Author: francois Date: 2010-04-22 11:19:49 +0200 (Thu, 22 Apr 2010) New Revision: 29232
Added: plugins/sfPropel15Plugin/trunk/doc/ plugins/sfPropel15Plugin/trunk/doc/admin_generator.txt Modified: plugins/sfPropel15Plugin/trunk/README Log: [sfPropel15Plugin] Refactored documentation and documented widget customization in YAML for generator Modified: plugins/sfPropel15Plugin/trunk/README =================================================================== --- plugins/sfPropel15Plugin/trunk/README 2010-04-22 08:15:40 UTC (rev 29231) +++ plugins/sfPropel15Plugin/trunk/README 2010-04-22 09:19:49 UTC (rev 29232) @@ -1,20 +1,22 @@ -# sfPropel15Plugin # +sfPropel15Plugin +================ Replaces symfony's core Propel plugin by the latest version of Propel, in branch 1.5. -## Installation ## +Installation +------------ Install the plugin via the subversion repository: - $ svn co http://svn.symfony-project.com/plugins/sfPropel15Plugin/trunk plugins/sfPropel15Plugin + > svn co http://svn.symfony-project.com/plugins/sfPropel15Plugin/trunk plugins/sfPropel15Plugin from the project root directory or by using the command: - $ ./symfony plugin:install sfPropel15Plugin + > ./symfony plugin:install sfPropel15Plugin Right after the installation of the plugin, you should update plugin assets: - $ ./symfony plugin:publish-assets + > ./symfony plugin:publish-assets Disable the core Propel plugin and enable the `sfPropel15Plugin` instead: @@ -36,227 +38,109 @@ propel.behavior.symfony_behaviors.class = plugins.sfPropel15Plugin.lib.behavior.SfPropelBehaviorSymfonyBehaviors propel.behavior.symfony_timestampable.class = plugins.sfPropel15Plugin.lib.behavior.SfPropelBehaviorTimestampable -## What's New ## +What's New In Propel 1.5 +------------------------ -Propel 1.5 is a backwards compatible evolution of Propel 1.4 (the version bundled with symfony 1.3 and 1.4), which adds some very interesting features. Among these features, you will find the new Propel Query API, which is essentially a Criteria on steroids. Check out the [WHATS_NEW](http://propel.phpdb.org/trac/wiki/Users/Documentation/1.5/WhatsNew) page in the Propel trac to see the full list of changes. +Propel 1.5 is a **backwards compatible** evolution of Propel 1.4 (the version bundled with symfony 1.3 and 1.4), which adds some very interesting features. Among these features, you will find the **new Propel Query API**, which is essentially a Criteria on steroids: [php] - $books = PropelQuery::from('Book b') - ->join('b.Author a') - ->where('a.FirstName = ?', 'Leo') - ->limit(10) - ->find($con); + // find the 10 latest books published by authror 'Leo' + $books = BookQuery::create() + ->useAuthorQuery() + ->filterByFirstName('Leo') + ->endUse() + ->orderByPublishedAt('desc') + ->limit(10) + ->find($con); -## Admin Generator Extensions ## +Propel 1.5 also supports **many-to-many relationships**, **collections**, **on-demand hydration**, **new core behaviors** (see below), better Oracle support, and is now licensed under the MIT license. -The plugin comes bundled with a new admin generator theme named 'admin15'. This theme provides additional features based on the new Propel 1.5 query objects, and is backwards compatible with sfPropelPlugin's admin generator theme. +Check out the [WHATS_NEW](http://propel.phpdb.org/trac/wiki/Users/Documentation/1.5/WhatsNew) page in the Propel trac to see the full list of changes. -To enable this theme, edit your `generator.yml` and change the `theme` property from `admin` to `admin15`, as follows: +Core Propel Behaviors +--------------------- - [yaml] - generator: - class: sfPropelGenerator - param: - model_class: Book - theme: admin15 - non_verbose_templates: true - with_show: false - singular: Book - plural: Books - route_prefix: book - with_propel_route: 1 - actions_base_class: sfActions +Propel 1.5 bundles most common behaviors in a new, robust buildtime implementation. These core behaviors provide faster runtime execution and the ability to modify the data model: -You can now use the additional features listed below. +- [timestampable](http://www.propelorm.org/wiki/Documentation/1.5/Behaviors/timestampable) +- [sluggable](http://www.propelorm.org/wiki/Documentation/1.5/Behaviors/sluggable) +- [soft_delete]([http://www.propelorm.org/wiki/Documentation/1.5/Behaviors/soft_delete) +- [nested_set](http://www.propelorm.org/wiki/Documentation/1.5/Behaviors/nested_set) +- [sortable](http://www.propelorm.org/wiki/Documentation/1.5/Behaviors/sortable) +- [concrete_inheritance](http://www.propelorm.org/wiki/Documentation/1.5/Inheritance#ConcreteTableInheritance) +- [query_cache](http://www.propelorm.org/wiki/Documentation/1.5/Behaviors/query_cache) +- [alternative_coding_standards](http://www.propelorm.org/xiki/Documentation/1.5/Behaviors/alternative_coding_standards) +- [auto_add_pk](http://www.propelorm.org/wiki/Documentation/1.5/Behaviors/auto_add_pk) -### Hydrating Related Objects ### +`sfPropel15Plugin` allows you to register core propel behaviors right from your `schema.yml`. For instance, to create a tree structure from a `Section` model: -The `admin15` theme doesn't use the Peer classes anymore, therefore settings referencing the Peer classes are ignored in this theme. This includes `peer_method`, and `peer_count_method`. The new theme provides a simple alternative for these settings, called `with`. Add each of the objects to hydrate together with the main object in the `with` setting list: - [yaml] - list: - display: [title, Author] - with: [Author] + propel: + section: + _attributes: { phpName: Section } + _propel_behaviors: + - nested_set + id: ~ + title: { type: varchar(100), required: true primaryString: true } -The admin generator will then execute the following query to display the list, effectively executing a single query instead of 1+n queries: +You can also register a behavior for all your models right in the `propel.ini`. `sfPropel15Plugin` already enables the `symfony` and `symfony_i18n` behaviors to support symfony's behavior system and model localization features, but you can easily add your owns: - [php] - $books = BookQuery::create() - ->joinWithAuthor() - ->paginate(); + [ini] + propel.behavior.default = symfony,symfony_i18n,alternative_coding_standards,auto_add_pk -Of course, you can add as many `with` names as you want, to hydrate multiple objects: +Admin Generator Extensions +-------------------------- - [yaml] - list: - display: [title, Author, Publisher] - with: [Author, Publisher] +The plugin comes bundled with a new admin generator theme named 'admin15'. This theme is backwards compatible with sfPropelPlugin's admin generator theme, and provides additional features based on the new Propel 1.5 query objects: -*Tip*: Before adding relations to the `with` setting, check that you don't already have a filter on the foreign key column that already makes the query to list all the related objects. If it's the case, then Propel's Instance Pooling will make the `with` superfluous, as each call to a related object will not trigger an additional query anyway. +### List view enhancements -### Additional Query Methods ### +- **Easy related objects hydration**: You don't need to write custom diSelectJoinXXX() methods to hydrate related objects. The `with` setting is much more poxwerful that the previous `peer_method` and `peer_count_method` settings, and much easier to use. +- **Custom query methods**: You can refine the query executed to display the list view by by setting the `query_methods` parameter. This allows to hydrate an additional column wit hno additional query, or to pre-filter the list to hide rows that the user shouldn't see. +- **All columns are sortable**: Virtual columns and foreign key columns are now sortable in the list view. You'll need to set the sort method to use for that, but it's a one-liner. No more lists with column headers that can't be clicked for sorting! +- **Easy links to filtered lists**: A link to a fitlered list view is very easy to write with the new theme. Just add GET parameter, the same way you used to do with the admin generator in symfony 1.2, and it works +- **Links to another admin module**: To make a foreign key column link to the edit view of the related object in another module, you no longer need to create a partial. Just define the `link_module` setting in the foreign key field configuration, and you're good to go: +- **Easy custom filters**: Adding custom filters becomes very easy once you can take advantage of the generated Propel query classes. This allows your, for instance, to setup a full-text search input in two minutes, replacing many text filters by a single one for better usability. -You can execute additional query methods in the list by setting the `query_methods` parameter. For instance, in a list of `Books`, to limit the list of published books, setup your `list` view as follows: +### Filter and Edit forms enhancement - [yaml] - list: - display: [title] - query_methods: [filterByAlreadyPublished] +- **YAML widget customization**: The `generator.yml` format was extended to allow basic widget customization directly in YAML, without the need to edit a form object. -The admin generator will then execute the following query to display the list: +The new options for the `admin15` generator theme are fully documented, and illustrated by real life examples, in the [`doc/admin_generator.txt`](http://trac.symfony-project.org/browser/plugins/sfPropel15Plugin/doc/admin_generator.txt) file in this plugin source code. - [php] - $books = BookQuery::create() - ->filterByAlreadyPublished() - ->paginate(); +Form Subframework Modifications +------------------------------- -You must implement each `query_method` in the main object's query class. In this exemple, here is how you can implement `Bookquery::filterByAlreadyPublished()`: +### Updated `sfWidgetFormPropelChoice` widget - [php] - class BookQuery extends BaseBookQuery - { - public function filterByAlreadyPublished() - { - return $this->filterByPublishedAt(array('min' => time())); - } - } - -You can use this feature to add calculated columns to the list without additional queries: +The `sfWidgetFormPropelChoice` widget now uses the new Query API. You can customize the list of choices more easily by executing custom query methods, using the new `query_methods` option. For instance, if the `Section` model uses the `nested_set` behavior, you probably want to display a section selection widget in hierarchical order. This is easily achived by execiting the `orderByBranch()` query method, and you can register it as follows: - [yaml] - list: - display: [title] - query_methods: [withNbReviews] - -For this to work, add the following method to the query class: - [php] - class BookQuery extends BaseBookQuery + class ContentForm extends BaseContentForm { - public function withNbReviews() + public function configure() { - return $this - ->leftJoin('Book.Review') - ->withColumn('COUNT(Review.Id)', 'NbReviews'); + $this->widgetSchema['section'] = new sfWidgetFormPropelChoice(array( + 'model' => 'Section', + 'query_methods' => array('orderByBranch') + 'add_empty' => true, + )); } } -Now you can add a partial column and use the virtual `NbReviews` column in the list: +In practice, you won't need to build a custom Criteria object to achieve a custom list choice - but it still works: [php] - <?php echo $book->getVirtualColumn('NbReviews') ?> - -### Sorting On A Virtual Column ### - -The new theme provides an easy way to make virtual columns sortable in the list view. Just declare the corresponding fields with `is_sortable` to `true`, and the generated module will look for an `orderByXXX()` method in the generated query. For instance, to allow a book list to be sortable on the author name: - - [yaml] - # in generator.yml - list: - display: [title, Author] - query_methods: [joinWithAuthor] - fields: - - Author: { is_sortable: true } - -Then the generator will try to execute `BookQuery::orderByAuthor()` whenever the user clicks on the `Author` header to sort on this column. The method must be implemented as follows: - - [php] - class BookQuery extends BaseBookQuery + class ContentForm extends BaseContentForm { - public function orderByAuthor($order = Criteria::ASC) - { - return $this - ->joinAuthor() - ->orderBy('Author.LastName', $order); - } - } - -You can override the default sorting method name for a field by setting the `sort_method` parameter: - - [yaml] - # in generator.yml - list: - display: [title, Author] - query_methods: [joinWithAuthor] - fields: - - Author: { is_sortable: true, sort_method: orderByAuthorLastName } - -The generator will execute `BookQuery::orderByAuthorLastName()` instead of `BookQuery::orderByAuthor()` in that case. - -### Filtering The List With GET Parameters ### - -The admin generator doesn't allow to filter the list using GET parameters. This neat feature used to be supported in previous versions of the generator, and is supported again in the `admin15` theme. - -All you have to do to filter a list view is to prepend a query string to the URL, describing the filters in a `filters` array. For instance, to link to the book list view filtered by Author, try the following link: - - [php] - <?php echo link_to($author->getName(), 'book', array(), array('query_string' => 'filters[author_id]=' . $author->getId())) ?> - -This is very useful for partial lists, to link admin modules together. - -### Cross-Linking Admin Modules ### - -In lists, related object columns often have to link to another admin generator module. For instance, in a list of `Books`, a column showing the `Author` name usually needs to link to the `edit` view in the `author` module for the current book author. You can implement this feature using a partial column: - - [yaml] - # in generator.yml - list: - display: [title, _author] - -The partial column code is a one-liner, but it's quite tedious to repeat it many times: - - [php] - // in modules/book/templates/_author.php - <?php echo link_to($book->getAuthor(), 'author_edit', $book->getAuthor) ?> - -The `admin15` theme provides a shortcut for this situation. Just define the `link_module` setting in the `Author` field configuration to point the `author` module, and you're good to go: - - [yaml] - # in generator.yml - list: - display: [title, Author] - fields: - Author: { link_module: author } - -You no longer need a partial for such simple cases. This should unclutter the `templates/` directory of your admin generator modules. - -### Easy Custom Filter ### - -Adding custom filters becomes very easy once you can take advantage of the generated Propel query classes. For example, in a list of `Books`, the default filters offer one text input for the book title, and a second one for the book ISBN. In order to replace them with a single text input, here is what you need to do: - - [php] - // in lib/filter/BookFormFilter.php - class BookFormFilter extends BaseBookFormFilter - { public function configure() { - $this->widgetSchema['full_text'] = new sfWidgetFormFilterInput(array('with_empty' => false)); - $this->validatorSchema['full_text'] = new sfValidatorPass(array('required' => false)); + $query = SectionQuery::create() + ->filterByIsVisible(true); + $this->widgetSchema['section'] = new sfWidgetFormPropelChoice(array( + 'model' => 'Section', + 'criteria' => $query, + 'add_empty' => true, + )); } } - - // in lib/model/Bookquery.php - class BookQuery extends BaseBookQuery - { - public function filterByFullText($value) - { - if (isset($value['text'])) { - $pattern = '%' . $value['text'] . '%'; - $this - ->condition('condTitle', 'Book.Title LIKE ?', $pattern) - ->condition('condISBN', 'Book.ISBN LIKE ?', $pattern) - ->combine(array('condTitle', 'condISBN'), Criteria::LOGICAL_OR); - } - return $this; - } - } - -Now just modify the `filters.display` setting in the `generator.yml` to remove the `title` and `isbn` filters, and replace them with the new `full_text` filter: - - [yaml] - # in modules/book/config/generator.yml - config: - filters: - display: [full_text] - -The amdin generator looks for a `filterByXXX()` method in the query class, where `XXX` is the CamelCase version of the custom filter you add. \ No newline at end of file Added: plugins/sfPropel15Plugin/trunk/doc/admin_generator.txt =================================================================== --- plugins/sfPropel15Plugin/trunk/doc/admin_generator.txt (rev 0) +++ plugins/sfPropel15Plugin/trunk/doc/admin_generator.txt 2010-04-22 09:19:49 UTC (rev 29232) @@ -0,0 +1,239 @@ +Admin Generator Extensions +========================== + +sfPropel15Plugin comes bundled with a new admin generator theme named 'admin15'. This theme provides additional features based on the new Propel 1.5 query objects, and is backwards compatible with sfPropelPlugin's admin generator theme. + +To enable this theme, edit your `generator.yml` and change the `theme` property from `admin` to `admin15`, as follows: + + [yaml] + generator: + class: sfPropelGenerator + param: + model_class: Book + theme: admin15 + non_verbose_templates: true + with_show: false + singular: Book + plural: Books + route_prefix: book + with_propel_route: 1 + actions_base_class: sfActions + +You can now use the additional features listed below. + +Hydrating Related Objects +------------------------- + +The `admin15` theme doesn't use the Peer classes anymore, therefore settings referencing the Peer classes are ignored in this theme. This includes `peer_method`, and `peer_count_method`. The new theme provides a simple alternative for these settings, called `with`. Add each of the objects to hydrate together with the main object in the `with` setting list: + + [yaml] + list: + display: [title, Author] + with: [Author] + +The admin generator will then execute the following query to display the list, effectively executing a single query instead of 1+n queries: + + [php] + $books = BookQuery::create() + ->joinWithAuthor() + ->paginate(); + +Of course, you can add as many `with` names as you want, to hydrate multiple objects: + + [yaml] + list: + display: [title, Author, Publisher] + with: [Author, Publisher] + +*Tip*: Before adding relations to the `with` setting, check that you don't already have a filter on the foreign key column that already makes the query to list all the related objects. If it's the case, then Propel's Instance Pooling will make the `with` superfluous, as each call to a related object will not trigger an additional query anyway. + +Additional Query Methods +------------------------ + +You can execute additional query methods in the list by setting the `query_methods` parameter. For instance, in a list of `Books`, to limit the list of published books, setup your `list` view as follows: + + [yaml] + list: + display: [title] + query_methods: [filterByAlreadyPublished] + +The admin generator will then execute the following query to display the list: + + [php] + $books = BookQuery::create() + ->filterByAlreadyPublished() + ->paginate(); + +You must implement each `query_method` in the main object's query class. In this exemple, here is how you can implement `Bookquery::filterByAlreadyPublished()`: + + [php] + class BookQuery extends BaseBookQuery + { + public function filterByAlreadyPublished() + { + return $this->filterByPublishedAt(array('min' => time())); + } + } + +You can use this feature to add calculated columns to the list without additional queries: + + [yaml] + list: + display: [title] + query_methods: [withNbReviews] + +For this to work, add the following method to the query class: + + [php] + class BookQuery extends BaseBookQuery + { + public function withNbReviews() + { + return $this + ->leftJoin('Book.Review') + ->withColumn('COUNT(Review.Id)', 'NbReviews'); + } + } + +Now you can add a partial column and use the virtual `NbReviews` column in the list: + + [php] + <?php echo $book->getVirtualColumn('NbReviews') ?> + +Sorting On A Virtual Column +--------------------------- + +The new theme provides an easy way to make virtual columns and foreign key columns sortable in the list view. Just declare the corresponding fields with `is_sortable` to `true`, and the generated module will look for an `orderByXXX()` method in the generated query. For instance, to allow a book list to be sortable on the author name: + + [yaml] + # in generator.yml + list: + display: [title, Author] + query_methods: [joinWithAuthor] + fields: + - Author: { is_sortable: true } + +Then the generator will try to execute `BookQuery::orderByAuthor()` whenever the user clicks on the `Author` header to sort on this column. The method must be implemented as follows: + + [php] + class BookQuery extends BaseBookQuery + { + public function orderByAuthor($order = Criteria::ASC) + { + return $this + ->useAuthorQuery() + ->orderByLastName($order) + ->endUse(); + } + } + +You can override the default sorting method name for a field by setting the `sort_method` parameter: + + [yaml] + # in generator.yml + list: + display: [title, Author] + query_methods: [joinWithAuthor] + fields: + - Author: { is_sortable: true, sort_method: orderByAuthorLastName } + +The generator will execute `BookQuery::orderByAuthorLastName()` instead of `BookQuery::orderByAuthor()` in that case. + +Filtering The List With GET Parameters +-------------------------------------- + +The admin generator doesn't allow to filter the list using GET parameters. This neat feature used to be supported in previous versions of the generator, and is supported again in the `admin15` theme. + +All you have to do to filter a list view is to prepend a query string to the URL, describing the filters in a `filters` array. For instance, to link to the book list view filtered by Author, try the following link: + + [php] + <?php echo link_to($author->getName(), 'book', array(), array('query_string' => 'filters[author_id]=' . $author->getId())) ?> + +This is very useful for partial lists, to link admin modules together. + +Cross-Linking Admin Modules +--------------------------- + +In lists, related object columns often have to link to another admin generator module. For instance, in a list of `Books`, a column showing the `Author` name usually needs to link to the `edit` view in the `author` module for the current book author. You can implement this feature using a partial column: + + [yaml] + # in generator.yml + list: + display: [title, _author] + +The partial column code is a one-liner, but it's quite tedious to repeat it many times: + + [php] + // in modules/book/templates/_author.php + <?php echo link_to($book->getAuthor(), 'author_edit', $book->getAuthor) ?> + +The `admin15` theme provides a shortcut for this situation. Just define the `link_module` setting in the `Author` field configuration to point the `author` module, and you're good to go: + + [yaml] + # in generator.yml + list: + display: [title, Author] + fields: + Author: { link_module: author } + +You no longer need a partial for such simple cases. This should unclutter the `templates/` directory of your admin generator modules. + +Easy Custom Filter +------------------ + +Adding custom filters becomes very easy once you can take advantage of the generated Propel query classes. For example, in a list of `Books`, the default filters offer one text input for the book title, and a second one for the book ISBN. In order to replace them with a single text input, here is what you need to do: + + [php] + // in lib/filter/BookFormFilter.php + class BookFormFilter extends BaseBookFormFilter + { + public function configure() + { + $this->widgetSchema['full_text'] = new sfWidgetFormFilterInput(array('with_empty' => false)); + $this->validatorSchema['full_text'] = new sfValidatorPass(array('required' => false)); + } + } + + // in lib/model/Bookquery.php + class BookQuery extends BaseBookQuery + { + public function filterByFullText($value) + { + if (isset($value['text'])) { + $pattern = '%' . $value['text'] . '%'; + $this + ->condition('condTitle', 'Book.Title LIKE ?', $pattern) + ->condition('condISBN', 'Book.ISBN LIKE ?', $pattern) + ->combine(array('condTitle', 'condISBN'), Criteria::LOGICAL_OR); + } + return $this; + } + } + +Now just modify the `filters.display` setting in the `generator.yml` to remove the `title` and `isbn` filters, and replace them with the new `full_text` filter: + + [yaml] + # in modules/book/config/generator.yml + config: + filters: + display: [full_text] + +The amdin generator looks for a `filterByXXX()` method in the query class, where `XXX` is the CamelCase version of the custom filter you add. + +YAML Widget Customization +------------------------- + +You can now change widget options directly from within the `generator.yml`. That means you no longer need to edit a form object for basic widget customization. + +Just add your custom widget `class`, `options`, or `attributes` under the `widget` key of your field description. For instance, to add a custom order and CSS class to a choice widget in the edit form, the following YAML code is enough: + + [yaml] + # in modules/book/config/generator.yml + config: + edit: + display: [id, title, author_id] + fields: + author_id: + widget: + options: { order_by: [LastName, asc] } + attributes: { class: authorList } \ No newline at end of file Property changes on: plugins/sfPropel15Plugin/trunk/doc/admin_generator.txt ___________________________________________________________________ Added: svn:executable + * -- You received this message because you are subscribed to the Google Groups "symfony SVN" group. To post to this group, send email to [email protected]. To unsubscribe from this group, send email to [email protected]. For more options, visit this group at http://groups.google.com/group/symfony-svn?hl=en.
