PageRenderTime 61ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 1ms

/generator/lib/behavior/sluggable/SluggableBehavior.php

https://github.com/trendone/Propel
PHP | 347 lines | 212 code | 33 blank | 102 comment | 23 complexity | 654927ef613fdd3b43b4a6863906fbc9 MD5 | raw file
  1. <?php
  2. /**
  3. * This file is part of the Propel package.
  4. * For the full copyright and license information, please view the LICENSE
  5. * file that was distributed with this source code.
  6. *
  7. * @license MIT License
  8. */
  9. /**
  10. * Adds a slug column
  11. *
  12. * @author Francois Zaninotto
  13. * @author Massimiliano Arione
  14. * @version $Revision$
  15. * @package propel.generator.behavior.sluggable
  16. */
  17. class SluggableBehavior extends Behavior
  18. {
  19. // default parameters value
  20. protected $parameters = array(
  21. 'slug_column' => 'slug',
  22. 'slug_pattern' => '',
  23. 'replace_pattern' => '/\W+/', // Tip: use '/[^\\pL\\d]+/u' instead if you're in PHP5.3
  24. 'replacement' => '-',
  25. 'separator' => '-',
  26. 'permanent' => 'false',
  27. 'scope_column' => ''
  28. );
  29. /**
  30. * Add the slug_column to the current table
  31. */
  32. public function modifyTable()
  33. {
  34. if (!$this->getTable()->containsColumn($this->getParameter('slug_column'))) {
  35. $this->getTable()->addColumn(array(
  36. 'name' => $this->getParameter('slug_column'),
  37. 'type' => 'VARCHAR',
  38. 'size' => 255,
  39. 'required' => false,
  40. ));
  41. // add a unique to column
  42. $unique = new Unique($this->getColumnForParameter('slug_column'));
  43. $unique->setName($this->getTable()->getCommonName() . '_slug');
  44. $unique->addColumn($this->getTable()->getColumn($this->getParameter('slug_column')));
  45. if ($this->getParameter('scope_column')) {
  46. $unique->addColumn($this->getTable()->getColumn($this->getParameter('scope_column')));
  47. }
  48. $this->getTable()->addUnique($unique);
  49. }
  50. }
  51. /**
  52. * Get the getter of the column of the behavior
  53. *
  54. * @return string The related getter, e.g. 'getSlug'
  55. */
  56. protected function getColumnGetter()
  57. {
  58. return 'get' . $this->getColumnForParameter('slug_column')->getPhpName();
  59. }
  60. /**
  61. * Get the setter of the column of the behavior
  62. *
  63. * @return string The related setter, e.g. 'setSlug'
  64. */
  65. protected function getColumnSetter()
  66. {
  67. return 'set' . $this->getColumnForParameter('slug_column')->getPhpName();
  68. }
  69. /**
  70. * Add code in ObjectBuilder::preSave
  71. *
  72. * @return string The code to put at the hook
  73. */
  74. public function preSave($builder)
  75. {
  76. $const = $builder->getColumnConstant($this->getColumnForParameter('slug_column'));
  77. $script = "
  78. if (\$this->isColumnModified($const) && \$this->{$this->getColumnGetter()}()) {
  79. \$this->{$this->getColumnSetter()}(\$this->makeSlugUnique(\$this->{$this->getColumnGetter()}()));";
  80. if ($this->getParameter('permanent') == 'true') {
  81. $script .= "
  82. } elseif (!\$this->{$this->getColumnGetter()}()) {
  83. \$this->{$this->getColumnSetter()}(\$this->createSlug());
  84. }";
  85. } else {
  86. $script .= "
  87. } else {
  88. \$this->{$this->getColumnSetter()}(\$this->createSlug());
  89. }";
  90. }
  91. return $script;
  92. }
  93. public function objectMethods($builder)
  94. {
  95. $this->builder = $builder;
  96. $script = '';
  97. if ($this->getParameter('slug_column') != 'slug') {
  98. $this->addSlugSetter($script);
  99. $this->addSlugGetter($script);
  100. }
  101. $this->addCreateSlug($script);
  102. $this->addCreateRawSlug($script);
  103. $this->addCleanupSlugPart($script);
  104. $this->addLimitSlugSize($script);
  105. $this->addMakeSlugUnique($script);
  106. return $script;
  107. }
  108. protected function addSlugSetter(&$script)
  109. {
  110. $script .= "
  111. /**
  112. * Wrap the setter for slug value
  113. *
  114. * @param string
  115. * @return " . $this->getTable()->getPhpName() . "
  116. */
  117. public function setSlug(\$v)
  118. {
  119. return \$this->" . $this->getColumnSetter() . "(\$v);
  120. }
  121. ";
  122. }
  123. protected function addSlugGetter(&$script)
  124. {
  125. $script .= "
  126. /**
  127. * Wrap the getter for slug value
  128. *
  129. * @return string
  130. */
  131. public function getSlug()
  132. {
  133. return \$this->" . $this->getColumnGetter() . "();
  134. }
  135. ";
  136. }
  137. protected function addCreateSlug(&$script)
  138. {
  139. $script .= "
  140. /**
  141. * Create a unique slug based on the object
  142. *
  143. * @return string The object slug
  144. */
  145. protected function createSlug()
  146. {
  147. \$slug = \$this->createRawSlug();
  148. \$slug = \$this->limitSlugSize(\$slug);
  149. \$slug = \$this->makeSlugUnique(\$slug);
  150. return \$slug;
  151. }
  152. ";
  153. }
  154. protected function addCreateRawSlug(&$script)
  155. {
  156. $pattern = $this->getParameter('slug_pattern');
  157. $script .= "
  158. /**
  159. * Create the slug from the appropriate columns
  160. *
  161. * @return string
  162. */
  163. protected function createRawSlug()
  164. {
  165. ";
  166. if ($pattern) {
  167. $script .= "return '" . str_replace(array('{', '}'), array('\' . $this->cleanupSlugPart($this->get', '()) . \''), $pattern). "';";
  168. } else {
  169. $script .= "return \$this->cleanupSlugPart(\$this->__toString());";
  170. }
  171. $script .= "
  172. }
  173. ";
  174. return $script;
  175. }
  176. public function addCleanupSlugPart(&$script)
  177. {
  178. $script .= "
  179. /**
  180. * Cleanup a string to make a slug of it
  181. * Removes special characters, replaces blanks with a separator, and trim it
  182. *
  183. * @param string \$slug the text to slugify
  184. * @param string \$replacement the separator used by slug
  185. * @return string the slugified text
  186. */
  187. protected static function cleanupSlugPart(\$slug, \$replacement = '" . $this->getParameter('replacement') . "')
  188. {
  189. // transliterate
  190. if (function_exists('iconv')) {
  191. \$slug = iconv('utf-8', 'us-ascii//TRANSLIT', \$slug);
  192. }
  193. // lowercase
  194. if (function_exists('mb_strtolower')) {
  195. \$slug = mb_strtolower(\$slug);
  196. } else {
  197. \$slug = strtolower(\$slug);
  198. }
  199. // remove accents resulting from OSX's iconv
  200. \$slug = str_replace(array('\'', '`', '^'), '', \$slug);
  201. // replace non letter or digits with separator
  202. \$slug = preg_replace('" . $this->getParameter('replace_pattern') . "', \$replacement, \$slug);
  203. // trim
  204. \$slug = trim(\$slug, \$replacement);
  205. if (empty(\$slug)) {
  206. return 'n-a';
  207. }
  208. return \$slug;
  209. }
  210. ";
  211. }
  212. public function addLimitSlugSize(&$script)
  213. {
  214. $size = $this->getColumnForParameter('slug_column')->getSize();
  215. $script .= "
  216. /**
  217. * Make sure the slug is short enough to accomodate the column size
  218. *
  219. * @param string \$slug the slug to check
  220. * @param int \$incrementReservedSpace the number of characters to keep empty
  221. *
  222. * @return string the truncated slug
  223. */
  224. protected static function limitSlugSize(\$slug, \$incrementReservedSpace = 3)
  225. {
  226. // check length, as suffix could put it over maximum
  227. if (strlen(\$slug) > ($size - \$incrementReservedSpace)) {
  228. \$slug = substr(\$slug, 0, $size - \$incrementReservedSpace);
  229. }
  230. return \$slug;
  231. }
  232. ";
  233. }
  234. public function addMakeSlugUnique(&$script)
  235. {
  236. $script .= "
  237. /**
  238. * Get the slug, ensuring its uniqueness
  239. *
  240. * @param string \$slug the slug to check
  241. * @param string \$separator the separator used by slug
  242. * @param int \$increment the count of occurences of the slug
  243. * @return string the unique slug
  244. */
  245. protected function makeSlugUnique(\$slug, \$separator = '" . $this->getParameter('separator') ."', \$increment = 0)
  246. {
  247. \$slug2 = empty(\$increment) ? \$slug : \$slug . \$separator . \$increment;
  248. \$slugAlreadyExists = " . $this->builder->getStubQueryBuilder()->getClassname() . "::create()
  249. ->filterBySlug(\$slug2)
  250. ->prune(\$this)";
  251. if ($this->getParameter('scope_column')) {
  252. $getter = 'get' . $this->getColumnForParameter('scope_column')->getPhpName();
  253. $script .="
  254. ->filterBy('{$this->getColumnForParameter('scope_column')->getPhpName()}', \$this->{$getter}())";
  255. }
  256. // watch out: some of the columns may be hidden by the soft_delete behavior
  257. if ($this->table->hasBehavior('soft_delete')) {
  258. $script .= "
  259. ->includeDeleted()";
  260. }
  261. $script .= "
  262. ->count();
  263. if (\$slugAlreadyExists) {
  264. return \$this->makeSlugUnique(\$slug, \$separator, ++\$increment);
  265. } else {
  266. return \$slug2;
  267. }
  268. }
  269. ";
  270. }
  271. public function queryMethods($builder)
  272. {
  273. $this->builder = $builder;
  274. $script = '';
  275. if ($this->getParameter('slug_column') != 'slug') {
  276. $this->addFilterBySlug($script);
  277. }
  278. $this->addFindOneBySlug($script);
  279. return $script;
  280. }
  281. protected function addFilterBySlug(&$script)
  282. {
  283. $script .= "
  284. /**
  285. * Filter the query on the slug column
  286. *
  287. * @param string \$slug The value to use as filter.
  288. *
  289. * @return " . $this->builder->getStubQueryBuilder()->getClassname() . " The current query, for fluid interface
  290. */
  291. public function filterBySlug(\$slug)
  292. {
  293. return \$this->addUsingAlias(" . $this->builder->getColumnConstant($this->getColumnForParameter('slug_column')) . ", \$slug, Criteria::EQUAL);
  294. }
  295. ";
  296. }
  297. protected function addFindOneBySlug(&$script)
  298. {
  299. $script .= "
  300. /**
  301. * Find one object based on its slug
  302. *
  303. * @param string \$slug The value to use as filter.
  304. * @param PropelPDO \$con The optional connection object
  305. *
  306. * @return " . $this->builder->getStubObjectBuilder()->getClassname() . " the result, formatted by the current formatter
  307. */
  308. public function findOneBySlug(\$slug, \$con = null)
  309. {
  310. return \$this->filterBySlug(\$slug)->findOne(\$con);
  311. }
  312. ";
  313. }
  314. }