【问题标题】:Symfony cyrillic routing slugSymfony 西里尔文路由 slug
【发布时间】:2012-06-04 14:44:37
【问题描述】:

我的 slugify 路由参数有问题。我想用“-”替换所有间隔和符号。当参数使用拉丁字母时所有工作,但如果我尝试使用西里尔字母 slugify 参数我得到错误。

路由:

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

蛞蝓函数:

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/” (/) 后的空模块和/或操作。

【问题讨论】:

    标签: symfony1 symfony-1.4 cyrillic


    【解决方案1】:

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

    然后,将您的函数替换为:

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

    编辑:

    事实上,Doctrine 似乎不能很好地处理西里尔字母(即使在 2.0 中)。您将不得不自己处理它。我找到了this function

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

    【讨论】:

    • 好的,我试过了,但结果是一样的。函数仅适用于我的数据库中的拉丁名称:(
    • 您能否发布(在您的问题中)错误和带有西里尔字母问题的名称?
    • 是的! Whit 这个功能是工作。但令人失望的是因为学说不支持西里尔语。在这种情况下,我认为网址 whit + 比拉丁语更好。
    【解决方案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));
        }
    
    }
    

    test/unit/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'
        )));
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-21
      • 1970-01-01
      • 2012-12-27
      • 1970-01-01
      • 1970-01-01
      • 2017-06-02
      相关资源
      最近更新 更多