OxyScripts.com
Menu spacer Home Tutorials Articles Code Forums irc.freenode.net #oxyscripts
Main (PHP)
Home Forums PHP News PHP Tutorials Articles PHP Code Snippets Contact Us Sysadmin Resources Books Template Shop
3rd Party Streams
SlashDot PHPDeveloper.org PHP.Net
Resources
PHP Manual MySQL Manual Smarty Manual PEAR Manual PHP-GTK Manual Symfony Manual
Code Snippets
Authentication Database Graphics HTTP Miscellaneous Time/Date
Affiliates
Scripts TutorialMan TutorialGuide CodingForums.com PHP Scripts Cheap Web Hosting Affordable Web Hosting Dreamweaver Templates

Search This Site :     PHP Function Reference :
 

Templating in practice : Link helpers

Overview

One of the common needs in templates is the automation of the URL generation, and the inclusion of local files regardless of the file structure. The link and image helpers, for instance, naturally replace the <a> and <img> tags and do all the tedious jobs for you. Their use is compulsory to enable routing and relative links affected by configuration.

Introduction

The way to call an action with an URL has already been explained: put the module and action names after the front controller, then the parameters of the action either in the classic "GET" style or between /:

http://myapp.example.com/index.php/article/read?title=Finance_in_France
// is equivalent to
http:/myapp.example.com/index.php/article/read/title/Finance_in_France

// additionally, the following works if the routing is deactivated
http://myapp.example.com/index.php?module=article&action=read&title=Finance_in_France

Imagine that you want to add a hyperlink to this page in a template. In PHP, you could be tempted to write:

<a href="/index.php/article/read?title=Finance_in_France">Finance in France</a>

This is a bad idea, because:

  • by writing index.php, you point to a particular environment (in this case, the production environment). All links must be environment-independent if you don't want to accidentally change environment while navigating
  • if you later decide to change the routing policy (you can learn more about this feature in the routing chapter), and to display another format of URL, you would have to parse all of your template files and replace by hand the URLs already entered to URLs like:

      [php]
      <a href="/index.php/articles/europe/france/finance.html">Finance in France</a>
    

If you ever built a website, you know that these problems occur all the time.

The link helpers are there for you. They allow symfony to create URLs and hyperlinks to actions compliant to the routing policy, without any dependence on the environment.

Link helpers

Syntax

The url_for() helper returns an URL, the link_to() helper returns a hyperlink. You may never use the first one, but you will use link_to() a lot.

<?php echo url_for('article/read?title=Finance_in_France') ?>
// will generate in HTML
http://myapp.example.com/index.php/article/read/title/Finance_in_France
 
<?php echo link_to('interesting article', 'article/read?title=Finance_in_France') ?>
// will generate in HTML
<a href="http://myapp.example.com/index.php/article/read/title/Finance_in_France">interesting article</a>

Notice that the default routing rules transform all the ?, = and & characters into /.

Enter in the link helper exactly the same URL as you would have written in a <a href="... tag, and it will transform it for you into a "smart" link according to the current routing policy. And when the customer decides to change some of the rules, just modify the routing.yml configuration file and the generated URL can now look like:

<a href="http://myapp.example.com/articles/europe/france/finance.html">interesting article</a>

Link helpers are the key to a double way routing. Interpreting URLs is not a big deal, but generating them requires that all hyperlink tags pass by the same filter. That's why these helpers are compulsory as soon as you may use the routing feature. Make sure you take a look at the routing chapter to see how to change the shape of URLs, get rid of the controller name or add a '.html' to the generated URLs for more efficient caching and indexing.

Linking an image

Adding a link to an image is as simple as combining two helpers:

<?php echo link_to(image_tag('read.gif'), 'article/read?title=Finance_in_France') ?>
//will generate in html
<a href="/article/read/title/Finance_in_France.html"><img src="/images/read.gif" alt="Read" /></a>

The image_tag helper is described later in this chapter.

Using the rule instead of the module/action

If you had a look at the routing chapter, you saw that the routing is defined by rules. The link helpers accept a rule name instead of a module/action pair if an @ is written before. For instance, if the routing.yml file contains the rule:

cart:
  url: /shopping_cart
  param: { module: shoppingCart, action: index }

Then you can write

<?php echo link_to('go to shopping cart', '@cart') ?>

instead of

<?php echo link_to('go to shopping cart', 'shoppingCart/index') ?>

There are pros and cons to this trick. The advantages are:

  • The routing is done much faster, since symfony doesn't have to browse all the rules to find the one that matches the link. In a page with a great number of routed hyperlinks, the boost will be noticeable if you use rules instead of module/action.
  • Using the rule helps to abstract the logic behind an action. If the need to plug another action behind a given URL arises, then only the routing.yml file will need to be changed - all the link_to() calls will still work without intervention.
  • The logic of the call is more apparent with a rule name. Even if your modules and actions have explicit names, it is often better to call "display_article_by_title" than "article/display".

On the other hand,

  • If you write rules in your link_to(), you can not deactivate the routing anymore.
  • Debugging an application becomes less self-evident since you always need to refer to the routing.yml file to discover which action is called by a link.

The best choice depends on the project. In the long run, it's up to you.

Fake GET and post option

Sometimes, web developers tend to use GET requests to actually do a POST. For instance, consider the following URL:

http://myapp.example.com/index.php/shopping_cart/add?id=100

This request will change the data contained in the application, so it should be considered as a POST.

This URL can be bookmarked, cached and indexed by search engines. Imagine all the nasty things that might happen to the users or to the statistics of a website using this technique.

Symfony provides a way to transform a call to a link_to helper into an actual post. Just write:

<?php echo link_to('go to shopping cart', 'shoppingCart/add?id=100', 'post=true') ?>
// will generate in HTML
<a onclick="f = document.createElement('form'); document.body.appendChild(f); f.method = 'POST'; f.action = this.href; f.submit();return false;" href="/shoppingCart/add/id/100.html">go to shopping cart</a>

This <a> tag has an href attribute, so browsers without javascript support will follow the link doing the default GET. But for those with javascript support, the click on the link will actually do a POST request to the same URL, thanks to a dynamically-generated form in the onclick behavior.

It is a good habit to tag as POST the links that actually post data. Don't hesitate to use this possibility.

Additional options

In addition to the post option, the link_to helper accepts two other options : confirm and popup.

<?php echo link_to('add to cart', 'shoppingCart/add?id=100', 'confirm=Are you sure?') ?>
// will generate in HTML
<a onclick="return confirm('Are you sure?');" href="/fo_dev.php/shoppingCart/add/id/100.html">add to cart</a>
 
<?php echo link_to('add to cart', 'shoppingCart/add?id=100', 'popup=true') ?>
// will generate in HTML
<a onclick="window.open(this.href);return false;" href="/fo_dev.php/shoppingCart/add/id/100.html">add to cart</a>
 
<?php echo link_to('add to cart', 'shoppingCart/add?id=100', Array('popup' => Array('Window title','width=310,height=400,left=320,top=0'))) ?>
// will generate in HTML
<a onclick="window.open(this.href,'Window title','width=310,height=400,left=320,top=0');return false;" href="/fo_dev.php/shoppingCart/add/id/100.html">add to cart</a>

The options can be combined:

<?php echo link_to('add to cart', 'shoppingCart/add?id=100', 'confirm=Are you sure? post=true') ?>
// will generate in HTML
<a onclick="if (confirm('Are you sure?')) { f = document.createElement('form'); document.body.appendChild(f); f.method = 'POST'; f.action = this.href; f.submit(); };return false;" href="/fo_dev.php/shoppingCart/add/id/100.html">add to cart</a>
 
<?php echo link_to('add to cart', 'shoppingCart/add?id=100', 'confirm=Are you sure? popup=true') ?>
// will generate in HTML
<a onclick="if (confirm('Are you sure?')) { window.open(this.href); };return false;" href="/fo_dev.php/shoppingCart/add/id/100.html">add to cart</a>

Forcing GET variables

According to your routing rules, variables passed as parameters to a link_to() are transformed into patterns. The default rule transforms ?key=value into /key/value:

<?php echo link_to('interesting article', 'article/read?title=Finance_in_France') ?>
// will generate in the URL
http://myapp.example.com/index.php/article/read/title/Finance_in_France

But what if you actually need to keep the GET syntax, i.e. to output an url like:

http://myapp.example.com/index.php/article/read?title=Finance_in_France

You should then put the variables that have to be forced outside of the url parameter, in the query_string option:

<?php echo link_to('interesting article', 'article/read', array('query_string' => 'title=Finance_in_France')) ?>

button_to helper

When dealing with forms, you might want to use buttons instead of links. This is where the button_to helper enters:

<?php echo button_to('add to cart', 'shoppingCart/add?id=100') ?>
// will generate in HTML
<input value="add to cart" type="button" onclick="document.location.href='/fo_dev.php/shoppingCart/add/id/100.html';" />

Note that, by default, this button will do a GET request. If you want to do a POST, add the related option:

<?php echo button_to('add to cart', 'shoppingCart/add?id=100', 'post=true') ?>
// will generate in HTML
<form method="post" class="button_to" action="/fo_dev.php/shoppingCart/add/id/100.html"><input value="add to cart" type="submit" /></form>

Beware not to use the POST mode when in a form, since it adds a new <form> tag: you would end up with a form inside another, and the additional button would submit the first form.

As for link_to, the confirm and popup options can be added and combined:

<?php echo button_to('add to cart', 'shoppingCart/add?id=100', 'confirm=Are you sure? popup=true') ?>
// will generate in HTML
<input value="add to cart" type="button" onclick="if (confirm('Are you sure?')) {window.open('/fo_dev.php/shoppingCart/add/id/100.html');}" />

mail_to helper

The reason why symfony ships a mail_to() helper is that nowadays, email harvesting robots prowl about the web, and you can't display an email address on a website without becoming a spam victim within days.

This helper takes three parameters : the actual email address, the string that should be displayed and an array of options. If the third parameter is not set the email address is written non-crypted:

<?php echo mail_to('myaddress@mydomain.com', 'contact address') ?>
// will generate in HTML
<a href="mailto:myaddress@mydomain.com'>contact address</a>
 

If the flag is set to array('encode' => true) the displayed and pointed addresses are processed by a random decimal and hexadecimal entity encoder. This will probably not stop all address-harvesting spambots, but it will keep most of them away. Future versions of this helper will probably evolve as the harvesting techniques become more accurate.

<?php echo mail_to('myaddress@mydomain.com', 'contact address', array('encode' => true)) ?>
// will generate in HTML something like
<a href="&#109;&#x61;&#105;&#108;&#x74;&#x6f;&#58;&#x6d;&#121;&#x61;&#x64;&#x64;&#114;&#101;&#x73;&#115;&#64;&#x6d;&#x79;&#100;o&#x6d;&#97;&#105;&#110;&#46;&#x63;&#111;&#x6d;">&#x63;&#111;&#110;&#x74;&#x61;c&#x74;&#32;&#x61;d&#100;&#114;e&#115;&#x73;</a>

Note: The encoded e-mail address is reverted to human readable text when form repopulation is enabled.

Image helper

Considering that all your HTML pages are handled by actions, the href attribute is not a worry anymore. But what about all those tags having a src attribute? Symfony has image and javascript helpers that are faster to write and do most of the job themselves.

In addition, future versions will support configuration for the default location of media files. This may prove helpful if you decided suddenly to host all of your project media files (css, js, pdf, jpg, gif, etc.) in a new server to increase performance.

To create an <img> tag:

<?php echo image_tag('test') ?>
// will generate in HTML
<img href="/images/test.png" alt="Test" />

By default, the image test.png will be looked for in the /images/ directory of the web server (which is the myproject/web/image/ directory of your file structure, unless you customized it).

If you need to change the default file type or the default location, you can pass a more defined URL:

<?php echo image_tag('test.gif') ?>
// will generate in HTML
<img href="/images/test.gif" alt="Test" />
 
<?php echo image_tag('/my_images/test.gif') ?>
// will generate in HTML
<img href="/my_images/test.gif" alt="Test" />

You can add a second argument to specify additional HTML attributes; this argument must be an array.

<?php echo image_tag('/my_images/test.gif', array('class' => 'shortImage')) ?>
// will generate in HTML
<img href="/my_images/test.gif" alt="Test" class="shortImage"/>

Don't bother to specify a alt attribute if your media file has an explicit name, since symfony will determine it for you.

To fix the size of an image, use the attribute size:

<?php echo image_tag('/my_images/test.gif', array('size' => '100x20')) ?>
// will generate in HTML
<img href="/my_images/test.gif" alt="Test" width="100" height="20"/>

To keep the code readable and let you write templates fast, the options argument can use an abbreviated string syntax:

<?php echo image_tag('/my_images/test.gif', 'size=100x20 alt=My new car class=shortImage onclick=showNextImage(); ') ?>
// is the same as
<?php echo image_tag('/my_images/test.gif', array('size' => '100x20', 'alt' => 'My new car', 'class' => 'shortImage' , 'onclick' => 'showNextImage();') ) ?>
// will generate in HTML
<img href="/my_images/test.gif" alt="My new car" width="100" height="20" class="shortImage" onclick="showNextImage();" />

JavaScript helper

To link to JavaScript files, you can omit the path and the suffix:

<?php echo javascript_include_tag('myscript') ?>
// will generate in HTML
<script language="javascript" type="text/javascript" src="/js/myscript.js">

Once again, the default location can be overridden in a function call for quick needs, or redefined for the whole site in the configuration files for major changes.

If you read the whole documentation, you will see that symfony gives you three different ways to require an additional JavaScript file. You should use them with this order of preference:

  • parameter definition in the view.yml file: Most of the time, the best solution
  • $this->getResponse()->addJavascript() method call from the action: When the name of the files to include depend on calculations made in the action
  • javascript_include_tag() helpers in the template: To include a JavaScript file at a given position inside a template and not in the head.

The last solution is rarely good; if you need it, check whether your code needs some refactoring (for instance write a JavaScript function call in the code and require the script inclusion in the head). However, you sometimes don't have the choice, for instance if you have to include traffic measure scripts at the end of your pages.

Note: You may be looking for a stylesheet_tag() helper, but there is none. If you need to include a custom stylesheet, you should not do it in the template but rather in the view or in the action, as described in the view configuration chapter. This way, the declaration appears in the <head> instead of in the <body>.

Absolute paths

The url and asset helpers generate relative paths by default. You can easily add an absolute=true parameter to force the output to absolute paths, for instance for inclusions of links in an email, a RSS feed, or an API response.

<?php echo url_for('module/action', true) ?>
<?php echo link_to('my link', 'module/action', 'absolute=true') ?>
<?php echo image_tag('test', 'absolute=true') ?>
<?php echo javascript_include_tag('myscript', 'absolute=true') ?>
 
   Print this page

Top Sponsor
Symantec\'s Norton SystemWorks 2006
Sponsors
CA
Sponsors
AdWords Dominator 125*125
Advertisting

Affiliates
VertexTemplates PHPFreaks CodeWalkers StarGeek DevScripts CGI & PHP Scripts PHP CMS

Shopping Rebates   Sell It 4 You   Flash Page Counters   Get Insured
GPS Tracking Service   Charity Donate Info   Web Site Hosting   VOIP Service

Privacy Policy | Links | Site Map | Advertising

All content on OxyScripts.com is (©)2002-2007

 
Powered by Adrastea - Version 1.0.0. Copyright © Rune Solutions, 2004-2005