CakePHP:嵌套URL

时间:2013-12-06 01:53:57

标签: cakephp

我想使用页面的slug路径作为URL(即:/ products / stereos / stereo-1 / info - 这只是直接跟在db中的页面树结构:info是stereo-1的子节点,立体声-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'=>'\/?'
    )
);

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

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

有没有更好的方法来解决这个问题?

1 个答案:

答案 0 :(得分:0)

这是一个棘手的问题。

我这样做的方法是在/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 routes文件。

默认情况下,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网址(即使它违反了你的其他页面的惯例)。当客户雇用一个想要彻底改变某些页面的SEO网址的专业SEO公司时,这很有用。