Как сделать вложенные TV MIGx и как это потом вывести с помощью fenom


Доброе утро сообщество!
Сегодня у меня день рождения, а значит замечательный день чтобы написать новую заметку =)
Итак, буквально недавно столкнулся с задачей вывести несколько аккордеонов подряд, причем каждый их которых должен иметь собственный заголовок. Решено для этого было использовать вложенные TV типа MIGx. Подробности под катом.
На моём примере использовалось 2 уровня вложенности. То есть внутри одного TV был вложен только один TV. Но я не исключаю, что можно сколько угодно больше уровней вложенности делать, просто пока не проверял. Далее по порядку:

  1. Создаем MIGx конфигурацию AccordionItems, тот что на втором уровне.

    Показываю в редакторе MIGx полей для понимания:


    • Далее настроил форму, причем в поле description в качестве inputTV можно было ничего не указывать, я указал созданный заранее простой TV с визуальным редактором TinyMCE чтобы было удобно наполнять текстом. Если бы не указал, то было бы простое текстовое поле:

    • И колонки, тут все просто:

    • После чего создаем TV поле одноименное, с указанием типа MIGx и имени его конфигурации AccordionItems.
  2. Следующим этапом идет создание MIGx конфигурации AccordionSections тут все по аналогии, но только в поле inputTV мы уже указываем TV AccordionItems:
  3. После чего создаем TV поле одноименное, с указанием типа MIGx и имени его конфигурации AccordionSections.
  4. Ну а напоследок самое интересное, на мой взгляд создаем чанк который бы выводил аккордеоны с заголовками, причем нужно было чтобы редактировались данные в одном месте, в данном случае в одном ресурсе, а выводилось одни и те же секции везде где будет вставлен чанк.

    Ниже код чанка и затем пояснение по некоторым моментам:

    {if $_modx->resource.id == '832'?}
                <div class="panel-group" id="accordion" role="tablist" aria-multiselectable="true">
                    {foreach ($_modx->resource.AccordionSections | fromJSON) as $AccordionSection}
                    {var $sectionIds = $AccordionSection.MIGX_id}
                    <p class="accordion-section-title">{$AccordionSection.sectionTitle}</p>
                    {foreach ($AccordionSection.sectionContent | fromJSON) as $AccordionItem}
                    <div class="panel panel-default">
                        {var $accordionIds = $AccordionItem.MIGX_id}
                        <div class="panel-heading" role="tab" id="h{$sectionIds}-{$accordionIds}">
                            <h4 class="panel-title">
                                <a role="button" data-toggle="collapse" data-parent="#accordion" href="#c{$sectionIds}-{$accordionIds}" aria-expanded="true" aria-controls="c{$sectionIds}-{$accordionIds}">
                                    <i class="more-less glyphicon glyphicon-plus"></i>
                                    <span class="accordion-section-header">{$AccordionItem.title}</span>
                                </a>
                            </h4>
                        </div>
                        <div id="c{$sectionIds}-{$accordionIds}" class="panel-collapse collapse" role="tabpane{$sectionIds}-{$accordionIds}" aria-labelledby="h{$sectionIds}-{$accordionIds}">
                            <div class="panel-body">
                                  {$AccordionItem.description}
                            </div>
                        </div>
                    </div>
                    {/foreach}
                {/foreach}
                </div><!-- panel-group -->
            {else}
                <div class="panel-group" id="accordion" role="tablist" aria-multiselectable="true">
                    {var $otherAccSections = 832 | resource : 'AccordionSections'}
                    
                    {foreach ($otherAccSections | fromJSON) as $AccordionSection}
    
                    {var $sectionIds = $AccordionSection.MIGX_id}
                    <p class="accordion-section-title">{$AccordionSection.sectionTitle}</p>
                    {foreach ($AccordionSection.sectionContent | fromJSON) as $AccordionItem}
                    <div class="panel panel-default">
                        {var $accordionIds = $AccordionItem.MIGX_id}
                        <div class="panel-heading" role="tab" id="h{$sectionIds}-{$accordionIds}">
                            <h4 class="panel-title">
                                <a role="button" data-toggle="collapse" data-parent="#accordion" href="#c{$sectionIds}-{$accordionIds}" aria-expanded="true" aria-controls="c{$sectionIds}-{$accordionIds}">
                                    <i class="more-less glyphicon glyphicon-plus"></i>
                                    <span class="accordion-section-header">{$AccordionItem.title}</span>
                                </a>
                            </h4>
                        </div>
                        <div id="c{$sectionIds}-{$accordionIds}" class="panel-collapse collapse" role="tabpane{$sectionIds}-{$accordionIds}" aria-labelledby="h{$sectionIds}-{$accordionIds}">
                            <div class="panel-body">
                                  {$AccordionItem.description}
                            </div>
                        </div>
                    </div>
                    {/foreach}
                {/foreach}
                </div>
            {/if}
    • Для вывода данных используется простой разбор полей с помощью foreach
    • Для того чтобы секции аккордеона имели уникальные уникальные css классы и айди использовались поля MIGx конфигураций MIGX_id и создавались переменные для того чтобы не запутаться в коде.
    • В чанке условие, если айди ресурса тот для которого изначально создавалось TV поле с аккордеоном, то код имеет вид наподобие
      {$_modx->resource.AccordionSections}
      , если ресурс имеет любой другой айди то в коде указывается айди и поля ресурса которые нужно разобрать
      {832 | resource : 'AccordionSections'}
    • При разборе полей TV уровня, то есть AccordionSections когда доходим до поля sectionContent, производим еще один разбор этого поля как TV типа MIGx ведь оно в себе как раз и содержит вложенный TV второго уровня, то есть AccordionItems
Вот такое решение, надеюсь кому нибудь пригодится.
08 июня 2018, 07:54    Сергей Лелеко   G+  
4    310 0


Комментарии ()

  1. UDAV 08 июня 2018, 10:30 # +1
    Замудрил конечно) Все делается намного проще если сразу код migx указывать в tv поле.

    id получить тоже можно гораздо проще.
    {foreach ($AccordionSection.sectionContent | fromJSON) as $idx => $AccordionItem}
    в $idx будет id нужный
    1. Баха Волков 08 июня 2018, 10:52 # 0
      Я на счёт этого промолчал, хотя и вот это тоже мне не понятно, думал, что еще кого-то обижу (много людей сейчас обижаются):

      {var $accordionIds = $AccordionItem.MIGX_id}

      Зачем засовывать в переменную что-то, если в этом нет необходимости, разве что для удобство…
      1. Сергей Лелеко 08 июня 2018, 11:11 # 0
        мне так удобнее было, не знаю какие обиды.
        1. Баха Волков 08 июня 2018, 11:55 # 0
          Да я то не про вас лично :), тем более я так и написал:
          разве что для удобствА…
    2. Баха Волков 08 июня 2018, 10:47 # +3
      Сразу извиняюсь, просто если раньше нужно было так делать, то сейчас можно и попроще и без лишних TV

      1)
      Далее настроил форму, причем в поле description в качестве inputTV можно было ничего не указывать, я указал созданный заранее простой TV с визуальным редактором TinyMCE чтобы было удобно наполнять текстом. Если бы не указал, то было бы простое текстовое поле:

      TV создавать бессмысленно, так как есть Input TV type в котором нужно указывать тип поля, т.е. достаточно указать richtext и всё. Результат: Тот же, зато нет лишнего TV.

      2)
      После чего создаем TV поле одноименное, с указанием типа MIGx и имени его конфигурации AccordionItems.

      Это из той же оперы, зачем создавать TV, если есть Input TV type и Configs которому в json формате можно передать все параметры, т.е. можно например так:

      Input TV type указать number и передать ему что-то типа:

      {
         "allowDecimals":"No",
         "allowNegative":"No"
      }
      т.е. здесь я вместо того чтобы создавать лишний TV с типом ввода «Число», где «Разрешить десятичные» и «Разрешить минус» поставил бы «Нет» и данный TV у меня просто бы висел в админке и в БД так и не пригодившись, я указываю MIGX-у.

      В вашем же случае нужно так:


      Фотография кликабельна

      Спасибо за внимание!
      1. Алексей Бгатов 08 июня 2018, 15:15 # +1
        в данном случае в конфиге не нужен json — достаточно просто указать AccordionItems. JSON нужен только для полей, отличных от migx
      2. Сергей Лелеко 08 июня 2018, 10:52 # +2
        Спасибо за конструктивную критику и разъяснения. Решение сам искал, не знал что можно было сделать иначе)
        1. Илья Уткин 09 июня 2018, 07:01 # +2
          А если бы статью не написал, то и не узнал бы) и другие тоже почитают комменты и что-то для себя вынесут (я, например, тоже новое прочитал).
        Вы должны авторизоваться, чтобы оставлять комментарии.