Friendly URLs (3.1.1 and above)
From PRADO Wiki
Contents |
Search Engine Friendly URLs
Creating SEF urls in Prado is very simple once you know how to do it. The documentation is horrible because it's going to assume you already know Prado. This simple guide will hopefully fill in the gaps. You can refer to the documentation for more information and more examples of url mapping with regular expressions. http://www.pradosoft.com/demos/quickstart/?page=Configurations.UrlMapping
The type of urls this guide creates (no index.php)...
http://www.mysite.com/my-home-page
http://www.mysite.com/product/35
1. Add the following code to your .htaccess file
This will allow for the removal of index.php
Options +FollowSymLinks
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php/$1 [L]
2. Modify application.xml
Add the following to the modules section of protected/application.xml
<module id="request" class="THttpRequest" UrlManager="friendly-url" />
<module id="friendly-url" class="System.Web.TUrlMapping" EnableCustomUrl="true" UrlPrefix="/" >
<!-- example url map -->
<!-- For more info: http://www.pradosoft.com/demos/quickstart/?page=Configurations.UrlMapping -->
<url ServiceParameter="Home" pattern="my-home-page" />
<url ServiceParameter="ViewProductDetails" pattern="product/{id}" parameters.id="\d+" />
</module>
Some explaination of EnableCustomUrl="true" and UrlPrefix="/"...
EnableCustomUrl="true"
This means let Prado use your url map in the urls that get automatically generated by constructUrl.
UrlPrefix="/"
This removes index.php. If you installed your prado app in a subdirectory you'll want to change this to UrlPrefix="/mysubdirectory" replace "mysubdirectory" with your installation subdirectory.
3. Always use $this->Service->constructUrl()
Use $this->Service->constructUrl() everywhere in your appliation to create links.
Example:
<a href="<%# $this->Service->constructUrl('ViewProductDetails',array('id'=>$this->Data->product_id,'title'=>$this->Data->product_title)) %>">My Product Link</a>
if you have followed the steps above the constructUrl outputs...
<a href="/product/32">My Product Link</a>
Extracting culture from URL
With some additions you can go even further. Many sites for example use a URL suffix to direct the user to different language versions of the site like this
http://www.mysite.com/en
http://www.mysite.com/de
With the following guide you'll be able to fetch the culture info from the URL and still use friendly URLs. Suppose your application is in directory somepath. Your application will then recognize URLs of these formats:
http://www.mysite.com/somepath/
Shows DefaultPage with DefaultCulture
http://www.mysite.com/somepath/en
Shows DefaultPage with Culture=en
http://www.mysite.com/somepath/en?page=XY
Shows page XY Culture=en
http://www.mysite.com/somepath/en/my-home-page
Shows UrlMapped my-home-page with Culture=en
http://www.mysite.com/somepath/en/my-home-page?a=x
Like before but with additional Request parameters
http://www.mysite.com/somepath/en/category/47
Shows UrlMapped category 47 with Culture=en
http://www.mysite.com/somepath/en/category/47?a=x
Like before but with additional Request parameters
1. Add two files to your application
You can put these files into the protected/controls directory.
controls/GlobalizationUrlDetect.php
This class automatically sets the culture by a request parameter culture.
<?php /** * GlobalizationUrlDetect class will resolve the * default culture from URL parameter "culture=" * */ class GlobalizationUrlDetect extends TGlobalization { private $_detectedLanguage; public function init($xml) { parent::init($xml); $this->getApplication()->attachEventHandler('OnBeginRequest', array($this,'OnBeginRequest')); } /** * $this->Request isn't resolved yet when this component is initialized. * So we wait until the application fires the BeginRequest event. */ public function OnBeginRequest($param) { //set the culture according to request parameter "culture" if ($culture=$this->getRequest()->itemAt('culture')) { $this->_detectedLanguage=$culture; $this->setCulture($culture); } } public function getDetectedLanguage() { return $this->_detectedLanguage; } } ?>
controls/CultureMapping.php
This class will become our TUrlMappingPattern replacement. It makes sure the culture info gets included into all URLs created with constructURL().
<?php class CultureMapping extends TUrlMappingPattern { // Store UrlMappings UrlPrefix private $_prefix; public function init($config) { $this->_prefix=$this->getManager()->getUrlPrefix(); } /** * constructUrl * * Inject culture info into UrlPrefix of TUrlMapping * */ public function constructUrl($getItems,$encodeAmpersand,$encodeGetItems) { $culture=$this->getManager()->getApplication()->getGlobalization()->getCulture(); $this->getManager()->setUrlPrefix($this->_prefix.'/'.$culture); return parent::constructUrl($getItems,$encodeAmpersand,$encodeGetItems); } } ?>
2. Modify application.xml
In addition to the rules above for friendly URLs we need some more tweaks. We add a module for globalization and we configure our own MappingPattern class. We also use an additional alias to keep things a little cleaner.
<!-- Add this to your paths section. path should match the path where you put the above files --> <paths> ... <alias id="ctrl" path="controls" </paths> <!-- Use our custom globalization class to set culture according to URL parameter --> <module id="globalization" class="Application.controls.GlobalizationUrlDetect" DefaultCharset="UTF-8" DefaultCulture="de"> <!-- Translation --> <translation type="XLIFF" source="Application.languages" autosave="true" marker="@@" cache="true" /> </module> <!-- URL mapping --> <module id="request" class="THttpRequest" UrlManager="friendly-url" /> <module id="friendly-url" class="System.Web.TUrlMapping" EnableCustomUrl="true" UrlPrefix="/vat-eu" > <!-- Always use our own mapping class --> <url class="ctrl.CultureMapping" ServiceParameter="Home" pattern="home" /> <url class="ctrl.CultureMapping" ServiceParameter="Test" pattern="test" /> <url class="ctrl.CultureMapping" ServiceParameter="ViewProductDetails" pattern="product/{id}" parameters.id="\d+" /> </module>
3. Modify your .htaccess
Like above we need mod_rewrite for this. Put this into your .htaccess file (replacing the configuration above if necessary!)
RewriteEngine On # If your application is installed in a subdirectory of your # webroot and gets accessed like this: # # http://example.com/path/to/index.php # # and you get "Bad Request" errors, try to uncomment this line # and change the path accordingly: # #RewriteBase /path/to # # /path -> /path/index.php # /path/de -> /path/index.php?culture=de # /path/de?a=x -> /path/index.php?culture=de&a=x # /path/de/my-home-page -> /path/index.php/my-home-page?culture=de # /path/de/my-home-page?a=x -> /path/index.php/my-home-page?culture=de&a=x # /path/de/category/47?a=x -> /path/index.php/category/47?culture=de&a=x # # Don't apply for really existing files/directories RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{QUERY_STRING} \??(.*) RewriteRule ^([^/]*)(.*)$ index.php$2?culture=$1&%1 [L]

