sfPropel15Plugin - 0.9.0

Replaces symfony's core Propel plugin by the latest version of Propel, in branch 1.5.

You are currently browsing
the website for symfony 1

Visit the Symfony2 website


« Back to the Plugins Home

Signin


Forgot your password?
Create an account

Tools

Stats

advanced search
Information Readme Releases Changelog Contribute
This plugin is deprecated and is not maintained anymore. Please, use the sfPropelORMPlugin plugin : http://www.symfony-project.org/plugins/sfPropelORMPlugin
Show source

sfPropel15Plugin

Replaces symfony's core Propel plugin by the latest version of Propel, in branch 1.5.

Installation

Install the plugin via the subversion repository:

$ 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

Right after the installation of the plugin, you should update plugin assets:

$ ./symfony plugin:publish-assets

Disable the core Propel plugin and enable the sfPropel15Plugin instead:

class ProjectConfiguration extends sfProjectConfiguration
{
  public function setup()
  {
    $this->enablePlugins('sfPropel15Plugin');
  }
}

Change the path of the symfony behaviors in the config/propel.ini file of your project:

propel.behavior.symfony.class                  = plugins.sfPropel15Plugin.lib.behavior.SfPropelBehaviorSymfony
propel.behavior.symfony_i18n.class             = plugins.sfPropel15Plugin.lib.behavior.SfPropelBehaviorI18n
propel.behavior.symfony_i18n_translation.class = plugins.sfPropel15Plugin.lib.behavior.SfPropelBehaviorI18nTranslation
propel.behavior.symfony_behaviors.class        = plugins.sfPropel15Plugin.lib.behavior.SfPropelBehaviorSymfonyBehaviors
propel.behavior.symfony_timestampable.class    = plugins.sfPropel15Plugin.lib.behavior.SfPropelBehaviorTimestampable

What's New

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 page in the Propel trac to see the full list of changes.

$books = PropelQuery::from('Book b')
    ->join('b.Author a')
    ->where('a.FirstName = ?', 'Leo')
    ->limit(10)
    ->find($con);

Admin Generator Extensions

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.

To enable this theme, edit your generator.yml and change the theme property from admin to admin15, as follows:

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:

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:

$books = BookQuery::create()
  ->joinWithAuthor()
  ->paginate();

Of course, you can add as many with names as you want, to hydrate multiple objects:

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:

list:
  display: [title]
  query_methods: [filterByAlreadyPublished]

The admin generator will then execute the following query to display the list:

$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():

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:

list:
  display: [title]
  query_methods: [withNbReviews]

For this to work, add the following method to the query class:

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 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:

# 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:

class BookQuery extends BaseBookQuery
{
  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:

# 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 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:

# 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:

// 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:

# 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:

// 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:

# 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.