CakePHP:嵌套URL

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

我想使用页面的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(
    '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.=”