![]() |
|
Snippets |
|
If you want add a column to sfGuardUserProfile's list view for show a link to sfGuardUser's edit view:
Create a partial : site.com/apps/backend/modules/sf_Guard_User_Profile/templates/_user.php
And put this:
<?php echo link_to($sf_guard_user_profile->getSfGuardUser()->getUsername(), 'sfGuardUser/edit?id='.$sf_guard_user_profile->getSfGuardUser()->getId()) ?>
PD(It's not very much, but it is my first snippet)
My First snippet ever AND, my first contribution to the programming world... hope you like it ;)
This snippet is for those of you who, just like me, have 30 fields in one class and doesnt want to write them all down in the admin generator and erase the ones you don't want.
if you want to display all field except one, here's how:
generator: class: sfPropelAdminGenerator param: model_class: users theme: default list: sort: [updated_at, desc] hide: [the_fields_i_dont_want]
Notice the "HIDE" option.
If you want to display all fields AND you want to add a partial, it gets a little tricky (and ugly, but it does the trick until something better is created)
generator: class: sfPropelAdminGenerator param: model_class: users theme: default list: sort: [updated_at, desc] display: [_my_partial, <?php echo implode(', ',JobPeer::getFieldNames(BasePeer::TYPE_FIELDNAME)) ?>] max_per_page: 20
Notice the "DISPLAY" option ... I know, it's ugly to have php in a yml file ...
You can also combien the two and get all columns and hide the ones you don't want .
P.S. I should have wrote this earlier but this snippet wouldn't exists if it weren't for pookey from #symfony (irc). THanks again man ;)
The list view of the admin generator currently always displays all defined object actions for each object. There is no way to display an object action for an object only if some condition on this object is met.
In order to extend the admin generator with this functionality only a small enhancement is required. You can either apply this change per module or create a new admin generator theme as described in the Symfony book.
The templates/_list_td_actions.php has to be extended to look roughly like this, depending on whether you already have your own modifications in there:
<?php if ($this->getParameterValue('list.object_actions')): ?> <td> <ul class="sf_admin_td_actions"> <?php foreach ($this->getParameterValue('list.object_actions') as $actionName => $params): ?> <?php if ( isset( $params['condition'] ) ): ?> [?php if ( <?php echo ( isset( $params['condition']['invert'] ) && $params['condition']['invert'] ? '!' : '') . '$' . $this->getSingularName( ) . '->' . $params['condition']['function'] ?>( <?php echo ( isset( $params['condition']['params'] ) ? $params['condition']['params'] : '' ) ?> ) ): ?] <?php endif; ?> <?php echo $this->addCredentialCondition($this->getLinkToAction($actionName, $params, true), $params) ?> <?php if ( isset( $params['condition'] ) ): ?> [?php endif; ?] <?php endif; ?> <?php endforeach; ?> </ul> </td> <?php endif; ?>
With this enhancement you can now use conditions for your actions in the generator.yml. The syntax should be pretty self-explanatory. An example would look like this:
object_actions:
subscribe: { name: Notify when changed, action: subscribe, icon: pencil_add.png }
condition:
function: isUserSubscribed
params: "$sf_user, 'test'"
invert: true
As you can see each object action now also takes a condition parameter, which again takes a number of parameter.
function is the function of the object that will be called. It will be evaluated as boolean. Required!params is a string that will be passed verbatim to the function, so if you need several parameters make sure to enclose them in quotes. Since the function will be called from the view layer you have access to all data available there such as $sf_user. Defaults to an empty stringinvert will invert the return value of the function so saving you an additional function if you need something like subscribe / unsubscribe actions. Defaults to false.Enjoy!
This JavaScript code registers a change detection mechanism in every form field and notifies the user about unsaved changes. No changes need to be applied to existing modules/actions. Additionaly, the TinyMCE helper can be changed in order to detect changes there as well.
Only requirement: the links for leaving the page need to be in a container with id "header". This can of course be changed.
Add this to the head of the page (or to an external js-file):
var changesDetected = false; /** * Registers a change detection mechanism that notifies users about unsaved changes whenever they click on a link. */ function registerChangeDetection() { /** * Notifies user about unsaved changes */ function notifyAboutChanges(e) { if(changesDetected){ //My choice: modal dialog using modalbox (http://www.wildbit.com/labs/modalbox/) //Modalbox.show('<div class=\'warning\'><p>Before continuing, you need to save you changes.</p> <input type=\'button\' value=\'Ignore changes\' onclick=\'changesDetected=false;Modalbox.hide()\' style=\'color: #999\' /> <input type=\'button\' value=\'OK\' onclick=\'Modalbox.hide()\' /></div>', {title: 'Warning', width: 300}); //Alternative: alert('Before continuing, you need to save your changes.'); return false; } } /* Add change detection to every form field */ if(document.forms.sf_admin_edit_form != null) { var elements = Form.getElements(document.forms.sf_admin_edit_form); elements.each(function(item) { item.onchange = function(e) { changesDetected = true; } }); } /* Add an onclick handler to every link in the container with id "header" */ var links = $$('#header a'); links.each(function(item) { if(!(item.onclick instanceof Function)) { //Avoid overwriting existing onclick handlers item.onclick = notifyAboutChanges; } }); }
Register the change detection in the body tag:
<body onload="registerChangeDetection()">
I also modified the sfRichTextEditorTinyMCE helper in order to use TinyMCE 3 (currently beta). Here is the code relevant to change detection to be put into TinyMCE.init({...}) (Go to http://wiki.moxiecode.com/index.php/TinyMCE:API/tinymce.Editor/onChange for more information):
setup: function(ed) { var i = 0; ed.onChange.add(function(ed, l) { if(i == 0) i++ //Ignore the first change else changesDetected = true; }); }
By default, we can't display primary keys in the admin generator edit view.
But I wanted to do just that.
Here is an example for the module/table "article", and the primary key column "id" :
Create a partial "_input_id.php" in the "templates" directory of your module :
<?php echo input_tag('inputId', $article->getId(), array('disabled' => true, 'size'=>10)); ?>
In "config/generator.yml", declare your partial field in the "fields" section to set back the original name of the field, and in the "edit/display" parameter :
generator: class: sfPropelAdminGenerator param: model_class: Article theme: default fields: input_id: {name: id} list: title: Article List edit: display: [_inputId, name]
Beware of the tricky spelling of the partial name in the generator.yml file if, like me, you like underscores...
Sometimes in the generator you have a large listing of elements in a admin_double_list.
Well I wanted to write a quick little autocomplete text box that would search for results and when you selected one, it would be added into the associated select box.
In your generator add a new partial: edit: display: [ _quick_search ]
Create a file in your templates directory called _quick_search.php
Copy this code in there:
===CODE===
<?php $response = sfContext::getInstance()->getResponse(); $response->addJavascript(sfConfig::get('sf_prototype_web_dir').'/js/prototype'); $response->addJavascript(sfConfig::get('sf_prototype_web_dir').'/js/effects'); $response->addJavascript(sfConfig::get('sf_prototype_web_dir').'/js/controls'); $response->addStylesheet(sfConfig::get('sf_prototype_web_dir').'/css/input_auto_complete_tag'); ?> <input type="text" id="quick_search" name="quick_search"/>
<div class="auto_complete" id="quick_search_auto_complete" style="position: absolute; left: 445px; top: 421px; width: 113px; opacity: 0.17329; display: none;">
</div>
<script type="text/javascript">
//<![CDATA[
function addSelection (li)
{
$('associated_titles').options[ $('associated_titles').options.length] = new Option (li.childNodes[0].nodeValue, li.id);
}
new Ajax.Autocompleter('quick_search', 'quick_search_auto_complete', '/backend_dev.php/search', { updateElement: addSelection });
//]]>
</script>
===CODE===
Make sure you change your url from /backend_dev.php/search to whatever your action that will search your database and your good to go!
Just FYI: You can use the Symfony helper autocomplete_tag () because it does not allow for passing the updateElement parameter.
This is a simple way I came up for keeping original filenames for the files I upload using the admin generator.
We need an extra field in our database schema to store the original filename, lets say our file field it's called "lecture" then our original lecture's filename field would be "original_lecture", our object will be called "Course".
Remember to rebuild your object model before the next step.
Once we have the 2 fields there we need to ignore the second field inside generator.yml, the way to do this is to alter the display parameter and only list the fields you want to edit.
Then we overwrite our actions and add the following code:
class courseActions extends autocourseActions { protected function updateCourseFromRequest() { $this->course->setOriginalLecture($this->getRequest()->getFileName('course[lecture]')); parent::updateCourseFromRequest(); } }
This will automatically setup the original filename on the right field.
Now, we move to the frontend, we need an action to download our file so we can alter the request and add our filename on the fly, you can add the following code on any frontend action but for clarity sake I've created a module called "download" that I'll use to download any of my files.
So, inside our download module we add the following action:
class downloadActions extends sfActions { /** * Executes lecture action * */ public function executeLecture() { $id = $this->getRequestParameter('id'); $this->course = CoursePeer::retrieveByPk($id); $this->getResponse()->addHttpMeta('Content-Disposition', 'attachment; filename="'.$this->course->getOriginalLecture().'"'); } }
As you can see, we added a Content-Disposition header to our request, this header will force to download a file and name it according to our original_lecture field.
Finally, on our view, we need to do 2 things.
1) Disable the layout, this is done under view.yml just add:
lectureSuccess: has_layout: off
2) Inside lectureSuccess.php we add:
readfile(sfConfig::get('sf_upload_dir').'/lectures/'.$course->getLecture());
This will output the file name stored in the filesystem, remember to provide the right path, this is just an example :)
Finally, to download the file you just need to follow this link:
http://www.yourhost.com/download/lecture?id=FILEID
That's all, your browser will prompt you with a save file dialog.
This is a simple way I came up for keeping original filenames for the files I upload using the admin generator.
We need an extra field in our database schema to store the original filename, lets say our file field it's called "lecture" then our original lecture's filename field would be "original_lecture", our object will be called "Course".
Remember to rebuild your object model before the next step.
Once we have the 2 fields there we need to ignore the second field inside generator.yml, the way to do this is to alter the display parameter and only list the fields you want to edit.
Then we overwrite our actions and add the following code:
class courseActions extends autocourseActions { protected function updateCourseFromRequest() { $this->course->setOriginalLecture($this->getRequest()->getFileName('course[lecture]')); parent::updateCourseFromRequest(); } }
This will automatically setup the original filename on the right field.
Now, we move to the frontend, we need an action to download our file so we can alter the request and add our filename on the fly, you can add the following code on any frontend action but for clarity sake I've created a module called "download" that I'll use to download any of my files.
So, inside our download module we add the following action:
class downloadActions extends sfActions { /** * Executes lecture action * */ public function executeLecture() { $id = $this->getRequestParameter('id'); $this->course = CoursePeer::retrieveByPk($id); $this->getResponse()->addHttpMeta('Content-Disposition', 'attachment; filename="'.$this->course->getOriginalLecture().'"'); } }
As you can see, we added a Content-Disposition header to our request, this header will force to download a file and name it according to our original_lecture field.
Finally, on our view, we need to do 2 things.
1) Disable the layout, this is done under view.yml just add:
lectureSuccess: has_layout: off
2) Inside lectureSuccess.php we add:
<?php readfile(sfConfig::get('sf_upload_dir').'/lectures/'.$course->getLecture()); ?>
This will output the file name stored in the filesystem, remember to provide the right path, this is just an example :)
Finally, to download the file you just need to follow this link:
http://www.yourhost.com/download/lecture?id=FILEID
That's all, your browser will prompt you with a save file dialog.
Sometimes you may want to give the user the possibility to select a certain range of numbers in a numeric field in the admin generator. An example would be a rating between 1 and 5. This is where this snippet comes in handy.
Add the helper code below to one of your helper groups, that preferably is included in your standard_helpers.
Then you can use it like in your generator.yml like follows:
generator:
...
param:
...
edit:
display: [..., percentage, ...]
fields:
...
percentage: { type: select_range_tag, params: min=0 max=100 step=5 }
Supplying a step is optional, it defaults to 1.
Helper code:
function select_range_tag($name, $selected, $options) { $options = _parse_attributes($options); $select_options = range(_get_option($options, 'min', 1), _get_option($options, 'max', 5), _get_option($options, 'step', 1)); return select_tag($name, options_for_select(array_combine($select_options, $select_options), $selected)); } function object_select_range_tag($object, $method, $options = array(), $default_value = null) { $options = _parse_attributes($options); $value = _get_object_value($object, $method, $default_value); return select_range_tag(_convert_method_to_name($method, $options), $value, $options); }
Here is a method i developed to include some custom partials at the end of the edit action of a module which adapts admin generator.
i just added this at the end of editSuccess.php file of my generator theme ($sf_data_dir/generator/sfPropelAdmin/<myCustomTheme>/templates/editSuccess.php)
[?php // include xtra partials ?] <?php if ($this->getParameterValue('edit.partials')): ?> <?php $partials = $this->getParameterValue('edit.partials'); foreach( $partials as $partial => $vars ) : ?> [?php include_partial('<?php echo $this->getModuleName() ?>/<?php echo $partial ?>', array('<?php echo $this->getSingularName() ?>' => $<?php echo $this->getSingularName() ?> <?php foreach ($vars as $var): ?> , '<?php echo $var ?>' => $<?php echo $var; endforeach; ?>)); ?] <?php endforeach; ?>
then you just have to add the partials in the generator.yml like this :
edit:
partials:
partial1: [ var1a, var1b ]
partial2: [ var2a, var2b ]
where var.. are the variables you want to include in each partial.
this can be easily made for list success also.
This is a very usefull and simple tip if you want to defined default value in edit form (only on creation of a new record) with the value that the user defined in the list filter.
An exemple for a product module which define the category select field with the value of the same field in the list filter.
action.class.php
public function executeEdit () { $filters = $this->getUser()->getAttributeHolder()->getAll('sf_admin/product/filters'); if (!$this->getRequestParameter('product_id', 0) && isset($filters['category_id'])) { $this->product = new Product(); $this->produit->setCatergoryId($filters['category_id']); } parent::executeEdit(); } protected function getProductOrCreate ($product_id = 'product_id') { if (isset($this->product)) return $this->product; else return parent::getProductOrCreate($product_id);
Here we go !
The sort in admin generator is for a single field only, but in some complex list, it can be usefull to sort by multiple criterias. This is the main goal of this snippet. Those functions therefore override the ones of your auto-generated class. (1) And to display what are the ongoing sort criterias, you have to modify your '_list_th_tabular.php' file.
// /** * Add a sort criteria */ protected function processSort () { $sort = $this->getRequestParameter('sort'); $type = $this->getRequestParameter('type'); // Register sort if ($sort) { $this->getUser()->setAttribute($sort, $type, 'sf_admin/produits/sort'); } } /** * Add the sort criterias to the query */ protected function addSortCriteria(&$c) { $multisort = $this->getUser()->getAttributeHolder()->getAll('sf_admin/produits/sort'); if ($multisort) { foreach($multisort as $sort_column => $sort_type) { $sort_column = Propel::getDB($c->getDbName())->quoteIdentifier($sort_column); if ($sort_type == 'asc') { $c->addAscendingOrderByColumn($sort_column); } elseif ($sort_type == 'desc') { $c->addDescendingOrderByColumn($sort_column); } } } else { // Default sort $sort_column = Propel::getDB($c->getDbName())->quoteIdentifier('libelle'); $c->addAscendingOrderByColumn($sort_column); } } /** * Specific function for multi-sort */ protected function processFilters () { if ($this->getRequest()->hasParameter('filter')) { $filters = $this->getRequestParameter('filters'); // Multi-sort initialisation if (!is_array($filters)) { $this->getUser()->getAttributeHolder()->removeNamespace('sf_admin/produits/sort'); } $this->getUser()->getAttributeHolder()->removeNamespace('sf_admin/produits/filters'); $this->getUser()->getAttributeHolder()->add($filters, 'sf_admin/produits/filters'); } }
(for each sortable field)
<?php $multisort = $sf_user->getAttributeHolder()->getAll('sf_admin/produits/sort'); ?> <th id="sf_admin_list_th_libelle"> <?php if (isset($multisort['libelle'])) { echo link_to('Libellé', 'Produits/list?sort=libelle&type='. ($multisort['libelle'] == 'asc' ? 'desc' : 'asc')); echo ' ('. $multisort['libelle'] . ')'; } else { echo link_to('Libellé', 'Produits/list?sort=libelle&type=asc'); } ?> </th>
'Produits' is the module name, 'libelle' is the field to sort.
The 'reset button' of filters also initialize the multi-sort. The sort is made from the first field clicked to the last. That means, if you want a different primary sort you will have to use the reset filter button before.
PS: Obviously, this modification can be easly integrated in your backoffice theme, note that the default sort criteria set in the 'generator.yml' is used in the addSortCriteria function (from line // default sort)
COil :)
With admin generator you can have a field specified to be a uploading file. Then as it is written in the doc, you can wirte in your generator.yml :
picture:
name: Picture
type: admin_input_file_tag
upload_dir: picture
params: include_link=picture include_remove=true
Then the file will be uploaded in /upload/picture directory
But maybe you want to restrict the size of the picture or add different files for different picture sizes.
Then this is an easy way to generate thumbnails in subdirectories of the main upload directory specified.
Just add the following method to your action class and adapt :
action.class.php:
protected function updateProductFromRequest() { $product = $this->getRequestParameter('product'); $thumbnails[]=array('dir' => '16x16', 'width' => 16, 'height' => 16); $thumbnails[]=array('dir' => '32x32', 'width' => 32, 'height' => 32); if (!$this->getRequest()->hasErrors() && isset($produit['picture_remove'])) { foreach ($thumbnails as $thumbParam) { $currentFile = sfConfig::get('sf_upload_dir').'/picture/'.$thumbParam['dir'].'/'.$this->produit->getPhoto(); if (is_file($currentFile)) unlink($currentFile); } } parent::updateProductFromRequest(); if (!$this->getRequest()->hasErrors() && $this->getRequest()->getFileSize('product[picture]')) { $fileName=$this->product->getPicture(); foreach ($thumbnails as $thumbParam) { $thumbnail = new sfThumbnail($thumbParam['width'], $thumbParam['height'],true,false); $thumbnail->loadFile(sfConfig::get('sf_upload_dir')."/product/".$fileName); $thumbnail->save(sfConfig::get('sf_upload_dir').'/product/'.$thumbParam['dir'].'/'.$fileName, 'image/jpeg'); } } }
As for uploaded files, fenerated thumbnails are not deleted when record is deleted.
... without having trouble with your PEAR directory.
If you use the admin generator but don't like the generated html code, you either can use a custom css file to redo the style, or you have to copy the original theme from
/path/to/$PEAR/symfony/generator/sfPropelAdmin/default
and redo the html here. The problem with that technique is, that you have to manage this PEAR directory from now on, instead having the new theme located in your project folder. That's bad, because your theme will be lost if you clear your PEAR installation or decide to uninstall the symfony version and re-install another one.
After doing some research in the forums and docs, I tried to create the theme in my project directory, with the expected folder structure. I created a folder structure in my projects data dir, like this:
/path/to/$PEAR/data/generator/sfPropelAdmin/$THEME_NAME
I just copied all directories and files from the default sfPropelAdmin theme to this folder, but this didn't worked out. symfony wasn't able to find this theme. So, I created a symbolic link to this folder:
ln -s \ /path/to/$PROJECT_NAME/data/generator/sfPropelAdmin/$THEME_NAME \ /path/to/$PEAR/data/symfony/generator/sfPropelAdmin/$THEME_NAME
Now, you I modify the template to fit my needs, e.g. reset the css classes, add a new table structure and so on. After upgrading/uninstalling/installing a new copy of symfony, don't forget to check if the symbolic link still exists. If not, just re-create it, and everything should work.
If your webserver and php understoods the following of symbolic links (Windows doesn't), you can use this new theme for your sfPropelAdmin generated modules via the theme configuration handle in your generator.yml:
generator:
class: sfPropelAdminGenerator
param:
model_class: ModelClass
theme: $THEME_NAME
Problem:
Mysql produce TINYINT fields because BOOLEAN is just a synonym for TINYINT. And if you have TINYINT fields with value 0 or 1 (like BOOLEAN fields) in your database and use command symfony propel-build-schema to generate schema, you will have one problem with admin generator, because it will produse TINYINT fields as text form fields with value - 0 or 1, not as checkboxes. Admin generator needs BOOLEAN fields in schema to produse checkboxes.
Solution:
Solution to automate transformation field type tinyint to boolean where field name prefix is "is_".
sfPakeTransformTinyint.php
<?php pake_desc( 'apply tinyint-boolean transformation to your data model' ); pake_task( 'transform-schema-tinyint', 'project_exists' ); function run_transform_schema_tinyint( $task, $args ) { // Check params // -- missing params ? if ( !count($args) ) { throw new Exception( 'You must provide a transformation to apply.' ); } // -- schema exists ? $schema_filename = sprintf( '%s/schema.xml', sfConfig::get('sf_config_dir') ); if ( !file_exists($schema_filename) ) { throw new Exception( "Missing schema.xml" ); } // Backup schema pake_copy( $schema_filename, $schema_filename . '.previous', array('override' => true) ); //do hard work - tinyint->boolean if ($args[0] == 'do') { $handle = fopen($schema_filename, "r"); $contents = ''; while (!feof($handle)) { $contents .= fread($handle, 8192); } fclose($handle); $contents = preg_replace('/(name="is_.*?type=")TINYINT"/i','$1BOOLEAN"',$contents); $handle = fopen($schema_filename, "w+"); fwrite($handle, $contents); fclose($handle); } //undo hard work - boolean->tinyint if ($args[0] == 'undo') { $handle = fopen($schema_filename, "r"); $contents = ''; while (!feof($handle)) { $contents .= fread($handle, 8192); } fclose($handle); $contents = preg_replace('/(name="is_.*?type=")BOOLEAN"/i','$1TINYINT"',$contents); $handle = fopen($schema_filename, "w+"); fwrite($handle, $contents); fclose($handle); } } ?>
copy this code and drop it as new file in SF_DATA_DIR/tasks/ use command: symfony transform-schema-tinyint do to change tinyint to boolean, where field name with "is_" prefix, than rebuild your model with propel-build-model, clear cache, and use admin generator with checkboxes.
If something going wrong, do this command to undo changes in your model:
symfony transform-schema-tinyint undo (to change boolean to tinyint, where field name with "is_" prefix)
or you may use schema.xml.previous <- this is your schema before transformation
By default, the admin generator allows to filter the data with the rows from the table currently listed.
Here's how to extend this to data from other linked tables.
We'll consider the following example : a table "command" linked to a table "user". This very simple schema.xml shows the relation between these two tables :
<table name="buyer" phpName="BtqBuyer" > <column name="buyer_id" type="BIGINT" required="true" primaryKey="true"/> <column name="buyer_name" type="VARCHAR" size="255" required="true"/> </table> <table name="command" phpName="BtqCommand" > <column name="com_id" type="BIGINT" required="true" primaryKey="true"/> <column name="com_ref" type="VARCHAR" size="6" required="true"/> <column name="com_buyer_id" type="BIGINT" required="true"/> <foreign-key foreignTable="buyer" onDelete="" onUpdate=""> <reference local="com_buyer_id" foreign="buyer_id"/> </foreign-key> </table>
In the file generator.yml, add a partial in the filters parameter to print our specific filter :
filters: [com_ref, _btq_buyer]
The source code for the partial _btq_buyer.php (located in the templates directory) is :
<?php echo input_tag('filters[buyer]', isset($filters['buyer']) ? $filters['buyer'] : '') ?>
Now we have to add our specific filter in the filter process. To do this, we extend the addFiltersCriteria from the admin generator. This is done in the file actions.class.php by adding :
protected function addFiltersCriteria (&$c) { if (isset($this->filters['buyer']) && $this->filters['buyer'] != '') { $c->add(BtqBuyerPeer::BUYER_NAME, strtr($this->filters['buyer'], '*', '%'), Criteria::LIKE); $c->addJoin(BtqBuyerPeer::BUYER_ID, BtqCommandPeer::COM_BUYER_ID); } }
As you can see, we've even allowed the use of wildcard in our filter. Nice ;)
There is no method given by Symfony to redirect to module/action of an other application. Redirect method of SfActions permit only to redirect to module/action of the current application or to an url.
In the forum fabien say, it is because applications are independant.
But it could be usefull for a backend (generated with admin generator), to add a new "object_actions" which permit to view the result of a record (an article for e.g.) by redirecting to the article webpage in the frontend.
Then you can add in the Actions class an action method like :
public function executeView() { $this->redirect("http://".$this->getContext()->getRequest()->getHost().'/article/'.$this->getRequestParameter('id')); } // or if the application is not the default application (behind index.php) and the application is named "frontend" public function executeView() { $applicationName='frontend'; $this->redirect("http://".$this->getContext()->getRequest()->getHost().'/'.$applicationName.'.php/article/'.$this->getRequestParameter('id')); }
To add this action in the backend, add this line to generator.yml :
generator:
param:
list:
object_actions:
_edit: -
view: { name : View this article, action: view, icon: backend/view.png }
Say that you have a model object Son that inherits from the model object Father, via propel inheritance. You want to create an admin generator interface for the object Son. The problem is that propel does not generate a SonPeer class, so you'll have to call:
symfony propel-init-admin Father
but the list function will list all the Father objects instead of the Son objects only. Same problem with the create function that will create a Father object, not a Son object.
Here is a solution. You will have to overload getFatherOrCreate and addFiltersCriteria:
// add this in the actions.class.php of your admin module protected function addFiltersCriteria(&$c) { $c->add(FatherPeer::CLASS_KEY, FatherPeer::CLASSKEY_SON); parent::addFiltersCriteria($c); } protected function getFatherOrCreate ($id = 'id') { $son = parent::getFatherOrCreate($id); if ($son->isNew()) // if it is a new one then we create a Son object $son = new Son(); else $this->redirect404Unless($son->isSon()); // we check that we really got a son object return $son; }
Now everything will work as if you were using the Son object.