我在 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/”(/) 后清空模块和/或操作。
我建议您使用 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);
}
您也可以在整个项目中全局修复该行为。 感谢 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'
)));