Code snippets for symfony 1.x

Navigation

Refine Tags

Snippets tagged "filter helper"

Filter item in admin_check_list using admin generator.

Hi, this is my first snippet (in my first Symfony project), so I hope this is useful and not boring for you. I show you my code to solve a problem: how to filter an admin_check_list using a criteria.

In my project I have in the schema also this tables:

  role:
    type:                { primaryKey: true, type: char }
    descritpion:         { type: varchar(50), required: true }
  user:
    id:
    username:            { type: varchar(100), index: unique, required: true }
    role_type:           { type: char, foreignTable: role, foreignReference: type, required: true }
  course:
    id:
    name:                { type: varchar(255), required: true }
    research_proposal:   { type: longvarchar }
  course_teacher:
    course_id:
    user_id:
 

Little explanation: Each user have a role. Each course can have more teacher; each teacher is an user with "T" role_type.

In the generator.yml I can write

edit:
  fields:
    course_teachers:         { type: admin_check_list, params: through_class=CourseTeacher }
 

then in the course creation page I have a list of all users (and not a list of the teacher).

To reach my scope I need to override the ObjectAdminHelper. I create a file named ObjectAdminHelper.php and put it into the /lib/helper folder of my Symfony folder. To override successfully an helper it is necessary to overwrite (or write) all its method. So just copy all from the original ObjectAdminHelper.php file and paste it into this new file. The only method we need to override is "_get_object_list($object, $method, $options, $callback)": it use by default the method "_get_propel_object_list" to get the list to show... But if we would like to modify that list how can we do?

function _get_object_list($object, $method, $options, $callback){
  $object = get_class($object) == 'sfOutputEscaperObjectDecorator' ? $object->getRawValue() : $object;
  // the default callback is the propel one
  if (!$callback) {
    $callback = _get_option($options, 'callback');
    if (!$callback) {
        $callback = '_get_propel_object_list';
    }
  }
  return call_user_func($callback, $object, $method, $options);
}
 

This method get an option called "callback" to get the name of the callback method. If a callback method is not present it use the standard "_get_propel_object_list".

So if I would like to get only the teacher (role_type="T") i can write this function (very similar than _get_propel_object_list):

function _get_teacher_from_users($object, $method, $options){
    $criteria = new Criteria();
    $criteria->add(UserPeer::ROLE_TYPE, "T");
    $through_class = _get_option($options, 'through_class');
    $objects = sfPropelManyToMany::getAllObjects($object, $through_class, $criteria);
    $objects_associated = sfPropelManyToMany::getRelatedObjects($object, $through_class, $criteria);
    $ids = array_map(create_function('$o', 'return $o->getPrimaryKey();'), $objects_associated);
    return array($objects, $objects_associated, $ids);
}
 

Now you can write all the function you need to filter the lists.

Last step: how can my generator.yml say to the helper which method it must use? Simply modify the course_teacher row:

edit:
  fields:
    course_teachers:         { type: admin_check_list, params: through_class=CourseTeacher callback=_get_teacher_from_users }
 

I hope this is useful for you (and sorry for my english).

Pierpaolo Cira

by Pierpaolo Cira on 2008-01-21, tagged adminchecklist  filter  helper 

Complimentary Filters

A common modification to a CRUD module is filtering records on the list page. There are probably several nice ways to do this, including drop-downs, forms, etc. depending on the situation. While some of these approaches are nice, they are often not minimal... We like minimal!

Discussion

Say you have a book table, with a related author and genre. You want to filter the list of books by those related tables with links, paginate your list, and make it sortable via links in the header of the table.

To do this traditionally, you'll need lots of nasty little if statements in your template code, to check for all of these parameters (author_id, genre_id, title, num_pages, page, etc.) and combine them all together into a meaningful uri for your link_to function (something like "book/list?author_id=10&genre_id=5&sort=title&page=5"). We still want that link in the end, but generating it... How about a better way!

Followup Example

<!-- listSuccess.php -->
<?php use_helpers('Filter', 'Pagination') ?>
<h2>Books</h2>
<h3>Filter By</h3>
<table class="filters">
  <tbody>
    <tr>
      <th>Author:</th>
      <td><?php echo filter_navigation(objects_for_filter($authors), 'author_id', $author_id) ?></td>
    </tr>
    <tr>
      <th>Genre:</th>
      <td><?php echo filter_navigation(objects_for_filter($genres), 'genre_id', $genre_id) ?></td>
    </tr>
  </tbody>
</table>
<hr />
<table class="list">
  <thead>
    <tr>
      <th><?php link_to_unless($sort == 'id', 'Id', filter_url('sort', 'id')) ?></th>
      <th><?php link_to_unless($sort == 'title', 'Title', filter_url('sort', 'title')) ?></th>
      <th><?php link_to_unless($sort == 'author_id', 'Author', filter_url('sort', 'author_id')) ?></th>
      <th><?php link_to_unless($sort == 'genre_id', 'Genre', filter_url('sort', 'genre_id')) ?></th>
    </tr>
  </thead>
  <tbody>
    <?php foreach ($pager->getResults() as $book): ?>
      <tr>
        <td><?php echo $book->getId() ?></td>
        <td><?php echo $book->getTitle() ?></td>
        <td><?php echo $book->getAuthor()->getName() ?></td>
        <td><?php echo $book->getGenre()->getName() ?></td>
      </tr>
    <?php endforeach; ?>
  </tbody>
</table>
<?php echo pager_navigation($pager) ?>

NOTE: pager_navigation is covered at http://www.symfony-project.com/snippets/snippet/4, but needs to guess the uri, which is done at http://www.symfony-project.com/snippets/snippet/59.

NOTE: filter_navigation returns an unordered list, so you'll need css to display the <li> tags inline, and remove <ul> padding, margin, etc.

I'll leave it as an exercise to the reader to create the controller (action) code for this template, but it should be obvious.

The Code

<?php
 
/**
 * Generate a url using the current internal uri, but replaces a param with a new value.
 * If the param is not in the current uri's query string, it is added instead.
 *
 * This is useful for a page that uses several filters to record sets,
 * and needs all the filters to work together, instead of blasting each
 * other away when a new link is clicked.
 *
 * <strong>Examples:</strong>
 * <code>
 *  // with current uri => mymodule/myaction?author=10&genre=3
 *
 *  echo link_to('new author', filter_url('author', 5));
 *  // uri when clicked => mymodule/myaction?author=5&genre=3
 *
 *  echo link_to('new genre', filter_url('genre', 1));
 *  // uri when clicked => mymodule/myaction?author=10&genre=1
 *
 *  // with current uri => mymodule/myaction
 *
 *  echo link_to('an author', filter_url('author', 10));
 *  // uri when clicked => mymodule/myaction?author=10
 * </code>
 *
 * @param string the name of the parameter to replace
 * @param string the value to replace the current value with
 * @param boolean use route name
 * @return string the url with the parameter replaced
 * @see link_to
 */
function filter_url($param, $new_value, $with_route_name = false)
{
    // fetch params from query string
    $params = _get_params(_get_query_string());
 
    // replace param with new value
    $params[$param] = $new_value;
 
    return _get_uri($with_route_name) . '?' . _build_query_string($params);
}
 
/**
 * Removes a parameter from the current uri and returns the resulting url.
 *
 * @see filter_url
 */
function remove_filter_url($param, $with_route_name = false)
{
    // fetch params from query string
    $params = _get_params(_get_query_string());
 
    // remove param
    unset($params[$param]);
 
    return _get_uri($with_route_name) . '?' . _build_query_string($params);
}
 
/**
 * Generates an unordered list of links to filter the current record set by.
 * Multiple sets of filter_navigation links will work together, using the current uri.
 *
 * <strong>Examples:</strong>
 * <code>
 *  echo filter_navigation(array(10=>'Jones', 12=>'Smith, J.', 13=>'Darby'), 'author_id', 13);
 *  echo filter_navigation(objects_for_filter($authors), 'author_id', 13);
 * </code>
 *
 * @param array list of key=>value pairs of ids and strings
 * @param string the name of the parameter for this filter
 * @param string the selected id (or null, if none selected)
 * @param string the text to use for the "all" link
 * @see filter_url
 */
function filter_navigation($list, $param, $selected = null, $all_text = 'All')
{
    $html = '';
 
    $html .= content_tag('li', link_to_unless($selected === null, $all_text, remove_filter_url($param)));
    foreach ($list as $key => $value)
    {
        $html .= content_tag('li', link_to_unless($selected == $key, $value, filter_url($param, $key)));
    }
 
    return content_tag('ul', $html);
}
 
/**
 * Generates a simple list from a record set of propel objects.
 * Expects a getId function and a toString function.
 *
 * @param array objects to be converted to a list
 * @see filter_navigation
 */
function objects_for_filter($objects)
{
    $list = array();
 
    foreach ($objects as $object)
    {
        $list[$object->getId()] = $object->toString();
    }
 
    return $list;
}
 
function _get_uri($with_route_name = false)
{
    $internal_uri = sfRouting::getInstance()->getCurrentInternalUri($with_route_name);
    $ar = explode('?', $internal_uri);
 
    return ($with_route_name ? '@' : '') . $ar[0];
}
 
function _get_query_string()
{
    $internal_uri = sfRouting::getInstance()->getCurrentInternalUri();
    $ar = explode('?', $internal_uri);
 
    return isset($ar[1]) ? $ar[1] : '';
}
 
function _get_params($query_string)
{
    // parse query string into associative array
    $params = array();
    if ($query_string != '')
    {
        foreach (explode('&', $query_string) as $kvpair)
        {
            list($key, $value) = explode('=', $kvpair);
            $params[$key] = $value;
        }
    }
 
    return $params;
}
 
function _build_query_string($params)
{
    // build list of key=value strings
    $ar = array();
    foreach ($params as $key => $value)
    {
        $ar[] = $key . '=' . $value;
    }
 
    return implode('&', $ar);
}

NOTE: Place this in apps/myapp/lib/helper/FilterHelper.php.

Additional Usage Examples

<?php echo link_to('new author', filter_url('author_id', 10)) ?>
<?php echo url_for(filter_url('author_id', 10)) ?>
<?php echo link_to_if($condition, 'new author',  filter_url('author_id', 10)) ?>
<?php echo link_to_unless($condition, 'new author',  filter_url('author_id', 10)) ?>
<?php echo button_to('new author',  filter_url('author_id', 10)) ?>

Additional Helpers

<?php
 
/**
 * Shortcut combining link_to and filter_url into single function.
 *
 * @see link_to
 * @see filter_url
 */
function link_to_filter($name, $param, $new_value, $options = array())
{
    return link_to($name, filter_url($param, $new_value), $options);
}
 
/**
 * Shortcut combining url_for and filter_url into single function.
 *
 * @see url_for
 * @see filter_url
 */
function filter_url_for($param, $new_value)
{
    return url_for(filter_url($param, $new_value));
}
 
/**
 * Shortcut combining link_to_if and filter_url into single function.
 *
 * @see link_to_if
 * @see filter_url
 */
function link_to_filter_if($condition, $name, $param, $new_value, $options = array())
{
    return link_to_if($condition, $name, filter_url($param, $new_value), $options);
}
 
/**
 * Shortcut combining link_to_unless and filter_url into single function.
 *
 * @see link_to_unless
 * @see filter_url
 */
function link_to_filter_unless($condition, $name, $param, $new_value, $options = array())
{
    return link_to_unless($condition, $name, filter_url($param, $new_value), $options);
}
 
/**
 * Shortcut combining button_to and filter_url into single function.
 *
 * @see button_to
 * @see filter_url
 */
function button_to_filter($name, $param, $new_value, $options = array())
{
    return button_to($name, filter_url($param, $new_value), $options);
}
by Stephen Riesenberg on 2007-02-03, tagged css  filter  helper  pager  pagination  template  view