Overview

Namespaces

  • Charcoal
    • Object
    • User
      • Acl

Classes

  • Charcoal\Object\Content
  • Charcoal\Object\ObjectRevision
  • Charcoal\Object\ObjectRoute
  • Charcoal\Object\ObjectSchedule
  • Charcoal\Object\UserData
  • Charcoal\User\AbstractUser
  • Charcoal\User\Acl\Manager
  • Charcoal\User\Acl\Permission
  • Charcoal\User\Acl\PermissionCategory
  • Charcoal\User\Acl\Role
  • Charcoal\User\Authenticator
  • Charcoal\User\Authorizer
  • Charcoal\User\AuthToken
  • Charcoal\User\AuthTokenMetadata
  • Charcoal\User\GenericUser

Interfaces

  • Charcoal\Object\ArchivableInterface
  • Charcoal\Object\CategorizableInterface
  • Charcoal\Object\CategorizableMultipleInterface
  • Charcoal\Object\CategoryInterface
  • Charcoal\Object\ContentInterface
  • Charcoal\Object\HierarchicalInterface
  • Charcoal\Object\ObjectRevisionInterface
  • Charcoal\Object\ObjectRouteInterface
  • Charcoal\Object\ObjectScheduleInterface
  • Charcoal\Object\PublishableInterface
  • Charcoal\Object\RevisionableInterface
  • Charcoal\Object\RoutableInterface
  • Charcoal\Object\UserDataInterface
  • Charcoal\User\UserInterface

Traits

  • Charcoal\Object\ArchivableTrait
  • Charcoal\Object\CategorizableMultipleTrait
  • Charcoal\Object\CategorizableTrait
  • Charcoal\Object\CategoryTrait
  • Charcoal\Object\HierarchicalTrait
  • Charcoal\Object\PublishableTrait
  • Charcoal\Object\RevisionableTrait
  • Charcoal\Object\RoutableTrait
  • Overview
  • Namespace
  • Class
  1: <?php
  2: namespace Charcoal\Object;
  3: 
  4: use \DateTime;
  5: use \InvalidArgumentException;
  6: use \RuntimeException;
  7: 
  8: use \Pimple\Container;
  9: 
 10: // Dependencies from 'charcoal-core'
 11: use \Charcoal\Model\AbstractModel;
 12: use \Charcoal\Loader\CollectionLoader;
 13: 
 14: // Dependency from 'charcoal-factory'
 15: use \Charcoal\Factory\FactoryInterface;
 16: 
 17: // Local Dependency
 18: use \Charcoal\Object\ObjectRouteInterface;
 19: 
 20: /**
 21:  * Represents a route to an object (i.e., a permalink).
 22:  *
 23:  * Intended to be used to collect all routes related to models
 24:  * under a single source (e.g., database table).
 25:  *
 26:  * {@see Charcoal\Object\ObjectRevision} for a similar model that aggregates data
 27:  * under a common source.
 28:  *
 29:  * Requirements:
 30:  *
 31:  * - 'model/factory'
 32:  * - 'model/collection/loader'
 33:  */
 34: class ObjectRoute extends AbstractModel implements
 35:     ObjectRouteInterface
 36: {
 37:     /**
 38:      * A route is active by default.
 39:      *
 40:      * @var boolean
 41:      */
 42:     protected $active = true;
 43: 
 44:     /**
 45:      * The route's URI.
 46:      *
 47:      * @var string
 48:      */
 49:     protected $slug;
 50: 
 51:     /**
 52:      * The route's locale.
 53:      *
 54:      * @var string
 55:      */
 56:     protected $lang;
 57: 
 58:     /**
 59:      * The creation timestamp.
 60:      *
 61:      * @var DateTime
 62:      */
 63:     protected $creationDate;
 64: 
 65:     /**
 66:      * The last modification timestamp.
 67:      *
 68:      * @var DateTime
 69:      */
 70:     protected $lastModificationDate;
 71: 
 72:     /**
 73:      * The foreign object type related to this route.
 74:      *
 75:      * @var string
 76:      */
 77:     protected $routeObjType;
 78: 
 79:     /**
 80:      * The foreign object ID related to this route.
 81:      *
 82:      * @var mixed
 83:      */
 84:     protected $routeObjId;
 85: 
 86:     /**
 87:      * The foreign object's template identifier.
 88:      *
 89:      * @var string
 90:      */
 91:     protected $routeTemplate;
 92: 
 93:     /**
 94:      * Store a copy of the original—_preferred_—slug before alterations are made.
 95:      *
 96:      * @var string
 97:      */
 98:     private $originalSlug;
 99: 
100:     /**
101:      * Store the increment used to create a unique slug.
102:      *
103:      * @var integer
104:      */
105:     private $slugInc = 0;
106: 
107:     /**
108:      * Store the factory instance for the current class.
109:      *
110:      * @var FactoryInterface
111:      */
112:     private $modelFactory;
113: 
114:     /**
115:      * Store the collection loader for the current class.
116:      *
117:      * @var CollectionLoader
118:      */
119:     private $collectionLoader;
120: 
121:     /**
122:      * Inject dependencies from a DI Container.
123:      *
124:      * @param Container $container A dependencies container instance.
125:      * @return void
126:      */
127:     public function setDependencies(Container $container)
128:     {
129:         $this->setModelFactory($container['model/factory']);
130:         $this->setCollectionLoader($container['model/collection/loader']);
131:     }
132: 
133:     /**
134:      * Event called before _creating_ the object.
135:      *
136:      * @see    Charcoal\Source\StorableTrait::preSave() For the "create" Event.
137:      * @return boolean
138:      */
139:     public function preSave()
140:     {
141:         $this->generateUniqueSlug();
142:         $this->setCreationDate('now');
143:         $this->setLastModificationDate('now');
144: 
145:         return parent::preSave();
146:     }
147: 
148:     /**
149:      * Event called before _updating_ the object.
150:      *
151:      * @see    Charcoal\Source\StorableTrait::preUpdate() For the "update" Event.
152:      * @param  array $properties Optional. The list of properties to update.
153:      * @return boolean
154:      */
155:     public function preUpdate(array $properties = null)
156:     {
157:         $this->setCreationDate('now');
158:         $this->setLastModificationDate('now');
159: 
160:         return parent::preUpdate($properties);
161:     }
162: 
163:     /**
164:      * Determine if the current slug is unique.
165:      *
166:      * @return boolean
167:      */
168:     public function isSlugUnique()
169:     {
170:         $proto  = $this->modelFactory()->get(self::class);
171:         $loader = $this->collectionLoader();
172:         $loader
173:             ->reset()
174:             ->setModel($proto)
175:             ->addFilter('active', true)
176:             ->addFilter('slug', $this->slug())
177:             ->addOrder('creation_date', 'desc')
178:             ->setPage(1)
179:             ->setNumPerPage(1);
180:         $routes = $loader->load()->objects();
181:         if (!$routes) {
182:             return true;
183:         }
184:         $obj = reset($routes);
185:         if (!$obj->id()) {
186:             return true;
187:         }
188:         if ($obj->id() === $this->id()) {
189:             return true;
190:         }
191:         if ($obj->routeObjId() === $this->routeObjId() &&
192:             $obj->routeObjType() === $this->routeObjType() &&
193:             $obj->lang() === $this->lang()) {
194:             $this->setId($obj->id());
195:             return true;
196:         }
197:         return false;
198:     }
199: 
200:     /**
201:      * Generate a unique URL slug for routable object.
202:      *
203:      * @return self
204:      */
205:     public function generateUniqueSlug()
206:     {
207:         if (!$this->isSlugUnique()) {
208:             if (!$this->originalSlug) {
209:                 $this->originalSlug = $this->slug();
210:             }
211:             $this->slugInc++;
212:             $this->setSlug($this->originalSlug.'-'.$this->slugInc);
213:             return $this->generateUniqueSlug();
214:         }
215:         return $this;
216:     }
217: 
218:     /**
219:      * Set an object model factory.
220:      *
221:      * @param FactoryInterface $factory The model factory, to create objects.
222:      * @return self
223:      */
224:     protected function setModelFactory(FactoryInterface $factory)
225:     {
226:         $this->modelFactory = $factory;
227:         return $this;
228:     }
229: 
230:     /**
231:      * Set a model collection loader.
232:      *
233:      * @param CollectionLoader $loader The collection loader.
234:      * @return self
235:      */
236:     protected function setCollectionLoader(CollectionLoader $loader)
237:     {
238:         $this->collectionLoader = $loader;
239:         return $this;
240:     }
241: 
242:     /**
243:      * Set the object route URI.
244:      *
245:      * @param string $slug The route.
246:      * @return self
247:      */
248:     public function setSlug($slug)
249:     {
250:         $this->slug = $slug;
251: 
252:         return $this;
253:     }
254: 
255:     /**
256:      * Set the locale of the object route.
257:      *
258:      * @param string $lang The route's locale.
259:      * @return self
260:      */
261:     public function setLang($lang)
262:     {
263:         $this->lang = $lang;
264: 
265:         return $this;
266:     }
267: 
268:     /**
269:      * @param \DateTime|string|null $creationDate The Creation Date date/time.
270:      * @throws InvalidArgumentException If the date/time is invalid.
271:      * @return self
272:      */
273:     public function setCreationDate($creationDate)
274:     {
275:         if ($creationDate === null) {
276:             $this->creationDate = null;
277:             return $this;
278:         }
279: 
280:         if (is_string($creationDate)) {
281:             $creationDate = new DateTime($creationDate);
282:         }
283:         if (!($creationDate instanceof DateTime)) {
284:             throw new InvalidArgumentException(
285:                 'Invalid "Creation Date" value. Must be a date/time string or a DateTime object.'
286:             );
287:         }
288:         $this->creationDate = $creationDate;
289: 
290:         return $this;
291:     }
292: 
293:     /**
294:      * @param \DateTime|string|null $lastModificationDate The Last modification date date/time.
295:      * @throws InvalidArgumentException If the date/time is invalid.
296:      * @return self
297:      */
298:     public function setLastModificationDate($lastModificationDate)
299:     {
300:         if ($lastModificationDate === null) {
301:             $this->lastModificationDate = null;
302:             return $this;
303:         }
304:         if (is_string($lastModificationDate)) {
305:             $lastModificationDate = new DateTime($lastModificationDate);
306:         }
307:         if (!($lastModificationDate instanceof DateTime)) {
308:             throw new InvalidArgumentException(
309:                 'Invalid "Creation Date" value. Must be a date/time string or a DateTime object.'
310:             );
311:         }
312:         $this->lastModificationDate = $lastModificationDate;
313:         return $this;
314:     }
315: 
316:     /**
317:      * Set the foreign object type related to this route.
318:      *
319:      * @param string $type The object type.
320:      * @return self
321:      */
322:     public function setRouteObjType($type)
323:     {
324:         $this->routeObjType = $type;
325: 
326:         return $this;
327:     }
328: 
329:     /**
330:      * Set the foreign object ID related to this route.
331:      *
332:      * @param string $id The object ID.
333:      * @return self
334:      */
335:     public function setRouteObjId($id)
336:     {
337:         $this->routeObjId = $id;
338: 
339:         return $this;
340:     }
341: 
342:     /**
343:      * Set the foreign object's template identifier.
344:      *
345:      * @param string $template The template identifier.
346:      * @return self
347:      */
348:     public function setRouteTemplate($template)
349:     {
350:         $this->routeTemplate = $template;
351: 
352:         return $this;
353:     }
354: 
355:     /**
356:      * Retrieve the object model factory.
357:      *
358:      * @throws RuntimeException If the model factory was not previously set.
359:      * @return FactoryInterface
360:      */
361:     public function modelFactory()
362:     {
363:         if (!isset($this->modelFactory)) {
364:             throw new RuntimeException(
365:                 sprintf('Model Factory is not defined for "%s"', get_class($this))
366:             );
367:         }
368:         return $this->modelFactory;
369:     }
370: 
371:     /**
372:      * Retrieve the model collection loader.
373:      *
374:      * @throws RuntimeException If the collection loader was not previously set.
375:      * @return CollectionLoader
376:      */
377:     public function collectionLoader()
378:     {
379:         if (!isset($this->collectionLoader)) {
380:             throw new RuntimeException(
381:                 sprintf('Collection Loader is not defined for "%s"', get_class($this))
382:             );
383:         }
384:         return $this->collectionLoader;
385:     }
386: 
387:     /**
388:      * Retrieve the object route.
389:      *
390:      * @return string
391:      */
392:     public function slug()
393:     {
394:         return $this->slug;
395:     }
396: 
397:     /**
398:      * Retrieve the locale of the object route.
399:      *
400:      * @return string
401:      */
402:     public function lang()
403:     {
404:         return $this->lang;
405:     }
406: 
407:     /**
408:      * Creation date.
409:      * @return DateTime Creation date.
410:      */
411:     public function creationDate()
412:     {
413:         return $this->creationDate;
414:     }
415: 
416:     /**
417:      * Last modification date.
418:      * @return DateTime Last modification date.
419:      */
420:     public function lastModificationDate()
421:     {
422:         return $this->lastModificationDate;
423:     }
424: 
425:     /**
426:      * Retrieve the foreign object type related to this route.
427:      *
428:      * @return string
429:      */
430:     public function routeObjType()
431:     {
432:         return $this->routeObjType;
433:     }
434: 
435:     /**
436:      * Retrieve the foreign object ID related to this route.
437:      *
438:      * @return string
439:      */
440:     public function routeObjId()
441:     {
442:         return $this->routeObjId;
443:     }
444: 
445:     /**
446:      * Retrieve the foreign object's template identifier.
447:      *
448:      * @return string
449:      */
450:     public function routeTemplate()
451:     {
452:         return $this->routeTemplate;
453:     }
454: 
455:     /**
456:      * Alias of {@see self::slug()}.
457:      *
458:      * @return string
459:      */
460:     public function __toString()
461:     {
462:         return (string)$this->slug();
463:     }
464: }
465: 
API documentation generated by ApiGen