Coverage for Doctrine_Template_Listener_Sluggable

Back to coverage report

1 <?php
2 /*
3  *  $Id$
4  *
5  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
6  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
7  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
8  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
9  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
10  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
11  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
12  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
13  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
14  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
15  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16  *
17  * This software consists of voluntary contributions made by many individuals
18  * and is licensed under the LGPL. For more information, see
19  * <http://www.phpdoctrine.org>.
20  */
21
22 /**
23  * Doctrine_Template_Listener_Sluggable
24  *
25  * Easily create a slug for each record based on a specified set of fields
26  *
27  * @package     Doctrine
28  * @subpackage  Template
29  * @license     http://www.opensource.org/licenses/lgpl-license.php LGPL
30  * @link        www.phpdoctrine.org
31  * @since       1.0
32  * @version     $Revision$
33  * @author      Konsta Vesterinen <kvesteri@cc.hut.fi>
34  */
35 class Doctrine_Template_Listener_Sluggable extends Doctrine_Record_Listener
36 {
37     /**
38      * Array of timestampable options
39      *
40      * @var string
41      */
42     protected $_options = array();
43
44     /**
45      * __construct
46      *
47      * @param string $array 
48      * @return void
49      */
50     public function __construct(array $options)
51     {
52         $this->_options = $options;
53     }
54
55     /**
56      * preInsert
57      *
58      * @param Doctrine_Event $event 
59      * @return void
60      */
61     public function preInsert(Doctrine_Event $event)
62     {
63         $name = $this->_options['name'];
64
65         $record = $event->getInvoker();
66
67         if ( ! $record->$name) {
68             $record->$name = $this->buildSlug($record);
69         }
70     }
71
72     /**
73      * preUpdate
74      *
75      * @param Doctrine_Event $event 
76      * @return void
77      */
78     public function preUpdate(Doctrine_Event $event)
79     {
80         if (false !== $this->_options['unique']) {
81             $name = $this->_options['name'];
82     
83             $record = $event->getInvoker();
84
85             if ( ! $record->$name) {
86                 $record->$name = $this->buildSlug($record);        
87             }
88         }
89     }
90
91     /**
92      * buildSlug
93      *
94      * Generate the slug for a given Doctrine_Record
95      *
96      * @param Doctrine_Record $record 
97      * @return string $slug
98      */
99     protected function buildSlug($record)
100     {
101         if (empty($this->_options['fields'])) {
102             if (method_exists($record, 'getUniqueSlug')) {
103                 $value = $record->getUniqueSlug($record);
104             } else {
105                 $value = (string) $record;
106             }
107         } else {
108             if ($this->_options['unique'] === true) {   
109                 $value = $this->getUniqueSlug($record);
110             } else {  
111                 $value = '';
112                 foreach ($this->_options['fields'] as $field) {
113                     $value .= $record->$field . ' ';
114                 } 
115             }
116
117             $value =  Doctrine_Inflector::urlize($value);
118         }
119
120         return $value;
121     }
122
123     /**
124      * getUniqueSlug
125      *
126      * Creates a unique slug for a given Doctrine_Record. This function enforces the uniqueness by incrementing
127      * the values with a postfix if the slug is not unique
128      *
129      * @param Doctrine_Record $record 
130      * @return string $slug
131      */
132     public function getUniqueSlug($record)
133     {
134         $name = $this->_options['name'];
135         $slugFromFields = '';
136         foreach ($this->_options['fields'] as $field) {
137             $slugFromFields .= $record->$field . ' ';
138         }
139
140         $proposal = $record->$name ? $record->$name : $slugFromFields;
141         $proposal =  Doctrine_Inflector::urlize($proposal);
142         $slug = $proposal;
143
144         $whereString = 'r.' . $name . ' LIKE ?';
145         $whereParams = array($proposal.'%');
146         
147         if ($record->exists()) {
148             $identifier = $record->identifier();
149             $whereString .= ' AND r.' . implode(' != ? AND r.', $record->getTable()->getIdentifierColumnNames()) . ' != ?';
150             $whereParams = array_merge($whereParams, array_values($identifier));
151         }
152
153         foreach ($this->_options['uniqueBy'] as $uniqueBy) {
154             if (is_null($record->$uniqueBy)) {
155                 $whereString .= ' AND r.'.$uniqueBy.' IS NULL';
156             } else {
157                 $whereString .= ' AND r.'.$uniqueBy.' = ?';
158                 $whereParams[] =  $record->$uniqueBy;
159             }
160         }
161
162         $query = Doctrine_Query::create()
163         ->select('r.'.$name)
164         ->from(get_class($record).' r')
165         ->where($whereString , $whereParams)
166         ->setHydrationMode(Doctrine::HYDRATE_ARRAY);
167
168         $similarSlugResult = $query->execute();
169
170         $similarSlugs = array();
171         foreach ($similarSlugResult as $key => $value) {
172             $similarSlugs[$key] = $value[$name];
173         }
174
175         $i = 1;
176         while (in_array($slug, $similarSlugs)) {
177             $slug = $proposal.'-'.$i;
178             $i++;
179         }
180
181         return  $slug;
182     }
183 }