Overview

Namespaces

  • Alpha
    • Controller
      • Front
    • Exception
    • Model
      • Type
    • Task
    • Util
      • Backup
      • Cache
      • Code
        • Highlight
        • Metric
      • Config
      • Convertor
      • Email
      • Extension
      • Feed
      • File
      • Graph
      • Helper
      • Http
        • Filter
        • Session
      • Image
      • Logging
      • Search
      • Security
    • View
      • Renderer
        • Html
        • Json
      • Widget

Classes

  • ActionLog
  • ActiveRecord
  • ActiveRecordProviderFactory
  • ActiveRecordProviderMySQL
  • ActiveRecordProviderSQLite
  • Article
  • ArticleComment
  • ArticleVote
  • BadRequest
  • BlacklistedClient
  • BlacklistedIP
  • Person
  • Rights
  • Tag

Interfaces

  • ActiveRecordProviderInterface
  • Overview
  • Namespace
  • Class
  • Tree
  1: <?php
  2: 
  3: namespace Alpha\Model;
  4: 
  5: use Alpha\Model\Type\String;
  6: use Alpha\Model\Type\Integer;
  7: use Alpha\Exception\AlphaException;
  8: use Alpha\Exception\IllegalArguementException;
  9: use Alpha\Exception\CustomQueryException;
 10: use Alpha\Util\Config\ConfigProvider;
 11: use Alpha\Util\Cache\CacheProviderFactory;
 12: use Alpha\Util\Helper\Validator;
 13: use Alpha\Util\Logging\Logger;
 14: 
 15: /**
 16:  * The tag class used in tag clouds and search.
 17:  *
 18:  * @since 1.0
 19:  *
 20:  * @author John Collins <dev@alphaframework.org>
 21:  * @license http://www.opensource.org/licenses/bsd-license.php The BSD License
 22:  * @copyright Copyright (c) 2015, John Collins (founder of Alpha Framework).
 23:  * All rights reserved.
 24:  *
 25:  * <pre>
 26:  * Redistribution and use in source and binary forms, with or
 27:  * without modification, are permitted provided that the
 28:  * following conditions are met:
 29:  *
 30:  * * Redistributions of source code must retain the above
 31:  *   copyright notice, this list of conditions and the
 32:  *   following disclaimer.
 33:  * * Redistributions in binary form must reproduce the above
 34:  *   copyright notice, this list of conditions and the
 35:  *   following disclaimer in the documentation and/or other
 36:  *   materials provided with the distribution.
 37:  * * Neither the name of the Alpha Framework nor the names
 38:  *   of its contributors may be used to endorse or promote
 39:  *   products derived from this software without specific
 40:  *   prior written permission.
 41:  *
 42:  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 43:  * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 44:  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 45:  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 46:  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 47:  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 48:  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 49:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 50:  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 51:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 52:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 53:  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 54:  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 55:  * </pre>
 56:  */
 57: class Tag extends ActiveRecord
 58: {
 59:     /**
 60:      * The name of the class of the object which is tagged.
 61:      *
 62:      * @var Alpha\Model\Type\String
 63:      *
 64:      * @since 1.0
 65:      */
 66:     protected $taggedClass;
 67: 
 68:     /**
 69:      * The OID of the object which is tagged.
 70:      *
 71:      * @var Alpha\Model\Type\Integer
 72:      *
 73:      * @since 1.0
 74:      */
 75:     protected $taggedOID;
 76: 
 77:     /**
 78:      * The content of the tag.
 79:      *
 80:      * @var Alpha\Model\Type\String
 81:      *
 82:      * @since 1.0
 83:      */
 84:     protected $content;
 85: 
 86:     /**
 87:      * An array of data display labels for the class properties.
 88:      *
 89:      * @var array
 90:      *
 91:      * @since 1.0
 92:      */
 93:     protected $dataLabels = array('OID' => 'Tag ID#', 'taggedClass' => 'Class Name', 'taggedOID' => 'Tagged Object ID#', 'content' => 'Tag');
 94: 
 95:     /**
 96:      * The name of the database table for the class.
 97:      *
 98:      * @var string
 99:      *
100:      * @since 1.0
101:      */
102:     const TABLE_NAME = 'Tag';
103: 
104:     /**
105:      * Trace logger.
106:      *
107:      * @var Alpha\Util\Logging\Logger
108:      *
109:      * @since 1.0
110:      */
111:     private static $logger = null;
112: 
113:     /**
114:      * The constructor.
115:      *
116:      * @since 1.0
117:      */
118:     public function __construct()
119:     {
120:         self::$logger = new Logger('Tag');
121: 
122:         // ensure to call the parent constructor
123:         parent::__construct();
124:         $this->taggedClass = new String();
125:         $this->taggedOID = new Integer();
126:         $this->content = new String();
127: 
128:         $this->markUnique('taggedClass', 'taggedOID', 'content');
129:     }
130: 
131:     /**
132:      * Returns an array of Tags matching the class and OID provided.
133:      *
134:      * @param $taggedClass The class name of the DAO that has been tagged (with namespace).
135:      * @param $taggedOID The Object ID of the DAO that has been tagged.
136:      *
137:      * @return array
138:      *
139:      * @since 1.0
140:      *
141:      * @throws Alpha\Exception\AlphaException
142:      * @throws Alpha\Exception\IllegalArguementException
143:      */
144:     public function loadTags($taggedClass, $taggedOID)
145:     {
146:         $config = ConfigProvider::getInstance();
147: 
148:         if ($taggedClass == '' || $taggedOID == '') {
149:             throw new IllegalArguementException('The taggedClass or taggedOID provided are empty');
150:         }
151: 
152:         $provider = ActiveRecordProviderFactory::getInstance($config->get('db.provider.name'), $this);
153: 
154:         try {
155:             $tags = $provider->loadAllByAttributes(array('taggedOID', 'taggedClass'), array($taggedOID, $taggedClass));
156: 
157:             return $tags;
158:         } catch (RecordNotFoundException $bonf) {
159:             return array();
160:         } catch (Exception $e) {
161:             self::$logger->error($e->getMessage());
162:             throw new AlphaException($e->getMessage());
163:         }
164:     }
165: 
166:     /**
167:      * Returns a hash array of the most popular tags based on their occurence in the database,
168:      * ordered by alphabet and restricted to the a count matching the $limit supplied.  The
169:      * returned has array uses the tag content as a key and the database value as a value.
170:      *
171:      * @param $limit
172:      *
173:      * @return array
174:      *
175:      * @since 1.0
176:      *
177:      * @throws Alpha\Exception\AlphaException
178:      */
179:     public static function getPopularTagsArray($limit)
180:     {
181:         $config = ConfigProvider::getInstance();
182: 
183:         $provider = ActiveRecordProviderFactory::getInstance($config->get('db.provider.name'), new self());
184: 
185:         $sqlQuery = 'SELECT content, count(*) as count FROM '.self::TABLE_NAME." GROUP BY content ORDER BY count DESC LIMIT $limit";
186: 
187:         try {
188:             $result = $provider->query($sqlQuery);
189:         } catch (CustomQueryException $e) {
190:             throw new AlphaException('Failed to query the tags table, error is ['.$e->getMessage().']');
191: 
192:             return array();
193:         }
194: 
195:         // now build an array of tags to be returned
196:         $popTags = array();
197: 
198:         foreach ($result as $row) {
199:             $popTags[$row['content']] = $row['count'];
200:         }
201: 
202:         // sort the array by content key before returning
203:         ksort($popTags);
204: 
205:         return $popTags;
206:     }
207: 
208:     /**
209:      * Splits the passed content by spaces, filters (removes) stop words from stopwords.ini,
210:      * and returns an array of Tag instances.
211:      *
212:      * @param $content
213:      * @param $taggedClass Optionally provide a BO class name (with namespace)
214:      * @param $taggedOID Optionally provide a BO instance OID
215:      * @param $applyStopwords Defaults true, set to false if you want to ignore the stopwords.
216:      *
217:      * @return array
218:      *
219:      * @throws Alpha\Exception\AlphaException
220:      *
221:      * @since 1.0
222:      */
223:     public static function tokenize($content, $taggedClass = '', $taggedOID = '', $applyStopwords = true)
224:     {
225:         if (self::$logger == null) {
226:             self::$logger = new Logger('Tag');
227:         }
228: 
229:         $config = ConfigProvider::getInstance();
230: 
231:         // apply stop words
232:         $lowerWords = preg_split("/[\s,.:-]+/", $content);
233: 
234:         array_walk($lowerWords, 'Alpha\Model\Tag::lowercaseArrayElement');
235: 
236:         if ($applyStopwords) {
237:             if (file_exists($config->get('app.root').'config/stopwords-'.$config->get('search.stop.words.size').'.ini')) {
238:                 $stopwords = file($config->get('app.root').'config/stopwords-'.$config->get('search.stop.words.size').'.ini', FILE_IGNORE_NEW_LINES);
239:             } elseif (file_exists($config->get('app.root').'Alpha/stopwords-'.$config->get('search.stop.words.size').'.ini')) {
240:                 $stopwords = file($config->get('app.root').'Alpha/stopwords-'.$config->get('search.stop.words.size').'.ini', FILE_IGNORE_NEW_LINES);
241:             } else {
242:                 throw new AlphaException('Unable to find a stopwords-'.$config->get('search.stop.words.size').'.ini file in the application!');
243:             }
244: 
245:             array_walk($stopwords, 'Alpha\Model\Tag::lowercaseArrayElement');
246: 
247:             $filtered = array_diff($lowerWords, $stopwords);
248:         } else {
249:             $filtered = $lowerWords;
250:         }
251: 
252:         $tagObjects = array();
253:         $tagContents = array();
254:         foreach ($filtered as $tagContent) {
255:             // we only want to create word tags
256:             if (Validator::isAlpha($tagContent)) {
257:                 // just making sure that we haven't added this one in already
258:                 if (!in_array($tagContent, $tagContents) && !empty($tagContent)) {
259:                     $tag = new self();
260:                     $tag->set('content', trim(mb_strtolower($tagContent)));
261:                     if (!empty($taggedClass)) {
262:                         $tag->set('taggedClass', $taggedClass);
263:                     }
264:                     if (!empty($taggedOID)) {
265:                         $tag->set('taggedOID', $taggedOID);
266:                     }
267: 
268:                     array_push($tagObjects, $tag);
269:                     array_push($tagContents, $tagContent);
270:                 }
271:             }
272:         }
273: 
274:         self::$logger->debug('Tags generated: ['.var_export($tagContents, true).']');
275: 
276:         return $tagObjects;
277:     }
278: 
279:     /**
280:      * Applies trim() and strtolower to the array element passed by reference.
281:      *
282:      * @param $element
283:      * @param $key (not required)
284:      */
285:     private static function lowercaseArrayElement(&$element, $key)
286:     {
287:         $element = trim(mb_strtolower($element));
288:     }
289: 
290:     /**
291:      * Cleans tag content by removing white spaces and converting to lowercase.
292:      *
293:      * @param $content
294:      *
295:      * @return string
296:      */
297:     public static function cleanTagContent($content)
298:     {
299:         return trim(mb_strtolower(str_replace(' ', '', $content)));
300:     }
301: 
302:     /**
303:      * Remove the tag search matches from the cache.
304:      *
305:      * @since 1.2.4
306:      */
307:     protected function after_save_callback()
308:     {
309:         $config = ConfigProvider::getInstance();
310: 
311:         if ($config->get('cache.provider.name') != '') {
312:             try {
313:                 $cache = CacheProviderFactory::getInstance($config->get('cache.provider.name'));
314:                 $cache->delete($this->get('content'));
315:             } catch (\Exception $e) {
316:                 self::$logger->error('Error while attempting to remove search matches array from the ['.$config->get('cache.provider.name').'] 
317:                     instance: ['.$e->getMessage().']');
318:             }
319:         }
320:     }
321: 
322:     /**
323:      * Remove the tag search matches from the cache.
324:      *
325:      * @since 1.2.4
326:      */
327:     protected function before_delete_callback()
328:     {
329:         $this->after_save_callback();
330:     }
331: }
332: 
Alpha Framework 2.0.4 API Documentation API documentation generated by ApiGen 2.8.0