Symfony 西里尔文路由 slug

问题描述 投票:0回答:2

我在 slugify 路由参数方面遇到问题。我想用“-”替换所有间隔和符号。当参数包含拉丁字母时,一切正常,但如果我尝试使用西里尔字母来slugify参数,则会出现错误。

路由:

 catTests:
      url:    /cat/:id/:name_slug
      class:   sfDoctrineRoute
      options: { model: categories, type: object }
      param: { module: categories, action: testsByCat }
      requirements:
        id: \d+

slug 函数:

static public function slugify($text)
{
  // replace all non letters or digits by -
  $text = preg_replace('/\W+/', '-', $text);

  // trim and lowercase
  $text = strtolower(trim($text, '-'));

  return $text;
}

public function getNameSlug()
{
  $text= Category::slugify($this->getName());
  return $text;
}

示例: 我的数据库中有两个名字:

  • 英语
  • Български език

通常,whitin 函数的 url 是:

  • 英语+语言
  • Български+език

当我输入函数结果时:

  • 英语
  • 并且在西里尔文版本中参数为空。

    解析 URL“/cat/1/”(/) 后清空模块和/或操作。

php symfony1 symfony-1.4 cyrillic
2个回答
3
投票

我建议您使用 Doctrine::urlize 而不是您自己的 slugify 函数(因为您正在使用 Doctrine)。

然后,替换你的函数:

public function getNameSlug()
{
  return Doctrine_Inflector::urlize($this->getName());
}

编辑:

事实上,Doctrine 似乎不能很好地处理西里尔字母(即使在 2.0 中也是如此)。您必须自行处理。我找到了这个功能

  public static function replaceCyrillic ($text)
  {
    $chars = array(
      'ґ'=>'g','ё'=>'e','є'=>'e','ї'=>'i','і'=>'i',
      'а'=>'a', 'б'=>'b', 'в'=>'v',
      'г'=>'g', 'д'=>'d', 'е'=>'e', 'ё'=>'e',
      'ж'=>'zh', 'з'=>'z', 'и'=>'i', 'й'=>'i',
      'к'=>'k', 'л'=>'l', 'м'=>'m', 'н'=>'n',
      'о'=>'o', 'п'=>'p', 'р'=>'r', 'с'=>'s',
      'т'=>'t', 'у'=>'u', 'ф'=>'f', 'х'=>'h',
      'ц'=>'c', 'ч'=>'ch', 'ш'=>'sh', 'щ'=>'sch',
      'ы'=>'y', 'э'=>'e', 'ю'=>'u', 'я'=>'ya', 'é'=>'e', '&'=>'and',
      'ь'=>'', 'ъ' => '',
    );

    return strtr($text, $chars);
  }

然后:

public function getNameSlug()
{
  $slug = Category::replaceCyrillic($this->getName());
  return Doctrine_Inflector::urlize($slug);
}

2
投票

您也可以在整个项目中全局修复该行为。 感谢 symfony 自动加载器,它将您的全局目录添加到插件之前,您可以这样做:

mkdir lib/doctrine
touch lib/doctrine/Inflector_Cyrilic.php
touch lib/doctrine/Sluggable.php
touch test/unit/TransliterationTest.php

lib/doctrine/Inflector_Cyrilic.php:

<?php
class Doctrine_Inflector_Cyrilic extends Doctrine_Inflector
{

    /**
     * @param string $text
     * @param Doctrine_Record $record
     *
     * @return string
     */
    public static function urlizeExtended($text, $record) {
        // we need to use other method name because of PHP strict standards (one more attribute unlike parent so its not compatible)
        // $record attribute is given here standardly, it was only not used before

        //XXX this sollution expect youll have all slugs in Translation records (in I18n in schema.yml)
        // You can alter this conditions how do you need for your project
        // this is important because this should not be used on other writing systems

        if (preg_match('/Translation$/', get_class($record))) {
            if ($record->lang === 'ru') {
                $text = self::cyrilicToLatin($text);
            }
        }
        return parent::urlize($text);
    }

    /**
     * @param string $text
     *
     * @return string
     */
    public static function cyrilicToLatin ($text)
    {
        $chars = array(
            'ґ'=>'g','ё'=>'e','є'=>'e','ї'=>'i','і'=>'i',
            'а'=>'a', 'б'=>'b', 'в'=>'v',
            'г'=>'g', 'д'=>'d', 'е'=>'e', 'ё'=>'e',
            'ж'=>'zh', 'з'=>'z', 'и'=>'i', 'й'=>'i',
            'к'=>'k', 'л'=>'l', 'м'=>'m', 'н'=>'n',
            'о'=>'o', 'п'=>'p', 'р'=>'r', 'с'=>'s',
            'т'=>'t', 'у'=>'u', 'ф'=>'f', 'х'=>'h',
            'ц'=>'c', 'ч'=>'ch', 'ш'=>'sh', 'щ'=>'sch',
            'ы'=>'y', 'э'=>'e', 'ю'=>'u', 'я'=>'ya', 'é'=>'e',
            'ь'=>'', 'ъ' => '',
        );
        return strtr($text, $chars);
    }

}

lib/doctrine/Sluggable.php:

<?php
/**
* we cannot use inheritance here because we are replacing class by otherone with the same name
*/
class Doctrine_Template_Sluggable extends Doctrine_Template
{

    /**
     * Array of Sluggable options
     *
     * @var string
     */
    protected $_options = array(
        'name'          =>  'slug',
        'alias'         =>  NULL,
        'type'          =>  'string',
        'length'        =>  255,
        'unique'        =>  TRUE,
        'options'       =>  array(),
        'fields'        =>  array(),
        'uniqueBy'      =>  array(),
        'uniqueIndex'   =>  TRUE,
        'canUpdate'     =>  FALSE,
        'builder'       =>  array('Doctrine_Inflector_Cyrilic', 'urlizeExtended'),
        'provider'      =>  NULL,
        'indexName'     =>  NULL
    );

    /**
     * Set table definition for Sluggable behavior
     *
     * @return void
     */
    public function setTableDefinition()
    {
        $name = $this->_options['name'];
        if ($this->_options['alias']) {
            $name .= ' as ' . $this->_options['alias'];
        }
        if ($this->_options['indexName'] === NULL) {
            $this->_options['indexName'] = $this->getTable()->getTableName().'_sluggable';
        }
        $this->hasColumn($name, $this->_options['type'], $this->_options['length'], $this->_options['options']);

        if ($this->_options['unique'] == TRUE && $this->_options['uniqueIndex'] == TRUE) {
            $indexFields = array($this->_options['name']);
            $indexFields = array_merge($indexFields, $this->_options['uniqueBy']);
            $this->index($this->_options['indexName'], array('fields' => $indexFields,
                    'type' => 'unique'));
        }

        $this->addListener(new Doctrine_Template_Listener_Sluggable($this->_options));
    }

}

测试/单元/TransliterationTest.php:

<?php

// some bootstrapping of your tests

$record = Doctrine_Core::getTable('YourTable')->create(array(
        'record params....'
    ));
$record->Translation['ru']->name = 'холодильник';
$record->save();
$t->ok(preg_match('/^holodilnik/', $record->Translation['ru']->slug), '        RU slug transliterated cyrilic to latin');

请注意,如果您想在 cli 任务中使用它,由于其运行环境,您必须在那里手动预加载它。 sf1.4 cli 任务有自己特定的运行环境,在我的项目中,它不会在 Doctrine 原始类之前预加载此类..

//i have this in my abstract class which is parent of each my cli tasks
require_once(implode(DIRECTORY_SEPARATOR, array(
        __DIR__, '..',
        'Doctrine',
        'Sluggable.php'
    )));
© www.soinside.com 2019 - 2024. All rights reserved.