slug.php 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. <?php
  2. /**
  3. * Fuel is a fast, lightweight, community driven PHP5 framework.
  4. *
  5. * @package Fuel
  6. * @version 1.5
  7. * @author Fuel Development Team
  8. * @license MIT License
  9. * @copyright 2010 - 2013 Fuel Development Team
  10. * @link http://fuelphp.com
  11. */
  12. namespace Orm;
  13. /**
  14. * Observer class to generate SEO friendly slugs from a model property (usually something like a title)
  15. */
  16. class Observer_Slug extends Observer
  17. {
  18. /**
  19. * @var mixed Default source property or array of properties, which is/are used to create the slug
  20. */
  21. public static $source = 'title';
  22. /**
  23. * @var string Default slug property
  24. */
  25. public static $property = 'slug';
  26. /**
  27. * @var mixed Source property or array of properties, which is/are used to create the slug
  28. */
  29. protected $_source;
  30. /**
  31. * @var string Slug property
  32. */
  33. protected $_property;
  34. /**
  35. * Set the properties for this observer instance, based on the parent model's
  36. * configuration or the defined defaults.
  37. *
  38. * @param string Model class this observer is called on
  39. */
  40. public function __construct($class)
  41. {
  42. $props = $class::observers(get_class($this));
  43. $this->_source = isset($props['source']) ? $props['source'] : static::$source;
  44. $this->_property = isset($props['property']) ? $props['property'] : static::$property;
  45. }
  46. /**
  47. * Creates a unique slug and adds it to the object
  48. *
  49. * @param Model Model object subject of this observer method
  50. */
  51. public function before_insert(Model $obj)
  52. {
  53. // determine the slug
  54. $properties = (array) $this->_source;
  55. $source = '';
  56. foreach ($properties as $property)
  57. {
  58. $source .= '-'.$obj->{$property};
  59. }
  60. $slug = \Inflector::friendly_title(substr($source, 1), '-', true);
  61. // do we have records with this slug?
  62. $same = $obj->query()->where($this->_property, 'like', $slug.'%')->get();
  63. // make sure our slug is unique
  64. if ( ! empty($same))
  65. {
  66. $max = -1;
  67. foreach ($same as $record)
  68. {
  69. if (preg_match('/^'.$slug.'(?:-([0-9]+))?$/', $record->{$this->_property}, $matches))
  70. {
  71. $index = isset($matches[1]) ? (int) $matches[1] : 0;
  72. $max < $index and $max = $index;
  73. }
  74. }
  75. $max < 0 or $slug .= '-'.($max + 1);
  76. }
  77. $obj->{$this->_property} = $slug;
  78. }
  79. /**
  80. * Creates a new unique slug and update the object
  81. *
  82. * @param Model Model object subject of this observer method
  83. */
  84. public function before_update(Model $obj)
  85. {
  86. // determine the slug
  87. $properties = (array) $this->_source;
  88. $source = '';
  89. foreach ($properties as $property)
  90. {
  91. $source .= '-'.$obj->{$property};
  92. }
  93. $slug = \Inflector::friendly_title(substr($source, 1), '-', true);
  94. // update it if it's different from the current one
  95. $obj->{$this->_property} === $slug or $this->before_insert($obj);
  96. }
  97. }