symfonynerds.com

Nerds who love the symfony-project

Archive for the ‘view’ Category

This tip is a quick one for newbies. The Symfony book has some great tips as to when you would want to use a Symfony forward, vs a Symfony redirect. This quick post will show you the difference between the two and give you some guidelines to know when to use redirect or forward.

So what’s the main difference?

Symfony Redirect: This simply does a HTTP header(”location: “)
Symfony Forward:
This is complete custom code that comes with the Symfony framework that forwards you within the Symfony application.

Use Symfony Forward if:

  • If the action needs to forward a call to another action
    This will mean you can keep all the action class’ objects in scope and still have access to them
  • You want to forward the user to an action within the application, and keep it transparent to the user.
    From a users perspective - the displayed URL stays the same.

Use a Symfony Redirect if:

  • You need to go to an external website (http://google.com for example)
  • You don’t want the user to re-submit a form (if you are doing a form POST)
    It is generally good practice to do a redirect after a POST to ensure the user does not re-submit the form.

Conditional Forwarding/redirect
Quite often you need to forward or redirect if a condition has been met. Be sure to checkout the other Symfony functions that help you do this (forwardIf(), forwardUnless(), forward404If(), forward404Unless(), redirectIf(), and redirectUnless())

What about AJAX calls?
You can check if a HTTP request is an AJAX call before deciding what to do with it by calling calling  $request->isXmlHttpRequest() in your actions class. Once you have done this you can choose what you want to do; redirect or forward.

I am working on an interesting project where I have been given the task of creating a web interface that allows an authenticated and authorised user to conduct specific types of search on a huge data set.

The data set begins as flat text logs which are transformed and loaded into a normalised schema - which was designed well before I got involved.  So, I have been very impressed by the way that propel and creole have consistently reverse engineered the schema and built a reliable model.

This is not a post about Propel or Creole but I thought to put this into context since I have been given a development specification that requires me to present data on a browser in a manner different to the way in which it is ordered and layed out in the database schema.

So - consider a table that has the following structure:

id (auto increment unique id)
my_date (of type date)
my_date_as_int (a conversion of date to int eg 2008-08-06 would be 20080806)

The insertion of dates into the above fields is not ordered - so id 1 may have an older date than id 2 and so on…for example:

id my_date_as_int my_date
1 20080602 2008-06-02
2 20080724 2008-07-24
3 20080723 2008-07-23
4 20080411 2008-04-11
5 20080412 2008-04-12

My task was to create a “drop down” select tag that showed the above sorted in an ascending order by the date field.

Step 1.  Create a __toString method to return the date field as opposed to the Id.

public function __toString()
{
return $this->getMyDate();
}


Step 2.  Create a custom method in the relevant Peer class to get a sorted list:

public static function getSortedDate()
{
$c = new Criteria();
$c->addAscendingOrderByColumn(DatePeer::MY_DATE_AS_INT);
$rs = DatePeer::doSelect($c);
return $rs;
}

As you can see, I choose to sort by the integer representation of the date field, but you can use the MY_DATE field in the same manner.

Step 3.  Create a drop down select_tag in your view.

There are two options here.

Option 1.  Standard form name, value pairs being the date and id fields respectivey.

<?php echo object_select_tag('', 'getMyDate', array (
  'related_class' => 'Date',
  'peer_method' => 'getSortedDate',
  'include_blank' => true,
)) ?>


Option 2.  Form name, value pairs being the my_date and the my_date_as_int fields respectivey.

<?php
  echo select_tag('', 
   objects_for_select(DatePeer::getSortedDate(), 'getMyDateAsInt','getMyDate'),
   array('id'=>"this_date",'name'=>"this_date"))
?>

That is it! The view then renders a drop down select that is constructed firstly by a call to the getSortedDate method, which in turn returns an array of sorted items - each of which is shown in the drop down using the __toString method to convert from an id to the date.

Export to Excel with Symfony

Exporting to excel isn’t really something that’s symfony specific. There are plenty of good PHP libraries out there that can allow you to do some pretty advanced Microsoft Excel stuff with PHP.

In this example, I’ll show you how to get a view exporting to Excel. This is a very basic example that will get you started - with no external third-party libs.

Firstly, modify your actions class to turn off any layout template , do your sql query and then change the HTTP headers to have a response type of ‘application/msexcel’:

1
2
3
4
5
6
7
8
9
10
11
  public function executeList()
  {
    //Turn off the layout
    $this->setLayout(false);
 
    //My query
    $this->accounts = AccountPeer::doSelect(new Criteria());
 
    //Export the output in Excel 
    $this->getResponse()->setContentType('application/msexcel');
 }

Then in your view, all you need to do is have a basic HTML non-formatted table. For example, the contents of listSuccess.php could look something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<table>
<thead>
<tr>
  <th>Account</th>
  <th>Type</th>
  ...
</tr>
</thead>
<tbody>
<?php foreach ($accounts as $account): ?>
  <tr>
          <td><?php echo $account->getCompanyName() ?></td>
          <td><?php echo $account->getAccountType() ?></td>
          ...
  </tr>
<?php endforeach; ?>
</tbody>
</table>

Thats it! Simple!

If you want to do some more advanced stuff - you should get a third-party lib, but if all your after is to export one view into a single Excel workbook with PHP and Symfony - this should be all you need.

Symfony has an awesome feature that automatically re-populates your form for you without writing any code. All you have to do is specify it in your app/module/validate/myForm.yml file:

fillin: 
  enabled: true

So what happens if you have multiple forms on the same page? Well all you have to do is ensure that each one of your forms has ID and a Name:

echo form_tag('mymodule/action', 'name=myForm id=myForm');

Then in your yml validation file for that form, ensure that you specify the form name:

fillin: 
  enabled: true
  param:
    name: myForm
....

That’s it. Click here to read more about Symfony Form Validation.

Wow, I’m blown away with how easy it is to get some pagination going with Symfony. In my previous life, I had coded my own custom Pagination class - it would have been easily 100 lines of code. I’ve just implemented some very basic pagination with less than 20 lines of code.

I’m assuming you have created your model objects, and have a basic setup going. Im also doing this in Symfony 1.0. Lets now go ahead and create some basic pagination.

1. Edit your actions.class.php for the module you want to paginate. In my case, I want to create a listing of all companies. For this, I’ll have a executeList action within that class. Here is what it looks like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class companyActions extends sfActions
{
  ...
  public function executeList(){
    //Get a listing of all companies
    $this->companys = CompanyPeer::doSelect(new Criteria());
 
    //Lets do the pagination for it, firstly define a pager for the Company object. Lets go with 10 results per page
    $pager = new sfPropelPager('Company', 10);
    //Define the criteria, in this case, we won't have any - lets get all companies 
    $pager->setCriteria(new Criteria());
    //Set the first page to 1
    $pager->setPage($this->getRequestParameter('page', 1));
    $pager->init();
    $this->pager = $pager;
  }
   ...
}//class

2. Now lets modify your view for listSuccess.php to display what results you are viewing

1
2
//Display a summary of the total companies found, and how many companies there are
echo $pager->getNbResults()." Companies found. Displaying results ".$pager->getFirstIndice()." to ".$pager->getLastIndice();

3. Now lets put in our main code to loop through the paginated results (still in listSucess.php)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
foreach ($pager->getResults() as $company){
    echo $company->getCompanyName();
     //go through and display all you want maybe in a nice table here
     //... 
}
//Now lets display a small navigation bar with arrows for next, previous and page numbers
echo "<br/>";
  <?php if ($pager->haveToPaginate()): ?>
    <?php echo link_to('&laquo;', 'company/list?page='.$pager->getFirstPage()) ?>
    <?php echo link_to('&lt;', 'company/list?page='.$pager->getPreviousPage()) ?>
    <?php $links = $pager->getLinks(); foreach ($links as $page): ?>
      <?php echo ($page == $pager->getPage()) ? $page : link_to($page, 'company/list?page='.$page) ?>
      <?php if ($page != $pager->getCurrentMaxLink()): ?> - <?php endif ?>
    <?php endforeach ?>
    <?php echo link_to('&gt;', 'company/list?page='.$pager->getNextPage()) ?>
    <?php echo link_to('&raquo;', 'company/list?page='.$pager->getLastPage()) ?>
  <?php endif ?>

That’s it! Now have a play with that, and if you are gaim, you could even go and do some Ajax Pagination or get some sorting going.

  • 17 Comments
  • Filed under: model, plugins, view
  • I don’t like the default symfony ‘down arrow’ to associated with a form error. So I want to make it look a bit more sexy. Here is what you need to do:

    1. Edit your application settings.yml file to overwrite the default ‘down’ arrow. The following settings indicate no prefix or suffix, but a CSS class ‘formerror’ which we will define later:

    all:
      .settings:
        #Form validator style settings
        validation_error_class:     formerror
        validation_error_prefix:    ''
        validation_error_suffix:    ''
        validation_error_id_prefix: error_for_

    2. Find a nice icon to use to display next to a field with an error. For example, I like this one:

    3. Update your CSS file to include a formerror class:

    .formerror{
       padding: 3px 20px 0px;
       background: url(../images/icon_sml_alert.png) no-repeat left bottom;
       color: red;
    }

    4. Now when you use the Symfony form helper to validate a field, it will automatically set the CSS class to ‘formerror’. For example;

    echo form_error('request_type');

    Will print (if the error is triggered)

    <div style="" class="formerror" id="error_for_request_type">Please specify the request type </div>

    So you get something looking a bit nicer than that ‘down’ arrorw:

    Looks hot! - I know you like it, now wipe off that drool on your keyboard and get back to work….