Yii URL Manger create a route with multi optional parameters - php

I have a URL rule with multiple optional parameters and it was working but it stopped after I upgraded from Yii 1.1.15 to 1.1.19.
const OPTIONAL_PARAMS = '(/<featured:featured>)?'
. '(/subType/<subType:.*?>)?'
. '(/type/<type:\d+>)?'
. '(/category/<category:.*>)?';
'<lang:(en|fr)>/reports'. OPTIONAL_PARAMS => 'reports',
Any one can provide me some ideas or someone faced similar issues?
P.S. The other URL manager rules are working fine, only this one with (SOME_CODE)? for optional params is not working. I'm using PHP 5.6 and Apache.

You may be interested in by this issue. But in short: this syntax (regexp outside of named params) was never officially supported and it was removed as a bugfix in Yii 1.1.17.
The last version which supports this is 1.1.16, but it is really old and I would not recommend using it. You should probably create custom UrlRule and use it instead of CUrlRule for this particular case.
You may also try to add /* at the end of the pattern, like this:
'<lang:(en|fr)>/reports/*' => 'reports',
This will allow to append GET params to URL as /key/value. So this:
$this->createUrl('reports', [
'type' => 'sometype',
'category' => 'somecategory',
'lang' => 'en',
]);
will create URL like:
/en/reports/type/sometype/category/somecategory

Related

Yii URL rewriting

I want to rewrite my url in YII to make url seo friendly .
The URL in my current system is
http://mysite/recipe/recipedetail/1
and i want to make it like
http://mysite/recipename
how i can do it
i am trying ot use rule but they are not working my rules in config/main files are
'url.rules' => array(
'recipe/<recipename:([A-Za-z0-9-]+)>/' => 'recipe/recipedetail/<recipename:\w+>/',
),
You may try this:
'recipe/recipedetail/<id:\d+>'=>'recipe/recipedetail',
A route part of rule must not contain parameters, but must be in controller/action format:
'url.rules' => array(
'recipe/<recipename:[A-Za-z0-9-]+>/' => 'recipe/recipedetail',
),
All named parameters will be available in $_GET, so inside your controller action you can access recipename value with $_GET['recipename]`.
Additionaly, please mention that you must not wrap parameter pattern ([A-Za-z0-9-]+ in your case) in brackets.
I guess you're missing var_name in your url
'recipe/<recipename:([A-Za-z0-9-]+)>/' => 'recipe/recipedetail/var_name/<recipename:\w+>/'
get the recipename inside your controller using var_name

Zend Framework: How to assemble proper url when in directory

How can I force Zend Router to assemble proper urls when the site is running under a directory?
Here's what I mean:
$this->view->url(array('controller' => 'controller', 'action' => 'action'), null, true)
Would usually return something like /controller/action where in my case it returns /tbogdanov/brandenburg/controller/action, because the site is running in the directory /tbogdanov/brandenburg.
That is actually a good URL and I have no problem with it. However, when passed to $this->_redirect() the redirector just prepends the directory again. So, the final redirect url now looks like this: /tbogdanov/brandenburg/tbogdanov/brandenburg/controller/action.
Now, that's incorrect.
Is there any setting I might be missing? It seems zend is aware it is running in a directory/sub-directory, but still at some point, it ignores it. I am looking for a good generalized solution, no str_replace ones!
Also the method should work properly even if at some point the project is moved in the root directory (which will happen).
The second parameter of _redirect() configures the options. Add array('prependBase' => false) and try again.
try using a redirector object where you have more options for the link creation
http://framework.zend.com/manual/1.12/en/zend.controller.actionhelpers.html#zend.controller.actionhelpers.redirector
// Redirect to 'my-action' of 'my-controller' in the current
// module, using the params param1 => test and param2 => test2
$this->_redirector->gotoSimple('my-action',
'my-controller',
null,
array('param1' => 'test',
'param2' => 'test2'
)
);

Define a singular rule in the bootstrap for Inflector

I'm using CakePHP 2.1 and need to define an Inflector rule for the word "Software", because CakePHP is converting all references to the plural form "Softwares" which isn't correct. Cake is looking for SoftwaresController and a table named Softwares.
I do know to create the rule in the boot strap, and read this doc reference.
http://book.cakephp.org/2.0/en/development/configuration.html#inflection-configuration
I also took a look at the lib/Cake/Inflector.php file, but can't figure out the syntax for defining a rule. It looks kind of like regex. Here are a few rule examples.
'/(s)tatus$/i' => '\1\2tatuses',
'/(quiz)$/i' => '\1zes',
'/^(ox)$/i' => '\1\2en',
'/([m|l])ouse$/i' => '\1ice',
'/(matr|vert|ind)(ix|ex)$/i' => '\1ices',
'/(x|ch|ss|sh)$/i' => '\1es',
What would be the correct code to define a Software singular Inflector rule?
EDIT:
Inflector::rules('singular', array('rules'=>array('/software/'=>'software'),'irregular'=>array('software'=>'software'),'uninflected'=>array('software')));
I tried adding this rule, which works for the SoftwareController but Cake is complaining that it can't find the Softwares table, which is actually named "Software". I feel I'm close, but still missing something about how this works.
you just have to know where to look (or search) in the book:
http://book.cakephp.org/2.0/en/development/configuration.html#inflection-configuration
in your case
Inflector::rules('singular', array(
'uninflected' => array('software')
));
Inflector::rules('plural', array(
'uninflected' => array('software')
));

cakephp choosing language by url

what I am trying to achieve is described here http://nuts-and-bolts-of-cakephp.com/2008/11/28/cakephp-url-based-language-switching-for-i18n-and-l10n-internationalization-and-localization/
but I can not get it working.
The router configurations looks like this:
Router::connect('/registered/:language/:controller/:action/*',
array('prefix' => 'registered', 'registered' => true, 'layout'=> 'registered'),
array('language' => '[a-z]{3}'));
butw when I try to go to www.example.com/registered/cze/packages I get:
Error: CzeController could not be found.
I am using cake 1.3, not 1.2 as the author, that may be the problem, but what do I need to change in order for this to work?
Edit:
$this->Session->write('Config.language','cze');
This code works and when used in the controller changes the language of the site, but I need to get it working according to the URL
The URL www.example.com/registered/cze/packages does not match the route /registered/:language/:controller/:action/*, since the :action segment is empty. Therefore, the URL falls through to the standard route, where registered is recognized as the prefix and cze as the controller.
You'll need to create a "shorter" /registered/:language/:controller route as well to catch "abbreviated" URLs.

PHP Application URL Routing

So I'm writing a framework on which I want to base a few apps that I'm working on (the framework is there so I have an environment to work with, and a system that will let me, for example, use a single sign-on)
I want to make this framework, and the apps it has use a Resource Oriented Architecture.
Now, I want to create a URL routing class that is expandable by APP writers (and possibly also by CMS App users, but that's WAYYYY ahead in the future) and I'm trying to figure out the best way to do it by looking at how other apps do it.
I prefer to use reg ex over making my own format since it is common knowledge. I wrote a small class that I use which allows me to nest these reg ex routing tables. I use to use something similar that was implemented by inheritance but it didn't need inheritance so I rewrote it.
I do a reg ex on a key and map to my own control string. Take the below example. I visit /api/related/joe and my router class creates a new object ApiController and calls it's method relatedDocuments(array('tags' => 'joe'));
// the 12 strips the subdirectory my app is running in
$index = urldecode(substr($_SERVER["REQUEST_URI"], 12));
Route::process($index, array(
"#^api/related/(.*)$#Di" => "ApiController/relatedDocuments/tags",
"#^thread/(.*)/post$#Di" => "ThreadController/post/title",
"#^thread/(.*)/reply$#Di" => "ThreadController/reply/title",
"#^thread/(.*)$#Di" => "ThreadController/thread/title",
"#^ajax/tag/(.*)/(.*)$#Di" => "TagController/add/id/tags",
"#^ajax/reply/(.*)/post$#Di"=> "ThreadController/ajaxPost/id",
"#^ajax/reply/(.*)$#Di" => "ArticleController/newReply/id",
"#^ajax/toggle/(.*)$#Di" => "ApiController/toggle/toggle",
"#^$#Di" => "HomeController",
));
In order to keep errors down and simplicity up you can subdivide your table. This way you can put the routing table into the class that it controls. Taking the above example you can combine the three thread calls into a single one.
Route::process($index, array(
"#^api/related/(.*)$#Di" => "ApiController/relatedDocuments/tags",
"#^thread/(.*)$#Di" => "ThreadController/route/uri",
"#^ajax/tag/(.*)/(.*)$#Di" => "TagController/add/id/tags",
"#^ajax/reply/(.*)/post$#Di"=> "ThreadController/ajaxPost/id",
"#^ajax/reply/(.*)$#Di" => "ArticleController/newReply/id",
"#^ajax/toggle/(.*)$#Di" => "ApiController/toggle/toggle",
"#^$#Di" => "HomeController",
));
Then you define ThreadController::route to be like this.
function route($args) {
Route::process($args['uri'], array(
"#^(.*)/post$#Di" => "ThreadController/post/title",
"#^(.*)/reply$#Di" => "ThreadController/reply/title",
"#^(.*)$#Di" => "ThreadController/thread/title",
));
}
Also you can define whatever defaults you want for your routing string on the right. Just don't forget to document them or you will confuse people. I'm currently calling index if you don't include a function name on the right. Here is my current code. You may want to change it to handle errors how you like and or default actions.
Yet another framework? -- anyway...
The trick is with routing is to pass it all over to your routing controller.
You'd probably want to use something similar to what I've documented here:
http://www.hm2k.com/posts/friendly-urls
The second solution allows you to use URLs similar to Zend Framework.
Use a list of Regexs to match which object I should be using
For example
^/users/[\w-]+/bookmarks/(.+)/$
^/users/[\w-]+/bookmarks/$
^/users/[\w-]+/$
Pros: Nice and simple, lets me define routes directly
Cons: Would have to be ordered, not making it easy to add new things in (very error prone)
This is, afaik, how Django does it
I think a lot of frameworks use a combination of Apache's mod_rewrite and a front controller. With mod_rewrite, you can turn a URL like this: /people/get/3 into this:
index.php?controller=people&method=get&id=3. Index.php would implement your front controller which routes the page request based on the parameters given.
As you might expect, there are a lot of ways to do it.
For example, in Slim Framework , an example of the routing engine may be the folllowing (based on the pattern ${OBJECT}->${REQUEST METHOD}(${PATTERM}, ${CALLBACK}) ):
$app->get("/Home", function() {
print('Welcome to the home page');
}
$app->get('/Profile/:memberName', function($memberName) {
print( 'I\'m viewing ' . $memberName . '\'s profile.' );
}
$app->post('/ContactUs', function() {
print( 'This action will be fired only if a POST request will occure');
}
So, the initialized instance ($app) gets a method per request method (e.g. get, post, put, delete etc.) and gets a route as the first parameter and callback as the second.
The route can get tokens - which is "variable" that will change at runtime based on some data (such as member name, article id, organization location name or whatever - you know, just like in every routing controller).
Personally, I do like this way but I don't think it will be flexible enough for an advanced framework.
Since I'm working currently with ZF and Yii, I do have an example of a router I've created as part of a framework to a company I'm working for:
The route engine is based on regex (similar to #gradbot's one) but got a two-way conversation, so if a client of yours can't run mod_rewrite (in Apache) or add rewrite rules on his or her server, he or she can still use the traditional URLs with query string.
The file contains an array, each of it, each item is similar to this example:
$_FURLTEMPLATES['login'] = array(
'i' => array( // Input - how the router parse an incomming path into query string params
'pattern' => '#Members/Login/?#i',
'matches' => array( 'Application' => 'Members', 'Module' => 'Login' ),
),
'o' => array( // Output - how the router parse a query string into a route
'#Application=Members(&|&)Module=Login/?#' => 'Members/Login/'
)
);
You can also use more complex combinations, such as:
$_FURLTEMPLATES['article'] = array(
'i' => array(
'pattern' => '#CMS/Articles/([\d]+)/?#i',
'matches' => array( 'Application' => "CMS",
'Module' => 'Articles',
'Sector' => 'showArticle',
'ArticleID' => '$1' ),
),
'o' => array(
'#Application=CMS(&|&)Module=Articles(&|&)Sector=showArticle(&|&)ArticleID=([\d]+)#' => 'CMS/Articles/$4'
)
);
The bottom line, as I think, is that the possibilities are endless, it just depend on how complex you wish your framework to be and what you wish to do with it.
If it is, for example, just intended to be a web service or simple website wrapper - just go with Slim framework's style of writing - very easy and good-looking code.
However, if you wish to develop complex sites using it, I think regex is the solution.
Good luck! :)
You should check out Pux https://github.com/c9s/Pux
Here is the synopsis
<?php
require 'vendor/autoload.php'; // use PCRE patterns you need Pux\PatternCompiler class.
use Pux\Executor;
class ProductController {
public function listAction() {
return 'product list';
}
public function itemAction($id) {
return "product $id";
}
}
$mux = new Pux\Mux;
$mux->any('/product', ['ProductController','listAction']);
$mux->get('/product/:id', ['ProductController','itemAction'] , [
'require' => [ 'id' => '\d+', ],
'default' => [ 'id' => '1', ]
]);
$mux->post('/product/:id', ['ProductController','updateAction'] , [
'require' => [ 'id' => '\d+', ],
'default' => [ 'id' => '1', ]
]);
$mux->delete('/product/:id', ['ProductController','deleteAction'] , [
'require' => [ 'id' => '\d+', ],
'default' => [ 'id' => '1', ]
]);
$route = $mux->dispatch('/product/1');
Executor::execute($route);
Zend's MVC framework by default uses a structure like
/router/controller/action/key1/value1/key2/value2
where router is the router file (mapped via mod_rewrite, controller is from a controller action handler which is defined by a class that derives from Zend_Controller_Action and action references a method in the controller, named actionAction. The key/value pairs can go in any order and are available to the action method as an associative array.
I've used something similar in the past in my own code, and so far it's worked fairly well.
Try taking look at MVC pattern.
Zend Framework uses it for example, but also CakePHP, CodeIgniter, ...
Me personally don't like the MVC model, but it's most of the time implemented as "View for web" component.
The decision pretty much depends on preference...

Categories