There seems to be an error in the formtabs config

Можно ли с помощью modx изменить параметры ввода для TV? Я хочу сделать систему категорий товаров у себя на сайте. Я создал несколько ресурсов, которые отвечают за категории товаров. Я добавил id этих ресурсов в параметры ввода в MIGX, чтобы в каждом товаре можно было выбрать, к какой категории он принадлежит. Если я на […]

Содержание

  1. Можно ли с помощью modx изменить параметры ввода для TV?
  2. Комментарии (5)
  3. ТОП 10 сайтов в году
  4. Создание слайдера с использованием MIGX в MODX
  5. Что такое MIGX
  6. Установка MIGX
  7. MIGX — Создание карусели Bootstrap
  8. Создание нового MIGX элемента
  9. Создание TV-поля MIGX с конфигурацией photos
  10. Ввод данных в TV MIGX поле photos
  11. Вывод данных TV MIGX поля на страницу
  12. Empty Form Tabs in MODX 2.4.4 #256
  13. Comments
  14. Footer
  15. MODX. MIGX, расширение функциональности дополнительных полей (TV)
  16. Метод с использованием JSON кода
  17. Метод с использованием менеджера полей
  18. Описание вкладок и параметров MIGX
  19. Типы полей для inputTV и inputTVtype:
  20. Примеры оформления JSON кода для настройки полей
  21. О рендерах
  22. Вывод информации MIGX на сайте
  23. MIGX и базы данных / создание приложения c MIGX
  24. Migx в Migx
  25. Примеры применения MIGX

Можно ли с помощью modx изменить параметры ввода для TV?

Я хочу сделать систему категорий товаров у себя на сайте.
Я создал несколько ресурсов, которые отвечают за категории товаров. Я добавил id этих ресурсов в параметры ввода в MIGX, чтобы в каждом товаре можно было выбрать, к какой категории он принадлежит.

Если я на сайт добавлю категорию, то должны измениться параметры ввода, чтобы я мог присвоить товарам новую категорию.

Как мне сделать изменение параметров ввода для TV (MIGX), в которой содержатся категории — при добавлении нового ресурса (категории)?

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

Спасибо за ответ.
Но у меня никак не получается написать работающий код. Не подскажете, где ошибка?

Выводится вот такая ошибка:
There seems to be an error in the formtabs-config

Сделайте TV catstv без привязки к шаблону с типом ввода «Список (множественный выбор)» и возможными значениями:

Используйте эту TV-шку в MIGX-TV во вкладках формы для поля cat:

Большое спасибо, все получилось. А можно еще вопрос?
Что вот это означает?

Где можно почитать об этом приеме?

Это просто шаблон вывода элемента для списка.
В TV возможные значения пишутся:

В админке пункты будут выглядеть как названия, а в базу будут писаться значения.
В данном случае у Вас в списке категория будет выглядеть как
А в базу будет писаться ее ID — 15.

Для добавления комментариев вы должны авторизоваться или зарегистрироваться.

ТОП 10 сайтов в году

К сожалению, пока недостаточно данных. Пожалуйста, выберите другой год.

Источник

Создание слайдера с использованием MIGX в MODX

Урок, в котором рассмотрим назначение дополнения MODX Revo MIGX.

Работу с MIGX разберём на примере, результатом которого станет возможность добавлять в удобной форме изображения к ресурсам. Вывод изображений связанных с ресурсом на страницу будем осуществлять посредством карусели (слайдера) Bootstrap 3.

Что такое MIGX

MIGX — это компонент для MODX Revolution, который добавляет к переменным шаблона (TV параметрам) новый тип ввода с аналогичным названием (migx) и удобными инструментами для работы с ним. MIGX позволяет сохранить в одну TV-переменную целую таблицу данных. Это означает то, что с помощью MIGX и одного дополнительного поля (TV) можно с каждым ресурсом связать сложный набор данных. Для хранения данных в MIGX TV-переменной используется формат JSON.

Название MIGX расшифровывается как MultiItemsGridtv (МногоЭлементнаяСеткаTV) для MODX.

Для извлечения сложных элементов данных из дополнительного TV поля с типом MIGX можно использовать сниппет getImageList . Данный сниппет поставляется вместе с пакетом MIGX.

Установка MIGX

Процесс установки MIGX начинается c открытия в админке MODX Revolution страницы «Управление пакета» (Приложение -> Установщик) и нажатия в ней кнопки «Загрузить дополнения». На открывшейся странице в поле «Поиск» вводим название пакета (MIGX) и нажимаем клавишу Enter . После этого из представленных результатов выбираем искомое дополнение и нажимаем на кнопку «Загрузить». Возвращаемся на предыдущую страницу и завершаем процесс инсталляции с помощью кнопки «Установить».

В процессе установке необходимо определиться с местом расположения компонента MIGX в главном меню админки. Выбор тут осуществляется из 2 вариантов. Первый вариант (Top Nav) подразумевает размещения ссылки на компонент в качестве основного пункта меню, а второй (Extras/Components) – в элементе «Приложения».

Результат установки дополнения MIGX:

MIGX — Создание карусели Bootstrap

В качестве примера рассмотрим применение компонента MIGX для создания карусели Bootstrap. Перед тем как переходить к созданию элемента определимся с перечнем основных полей, которые необходимы для формирования каждого слайда карусели. Этот список будет состоять из следующих полей:

  • title — заголовок (название) слайда (изображения);
  • image – изображение;
  • description — описание изображения.

Создание MIGX элемента, состоящего из вышеперечисленных полей, осуществляется на вкладке «MIGX» страницы «Управление MIGX». Открытие страницы «Управление MIGX» выполняется с помощью пункта MIGX в главном меню менеджера или в раскрывающем списке «Приложения» в зависимости от настройки его расположения.

Создание нового MIGX элемента

Процесс разработки нового элемента MIGX осуществляется с помощью кнопки «Добавить элемент». После нажатия на эту кнопку открывается модальное окно «MIGX», состоящее из множества вкладок. Для большинства задач достаточно использовать только первых три: Settings (Основные параметры), Formtabs (вкладка для создания структуры) и Columns (вкладка для разработки таблицы, с помощью которой конечный пользователь будет управлять данными).

На вкладке «Settings» введём название элемента (например, photos) и надпись, которая будет заменять текст «Добавить элемент».

На вкладке «Formtabs» осуществляется создание полей. Другими словами она определяет структуру, которую конечные пользователи будут использовать для ввода своих данных. Чтобы добавить поля к MIGX необходимо нажать на кнопку «Добавить элемент» и в открывшемся диалоговом окне ввести название набора (Caption) и заполнить таблицу Fields.

Ввод записей в таблицу MODX Revolution MIGX осуществляется с помощью кнопки, расположенной сразу же после заголовка «Fields».

В таблицу Fields внесём следующие 3 записи:

  • Fieldname (имя поля) – title, Caption – Заголовок, Description – Описание фотографии.
  • Fieldname (имя поля) – image, Caption – Изображение, Input TV Type – image.
  • Fieldname (имя поля) – description, Caption – Описание.

Заключительный шаг – это ввод данных во вкладку «Columns». Данная вкладка определяет название столбцов колонок таблицы (внешний вид), с помощью которых пользователь осуществляет просмотр и ввод данных в соответствующую дополнительную TV-переменную MIGX ресурса (в данном случае TV-переменную, определённую MIGX-элементом photos).

Введём в таблицу Columns следующие сведения:

  • Header – Заголовок, Field (имя поля) – title, Column width (ширина колонки) – 100.
  • Header – Файл изображения, Field – image, Renderer – this.renderImage.
  • Header – Описание, Field – description, Column width (ширина колонки) – 200.

Добавление записей в таблицу осуществляется с помощью кнопки «Добавить элемент».

Создание TV-поля MIGX с конфигурацией photos

После создания MIGX-элемента (конфигурации) photos приступим к созданию дополнительного поля (TV) с типом ввода MIGX и конфигурацией photos.

Создание дополнительного поля в админке осуществляется на левой панели во вкладке «Элементы». Для этого напротив надписи «Дополнительные поля» нажмите на значок плюса и в открывшейся странице введите следующие данные:

  • На вкладке «Общая информация» в поле «Имя» значение photos (имя дополнительного поля);
  • На вкладке «Параметры ввода» в раскрывающемся списке «Тип ввода» выбрать пункт migx, а в поле «Конфигурации» ввести значение photos.
  • На вкладке «Доступно для шаблонов» выбрать те шаблоны, для которых (а точнее для ресурсов, у которых установлены данные шаблоны) это поле будет доступно.

Ввод данных в TV MIGX поле photos

Откроем любой ресурс, у которого доступно MIGX TV поле photos и введём в него, например, следующие данные:

Вывод данных TV MIGX поля на страницу

Выводить данные на страницу будем с помощью сниппета getImageList , который поставляется вместе с дополнением MIGX.

Данные из TV MIGX поля photos визуально представим в виде карусели Bootstrap. Познакомиться с тем, какой необходимо получить на выходе HTML код можно используя статью Знакомство с каруселью Twitter Bootstrap.

Приступ к реализации. Для этого откроем шаблон, установленный для данного ресурса, и в необходимое место вставим следующий код:

Вышеприведённый код состоит из HTML разметки и 2 вызовов сниппета getImageList . Первый выводит индикаторы карусели, а второй – слайды, содержащие изображения. Данные сниппеты имеют 2 параметра. Параметр tvname предназначен для указания имени TV-переменной с MIGX данными, которые необходимо вывести на страницу. А параметр tpl определён для того чтобы задать шаблон (чанк), посредством которого будет формироваться каждая строка данных из MIGX TV-поля photo.

Содержимое чанка tplCarouselIndicator :

Содержимое чанка tplCarouselItem :

Результат отображения карусели на странице:

Источник

Empty Form Tabs in MODX 2.4.4 #256

Since the update in MODX 2.4.4, form tabs in MIGX TV are empty. Grids are ok.
Did I miss something ?
I’m using MIGX 2.9.6-pl

Thanks for your help.

The text was updated successfully, but these errors were encountered:

hmm. haven’t empty formtabs in 2.4.4
I’m on 2.10.0 (beta10), but I think that shouldn’t matter

After some researches, the problem appeared when I used the fix related to this issue #222 with that 22004b3. It was actually working fine in migx-2.9-6.
In migx-2.9.7-pl, I’m facing the same problem with MODX 2.4.4.

To be a little more precise, this what I’m facing :

    MODX 2.4.2 + migx-2.9-6 : formtabs ok, but extra not loading in the manager (

[SOLVED] Error when i try to access to MIGX via extras menu in the manager. #222 )

  • MODX 2.4.2 + migx-2-9-6 + ‘patch’ 22004b3 : formtabs empty, but extra loading successfully in the manager.
  • MODX 2.4.4 + migx-2-9-7 : formtabs empty, but extra loading successfully in the manager.
  • Is there someone else who face this problem ?

    Hello,
    MODX 2.4.4, — I’m using MIGX 2.10.0(10)
    Does not work!

    after clicking Add Item 1, 2, 3, .

    :

    when holding down the left mouse button:

    In most cases, where I’ve seen empty formtabs, there was an error in the formtabs-json

    an upgrade to 2.10.0 beta10 has fixed the issue for @jchirschy

    © 2023 GitHub, Inc.

    You can’t perform that action at this time.

    You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.

    Источник

    MODX. MIGX, расширение функциональности дополнительных полей (TV)

    Отредактировано: 14 Ноября 2022

    Частые JSON конструкции

    MIGX позволяет разработчику создавать формы / таблицы / миниприложения с неограниченным набором полей и гибко настраивать их структуру в рамках одного TV поля. Поля MIGX создаются аналогично обычным, за исключением пары дополнительных настроек.

    Коротко о главном в MIGX от OpenMODX:

    Для создания MIGX поля надо установить компонент MIGX (во время установки компонент спросит, где располагать пункт меню MIGX, в меню MODX или в подпункте Extras, имхо, если не планируете создавать ТВ каждый день, устанавливайте в подпункт). Далее, для создания доп. поля действуем по следующей схеме:

    1. Создать новое дополнительное поле;
    2. На вкладке «Общая информация» заполнить поля: Имя и Подпись;
    3. На вкладке «Доступно для шаблонов» отметить необходимые шаблоны. (При необходимости настроить права доступа и источники файлов) ;
    4. На вкладке «Параметры ввода» установить «тип ввода» MIGX, и создать структуру полей. Сделать это можно двумя способами, либо написав нужный JSON код самостоятельно, либо заполнив соответствующие поля на специальной странице.

    Метод с использованием JSON кода

    В поле «Тип ввода» выбрать MIGX, и заполнить поля «Вкладки формы» и «Разметка колонок». Параметры для этих полей описаны ниже.

    Код для поля «Вкладки формы» (Form Tabs)

    Создание и настройка доп полей MIGX

    • formtabs — вкладка всплывающего окна, разделяющая группы полей. Если указана только одна, то вкладки не отображаются;
    • caption — заголовок вкладки или поля, который будет отображаться в админпанели;
    • fields — поля содержащиеся на вкладке;
    • field — символьный код поля;
    • description — Описание поля ввода в панели управления;
    • inputTV — тип поля для ввода данных. Применяется если НЕ надо указывать специфические настройки, такие как значения по умолчанию, параметры вывода и пр. (необязательный атрибут) ;
    • inputTVtype — тип поля для ввода данных. Применяется если НАДО указывать специфические настройки, такие как значения по умолчанию, параметры вывода и пр. (необязательный атрибут) ;
    • sourceFrom — указывается предустановленный в настройках TV-поля источник файлов (необязательный атрибут) . Чтобы это поле работало, необходимо создать и указать соответствующий inputTV;
    • inputOptionValues — параметр для указания возможных значений таких типов полей как listbox (необязательный атрибут) ;

    параметры для формирования столбцов:

    • header — отображаемое имя столбца ;
    • dataIndex — указывается значение параметра «field», для которого формируется столбец. Не обязательно указывать существующее поле, например если в последствии будет использоваться рендер чанка или что-то в этом роде. ;
    • editor — указывается для того, чтобы можно было редактировать значения прямо в теле таблицы, не заходя в модальное окно редактирования ;

    Код для поля «Разметка колонок» (Grid Columns)

    Вывод полей на странице создания ресурса

    • header — заголовок поля, который будет отображаться в админпанели;
    • width — ширина колонки отображения в админ панели;
    • sortable — указывается возможность сортировки в админ панели по данному полю, значения true или false;
    • dataIndex — значение привязывающее к значению field из символьного кода поля;
    • renderer — поле для отображения типа данных в админпанели. Можно использовать средства визуализации для каждого столбца. Например, для того чтобы отобразить миниатюры изображений.
    • editor — для возможности редактирования ячейки в админпанели в таблице предпросмотра.

    Полный список представлен ниже, в «описании вкладок и параметров».

    Метод с использованием менеджера полей

    На вкладке TV «Тип ввода» в поле «Конфигурация» (Configurations) прописать название конфигурации полей, которая будет создана далее. Затем перейти в меню компонента MIGX (расположение этого меню выбирается при установке, размещается либо в основном списке, либо в меню «Приложения» (Extras)).

    В MIGX Management поля добавляются через вкладку MIGX, там нажимаем «Добавить элемент», этот элемент и будет новой конфигурацией. В появившемся окне создания конфигурации очень много настроек, от параметров которых и зависит каким будет новое MIGX поле. Настройки можно устанавливать вручную, или импортировать из json файла (этот пункт возможен если кликнуть правой кнопкой мыши по названию конфигурации в списке конфигураций). Поля для настройки конфигурации описаны ниже.

    Описание вкладок и параметров MIGX

    Рядом с названием поля курсивом в квадратных скобках указано название для кода JSON.

    Базовые настройки для формы поля MIGX

    • Name — название, которое указывается в поле «конфигурация» при создании дополнительного поля.
    • Category — категория. Помогает в фильтрации конфигураций, если их, к примеру, очень много.
    • Add new Category — добавляет новую категорию.
    • «Add Item» Replacement — замена текста на кнопке Add Item.
    • Disable Add Items — убрать возможность добавления новых элементов, но оставить возможность редактирования существующих.
    • Add Items directly — добавлять элементы сразу, не вызывая всплывающее окно.
    • Form Caption — заголовок внутри всплывающего окна для заполнения полей. Можно указывать теги MODX.
    • Window Title — название поля в окне создания ресурса.
    • unique MIGX ID — уникальный ID поля MIGX.
    • max MIGX records — максимальное количество записей которое можно добавить к ресурсу.
    • Add new MIGX records at — позиция для новых добавленных элементов: bottom или top.
    • Mediasource ID — ID медиаисточника.

    Вкладка, формирующая во всплывающем окне табы с полями MIGX. Если указана только одна, то вкладки не отображаются.

    • Fields[fields] — тут добавляются поля конфигурации MIGX, которые будут доступны на странице добавления ресурса. Каждый итем содержит в себе коллекцию полей одной вкладки MIGX.
      • Caption — заголовок для группы полей.
      • Display above Tabs — показывать над другими табами (работает только если это первый таб).
      • Fields — добавление полей.

      Вкладка Field [field]

      Формирует данные поля

      • Fieldname — текстовое ID поля.
      • Caption — название поля.
      • Description[description] — описание для поля.
      • Description is Code — описание кода.
      • Input TV[inputTV] — тип поля для ввода данных. Применяется если НЕ надо указывать специфические настройки, такие как значения по умолчанию, параметры вывода и пр. (необязательный атрибут).
      • Input TV type[inputTVtype] — тип поля для ввода данных. Применяется если НАДО указывать специфические настройки, такие как значения по умолчанию, параметры вывода и пр. (необязательный атрибут).
      • Validation — условия для валидации по полю.
      • Configs — поле для дополнительной конфигурации. Можно использовать для migx-TV-configname, либо для свойств ввода любого TV-type как json-string.
      • Restrictive Condition (MODX tags) — ограничительное условие. Пустой результат будет отображать значение этого поля.
      • Display — выбор, отображать поле или нет.

      При необходимости, привязывает к полю источники файлов.

      • source From[sourceFrom] — выбор места из которого брать значение для источника файлов.
      • Sources — поле для указания источника файлов который должен использоваться (в качестве базового контекста используйте web).

      Вкладка Input Options

      Дополнительные параметры для поля.

      • Input Option Values[inputOptionValues] — список возможных значений для полей типа выпадающих списков и чекбоксов.
      • Default Value — значение настроек по умолчанию (например: @CHUNK getAttributeOptions).
      • Use Default if Empty — использовать ли значение по умолчанию если параметр Input Option Values не указан.
  • Multiple Formtabs — поле для выбора конфигураций форм которые будут доступны во всплывающем окне MIGX поля.
  • Multiple Formtabs Label — лейбл для поля выбора формы.
  • Multiple Formtabs Field — имена полей для этой конфигурации формы. По умолчанию: MIGX_formname.
  • Multiple Formtabs Optionstext — текст который будет выводиться в селекте, для обозначения данной конфигурации формы.
  • Multiple Formtabs Optionsvalue — значение для данной конфигурации формы.
  • Вкладка отвечающая за то, как пользователи админ панели будут видеть содержимое MIGX поля в админке. Аналогично полю «Разметка колонок» из метода с использованием кода. Для последующей корректной работы возможности редактирования, должно быть предусмотренно поле id.

    Кнопка AddItem позволяет добавить поле для отображения в админке. Поля для заполнения:

    Вкладка Column [dataIndex]

    • Header[header] — заголовок для поля.
    • Field — уникальный ID поля, которое должно отображаться.
    • Column width — ширина которую должна занимать колонка
    • Sortable — должна ли быть возможность сортировки по полю.
    • Show in Grid — показывать ли в сетке. Если указано нет — столбец будет по умолчанию скрыт.
    • Custom Renderer — если необходим собственный рендер, которого нет в списке.
    • Renderer — список предустановленных рендеров.
    • on Click — действие по клику.
    • SelectFromGrid config — .
    • renderChunk template — чанк с шаблоном рендера.
    • Renderoptions — прочие настройки для рендера, например имя чанка который должен быть обработан.

    Вкладка Cell Editor [editor]

    Выбор отображения редактора ячейки в таблице предпросмотра.

    • this.textEditor — текстовый редактор;
    • this.listboxEditor — выпадающий список.

    Contextmenues — кнопки для контекстного меню, которое открывается при клике правой кнопкой мыши на списке элементов.

    Columnbuttons — кнопки для редактирования в

    Для корректной работы, в колонках нужно создать поле id, иначе будет проблема с редактированием данных.

    • update — редактировать.
    • duplicate — дублировать.
    • addbefore — добавить до.
    • addafter — добавить после.
    • publish — публиковать.
    • unpublish — снять с публикации.
    • activate — активировать.
    • deactivate — деактивировать.
    • recall_remove_delete
    • remove — удалить.
    • edit_migx — редактировать для migx.
    • duplicate_migx — дублировать для migx.
    • remove_migx — удалить для migx.
    • remove_migx_and_image — удалить migx элемент и изображения.
    • movetotop_migx — сдвинуть выше для migx.
    • movetotop_bottom — сдвинуть вверх или вниз.
    • publishtarget — публиковать выбранные.
    • unpublishtarget — снять с публикации выбранные.

    Добавляет дополнительные кнопки в окне создания/редактирования элемента поля.

    • Buttons per row — количество кнопок на строку
    • Actionbuttons — варианты кнопок
      • addItem — добавить элемент.
      • bulk — массовые действия: publish, unpublish, delete.
      • toggletrash — переключатель: просмотр элементов в карзине / нормальный просмотр.
      • exportview — экспортировать.
      • exportimportmigx — экспорт/импорт параметров поля migx в формате json.
      • upload — загрузка.
      • loadfromsource — загрузка элементов из пивязанного медиаресурса.
      • resetwinposition — сброс позиционирования окна.
      • emptyTrash — очистить корзину.
      • uploadfiles — загрузить файлы (мультизагрузка).
      • uploadfiles_db — загрузить файлы в базу данных (мультизагрузка).
      • importcsvmigx — импортировать из csv.
      • import_from_package — импортировать из пакета.
    • this.resetWinPosition — сбросить позиционирование окна
    • this.emptyTrash — очистить корзину
    • this.handlePositionSelector — управление позиционированием выбранного
    • this.selectSelectorOption
    • gridfilter
    • this.addItem — добавить итем
    • this.addNewItem — добавить новый итем
    • this.preview — предпросмотр
    • this.uploadImages — загрузить изображение
    • this.remove — удалить
    • this.update — изменить
    • this.duplicate — дублировать
    • this.addbefore — добавить перед
    • this.addafter — добавить после
    • this.toggleDeleted
    • this.handleColumnSwitch — переключатель между полями
    • this.publishObject — опубликовать объект
    • this.unpublishObject — снять объект с публикации
    • this.activateObject — активировать объект
    • this.deactivateObject — деактивировать объект
    • this.publishSelected — опубликовать выбранное
    • this.unpublishSelected — снять с публикации выбранное
    • this.deleteSelected — удалить выбранное
    • this.deleteObject — удалить объект
    • this.recallObject — перевызвать объект
    • this.csvExport — экспорт CSV
    • this.removeObject — удалить объект
    • this.publishTargetObject — опубликовать выбранный объект
    • this.unpublishTargetObject — снять с публикации выбранный объект
    • this.showScreenshot — показать скриншот
    • this.uploadFiles — загрузить файлы
    • this.uploadSuccess
    • this.loadFromSource_db — загрузить из источника БД
    • this.migx_removeMigxAndImage
    • this.exportMigxItems — экспортировать объекты из MIGX
    • this.selectImportFile — выбрать импортированный файл
    • this.importCsvMigx — импортировать из CSV
    • this.import_from_package — импортировать из пакета

    Фильтры для работы с данными из БД

    • Filters per row — количество фильтров на страницу.
    • Filters — список в который добавляются фильтры.
      • filter Name — имя фильтра (на латинице)
      • Label — лейбл, название фильтра на любом языке
      • Empty Text — текст в незаполненном поле фильтра. Например: —Фильтр по категориям—
      • Filter Type — тип фильтра: дата, сброс всего, текстовое поле, мульти список, комбобокс (комбинированный список), древовидный список
      • getlist-where — оператор where, для обработки результирующего списка. Пример записи:
      • getcombo processor — процессор который должен обрабатывать комбобокс (список существующих процессоров). Можно создавать собственные процессоры по адресу: core/components/yourpackage/processors/mgr/default/getpublishedcombo.php
      • getcombo textfield — название текстового поля со списком значений для комбобокса
      • getcombo idfield — название поля указывающего на id
      • getcombo where — оператор where, для обработки результатов комбобокса
      • getcombo classname — имя класса для комбобокса
      • getcombo packageName — имя пространства имен (название дополнения) для комбобокса
      • Prefix — выбор префикса: по умолчанию или собственный
      • Custom Prefix — если собственный, то указывается какой
      • getcombo joins — оператор JOIN для связи с данными из другой таблицы
      • parent combobox — родительский элемент для комбобокса
      • default value — значение по умолчанию

    Настройки для связи поля с собственной таблицей в БД

    • Package — пространство имен компонента.
    • Classname — имя класса объекта связи с БД.
    • Processors Path — путь к процессору.
    • getlist defaultsort — сортировка по умолчанию для вывода списка.
    • getlist defaultsortdir — направление сортировки по умолчанию для вывода списка.
    • Sort Config — параметры сортировки множественных полей, в формате JSON.
    • Items per Page Default — количество элементов на странице.
    • Prefix — выбор между префиксом по умолчанию и собственным.
    • Custom Prefix — указание префикса.
    • Grid — сетка ExtJS.
    • Load Grid — указание как грузить сетку.
    • Check Resource — проверять ли ресурс.
    • Check Resource TV — проверять ли доп поля ресурса.
    • Join Alias — SQL команда Join Alias.
    • Has Extra Connection Table — указывает должно ли поле связываться с таблицей.
    • Where — SQL оператор выборки WHERE.
    • Joins — указание связи полей из разных таблиц друг с другом, подобно SQL оператору JOIN. Пример записи: [<«alias»:»aggregateName»,»selectfield»:»fieldName»>], где alias — это указание на таблицу с которой надо связаться, а field — название поля которое надо получить.
    • Hook Snippets — дополнительный блок кода, который надо выполнить при каком-либо событии.

    Настройки страницы в панели менеджера (CMP)

    • Main Caption — основной заголовок;
    • Tab Caption — заголовок таба;
    • Tab Description — описание таба;
    • Custom Tab Controller — пользовательский контроллер для таба (о контроллерах).
    • Window Buttons — js-код, работающий при создании окна (Подробности в migxfe/templates/web/form/form.tpl and winbuttons.tpl).
    • On Submit success — js-код, запускаемый при успешной отправке.
    • Submit params — параметры передаваемые пи отправке.

    Типы полей для inputTV и inputTVtype:

    • autotag — авто-метка;
    • text — текст;
    • textarea — текстовая область;
    • textareamini — текстовая область (мини);
    • richtext — текстовый редактор;
    • dropdown — выпадающий список;
    • listbox — список (одиночный выбор);
    • listbox-multiple — список (множественный выбор);
    • list-multiple-legacy — устаревший список множественного выбора;
    • option — переключатели (radio);
    • checkbox — флажки (checkbox);
    • image — изображение;
    • file — файл;
    • url — URL;
    • email — электронная почта;
    • number — число;
    • date — дата;
    • tag — тег;

    Примеры оформления JSON кода для настройки полей

    Для настройки отображения полей в админке некоторые типы полей требуют предварительного рендера

    Параметры с опциями запоняются аналогично стандартным TV

    О рендерах

    Предустановленные рендеры:

    • this.renderImage — воспроизводит изображение;
    • this.renderImageFromHtml — воспроизводит изображение из html кода;
    • this.renderPlaceholder — воспроизводит данные из плейсхолдера;
    • this.renderFirst — отображает первый элемент;
    • this.renderLimited — выводит не более 100 элементов;
    • this.renderCrossTick — значки галочкакрестик для boolean полей;
    • this.renderClickCrossTick — значки галочкакрестик для boolean полей с возможностью изменения значения кликом (поддерживается для MIGXdb);
    • this.renderSwitchStatusOptions — изменение статуса кликом по полю (настраивается через Renderoptions);
    • this.renderPositionSelector — отображает позиционный переключатель активно / неактивно;
    • this.renderRowActions — воспроизводит функцию установленную в сетке;
    • this.renderChunk — отображает указанный чанк;
    • ImagePlus.MIGX_Renderer — рендер расширения Image+ (входит в состав MODX);
    • this.renderDate — используется для вывода даты;
    • this.renderOptionSelector — отображает опции checkbox списка;

    Предустановленные рендеры для поля editor:

    • this.textEditor — простое текстовое поле
    • this.listboxEditor — показывает список с вводимыми параметрами из указанного поля

    Коды рендеров храняться по адресу: core/components/migx/config/grid/ в файлах grid.renderer.config.php и grid.renderer.inc.php. Чтобы добавить свой рендер надо отредактировать оба указанных файла, просто берем существующий рендер, копируем, а дальше видоизменяем исходя из задачи.

    Вывод информации MIGX на сайте

    Для вывода данных из MIGX поля на сайт, можно написать свой снипет конвертации json в данные, либо использовать один из идущих в комплекте с MIGX сниппетов: getImageList или migxLoopCollection. Подробнее о возможностях getImageList. Подробнее о возможностях migxLoopCollection.

    Для вывода полей в скобках указывается их символьный код. У каждого элемента есть предопределенное поле ID, которое можно получить используя код [[+idx]].

    При выводе через xPDO поле предварительно надо декодировать из формата json. Вывод через xPDO будет примерно таким:

    При записи в поле MIGX кодируем обратно:

    MIGX и базы данных / создание приложения c MIGX

    MIGX можно привязывать к собственным таблицам. Порядок действий для настройки работы MIGX с базой данных:

    • На странице администрирования MIGX, в разделе Package Manager в поле Package Name надо указать название компонента, и нажать кнопку Create Package, после чего в структуре админки будет создан соответствующий каталог. О структуре компонентов MODX.
    • Далее, на вкладке XML Schema указываем схему БД и сохраняем кнопкой Save Scheme (схема используется для того чтобы была возможность работать с БД разного типа, подробнее в статье про структуру компонентов).
    • На вкладке Schema нажимаем «parse schema», после этого действия создасться структура файлов компонента, позволяющая подключаться к БД.
    • Далее переходим на вкладку Create Tables, и жмем одноименную кнопку, это действие создаст таблицу на сервере.
    • Далее переходим в раздел MIGX и создаем поле, с помощью одного из методов описанных выше, либо используем таблицы в собственном снипете.

    Migx в Migx

    В поле типа Migx можно поместить другое поле Migx. Для этого при указании типа поля в InputTV надо указать код нужного TV. Для примера рассмотрим два TV поля: tvBooks и tvChapters:

    Для вывода подобных полей на сайте код вывода второго поля надо поместить в чанк вывода для первого поля:

    Примеры применения MIGX

    Подборка конфигураций js для MIGX

    Пример фрагмента кода с вымышленным dataIndex, для создания ячейки координат:

    Источник

    <?php /** * migx * * @author Bruno Perner * * * @package migx */ /** * @package migx * @subpackage migx */ class Migx { /** * @access public * @var modX A reference to the modX object. */ public $modx = null; /** * @access public * @var array A collection of properties to adjust MIGX behaviour. */ public $config = array(); /** * @access public * @var source, the source of this MIGX-TV */ public $source = false; /** * @access public * @var working_context, the working context */ public $working_context = null; /** * The MIGX Constructor. * * This method is used to create a new MIGX object. * * @param modX &$modx A reference to the modX object. * @param array $config A collection of properties that modify MIGX * behaviour. * @return MIGX A unique MIGX instance. */ function __construct(modX & $modx, array $config = array()) { $this->modx = &$modx; $packageName = ‘migx’; $packagepath = $this->findPackagePath($packageName); $modelpath = $packagepath . ‘model/’; $prefix = null; $this->modx->addPackage($packageName, $modelpath, $prefix); /* allows you to set paths in different environments * this allows for easier SVN management of files */ $corePath = $this->modx->getOption(‘migx.core_path’, null, $modx->getOption(‘core_path’) . ‘components/migx/’); $assetsPath = $this->modx->getOption(‘migx.assets_path’, null, $modx->getOption(‘assets_path’) . ‘components/migx/’); $assetsUrl = $this->modx->getOption(‘migx.assets_url’, null, $modx->getOption(‘assets_url’) . ‘components/migx/’); $defaultconfig[‘debugUser’] = »; $defaultconfig[‘corePath’] = $corePath; $defaultconfig[‘modelPath’] = $corePath . ‘model/’; $defaultconfig[‘processorsPath’] = $corePath . ‘processors/’; $defaultconfig[‘templatesPath’] = $corePath . ‘templates/’; $defaultconfig[‘controllersPath’] = $corePath . ‘controllers/’; $defaultconfig[‘chunksPath’] = $corePath . ‘elements/chunks/’; $defaultconfig[‘snippetsPath’] = $corePath . ‘elements/snippets/’; $defaultconfig[‘auto_create_tables’] = true; $defaultconfig[‘baseUrl’] = $assetsUrl; $defaultconfig[‘cssUrl’] = $assetsUrl . ‘css/’; $defaultconfig[‘jsUrl’] = $assetsUrl . ‘js/’; $defaultconfig[‘jsPath’] = $assetsPath . ‘js/’; $defaultconfig[‘connectorUrl’] = $assetsUrl . ‘connector.php’; $defaultconfig[‘request’] = $_REQUEST; $this->config = array_merge($defaultconfig, $config); /* load debugging settings */ if ($this->modx->getOption(‘debug’, $this->config, false)) { error_reporting(E_ALL); ini_set(‘display_errors’, true); $this->modx->setLogTarget(‘HTML’); $this->modx->setLogLevel(modX::LOG_LEVEL_ERROR); $debugUser = $this->config[‘debugUser’] == » ? $this->modx->user->get(‘username’) : ‘anonymous’; $user = $this->modx->getObject(‘modUser’, array(‘username’ => $debugUser)); if ($user == null) { $this->modx->user->set(‘id’, $this->modx->getOption(‘debugUserId’, $this->config, 1)); $this->modx->user->set(‘username’, $debugUser); } else { $this->modx->user = $user; } } } public function findPackagePath($packageName) { $modx = &$this->modx; $lc_packageName = strtolower($packageName); return $modx->getOption( $lc_packageName . ‘.core_path’,null,$modx->getOption(‘core_path’).‘components/’ . $lc_packageName . ‘/’); } public function getXpdoInstanceAndAddPackage($scriptProperties) { $modx = &$this->modx; $prefix = isset($scriptProperties[‘prefix’]) ? $scriptProperties[‘prefix’] : »; $usecustomprefix = $modx->getOption(‘useCustomPrefix’, $scriptProperties, »); $usecustomprefix = empty($usecustomprefix) ? $modx->getOption(‘usecustomprefix’, $scriptProperties, ») : $usecustomprefix; $usecustomprefix = empty($usecustomprefix) ? $modx->getOption(‘use_custom_prefix’, $scriptProperties, ») : $usecustomprefix; if (empty($prefix)) { $prefix = !empty($usecustomprefix) ? $prefix : null; } $packageName = $modx->getOption(‘packageName’, $scriptProperties, »); if (!empty($packageName)) { $packagepath = $this->findPackagePath($packageName); $modelpath = $packagepath . ‘model/’; $xpdo_name = $packageName . ‘_xpdo’; if (isset($this->modx->$xpdo_name)) { //create xpdo-instance for that package only once $xpdo = &$this->modx->$xpdo_name; } elseif (file_exists($packagepath . ‘config/config.inc.php’)) { include ($packagepath . ‘config/config.inc.php’); if (is_null($prefix) && isset($table_prefix)) { $prefix = $table_prefix; } $charset = »; if (!empty($database_connection_charset)) { $charset = ‘;charset=’ . $database_connection_charset; } $dsn = $database_type . ‘:host=’ . $database_server . ‘;dbname=’ . $dbase . $charset; $xpdo = new xPDO($dsn, $database_user, $database_password); //echo $o=($xpdo->connect()) ? ‘Connected’ : ‘Not Connected’; $this->modx->$xpdo_name = &$xpdo; } else { $xpdo = &$this->modx; } $xpdo->addPackage($packageName, $modelpath, $prefix); } else { $xpdo = &$this->modx; } return $xpdo; } public function prepareQuery(&$xpdo, $scriptProperties) { $modx = &$this->modx; $limit = $modx->getOption(‘limit’, $scriptProperties, ‘0’); $offset = $modx->getOption(‘offset’, $scriptProperties, 0); $totalVar = $modx->getOption(‘totalVar’, $scriptProperties, ‘total’); $where = $modx->getOption(‘where’, $scriptProperties, array()); //$where = !empty($where) && !is_array($where) ? $modx->fromJSON($where) : $where; $queries = $modx->getOption(‘queries’, $scriptProperties, array()); $queries = !empty($queries) && !is_array($queries) ? $modx->fromJSON($queries) : $queries; $sortConfig = $modx->getOption(‘sortConfig’, $scriptProperties, array()); $sortConfig = !empty($sortConfig) && !is_array($sortConfig) ? $modx->fromJSON($sortConfig) : $sortConfig; $joins = $modx->getOption(‘joins’, $scriptProperties, array()); $joins = !empty($joins) && !is_array($joins) ? $modx->fromJSON($joins) : $joins; $having = $modx->getOption(‘having’, $scriptProperties, »); $selectfields = $modx->getOption(‘selectfields’, $scriptProperties, »); $selectfields = !empty($selectfields) ? explode(‘,’, $selectfields) : null; $specialfields = $modx->getOption(‘specialfields’, $scriptProperties, »); $classname = $scriptProperties[‘classname’]; $groupby = $modx->getOption(‘groupby’, $scriptProperties, »); $debug = $modx->getOption(‘debug’, $scriptProperties, false); $c = $xpdo->newQuery($classname); $c->select($xpdo->getSelectColumns($classname, $c->getAlias(), », $selectfields)); if (!empty($specialfields)) { $c->select($specialfields); } if (is_array($joins) && count($joins) > 0) { $this->prepareJoins($classname, $joins, $c); } if (!empty($where)) { if (is_string($where) && ($where[0] == ‘{‘ || $where[0] == ‘[‘)) { $where = json_decode($where, true); } if (is_array($where)) { foreach ($where as $key => $value) { if (strstr($key, ‘MONTH’) || strstr($key, ‘YEAR’) || strstr($key, ‘DATE’)) { $c->where($key . « = » . $value, xPDOQuery::SQL_AND); unset($where[$key]); } } } else { $where = array($where); } $c->where($where); } if (!empty($queries)) { foreach ($queries as $key => $query) { $c->where($query, $key); } } if (!empty($having)) { $c->having($having); } if (!empty($groupby)) { $c->groupby($groupby); } //set «total» placeholder for getPage $total = $xpdo->getCount($classname, $c); $modx->setPlaceholder($totalVar, $total); if (is_array($sortConfig)) { foreach ($sortConfig as $sort) { $sortby = $sort[‘sortby’]; $sortdir = isset($sort[‘sortdir’]) ? $sort[‘sortdir’] : ‘ASC’; $c->sortby($sortby, $sortdir); } } //&limit, &offset if (!empty($limit)) { $c->limit($limit, $offset); } $c->prepare(); if ($debug) { echo $c->toSql(); } return $c; } public function getCollection($c) { $rows = array(); $this->modx->exec(‘SET SQL_BIG_SELECTS = 1’); if ($c->stmt->execute()) { if (!$rows = $c->stmt->fetchAll(PDO::FETCH_ASSOC)) { $rows = array(); } } return $rows; } public function checkGrouping($fields, $groupingField, $key, &$oldgroupvalue, &$group_keys, $output, $level = 0) { if (!empty($groupingField)) { $newgroupvalue = isset($fields[$groupingField]) ? $fields[$groupingField] : »; $gr_level = empty($level) ? » : $level; /* print_r($oldgroupvalue); echo ‘old:’ . $oldgroupvalue[$level]; echo ‘ ‘; echo ‘new:’ . $newgroupvalue; echo ‘ ‘; echo $gr_level; echo ‘ ‘; echo $level . ‘ — ‘; */ if ($oldgroupvalue[$level] == $newgroupvalue) { //still the same group if ($fields[‘_last’]) { //last item at all $group_keys[$level][] = $key; $group_count = count($group_keys[$level]); $group_idx = 1; foreach ($group_keys[$level] as $group_key) { $output[$group_key][‘_groupcount’ . $gr_level] = $group_count; $output[$group_key][‘_groupidx’ . $gr_level] = $group_idx; $output[$group_key][‘_groupfirst’ . $gr_level] = $group_idx == 1 ? true : »; $output[$group_key][‘_grouplast’ . $gr_level] = $group_idx == $group_count ? true : »; $group_idx++; } } } else { //new group has started $group_count = count($group_keys[$level]); $group_idx = 1; foreach ($group_keys[$level] as $group_key) { $output[$group_key][‘_groupcount’ . $gr_level] = $group_count; $output[$group_key][‘_groupidx’ . $gr_level] = $group_idx; $output[$group_key][‘_groupfirst’ . $gr_level] = $group_idx == 1 ? true : »; $output[$group_key][‘_grouplast’ . $gr_level] = $group_idx == $group_count ? true : »; $group_idx++; } if ($fields[‘_last’]) { $output[$key][‘_groupcount’ . $gr_level] = 1; $output[$key][‘_groupidx’ . $gr_level] = 1; $output[$key][‘_groupfirst’ . $gr_level] = true; $output[$key][‘_grouplast’ . $gr_level] = true; } $oldgroupvalue[$level] = $newgroupvalue; $group_keys[$level] = array(); } $group_keys[$level][] = $key; } return $output; } public function renderOutput($rows, $scriptProperties) { $modx = &$this->modx; $tpl = $modx->getOption(‘tpl’, $scriptProperties, »); $wrapperTpl = $modx->getOption(‘wrapperTpl’, $scriptProperties, »); $emptyTpl = $modx->getOption(’emptyTpl’, $scriptProperties, »); $tplFirst = $modx->getOption(‘tplFirst’, $scriptProperties, »); $tplLast = $modx->getOption(‘tplLast’, $scriptProperties, »); $groupingField = $modx->getOption(‘groupingField’, $scriptProperties, »); $groupingField = $modx->getOption(‘groupingFields’, $scriptProperties, $groupingField); $prepareSnippet = $modx->getOption(‘prepareSnippet’, $scriptProperties, »); $totalVar = $modx->getOption(‘totalVar’, $scriptProperties, ‘total’); $total = $modx->getPlaceholder($totalVar); $toSeparatePlaceholders = $modx->getOption(‘toSeparatePlaceholders’, $scriptProperties, false); $toPlaceholder = $modx->getOption(‘toPlaceholder’, $scriptProperties, false); $toPlaceholders = $modx->getOption(‘toPlaceholders’, $scriptProperties, false); $outputSeparator = $modx->getOption(‘outputSeparator’, $scriptProperties, »); //$placeholdersKeyField = $modx->getOption(‘placeholdersKeyField’, $scriptProperties, ‘MIGX_id’); $placeholdersKeyField = $modx->getOption(‘placeholdersKeyField’, $scriptProperties, ‘id’); $toJsonPlaceholder = $modx->getOption(‘toJsonPlaceholder’, $scriptProperties, false); $toJson = $modx->getOption(‘toJson’, $scriptProperties, false); $jsonPrettyPrint = $modx->getOption(‘jsonPrettyPrint’, $scriptProperties, false); $processedToJson = !empty($toJson) ? true : false; $processedToJson = $modx->getOption(‘processedFieldsToJson’, $scriptProperties, $processedToJson); $createChunk = $modx->getOption(‘createChunk’, $scriptProperties, false); $addfields = $modx->getOption(‘addfields’, $scriptProperties, »); $addfields = !empty($addfields) ? explode(‘,’, $addfields) : null; $count = count($rows); $properties = array(); foreach ($scriptProperties as $property => $value) { $properties[‘property.’ . $property] = $value; } $properties[‘_count’] = $count; $properties[‘_total’] = $total; $idx = $modx->getOption(‘idx’, $scriptProperties, 0); $output = array(); $template = array(); $groupoutput = array(); $group_indexes = array(); $groups = array(); $oldgroupvalue = array(); $group_keys = array(); $jsonOptions = $jsonPrettyPrint ? JSON_PRETTY_PRINT : null; if ($count > 0) { foreach ($rows as $key => $fields) { if (!empty($addfields)) { foreach ($addfields as $addfield) { $addfield = explode(‘:’, $addfield); $addname = $addfield[0]; $adddefault = isset($addfield[1]) ? $addfield[1] : »; $fields[$addname] = $adddefault; } } if (($toJson || $toJsonPlaceholder) && !$processedToJson) { $output[] = $fields; } else { $fields[‘_alt’] = $idx % 2; $idx++; $fields[‘_first’] = $idx == 1 ? true : »; $fields[‘_last’] = $idx == $count ? true : »; $fields[‘idx’] = $fields[‘_idx’] = $idx; $fields = array_merge($fields, $properties); if (!empty($prepareSnippet)) { $result = $modx->runSnippet($prepareSnippet, array(‘fields’ => &$fields)); } $output[] = $fields; //check grouping $groupingFields = explode(‘,’, $groupingField); foreach ($groupingFields as $level => $gr_field) { $output = $this->checkGrouping($fields, $gr_field, $key, $oldgroupvalue, $group_keys, $output, $level); } } } if ($toJson || $toJsonPlaceholder) { } else { $rows = $output; $output = array(); $i = 0; foreach ($rows as $fields) { if ($i == 0 && $createChunk) { if ($chunk = $modx->getObject(‘modChunk’, array(‘name’ => $createChunk))) { } else { $ph_prefix = !empty($toPlaceholders) ? $toPlaceholders . ‘.’ : »; $chunk = $modx->newObject(‘modChunk’); $chunk->set(‘name’, $createChunk); $chunk_content = array(); foreach ($fields as $field => $value) { $chunk_content[] = ‘[[+’ . $ph_prefix . $field . ‘]]’; } $chunk->set(‘content’, implode(«n», $chunk_content)); $chunk->save(); } } if ($toPlaceholders) { //works only for one row — output the fields to placeholders if ($toPlaceholders == ‘print_r’) { return ‘<pre>’ . print_r($fields, 1) . ‘</pre>’; } $modx->toPlaceholders($fields, $toPlaceholders); return »; } $rowtpl = »; $idx = isset($fields[‘idx’]) ? $fields[‘idx’] : 0; //get changing tpls from field if (substr($tpl, 0, 7) == «@FIELD:«) { $tplField = substr($tpl, 7); $rowtpl = $fields[$tplField]; } if ($fields[‘_first’] && !empty($tplFirst)) { $rowtpl = $tplFirst; } if ($fields[‘_last’] && empty($rowtpl) && !empty($tplLast)) { $rowtpl = $tplLast; } $tplidx = ‘tpl_’ . $idx; if (empty($rowtpl) && !empty($scriptProperties[$tplidx])) { $rowtpl = $scriptProperties[$tplidx]; } if ($idx > 1 && empty($rowtpl)) { $divisors = $this->getDivisors($idx); if (!empty($divisors)) { foreach ($divisors as $divisor) { $tplnth = ‘tpl_n’ . $divisor; if (!empty($scriptProperties[$tplnth])) { $rowtpl = $scriptProperties[$tplnth]; if (!empty($rowtpl)) { break; } } } } } //get changing tpls by running a snippet to determine the current tpl if (substr($tpl, 0, 9) == «@SNIPPET:«) { $snippet = substr($tpl, 9); $rowtpl = $modx->runSnippet($snippet, $fields); } if (!empty($rowtpl)) { $template = $this->getTemplate($tpl, $template); $fields[‘_tpl’] = $template[$tpl]; } else { $rowtpl = $tpl; } $template = $this->getTemplate($rowtpl, $template); if ($template[$rowtpl]) { $chunk = $modx->newObject(‘modChunk’); $chunk->setCacheable(false); $chunk->setContent($template[$rowtpl]); if (!empty($placeholdersKeyField) && isset($fields[$placeholdersKeyField])) { $output[$fields[$placeholdersKeyField]] = $chunk->process($fields); } else { $output[] = $chunk->process($fields); } } else { if (!empty($placeholdersKeyField)) { $output[$fields[$placeholdersKeyField]] = ‘<pre>’ . print_r($fields, 1) . ‘</pre>’; } else { $output[] = ‘<pre>’ . print_r($fields, 1) . ‘</pre>’; } } $i++; } } } if ($toJsonPlaceholder) { $modx->setPlaceholder($toJsonPlaceholder, json_encode($output)); return »; } if ($toJson) { return json_encode($output,$jsonOptions); } if (!empty($toSeparatePlaceholders)) { $modx->toPlaceholders($output, $toSeparatePlaceholders); return »; } if (is_array($output)) { $o = implode($outputSeparator, $output); } else { $o = $output; } if (!empty($o) && !empty($wrapperTpl)) { $template = $this->getTemplate($wrapperTpl); if ($template[$wrapperTpl]) { $chunk = $modx->newObject(‘modChunk’); $chunk->setCacheable(false); $chunk->setContent($template[$wrapperTpl]); $properties[‘output’] = $o; $o = $chunk->process($properties); } } if (empty($o) && !empty($emptyTpl)) { $template = $this->getTemplate($emptyTpl); if ($template[$emptyTpl]) { $chunk = $modx->newObject(‘modChunk’); $chunk->setCacheable(false); $chunk->setContent($template[$emptyTpl]); $o = $chunk->process($properties); } } if (!empty($toPlaceholder)) { $modx->setPlaceholder($toPlaceholder, $o); return »; } return $o; } function findProcessor($processorspath, $filename, &$filenames) { $result = $this->findCustomFile($processorspath, $filename, $filenames); if (!$result){ $filename = strtolower($filename); $result = $this->findCustomFile($processorspath, $filename, $filenames); } return $result; } function findGrid($processorspath, $filename, &$filenames) { return $this->findCustomFile($processorspath, $filename, $filenames, ‘grids’); } function findCustomFile($defaultpath, $filename, &$filenames, $type = ‘processors’) { $config = $this->customconfigs; $packageName = $this->modx->getOption(‘packageName’, $config); $packageName = explode(‘,’, $packageName); $packageName = $packageName[0]; $task = $this->getTask(); if (!empty($packageName)) { $packagepath = $this->findPackagePath($packageName); switch ($type) { case ‘processors’: $path = $packagepath . ‘processors/mgr/’; if (!empty($task)) { $filepath = $path . $task . ‘/’ . $filename; $filenames[] = $filepath; if (file_exists($filepath)) { return $filepath; } } $filepath = $path . ‘default/’ . $filename; $filenames[] = $filepath; if (file_exists($filepath)) { return $filepath; } break; case ‘grids’: $path = $packagepath . ‘migxtemplates/mgr/grids/’; $filepath = $path . ‘/’ . $filename; $filenames[] = $filepath; if (file_exists($filepath)) { return $filepath; } break; } } switch ($type) { case ‘processors’: if (!empty($task)) { $filepath = $defaultpath . $task . ‘/’ . $filename; $filenames[] = $filepath; $found = false; if (file_exists($filepath)) { return $filepath; } } $filepath = $defaultpath . ‘default/’ . $filename; $filenames[] = $filepath; if (file_exists($filepath)) { return $filepath; } break; case ‘grids’: default: $filepath = $defaultpath . $filename; $filenames[] = $filepath; if (file_exists($filepath)) { return $filepath; } break; } return false; } function checkMultipleForms($formtabs, &$controller, &$allfields, &$record) { $multiple_formtabs = $this->modx->getOption(‘multiple_formtabs’, $this->customconfigs, »); $multiple_formtabs_label = $this->modx->getOption(‘multiple_formtabs_label’, $this->customconfigs, ‘Formname’); $multiple_formtabs_field = $this->modx->getOption(‘multiple_formtabs_field’, $this->customconfigs, ‘MIGX_formname’); $controller->setPlaceholder(‘multiple_formtabs_label’, $multiple_formtabs_label); if (!empty($multiple_formtabs)) { if (isset($_REQUEST[‘loadaction’]) && $_REQUEST[‘loadaction’] == ‘switchForm’) { $data = $this->modx->fromJson($this->modx->getOption(‘record_json’, $_REQUEST, »)); if (is_array($data) && isset($data[$multiple_formtabs_field])) { $record = array_merge($record, $data); } } $mf_configs = explode(‘||’, $multiple_formtabs); $classname = ‘migxConfig’; $c = $this->modx->newQuery($classname); $c->select($this->modx->getSelectColumns($classname, $c->getAlias())); $c->where(array(‘id:IN’ => $mf_configs)); $c->sortby(‘FIELD(‘ . $classname . ‘.id, ‘ . implode(‘,’, $mf_configs) . ‘)’); $formnames = array(); if ($collection = $this->modx->getCollection($classname, $c)) { $idx = 0; $formtabs = false; $firstformtabs = array(); foreach ($collection as $object) { $ext = $object->get(‘extended’); $text = $this->modx->getOption(‘multiple_formtabs_optionstext’, $ext, »); $value = $this->modx->getOption(‘multiple_formtabs_optionsvalue’, $ext, »); $formname = array(); $formname[‘value’] = !empty($value) ? $value : $object->get(‘name’); $formname[‘text’] = !empty($text) ? $text : $object->get(‘name’); $formname[‘selected’] = 0; if ($idx == 0) { $firstformtabs = $this->modx->fromJson($object->get(‘formtabs’)); } if (isset($record[$multiple_formtabs_field]) && $record[$multiple_formtabs_field] == $formname[‘value’]) { $formname[‘selected’] = 1; $formtabs = $this->modx->fromJson($object->get(‘formtabs’)); } $formnames[] = $formname; $idx++; /* foreach ($form[‘formtabs’] as $tab) { $tabs[$form[‘formname’]][] = $tab; } */ } $formtabs = $formtabs ? $formtabs : $firstformtabs; $config = $this->customconfigs; $hooksnippets = $this->modx->fromJson($this->modx->getOption(‘hooksnippets’, $config, »)); if (is_array($hooksnippets)) { $hooksnippet = $this->modx->getOption(‘getformnames’, $hooksnippets, »); if (!empty($hooksnippet)) { $snippetProperties = array(); $snippetProperties[‘formnames’] = &$formnames; $result = $this->modx->runSnippet($hooksnippet, $snippetProperties); } } $controller->setPlaceholder(‘formnames’, $formnames); $field = array(); $field[‘field’] = $multiple_formtabs_field; $field[‘tv_id’] = ‘Formname’; $allfields[] = $field; } } return $formtabs; } function loadConfigs($grid = true, $other = true, $properties = array(), $sender = ») { $winbuttons = array(); $gridactionbuttons = array(); $gridcolumnbuttons = array(); $gridcontextmenus = array(); $gridfunctions = array(); $winfunctions = array(); $renderer = array(); $editors = array(); $gridfilters = array(); $configs = array(‘migx_default’); //$configs = array(); if (isset($properties[‘configs’]) && !empty($properties[‘configs’])) { $configs = explode(‘,’, $properties[‘configs’]); } elseif (isset($this->config[‘configs’]) && !empty($this->config[‘configs’])) { $configs = explode(‘,’, $this->config[‘configs’]); } $tempParams = $this->modx->getOption(‘tempParams’, $properties, »); if (!empty($configs)) { //$configs = (isset($this->config[‘configs’])) ? explode(‘,’, $this->config[‘configs’]) : array(); //$configs = array_merge( array (‘master’), $configs); if ($grid) { $configFile = $this->config[‘corePath’] . ‘configs/grid/grid.config.inc.php’; // [ file ] if (file_exists($configFile)) { include ($configFile); } //custom collection of grid-functions…… — deprecated $configFile = $this->config[‘corePath’] . ‘configs/grid/grid.custom.config.inc.php’; // [ file ] if (file_exists($configFile)) { include ($configFile); } } //get migxconfig-specific grid-configs $req_configs = $this->modx->getOption(‘configs’, $_REQUEST, »); $preloadGridConfigs = false; if ($sender == ‘mgr/fields’ && ($req_configs == ‘migxcolumns’ || $req_configs == ‘migxdbfilters’)) { $preloadGridConfigs = true; $configs_id = $this->modx->getOption(‘co_id’, $_REQUEST, »); $this->configsObject = $this->modx->getObject(‘migxConfig’, $configs_id); } if ($sender == ‘migxconfigs/fields’) { $preloadGridConfigs = true; } if ($preloadGridConfigs && is_Object($this->configsObject)) { $config = $this->configsObject->get(‘name’); $configFile = $this->config[‘corePath’] . ‘configs/grid/grid.’ . $config . ‘.config.inc.php’; // [ file ] if (file_exists($configFile)) { include ($configFile); } //package-specific $extended = $this->configsObject->get(‘extended’); $packageName = $this->modx->getOption(‘packageName’, $extended, »); if (!empty($packageName)) { $packageName = explode(‘,’, $packageName); $packageName = $packageName[0]; $packagepath = $this->findPackagePath($packageName); $configFile = $packagepath . ‘migxconfigs/grid/grid.’ . $config . ‘.config.inc.php’; // [ file ] if (file_exists($configFile)) { include ($configFile); } $configFile = $packagepath . ‘migxconfigs/grid/grid.config.inc.php’; // [ file ] if (file_exists($configFile)) { include ($configFile); } } } if ($tempParams == ‘importcsv’) { $configs[] = ‘importcsv’; } if ($tempParams == ‘exportcsv’) { $configs[] = ‘exportcsv’; } foreach ($configs as $config) { $parts = explode(‘:’, $config); $cfObject = false; if (isset($parts[1])) { $config = $parts[0]; $packageName = $parts[1]; } elseif ($cfObject = $this->modx->getObject(‘migxConfig’, array(‘name’ => $config, ‘deleted’ => ‘0’))) { $extended = $cfObject->get(‘extended’); $packageName = $this->modx->getOption(‘packageName’, $extended, »); } if (isset($packageName)) { $packageName = explode(‘,’, $packageName); $packageName = $packageName[0]; $packagepath = $this->findPackagePath($packageName); $configpath = $packagepath . ‘migxconfigs/’; } if ($grid) { //first try to find custom-grid-configurations (buttons,context-menus,functions) $configFile = $this->config[‘corePath’] . ‘configs/grid/grid.’ . $config . ‘.config.inc.php’; // [ file ] if (file_exists($configFile)) { include ($configFile); } if (!empty($packageName)) { $configFile = $configpath . ‘grid/grid.’ . $config . ‘.config.inc.php’; // [ file ] if (file_exists($configFile)) { include ($configFile); } $configFile = $configpath . ‘grid/grid.config.inc.php’; // [ file ] if (file_exists($configFile)) { include ($configFile); } } } if ($other) { //second try to find config-object if (isset($configpath) && !$cfObject && file_exists($configpath . $config . ‘.config.js’)) { $filecontent = @file_get_contents($configpath . $config . ‘.config.js’); $objectarray = $this->importconfig($this->modx->fromJson($filecontent)); $this->prepareConfigsArray($objectarray, $gridactionbuttons, $gridcontextmenus, $gridcolumnbuttons, $winbuttons); } if ($cfObject) { $objectarray = $cfObject->toArray(); $this->prepareConfigsArray($objectarray, $gridactionbuttons, $gridcontextmenus, $gridcolumnbuttons, $winbuttons); } //and from MIGX config folder $configFile = $this->config[‘corePath’] . ‘configs/’ . $config . ‘.config.js’; // [ file ] if (file_exists($configFile)) { $filecontent = @file_get_contents($configFile); $objectarray = $this->importconfig($this->modx->fromJson($filecontent)); if (isset($objectarray[‘name’]) && ($objectarray[‘name’] == ‘importcsv’ || $objectarray[‘name’] == ‘exportcsv’)){ if (isset($this->customconfigs[‘win_id’])){ $objectarray[‘extended’][‘win_id’] = $this->customconfigs[‘win_id’]; } } $this->prepareConfigsArray($objectarray, $gridactionbuttons, $gridcontextmenus, $gridcolumnbuttons, $winbuttons); } if (!isset($objectarray) || !is_array($objectarray)){ //get some default configs, if not allready done $objectarray = array(); $this->prepareConfigsArray($objectarray, $gridactionbuttons, $gridcontextmenus, $gridcolumnbuttons, $winbuttons); } //third add configs from file, if exists $configFile = $this->config[‘corePath’] . ‘configs/’ . $config . ‘.config.inc.php’; // [ file ] if (file_exists($configFile)) { include ($configFile); } if (!empty($packageName)) { $configFile = $configpath . $config . ‘.config.inc.php’; // [ file ] if (file_exists($configFile)) { include ($configFile); } } } //print_r($this->customconfigs[‘tabs’]) ; } } if (isset($this->customconfigs[‘filters’]) && is_array($this->customconfigs[‘filters’]) && count($this->customconfigs[‘filters’]) > 0) { foreach ($this->customconfigs[‘filters’] as $filter) { if (isset($gridfilters[$filter[‘type’]]) && is_array($gridfilters[$filter[‘type’]])) { $this->customconfigs[‘gridfilters’][$filter[‘name’]] = array_merge($filter, $gridfilters[$filter[‘type’]]); } } } $this->customconfigs[‘gridactionbuttons’] = $gridactionbuttons; $this->customconfigs[‘gridcontextmenus’] = $gridcontextmenus; $this->customconfigs[‘gridcolumnbuttons’] = $gridcolumnbuttons; $this->customconfigs[‘gridfunctions’] = array_merge($gridfunctions, $renderer, $editors); $this->customconfigs[‘winfunctions’] = $winfunctions; $this->customconfigs[‘windowbuttons’] = $winbuttons; //$defaulttask = empty($this->customconfigs[‘join_alias’]) ? ‘default’ : ‘default_join’; $defaulttask = ‘default’; $this->customconfigs[‘task’] = empty($this->customconfigs[‘task’]) ? $defaulttask : $this->customconfigs[‘task’]; } public function prepareConfigsArray($objectarray, &$gridactionbuttons, &$gridcontextmenus, &$gridcolumnbuttons, &$winbuttons) { if (isset($objectarray[‘extended’]) && is_array($objectarray[‘extended’])) { foreach ($objectarray[‘extended’] as $key => $value) { if (!empty($value)) { $this->customconfigs[$key] = $value; } } } unset($objectarray[‘extended’]); if (isset($this->customconfigs)) { $this->customconfigs = is_array($this->customconfigs) ? array_merge($this->customconfigs, $objectarray) : $objectarray; $this->customconfigs[‘tabs’] = isset($objectarray[‘formtabs’]) ? $this->modx->fromJson($objectarray[‘formtabs’]) : array(); $this->customconfigs[‘filters’] = isset($objectarray[‘filters’]) ? $this->modx->fromJson($objectarray[‘filters’]) : array(); //$this->customconfigs[‘tabs’] = stripslashes($cfObject->get(‘formtabs’)); //$this->customconfigs[‘columns’] = $this->modx->fromJson(stripslashes($cfObject->get(‘columns’))); $this->customconfigs[‘columns’] = isset($objectarray[‘columns’]) ? $this->modx->fromJson($objectarray[‘columns’]) : array(); } $menus = isset($objectarray[‘contextmenus’]) ? $objectarray[‘contextmenus’] : »; if (!empty($menus)) { $menus = explode(‘||’, $menus); foreach ($menus as $menu) { $gridcontextmenus[$menu][‘active’] = 1; } } $columnbuttons = isset($objectarray[‘columnbuttons’]) ? $objectarray[‘columnbuttons’] : »; if (!empty($columnbuttons)) { $columnbuttons = explode(‘||’, $columnbuttons); foreach ($columnbuttons as $button) { if (isset($gridcontextmenus[$button])) { $gridcolumnbuttons[$button] = $gridcontextmenus[$button]; $gridcolumnbuttons[$button][‘active’] = 1; } } } $actionbuttons = isset($objectarray[‘actionbuttons’]) ? $objectarray[‘actionbuttons’] : »; if (!empty($actionbuttons)) { $actionbuttons = explode(‘||’, $actionbuttons); foreach ($actionbuttons as $button) { $gridactionbuttons[$button][‘active’] = 1; } } $winbuttonslist = null; if (isset($this->customconfigs[‘winbuttonslist’])) { $winbuttonslist = $this->customconfigs[‘winbuttonslist’]; if (!empty($winbuttonslist)) { $winbuttonslist = explode(‘||’, $winbuttonslist); foreach ($winbuttonslist as $button) { $winbuttons[$button][‘active’] = 1; } } } if (!is_array($winbuttonslist)){ foreach ($winbuttons as $key =>$button){ if (isset($button[‘default’]) && !empty($button[‘default’])){ $winbuttons[$key][‘active’] = 1; } } } } function loadPackageManager() { include_once ($this->config[‘modelPath’] . ‘migx/migxpackagemanager.class.php’); return new MigxPackageManager($this->modx); } public function getTask() { return isset($this->customconfigs[‘task’]) ? $this->customconfigs[‘task’] : »; } public function getTabs() { return isset($this->customconfigs[‘tabs’]) ? $this->customconfigs[‘tabs’] : »; } public function getColumns() { return isset($this->customconfigs[‘columns’]) ? $this->customconfigs[‘columns’] : »; } public function getGrid() { return !empty($this->customconfigs[‘grid’]) ? $this->customconfigs[‘grid’] : ‘default’; } public function prepareCmpTabs($properties, &$controller, &$tv) { $cmptabs = (isset($this->config[‘cmptabs’])) ? explode(‘||’, $this->config[‘cmptabs’]) : array(); $cmptabsout = array(); $grids = »; $updatewindows = »; $iframewindows = »; $customHandlers = array(); $maincaption = «_(‘migx.management’)«; if (count($cmptabs) > 0) { foreach ($cmptabs as $tab_idx => $tab) { $this->customconfigs = array(); $this->config[‘configs’] = $tab; $properties[‘tv_id’] = $tab_idx + 1; $this->prepareGrid($properties, $controller, $tv); $tabcaption = empty($this->customconfigs[‘cmptabcaption’]) ? ‘undefined’ : $this->customconfigs[‘cmptabcaption’]; $tabdescription = empty($this->customconfigs[‘cmptabdescription’]) ? ‘undefined’ : $this->customconfigs[‘cmptabdescription’]; $maincaption = empty($this->customconfigs[‘cmpmaincaption’]) ? $maincaption : «» . $this->replaceLang($this->customconfigs[‘cmpmaincaption’]) . ««; $controller->setPlaceholder(‘config’, $this->config); $controller->setPlaceholder(‘cmptabcaption’, $tabcaption); $controller->setPlaceholder(‘cmptabdescription’, $tabdescription); $cmptabfile = $this->config[‘templatesPath’] . ‘mgr/cmptab.tpl’; if (!empty($this->customconfigs[‘cmptabcontroller’])) { $controllerfile = $this->config[‘controllersPath’] . ‘custom/’ . $this->customconfigs[‘cmptabcontroller’] . ‘.php’; if (file_exists($controllerfile)) { $tabTemplate = »; include ($controllerfile); if (!empty($tabTemplate) && file_exists($tabTemplate)) { $cmptabfile = $tabTemplate; } } } $cmptabsout[] = $this->replaceLang($controller->fetchTemplate($cmptabfile)); $grid = $this->getGrid(); $filenames = array(); $defaultpath = $this->config[‘templatesPath’] . ‘/mgr/grids/’; $filename = $grid . ‘.grid.tpl’; if ($gridfile = $this->findGrid($defaultpath, $filename, $filenames)) { $grids .= $this->replaceLang($controller->fetchTemplate($gridfile)); } //$gridfile = $this->config[‘templatesPath’] . ‘/mgr/grids/’ . $grid . ‘.grid.tpl’; //$windowfile = $this->config[‘templatesPath’] . ‘mgr/updatewindow.tpl’; //$updatewindows .= $this->replaceLang($controller->fetchTemplate($windowfile)); $filenames = array(); $defaultpath = $this->config[‘templatesPath’] . ‘mgr/’; $filename = ‘updatewindow.tpl’; if ($gridfile = $this->findGrid($defaultpath, $filename, $filenames)) { $updatewindows .= $this->replaceLang($controller->fetchTemplate($gridfile)); } $filenames = array(); $filename = ‘iframewindow.tpl’; if ($windowfile = $this->findGrid($defaultpath, $filename, $filenames)) { $iframewindows .= $this->replaceLang($controller->fetchTemplate($windowfile)); } } } if (count($customHandlers) > 0) { $customHandlers = implode(‘,’, $customHandlers); $controller->setPlaceholder(‘customHandlers’, $customHandlers); } $controller->setPlaceholder(‘maincaption’, $maincaption); $controller->setPlaceholder(‘grids’, $grids); $controller->setPlaceholder(‘updatewindows’, $updatewindows); $controller->setPlaceholder(‘iframewindows’, $iframewindows); $controller->setPlaceholder(‘cmptabs’, implode(‘,’, $cmptabsout)); return $controller->fetchTemplate($this->config[‘templatesPath’] . ‘mgr/gridpanel.tpl’); } public function loadLang($prefix = ‘migx’) { $lang = $this->modx->lexicon->fetch($prefix); if (is_array($lang)) { $this->migxlang = isset($this->migxlang) && is_array($this->migxlang) ? array_merge($this->migxlang, $lang) : $lang; //$this->migxi18n = array(); foreach ($lang as $key => $value) { $this->addLangValue($key, $value); } } } public function addLangValue($key, $value) { //$key = str_replace(‘migx.’, ‘migx_’, $key); //$this->migxi18n[$key] = $value; $this->langSearch[$key] = ‘[[%’ . $key . ‘]]’; $this->langReplace[$key] = $value; } public function replaceLang($value, $debug = false) { if ($debug) { echo str_replace($this->langSearch, $this->langReplace, $value); } if (isset($this->langSearch) && isset($this->langReplace)) { $value = str_replace($this->langSearch, $this->langReplace, $value); } return $value; } public function prepareGrid($properties, &$controller, &$tv, $columns = array()) { $this->loadConfigs(false); //$lang = $this->modx->lexicon->fetch(); $resource = is_object($this->modx->resource) ? $this->modx->resource->toArray() : array(); $resource[‘id’] = $this->config[‘resource_id’] = $this->modx->getOption(‘id’, $resource, »); $this->config[‘connected_object_id’] = $this->modx->getOption(‘object_id’, $_REQUEST, »); $this->config[‘req_configs’] = $this->modx->getOption(‘configs’, $_REQUEST, »); if (isset($this->customconfigs[‘media_source_id’])) { $this->config[‘media_source_id’] = $this->customconfigs[‘media_source_id’]; } else { $this->config[‘media_source_id’] = is_object($this->source) ? $this->source->id : $this->getDefaultSource(‘id’); } if (is_object($tv)) { $win_id = $tv->get(‘id’); $tv_type = $tv->get(‘type’); } else { $tv_type = »; $win_id = ‘migxdb’; $tv = $this->modx->newObject(‘modTemplateVar’); $controller->setPlaceholder(‘tv’, $tv); } $this->customconfigs[‘win_id’] = !empty($this->customconfigs[‘win_id’]) ? $this->customconfigs[‘win_id’] : $win_id; $tv_id = $tv->get(‘id’); $tv_id = empty($tv_id) && isset($properties[‘tv_id’]) ? $properties[‘tv_id’] : $tv_id; $this->config[‘tv_id’] = $tv_id; $search = array(); $replace = array(); foreach ($this->config as $key => $value) { if (!is_array($value)) { $replace[‘config_’ . $key] = $value; $search[‘config_’ . $key] = ‘[[+config.’ . $key . ‘]]’; } } foreach ($this->customconfigs as $key => $value) { if (!is_array($value)) { $replace[‘config_’ . $key] = $value; $search[‘config_’ . $key] = ‘[[+config.’ . $key . ‘]]’; } } $this->migxlang[‘migx.add’] = isset($this->migxlang[‘migx.add’]) ? $this->migxlang[‘migx.add’] : ‘Add Item’; $l[‘migx.add’] = !empty($this->customconfigs[‘migx_add’]) ? $this->customconfigs[‘migx_add’] : $this->migxlang[‘migx.add’]; $l[‘migx.add’] = str_replace(««, ««, $l[‘migx.add’]); $this->addLangValue(‘migx.add’, $l[‘migx.add’]); $this->loadConfigs(); $handlers = array(); if (isset($this->customconfigs[‘extrahandlers’])) { $extrahandlers = explode(‘||’, $this->customconfigs[‘extrahandlers’]); foreach ($extrahandlers as $handler) { $handlers[] = $handler; } } //winbuttons $winbuttons = »; if (isset($this->customconfigs[‘windowbuttons’])) { if (is_array($this->customconfigs[‘windowbuttons’]) && count($this->customconfigs[‘windowbuttons’]) > 0) { $buttons_a = array(); foreach ($this->customconfigs[‘windowbuttons’] as $button) { if (!empty($button[‘active’])) { unset($button[‘active’]); if (isset($button[‘handler’])) { $handlerarr = explode(‘,’, $button[‘handler’]); foreach ($handlerarr as $handler) { if (!in_array($handler, $handlers)) { $handlers[] = $handler; } } } $buttons_a[] = str_replace(‘»‘, », json_encode($button)); } } if (count($buttons_a) > 0) { $winbuttons = ‘,buttons:[‘ . implode(‘,’, $buttons_a) . ‘]’; } } } $this->customconfigs[‘winbuttons’] = $winbuttons; $buttons = array(); if (count($this->customconfigs[‘gridactionbuttons’]) > 0) { foreach ($this->customconfigs[‘gridactionbuttons’] as $button) { if (!empty($button[‘active’])) { unset($button[‘active’]); if (isset($button[‘handler’])) { $handlerarr = explode(‘,’, $button[‘handler’]); $button[‘handler’] = $handlerarr[0]; //can have only one handler, use the first one //load one or multiple handlers foreach ($handlerarr as $handler) { if (!in_array($handler, $handlers)) { $handlers[] = $handler; } } } if (isset($button[‘menu’]) && is_array($button[‘menu’])) { foreach ($button[‘menu’] as $menu) { if (!in_array($menu[‘handler’], $handlers)) { $handlers[] = $menu[‘handler’]; } } } //$button[‘text’] = $this->replaceLang($button[‘text’]); $standalone = $this->modx->getOption(‘standalone’, $button, »); if (!empty($standalone)) { $gridbuttons[] = str_replace(‘»‘, », json_encode($button)); } else { $buttons[] = str_replace(‘»‘, », json_encode($button)); } } } } $filters = array(); $filterDefaults = array(); if (isset($this->customconfigs[‘gridfilters’]) && count($this->customconfigs[‘gridfilters’]) > 0) { foreach ($this->customconfigs[‘gridfilters’] as $filter) { if (isset($filter[‘comboparent’]) && !empty($filter[‘comboparent’])) { $combochilds[$filter[‘comboparent’]][$filter[‘name’]] = $filter[‘name’]; } } foreach ($this->customconfigs[‘gridfilters’] as $filter) { $filter[’emptytext’] = empty($filter[’emptytext’]) ? ‘migx.search’ : $filter[’emptytext’]; $filter[’emptytext’] = str_replace(array(‘[[%’, ‘]]’), », $this->replaceLang(‘[[%’ . $filter[’emptytext’] . ‘]]’)); $filter[‘combochilds’] = ‘[]’; if (isset($combochilds[$filter[‘name’]])) { $filter[‘combochilds’] = json_encode(array_values($combochilds[$filter[‘name’]])); //print_r($filter); } foreach ($filter as $key => $value) { if (!is_array($value)) { $replace[$key] = $value; $search[$key] = ‘[[+’ . $key . ‘]]’; } } $filtername = $filter[‘handler’] . ‘_’ . $filter[‘name’]; if (isset($this->customconfigs[‘gridfunctions’][$filter[‘handler’]])) { $this->customconfigs[‘gridfunctions’][$filtername] = str_replace($search, $replace, $this->customconfigs[‘gridfunctions’][$filter[‘handler’]]); } $filters[] = str_replace($search, $replace, $filter[‘code’]); if (!in_array($filtername, $handlers)) { $handlers[] = $filtername; } $default = array(); $default[‘name’] = $filter[‘name’]; $default[‘default’] = isset($filter[‘default’]) ? $filter[‘default’] : »; if (isset($_REQUEST[‘filter_’ . $filter[‘name’]])) { $default[‘default’] = $this->modx->sanitizeString($_REQUEST[‘filter_’ . $filter[‘name’]]); } $filterDefaults[] = $default; } } $this->customconfigs[‘tbar’] = »; $tbaritems = array(); $tbaractions = array(); if (isset($gridbuttons) && count($gridbuttons) > 0) { $gridbuttons = implode(‘,’, $gridbuttons); $tbaractions[] = $gridbuttons; } if (isset($buttons) && count($buttons) > 0) { $gridactionbuttons = implode(‘,’, $buttons); $perRow = $this->modx->getOption(‘actionbuttonsperrow’, $this->customconfigs, ‘4’); $tbaractions[] = « { xtype: ‘buttongroup’, title: ‘[[%migx.actions]]’, columns: {$perRow}, defaults: { scale: ‘large’ }, items: [{$gridactionbuttons}] } «; } if (count($tbaractions) > 0) { $tbaritems[] = implode(‘,’, $tbaractions); } $tbarfilters = array(); if (count($filters) > 0) { $gridfilters = implode(‘,’, $filters); $perRow = $this->modx->getOption(‘filtersperrow’, $this->customconfigs, ‘4’); $tbarfilters[] = « { xtype: ‘buttongroup’, title: ‘[[%migx.filters]]’, columns: {$perRow}, defaults: { scale: ‘large’ }, items: [{$gridfilters}] } «; } if (count($tbarfilters) > 0) { $tbaritems[] = implode(‘,’, $tbarfilters); } if (count($tbaritems) > 0) { $this->customconfigs[‘tbar’] = implode(‘,’, $tbaritems); } $menues = »; if (count($this->customconfigs[‘gridcontextmenus’]) > 0) { foreach ($this->customconfigs[‘gridcontextmenus’] as $menue) { if (!empty($menue[‘active’])) { unset($menue[‘active’]); if (!empty($menue[‘handler’])) { $handlerarr = explode(‘,’, $menue[‘handler’]); foreach ($handlerarr as $handler) { if (!in_array($handler, $handlers)) { $handlers[] = $handler; } } } //$menues .= $this->replaceLang($menue[‘code’]); $menues .= $menue[‘code’]; } } } if ($tv_type == ‘migx’ && empty($menues)) { //default context-menues for migx $menues = « m.push({ text: ‘[[%migx.edit]]’ ,handler: this.migx_update }); m.push({ text: ‘[[%migx.duplicate]]’ ,handler: this.migx_duplicate }); m.push(‘-‘); m.push({ text: ‘[[%migx.remove]]’ ,handler: this.migx_remove }); m.push(‘-‘); m.push({ text: ‘[[%migx.move_to_top]]’ ,handler: this.moveToTop }); m.push({ text: ‘[[%migx.move_to_bottom]]’ ,handler: this.moveToBottom }); «; } $this->customconfigs[‘gridcontextmenus’] = $menues; $columnbuttons = »; if (count($this->customconfigs[‘gridcolumnbuttons’]) > 0) { foreach ($this->customconfigs[‘gridcolumnbuttons’] as $button) { if (!empty($button[‘active’])) { unset($button[‘active’]); if (!empty($button[‘handler’])) { $handlerarr = explode(‘,’, $button[‘handler’]); foreach ($handlerarr as $handler) { if (!in_array($handler, $handlers)) { $handlers[] = $handler; } } } //$menues .= $this->replaceLang($menue[‘code’]); $columnbuttons .= $button[‘code’]; } } } $this->customconfigs[‘gridcolumnbuttons’] = $columnbuttons; $gridfunctions = array(); $default_formtabs = ‘[{«caption»:»Default», «fields»: [{«field»:»title»,»caption»:»Title»}]}]’; $default_columns = ‘[{«header»: «Title», «width»: «160», «sortable»: «true», «dataIndex»: «title»}]’; $formtabs = $this->getTabs(); if (empty($formtabs)) { // get them from input-properties $formtabs = $this->modx->fromJSON($this->modx->getOption(‘formtabs’, $properties, $default_formtabs)); $formtabs = empty($properties[‘formtabs’]) ? $this->modx->fromJSON($default_formtabs) : $formtabs; } //$this->migx->debug(‘resource’,$resource); //multiple different Forms // Note: use same field-names and inputTVs in all forms $inputTvs = $this->extractFieldsFromTabs($formtabs); /* get base path based on either TV param or filemanager_path */ //$this->modx->getService(‘fileHandler’, ‘modFileHandler’, », array(‘context’ => $this->modx->context->get(‘key’))); /* pasted from processors.element.tv.renders.mgr.input*/ /* get working context */ $wctx = isset($_GET[‘wctx’]) && !empty($_GET[‘wctx’]) ? $this->modx->sanitizeString($_GET[‘wctx’]) : »; if (!empty($wctx)) { $workingContext = $this->modx->getContext($wctx); if (!$workingContext) { return $this->modx->error->failure($this->modx->lexicon(‘permission_denied’)); } $wctx = $workingContext->get(‘key’); } else { $wctx = $this->modx->context->get(‘key’); } $this->working_context = $wctx; if (is_object($tv)) { $this->source = $tv->getSource($this->working_context, false); } /* pasted end*/ //$base_path = $modx->getOption(‘base_path’, null, MODX_BASE_PATH); //$base_url = $modx->getOption(‘base_url’, null, MODX_BASE_URL); //$columns = $this->modx->fromJSON($this->modx->getOption(‘columns’, $properties, $default_columns)); //$columns = empty($properties[‘columns’]) ? $this->modx->fromJSON($default_columns) : $columns; $columns = empty($columns) ? $this->getColumns() : $columns; $item = array(); $pathconfigs = array(); $cols = array(); $fields = array(); $colidx = 0; if (is_array($columns) && count($columns) > 0) { foreach ($columns as $key => $column) { $field = array(); if (isset($column[‘type’])) { $field[‘type’] = $column[‘type’]; } $field[‘name’] = $column[‘dataIndex’]; $field[‘mapping’] = $column[‘dataIndex’]; $fields[] = $field; $column[‘show_in_grid’] = isset($column[‘show_in_grid’]) ? (int)$column[‘show_in_grid’] : 1; $fieldconfig = $this->modx->getOption($field[‘name’], $inputTvs, »); if (!empty($column[‘show_in_grid’])) { $col = array(); $col[‘dataIndex’] = $column[‘dataIndex’]; $col[‘header’] = htmlentities($this->replaceLang($column[‘header’]), ENT_QUOTES, $this->modx->getOption(‘modx_charset’)); $col[‘sortable’] = isset($column[‘sortable’]) && $column[‘sortable’] == ‘true’ ? true : false; if (isset($column[‘width’]) && !empty($column[‘width’])) { $col[‘width’] = (int)$column[‘width’]; } if (isset($column[‘renderer’]) && !empty($column[‘renderer’])) { $col[‘renderer’] = $column[‘renderer’]; $handlers[] = $column[‘renderer’]; } if (isset($column[‘editor’]) && !empty($column[‘editor’])) { $col[‘editor’] = $column[‘editor’]; $handlers[] = $column[‘editor’]; } $cols[] = $col; $pathconfigs[$colidx] = isset($inputTvs[$field[‘name’]]) ? $this->prepareSourceForGrid($inputTvs[$field[‘name’]]) : array(); $colidx++; } $default = isset($fieldconfig[‘default’]) ? (string )$fieldconfig[‘default’] : »; $item[$field[‘name’]] = isset($column[‘default’]) ? $column[‘default’] : $default; } } $newitem[] = $item; $gf = »; $wf = »; if (count($handlers) > 0) { $gridfunctions = array(); $winfunctions = array(); $collectedhandlers = array(); foreach ($handlers as $handler) { if (!in_array($handler, $collectedhandlers) && isset($this->customconfigs[‘gridfunctions’][$handler])) { $gridfunction = $this->customconfigs[‘gridfunctions’][$handler]; if (!empty($gridfunction)) { $collectedhandlers[] = $handler; $gridfunctions[] = $gridfunction; } } if (!in_array($handler, $collectedhandlers) && isset($this->customconfigs[‘winfunctions’][$handler])) { $winfunction = $this->customconfigs[‘winfunctions’][$handler]; if (!empty($winfunction)) { $collectedhandlers[] = $handler; $winfunctions[] = $winfunction; } } } if (count($gridfunctions) > 0) { $gf = ‘,’ . str_replace($search, $replace, implode(‘,’, $gridfunctions)); $gf = str_replace(‘[[+newitem]]’, json_encode($newitem), $gf); } if (count($winfunctions) > 0) { $wf = ‘,’ . str_replace($search, $replace, implode(‘,’, $winfunctions)); } } $this->customconfigs[‘gridfunctions’] = $gf; $this->customconfigs[‘winfunctions’] = $wf; //print_r(array_keys($this->customconfigs)); //$controller->setPlaceholder(‘i18n’, $this->migxi18n); $tv_caption = $tv->get(‘caption’); $tv_name = $tv->get(‘name’); $default_win_title = !empty($tv_name) ? $tv_name : ‘MIGX’; $default_win_title = !empty($tv_caption) ? $tv_caption : $default_win_title; $controller->setPlaceholder(‘filterDefaults’, json_encode($filterDefaults)); $controller->setPlaceholder(‘tv_id’, $tv_id); $controller->setPlaceholder(‘migx_lang’, json_encode($this->migxlang)); $controller->setPlaceholder(‘properties’, $properties); $controller->setPlaceholder(‘resource’, $resource); $controller->setPlaceholder(‘configs’, $this->modx->getOption(‘configs’, $this->config, »)); $controller->setPlaceholder(‘reqConfigs’, $this->modx->getOption(‘configs’, $_REQUEST, »)); $controller->setPlaceholder(‘object_id’, $this->modx->getOption(‘object_id’, $_REQUEST, »)); $controller->setPlaceholder(‘reqTempParams’, $this->modx->getOption(‘tempParams’, $_REQUEST, »)); $controller->setPlaceholder(‘connected_object_id’, $this->modx->getOption(‘object_id’, $_REQUEST, »)); $controller->setPlaceholder(‘window_id’, $this->modx->getOption(‘window_id’, $_REQUEST, »)); $controller->setPlaceholder(‘pathconfigs’, json_encode($pathconfigs)); $controller->setPlaceholder(‘columns’, json_encode($cols)); $controller->setPlaceholder(‘fields’, json_encode($fields)); $controller->setPlaceholder(‘newitem’, json_encode($newitem)); $controller->setPlaceholder(‘base_url’, $this->modx->getOption(‘base_url’)); $controller->setPlaceholder(‘myctx’, $wctx); $controller->setPlaceholder(‘auth’, $_SESSIONmodx.{$this->modx->context->get(‘key’)}.user.token«]); $controller->setPlaceholder(‘customconfigs’, $this->customconfigs); $controller->setPlaceholder(‘win_id’, $this->customconfigs[‘win_id’]); $controller->setPlaceholder(‘update_win_title’, !empty($this->customconfigs[‘update_win_title’]) ? $this->customconfigs[‘update_win_title’] : $default_win_title); } function getColumnRenderOptions($col = ‘*’, $indexfield = ‘idx’, $format = ‘json’, $getdefaultclickaction = false) { $columns = $this->getColumns(); $columnrenderoptions = array(); $optionscolumns = array(); if (is_array($columns)) { foreach ($columns as $column) { $defaultclickaction = »; $renderer = $this->modx->getOption(‘renderer’, $column, »); $renderoptions = $this->modx->getOption(‘renderoptions’, $column, »); $renderchunktpl = $this->modx->getOption(‘renderchunktpl’, $column, »); $options = $this->modx->fromJson($renderoptions); if ($getdefaultclickaction && !empty($column[‘clickaction’])) { $option = array(); $defaultclickaction = $column[‘clickaction’]; $option[‘clickaction’] = $column[‘clickaction’]; $option[‘selectorconfig’] = $this->modx->getOption(‘selectorconfig’, $column, »); $defaultselectorconfig = $option[‘selectorconfig’]; $columnrenderoptions[$column[‘dataIndex’]][‘default_clickaction’] = $option; } if (is_array($options) && count($options) > 0) { foreach ($options as $key => $option) { $option[‘idx’] = $key; $option[‘_renderer’] = $renderer; $option[‘clickaction’] = empty($option[‘clickaction’]) && !empty($defaultclickaction) ? $defaultclickaction : $option[‘clickaction’]; $option[‘selectorconfig’] = $this->modx->getOption(‘selectorconfig’, $column, »); $option[‘selectorconfig’] = empty($option[‘selectorconfig’]) && !empty($defaultselectorconfig) ? $defaultselectorconfig : $option[‘selectorconfig’]; if (isset($option[‘use_as_fallback’]) && !empty($option[‘use_as_fallback’])) { $option[‘value’] = ‘use_as_fallback’; } $option[$indexfield] = isset($option[$indexfield]) ? $option[$indexfield] : 0; $columnrenderoptions[$column[‘dataIndex’]][$option[$indexfield]] = $format == ‘json’ ? json_encode($option) : $option; } } elseif (!empty($renderer) && $renderer == ‘this.renderChunk’) { $option[‘idx’] = 0; $option[‘_renderer’] = $renderer; $option[‘_renderchunktpl’] = $renderchunktpl; $option[$indexfield] = isset($option[$indexfield]) ? $option[$indexfield] : 0; $columnrenderoptions[$column[‘dataIndex’]][$option[$indexfield]] = $format == ‘json’ ? json_encode($option) : $option; } } } return $col == ‘*’ ? $columnrenderoptions : $columnrenderoptions[$col]; } function renderChunk($tpl, $properties = array(), $getChunk = true, $printIfemty = true) { $value = $this->parseChunk($tpl, $properties, $getChunk, $printIfemty); $this->modx->getParser(); /*parse all non-cacheable tags and remove unprocessed tags, if you want to parse only cacheable tags set param 3 as false*/ $this->modx->parser->processElementTags(», $value, true, true, ‘[[‘, ‘]]’, array()); return $value; } function checkRenderOptions($rows) { $columnrenderoptions = $this->getColumnRenderOptions(‘*’, ‘value’, ‘array’); //print_r($columnrenderoptions); $outputrows = is_array($rows) ? $rows : array(); if (is_array($rows) && count($columnrenderoptions) > 0) { $outputrows = array(); foreach ($rows as $row) { foreach ($columnrenderoptions as $column => $options) { $value = $this->modx->getOption($column, $row, »); $row[$column . ‘_ro’] = isset($options[$value]) ? json_encode($options[$value]) : »; if (empty($row[$column . ‘_ro’]) && isset($options[‘use_as_fallback’])) { $row[$column . ‘_ro’] = json_encode($options[‘use_as_fallback’]); } foreach ($options as $option) { if ($option[‘_renderer’] == ‘this.renderChunk’) { $row[‘_this.value’] = $value; $properties = $row; $properties[‘_request’] = $_REQUEST; $properties[‘_media_source_id’] = $this->config[‘media_source_id’]; $renderchunktpl = $this->modx->getOption(‘_renderchunktpl’, $option, »); if (!empty($renderchunktpl)) { $row[$column] = $this->renderChunk($renderchunktpl, $properties, false); } else { $row[$column] = $this->renderChunk($option[‘name’], $properties); } } break; } } $outputrows[] = $row; } } return $outputrows; } function prepareSourceForGrid($inputTv) { if (!empty($inputTv[‘inputTV’]) && $tv = $this->modx->getObject(‘modTemplateVar’, array(‘name’ => $inputTv[‘inputTV’]))) { } else { $tv = $this->modx->newObject(‘modTemplateVar’); } $mediasource = $this->getFieldSource($inputTv, $tv); return ‘&source=’ . $mediasource->get(‘id’); } function getFieldSource($field, &$tv) { //source from config $sourcefrom = isset($field[‘sourceFrom’]) && !empty($field[‘sourceFrom’]) ? $field[‘sourceFrom’] : ‘config’; if ($sourcefrom == ‘config’ && isset($field[‘sources’])) { if (is_array($field[‘sources’])) { foreach ($field[‘sources’] as $context => $sourceid) { $sources[$context] = $sourceid; } } else { $fsources = $this->modx->fromJson($field[‘sources’]); if (is_array($fsources)) { foreach ($fsources as $source) { if (isset($source[‘context’]) && isset($source[‘sourceid’])) { $sources[$source[‘context’]] = $source[‘sourceid’]; } } } } } if (isset($sources[$this->working_context]) && !empty($sources[$this->working_context])) { //try using field-specific mediasource from config if ($mediasource = $this->modx->getObject(‘sources.modMediaSource’, $sources[$this->working_context])) { return $mediasource; } } if ($this->source && $sourcefrom == ‘migx’) { //use global MIGX-mediasource for all TVs $tv->setSource($this->source); $mediasource = $this->source; } else { //useTV-specific mediasource $mediasource = $tv->getSource($this->working_context, false); } //try to get the context-default-media-source if (!$mediasource) { $mediasource = $this->getDefaultSource(); } return $mediasource; } function getDefaultSource($return = ‘object’) { $defaultSourceId = null; if ($contextSetting = $this->modx->getObject(‘modContextSetting’, array(‘key’ => ‘default_media_source’, ‘context_key’ => $this->working_context))) { $defaultSourceId = $contextSetting->get(‘value’); } $mediasource = modMediaSource::getDefaultSource($this->modx, $defaultSourceId); return $return == ‘object’ ? $mediasource : $mediasource->get($return); } function generateTvTab($tvnames) { $tvnames = !empty($tvnames) ? explode(‘,’, $tvnames) : array(); $fields = array(); foreach ($tvnames as $tvname) { $field[‘field’] = $tvname; $field[‘inputTV’] = $tvname; $fields[] = $field; } return $fields; } function checkForConnectedResource($resource_id = false, &$config = []) { if ($resource_id) { $check_resid = $this->modx->getOption(‘check_resid’, $config); if ($check_resid == ‘@TV’ && $resource = $this->modx->getObject(‘modResource’, $resource_id)) { if ($check = $resource->getTvValue($config[‘check_resid_TV’])) { $check_resid = $check; } } if (!empty($check_resid)) { //$c->where(«CONCAT(‘||’,resource_ids,’||’) LIKE ‘%||{$resource_id}||%'», xPDOQuery::SQL_AND); return true; } } return false; } function createForm(&$tabs, &$record, &$allfields, &$categories, $scriptProperties) { $fieldid = 0; $config = $this->customconfigs; $hooksnippets = $this->modx->fromJson($this->modx->getOption(‘hooksnippets’, $config, »)); if (is_array($hooksnippets)) { $hooksnippet_beforecreateform = $this->modx->getOption(‘beforecreateform’, $hooksnippets, »); if (!empty($hooksnippet_beforecreateform)) { $snippetProperties = array(); $snippetProperties[‘tabs’] = &$tabs; $snippetProperties[‘record’] = &$record; $snippetProperties[‘scriptProperties’] = &$scriptProperties; $result = $this->modx->runSnippet($hooksnippet_beforecreateform, $snippetProperties); } } $input_prefix = $this->modx->getOption(‘input_prefix’, $scriptProperties, »); $input_prefix = !empty($input_prefix) ? $input_prefix . ‘_’ : »; $rte = isset($scriptProperties[‘which_editor’]) ? $scriptProperties[‘which_editor’] : $this->modx->getOption(‘which_editor’, », $this->modx->_userConfig); if (!is_array($tabs)) { return array(‘error’ => ‘There seems to be an error in the formtabs-config’); } foreach ($tabs as $tabid => $tab) { $layouts = array(); $layoutcolumns = array(); $tvs = array(); $fields = $this->modx->getOption(‘fields’, $tab, array()); $fields = is_array($fields) ? $fields : $this->modx->fromJson($fields); if (is_array($fields) && count($fields) > 0) { foreach ($fields as &$field) { if (isset($field[‘restrictive_condition’])) { $props = $record; $rc = $this->renderChunk($field[‘restrictive_condition’], $props, false, false); if (!empty($rc)) { continue; } } $fieldname = $this->modx->getOption(‘field’, $field, »); $useDefaultIfEmpty = $this->modx->getOption(‘useDefaultIfEmpty’, $field, 0); $fieldid++; /*generate unique tvid, must be numeric*/ /*todo: find a better solution*/ $field[‘tv_id’] = $input_prefix . $scriptProperties[‘tv_id’] . ‘_’ . $fieldid; $params = array(); $tv = false; if (isset($field[‘inputTV’]) && $tv = $this->modx->getObject(‘modTemplateVar’, array(‘name’ => $field[‘inputTV’]))) { $params = $tv->get(‘input_properties’); $params[‘inputTVid’] = $tv->get(‘id’); } if (!empty($field[‘inputTVtype’])) { $tv = $this->modx->newObject(‘modTemplateVar’); $tv->set(‘type’, $field[‘inputTVtype’]); } if (!$tv) { $tv = $this->modx->newObject(‘modTemplateVar’); $tv->set(‘type’, ‘text’); } $o_type = $tv->get(‘type’); if ($tv->get(‘type’) == ‘richtext’) { $tv->set(‘type’, ‘migx’ . str_replace(‘ ‘, ‘_’, strtolower($rte))); } //we change the phptype, that way we can use any id, not only integers (issues on windows-systems with big integers!) $tv->_fieldMeta[‘id’][‘phptype’] = ‘string’; /* $tv->set(‘id’,’skdjflskjd’); echo ‘id:’. $tv->get(‘id’); $tv->_fieldMeta[‘id’][‘phptype’] = ‘string’; echo($tv->_fieldMeta[‘id’][‘phptype’]); $tv->set(‘id’,’skdjflskjd’); echo ‘id:’. $tv->get(‘id’); */ if (!empty($field[‘inputOptionValues’])) { $tv->set(‘elements’, $field[‘inputOptionValues’]); } if (!empty($field[‘default’])) { $tv->set(‘default_text’, $tv->processBindings($field[‘default’])); } if (isset($field[‘display’])) { $tv->set(‘display’, $field[‘display’]); } if (!empty($field[‘configs’])) { $props = $record; $cfg_parsed = $this->renderChunk($field[‘configs’], $props, false, false); $cfg = json_decode($cfg_parsed, 1); if (is_array($cfg)) { $params = array_merge($params, $cfg); } else { $params[‘configs’] = $cfg_parsed; } } /*insert actual value from requested record, convert arrays to ||-delimeted string */ $fieldvalue = »; if (isset($record[$fieldname])) { $fieldvalue = $record[$fieldname]; if (is_array($fieldvalue)) { $fieldvalue = is_array($fieldvalue[0]) ? json_encode($fieldvalue) : implode(‘||’, $fieldvalue); } } $tv->set(‘value’, $fieldvalue); if (!empty($field[‘caption’])) { $field[‘caption’] = htmlentities($this->replaceLang($field[‘caption’]), ENT_QUOTES, $this->modx->getOption(‘modx_charset’)); $tv->set(‘caption’, $field[‘caption’]); } $desc = »; if (!empty($field[‘description’])) { $desc = $field[‘description’]; $field[‘description’] = is_string($desc) ? htmlentities($this->replaceLang($desc), ENT_QUOTES, $this->modx->getOption(‘modx_charset’)) : »; $tv->set(‘description’, $field[‘description’]); } $allfield = array(); $allfield[‘field’] = $fieldname; $allfield[‘tv_id’] = $field[‘tv_id’]; $allfield[‘array_tv_id’] = $field[‘tv_id’] . ‘[]’; $allfields[] = $allfield; $field[‘array_tv_id’] = $field[‘tv_id’] . ‘[]’; $mediasource = $this->getFieldSource($field, $tv); $tv->setSource($mediasource); $tv->set(‘id’, $field[‘tv_id’]); /* $default = $tv->processBindings($tv->get(‘default_text’), $resourceId); if (strpos($tv->get(‘default_text’), ‘@INHERIT’) > -1 && (strcmp($default, $tv->get(‘value’)) == 0 || $tv->get(‘value’) == null)) { $tv->set(‘inherited’, true); } */ $isnew = $this->modx->getOption(‘isnew’, $scriptProperties, 0); $isduplicate = $this->modx->getOption(‘isduplicate’, $scriptProperties, 0); $existingvalue = $tv->get(‘value’); if (!empty($useDefaultIfEmpty)) { //old behaviour minus use now default values for checkboxes, if new record if ($tv->get(‘value’) == null) { $v = $tv->get(‘default_text’); if ($tv->get(‘type’) == ‘checkbox’ && $tv->get(‘value’) == ») { if (!empty($isnew) && empty($isduplicate)) { $v = $tv->get(‘default_text’); } else { $v = »; } } $tv->set(‘value’, $v); } } else { //set default value, only on new records if (empty($existingvalue) && !empty($isnew) && empty($isduplicate)) { $v = $tv->get(‘default_text’); $tv->set(‘value’, $v); } } $this->modx->smarty->assign(‘tv’, $tv); /* move this part into a plugin onMediaSourceGetProperties and create a mediaSource — property ‘autoCreateFolder’ * may be performancewise its better todo that here? if (!empty($properties[‘basePath’])) { if ($properties[‘autoResourceFolders’] == ‘true’) { $params[‘basePath’] = $basePath . $scriptProperties[‘resource_id’] . ‘/’; $targetDir = $params[‘basePath’]; $cacheManager = $this->modx->getCacheManager(); // if directory doesnt exist, create it if (!file_exists($targetDir) || !is_dir($targetDir)) { if (!$cacheManager->writeTree($targetDir)) { $this->modx->log(modX::LOG_LEVEL_ERROR, ‘[MIGX] Could not create directory: ‘ . $targetDir); return $this->modx->error->failure(‘Could not create directory: ‘ . $targetDir); } } // make sure directory is readable/writable if (!is_readable($targetDir) || !is_writable($targetDir)) { $this->modx->log(xPDO::LOG_LEVEL_ERROR, ‘[MIGX] Could not write to directory: ‘ . $targetDir); return $this->modx->error->failure(‘Could not write to directory: ‘ . $targetDir); } } else { $params[‘basePath’] = $basePath; } } */ if (!isset($params[‘allowBlank’])) $params[‘allowBlank’] = 1; $value = $tv->get(‘value’); if ($value === null) { $value = $tv->get(‘default_text’); } $this->modx->smarty->assign(‘params’, $params); /* find the correct renderer for the TV, if not one, render a textbox */ $inputRenderPaths = $tv->getRenderDirectories(‘OnTVInputRenderList’, ‘input’); if ($o_type == ‘richtext’) { $fallback = true; foreach ($inputRenderPaths as $path) { $renderFile = $path . $tv->get(‘type’) . ‘.class.php’; if (file_exists($renderFile)) { $fallback = false; break; } } if ($fallback) { $tv->set(‘type’, ‘textarea’); } } $inputForm = $tv->getRender($params, $value, $inputRenderPaths, ‘input’, null, $tv->get(‘type’)); /* //extract scripts from content $pattern = ‘#<script(.*?)</script>#is’; preg_match_all($pattern, $inputForm, $matches); foreach ($matches[0] as $jsvalue) { $js .= $jsvalue; } $inputForm = preg_replace($pattern, », $inputForm); */ if (isset($field[‘description_is_code’]) && !empty($field[‘description_is_code’])) { $props = $record; unset($field[‘description’]); $tv_array = $tv->toArray(); unset($tv_array[‘description’]); // don’t parse the value — set special placeholder, replace it later $tv_array[‘value’] = ‘[+[+value]]’; $tempvalue = $tv->get(‘value’); $props[‘record_json’] = json_encode($props); $props[‘tv_json’] = json_encode($tv_array); $props[‘field_json’] = json_encode($field); // don’t parse the rendered formElement — set special placeholder, replace it later $props[‘tv_formElement’] = ‘[+[+tv_formElement]]’; $tv->set(‘formElement’, str_replace(array(‘[+[+value]]’, ‘[+[+tv_formElement]]’), array($tempvalue, $inputForm), $this->renderChunk($desc, $props, false, false))); $tv->set(‘type’, ‘description_is_code’); } else { if (empty($inputForm)) continue; $tv->set(‘formElement’, $inputForm); } //$tvs[] = $tv; $layout_id = isset($field[‘MIGXlayoutid’]) ? $field[‘MIGXlayoutid’] : 0; $column_id = isset($field[‘MIGXcolumnid’]) ? $field[‘MIGXcolumnid’] : 0; $column_width = $this->modx->getOption(‘MIGXcolumnwidth’, $field, »); $column_minwidth = $this->modx->getOption(‘MIGXcolumnminwidth’, $field, »); if (empty($column_width)) { $column_width = ‘100%’; } $column_minwidth = empty($column_minwidth) ? ‘0’ : $column_minwidth; $layouts[$layout_id][‘caption’] = $this->modx->getOption(‘MIGXlayoutcaption’, $field, »); $layouts[$layout_id][‘style’] = $this->modx->getOption(‘MIGXlayoutstyle’, $field, »); $layouts[$layout_id][‘columns’][$column_id][‘tvs’][] = $tv; $layouts[$layout_id][‘columns’][$column_id][‘width’] = $column_width; $layouts[$layout_id][‘columns’][$column_id][‘minwidth’] = $column_minwidth; $layouts[$layout_id][‘columns’][$column_id][‘style’] = $this->modx->getOption(‘MIGXcolumnstyle’, $field, »); $layouts[$layout_id][‘columns’][$column_id][‘caption’] = $this->modx->getOption(‘MIGXcolumncaption’, $field, »); } } //echo ‘<pre>’ . print_r($layouts,1) . ‘</pre>’; //$layoutcolumn = array(); //$layoutcolumn[‘tvs’] = $tvs; //$layoutcolumns[] = $layoutcolumn; //$layout = array(); //$layout[‘columns’] = $layoutcolumns; //$layouts[] = $layout; $cat = array(); $cat[‘category’] = $this->modx->getOption(‘caption’, $tab, ‘undefined’); $cat[‘print_before_tabs’] = isset($tab[‘print_before_tabs’]) && !empty($tab[‘print_before_tabs’]) ? true : false; $cat[‘id’] = $tabid; $cat[‘layouts’] = $layouts; //$cat[‘tvs’] = $tvs; $categories[] = $cat; } } function extractFieldsFromTabs($formtabs, $onlyTvTypes = false) { //multiple different Forms // Note: use same field-names and inputTVs in all forms if (is_array($formtabs) && isset($formtabs[0][‘formtabs’])) { $forms = $formtabs; $formtabs = array(); foreach ($forms as $form) { foreach ($form[‘formtabs’] as $tab) { $tab[‘formname’] = $form[‘formname’]; $formtabs[] = $tab; } } } $inputTvs = array(); if (is_array($formtabs)) { foreach ($formtabs as $tabidx => $tab) { $formname = isset($tab[‘formname’]) && !empty($tab[‘formname’]) ? $tab[‘formname’] . ‘_’ : »; if (isset($tab[‘fields’])) { $fields = is_array($tab[‘fields’]) ? $tab[‘fields’] : $this->modx->fromJson($tab[‘fields’]); if (is_array($fields)) { foreach ($fields as $field) { //$fieldkey = $formname.$field[‘field’]; if (isset($field[‘inputTV’]) && !empty($field[‘inputTV’])) { $inputTvs[$field[‘field’]] = $field; //for different inputTvs, for example with different mediasources, in multiple forms, currently not used for the grid $inputTvs[$formname . $field[‘field’]] = $field; } elseif (isset($field[‘inputTVtype’]) && !empty($field[‘inputTVtype’])) { $inputTvs[$field[‘field’]] = $field; $inputTvs[$formname . $field[‘field’]] = $field; } elseif (!$onlyTvTypes) { $inputTvs[$field[‘field’]] = $field; $inputTvs[$formname . $field[‘field’]] = $field; } } } } } } return $inputTvs; } function extractInputTvs($formtabs) { return $this->extractFieldsFromTabs($formtabs, true); } function parseChunk($tpl, $fields = array(), $getChunk = true, $printIfemty = true) { $output = »; if ($getChunk) { if ($chunk = $this->modx->getObject(‘modChunk’, array(‘name’ => $tpl), true)) { $tpl = $chunk->getContent(); } elseif (file_exists($tpl)) { $tpl = file_get_contents($tpl); } elseif (file_exists($this->modx->getOption(‘base_path’) . $tpl)) { $tpl = file_get_contents($this->modx->getOption(‘base_path’) . $tpl); } else { $tpl = false; } } if ($tpl) { $chunk = $this->modx->newObject(‘modChunk’); $chunk->setCacheable(false); $chunk->setContent($tpl); $output = $chunk->process($fields); } elseif ($printIfemty) { $output = ‘<pre>’ . print_r($fields, 1) . ‘</pre>’; } return $output; } function sortTV($sort, &$c, $dir = ‘ASC’, $sortbyTVType = ») { $c->leftJoin(‘modTemplateVar’, ‘tvDefault’, arraytvDefault.name» => $sort)); $c->leftJoin(‘modTemplateVarResource’, ‘tvSort’, arraytvSort.contentid = modResource.id«, «tvSort.tmplvarid = tvDefault.id«)); if (empty($sortbyTVType)) $sortbyTVType = ‘string’; if ($this->modx->getOption(‘dbtype’) === ‘mysql’) { switch ($sortbyTVType) { case ‘integer’: $c->selectCAST(IFNULL(tvSort.value, tvDefault.default_text) AS SIGNED INTEGER) AS sortTV«); break; case ‘decimal’: $c->selectCAST(IFNULL(tvSort.value, tvDefault.default_text) AS DECIMAL) AS sortTV«); break; case ‘datetime’: $c->selectCAST(IFNULL(tvSort.value, tvDefault.default_text) AS DATETIME) AS sortTV«); break; case ‘string’: default: $c->selectIFNULL(tvSort.value, tvDefault.default_text) AS sortTV«); break; } } $c->sortbysortTV«, $dir); return true; } function tvFilters($tvFilters = », &$criteria = null) { //tvFilter::categories=inArray=[[+category]] $tvFilters = !empty($tvFilters) ? explode(‘||’, $tvFilters) : array(); if (!empty($tvFilters)) { $tmplVarTbl = $this->modx->getTableName(‘modTemplateVar’); $tmplVarResourceTbl = $this->modx->getTableName(‘modTemplateVarResource’); $conditions = array(); $operators = array( ‘<=>’ => ‘<=>’, ‘===’ => ‘=’, ‘!==’ => ‘!=’, ‘<>’ => ‘<>’, ‘==’ => ‘LIKE’, ‘!=’ => ‘NOT LIKE’, ‘<<‘ => ‘<‘, ‘<=’ => ‘<=’, ‘=<‘ => ‘=<‘, ‘>>’ => ‘>’, ‘>=’ => ‘>=’, ‘=>’ => ‘=>’, ‘=inArray=’ => ‘=inArray=’); foreach ($tvFilters as $fGroup => $tvFilter) { $filterGroup = array(); $filters = explode(‘,’, $tvFilter); $multiple = count($filters) > 0; foreach ($filters as $filter) { $operator = ‘==’; $sqlOperator = ‘LIKE’; foreach ($operators as $op => $opSymbol) { if (strpos($filter, $op, 1) !== false) { $operator = $op; $sqlOperator = $opSymbol; break; } } $tvValueField = ‘tvr.value’; $tvDefaultField = ‘tv.default_text’; $f = explode($operator, $filter); if (count($f) == 2) { $tvName = $this->modx->quote($f[0]); if (is_numeric($f[1]) && !in_array($sqlOperator, array(‘LIKE’, ‘NOT LIKE’))) { $tvValue = $f[1]; if ($f[1] == (integer)$f[1]) { $tvValueField = «CAST({$tvValueField} AS SIGNED INTEGER)«; $tvDefaultField = «CAST({$tvDefaultField} AS SIGNED INTEGER)«; } else { $tvValueField = «CAST({$tvValueField} AS DECIMAL)«; $tvDefaultField = «CAST({$tvDefaultField} AS DECIMAL)«; } } elseif ($sqlOperator == ‘=inArray=’) { $sqlOperator = ‘LIKE’; $tvValueField = «CONCAT(‘||’,{$tvValueField},’||’)«; $tvDefaultField = «CONCAT(‘||’,{$tvDefaultField},’||’)«; $tvValue = $this->modx->quote(‘%||’ . $f[1] . ‘||%’); } else { $tvValue = $this->modx->quote($f[1]); } if ($multiple) { $filterGroup[] = «(EXISTS (SELECT 1 FROM {$tmplVarResourceTbl} tvr JOIN {$tmplVarTbl} tv ON {$tvValueField} {$sqlOperator} {$tvValue} AND tv.name = {$tvName} AND tv.id = tvr.tmplvarid WHERE tvr.contentid = modResource.id) » . «OR EXISTS (SELECT 1 FROM {$tmplVarTbl} tv WHERE tv.name = {$tvName} AND {$tvDefaultField} {$sqlOperator} {$tvValue} AND tv.id NOT IN (SELECT tmplvarid FROM {$tmplVarResourceTbl} WHERE contentid = modResource.id)) » . «)«; } else { $filterGroup = «(EXISTS (SELECT 1 FROM {$tmplVarResourceTbl} tvr JOIN {$tmplVarTbl} tv ON {$tvValueField} {$sqlOperator} {$tvValue} AND tv.name = {$tvName} AND tv.id = tvr.tmplvarid WHERE tvr.contentid = modResource.id) » . «OR EXISTS (SELECT 1 FROM {$tmplVarTbl} tv WHERE tv.name = {$tvName} AND {$tvDefaultField} {$sqlOperator} {$tvValue} AND tv.id NOT IN (SELECT tmplvarid FROM {$tmplVarResourceTbl} WHERE contentid = modResource.id)) » . «)«; } } elseif (count($f) == 1) { $tvValue = $this->modx->quote($f[0]); if ($multiple) { $filterGroup[] = «EXISTS (SELECT 1 FROM {$tmplVarResourceTbl} tvr JOIN {$tmplVarTbl} tv ON {$tvValueField} {$sqlOperator} {$tvValue} AND tv.id = tvr.tmplvarid WHERE tvr.contentid = modResource.id)«; } else { $filterGroup = «EXISTS (SELECT 1 FROM {$tmplVarResourceTbl} tvr JOIN {$tmplVarTbl} tv ON {$tvValueField} {$sqlOperator} {$tvValue} AND tv.id = tvr.tmplvarid WHERE tvr.contentid = modResource.id)«; } } } $conditions[] = $filterGroup; } if (!empty($conditions)) { $firstGroup = true; foreach ($conditions as $cGroup => $c) { if (is_array($c)) { $first = true; foreach ($c as $cond) { if ($first && !$firstGroup) { $criteria->condition($criteria->query[‘where’][0][1], $cond, xPDOQuery::SQL_OR, null, $cGroup); } else { $criteria->condition($criteria->query[‘where’][0][1], $cond, xPDOQuery::SQL_AND, null, $cGroup); } $first = false; } } else { $criteria->condition($criteria->query[‘where’][0][1], $c, $firstGroup ? xPDOQuery::SQL_AND : xPDOQuery::SQL_OR, null, $cGroup); } $firstGroup = false; } } return true; } } public function debug($key, $value, $reset = false) { $debug[$key] = $value; $chunk = $this->modx->getObject(‘modChunk’, array(‘name’ => ‘debug’)); $oldContent = $reset ? » : $chunk->getContent(); $chunk->setContent($oldContent . print_r($debug, 1)); $chunk->save(); } function filterItems($where, $items) { $tempitems = array(); foreach ($items as $item) { $include = true; foreach ($where as $key => $operand) { $key = explode(‘:’, $key); $field = $key[0]; $then = $include; $else = false; $subject = $item[$field]; $operator = isset($key[1]) ? $key[1] : ‘=’; $params = isset($key[2]) ? $key[2] : »; $operator = strtolower($operator); switch ($operator) { case ‘!=’: case ‘neq’: case ‘not’: case ‘isnot’: case ‘isnt’: case ‘unequal’: case ‘notequal’: $output = (($subject != $operand) ? $then : (isset($else) ? $else : »)); break; case ‘<‘: case ‘lt’: case ‘less’: case ‘lessthan’: $output = (($subject < $operand) ? $then : (isset($else) ? $else : »)); break; case ‘>’: case ‘gt’: case ‘greater’: case ‘greaterthan’: $output = (($subject > $operand) ? $then : (isset($else) ? $else : »)); break; case ‘<=’: case ‘lte’: case ‘lessthanequals’: case ‘lessthanorequalto’: $output = (($subject <= $operand) ? $then : (isset($else) ? $else : »)); break; case ‘>=’: case ‘gte’: case ‘greaterthanequals’: case ‘greaterthanequalto’: $output = (($subject >= $operand) ? $then : (isset($else) ? $else : »)); break; case ‘isempty’: case ’empty’: $output = empty($subject) ? $then : (isset($else) ? $else : »); break; case ‘!empty’: case ‘notempty’: case ‘isnotempty’: $output = !empty($subject) && $subject != » ? $then : (isset($else) ? $else : »); break; case ‘isnull’: case ‘null’: $output = $subject == null || strtolower($subject) == ‘null’ ? $then : (isset($else) ? $else : »); break; case ‘inarray’: case ‘in_array’: case ‘ia’: case ‘in’: $operand = is_array($operand) ? $operand : explode(‘,’, $operand); $output = in_array($subject, $operand) ? $then : (isset($else) ? $else : »); break; case ‘find’: case ‘find_in_set’: $subject = is_array($subject) ? $subject : explode(‘,’, $subject); $output = in_array($operand, $subject) ? $then : (isset($else) ? $else : »); break; case ‘find_pd’: case ‘find_in_pipesdelimited_set’: $subject = explode(‘||’, $subject); $output = in_array($operand, $subject) ? $then : (isset($else) ? $else : »); break; case ‘contains’: $output = strpos($subject, $operand) !== false ? $then : (isset($else) ? $else : »); break; case ‘snippet’: $result = $this->modx->runSnippet($params, array(‘subject’ => $subject, ‘operand’ => $operand)); $output = !empty($result) ? $then : (isset($else) ? $else : »); break; case ‘==’: case ‘=’: case ‘eq’: case ‘is’: case ‘equal’: case ‘equals’: case ‘equalto’: default: $output = (($subject == $operand) ? $then : (isset($else) ? $else : »)); break; } $include = $output ? $output : false; } if ($include) { $tempitems[] = $item; } } return $tempitems; } /** * Sort DB result * * @param array $data Result of sql query as associative array * * @param array $options Sortoptions as array * * * <code> * * // You can sort data by several columns e.g. * $data = array(); * for ($i = 1; $i <= 10; $i++) { * $data[] = array( ‘id’ => $i, * ‘first_name’ => sprintf(‘first_name_%s’, rand(1, 9)), * ‘last_name’ => sprintf(‘last_name_%s’, rand(1, 9)), * ‘date’ => date(‘Y-m-d’, rand(0, time())) * ); * } * * $options = array(array(‘sortby’=>’date’,’sortdir’=>’DESC’,’sortmode’=>’numeric’)); * $data = sortDbResult($data, $options); * printf(‘<pre>%s</pre>’, print_r($data, true)); * * $options = array(array(‘sortby’=>’last_name’,’sortdir’=>’ASC’,’sortmode’=>’string’),array(‘sortby’=>’first_name’,’sortdir’=>’ASC’,’sortmode’=>’string’)); * $data = sortDbResult($data, $options); * printf(‘<pre>%s</pre>’, print_r($data, true)); * * </code> * * @return array $data — Sorted data */ function sortDbResult($_data, $options = array()) { $sortmodes = array(); $sortmodes[‘numeric’] = SORT_NUMERIC; $sortmodes[‘string’] = SORT_STRING; $sortmodes[‘regular’] = SORT_REGULAR; $sortdirs = array(); $sortdirs[‘ASC’] = SORT_ASC; $sortdirs[‘DESC’] = SORT_DESC; $_rules = array(); if (count($options) > 0) { foreach ($options as $option) { $rule[‘name’] = isset($option[‘sortby’]) ? (string )$option[‘sortby’] : »; if (empty($rule[‘name’]) || (is_array(current($_data)) && !in_array($rule[‘name’], array_keys(current($_data))))) { continue; } $rule[‘order’] = isset($option[‘sortdir’]) && isset($sortdirs[$option[‘sortdir’]]) ? $sortdirs[$option[‘sortdir’]] : $sortdirs[‘ASC’]; $rule[‘mode’] = isset($option[‘sortmode’]) && isset($sortmodes[$option[‘sortmode’]]) ? $sortmodes[$option[‘sortmode’]] : $sortmodes[‘regular’]; $_rules[] = $rule; } } $_cols = array(); foreach ($_data as $_k => $_row) { foreach ($_rules as $_rule) { if (!isset($_cols[$_rule[‘name’]])) { $_cols[$_rule[‘name’]] = array(); $_params[] = &$_cols[$_rule[‘name’]]; $_params[] = $_rule[‘order’]; $_params[] = $_rule[‘mode’]; } $_cols[$_rule[‘name’]][$_k] = $_row[$_rule[‘name’]]; } } $_params[] = &$_data; call_user_func_array(‘array_multisort’, $_params); return $_data; } public function prepareJoins($classname, $joins, &$c) { $selectcolumns = array(); if (is_array($joins)) { foreach ($joins as $join) { $jalias = $this->modx->getOption(‘alias’, $join, »); $type = $this->modx->getOption(‘type’, $join, ‘left’); $joinclass = $this->modx->getOption(‘classname’, $join, »); $selectfields = $this->modx->getOption(‘selectfields’, $join, »); $on = $this->modx->getOption(‘on’, $join, null); if (!empty($jalias)) { if (empty($joinclass) && $fkMeta = $c->xpdo->getFKDefinition($classname, $jalias)) { $joinclass = $fkMeta[‘class’]; } if (!empty($joinclass)) { /* if ($joinFkMeta = $modx->getFKDefinition($joinclass, ‘Resource’)){ $localkey = $joinFkMeta[‘local’]; } */ $selectfields = !empty($selectfields) ? explode(‘,’, $selectfields) : null; switch ($type) { case ‘left’: $c->leftjoin($joinclass, $jalias, $on); break; case ‘right’: $c->rightjoin($joinclass, $jalias, $on); break; case ‘inner’: $c->innerjoin($joinclass, $jalias, $on); break; default: $c->leftjoin($joinclass, $jalias, $on); break; } if ($object = $c->xpdo->newObject($joinclass)) { $columns = $object->toArray($jalias . ‘_’); $selectcolumns = array_merge($selectcolumns, $columns); $c->select($c->xpdo->getSelectColumns($joinclass, $jalias, $jalias . ‘_’, $selectfields)); } } } } } return $selectcolumns; } public function addRelatedLinkIds(&$object, &$record, $config) { $modx = &$this->modx; $xpdo = &$object->xpdo; $link_classname = $modx->getOption(‘link_classname’, $config, »); $link_alias = $modx->getOption(‘link_alias’, $config, »); $postfield = $modx->getOption(‘postfield’, $config, »); $id_field = $modx->getOption(‘id_field’, $config, »); $link_field = $modx->getOption(‘link_field’, $config, »); $ids = array(); if ($collection = $object->getMany($link_alias)) { foreach ($collection as $link_object) { $ids[] = $link_object->get($link_field); //print_r($object->toArray()); } } $record[$postfield] = implode(‘||’, $ids); } public function handleRelatedLinks(&$object, $postvalues, $config = array()) { $modx = &$this->modx; $xpdo = &$object->xpdo; $link_classname = $modx->getOption(‘link_classname’, $config, »); $link_alias = $modx->getOption(‘link_alias’, $config, »); $postfield = $modx->getOption(‘postfield’, $config, »); $id_field = $modx->getOption(‘id_field’, $config, »); $link_field = $modx->getOption(‘link_field’, $config, »); $attributes = explode(‘||’, $modx->getOption($postfield, $postvalues, »)); $old_attributes = array(); if ($attr_collection = $object->getMany($link_alias)) { foreach ($attr_collection as $attr_o) { $old_attributes[$attr_o->get($link_field)] = $attr_o; } } foreach ($attributes as $attribute) { if (!empty($attribute)) { if (isset($old_attributes[$attribute])) { unset($old_attributes[$attribute]); } else { $attr_o = $xpdo->newObject($link_classname); $attr_o->set($link_field, $attribute); $attr_o->set($id_field, $object->get(‘id’)); $attr_o->save(); } } } foreach ($old_attributes as $attr_o) { $attr_o->remove(); } } public function handleRelatedLinksFromMIGX(&$object, $postvalues, $config) { $modx = &$this->modx; $xpdo = &$object->xpdo; $link_classname = $modx->getOption(‘link_classname’, $config, »); $link_alias = $modx->getOption(‘link_alias’, $config, »); $postfield = $modx->getOption(‘postfield’, $config, »); $id_field = $modx->getOption(‘id_field’, $config, »); $link_field = $modx->getOption(‘link_field’, $config, »); $pos_field = $modx->getOption(‘pos_field’, $config, ‘pos’); $resave_object = $modx->getOption(‘resave_object’, $config, 0); $extrafields = explode(‘,’, $modx->getOption(‘extrafields’, $config, »)); $products = $modx->fromJson($modx->getOption($postfield, $postvalues, »)); $old_products = array(); if ($product_collection = $object->getMany($link_alias)) { foreach ($product_collection as $product_o) { $old_products[$product_o->get(‘id’)] = $product_o; } } $pos = 1; $new_products = array(); foreach ($products as $product) { $product_id = $modx->getOption($link_field, $product, »); $migx_id = $modx->getOption(‘MIGX_id’, $product, »); $id = $modx->getOption(‘id’, $product, ‘new’); if (!empty($product_id)) { if (isset($old_products[$id])) { $product_o = $old_products[$id]; unset($old_products[$id]); } else { $product_o = $xpdo->newObject($link_classname); } $product_o->set($pos_field, $pos); foreach ($extrafields as $extrafield) { $value = $modx->getOption($extrafield, $product, »); $product_o->set($extrafield, $value); } $product_o->set($link_field, $product_id); $product_o->set($id_field, $object->get(‘id’)); $product_o->save(); $new_product = $product_o->toArray(); $new_product[‘MIGX_id’] = $migx_id; $new_products[] = $new_product; $pos++; } } //save cleaned json $object->set($postfield, json_encode($new_products)); if (!empty($resave_object)) { $object->save(); } foreach ($old_products as $product_o) { $product_o->remove(); } } public function handleTranslations(&$object, $postvalues, $config) { $modx = &$this->modx; $xpdo = &$object->xpdo; $link_classname = $modx->getOption(‘link_classname’, $config, »); $link_alias = $modx->getOption(‘link_alias’, $config, ‘Translations’); $postfield = $modx->getOption(‘postfield’, $config, »); $id_field = $modx->getOption(‘id_field’, $config, »); $link_field = $modx->getOption(‘link_field’, $config, ‘iso_code’); $languages = $modx->getOption(‘languages’, $config, array()); $old_translations = array(); if ($trans_collection = $object->getMany($link_alias)) { foreach ($trans_collection as $trans_o) { $old_translations[$trans_o->get($link_field)] = $trans_o; } } foreach ($languages as $language) { $iso_code = $modx->getOption($link_field, $language, »); if (!empty($iso_code)) { if (isset($old_translations[$iso_code])) { $trans_o = $old_translations[$iso_code]; unset($old_translations[$iso_code]); } else { $trans_o = $xpdo->newObject($link_classname); $trans_o->set($link_field, $iso_code); $trans_o->set($id_field, $object->get(‘id’)); } foreach ($postvalues as $field => $value) { $fieldparts = explode(‘_’, $field); $fieldparts = array_reverse($fieldparts); if ($fieldparts[0] == $iso_code) { $fieldname = str_replace(‘_’ . $iso_code, », $field); $trans_o->set($fieldname, $value); } } $trans_o->save(); } } foreach ($old_translations as $trans_o) { $trans_o->remove(); } } public function handleOrderPositions(&$xpdo, $config, $scriptProperties) { $modx = &$this->modx; $classname = $config[‘classname’]; $checkdeleted = isset($config[‘gridactionbuttons’][‘toggletrash’][‘active’]) && !empty($config[‘gridactionbuttons’][‘toggletrash’][‘active’]) ? true : false; $newpos_id = $modx->getOption(‘new_pos_id’, $scriptProperties, 0); $col = $modx->getOption(‘col’, $scriptProperties, »); $object_id = $modx->getOption(‘object_id’, $scriptProperties, 0); $showtrash = $modx->getOption(‘showtrash’, $scriptProperties, »); $resource_id = $modx->getOption(‘co_id’, $scriptProperties, is_object($modx->resource) ? $modx->resource->get(‘id’) : false); $col = explode(‘:’, $col); if (!empty($newpos_id) && !empty($object_id) && count($col) > 1) { $workingobject = $xpdo->getObject($classname, $object_id); $posfield = $col[0]; $position = $col[1]; $joinalias = isset($config[‘join_alias’]) ? $config[‘join_alias’] : »; if (!empty($joinalias)) { if ($fkMeta = $xpdo->getFKDefinition($classname, $joinalias)) { $joinclass = $fkMeta[‘class’]; $joinfield = $fkMeta[$fkMeta[‘owner’]]; } else { $joinalias = »; } } //$parent = $workingobject->get(‘parent’); $c = $xpdo->newQuery($classname); //$c->where(array(‘deleted’=>0 , ‘parent’=>$parent)); $c->select($xpdo->getSelectColumns($classname, $classname)); if (!empty($joinalias)) { /* if ($joinFkMeta = $modx->getFKDefinition($joinclass, ‘Resource’)){ $localkey = $joinFkMeta[‘local’]; } */ $c->leftjoin($joinclass, $joinalias); $c->select($xpdo->getSelectColumns($joinclass, $joinalias, ‘Joined_’)); } if ($this->checkForConnectedResource($resource_id, $config)) { if (!empty($joinalias)) { $c->where(array($joinalias . ‘.’ . $joinfield => $resource_id)); } else { $c->where(array($classname . ‘.resource_id’ => $resource_id)); } } if ($checkdeleted) { if (!empty($showtrash)) { $c->where(array($classname . ‘.deleted’ => ‘1’)); } else { $c->where(array($classname . ‘.deleted’ => ‘0’)); } } $c->sortby($posfield); //$c->sortby(‘name’); if ($collection = $xpdo->getCollection($classname, $c)) { $curpos = 1; foreach ($collection as $object) { $id = $object->get(‘id’); if ($id == $newpos_id && $position == ‘before’) { $workingobject->set($posfield, $curpos); $workingobject->save(); $curpos++; } if ($id != $object_id) { $object->set($posfield, $curpos); $object->save(); $curpos++; } if ($id == $newpos_id && $position == ‘after’) { $workingobject->set($posfield, $curpos); $workingobject->save(); $curpos++; } } } } } public function getTemplate($rowtpl, $template = array()) { if (!isset($template[$rowtpl])) { if (substr($rowtpl, 0, 6) == «@FILE:«) { $template[$rowtpl] = file_get_contents($this->modx->config[‘base_path’] . substr($rowtpl, 6)); } elseif (substr($rowtpl, 0, 6) == «@CODE:«) { $template[$rowtpl] = str_replace(array(‘{{‘, ‘}}’), array(‘[[‘, ‘]]’), substr($rowtpl, 6)); } elseif ($chunk = $this->modx->getObject(‘modChunk’, array(‘name’ => $rowtpl), true)) { $template[$rowtpl] = $chunk->getContent(); } else { $template[$rowtpl] = false; } } return $template; } public function addConnectorParams($properties, $unset = ») { global $modx; $properties[‘connectorUrl’] = $this->config[‘connectorUrl’]; $params = array(); $unset = explode(‘,’, $unset); $req = $_REQUEST; foreach ($unset as $param) { unset($req[$param]); } foreach ($req as $key => $value) { $params[] = $key . ‘=’ . $value; } $properties[‘urlparams’] = implode(‘&’, $params); return $properties; } public function getDivisors($integer) { $divisors = array(); for ($i = $integer; $i > 1; $i—) { if (($integer % $i) === 0) { $divisors[] = $i; } } return $divisors; } public function is_modx3(){ $result = false; $versionData = []; if (method_exists($this->modx,‘getVersionData’)){ $versionData = $this->modx->getVersionData(); } if (isset($versionData[‘version’]) && (int) $versionData[‘version’] >= 3){ $result = true; } return $result; } function importconfig($array) { $excludekeys_ifarray = array( ‘getlistwhere’, ‘hooksnippets’, ‘joins’, ‘configs’); $array = $this->recursive_encode($array, $excludekeys_ifarray); return $array; } function recursive_encode($array, $excludekeys_ifarray = array()) { if (is_array($array)) { foreach ($array as $key => $value) { if (!is_int($key) && is_array($value) && in_array($key, $excludekeys_ifarray)) { $array[$key] = !empty($value) ? json_encode($value) : $value; //$array[$key] = $this->recursive_encode($value, $excludekeys); } else { $array[$key] = $this->recursive_encode($value, $excludekeys_ifarray); } } if (!$this->is_assoc($array)) { $array = json_encode($array); } } return $array; } function is_assoc($array) { return (bool)count(array_filter(array_keys($array), ‘is_string’)); } function recursive_decode($array) { foreach ($array as $key => $value) { if (is_string($value) && $decoded = json_decode($value, true)) { $array[$key] = $this->recursive_decode($decoded); } else { $array[$key] = $this->recursive_decode($value); } } return $array; } /** * Indents a flat JSON string to make it more human-readable. * Source: http://recursive-design.com/blog/2008/03/11/format-json-with-php/ * * @param string $json The original JSON string to process. * * @return string Indented version of the original JSON string. */ function indent($json) { $result = »; $pos = 0; $strLen = strlen($json); $indentStr = ‘ ‘; $newLine = «n»; $prevChar = »; $outOfQuotes = true; for ($i = 0; $i <= $strLen; $i++) { // Grab the next character in the string. $char = substr($json, $i, 1); // Are we inside a quoted string? if ($char == ‘»‘ && $prevChar != ‘\’) { $outOfQuotes = !$outOfQuotes; // If this character is the end of an element, // output a new line and indent the next line. } else if (($char == ‘}’ || $char == ‘]’) && $outOfQuotes) { $result .= $newLine; $pos—; for ($j = 0; $j < $pos; $j++) { $result .= $indentStr; } } // Add the character to the result string. $result .= $char; // If the last character was the beginning of an element, // output a new line and indent the next line. if (($char == ‘,’ || $char == ‘{‘ || $char == ‘[‘) && $outOfQuotes) { $result .= $newLine; if ($char == ‘{‘ || $char == ‘[‘) { $pos++; } for ($j = 0; $j < $pos; $j++) { $result .= $indentStr; } } $prevChar = $char; } return $result; } }

    What’s the best way to create a list of items and apply them to blog posts?

    I got this error when trying to add something «There seems to be an error in the formtabs-config».

    If this isn’t the right way, please advise. I want to add a list of categories that I can use for blog posts and events. These will be listed with the loop item. Lists that use software names for example (i.e. Photoshop, Illustrator, InDesign. ). Then I’d I’ll add these to a filter above the results too. But mainly, I want to have this list available from the post’s page (probably as a TV).

    I got this error when trying to add something «There seems to be an error in the formtabs-config».

    If this isn’t the right way, please advise. I want to add a list of categories that I can use for blog posts and events. These will be listed with the loop item. Lists that use software names for example (i.e. Photoshop, Illustrator, InDesign. ). Then I’d I’ll add these to a filter above the results too. But mainly, I want to have this list available from the post’s page (probably as a TV).

    MODX Revolution 2.6.5-pl (traditional)

    Hosted on MODX Cloud

    Thanks, that’s a good idea!

    I’ll give it a shot tonight. I use PDO tools for most of my stuff, we’ll see how that goes.

    Don’t have a MODX.com account? Create one

    In the time it takes to read this, you could start a new site with nothing to download or install.

    Don’t Be That Guy

    Be nice, respectful and patient. Inflammatory or inappropriate posts will get your post nuked and flood your life with bans and bad karma.

    Thank the People that Help

    Remember, this is an Open Source project and the volunteers here assist out of love for the project and a desire to help others.

    Источник

    Проблема пути до файла в MIGX

    Всем привет!
    На сайте реализован MIGX с разными типами файлов вот по этому мануалу: [MIGX] — Большой и страшный. Multiple Formtabs.

    Есть 2 типа условных «слайдов» — фото и видео. Фото взят за основной (как и в примере), видео дополнительным. Для фото всё работает исправно, а в случае с видео не работает правильно путь до файла Mediasources и вывод не обрабатывается pthumb (хотя, конечно, в отдельном чанке).

    Вызов
    Чанк image
    — здесь всё работает правильно, изображения получают правильный путь, обрабатываются pthumb

    А вот media-video
    — как видите, мне приходится тут дописывать /assets/img/ еще и по папкам разбивать для разных страниц. Иначе не работает… Pthumb не отрабатывает совсем(

    Вот настройки этого MIGX
    Settings

    Formtabs

    Mediasources (для видео и его превью одинаковы, равно как и для работающих значений изображений)

    И настройка ресурса в дополнительном поле

    Прошу помощи разобраться… Если какой-то инфы не хватает — скажите, добавлю

    Источник

    MIGX(db) Configuration: Multiple Formtabs purpose and usage

    you can create different formtab-sets by creating some different configurations with different formtabs in it.

    If you select this configurations in the multiple formtabs listbox, you will get a new listbox in your form-window, which switches the formtabs between the different configurations as soon as you select another item on this listbox.

    This is usefull for example, if you have different layouts for each record and you want also to have different input-fields depending on the selected layout.

    you can buy me a beer, if you like MIGX

    That’s what I thought. I just can’t get it to work. I tried to do it like this:

    I created 2 configurations with different input-fields.

    I created a third configuration with those 2 configurations choosen in the listbox and attached this third configuration as a MIGX-TV to a template. Look’s like this is not the way to do it.

    Ok, I think I tried everything but I just can’t get it to work.

    I know how to setup varying layout-boxes as described here http://rtfm.modx.com/display/ADDON/MIGX.Varying+layout-boxes directly in a MIGX-TV or with multiple MIGX-configurations.

    But what I’m looking for are varying layout-boxes for MIGXdb — so for a custom database table/custom object and not for JSON.

    Did anybody ever did something like this with MIGXdb an can point me in the right direction?

    Don’t have a MODX.com account? Create one

    In the time it takes to read this, you could start a new site with nothing to download or install.

    Don’t Be That Guy

    Be nice, respectful and patient. Inflammatory or inappropriate posts will get your post nuked and flood your life with bans and bad karma.

    Thank the People that Help

    Remember, this is an Open Source project and the volunteers here assist out of love for the project and a desire to help others.

    Источник

    MIGX галерея с мультизагрузкой

    Перевод оригинальной статьи Using resource-specific mediasource and multifile-uploader with MIGX. Немного переделана конфигурация для MIGX.

    Создаем источник файлов

    Открываем в верхнем меню пункт «Медиа» — «Источники файлов». Нажимаем «Создать новый источник файлов»:

    • Имя: ResourceMediaPath
    • Тип источника файлов: Файловая система

    Сохраняем, в списке находим только что созданный источник, жмем правую кнопку, выбираем «Редактировать». Необходимо отредактировать поля «basePath» и «baseUrl», установить им значение:

    Необходимо в /assets/ создать директорию resourceimages и установить права на запись.

    Создаем TV параметр

    • Вкладка «Общая информация»
      • Имя — resourcealbum
      • Подпись — Галерея
    • Вкладка «Параметры ввода»
      • Тип ввода — migx
      • Конфигурации — resourcealbum
    • Вкладка «Доступно для шаблонов»
      • Отмечаем шаблоны, в которых будет использоваться галерея.
    • Вкладка «Источники файлов»
      • Для нужного контекста (web по умолчанию) устанавливаем созданный в первом шаге источник файлов ResourceMediaPath (двойным кликом по соответствующему полю).

    Создаем конфигурацию для MIGX

    В верхнем меню переходим в «Приложения» — «MIGX». Переключаемся на вкладку «MIGX» и нажимаем «Добавить элемент». В поле «Name» пишем resourcealbum, нажимаем кнопку «Выполнено». В списке находим созданную конфигурацию, нажимаем правой кнопкой, выбираем «Экспорт/импорт», в текстовое поле вставляем следующий код:

    После этого заходит в документ, который будет использовать галерею, в дополнительных полях видим таблицу и 2 кнопки:

    • Load from media source — загрузить все файлы, которые относятся к этому документу. Кнопка полезна, если вы закачиваете изображения по FTP. Для каждого из документов создается директория в assets/resourceimages/ID.
    • Upload Files — открывает диалоговое окно с загрузкой файлов в галерею.

    Для того, чтобы сделать надписи кнопок на русском языке, можно создать соответствующие записи в лексиконе. Заходим в «Управление словарями», выбираем пространство имен «migx», тема «default», язык «ru» и создаем 2 записи:

    Источник

    Empty Form Tabs in MODX 2.4.4 #256

    Comments

    jchirschy commented Apr 8, 2016

    Since the update in MODX 2.4.4, form tabs in MIGX TV are empty. Grids are ok.
    Did I miss something ?
    I’m using MIGX 2.9.6-pl

    Thanks for your help.

    The text was updated successfully, but these errors were encountered:

    Bruno17 commented Apr 8, 2016

    hmm. haven’t empty formtabs in 2.4.4
    I’m on 2.10.0 (beta10), but I think that shouldn’t matter

    jchirschy commented Apr 8, 2016

    After some researches, the problem appeared when I used the fix related to this issue #222 with that 22004b3. It was actually working fine in migx-2.9-6.
    In migx-2.9.7-pl, I’m facing the same problem with MODX 2.4.4.

    jchirschy commented Apr 11, 2016

    To be a little more precise, this what I’m facing :

      MODX 2.4.2 + migx-2.9-6 : formtabs ok, but extra not loading in the manager (

    [SOLVED] Error when i try to access to MIGX via extras menu in the manager. #222 )

  • MODX 2.4.2 + migx-2-9-6 + ‘patch’ 22004b3 : formtabs empty, but extra loading successfully in the manager.
  • MODX 2.4.4 + migx-2-9-7 : formtabs empty, but extra loading successfully in the manager.
  • Is there someone else who face this problem ?

    Linsizn commented Apr 21, 2016 •

    Hello,
    MODX 2.4.4, — I’m using MIGX 2.10.0(10)
    Does not work!

    after clicking Add Item 1, 2, 3, .

    :

    when holding down the left mouse button:

    Bruno17 commented Apr 26, 2016

    In most cases, where I’ve seen empty formtabs, there was an error in the formtabs-json

    Bruno17 commented Apr 27, 2016

    an upgrade to 2.10.0 beta10 has fixed the issue for @jchirschy

    Footer

    © 2023 GitHub, Inc.

    You can’t perform that action at this time.

    You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.

    Источник

    I am new to react. And I am using react-admin framework. There is issue which i can’t find a solution till now.

    I am using FormTab component in EDIT and using their required() method for validate the NumberInput field, Everything goes superb if i use NumberInput element without Div tag. But when i use NumberInput inside a Div then everything works fine except FormTab error.? Tab is not getting red text if we use NumberInputinside aDiv.

    enter code here

    <Edit {...props}  undoable={false} title={<EditTitle />} >
        <TabbedForm validate={validateInvoice} toolbar={<PackageEditToolbar />} >
            <FormTab label="Name">
                <DisabledInput label="Id" source="id" className="w20" />
                <TextInput source="szName" label="Package name" className="w20" validate={required()}/>
                <SelectInput validate={required()} 
                    source="iActive" label="Status" className="w20"
                    choices={[
                        { id: '1', name: 'Active' },
                        { id: '2', name: 'In-Active' }
                    ]}
                />
            </FormTab>
            <FormTab label="Product Prices">
                <div style={{marginTop:'20px'}}>Product prices</div>
                <ArrayInput source="price_product" label="" style={{ width:'100%',marginTop:'0px'}} className="price_feild">
                    <SimpleFormIterator disableRemove disableAdd >
                        <PriceFeild styleName="productprice"/>
                    </SimpleFormIterator>
                </ArrayInput>   
    
                <div className="TabFormHeading">Channel fee</div>
    
                <NumberInput source="iCNBPrice" label="C&B Prices" className="w20-fl" validate={priceFieldValidation}/>
                <NumberInput source="iBEPrice" label="BE Prices" className="w20-fl"  validate={priceFieldValidation}/>
                <NumberInput source="iEmailPrice" label="Email Prices" className="w20" validate={priceFieldValidation}/>
    
                <div className="row w100">
                 <div className="col-sm-9">
                    <div className="TabFormHeading">BE convert fee</div>
                    <NumberInput source="iMaxConvert" label="Converts greater than" className="w20-fl" validate={NoofcasesValidation}/>
                    <NumberInput source="iConvertFee" label="Convert fee" className="w20"  validate={priceFieldValidation}/>
                 </div>
                 <div className="col-sm-3">
                    <div className="TabFormHeading">BE service agreement</div>
                    <NumberInput source="iServiceCharge" label="Monthly service fee"  validate={priceFieldValidation}/>
                    </div>   
                </div> 
                <div className="TabFormHeading">Insurance channel fee</div>
                <ArrayInput source="insurance_channel_price" label="" style={{ width:'100%',marginTop:'0px',marginBottom:'0px'}} className="price_feild">
                    <SimpleFormIterator disableRemove disableAdd >
                        <PriceFeild />
                    </SimpleFormIterator>
                </ArrayInput>
    
    
    
                <div className="TabFormHeading">Extra services</div>
                <ArrayInput source="addtional_service" label="" style={{ width:'100%',marginTop:'0px',marginBottom:'0px'}} className="price_feild">
                    <SimpleFormIterator disableRemove disableAdd >
                        <PriceFeild />
                    </SimpleFormIterator>
                </ArrayInput>
    
            </FormTab>
            <FormTab label="Invoice Time ">
            <div className="Heading">Time to invoice</div>
                <TextInput source="szError" label=""  style={{ display:'none'}}/>
                <CheckboxGroupInput source="iInvoiceEOM" className="m-tb-none" label="" choices={[
                        { id: '1', name: 'EOM / End of month' },
                ]} />
                <CheckboxGroupInput source="iInvoiceDate" className="m-tb-none" label="" choices={[
                        { id: '1', name: 'Every 10. in each month' },
                ]} />
                <CheckboxGroupInput source="iInvoicePropertySold" className="m-tb-none" label="" choices={[
                        { id: '1', name: 'Property is sold' },
                ]} />
                <CheckboxGroupInput source="iInvoiceRecurring" className="m-tb-none" label="" choices={[
                        { id: '1', name: 'Recurring invoice' },
                ]} />
            </FormTab>
            <FormTab label="Discount Prices ">
            <div style={{marginTop:'20px'}}>Magazine number discount</div>
                <SelectInput className="w20-fl" source="iMagazineDiscountPeriod" label="Discount Period"
                    choices={[
                        { id: '1', name: '1 Month' },
                        { id: '2', name: '2 Month' },
                        { id: '3', name: '3 Month' },
                        { id: '4', name: '4 Month' },
                        { id: '5', name: '5 Month' },
                        { id: '6', name: '6 Month' },
                        { id: '7', name: '7 Month' },
                        { id: '8', name: '8 Month' },
                        { id: '9', name: '9 Month' },
                        { id: '10', name: '10 Month' },
                        { id: '11', name: '11 Month' },
                        { id: '12', name: '12 Month' },
                    ]}
                />
                <NumberInput source="iDiscountAfterMagazine" label="No of magazine" className="w20" />
    
                <div className="TabFormHeading">Product type discount</div>
                <ArrayInput source="product_type_discount" label="" style={{ width:'100%',marginTop:'0px',marginBottom:'0px'}} className="price_feild productTypeDiscount ">
                    <SimpleFormIterator disableRemove disableAdd className="productTypeDiscount">
                        <PriceFeild />
                    </SimpleFormIterator>
                </ArrayInput>
    
            </FormTab>
        </TabbedForm>
    
    </Edit>
    

    Hi,
    I’ve got Migx Nested setup working, but there is a strange problem. In migxdb cmp everything work fine till I start to ad records to child cmp. As I add records to child cmp, records from parent cmp start to disapear.
    111

    As you can see, cmp sees all records, but shows not all of them. As I add more records to children cmp, less records are shown in parent cmp. If I set max records to display to some huge number, it works, but it’s not a workaround. Btw, the search filter works. Even if there some records missing in grid, it shows them if I searc for them.

    <?xml version="1.0" encoding="UTF-8"?>
    <model package="productsapp" baseClass="xPDOObject" platform="mysql" defaultEngine="MyISAM" version="1.1">
        <object class="Product" table="migx_pa_products" extends="xPDOSimpleObject" >
            <field key="title" dbtype="mediumtext" phptype="string" null="false" default=""/>
            <field key="longtitle" dbtype="varchar" precision="255" phptype="string" null="false" default=""/>
            <field key="alias" dbtype="varchar" precision="255" phptype="string" null="true" default=""/>
            <field key="intro" dbtype="mediumtext" phptype="string" null="false" default=""/>
            <field key="content" dbtype="mediumtext" phptype="string" null="false" default=""/>
            <field key="photo" dbtype="text" phptype="string" null="false" default=""/>
    
            <field key="galerie" dbtype="mediumtext" phptype="string" null="false" default=""/>
    
            <field key="cat_id" dbtype="int" precision="10" attributes="unsigned" phptype="integer" null="false" default=""/>
            <field key="brand_id" dbtype="int" precision="10" attributes="unsigned" phptype="integer" null="false" default=""/>
    
            <field key="published" dbtype="int" precision="1" attributes="unsigned" phptype="integer" null="false" default="0" />
            <field key="pos" dbtype="int" precision="10" attributes="unsigned" phptype="integer" null="false" default="0" />
    
            <aggregate alias="ProdCategory" class="Category" local="cat_id" foreign="id" cardinality="one" owner="foreign"/>
            <aggregate alias="ProdBrand" class="Brand" local="brand_id" foreign="id" cardinality="one" owner="foreign"/>
        </object>
    
    
        <object class="Category" table="migx_pa_categories" extends="xPDOSimpleObject" >
            <field key="title" dbtype="varchar" precision="255" phptype="string" null="false" default=""/>
    
            <field key="showonstart" dbtype="int" precision="1" attributes="unsigned" phptype="integer" null="false" default="0" />
    
            <composite alias="CatProduct" class="Product" local="id" foreign="cat_id" owner="local" cardinality="many" />
            <composite alias="CatBrandcategory" class="Brandcategory" local="id" foreign="cat_id" owner="local" cardinality="many" />
        </object>
    
        <object class="Brand" table="migx_pa_brands" extends="xPDOSimpleObject" >
            <field key="title" dbtype="varchar" precision="255" phptype="string" null="false" default=""/>
            <field key="alias" dbtype="varchar" precision="255" phptype="string" null="true" default=""/>
            <field key="logo" dbtype="text" phptype="string" null="false" default=""/>
            <field key="content" dbtype="mediumtext" phptype="string" null="false" default=""/>
            <field key="published" dbtype="int" precision="1" attributes="unsigned" phptype="integer" null="false" default="0" />
            <composite alias="BrandProduct" class="Product" local="id" foreign="brand_id" owner="local" cardinality="many" />
            <composite alias="BrandBrandcategory" class="Brandcategory" local="id" foreign="brand_id" owner="local" cardinality="many" />
        </object>
    
        <object class="Brandcategory" table="migx_pa_brandcats" extends="xPDOSimpleObject" >
            <field key="cat_id" dbtype="int" precision="10" attributes="unsigned" phptype="integer" null="false" default=""/>
            <field key="brand_id" dbtype="int" precision="10" attributes="unsigned" phptype="integer" null="false" default=""/>
    
            <field key="content" dbtype="mediumtext" phptype="string" null="false" default=""/>
    
            <aggregate alias="BrandCatCategory" class="Category" local="cat_id" foreign="id" cardinality="one" owner="foreign"/>
            <aggregate alias="BrandCatBrand" class="Brand" local="brand_id" foreign="id" cardinality="one" owner="foreign"/>
        </object>
    </model>
    
    
    {
      "formtabs":[
        {
          "MIGX_id":11,
          "caption":"Brand",
          "print_before_tabs":"0",
          "fields":[
            {
              "MIGX_id":35,
              "field":"title",
              "caption":"Name",
              "description":"",
              "description_is_code":"0",
              "inputTV":"",
              "inputTVtype":"",
              "validation":"",
              "configs":"",
              "restrictive_condition":"",
              "display":"",
              "sourceFrom":"config",
              "sources":"",
              "inputOptionValues":"",
              "default":"",
              "useDefaultIfEmpty":"0",
              "pos":1
            },
            {
              "MIGX_id":36,
              "field":"alias",
              "caption":"Alias",
              "description":"",
              "description_is_code":"0",
              "inputTV":"",
              "inputTVtype":"",
              "validation":"",
              "configs":"",
              "restrictive_condition":"",
              "display":"",
              "sourceFrom":"config",
              "sources":"",
              "inputOptionValues":"",
              "default":"",
              "useDefaultIfEmpty":"0",
              "pos":2
            },
            {
              "MIGX_id":37,
              "field":"logo",
              "caption":"Logo",
              "description":"",
              "description_is_code":"0",
              "inputTV":"",
              "inputTVtype":"image",
              "validation":"",
              "configs":"",
              "restrictive_condition":"",
              "display":"",
              "sourceFrom":"config",
              "sources":[
                {
                  "MIGX_id":1,
                  "context":"web",
                  "sourceid":3
                },
                {
                  "MIGX_id":2,
                  "context":"mgr",
                  "sourceid":3
                }
              ],
              "inputOptionValues":"",
              "default":"",
              "useDefaultIfEmpty":"0",
              "pos":3
            },
            {
              "MIGX_id":38,
              "field":"content",
              "caption":"Content",
              "description":"",
              "description_is_code":"0",
              "inputTV":"",
              "inputTVtype":"richtext",
              "validation":"",
              "configs":"",
              "restrictive_condition":"",
              "display":"",
              "sourceFrom":"config",
              "sources":"",
              "inputOptionValues":"",
              "default":"",
              "useDefaultIfEmpty":"0",
              "pos":4
            },
            {
              "MIGX_id":39,
              "field":"published",
              "caption":"Published",
              "description":"",
              "description_is_code":"0",
              "inputTV":"",
              "inputTVtype":"checkbox",
              "validation":"",
              "configs":"",
              "restrictive_condition":"",
              "display":"",
              "sourceFrom":"config",
              "sources":"",
              "inputOptionValues":"ja==1",
              "default":1,
              "useDefaultIfEmpty":"0",
              "pos":5
            }
          ],
          "pos":1
        },
        {
          "MIGX_id":12,
          "caption":"Brand Kategorien",
          "print_before_tabs":"0",
          "fields":[
            {
              "MIGX_id":40,
              "field":"",
              "caption":"Brand Kategorien",
              "description":"",
              "description_is_code":"0",
              "inputTV":"",
              "inputTVtype":"migxdb",
              "validation":"",
              "configs":"pa_brandcats",
              "restrictive_condition":"",
              "display":"",
              "sourceFrom":"config",
              "sources":"",
              "inputOptionValues":"",
              "default":"",
              "useDefaultIfEmpty":"0",
              "pos":1
            }
          ],
          "pos":2
        }
      ],
      "contextmenus":"update||publish||unpublish",
      "actionbuttons":"addItem",
      "columnbuttons":"update||publish||unpublish",
      "filters":[
        {
          "MIGX_id":1,
          "name":"search",
          "label":"Suche",
          "emptytext":"Suche",
          "type":"textbox",
          "getlistwhere":{
            "title:LIKE":"%[[+search]]%"
          },
          "getcomboprocessor":"",
          "combotextfield":"",
          "comboidfield":"",
          "combowhere":"",
          "comboclassname":"",
          "combopackagename":"",
          "combo_use_custom_prefix":"0",
          "comboprefix":"",
          "combojoins":"",
          "comboparent":"",
          "default":""
        }
      ],
      "extended":{
        "migx_add":"",
        "disable_add_item":"",
        "add_items_directly":"",
        "formcaption":"",
        "update_win_title":"",
        "win_id":"pa_brands",
        "maxRecords":"",
        "addNewItemAt":"bottom",
        "media_source_id":"",
        "multiple_formtabs":"",
        "multiple_formtabs_label":"",
        "multiple_formtabs_field":"",
        "multiple_formtabs_optionstext":"",
        "multiple_formtabs_optionsvalue":"",
        "actionbuttonsperrow":4,
        "winbuttonslist":"",
        "extrahandlers":"",
        "filtersperrow":4,
        "packageName":"productsapp",
        "classname":"Brand",
        "task":"",
        "getlistsort":"title",
        "getlistsortdir":"",
        "sortconfig":"",
        "gridpagesize":"",
        "use_custom_prefix":"0",
        "prefix":"",
        "grid":"",
        "gridload_mode":2,
        "check_resid":1,
        "check_resid_TV":"",
        "join_alias":"",
        "has_jointable":"yes",
        "getlistwhere":"",
        "joins":[
          {
            "alias":"BrandBrandcategory"
          }
        ],
        "hooksnippets":{
          "aftersave":"migxAlias"
        },
        "cmpmaincaption":"Brands",
        "cmptabcaption":"Brands",
        "cmptabdescription":"Brands verwalten",
        "cmptabcontroller":"",
        "winbuttons":"",
        "onsubmitsuccess":"",
        "submitparams":""
      },
      "columns":[
        {
          "MIGX_id":1,
          "header":"Id",
          "dataIndex":"id",
          "width":20,
          "sortable":"false",
          "show_in_grid":"0",
          "customrenderer":"",
          "renderer":"",
          "clickaction":"",
          "selectorconfig":"",
          "renderchunktpl":"",
          "renderoptions":"",
          "editor":""
        },
        {
          "MIGX_id":6,
          "header":"Alias",
          "dataIndex":"alias",
          "width":20,
          "sortable":"false",
          "show_in_grid":1,
          "customrenderer":"",
          "renderer":"",
          "clickaction":"",
          "selectorconfig":"",
          "renderchunktpl":"",
          "renderoptions":"",
          "editor":""
        },
        {
          "MIGX_id":2,
          "header":"Name",
          "dataIndex":"title",
          "width":20,
          "sortable":"false",
          "show_in_grid":1,
          "customrenderer":"",
          "renderer":"",
          "clickaction":"",
          "selectorconfig":"",
          "renderchunktpl":"",
          "renderoptions":"",
          "editor":""
        },
        {
          "MIGX_id":5,
          "header":"Published",
          "dataIndex":"published",
          "width":20,
          "sortable":"false",
          "show_in_grid":1,
          "customrenderer":"",
          "renderer":"this.renderCrossTick",
          "clickaction":"",
          "selectorconfig":"",
          "renderchunktpl":"",
          "renderoptions":"",
          "editor":""
        }
      ],
      "category":""
    }
    
    
    {
      "formtabs":[
        {
          "MIGX_id":6,
          "caption":"Brand Kategorien",
          "print_before_tabs":"0",
          "fields":[
            {
              "MIGX_id":18,
              "field":"cat_id",
              "caption":"Kategorie",
              "description":"",
              "description_is_code":"0",
              "inputTV":"",
              "inputTVtype":"listbox",
              "validation":"required",
              "configs":"",
              "restrictive_condition":"",
              "display":"",
              "sourceFrom":"config",
              "sources":"",
              "inputOptionValues":"@EVAL return $modx->runSnippet('mxdbBrandCatList',array('packageName'=>'productsapp','classname'=>'Category','objId'=>$modx->getOption('object_id',$_REQUEST,'undefined'),'coId'=>$modx->getOption('co_id',$_REQUEST,'undefined')));",
              "default":"",
              "useDefaultIfEmpty":"0",
              "pos":1
            },
            {
              "MIGX_id":19,
              "field":"content",
              "caption":"Content",
              "description":"",
              "description_is_code":"0",
              "inputTV":"",
              "inputTVtype":"richtext",
              "validation":"",
              "configs":"",
              "restrictive_condition":"",
              "display":"",
              "sourceFrom":"config",
              "sources":"",
              "inputOptionValues":"",
              "default":"",
              "useDefaultIfEmpty":"0",
              "pos":2
            },
            {
              "MIGX_id":25,
              "field":"brand_id",
              "caption":"",
              "description":"",
              "description_is_code":"0",
              "inputTV":"",
              "inputTVtype":"",
              "validation":"",
              "configs":"",
              "restrictive_condition":"",
              "display":"none",
              "sourceFrom":"config",
              "sources":"",
              "inputOptionValues":"",
              "default":"@EVAL return $modx->getOption('co_id',$_REQUEST,'undefined');",
              "useDefaultIfEmpty":1,
              "pos":3
            }
          ],
          "pos":1
        }
      ],
      "contextmenus":"update||duplicate||remove",
      "actionbuttons":"addItem",
      "columnbuttons":"update||duplicate||remove",
      "filters":"",
      "extended":{
        "migx_add":"",
        "disable_add_item":"",
        "add_items_directly":"",
        "formcaption":"",
        "update_win_title":"",
        "win_id":"pa_brandcats",
        "maxRecords":"",
        "addNewItemAt":"bottom",
        "media_source_id":"",
        "multiple_formtabs":"",
        "multiple_formtabs_label":"",
        "multiple_formtabs_field":"",
        "multiple_formtabs_optionstext":"",
        "multiple_formtabs_optionsvalue":"",
        "actionbuttonsperrow":4,
        "winbuttonslist":"",
        "extrahandlers":"",
        "filtersperrow":4,
        "packageName":"productsapp",
        "classname":"Brandcategory",
        "task":"",
        "getlistsort":"",
        "getlistsortdir":"",
        "sortconfig":"",
        "gridpagesize":"",
        "use_custom_prefix":"0",
        "prefix":"",
        "grid":"",
        "gridload_mode":2,
        "check_resid":"0",
        "check_resid_TV":"",
        "join_alias":"BrandCatBrand",
        "has_jointable":"yes",
        "getlistwhere":{
          "brand_id":"[[+object_id]]"
        },
        "joins":[
          {
            "alias":"BrandCatCategory"
          }
        ],
        "hooksnippets":"",
        "cmpmaincaption":"Brand Kategorien",
        "cmptabcaption":"Brand Kategorien",
        "cmptabdescription":"Brand Kategorien verwalten",
        "cmptabcontroller":"",
        "winbuttons":"",
        "onsubmitsuccess":"",
        "submitparams":""
      },
      "columns":[
        {
          "MIGX_id":1,
          "header":"Id",
          "dataIndex":"id",
          "width":"",
          "sortable":"false",
          "show_in_grid":"0",
          "customrenderer":"",
          "renderer":"",
          "clickaction":"",
          "selectorconfig":"",
          "renderchunktpl":"",
          "renderoptions":"",
          "editor":""
        },
        {
          "MIGX_id":2,
          "header":"Kategorie",
          "dataIndex":"BrandCatCategory_title",
          "width":25,
          "sortable":"false",
          "show_in_grid":1,
          "customrenderer":"",
          "renderer":"",
          "clickaction":"",
          "selectorconfig":"",
          "renderchunktpl":"",
          "renderoptions":"",
          "editor":""
        },
        {
          "MIGX_id":3,
          "header":"Content",
          "dataIndex":"content",
          "width":75,
          "sortable":"false",
          "show_in_grid":1,
          "customrenderer":"",
          "renderer":"",
          "clickaction":"",
          "selectorconfig":"",
          "renderchunktpl":"",
          "renderoptions":"",
          "editor":""
        }
      ],
      "category":""
    }
    

    Понравилась статья? Поделить с друзьями:
  • There is problem with this windows installer package a program run as part как исправить
  • There is not enough room on your disk to install roblox как исправить
  • There is no stack trace or error line information available for this error
  • There is no cuda device which is selected octane render как исправить
  • There is another instance of doom running как исправить