【问题标题】:Silverstripe: Cleaning up URLsSilverstripe:清理 URL
【发布时间】:2017-01-27 18:58:01
【问题描述】:

我目前有一个显示员工资料的模块。它是这样工作的:

  • 员工持有人:显示所有员工的列表
  • 员工资料:显示“StaffMember”表中的数据库记录。

员工档案使用模板“StaffHolder_profile.ss”。显然,'profile' 是显示人员配置文件的操作。显示配置文件操作适用于如下所示的 URL:

'http:///staff/profile/记录id'

有人要求我从这些 URL 中删除“个人资料/ID”。据我所知,这是不可能的,因为模块依赖于 URL 才能工作? (它使用 URL 变量...)

这是真的吗?有没有办法我可以基本上“清理” URL,以便新 URL 将是“http://domain/staff/staff-member-name

【问题讨论】:

  • 您可以使用自定义路由来实现此目的,但可能成员名称不是唯一的,因此您会遇到同名成员的问题。
  • 您将其作为前端页面还是在 CMS 中处理?你有用户登录系统吗? (然后可以在会话中找到当前用户,请参阅 CMS Member 类)你使用 SiteTree::nested_urls 吗? (然后 StaffProfile 可以嵌套页面。)是的,您可以在StaffHolder_Controller::index($request) 中处理您的干净网址,其中$name = $request->getParam('ID');
  • @GregSmirnov 感谢您的回复。这是前端。是的,有一个登录系统,但是人员页面是将数据对象列表显示为页面。这不是当前用户的个人资料。什么是嵌套网址?那个 Controller 函数到底是做什么的?
  • @Dallby 解决同名员工之间的名字 + 姓氏冲突,您也可以将 ID 附加到 URL,例如domain/staff/123-staff-member-name

标签: php content-management-system silverstripe


【解决方案1】:

您可以通过覆盖页面控制器索引中的路由参数“Action”来实现特定的 url 模式。我不建议这样做。相反,我建议您为页面创建一个特定的操作,例如“域/员工/视图/...”。我下面的示例确实覆盖了路由参数“Action”,但只是为了解决您的问题。

您可以将标识符基于名称,但缺少详细信息和/或名称匹配等不一致会产生问题 - 这些示例未涵盖其中大部分问题。唯一标识符会好得多。

我没有测试运行任何这段代码,很抱歉出现错误。

-

示例 1:速度较慢,但​​所需的工作量更少。

StaffHolder_Controller:

public function index() {

    /**
     * @internal This will display the first match ONLY. If you'd like to
     * account for member's with exactly the same name, generate and store the
     * slug against their profile... See Example 2 for that.
     */

    // Re-purpose the 'Action' URL param (not advisable)
    $slug = $this->getRequest()->param('Action');

    // Partial match members by first name
    $names = explode('-', $slug);
    $matches = Member::get()->filter('FirstName:PartialMatch', $names[0]);

    // Match dynamically
    $member = null;
    foreach($matches as $testMember) {
        // Uses preg_replace to remove all non-alpha characters
        $testSlug = strtolower(
            sprintf(
                '%s-%s',
                preg_replace("/[^A-Za-z]/", '', $testMember->FirstName),
                preg_replace("/[^A-Za-z]/", '', $testMember->Surname)
            )
        ); // Or use Member::genereateSlug() from forthcoming example MemberExtension

        // Match member (will stop at first match)
        if($testSlug == $slug) {
            $member = $testMember;
            break;
        }
    }

    // Handle invalid requests
    if(!$member) {
        return $this->httpError(404, 'Not Found');
    }

    /**
     * @internal If you're lazy and want to use your existing template
     */
    return $this->customise(array(
        'Profile' => $member
        ))->renderWith(array('StaffHolder_profile', 'Page'));

}

-

示例 2:

config.yml:

Member:
  extensions:
    - MemberExtension

MemberExtension.php:

class MemberExtension extends DataExtension {

    private static $db = array(
        'Slug' => 'Varchar' // Use 'Text' if it's likely that there will be a value longer than 255
    );

    public function generateSlug() {
        // Uses preg_replace to remove all non-alpha characters
        return strtolower(
            sprintf(
                '%s-%s',
                preg_replace("/[^A-Za-z]/", '', $this->owner->FirstName),
                preg_replace("/[^A-Za-z]/", '', $this->owner->Surname)
            )
        );
    }

    public function onBeforeWrite() {

        // Define slug
        if(!$this->owner->Slug)) {
            $slug = $this->generateSlug();

            $count = Member::get()->filter('Slug:PartialMatch', $slug)->Count();

            // Check for unique
            $unique = null;
            $fullSlug = $slug;
            while(!$unique) {
                // Add count e.g firstname-surname-2
                if($count > 0) {
                    $fullSlug = sprintf('%s-%s', $slug, ($count+1));
                }

                // Check for pre-existing
                if(Member::get()->filter('Slug:PartialMatch', $fullSlug)->First()) {
                    $count++; // (Try again with) increment
                } else {
                    $unique = true;
                }
            }

            // Update member
            $this->owner->Slug = $fullSlug;
        }

    }

}

StaffHolder_Controller:

public function index() {

    // Re-purpose the action URL param (not advisable)
    $slug = $this->getRequest()->param('Action');

    // Check for member
    $member = Member::get()->filter('Slug', $slug)->first();

    // Handle invalid requests
    if(!$member) {
        return $this->httpError(404, 'Not Found');
    }

    /**
     * @internal If you're lazy and want to use your existing template
     */
    return $this->customise(array(
        'StaffMember' => $member
        ))->renderWith('StaffHolder_profile');

}

【讨论】:

    【解决方案2】:

    嵌套 url 是 SiteTree 类的默认行为。每个子页面 URL 段都添加到父完整 URL。因此,使用以下页面层次结构,您可以获得干净的 url

    Staff (StaffHolder, /staff)
    |- John Doe (StaffProfilePage, /staff/john-doe)
    |- Marie Smith (StaffProfilePage, /staff/marie-smith)
    

    您可以使用以下方法在 StaffHolder.ss 模板中获取员工个人资料页面列表

    <ul>
    <% loop $Children %>
        <li><a href="$Link">$Title</a></li>
    <% end_loop %>
    </ul>
    

    【讨论】:

      猜你喜欢
      • 2017-02-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-03
      • 1970-01-01
      相关资源
      最近更新 更多