Tovább mennék az első rész folyamányaként. Admin generátorról lesz itt is szó, néhány általános probléma megoldását tenném közzé:

  • a listában szereplő mezők változtatása
  • kapcsolt táblák szerinti rendezés


Eljött az idő hogy egy pici, de konkrét adatbázist kreáljunk.
Futtasuk le akár a már telepített phpmyadminban
[code language=”sql”]
CREATE DATABASE sandbox;
USE sandbox;
CREATE TABLE `categories` (
`id` int(11) NOT NULL auto_increment,
`name` varchar(255) default NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `products` (
`id` int(11) NOT NULL auto_increment,
`name` varchar(255) NOT NULL,
`price` float(9,3) default ‘0.000’,
`category_id` int(11) default NULL,
PRIMARY KEY (`id`),
KEY `category_id` (`category_id`),
CONSTRAINT `products_fk` FOREIGN KEY (`category_id`) REFERENCES `categories` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
[/code]

Az első leírásban létrehozott sandbox projectünket fogjuk átszerkeszteni.
Tehát állítsuk be a config könyvtárban lévő adatbázisokhoz tartozó fájlokat (propel.ini és databases.yml) az előbb létrehozott sandbox adatbázisra.
Majd futtassuk le az alábbi parancsokat is:
[code language=”bash”]
# generáljuk le a schema.yml fájlt
./symfony propel:build-schema
#hozzuk létre a formokat, filtereket, modeleket, -C direktiva kihagyja az sql-t (classes only)
./symfony propel:build-all -C
# és a két táblánkhoz tartozó admin felületet készítsük el:
./symfony propel:generate-admin –module=CategoriesAdmin frontend categories
# az apps/frontend/modules/CategoriesAdmin modulunkat
# és a route (apps/frontend/config/routing.yml) szabályt is létre fogja hozni
./symfony propel:generate-admin –module=ProductsAdmin frontend products
[/code]

Máris érdemes létrehozni a PROJECT_DIR/apps/frontend/templates/layout.php fájlban a 2 menüpontunkat. Közvetlenül a body nyitótagja után tegyük be az alábbi sorokat.
[code language=”html”]
<ul id="menu">
<li><a href="<?php echo url_for(‘@categories’)?>"></a>Kategóriák</a></li>
<li><a href="<?php echo url_for(‘@products’)?>">Termékek</a></li>
</ul>
[/code]

A http://mydomain/sandbox/frontend_dev.php/CategoriesAdmin érjük el az alkalmazásunkat. Most próbáljuk meg feltölteni adatokkal. Először vigyünk fel kategóriákat. Majd próbáljunk meg, felvinni termékeket is. Elvileg el kell akadnunk amiatt, hogy a categories modelunknek még nincs __toString() metódusa. Ez egy PHP metódus, ami egy objektum kiíratására szolgál. Jelen esetünkben, mi, a name mezővel jelenítenénk meg a tábla egyes rekordjait. Így hát hozzuk létre ezt a metódust a PROJECT_DIR/lib/model/categories.php fájlban.
[code language=”php”]
class Categories extends BaseCategories {
public function __toString()
{
return $this->getName();
}
} // Categories
[/code]

Ezután már sikeresen megjeleníthetjük a listát, és rögzíthetünk új rekordokat. De mint láthatjuk a termékek listában nem a kategóriák neve, hanem annak azonosítója (id) szerepel, ráadásul a felhasználóknak a termékek id-ja is megjelent. Sajnos a generátorunk nem tökéletes, így a létrehozott fájlokat jó pár helyen módosítanunk kell.
Elsőként magát a PROJECT_DIR/apps/frontend/modules/ProductsAdmin/config/generator.yml fájlt módosítjuk. Figyelve a .yml fájlokra jellemző szabályokra (legfőképp, hogy behúzás nem tabulátor, hanem 2 üres hely) a listát tartalmazó sort egészítsük ki:
[code]
list:
display: [categories, name, price ] # felsoroljuk a megjelenített mezőket, kapcsolt tábla esetén a classt
peer_method: doSelectJoinAll # modelpeer osztályunk metódusa
[/code]
Másodikként tekintsük meg a létrehozott PROJECT_DIR/apps/frontend/modules/ProductsAdmin/actions/action.class.php fájlt. Mint láthatjuk a ProductsAdminActions osztályunk az autoProductsAdminActions osztályból származik. Ez pedig a cache könyvtárban keresendő, a PROJECT_DIR/cache/frontend/dev/modules/ProductsAdmin/actions/action.class.php fájlban. Ennek az osztálynak kell 2 függvényét felül definiálnuk:
[code language=”php”]
class ProductsAdminActions extends autoProductsAdminActions
{
protected function addSortCriteria($criteria)
{
if (array(null, null) == ($sort = $this->getSort()))
{
return;
}

if ($sort[0] == ‘categories.name’)
{
$column = CategoriesPeer::NAME;
}
else
{
$column = ProductsPeer::translateFieldName($sort[0], BasePeer::TYPE_FIELDNAME, BasePeer::TYPE_COLNAME);
}

if (‘asc’ == $sort[1])
{
$criteria->addAscendingOrderByColumn($column);
}
else
{
$criteria->addDescendingOrderByColumn($column);
}
}

protected function isValidSortColumn($column)
{
if (in_array($column, array(‘categories.name’)))
{
return true;
}
else
{
return parent::isValidSortColumn($column)
}
}
}
[/code]

Majd hozzuk létre a PROJECT_DIR/apps/frontend/modules/ProductsAdmin/_list_th_tabular.php fájlt. Ezt is a cacheből másoltam ki és módosítottam.

[code language=”php”]
<?php slot(‘sf_admin.current_header’) ?>
<th class="sf_admin_text sf_admin_list_th_categories">
<?php if (‘categories.name’ == $sort[0]): ?>
<?php echo link_to(__(‘Categories’, array(), ‘messages’), ‘@products’, array(‘query_string’ => ‘sort=categories.name&sort_type=’.($sort[1] == ‘asc’ ? ‘desc’ : ‘asc’))) ?>
<?php echo image_tag(sfConfig::get(‘sf_admin_module_web_dir’).’/images/’.$sort[1].’.png’, array(‘alt’ => __($sort[1], array(), ‘sf_admin’), ‘title’ => __($sort[1], array(), ‘sf_admin’))) ?>
<?php else: ?>
<?php echo link_to(__(‘Categories’, array(), ‘messages’), ‘@products’, array(‘query_string’ => ‘sort=categories.name&sort_type=asc’)) ?>
<?php endif; ?>
</th>
<?php end_slot(); ?>
<?php include_slot(‘sf_admin.current_header’) ?>

<?php slot(‘sf_admin.current_header’) ?>
<th class="sf_admin_text sf_admin_list_th_name">
<?php if (‘name’ == $sort[0]): ?>
<?php echo link_to(__(‘Name’, array(), ‘messages’), ‘@products’, array(‘query_string’ => ‘sort=name&sort_type=’.($sort[1] == ‘asc’ ? ‘desc’ : ‘asc’))) ?>
<?php echo image_tag(sfConfig::get(‘sf_admin_module_web_dir’).’/images/’.$sort[1].’.png’, array(‘alt’ => __($sort[1], array(), ‘sf_admin’), ‘title’ => __($sort[1], array(), ‘sf_admin’))) ?>
<?php else: ?>
<?php echo link_to(__(‘Name’, array(), ‘messages’), ‘@products’, array(‘query_string’ => ‘sort=name&sort_type=asc’)) ?>
<?php endif; ?>
</th>
<?php end_slot(); ?>
<?php include_slot(‘sf_admin.current_header’) ?><?php slot(‘sf_admin.current_header’) ?>
<th class="sf_admin_text sf_admin_list_th_price">
<?php if (‘price’ == $sort[0]): ?>
<?php echo link_to(__(‘Price’, array(), ‘messages’), ‘@products’, array(‘query_string’ => ‘sort=price&sort_type=’.($sort[1] == ‘asc’ ? ‘desc’ : ‘asc’))) ?>
<?php echo image_tag(sfConfig::get(‘sf_admin_module_web_dir’).’/images/’.$sort[1].’.png’, array(‘alt’ => __($sort[1], array(), ‘sf_admin’), ‘title’ => __($sort[1], array(), ‘sf_admin’))) ?>
<?php else: ?>
<?php echo link_to(__(‘Price’, array(), ‘messages’), ‘@products’, array(‘query_string’ => ‘sort=price&sort_type=asc’)) ?>
<?php endif; ?>
</th>
<?php end_slot(); ?>
<?php include_slot(‘sf_admin.current_header’) ?>
[/code]

Ezzel a fájllal azonban már sikerült teljesen elontanunk a generátort. Hiszen ha új mezőket teszünk be, vagy veszünk ki, akkor ezt a fájlt újra és újra szerkesztenünk kell. Ez ellen a legjobb módszer talán az lenne, ha írnánk egy saját generátor, ami figyelembe veszi ezt. Talán később még módosítom ezt a leírást ezen ötletemmel.

Léteznek már nagyobb tudású generátorok:
ahAdminGeneratorThemesPlugin
sfAdminThemejRollerPlugin
Mindkettő Doctrinera alá készült el, de bizonyára nem túl nehéz átírni Propelesre. 🙂