Jelen írás egy fordított kivonat, melyet zserno készített. Az eredeti itt található:
http://www.trellon.com/content/blog/cck-creating-new-field-types
A CCK a legfontosabb rövidítés, amit ismernünk kell ha a Drupal tartalomkezeléséről beszélünk. Az eredeti rövidítés a Content Construction Kit szavakból áll össze, ami egy olyan keretrendszer, melynek segítségével egy webhely felhasználói különféle információkat küldhetnek be.
A többi Drupal kiegészítőhöz hasonlóan a CCK igazi szépsége sem csupán az általa kínált funkcionalitásban rejlik, hanem sokkal inkább a többi modul számára kínált kibővíthetőségében. A CCK API lehetővé teszi más modulok számára, hogy saját mezőtípusokat definiáljanak, melyek aztán tökéletesen illeszkednek a Drupal platformba.
A CCK sikerét jól jellemzi, hogy nagy részét már a Drupal 7-es alapcsomag is tartalmazza
A legismertebb CCK-ra épülő modulok a Filefield, Imagefield, Emfield, Link és Email, de összesen közel 300 CCK-val cimkézett Drupal 6 modul található a http://drupal.org-on. Függetlenül a felhasználási területtől, ezek mindegyike a CCK API-ját használva képes saját mezőtípusait definiálni, melyek azután bármelyik tartalomtípusban felhasználhatók.
Egy egyszerű példaként Matthias Hutterer Email modulját fogjuk megvizsgálni. Ez a modul a CCK API-t használva egy saját mezőtípust deklarál, amivel megfelelően formázott e-mail címeket tárolhatunk saját tartalomtípusainkban. Meg fogjuk vizsgálni a kulcsfontosságú függvényeket, amik az egyedi mezőtípus definiálásához szükségesek, és ahol szükséges, rövid magyarázattal szolgálunk a konfigurációs lehetőségekről.
Kezdjük a hozzávalókkal (a legfőbb hook-ok és eljárások, amiket használhatunk):
- Telepítés:
- Mező beállítások (field settings):
- hook_field_info
- hook_field_settings
- hook_field
- Felületi elemtípus beállítások (widget settings):
- hook_widget_info
- hook_widget_settings
- hook_widget
- hook_elements
- Sminkelés (theming):
- hook_theme + theme_MY_ELEMENT
- custom formatters
A lista hosszú, vágjunk is bele.
Telepítés
Első lépésként tudatnunk kell a CCK-val, hogy modulunk mikor áll használatra készen:
function email_install() {
drupal_load('module', 'content');
content_notify('install', 'email');
}
A *.install file-ban közölhetjük vele, amikor modulunk telepítése, engedélyezése, kikapcsolása vagy eltávolítása zajlik. Ezt a megfelelő hook-ban (pl. hook_install, hook_enable, stb), a megfelelő paraméterrel (install, enable, stb.) meghívott content_notify CCK eljárással tehetjük meg.
Mező beállítások
Az email.module file-ban látható, ahogy a mező formát ölt.
function email_field_info() {
return array(
'email' => array(
'label' => 'Email',
//...
A fenti kóddal regisztráltuk a mezőnket, az "email" belső azonosítóval és egy "Email" címkével.
function email_field_settings($op, $field) {
switch ($op) {
case 'database columns':
$columns['email'] = array('type' => 'varchar', 'length' => 255, 'not null' => FALSE, 'sortable' => TRUE);
return $columns;
}
}
Itt az Email modul arra kéri a CCK-t, hogy kezelje ő a szükséges adatbázissal kapcsolatos teendőit. Egy külön oszlopot kér az őt használó tartalomtípusok tábláiban. Az oszlop elnevezése a majdan létrehozott mezők nevétől függően mindig "field_MEZŐNÉV_email" alakú lesz, beállításait pedig a $columns['email'] tömbben megadott jellemzők határozzák meg. Az $op változó a "database columns" értéken kívül még a "form" szöveget is tartalmazhatja, amivel egyedi űrlap készíthető a további szükséges beállításoknak (ld. a CCK Text modulját).
Végül nézzük hogyan tudjuk validálni a mezőnk tartalmát.
function email_field($op, &$node, $field, &$items, $teaser, $page) {
switch ($op) {
case 'validate':
if (is_array($items)) {
foreach ($items as $delta => $item) {
if ($item['email'] != '' && !valid_email_address(trim($item['email']))) {
form_set_error($field['field_name'],t('"%mail" is not a valid email address',array('%mail' => $item['email'])));
}
}
}
break;
//...
Ha a mezőnek van értéke, akkor a fenti kód a Drupal valid_email_address eljárásával ellenőrzi, hogy az valódi e-mail cím-e.
Felületi elemtípus beállítások
Miután felvázoltuk a mezőtípusunk logikai összetevőit, jöhet a felületi elemtípus (ún. widget) űrlapjának definiálása, hogy a végleges HTML űrlapelem megkaphassa a megfelelő attribútumokat. A hook_field* függvényekhez hasonlóan a hook_widget* függvényeknek is van _info és _settings változata.
function email_widget_info() {
return array(
'email_textfield' => array(
'label' => t('Text field'),
'field types' => array('email'),
'multiple values' => CONTENT_HANDLE_CORE,
'callbacks' => array(
'default value' => CONTENT_CALLBACK_DEFAULT,
),
),
);
}
//…
function email_widget_settings($op, $widget) {
switch ($op) {
case 'form':
$size = (isset($widget['size']) && is_numeric($widget['size'])) ? $widget['size'] : 60;
$form['size'] = array(
'#type' => 'textfield',
'#title' => t('Size of textfield'),
'#default_value' => $size,
'#element_validate' => array('_email_widget_settings_size_validate'),
'#required' => TRUE,
);
return $form;
case 'save':
return array('size');
}
}
Vegyük észre hogy a hook_widget_info a hook_field_info-val hasonló struktúrát használ (name és label kulcsok), azonban kiegészíti a felhasználható mezőtípusok listájával ('field types' => array('email')).
A hook_field_settings-hez hasonlóan, a hook_widget_settings-ben is lehetőség van finomítani a beállítások űrlapján (kettőjük végeredményét látjuk az "admin/content/node-type/[TARTALOMTÍPUS NEVE]/fields/[MEZŐNÉV]" útvonalon).
Az Email modul (akárcsak a Text modul) ezt arra használja, hogy a "size" mezőnek (mely a bevihető szöveg maximális hosszát határozza meg) biztosan legyen értéke.
Ahhoz, hogy az űrlapelemünk megjelenjen az űrlapon, a hook_widget-et kell használnunk:
function email_widget(&$form, &$form_state, $field, $items, $delta = 0) {
$element = array(
'#type' => $field['widget']['type'],
'#default_value' => isset($items[$delta]) ? $items[$delta] : '',
);
return $element;
}
Tehát amikor a CCK hozzáadja a mezőnket az űrlaphoz, tudatjuk vele, hogy állítsa be a megfelelő widget típust (ez esetünkben az "email_textfield") és az alapértelmezett értéket, ha az létezik. Ha a modulunk több widget típust is használna, akkor itt a widget típus szerinti feltételes elágazással tudnánk a megfelelő attribútumokat beállítani. A legtöbb esetben azonban a fenti függvény elegendő (bővebben: nodereference.module).
Miután minden szükséges információt tudattunk a CCK-val, még a Drupal Form API-jának is el kell magyarázni, hogy miként bánjon a mezőnkkel. Ezt a hook_elements függvénnyel tehetjük meg:
function email_elements() {
return array(
'email_textfield' => array(
'#input' => TRUE,
'#columns' => array('email'),
'#delta' => 0,
'#process' => array('email_textfield_process'),
),
);
}
Vegyük észre, hogy itt az "email" azonosító helyett az "email_textfield"-et használjuk, mert a Fom API az új widget-re kíváncsi, amit még a hook_widget_info-ban a mezőnkhöz kapcsoltunk. Továbbá azt is megmondjuk, hogy hol találja az új űrlapelem feldolgozásakor használandó kódot: '#process' => array('email_textfield_process').
Az eddig tárgyalt függvények mind az új mezőnk létrehozásával foglalkoztak: definiálták annak beállításait és létrehozták a szükséges widget-et. Egyikük sem foglalkozott azonban azzal, hogy a Drupal hogyan is fogja a widget-ünket szabályos HTML űrlapelemként megjeleníteni egy node szerkesztő form-on. Ennek leírása a (hook_elements-ben már említett) "#process" attribútumban megadott callback függvénnyel tehető meg:
function email_textfield_process($element, $edit, $form_state, $form) {
$field = $form['#field_info'][$element['#field_name']];
$field_key = $element['#columns'][0];
$delta = $element['#delta'];
$element[$field_key] = array(
'#type' => 'textfield',
'#title' => $element['#title'],
'#description' => content_filter_xss($field['widget']['description']),
'#required' => $element['#required'],
'#maxlength' => 255,
'#size' => !empty($field['widget']['size']) ? $field['widget']['size'] : 60,
'#attributes' => array('class' => 'text', 'dir' => 'ltr'),
'#default_value' => isset($element['#value'][$field_key]) ? $element['#value'][$field_key] : NULL,
);
return $element;
}
A Form API-t ismerőknek ez a kódrészlet már első ránézésre sokat elárul. A mezőnk egy szöveges beviteli mező (textfield) lesz, melyhez felhasználtuk a korábban definiált mező- és widget beállításokat ('widget' kulcs a fenti kódban), valamint a CCK-tól kapott információkat (ilyen pl. az $element['#title'], ami a "Mezők kezelése" oldalon egy új mezőcímke beküldésekor kerül beállításra).
Most hogy a CCK már tud az új mezőtípusunkról és a FAPI is tudja, hogy miként jelenítse meg azt a node szerkesztő űrlapon, nincs más hátra, mint az összegyűjtött adatok sminkelése.
Sminkelés
A hook_elements meghívásakor a Drupal feltételezi, hogy léteznek a deklarált elemekhez azok sminkfüggvényei is. Így pl. az Email modul esetében mivel az egyetlen deklarált elemünk az "email_textfield" volt, ezért létre kell hoznunk egy "theme_ email_textfield" nevű sminkfüggvényt. Habár a Drupal automatikusan összekapcsolja az űrlapelemet a hozzá tartozó sminkfüggvénnyel, szükség van a szokásos hook_theme függvény megírására is, hogy tudja: ez egy sminkelhető függvény.
function email_theme() {
return array(
'email_textfield' => array(
'arguments' => array('element' => NULL),
),
// More theme functions declared here…
);
}
function theme_email_textfield($element) {
return $element['#children'];
}
A theme_email_textfield eljárás nem csinál semmi különöset, mindössze a Drupal Form API-ja által generált HTML értéket adja vissza (ahogy az az 'includes/form.inc'-ben látható). Érdemes tudni, hogy lehetne ennél komolyabb sminkfüggvényt is írni az element['field_name'] és $element['delta'] értékek felhasználásával (ezek az űrlapelem nevét és pozícióját tárolják).
Utolsó simításként készíthetünk a felhasználók által kezelhető ún. egyedi mező formázókat is, melyek az adott tartalomtípus "Megjelenítési beállítások" oldalán érhetők el (admin/content/node-type/[TARTALOMTÍPUS NEVE]/display).
Példa: az Email modul a hook_field_formatter_info segítségével definiálja saját mező formázóit, majd a hook_theme-ben deklarálja az azokat előállító callback függvényeket, végül megvalósítja az így deklarált theme_EGYEDI_FORMÁZÓ függvényeit, melyekben összeállítja a végső HTML kimeneteket.
---
A cikk hossza ellenére még csak a felszínét súroltuk a CCK lehetőségeinek. Az említett függvényekről bővebben a CCK csomagban található kiegészítő modulokban olvashatunk (pl. text, nodereference), melyek gazdag dokumentációt tartalmaznak.