CNC router for Zend Framework and caching
Task:
To handle URLs of the form:
/ > www. example.com/what/about-this-2010-09-08.html
given the parameters in, for example, this pattern:
[module]/[controller]-[action]-[year]-[month]-[day].[ext]
How did the task.
ZF, in addition to its versatility, also has a decent heaviness, and it is quite logical.
Therefore, when generating any content I try to apply caching to reduce the frequency of such generations.
Cache blocks, pages, object model, database queries — all that you can.
Pages that do not allow the active content changes to better cache entirely. And of those, oddly enough, is a lot.
This created a Zend_Cache_Frontend_Page. The first time I have he has not earned, though not at all complicated. And instead of getting HADNT, I decided that such pages can be given without the participation of PHP, just like .html file.
Not to overextend .htacess complex rules, the folder structure will match queries, and Vice versa.
It is also desirable that the requests were humanized and not too long.
URLs:
the
file structure:
the
It remains only to specify ranting for such URLs, capture ob_start() the output for specific controllers / actions and save to the folder _cache
Here Zend offers a powerful tool Zend_Controller_Router_Route_Regex.
But the remedy is a little more than NOT readable. And even reverse and map to boot.
Wrote.
Provide a template url through routes.ini
[module]/[controller]/{action} {page}.htm
the
this route is suitable for queries of the form:
the
In square brackets the required parameters is [param_name]
in figure — optional {my_param}
Non-alphabetical characters inside the brackets in addition to the ID may be needed for:
separation parameters [action]{-page} if not specified any of the characters* consist therein
if url e need these brackets
the
To pass a variable number of parameters I reserved identifier {paramstr},
It includes not expressly granted options.
For example, for the route:
[section]/{action}{~paramstr}.html
the
fit request
/car/view~year[2001~2003]fuel[diesel]color[blue~red]vol[1000~1600]state[good]place[mosque].html
and in the controller Test_CatalogController
we get all the parameters:
the
And back if to pass to the view helper these settings will generate the appropriate url.
the
1. As in Zend_Controller_Router_Route_Regex, you can use templates .reqs for each parameter
the
2. As shown above, the parameters {paramstr} are transmitted in the format key1[value1~value2]key2[value1~value2~value3]
This format can be changed in the classroom
the
The class workable, but not perfect.
In the future it can be corrected, to get rid of excess preg_match inherit from Regex, but from the Abstract
This class complements sendowski ranting, so for standard cases it is better to use standard tools. But if you love yourself to write regular expressions for URLs, it is generally better not to use this class.
Article based on information from habrahabr.ru
To handle URLs of the form:
/ > www. example.com/what/about-this-2010-09-08.html
given the parameters in, for example, this pattern:
[module]/[controller]-[action]-[year]-[month]-[day].[ext]
How did the task.
1. Need to cache static and rekomendacia page in ZF
ZF, in addition to its versatility, also has a decent heaviness, and it is quite logical.
Therefore, when generating any content I try to apply caching to reduce the frequency of such generations.
Cache blocks, pages, object model, database queries — all that you can.
2. To give the pages generated .html, without any PHP involvement
Pages that do not allow the active content changes to better cache entirely. And of those, oddly enough, is a lot.
This created a Zend_Cache_Frontend_Page. The first time I have he has not earned, though not at all complicated. And instead of getting HADNT, I decided that such pages can be given without the participation of PHP, just like .html file.
Not to overextend .htacess complex rules, the folder structure will match queries, and Vice versa.
It is also desirable that the requests were humanized and not too long.
URLs:
the
/what/about/this.html /what/about/other-12.html /it/computing_games~page1.html /it/computing_games~page1.html
file structure:
the
_cache/what/about/this.html /other-12.html _cache/it/computing_games~page1.html /computing_games~page2.html
It remains only to specify ranting for such URLs, capture ob_start() the output for specific controllers / actions and save to the folder _cache
3. Ask for the ZF routes other than the standard
Here Zend offers a powerful tool Zend_Controller_Router_Route_Regex.
But the remedy is a little more than NOT readable. And even reverse and map to boot.
4. Write your class that handles
Wrote.
class EXT_Controller_Router extends Zend_Controller_Router_Route_Regex
{
protected $_defaultReqs = "\w+";
protected $_paramStrFormat = "name[value]";
protected $_paramStrValueGlue = "~";
//protected $_paramStrFormat = "name-value";
//protected $_paramStrValueGlue = "!";
protected $_regex = null;
protected $_route = null;
protected $_insides = array();
protected $_quotes = array();
protected $_defaults = array();
protected $_values = array();
protected $_map = array();
protected $_reqs = array();
/**
* @param Zend_Config $config Configuration object
*/
public static function getInstance(Zend_Config $config)
{
$defaults = ($config->defaults instanceof Zend_Config) ? $config->defaults->toArray() : array();
$reqs = ($config->reqs instanceof Zend_Config) ? $config->reqs->toArray() : array();
}
public function __construct($route, $defaults = array(), $reqs = array())
{
$a = "(\[.*\])";
$b = "(\{.*\})";
$pattern = "#(.*)(" . $a . "|" . $b . ")#Ui";
$this->_quotes = array();
$this->_insides = array();
$map = array();
$regex = ";
if (preg_match_all($pattern, $route, $matches, PREG_SET_ORDER)) {
foreach ($matches as $i => $match) {
$inside = substr($match[2], 1, strlen($match[2])-2);
$key = preg_replace('[\W]', ", $inside);
if (!empty($reqs[$key])) {
$reg = $reqs[$key];
} elseif ('paramstr' == $key) {
$reg = '.*';
} else {
$reg = $this->_defaultReqs;
}
switch ($match[2][0]) {
case '[':
$end = ";
break;
case '{':
$end = '{0,1}';
break;
$regex .= preg_quote($match[1], '#') . '(' . str_replace($key, $reg, preg_quote($inside, '#')) . ')' . $end;
$map[$key] = $i+1;
$this->_quotes[$key] = $match[2][0];
$this->_insides[$key] = $inside;
}
}
preg_match("#[^\]\}]*$#i", $route, $lostMatch);
$regex .= preg_quote($lostMatch[0], '#');
$this->_route = $route;
$this->_regex = $regex;
$this->_defaults = (array) $defaults;
$this->_map = $map;
$this->_reqs = $reqs;
}
/**
* Matches a user submitted path with a previously defined route.
* Assigns and returns an array of defaults on a successful match.
*
* @param string $path Path used to match against this routing map
* @return array|false An array of assigned values or a false on a mismatch.
*/
public function match($path, $partial = false)
{
$path = trim(urldecode($path), '/');
$regex = '#^' . $this->_regex . '$#Ui';
$res = preg_match($regex, $path, $values);
if ($res === 0) {
return false;
}
foreach ($values as $i => $value) {
if (!is_int($i) || $i === 0 || empty($value)) {
}
}
$values = $this->_getMappedValues($values);
foreach ($this->_insides as $name => $ins) {
if ($name !== $ins && isset($values[$name])) {
$pattern = '#^' . str_replace($name, '(.*)', preg_quote($ins)) . '$#i';
if (preg_match($pattern, $values[$name], $matches)) {
$values[$name] = $matches[1];
}
}
}
if (!empty($values['paramstr'])) {
$values += $this->explodeParamStr($values['paramstr']);
}
$this->_values = $values;
$defaults = $this->_getMappedValues($this->_defaults, false, true);
$result = $values + $defaults;
return $result;
}
public function explodeParamStr($paramStr)
{
$values = array();
$pattern = str_replace(array('name', 'value'),
array('(\w+)', '(.*)'),
preg_quote($this->_paramStrFormat, '#'));
$pattern = '#(' . $pattern . ')#Uui';
if (preg_match_all($pattern, $paramStr, $matches, PREG_SET_ORDER)) {
if (!empty($match[3]))
$value = explode($this->_paramStrValueGlue, $match[3]);
if (count($value) > 1) {
$values[$match[2]] = $value;
} else {
$values[$match[2]] = $match[3];
}
}
}
return $values;
}
public function implodeParamStr(array $params)
{
$paramStr = ";
foreach($params as $name => $value) {
if (!in_array($name, array('controller', 'module', 'paramstr', 'action')) && !array_key_exists($name, $this->_map)) {
if (is_array($value)) {
$value = implode($this->_paramStrValueGlue, $value);
}
$paramStr .= str_replace(array('name', 'value'),
array($name, $value),
$this->_paramStrFormat);
}
}
if (empty($paramStr)) {
$paramStr = null;
}
return $paramStr;
}
/**
* Assembles a URL path defined by this route.
*
* @param array $data An array of name (or index) and value pairs used as parameters
*/
public function assemble($data = array(), $reset = false, $encode = false, $partial = false)
{
$replaces = array();
$searches = array();
$paramStr = $this->implodeParamStr($data);
$data = $data + $this->_values;
if (empty($paramStr)) {
unset($data['paramstr']);
} else {
$data['paramstr'] = $paramStr;
}
foreach($this->_map as $key => $i) {
$inside = $this->_insides[$key];
switch ($this->_quotes[$key]) {
case '[':
$searches[$i] = '[' . $inside . ']';
break;
case '{':
$searches[$i] = '{' . $inside . '}';
break;
default:
break;
}
if (!empty($data[$key])) {
$replaces[$i] = str_ireplace($key, $data[$key], $inside);
} else {
$replaces[$i] = ";
}
}
$url = str_replace($searches, $replaces, $this->_route);
}
}
Usage
Provide a template url through routes.ini
[module]/[controller]/{action} {page}.htm
the
my-route.type = "EXT_Controller_Router" my-route.route = "[module]/[controller]/{action} {page}.htm" my-route.defaults.action = index
this route is suitable for queries of the form:
the
www.notmysite.ru/what/about/this.html www.notmysite.ru/what/about/other-12.html
In square brackets the required parameters is [param_name]
in figure — optional {my_param}
Non-alphabetical characters inside the brackets in addition to the ID may be needed for:
separation parameters [action]{-page} if not specified any of the characters* consist therein
if url e need these brackets
www.notmysite.ru/dogovor[123e][12].htm, then the route is specified like [controller][[tom]][[page]].htm
the
dogovor.route = "[controller][[tom]][[page]].htm" dogovor.defaults.module = index dogovor.defaults.controller = dogovor dogovor.defaults.action = show
Magic [paramstr]
To pass a variable number of parameters I reserved identifier {paramstr},
It includes not expressly granted options.
For example, for the route:
[section]/{action}{~paramstr}.html
the
car.type = "EXT_Controller_Router" car.route = "[section]/{action}{~paramstr}.html" car.defaults.module = car car.defaults.controller = catalog
fit request
/car/view~year[2001~2003]fuel[diesel]color[blue~red]vol[1000~1600]state[good]place[mosque].html
and in the controller Test_CatalogController
we get all the parameters:
the
'section' => 'car' 'action' => 'view' 'paramstr' => 'year' [2001~2003]fuel[diesel]color[blue-red]vol[1000~1600]state[good]place[Moscow]' 'letter' => 'l' 'year' 0 => '2001' 1 => '2003' 'fuel' => 'diesel' 'color' 0 => 'blue' 1 => 'red' 'vol' 0 => '1000' 1 => '1600' 'state' => 'good' 'place' => 'Moscow' 'module' => 'test' 'controller' => 'index'
And back if to pass to the view helper these settings will generate the appropriate url.
the
$params = array('action' => 'view', 'step' => 2, 'year' => array('2009', '2010')); $nextUrl = $this->view->url($params, 'my-route');
Details
1. As in Zend_Controller_Router_Route_Regex, you can use templates .reqs for each parameter
the
for example, "a limited set of values": my-route.reqs.action = "index|view|print" or "only numbers": my-route.reqs.action = "\d+"
2. As shown above, the parameters {paramstr} are transmitted in the format key1[value1~value2]key2[value1~value2~value3]
This format can be changed in the classroom
the
protected $_paramStrFormat = "name[value]"; protected $_paramStrValueGlue = "~";
Important
The class workable, but not perfect.
In the future it can be corrected, to get rid of excess preg_match inherit from Regex, but from the Abstract
This class complements sendowski ranting, so for standard cases it is better to use standard tools. But if you love yourself to write regular expressions for URLs, it is generally better not to use this class.
Комментарии
Отправить комментарий