Development

/plugins/sfDoctrineActAsTaggablePlugin/trunk/lib/model/doctrine/PluginTagTable.class.php

You must first sign up to be able to contribute.

root/plugins/sfDoctrineActAsTaggablePlugin/trunk/lib/model/doctrine/PluginTagTable.class.php

Revision 33390, 17.2 kB (checked in by boutell, 1 year ago)

Tags should be sorted in a case-insensitive fashion for consistency with the results of sorting them with MySQL and for general friendliness

Line 
1 <?php
2 /**
3  * This class has been auto-generated by the Doctrine ORM Framework
4  */
5 class PluginTagTable extends Doctrine_Table
6 {
7     /**
8     * Retrieves a tag by his name. If it does not exist, creates it (but does not
9     * save it)
10     *
11     * @param      String      $tagname
12     * @return     Tag
13     */
14     public function findOrCreateByTagname($tagname)
15     {
16         // retrieve or create the tag
17         $tag = Doctrine_Core::getTable('Tag')->findOneByName($tagname);
18
19         if (!$tag)
20         {
21             $tag = new Tag();
22             $tag->name = $tagname;
23
24             $triple = TaggableToolkit::extractTriple($tagname);
25             list($tagname, $triple_namespace, $triple_key, $triple_value) = $triple;
26
27             $tag->triple_namespace = $triple_namespace;
28             $tag->triple_key = $triple_key;
29             $tag->triple_value = $triple_value;
30             $tag->is_triple = !is_null($triple_namespace);
31         }
32
33         return $tag;
34     }
35
36     /**
37     * Returns all tags, eventually with a limit option.
38     * The first optionnal parameter permits to add some restrictions on the
39     * objects the selected tags are related to.
40     * The second optionnal parameter permits to restrict the tag selection with
41     * different criterias
42     *
43     * @param      Doctrine_Query    $c
44     * @param      array       $options
45     * @return     array
46     */
47     public static function getAllTagName(Doctrine_Query $q = null, $options = array())
48     {
49         if ($q == null)
50         {
51             $q = Doctrine_Query::create();
52         }
53
54         if (!$q->getDqlPart('select'))
55         {
56           $q->select('t.name');
57         }
58
59         if (!$q->getDqlPart('from'))
60         {
61           $q->from('Tag t INDEXBY t.name');
62               }
63
64         if (isset($options['limit']))
65         {
66             $q->limit($options['limit']);
67         }
68
69         if (isset($options['like']))
70         {
71             $q->addWhere('t.name like ?', $options['like']);
72         }
73
74         if (isset($options['triple']))
75         {
76             $q->addWhere('t.is_triple = ?', $options['triple']);
77         }
78
79         if (isset($options['namespace']))
80         {
81             $q->addWhere('t.triple_namespace = ?', $options['namespace']);
82         }
83
84         if (isset($options['key']))
85         {
86             $q->addWhere('t.triple_key = ?', $options['key']);
87         }
88
89         if (isset($options['value']))
90         {
91             $q->addWhere('t.triple_value = ?', $options['value']);
92         }
93
94         return array_keys($q->execute(array(), Doctrine_Core::HYDRATE_ARRAY));
95     }
96
97     /**
98     * Returns all tags, sorted by name, with their number of occurencies.
99     * The first optional parameter permits to add some restrictions on the
100     * objects the selected tags are related to.
101     * The second optional parameter permits to restrict the tag selection with
102     * different criterias
103     *
104     * @param      Doctrine_Query    $c
105     * @param      array       $options
106     * @return     array
107     */
108     public static function getAllTagNameWithCount(Doctrine_Query $q = null, $options = array())
109     {
110         if ($q == null)
111         {
112             $q = Doctrine_Query::create();
113         }
114
115         $q->select('tg.tag_id, t.name, COUNT(tg.id) AS t_count');
116
117         //allows to pass more complex queries with a lot of joins
118         if (!$q->getDqlPart('from'))
119         {
120           $q->from('Tagging tg, tg.Tag t');
121         }
122
123         if (isset($options['limit']))
124         {
125             $q->limit($options['limit']);
126         }
127
128         if (isset($options['model']))
129         {
130             $q->addWhere('tg.taggable_model = ?', $options['model']);
131         }
132
133         if (isset($options['like']))
134         {
135             $q->addWhere('t.name like ?', $options['like']);
136         }
137
138         if (isset($options['triple']))
139         {
140             $q->addWhere('t.is_triple = ?', $options['triple']);
141         }
142
143         if (isset($options['namespace']))
144         {
145             $q->addWhere('t.triple_namespace = ?', $options['namespace']);
146         }
147
148         if (isset($options['key']))
149         {
150             $q->addWhere('t.triple_key = ?', $options['key']);
151         }
152
153         if (isset($options['value']))
154         {
155             $q->addWhere('t.triple_value = ?', $options['value']);
156         }
157
158         if (isset($options['min_tags_count']))
159         {
160             $q->having('t_count >= ?', $options['min_tags_count']);
161         }
162
163         $q->groupBy('tg.tag_id') // , t.name ?
164           ->orderBy('t_count DESC, t.name ASC')
165         ;
166
167         $rs = $q->execute(array(), Doctrine_Core::HYDRATE_ARRAY);
168
169         $tags = array();
170
171         foreach($rs as $tag)
172         {
173             $name = $tag['Tag']['name'];
174             $tags[$name] = $tag['t_count'];
175         }
176
177         if (!isset($options['sort_by_popularity']) || (true !== $options['sort_by_popularity']))
178         {
179             uksort($tags, array('TagTable', 'compareTags'));
180         }
181
182         return $tags;
183     }
184
185     /**
186      * Case insensitive comparison so results when sort_by_popularity is false are
187      * comparable to the results of MySQL doing the sorting (as seen most other places
188      * in a Symfony app)
189      */
190     static public function compareTags($a, $b)
191     {
192         return strcasecmp($a, $b);
193     }
194
195     /**
196     * Returns the names of the models that have instances tagged with one or
197     * several tags. The optionnal parameter might be a string, an array, or a
198     * comma separated string
199     *
200     * @param      mixed       $tags
201     * @return     array
202     */
203     public static function getModelsNameTaggedWith($tags = array())
204     {
205         if (is_string($tags))
206         {
207             if (false !== strpos($tags, ','))
208             {
209                 $tags = explode(',', $tags);
210             }
211             else
212             {
213                 $tags = array($tags);
214             }
215         }
216
217         $q = Doctrine_Query::create()
218                            ->select('tg.taggable_model, tg.taggable_id')
219                            ->from('Tagging tg, Tag t')
220                            ->where('t.name in ?', $tags)
221                            ->having('count(t.id) > ?', count($tags))
222                            ->groupBy('tg.taggable_id')
223                            ->execute(array(), Doctrine_Core::FETCH_ARRAY);
224
225         foreach($q as $cc)
226         {
227             $models[] = $cc[1];
228         }
229
230         return $models;
231     }
232
233     /**
234     * Returns the most popular tags with their associated weight. See
235     * TaggableToolkit::normalize for more details.
236     *
237     * The first optional parameter permits to add some restrictions on the
238     * objects the selected tags are related to.
239     * The second optional parameter permits to restrict the tag selection with
240     * different criterias
241     *
242     * @param      Doctrine_Query  $q
243     * @param      array           $options
244     * @return     array
245     */
246     public static function getPopulars($q = null, $options = array(), $normalized = true, $limit = null)
247     {
248         if ($q == null)
249         {
250             $q = Doctrine_Query::create()->limit((($limit != null) ? $limit : sfConfig::get('app_sfDoctrineActAsTaggablePlugin_limit', 100)));
251         }
252
253         $all_tags = self::getAllTagNameWithCount($q, $options);
254         return ($normalized)? TaggableToolkit::normalize($all_tags) : $all_tags ;
255     }
256
257     /**
258     * Returns the tags that are related to one or more other tags, with their
259     * associated weight (see TaggableToolkit::normalize for more
260     * details).
261     * The "related tags" of one tag are the ones which have at least one
262     * taggable object in common.
263     *
264     * The first optionnal parameter permits to add some restrictions on the
265     * objects the selected tags are related to.
266     * The second optionnal parameter permits to restrict the tag selection with
267     * different criterias
268     *
269     * @param      mixed       $tags
270     * @param      array       $options
271     * @return     array
272     */
273     public static function getRelatedTags($tags = array(), $options = array())
274     {
275         $tags = TaggableToolkit::explodeTagString($tags);
276
277         if (is_string($tags))
278         {
279             $tags = array($tags);
280         }
281
282         $tagging_options = $options;
283
284         if (isset($tagging_options['limit']))
285         {
286           unset($tagging_options['limit']);
287         }
288
289         $taggings = self::getTaggings($tags, $tagging_options);
290         $result = array();
291
292         foreach ($taggings as $key => $tagging)
293         {
294             $tags_rs = Doctrine_Query::create()
295                                      ->select('t.name, tg.taggable_id')
296                                      ->from('Tag t, t.Tagging tg')
297                                      ->where('tg.taggable_model = ?', $key)
298                                      ->andWhereNotIn('t.name', $tags)
299                                      ->andWhereIn('tg.taggable_id', $tagging)
300                                      ->execute(array(), Doctrine_Core::HYDRATE_SCALAR);
301
302             foreach ($tags_rs as $tag)
303             {
304                 $tag_name = $tag['t_name'];
305
306                 if (!isset($result[$tag_name]))
307                 {
308                     $result[$tag_name] = 0;
309                 }
310
311                 $result[$tag_name]++;
312             }
313         }
314
315         if (isset($options['limit']))
316         {
317             arsort($result);
318             $result = array_slice($result, 0, $options['limit'], true);
319         }
320
321         ksort($result);
322         return TaggableToolkit::normalize($result);
323     }
324
325     /**
326     * Retrieves the objects tagged with one or several tags.
327     *
328     * The second optionnal parameter permits to restrict the tag selection with
329     * different criterias
330     *
331     * @param      mixed       $tags
332     * @param      array       $options
333     * @return     array
334     */
335     public static function getObjectTaggedWith($tags = array(), $options = array())
336     {
337         $taggings = self::getTaggings($tags, $options);
338         $result = array();
339
340         foreach ($taggings as $key => $tagging)
341         {
342             $q = Doctrine_Query::create()->from($key . ' t');
343
344             if(isset($options['leftJoin']))
345             {
346                 $q->leftJoin($options['leftJoin']);
347             }
348
349             $hydration = isset($options['hydrate']) ?  $options['hydrate'] : Doctrine_Core::HYDRATE_RECORD;
350
351             $objects = $q->whereIn('t.id', $tagging)->execute(array(), $hydration);
352
353             foreach ($objects as $object)
354             {
355                 $result[] = $object;
356             }
357         }
358
359         return $result;
360     }
361
362     /**
363     * Retrieve a Doctrine_Query instance for querying tagged model objects.
364     *
365     * Example:
366     *
367     * $q = PluginTagTable::getObjectTaggedWithQuery('Article', array('tag1', 'tag2'));
368     * $q->orderBy('posted_at DESC');
369     * $q->limit(10);
370     * $this->articles = $q->execute();
371     *
372     * @param  string    $model  Taggable model name
373     * @param  mixed     $tags   array of tags (can be a string where tags are
374     * comma separated)
375     * @param  Doctrine_Query  $q     Existing Doctrine_Query to hydrate
376     * @return Doctrine_Query
377     */
378     public static function getObjectTaggedWithQuery($model, $tags = array(), Doctrine_Query $q = null, $options = array())
379     {
380         $tags = TaggableToolkit::explodeTagString($tags);
381
382         if (is_string($tags))
383         {
384             $tags = array($tags);
385         }
386
387         if (!class_exists($model) || !PluginTagTable::isDoctrineModelClass($model))
388         {
389             throw new sfDoctrineException(sprintf('The class "%s" does not exist, or it is not a model class.', $model));
390         }
391
392         if (!$q instanceof Doctrine_Query)
393         {
394             $q = Doctrine_Query::create()->from($model);
395         }
396
397         $taggings = self::getTaggings($tags, array_merge(array('model' => $model), $options));
398         $tagging = isset($taggings[$model]) ? $taggings[$model] : array();
399
400         if (empty($tagging))
401         {
402           $q->where('false');
403         }
404         else
405         {
406           $q->whereIn($model . '.id', $tagging);
407         }
408
409         return $q;
410     }
411
412     /**
413     * No comment
414     */
415     public static function isDoctrineModelClass($class)
416     {
417         return true;
418     }
419
420     /**
421     * Returns the taggings associated to one tag or a set of tags.
422     *
423     * The second optionnal parameter permits to restrict the results with
424     * different criterias
425     *
426     * @param      mixed       $tags      Array of tag strings or string
427     * @param      array       $options   Array of options parameters
428     * @return     array
429     */
430     protected static function getTaggings($tags = array(), $options = array())
431     {
432         $tags = TaggableToolkit::explodeTagString($tags);
433
434         if (is_string($tags))
435         {
436             $tags = array($tags);
437         }
438
439         $q = Doctrine_Query::create()
440                            ->select('DISTINCT t.id')
441                            ->from('Tag t INDEXBY t.id');
442
443         if(count($tags) > 0)
444         {
445             $q->whereIn('t.name', $tags);
446         }
447
448         if (isset($options['triple']))
449         {
450             $q->addWhere('t.is_triple = ?', $options['triple']);
451         }
452
453         if (isset($options['namespace']))
454         {
455             $q->addWhere('t.triple_namespace = ?', $options['namespace']);
456         }
457
458         if (isset($options['key']))
459         {
460             $q->addWhere('t.triple_key = ?', $options['key']);
461         }
462
463         if (isset($options['value']))
464         {
465             $q->addWhere('t.triple_value = ?', $options['value']);
466         }
467
468         if (!isset($options['nb_common_tags']) || ($options['nb_common_tags'] > count($tags)))
469         {
470             $options['nb_common_tags'] = count($tags);
471         }
472
473         $tag_ids = $q->execute(array(), Doctrine_Core::HYDRATE_ARRAY);
474
475         if (0 == count($tag_ids))
476         {
477             // if not tag has been found, then there will be no tagging
478             return array();
479         }
480
481         $q = Doctrine_Query::create()
482                            ->select('tg.taggable_id')
483                            ->from('Tagging tg')
484                            ->whereIn('tg.tag_id', array_keys($tag_ids))
485                            ->groupBy('tg.taggable_id')
486                            ->having('count(tg.taggable_model) >= ?', $options['nb_common_tags']);
487
488         // Taggable model class option
489         if (isset($options['model']))
490         {
491             if (!class_exists($options['model'])) // TODO: add a test to that's a doctrine model...
492             {
493                 throw new sfDoctrineException(sprintf('The class "%s" does not exist, or it is not a model class.',
494                                       $options['model']));
495             }
496
497             $q->addWhere('tg.taggable_model = ?', $options['model']);
498         }
499         else
500         {
501             $q->addSelect('tg.taggable_model')->addGroupBy('tg.taggable_model');
502         }
503
504         $results = $q->execute(array(), Doctrine_Core::HYDRATE_ARRAY);
505
506         $taggings = array();
507
508         foreach($results as $rs)
509         {
510             if(isset($options['model']))
511             {
512                 $model = $options['model'];
513             }
514             else
515             {
516                 $model = $rs['taggable_model'];
517             }
518
519             if (!isset($taggings[$model]))
520             {
521                 $taggings[$model] = array();
522             }
523
524             $taggings[$model][] = $rs['taggable_id'];
525         }
526
527         return $taggings;
528     }
529
530     /**
531      * Remove Tags without associations in Tagging table
532      *
533      * @return array
534      */
535     public static function purgeOrphans()
536     {
537         $q = Doctrine_Core::getTable('Tag')->createQuery('t INDEXBY t.id')
538             ->select('t.id')
539             ->addWhere('NOT EXISTS (SELECT tg.id FROM Tagging tg WHERE tg.tag_id = t.id)');
540
541         $orphans = $q->execute();
542         $orphan_data = $orphans->toArray(false);
543         $orphans->delete();
544         return $orphan_data;
545     }
546
547     /**
548      * Remove redundant taggings
549      */
550     public static function purgeRedundantTaggings()
551     {
552       // Doctrine makes a mangled mess of my subqueries here, so talk to PDO
553       $pdo = Doctrine_Manager::connection()->getDbh();
554       return $pdo->exec("delete from tagging where id not in (select * from (select min(tagging.id) from tagging inner join tag on tagging.tag_id = tag.id group by concat(tag.id, ':', tagging.taggable_id, ':', tagging.taggable_model)) as redundant);");
555     }
556
557     /**
558      * Retrieves tags with the number of taggings for a given set of models, can be accessed using ->$model
559      *
560      * @param Array $models
561      * @param Doctrine_Query $q
562      * @return Doctrine_Query
563      */
564     public function queryTagsWithCountsByModel($models, $q = null)
565     {
566       $q->leftJoin('r.Tagging tg')->addSelect('r.*');
567       foreach($models as $model)
568       {
569         $q->addSelect("SUM(IF(tg.taggable_model = '$model' , 1, 0)) AS ".$model."Count");
570       }
571       $q->groupBy('r.id');
572       
573       return $q;
574     }
575
576     /**
577      *
578      * @param $old_id id of tag to be merged
579      * @param $new_id id of tag to be merged in to
580      */
581     public function mergeTags($old_id, $new_id)
582     {
583       Doctrine_Query::create()
584         ->select('old.*')
585         ->from("tagging old, tagging new")
586         ->where("old.tag_id = ? AND new.tag_id = ? AND old.taggable_id = new.taggable_id AND old.taggable_model = new.taggable_model", array($old_id, $new_id))
587         ->execute()->delete();
588
589       Doctrine_Core::getTable('Tagging')->createQuery()
590         ->update()
591         ->set('tag_id', $new_id)
592         ->where('tag_id = ?', $old_id)
593         ->execute();
594     }
595 }
Note: See TracBrowser for help on using the browser.