【问题标题】:CakePHP: Nested URLsCakePHP:嵌套 URL
【发布时间】:2013-12-06 11:22:37
【问题描述】:

我想为 URL 使用页面的 slug 路径(即:/products/stereos/stereo-1/info - 这只是直接遵循 db 中页面的树结构:info 是 stereo-1 的子级,stereo-1 是立体的孩子,等等)。 (一切都将通过 Pages 控制器进行管理)。

我想的一种方法是做这样的事情:

// routes: (code found on another thread):
Router::connect('/:site/:language/:row:lastslash',array(
    'controller' => 'posts', 'action' => 'parseURL',),
    array(
        'pass'=>array('row'),
        'row'=>'.*?',
        'lastslash'=>'\/?'
    )
);

这应该将我与 $row 中的 URL 的其余部分一起转发到 parseURL。在 parseURL 中,我可以找到实际的帖子 ID(通过使用 slug 路径),获取指定操作的 db 字段,然后转发到那里。理论上,系统应该处理数据库中的任何 url 树路径。例如:

/page1/page2/page3/info/thisPage - parseURL 将遍历 url 的每个部分以查找“thisPage”的帖子 ID。 'thisPage' 将有一个 'action' 字段指定要使用的操作,并且 parseURL 将重定向到那里。

有没有更好的方法来处理这个问题?

【问题讨论】:

    标签: cakephp


    【解决方案1】:

    这是一个棘手的问题。

    我的做法是在 /app/tmp/cache/seo_routes.php 中创建一个 SEO 路由文件,每个请求都会加载该文件。

    此路由文件由您附加到每个模型的 SEO 行为自动生成和更新。

    它包含这样的行:

    Router::connect('/content/about-us', array(
                'plugin' => 'content',
                'controller' => 'content',
                'action' => 'view',
                16));
    

    这意味着当您制作一个新模型时,您只需将这些行添加到模型中:

        /**
     * @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 中你需要这样的东西:

    /**
     * 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);
        }
    }
    

    祝你好运,这是一个难题,这个解决方案对我来说效果很好,并且允许将任何 SEO url 编辑为你想要的任何内容(即使它违反了其他页面的约定)。当客户聘请专业的 SEO 公司想要完全更改某些页面的 SEO 网址时,这很有用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-01-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多