суббота, 28 января 2012 г.

tt_news - добавление новых полей к плагину


Чтобы лучше понять задачу ради которой я решил добавить к tt_news ряд полей, читайте первую часть.

Для того, чтобы к любому расширению Typo3 добавить новое поле, не нужно курочить тело плагина (экста). Это - плохой тон, потому что после очередного обновления данного плагина все ваши изменения будут удалены. Хороший тон - сделать новый плагин. Причем, один такой дополнительный плагин может расширять несколько экстов Typo3 одновременно.

Создать новое расширение можно с помощью инструмента - kickstarter. Но в данной ситуации я поступил иначе. Я скачал и установил уже готовый плагин - ttnewsfield, который добавляет к tt_news одно единственное поле -  tx_ttnewsfield_linktitle. Этот плагин послужил мне замечательной стартовой площадкой для добавления множества других полей.

Рассмотрим добавление 5 различных полей: обычное текстовое поле, поле в виде выпадающего списка, поле ссылающееся на запись  из другой таблицы (отношение 1:1), поле ссылающееся на записи  из другой таблицы (отношение 1:n), IRRE поле.



Добавление обычного текстового поля


Все что нужно для работы - это текстовый редактор и 3 файла ранее установленного ttnewsfield: ext_tables.sql, locallang_db.xml и ext_tables.php. Хотя, по-большому счету ext_tables.sql можно и не трогать, если  менять структуру таблиц с помощью phpmyadmin или других программ. Думаю, что с этим файлом всё абсолютно понятно и я не буду о нем писать, как и о locallang_db.xml, который содержит набор текстовых констант, которые служат для отображения надписей в админке и её локализации.

Самое интересное творится в ext_tables.php. На старте содержимое файла такое:

$tempColumns = Array (
    "tx_ttnewsfield_linktitle" => Array (
        "exclude" => 0,
        "label" => "LLL:EXT:ttnewsfield/locallang_db.xml:tt_news.tx_ttnewsfield_linktitle",
        "config" => Array (
            "type" => "input",
            "size" => "15",    
            "max" => "64",
            "eval" => "trim",
        )
    ),
);
t3lib_div::loadTCA("tt_news");
t3lib_extMgm::addTCAcolumns("tt_news",$tempColumns,1);
$TCA['tt_news']['palettes']['1']['showitem'] .= ",tx_ttnewsfield_linktitle";



Поле tx_ttnewsfield_linktitle, которое добавляется в эксте мне не интересно, поэтому я его переименовал в tx_fitness_vimeo. Его задача - хранить обычный кусок html-кода.
Вот описание этого поля для админки в файле ext_tables.php:

'tx_fitness_vimeo' => Array (
'label' => 'LLL:EXT:ttnews_fitness/locallang_db.xml:tx_ttnewsirre_vimeo',
'l10n_mode' => $l10n_mode,
'config' => Array (
'type' => 'text',
'cols' => '48',
'rows' => '5',
'softref' => 'typolink_tag,images,email[subst],url',
'wizards' => Array(
'_PADDING' => 4,
'RTE' => Array(
'notNewRecords' => 1,
'RTEonly' => 1,
'type' => 'script',
'title' => 'LLL:EXT:cms/locallang_ttc.php:bodytext.W.RTE',
'icon' => 'wizard_rte2.gif',
'script' => 'wizard_rte.php',
),
)
)
),
Хочу заметить, что данные строки и все последующие являются элементами массива $tempColumns, который я переименовал в $fitnessColumns. Чтобы лучше понять значение каждого из вышеуказанных параметров элемента массива - почитайте мануал по TCA array reference. Там нет ничего сложного.

А вот так поле будет выглядеть в админке:
Чтобы отобразить содержимое данного поля на FE советую заглянуть во внутрь экста - Raw HTML in tt_news ( ttnews_html ) или Youtube for tt_news ( esg_youtubenews ). Абсолютно ничего военного они не делают. Добавляется одна строка в файл ext_localconf.php и создается дополнительный файл с 10-15 строками, в котором идет сопоставление значения нового поля с определенным маркером в html-шаблоне. Но правда, есть еще один способ вывода. Это универсальный экст - ttnewsgenericmarkers, который выводит в html-шаблон все, что угодно.

Добавление поля с фиксированным списком

Сделать дополнительное поле в виде статического списка значение тоже не сложно.
Вот пример, для поля tx_fitness_shared_office_suitability, которое может принимать всего 5 значений: 1, 2, 3, 4 и 5 (файл ext_tables.php):

"tx_fitness_shared_office_suitability" => Array (
"exclude" => 0,
"label" => "LLL:EXT:ttnews_fitness/locallang_db.xml:tx_ttnewsirre_shared_office_suitability",
'config' => array(
'type' => 'select',
'items' => array(
array('LLL:EXT:ttnews_fitness/locallang_db.xml:suitability.1', 1),
array('LLL:EXT:ttnews_fitness/locallang_db.xml:suitability.2', 2),
array('LLL:EXT:ttnews_fitness/locallang_db.xml:suitability.3', 3),
array('LLL:EXT:ttnews_fitness/locallang_db.xml:suitability.4', 4),
array('LLL:EXT:ttnews_fitness/locallang_db.xml:suitability.5', 5),
),
),
),

Эти 5 строк нужно добавить в файл locallang_db.xml:


<label index="suitability.1">1</label>
<label index="suitability.2">2</label>
<label index="suitability.3">3</label>
<label index="suitability.4">4</label>
<label index="suitability.5">5</label>
Если числа внутри тега label заменить на слова, то список станет более информативным.
Внешний вид такого списка в админке typo3:


Добавление поля-ссылки (отношение 1 к 1)


Ради таких полей я и решил написать данную статью. Меня давно интересовал данный вопрос. И вот, наконец-то, я его разрулил.

В предыдущем случае поле (tx_fitness_shared_office_suitability) являлось фиксированным списком из пяти значений, но что делать если нужен динамический список элементов? Тут все немного интереснее.

1. Создаем новую таблицу в БД, которая, собственно и будет содержать все значения списка.
В моем случае эта таблица имела такую структуру:
CREATE TABLE `tx_fitness_workarea` (
  `uid` int(11) unsigned NOT NULL auto_increment,
  `pid` int(11) NOT NULL default '0',
  `tstamp` int(11) NOT NULL default '0',
  `crdate` int(11) NOT NULL default '0',
  `cruser_id` int(11) NOT NULL default '0',
  `sys_language_uid` int(11) NOT NULL default '0',
  `l18n_parent` int(11) NOT NULL default '0',
  `l18n_diffsource` mediumblob NOT NULL,
  `deleted` tinyint(4) NOT NULL default '0',
  `is_dummy_record` tinyint(1) unsigned NOT NULL default '0',
  `title` tinytext NOT NULL,
  PRIMARY KEY  (`uid`),
  KEY `parent` (`pid`),
  KEY `dummy` (`is_dummy_record`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8

Самое ценное из всех полей данной таблицы, конечно же поле title. Остальные поля - служебные и интересуют больше не меня, а typo3.

В таблицу tt_news я добавил числовое поле tx_fitness_workarea, которое будет содержать uid только одной записи из таблицы tx_fitness_workarea. Вот sql-определение данного поля:
CREATE TABLE tt_news (
...
tx_fitness_workarea int(11) NOT NULL default '0',
...
);

Эти настройки ТСА сделают новое поле tx_fitness_workarea в таблице tt_news выпадающим списком, который будет наполнен строками из таблицы tx_fitness_workarea:

'tx_fitness_workarea' => array(
'exclude' => 1,
'label' => 'LLL:EXT:ttnews_fitness/locallang_db.xml:tx_ttnewsirre_workarea',
'config' => array(
'type' => 'select',
'items' => array(
array('', 0),
),
'foreign_table' => 'tx_fitness_workarea',
'foreign_table_where' => 'AND tx_fitness_workarea.pid=###STORAGE_PID### ORDER BY tx_fitness_workarea.title',
'size' => 1,
'minitems' => 0,
'maxitems' => 1,
'wizards' => array(
'_PADDING' => 2,
'_VERTICAL' => 1,
'add' => array(
'type' => 'script',
'title' => 'Create new record',
'icon' => 'add.gif',
'params' => array(
'table'=>'tx_fitness_workarea',
'pid' => '###STORAGE_PID###',
'setValue' => 'prepend',
),
'script' => 'wizard_add.php',
),
'edit' => array(
'type' => 'popup',
'title' => 'Edit',
'script' => 'wizard_edit.php',
'popup_onlyOpenIfSelected' => 1,
'icon' => 'edit2.gif',
'JSopenParams' => 'height=350,width=580,status=0,menubar=0,scrollbars=1',
),
),
),
)
Вот так поле будет выглядеть в админке:


Самое интересное, как вы уже заметили, что возле списка есть кнопки, которые позволяют редактировать значения списка и добавлять в него новые элементы. Чтобы эти кнопки работали необходимо в файл ext_tables.php вставить следующие строки:

t3lib_extMgm::allowTableOnStandardPages("tx_fitness_workarea");
$TCA['tx_fitness_workarea'] = array(
'ctrl' => array(
'title' => 'LLL:EXT:ttnews_fitness/locallang_db.xml:tx_ttnewsirre_workarea',
'label' => 'title',
//'rootLevel' => 0,
'tstamp' => 'tstamp',
'crdate' => 'crdate',
'cruser_id' => 'cruser_id',
'languageField' => 'sys_language_uid',
'transOrigPointerField' => 'l18n_parent',
'transOrigDiffSourceField' => 'l18n_diffsource',
'default_sortby' => 'ORDER BY title',
'delete' => 'deleted',
"iconfile" => t3lib_extMgm::extRelPath($_EXTKEY)."res/workarea.gif"
),
'interface' => array(
'showRecordFieldList' => 'sys_language_uid,l18n_parent,l18n_diffsource,title'
),
"feInterface" => $TCA["tx_fitness_workarea"]["feInterface"],
'columns' => array(
'sys_language_uid' => array(
'exclude' => 1,
'label' => 'LLL:EXT:lang/locallang_general.xml:LGL.language',
'config' => array(
'type' => 'select',
'foreign_table' => 'sys_language',
'foreign_table_where' => 'ORDER BY sys_language.title',
'items' => array(
array('LLL:EXT:lang/locallang_general.xml:LGL.allLanguages', -1),
array('LLL:EXT:lang/locallang_general.xml:LGL.default_value', 0),
),
),
),
'l18n_parent' => array(
'displayCond' => 'FIELD:sys_language_uid:>:0',
'exclude' => 1,
'label' => 'LLL:EXT:lang/locallang_general.xml:LGL.l18n_parent',
'config' => array(
'type' => 'select',
'items' => array(
array('', 0),
),
'foreign_table' => 'tx_fitness_workarea',
'foreign_table_where' => 'AND tx_fitness_workarea.pid=###CURRENT_PID### AND tx_fitness_workarea.sys_language_uid IN (-1, 0)',
),
),
'l18n_diffsource' => array(
'config' => array(
'type' => 'passthrough',
)
),
'title' => array(
'exclude' => 0,
'label' => 'LLL:EXT:ttnews_fitness/locallang_db.xml:tx_ttnewsirre_workarea',
'config' => array(
'type' => 'input',
'size' => '30',
'eval' => 'required',
),
),
),
'types' => array(
'0' => array('showitem' => 'sys_language_uid;;;;1-1-1, l18n_parent, l18n_diffsource, title;;;;2-2-2'),
),
'palettes' => array(
'1' => array('showitem' => ''),
)
);


Хочу заметить, что эти строки уже не являются элементами массива $tempColumns ($fitnessColumns).

Теперь немного о ###CURRENT_PID### и ###STORAGE_PID###, которые поначалу вызывают недоумение. Что это такое? В принципе, имеются ввиду id фолдера или страницы содержащих (отображающие) записи таблицы tx_fitness_workarea.
Вначале у меня были какие-то ошибки при добавлении новых записей, но всё вылечилось установкой General Record Storage Page для фолдера хранящего все мои данные:

Добавление поля-ссылки (отношение один ко многим 1:n)


Ну а теперь самый сложный и самый интересный случай, когда на одну запись из родительской таблицы (tt_news) ссылается несколько записей из дочерней таблицы.

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

Итак, дополнительное поле в tt_news будет называться -  tx_fitness_equipment, дочерняя таблица - tx_fitness_equipment (список тренажеров), а промежуточная таблица -  tt_news_mainequipment_mm.
SQL для данной модели данных у меня такой:

CREATE TABLE tt_news (
...
  tx_fitness_equipment text,
...
);
CREATE TABLE `tx_fitness_equipment` (
  `uid` int(11) NOT NULL auto_increment,
  `pid` int(11) NOT NULL default '0',
  `tstamp` int(11) NOT NULL default '0',
  `crdate` int(11) NOT NULL default '0',
  `cruser_id` int(11) NOT NULL default '0',
  `sys_language_uid` int(11) NOT NULL default '0',
  `l18n_parent` int(11) NOT NULL default '0',
  `l18n_diffsource` mediumblob NOT NULL,
  `sorting` int(10) NOT NULL default '0',
  `deleted` tinyint(4) NOT NULL default '0',
  `hidden` tinyint(4) NOT NULL default '0',
  `t3ver_oid` int(11) NOT NULL default '0',
  `t3ver_id` int(11) NOT NULL default '0',
  `t3ver_wsid` int(11) NOT NULL default '0',
  `t3ver_label` varchar(30) NOT NULL default '',
  `t3ver_state` tinyint(4) NOT NULL default '0',
  `t3ver_stage` tinyint(4) NOT NULL default '0',
  `t3ver_count` int(11) NOT NULL default '0',
  `t3ver_tstamp` int(11) NOT NULL default '0',
  `t3ver_move_id` int(11) NOT NULL default '0',
  `t3_origuid` int(11) NOT NULL default '0',
  `title` tinytext NOT NULL,
  `exercises` int(11) NOT NULL default '0',
  `image` varchar(255) default NULL,

  PRIMARY KEY  (`uid`),
  KEY `parent` (`pid`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8

CREATE TABLE `tt_news_mainequipment_mm` (
  `uid_local` int(11) NOT NULL default '0',
  `uid_foreign` int(11) NOT NULL default '0',
  `tablenames` varchar(30) NOT NULL default '',
  `sorting` int(11) NOT NULL default '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8

Последняя таблица в своем наименовании имеет суффикс MM. Это не просто так. У Typo3 такой вид отношений между таблицами называется mm-отношения. Это довольно распространенный вид взаимосвязи,  наиболее ярким примером которой могут послужить новости и их категории. Ведь одна новость может принадлежать к нескольким категориям, а одна категория может принадлежать нескольким новостям.

Итак, в ext_tables.php добавляем:


'tx_fitness_equipment' => Array (
'exclude' => 1,
"label" => "LLL:EXT:ttnews_fitness/locallang_db.xml:tx_ttnewsirre_equipment",
'config' => Array (
'type' => 'select',
'size' => 10,
'foreign_table' => 'tx_fitness_equipment',
'foreign_table_where' => 'ORDER BY title',
'autoSizeMax' => 50,
'minitems' => 0,
'maxitems' => 10,
'MM' => 'tt_news_mainequipment_mm',
)
),


t3lib_extMgm::allowTableOnStandardPages("tx_fitness_equipment");
$TCA["tx_fitness_equipment"] = Array (
"ctrl" => Array (
'title' => 'LLL:EXT:ttnews_fitness/locallang_db.xml:tt_news.tx_ttnewsfield_equipment',
'label' => 'title',
'tstamp' => 'tstamp',
'crdate' => 'crdate',
'cruser_id' => 'cruser_id',
'languageField'            => 'sys_language_uid',
'transOrigPointerField'    => 'l18n_parent',
'transOrigDiffSourceField' => 'l18n_diffsource',
"sortby" => "sorting",
"delete" => "deleted",
"enablecolumns" => Array (
"disabled" => "hidden",
),
"iconfile" => t3lib_extMgm::extRelPath($_EXTKEY)."res/equipment.gif",
'versioningWS' => TRUE,
'origUid' => 't3_origuid',
),
"interface" => Array (
"showRecordFieldList" => "sys_language_uid,l18n_parent,l18n_diffsource,hidden,title,image,exercises"
),
"feInterface" => $TCA["tx_fitness_equipment"]["feInterface"],
"columns" => Array (
'sys_language_uid' => array (
'exclude' => 1,
'label'  => 'LLL:EXT:lang/locallang_general.xml:LGL.language',
'config' => array (
'type'                => 'select',
'foreign_table'       => 'sys_language',
'foreign_table_where' => 'ORDER BY sys_language.title',
'items' => array(
array('LLL:EXT:lang/locallang_general.xml:LGL.allLanguages', -1),
array('LLL:EXT:lang/locallang_general.xml:LGL.default_value', 0)
)
)
),
'l18n_parent' => array (
'displayCond' => 'FIELD:sys_language_uid:>:0',
'exclude'     => 1,
'label'       => 'LLL:EXT:lang/locallang_general.xml:LGL.l18n_parent',
'config'      => array (
'type'  => 'select',
'items' => array (
array('', 0),
),
'foreign_table'       => 'tx_fitness_equipment',
'foreign_table_where' => 'AND tx_fitness_equipment.pid=###CURRENT_PID### AND tx_fitness_equipment.sys_language_uid IN (-1,0)',
)
),
'l18n_diffsource' => array (
'config' => array (
'type' => 'passthrough'
)
),
"hidden" => Array (
"exclude" => 1,
"label" => "LLL:EXT:lang/locallang_general.xml:LGL.hidden",
"config" => Array (
"type" => "check",
"default" => "0"
)
),
"title" => Array (
"exclude" => 1,
'l10n_mode' => 'prefixLangTitle',
"label" => "LLL:EXT:ttnews_fitness/locallang_db.xml:tt_news.tx_ttnewsfield_equipment",
"config" => Array (
"type" => "input",
"size" => "30",
"eval" => "required",
)
),
'image' => array (
'exclude' => 0,
'l10n_mode' => 'exclude',
'label' => 'LLL:EXT:ttnews_fitness/locallang_db.xml:tt_news.tx_ttnewsfield_image',
'config' => array (
'type' => 'group',
'internal_type' => 'file',
'allowed' => $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'],
'max_size' => $GLOBALS['TYPO3_CONF_VARS']['BE']['maxFileSize'],
'uploadfolder' => 'uploads/tx_ttnews',
'show_thumbs' => '1',
'size' => 1,
'minitems' => 0,
'maxitems' => 1,
)
),
"exercises" => Array (
"exclude" => 1,
"label" => "LLL:EXT:ttnews_fitness/locallang_db.xml:tt_news.tx_ttnewsfield_exercises",
"config" => Array (
"type" => "inline",
"foreign_table" => "tx_fitness_exercise2equipment",
"foreign_field" => "equipmentid",
"foreign_sortby" => "equipmentsort",
"foreign_label" => "exerciseid",
"maxitems" => 10,
'appearance' => array(
'showSynchronizationLink' => 1,
'showAllLocalizationLink' => 1,
'showPossibleLocalizationRecords' => 1,
'showRemovedLocalizationRecords' => 1,
),
'behaviour' => array(
'localizationMode' => 'select',
),
)
),
),
"types" => Array (
"0" => Array("showitem" => "sys_language_uid;;;;1-1-1, l18n_parent, l18n_diffsource, hidden;;1, title;;;;2-2-2, image")
),
"palettes" => Array (
"1" => Array("showitem" => "")
)
);

Как результат, в админке мы увидим, что можно добавлять новые записи:

а при редактировании упражнений интерфейс будет таким:
Все супер, но не супер. Есть одно неудобство. Чтобы к упражнению можно было привязать несколько тренажеров, для этого, в первую очередь, необходимо предварительно создать записи этих тренажеров, т.е. для этого нужно каждый раз выходить из формы ввода упражнений (tt_news). Поэтому, я пришел к выводу, что нужно научиться вводить дочерние записи прямо из родительской таблицы. Технология Inline Relational Record Editing (IRRE) позволяет разработчику  сделать это.

Дополнительное IRRE поле


К упражнениям можно привязать еще одну характеристику - группы мышц, которые оно разрабатывает. Как и в предыдущем случае, создаем дополнительно поле в tt_news - musclegroups, дочернюю таблицу - tx_fitness_musclegroup и связующую таблицу - tx_fitness_exercise2musclegroup.


CREATE TABLE tt_news (
...
  musclegroups int(11) NOT NULL default '0',
...
);


CREATE TABLE tx_fitness_musclegroup (
  uid int(11) NOT NULL auto_increment,
  pid int(11) NOT NULL default '0',
  tstamp int(11) NOT NULL default '0',
  crdate int(11) NOT NULL default '0',
  cruser_id int(11) NOT NULL default '0',
  sys_language_uid int(11) NOT NULL default '0',
  l18n_parent int(11) NOT NULL default '0',
  l18n_diffsource mediumblob NOT NULL,
  sorting int(10) NOT NULL default '0',
  deleted tinyint(4) NOT NULL default '0',
  hidden tinyint(4) NOT NULL default '0',
  t3ver_oid int(11) NOT NULL default '0',
  t3ver_id int(11) NOT NULL default '0',
  t3ver_wsid int(11) NOT NULL default '0',
  t3ver_label varchar(30) NOT NULL default '',
  t3ver_state tinyint(4) NOT NULL default '0',
  t3ver_stage tinyint(4) NOT NULL default '0',
  t3ver_count int(11) NOT NULL default '0',
  t3ver_tstamp int(11) NOT NULL default '0',
  t3ver_move_id int(11) NOT NULL default '0',
  t3_origuid int(11) NOT NULL default '0',
  title tinytext NOT NULL,
  exercises int(11) NOT NULL default '0',
  PRIMARY KEY  (uid),
  KEY parent (pid)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8

CREATE TABLE `tx_fitness_exercise2musclegroup` (
  `uid` int(11) NOT NULL auto_increment,
  `pid` int(11) NOT NULL default '0',
  `tstamp` int(11) NOT NULL default '0',
  `crdate` int(11) NOT NULL default '0',
  `cruser_id` int(11) NOT NULL default '0',
  `sys_language_uid` int(11) NOT NULL default '0',
  `l18n_parent` int(11) NOT NULL default '0',
  `l18n_diffsource` mediumblob NOT NULL,
  `deleted` tinyint(4) NOT NULL default '0',
  `hidden` tinyint(4) NOT NULL default '0',
  `t3ver_oid` int(11) NOT NULL default '0',
  `t3ver_id` int(11) NOT NULL default '0',
  `t3ver_wsid` int(11) NOT NULL default '0',
  `t3ver_label` varchar(30) NOT NULL default '',
  `t3ver_state` tinyint(4) NOT NULL default '0',
  `t3ver_stage` tinyint(4) NOT NULL default '0',
  `t3ver_count` int(11) NOT NULL default '0',
  `t3ver_tstamp` int(11) NOT NULL default '0',
  `t3ver_move_id` int(11) NOT NULL default '0',
  `t3_origuid` int(11) NOT NULL default '0',
  `exerciseid` int(11) NOT NULL default '0',
  `musclegroupid` int(11) NOT NULL default '0',
  `exercisesort` int(10) NOT NULL default '0',
  `musclegroupsort` int(10) NOT NULL default '0',

  PRIMARY KEY  (`uid`),
  KEY `parent` (`pid`)
) ENGINE=InnoDB AUTO_INCREMENT=31 DEFAULT CHARSET=utf8

Строки для ext_tables.php:


'musclegroups' => Array (
"exclude" => 1,
"label" => "LLL:EXT:ttnews_fitness/locallang_db.xml:tt_news.tx_ttnewsfield_secondarymusclegroups",
"config" => Array (
"type" => "inline",
"foreign_table" => "tx_fitness_exercise2musclegroup",
"foreign_field" => "exerciseid",
"foreign_sortby" => "exercisesort",
"foreign_label" => "musclegroupid",
/*"symmetric_field" => "exerciseid",
"symmetric_label" => "type",*/
"maxitems" => 10,
'appearance' => array(
'showSynchronizationLink' => 1,
'showAllLocalizationLink' => 1,
'showPossibleLocalizationRecords' => 1,
'showRemovedLocalizationRecords' => 1,
'useSortable' => 1,
'collapseAll' => 1,
'expandSingle' => 1,
),
'behaviour' => array(
'localizationMode' => 'select',
),
)
),


t3lib_extMgm::allowTableOnStandardPages("tx_fitness_musclegroup");
$TCA["tx_fitness_musclegroup"] = Array (
"ctrl" => Array (
'title' => 'LLL:EXT:ttnews_fitness/locallang_db.xml:tt_news.tx_ttnewsfield_musclegroup',
'label' => 'title',
'tstamp' => 'tstamp',
'crdate' => 'crdate',
'cruser_id' => 'cruser_id',
'languageField'            => 'sys_language_uid',
'transOrigPointerField'    => 'l18n_parent',
'transOrigDiffSourceField' => 'l18n_diffsource',
"sortby" => "sorting",
"delete" => "deleted",
"enablecolumns" => Array (
"disabled" => "hidden",
),
//"dynamicConfigFile" => t3lib_extMgm::extPath($_EXTKEY)."tca.mnasym.php",
"iconfile" => t3lib_extMgm::extRelPath($_EXTKEY)."res/hand.gif",
'versioningWS' => TRUE,
'origUid' => 't3_origuid',
),
"interface" => Array (
"showRecordFieldList" => "sys_language_uid,l18n_parent,l18n_diffsource,hidden,title,exercises"
),
//"feInterface" => Array (
// "fe_admin_fieldList" => "sys_language_uid, l18n_parent, l18n_diffsource, hidden, title, exercises",
//)
"feInterface" => $TCA["tx_fitness_musclegroup"]["feInterface"],
"columns" => Array (
'sys_language_uid' => array (
'exclude' => 1,
'label'  => 'LLL:EXT:lang/locallang_general.xml:LGL.language',
'config' => array (
'type'                => 'select',
'foreign_table'       => 'sys_language',
'foreign_table_where' => 'ORDER BY sys_language.title',
'items' => array(
array('LLL:EXT:lang/locallang_general.xml:LGL.allLanguages', -1),
array('LLL:EXT:lang/locallang_general.xml:LGL.default_value', 0)
)
)
),
'l18n_parent' => array (
'displayCond' => 'FIELD:sys_language_uid:>:0',
'exclude'     => 1,
'label'       => 'LLL:EXT:lang/locallang_general.xml:LGL.l18n_parent',
'config'      => array (
'type'  => 'select',
'items' => array (
array('', 0),
),
'foreign_table'       => 'tx_fitness_bodypart',
'foreign_table_where' => 'AND tx_fitness_musclegroup.pid=###CURRENT_PID### AND tx_fitness_musclegroup.sys_language_uid IN (-1,0)',
)
),
'l18n_diffsource' => array (
'config' => array (
'type' => 'passthrough'
)
),
"hidden" => Array (
"exclude" => 1,
"label" => "LLL:EXT:lang/locallang_general.xml:LGL.hidden",
"config" => Array (
"type" => "check",
"default" => "0"
)
),
"title" => Array (
"exclude" => 1,
'l10n_mode' => 'prefixLangTitle',
"label" => "LLL:EXT:ttnews_fitness/locallang_db.xml:tt_news.tx_ttnewsfield_musclegroup",
"config" => Array (
"type" => "input",
"size" => "30",
"eval" => "required",
)
),
"exercises" => Array (
"exclude" => 1,
"label" => "LLL:EXT:ttnews_fitness/locallang_db.xml:tt_news.tx_ttnewsfield_exercises",
"config" => Array (
"type" => "inline",
"foreign_table" => "tx_fitness_exercise2musclegroup",
"foreign_field" => "musclegroupid",
"foreign_sortby" => "musclegroupsort",
"foreign_label" => "exerciseid",
"maxitems" => 10,
'appearance' => array(
'showSynchronizationLink' => 1,
'showAllLocalizationLink' => 1,
'showPossibleLocalizationRecords' => 1,
'showRemovedLocalizationRecords' => 1,
),
'behaviour' => array(
'localizationMode' => 'select',
),
)
),
),
"types" => Array (
"0" => Array("showitem" => "sys_language_uid;;;;1-1-1, l18n_parent, l18n_diffsource, hidden;;1, title;;;;2-2-2, exercises")
),
"palettes" => Array (
"1" => Array("showitem" => "")
)
);


t3lib_extMgm::allowTableOnStandardPages("tx_fitness_exercise2musclegroup");
$TCA["tx_fitness_exercise2musclegroup"] = Array (
"ctrl" => Array (
'title' => 'LLL:EXT:ttnews_fitness/locallang_db.xml:tt_news.tx_ttnewsfield_exercise2musclegroup',
'label' => 'exerciseid',
'label_alt' => 'musclegroupid',
'label_alt_force' => TRUE,
'tstamp' => 'tstamp',
'crdate' => 'crdate',
'cruser_id' => 'cruser_id',
'languageField'            => 'sys_language_uid',
'transOrigPointerField'    => 'l18n_parent',
'transOrigDiffSourceField' => 'l18n_diffsource',
"delete" => "deleted",
"enablecolumns" => Array (
"disabled" => "hidden",
),
"iconfile" => t3lib_extMgm::extRelPath($_EXTKEY)."res/finger-bw.gif",
'versioningWS' => TRUE,
'origUid' => 't3_origuid',
'shadowColumnsForNewPlaceholders' => 'exerciseid, musclegroupid',
),
);
$TCA["tx_fitness_exercise2musclegroup"] = Array (
"ctrl" => $TCA["tx_fitness_exercise2musclegroup"]["ctrl"],
"interface" => Array (
"showRecordFieldList" => "sys_language_uid,l18n_parent,l18n_diffsource,hidden,exerciseid,musclegroupid,exercisesort,musclegroupsort,type"
),
"feInterface" => $TCA["tx_fitness_exercise2musclegroup"]["feInterface"],
"columns" => Array (
'sys_language_uid' => array (
'exclude' => 1,
'label'  => 'LLL:EXT:lang/locallang_general.xml:LGL.language',
'config' => array (
'type'                => 'select',
'foreign_table'       => 'sys_language',
'foreign_table_where' => 'ORDER BY sys_language.title',
'items' => array(
array('LLL:EXT:lang/locallang_general.xml:LGL.allLanguages', -1),
array('LLL:EXT:lang/locallang_general.xml:LGL.default_value', 0)
)
)
),
'l18n_parent' => array (
'displayCond' => 'FIELD:sys_language_uid:>:0',
'exclude'     => 1,
'label'       => 'LLL:EXT:lang/locallang_general.xml:LGL.l18n_parent',
'config'      => array (
'type'  => 'select',
'items' => array (
array('', 0),
),
'foreign_table'       => 'tx_fitness_exercise2musclegroup',
'foreign_table_where' => 'AND tx_fitness_exercise2musclegroup.pid=###CURRENT_PID### AND tx_fitness_exercise2musclegroup.sys_language_uid IN (-1,0)',
)
),
'l18n_diffsource' => array (
'config' => array (
'type' => 'passthrough'
)
),
"hidden" => Array (
"exclude" => 1,
"label" => "LLL:EXT:lang/locallang_general.xml:LGL.hidden",
"config" => Array (
"type" => "check",
"default" => "0"
)
),
"exerciseid" => Array (
"label" => "LLL:EXT:ttnews_fitness/locallang_db.xml:tt_news.tx_ttnewsfield_exercise",
"config" => Array (
"type" => "select",
"foreign_table" => "tt_news",
'foreign_table_where' => 'AND type=3',
"maxitems" => 1,
'localizeReferences' => 1,
)
),
"musclegroupid" => Array (
"label" => "LLL:EXT:ttnews_fitness/locallang_db.xml:tt_news.tx_ttnewsfield_musclegroup",
"config" => Array (
"type" => "select",
"foreign_table" => "tx_fitness_musclegroup",
"maxitems" => 1,
'localizeReferences' => 1,
)
),
"exercisesort" => Array (
"config" => Array (
"type" => "passthrough",
)
),
"musclegroupsort" => Array (
"config" => Array (
"type" => "passthrough",
)
),
/*"type" => Array (
"exclude" => 0,
"label" => "LLL:EXT:ttnews_fitness/locallang_db.xml:tt_news.tx_ttnewsfield_musclegroup_type",
'config' => array(
'type' => 'select',
'items' => array(
array('LLL:EXT:ttnews_fitness/locallang_db.xml:musclegroup_type.1', 'Primary'),
array('LLL:EXT:ttnews_fitness/locallang_db.xml:musclegroup_type.2', 'Secondary'),
),
),
),*/
),
"types" => Array (
"0" => Array("showitem" => "sys_language_uid;;;;1-1-1, l18n_parent, l18n_diffsource, hidden;;1, title;;;;2-2-2, exerciseid;;;;3-3-3, musclegroupid, exercisesort, musclegroupsort")
),
"palettes" => Array (
"1" => Array("showitem" => "")
)
);

Получаем следующий результат в BE:
Как видим, такая форма более удобна, т.к. позволяет создавать дочерние записи прямо внутри родительской. Больше информации о IRRE можно найти здесь.

Нужно сказать, что после добавления всех вышеуказанных изменений в файле ext_tables.php, форма ввода tt_news содержать новых полей не будет. Для этого нужно добавить еще 2 строки:


t3lib_div::loadTCA("tt_news");
t3lib_extMgm::addTCAcolumns("tt_news",$fitnessColumns,1);

Возможно у кого-то возникнет вопрос: "А нафига мне Новости с кучей всяких дополнительных полей, которые нужны в одном случае, а в другом уже не нужны?". Все можно настроить. Для того, чтобы стандартные новости не содержали лишних полей создается дополнительный индивидуально настроенный тип записи. Изначально новости имеют 3 типа записей: Новости, Статьи, Внешняя ссылка. Создать еще один тип - проще простого. В файл ext_tables.php своего расширения добавляем:



$GLOBALS['TCA']['tt_news']['columns']['type']['config']['items'][] = Array('LLL:EXT:ttnews_fitness/locallang_db.xml:tt_news.type.I.3', 3);
$GLOBALS['TCA']['tt_news']['ctrl']['typeicons']['3'] = t3lib_extMgm::extRelPath($_EXTKEY)."res/ball-ico.gif";


Что дали последние 2 строки? Первое, добавили новый тип записи к новостям с кодом 3. Текстовое название этого типа сидит в файле locallang_db.xml в строке:

<label index="tt_news.type.I.3">Exercise</label>

Второе, новому типу записей сопоставлена иконка, которая сидит в каталоге res нашего расширения с названием - ball-ico.gif (16 на 16 пикселей).


А для того, чтобы новые поля в "новых новостях" были размещены в нужном и удобном для пользователя порядке добавляются такие строки:


$GLOBALS['TCA']['tt_news']['types']['3']['showitem'] = 'hidden, type;;;;1-1-1,title;;;;2-2-2,tx_fitness_shared_office_suitability,tx_fitness_workarea,bodytext;;2;richtext:rte_transform[flag=rte_enabled|mode=ts];4-4-4,tx_fitness_how2;;2;richtext:rte_transform[flag=rte_enabled|mode=ts];4-4-4,
--div--;LLL:EXT:ttnews_fitness/locallang_db.xml:exercise_info.name,tx_fitness_easier;;2;richtext:rte_transform[flag=rte_enabled|mode=ts];4-4-4,tx_fitness_harder;;2;richtext:rte_transform[flag=rte_enabled|mode=ts];4-4-4,tx_fitness_hints;;2;richtext:rte_transform[flag=rte_enabled|mode=ts];4-4-4,
--div--;LLL:EXT:ttnews_fitness/locallang_db.xml:exercise_relations, category;;;;3-3-3,tx_fitness_purpose,tx_fitness_equipment,tx_fitness_equivalent_gym_equipment,mainmusclegroups,musclegroups,
--div--;LLL:EXT:tt_news/locallang_tca.xml:tt_news.tabs.media, tx_damnews_dam_images,tx_fitness_musclegroupimage,tx_fitness_vimeo;;;;1-1-1,
--div--;LLL:EXT:tt_news/locallang_tca.xml:tt_news.tabs.access, starttime,endtime,fe_group,editlock';



Полный текст файла ext_tables.php можно взять здесь.

P.S. Это не статья, а по объему уже "Война и Мир"...:)

О себе

Моя фотография
Вадим Гиркало
Фрилансер, веб-разработчик сайтов на базе бесплатной, мощнейшей и очень гибкой CMS системы - TYPO3.
Просмотреть профиль

Позвонить мне в Skype

TOP - 3