CakePHP:嵌套URL
我想使用页面的slug路径作为URL(即:/products/steros/stereo-1/info-这直接遵循数据库中页面的树结构:info是stereo-1的子级,stereo-1是steros的子级,等等)。(所有内容都将通过页面控制器进行管理) 我的一个想法是这样做:CakePHP:嵌套URL,cakephp,Cakephp,我想使用页面的slug路径作为URL(即:/products/steros/stereo-1/info-这直接遵循数据库中页面的树结构:info是stereo-1的子级,stereo-1是steros的子级,等等)。(所有内容都将通过页面控制器进行管理) 我的一个想法是这样做: // routes: (code found on another thread): Router::connect('/:site/:language/:row:lastslash',array( 'contr
// routes: (code found on another thread):
Router::connect('/:site/:language/:row:lastslash',array(
'controller' => 'posts', 'action' => 'parseURL',),
array(
'pass'=>array('row'),
'row'=>'.*?',
'lastslash'=>'\/?'
)
);
Router::connect('/content/about-us', array(
'plugin' => 'content',
'controller' => 'content',
'action' => 'view',
16));
/**
* afterSave Callback
* Creates a new SEO record if required
*
* @param Model $model Model the callback is called on
* @param boolean $created Whether or not the save created a record.
* @return void
*/
public function afterSave(Model $model, $created) {
$modelPrimaryKey = $model->id;
// See if we already have an SEO record for this model record
$seoDetails = $this->seoModel->find(
'first',
array(
'conditions' => array(
'Seo.plugin' => $this->settings[$model->alias]['plugin'],
'Seo.model' => $model->name,
'Seo.foreign_key' => $modelPrimaryKey
)
)
);
if(empty($seoDetails)){
$modelData = $model->read(null, $modelPrimaryKey);
$slug = $model->getSlug($modelData[$model->alias]);
$title = $model->getDisplayName($modelData[$model->alias]);
$seoData = array(
$this->seoModel->alias => array(
'model' => $model->name,
'plugin' => $this->settings[$model->alias]['plugin'],
'foreign_key' => $model->id,
'action' => 'view',
'request_uri' => '/' . Inflector::underscore($model->name) . '/' . $slug,
'title' => $title,
'seo_attribute_type_id' => $this->defaultAttributeTypeId
)
);
// Create some default meta tags as well
$seoData['SeoMeta'] = array(
0 => array(
'key' => 'keywords',
'value' => ''
),
1 => array(
'key' => 'description',
'value' => ''
)
);
$this->seoModel->create();
$this->seoModel->saveAll($seoData);
$id = $this->seoModel->id;
}
}
这会将我转发到parseURL,URL的其余部分在$row中。在parseURL中,我可以找到实际的post id(通过使用slug路径),获取指定操作的db字段,然后转发到那里。理论上,系统应该处理数据库中的任何url树路径。例如:
/page1/page2/page3/info/thisPage-parseURL将遍历url的每个部分,以查找“thisPage”的帖子ID“thisPage”将有一个“action”字段,指定要使用的操作,parseURL将重定向到该字段
有没有更好的方法来处理这个问题 这是一个棘手的问题
我这样做的方式是在/app/tmp/cache/SEO_routes.php中创建一个SEO路由文件,该文件会在每个请求中加载
此路由文件由附加到每个模型的SEO行为自动生成和更新
它包含如下行:
// routes: (code found on another thread):
Router::connect('/:site/:language/:row:lastslash',array(
'controller' => 'posts', 'action' => 'parseURL',),
array(
'pass'=>array('row'),
'row'=>'.*?',
'lastslash'=>'\/?'
)
);
Router::connect('/content/about-us', array(
'plugin' => 'content',
'controller' => 'content',
'action' => 'view',
16));
/**
* afterSave Callback
* Creates a new SEO record if required
*
* @param Model $model Model the callback is called on
* @param boolean $created Whether or not the save created a record.
* @return void
*/
public function afterSave(Model $model, $created) {
$modelPrimaryKey = $model->id;
// See if we already have an SEO record for this model record
$seoDetails = $this->seoModel->find(
'first',
array(
'conditions' => array(
'Seo.plugin' => $this->settings[$model->alias]['plugin'],
'Seo.model' => $model->name,
'Seo.foreign_key' => $modelPrimaryKey
)
)
);
if(empty($seoDetails)){
$modelData = $model->read(null, $modelPrimaryKey);
$slug = $model->getSlug($modelData[$model->alias]);
$title = $model->getDisplayName($modelData[$model->alias]);
$seoData = array(
$this->seoModel->alias => array(
'model' => $model->name,
'plugin' => $this->settings[$model->alias]['plugin'],
'foreign_key' => $model->id,
'action' => 'view',
'request_uri' => '/' . Inflector::underscore($model->name) . '/' . $slug,
'title' => $title,
'seo_attribute_type_id' => $this->defaultAttributeTypeId
)
);
// Create some default meta tags as well
$seoData['SeoMeta'] = array(
0 => array(
'key' => 'keywords',
'value' => ''
),
1 => array(
'key' => 'description',
'value' => ''
)
);
$this->seoModel->create();
$this->seoModel->saveAll($seoData);
$id = $this->seoModel->id;
}
}
这意味着,在创建新模型时,只需将以下行添加到模型:
/**
* @var actsAs A list of Behaviours to use
*/
public $actsAs = array(
'Seo'
);
无论何时保存记录,seo路由文件都会更新
默认情况下,SEO行为将生成自己的slug,但是您可以通过添加getSlug($data)函数在模型中覆盖它。在appModel中需要以下函数:
/**
* Returns the display name for this model with the data provided
* @param $data
* @return mixed
*/
public function getDisplayName($data){
$displayName = $data[$this->displayField];
return $displayName;
}
/**
* Gets the SEO slug (short title) for the item
* @param $data
* @return string
*/
public function getSlug($data){
$displayName = $this->getDisplayName($data);
$slug = $this->createSlugFromString($displayName);
return $slug;
}
/**
* Creates a slug from an input string
* @param $string
* @return string
*/
public function createSlugFromString($string) {
$slugParts = explode('.', $string);
foreach($slugParts as $slugIndex => $slugPart){
$slugParts[$slugIndex] = strtolower(Inflector::slug($slugPart, '-'));
}
$slug = implode('.', $slugParts);
return $slug;
}
在本例中,您将重写getSlug函数以返回所需的嵌套路径
在您的seoBehavior中,您需要以下内容:
// routes: (code found on another thread):
Router::connect('/:site/:language/:row:lastslash',array(
'controller' => 'posts', 'action' => 'parseURL',),
array(
'pass'=>array('row'),
'row'=>'.*?',
'lastslash'=>'\/?'
)
);
Router::connect('/content/about-us', array(
'plugin' => 'content',
'controller' => 'content',
'action' => 'view',
16));
/**
* afterSave Callback
* Creates a new SEO record if required
*
* @param Model $model Model the callback is called on
* @param boolean $created Whether or not the save created a record.
* @return void
*/
public function afterSave(Model $model, $created) {
$modelPrimaryKey = $model->id;
// See if we already have an SEO record for this model record
$seoDetails = $this->seoModel->find(
'first',
array(
'conditions' => array(
'Seo.plugin' => $this->settings[$model->alias]['plugin'],
'Seo.model' => $model->name,
'Seo.foreign_key' => $modelPrimaryKey
)
)
);
if(empty($seoDetails)){
$modelData = $model->read(null, $modelPrimaryKey);
$slug = $model->getSlug($modelData[$model->alias]);
$title = $model->getDisplayName($modelData[$model->alias]);
$seoData = array(
$this->seoModel->alias => array(
'model' => $model->name,
'plugin' => $this->settings[$model->alias]['plugin'],
'foreign_key' => $model->id,
'action' => 'view',
'request_uri' => '/' . Inflector::underscore($model->name) . '/' . $slug,
'title' => $title,
'seo_attribute_type_id' => $this->defaultAttributeTypeId
)
);
// Create some default meta tags as well
$seoData['SeoMeta'] = array(
0 => array(
'key' => 'keywords',
'value' => ''
),
1 => array(
'key' => 'description',
'value' => ''
)
);
$this->seoModel->create();
$this->seoModel->saveAll($seoData);
$id = $this->seoModel->id;
}
}
您的SEO模型可能包含以下代码:
/**
* AfterSave function, called after an SEO item is saved
* @param bool $created
*/
public function afterSave($created){
parent::afterSave($created);
// Now we need to create our cached routes file
$this->createRouteFile();
// Clear any cached routes
CacheEngine::clearGroup('router');
}
/**
* Cleans up a slug, preserving slash characters
* @param $slug
* @return string
*/
public function sanitizeSlug($slug){
$slugParts = explode('/', $slug);
foreach($slugParts as $slugIndex => $slugPart){
$slugParts[$slugIndex] = $this->createSlugFromString($slugPart);
}
$slug = implode('/', $slugParts);
return $slug;
}
/**
* Creates/Updates the routes file by going through all the routes in the database and writing them to the routes file
*/
public function createRouteFile(){
$databaseRoutes = $this->find(
'all',
array(
'recursive' => -1,
'fields' => array(
'plugin',
'model',
'foreign_key',
'action',
'request_uri'
)
)
);
$fileContents = '';
$fileContents .= "<?php\n";
$fileContents .= "/** Automatically generated by " . __FILE__ . " on " . date('Y-m-d H:i:s') . " */\n";
foreach($databaseRoutes as $routeKey => $routeDetails){
$routeLine = "Router::connect('" . addcslashes ( $routeDetails[$this->alias]['request_uri'], "'" ) . "', array(
'plugin' => '" . addcslashes(Inflector::underscore($routeDetails[$this->alias]['plugin']), "'") . "',
'controller' => '" . addcslashes(Inflector::underscore($routeDetails[$this->alias]['model']), "'") . "',
'action' => '" . addcslashes($routeDetails[$this->alias]['action'], "'") . "',
" . addcslashes($routeDetails[$this->alias]['foreign_key'], "'") . "));\n";
$fileContents .= $routeLine;
}
// Write the routes data to our file. Note that SEO_ROUTES_FILE is defined in /app/Module/Core/Config/Routes.php
$success = file_put_contents(SEO_ROUTES_FILE, $fileContents);
if(!$success){
throw new Exception("SEO Routes file unwritable. Check the permissions of: " . SEO_ROUTES_FILE);
}
}
/**
*AfterSave函数,在保存SEO项目后调用
*@param bool$已创建
*/
公共函数afterSave($created){
父项::afterSave($created);
//现在我们需要创建缓存的路由文件
$this->createRouteFile();
//清除所有缓存的路由
CacheEngine::clearGroup(“路由器”);
}
/**
*清除段塞,保留斜杠字符
*@param$slug
*@返回字符串
*/
公共功能消毒塞($slug){
$slugParts=爆炸(“/”,$slug);
foreach($slugParts作为$slugIndex=>$slugPart){
$slugParts[$slugIndex]=$this->createSlugFromString($slugPart);
}
$slug=内爆('/',$slugParts);
返回$slug;
}
/**
*通过遍历数据库中的所有路由并将其写入路由文件来创建/更新路由文件
*/
公共函数createRouteFile(){
$databaseRoutes=$this->find(
“全部”,
排列(
“递归”=>-1,
“字段”=>数组(
“插件”,
“模型”,
“外键”,
“行动”,
“请求uri”
)
)
);
$fileContents='';
$fileContents.=”