Replaced with https://github.com/dave-redfern/somnambulist-domain
This project has been replaced with a generic domain library that combines several packages into one
for easier maintenace. Please note that many of these behaviours have since been removed entirely., (*1)
Behaviours for Laravel-Doctrine ORM
Adds some very common traits, contracts and event subscribers that can be used with the Laravel-Doctrine ORM
package, replacing Gedmo Blameable and Timestampable as well as a UUID pre-persist behaviour., (*2)
This library is very opinionated on naming and Doctrine config. Each of the behaviours and all
the traits work on the basis that Doctrine is running with configuration files and not annotations.
The names of each field are set within the traits., (*3)
Requirements
- PHP 7+
- laravel 5.3+
- laravel-doctrine/orm
BC Breaks
1.0.0
Earlier versions of this package featured Sluggable and Uuid listeners, these have since been removed
as the UUID and slug should be generated by the Application before persisting / flushing your entities., (*4)
In addition, many of the interfaces have either redefined, or removed entirely the requirement for
setters, as many of the property changes should be made through controlled state transitions. For
example: timestamps should be initialised and createdAt not readily modifiable; blamable should
set the creator but not allow modification, UUIDs should never change after the fact., (*5)
The full list of changes are:, (*6)
- Blamable
** removal of setCreatedBy, setUpdatedBy
** added blameCreator() blameUpdater()
** trait implements the interface and blameCreator() does not allow changes
- NumericallySortable
** removal of setOrdinal
** added updateSortingOrder()
- Publishable
** removal of setPublishedAt
** trait updated to remove setPublishedAt() method
- Sluggable
** removal of setSlug
** removal of SluggableEventSubscriber
- Timestampable
** removal of setCreatedAt, setUpdatedAt
** added initializeTimestamps() updateTimestamps()
** trait implements the interface and initializeTimestamps() does not reset dates
- UniversallyIdentifiable
** removal of setUuid
** removal of UuidEventSubscriber
- Versionable
** removal of setVersion
** changed initial value in trait to 0
** incrementVersion is now called on prePersist as well as on preUpdate
In the case of unique identifiers such as slug and UUID these should be generated for the entity
and passed in during first creation., (*7)
Installation
Install using composer, or checkout / pull the files from github.com., (*8)
- composer install somnambulist/laravel-doctrine-behaviours
Enabling in Doctrine
To enable the behaviours, add each EventSubscriber to the config/doctrine.php file:, (*9)
'managers' => [
'default' => [
'events' => [
'subscribers' => [
\Somnambulist\Doctrine\EventSubscribers\BlamableEventSubscriber::class,
\Somnambulist\Doctrine\EventSubscribers\TimestampableEventSubscriber::class,
\Somnambulist\Doctrine\EventSubscribers\VersionableEventSubscriber::class,
]
],
]
],
-
Note: you only need to add the subscribers you actively want to use.
To ensure Carbon is used in your entities, and the following to the types:, (*10)
'custom_types' => [
'date' => \Somnambulist\Doctrine\Types\DateType::class,
'datetime' => \Somnambulist\Doctrine\Types\DateTimeType::class,
'datetimetz' => \Somnambulist\Doctrine\Types\DateTimeTzType::class,
'time' => \Somnambulist\Doctrine\Types\TimeType::class,
],
-
Note: the type overrides are required when using TimestampableEventSubscriber.
-
Note: these behaviours are intended to be used with meta-data files not annotations!
JsonCollection
To enable the JsonCollectionType, add the following to the custom_types in the doctrine.php:, (*11)
'json_collection' => \Somnambulist\Doctrine\Types\JsonCollectionType::class,
This type hydrates a JSON encoded string into an ArrayCollection object instead of a
standard PHP array. Depending on use case this may be more useful and it allows consistent
collection handling within your Entity., (*12)
To use the JsonCollection, in your mapping files set the type to: json_collection
:, (*13)
// simple example
Entity:
fields:
properties:
type: json_collection
Then initialise the propoerty in your entities constructor., (*14)
-
Note: if the JSON data is empty, an empty ArrayCollection will be used.
-
Note: this does not replace the standard json_array; you can use both.
Service Provider
A Laravel service provider is included that allows defining repositories in a config file.
Add the service provider to your main app.php - after the DoctrineServiceProvider., (*15)
\Somnambulist\Doctrine\Providers\BehavioursServiceProvider::class,
Publish the vendors information, and two new config files will be added:, (*16)
- config/doctrine_behaviours.php
- config/doctrine_repositories.php
Behaviours contains settings for the make:entity
console command that makes it
easier to add a new entity and repository., (*17)
Repositories allows you to configure repositories so they can be type-hinted and
resolved by the dependency injection container (auto-wiring)., (*18)
The following options are required:, (*19)
- repository - the repository class, can be EntityRepository::class
- entity - the class name of the entity the repository is for
The following are optional:, (*20)
- alias - a shorter alias e.g. app.user.repository
- tags - any tags to add to the reference in the container e.g.
[ 'repository' ]
- em - an alternative entity manager that manages this entity e.g. 'my_manager'
Behaviours / Traits
Blamable
Blamable adds createdBy and updatedBy and then attempts to set the name of the User
who performed the create/update. This is extracted from the auth()->user() object.
The User object is checked in turn for one of the following:, (*21)
- UUID (UuidContract / getUuid)
- Username (getUsername)
- Email (getEmail)
- Id (getId)
If the User (somehow) does not implement any of those, the class and identifier are
pulled and attempted to be located from a Doctrine repository and then the same check
is made again on the found entity., (*22)
If there is no user a default is applied: 'system', (*23)
This can be overridden by setting the environment value: DOCTRINE_BLAMABLE_DEFAULT_USER., (*24)
To add Blamable support, ensure your entity implements the Blamable contract. A trait
is provided that adds the appropriate methods:, (*25)
use Somnambulist\Doctrine\Contracts\Blamable as BlamableContract;
use Somnambulist\Doctrine\Traits\Blamable;
class MyEntity implements BlamableContract
{
use Blamable;
}
Be sure to update your mapping files to include the fields:, (*26)
fields:
createdBy:
type: string
length: 36
updatedBy:
type: string
length: 36
These fields should be at least 36 characters long as UUIDs may be used with them., (*27)
Sluggable
Sluggable adds getSlug i.e. a URL friendly text representation of the name.
A trait is included implementing the property and method., (*28)
Example usage:, (*29)
use Somnambulist\Doctrine\Contracts\Sluggable as SluggableContract;
use Somnambulist\Doctrine\Traits\Sluggable;
class MyEntity implements SluggableContract
{
use Sluggable;
}
Mapping file fields:, (*30)
fields:
slug:
type: string
length: 255
You should add a unique constraint to the slug since they should be unique., (*31)
Note: as slugs should be unique, your application code should generate them., (*32)
Timestampable
Timestampable adds createdAt / updatedAt fields and persistence to your entities. This
extension uses Carbon internally (just like Laravels Eloquent). It is not necessary to
populate these fields as they will be automatically set by the event subscriber. As
Carbon is used internally, the type mappings must be added to the config/doctrine.php
file., (*33)
To add timestampable, implement the contract and optionally include the trait:, (*34)
use Somnambulist\Doctrine\Contracts\Timestampable as TimestampableContract;
use Somnambulist\Doctrine\Traits\Timestampable;
class MyEntity implements TimestampableContract
{
use Timestampable;
}
Then add the following to your entity mapping files:, (*35)
fields:
createdAt:
type: datetime
updatedAt:
type: datetime
Now your entities will be tagged with the date/time they are created/updated., (*36)
Note: the default timezone is used. Be sure to set this before using. It is recommended
to set your PHP default timezone to UTC, and then translate in the UI., (*37)
Universally Identifiable
UniversallyIdentifiable adds a UUID field to your entity., (*38)
UUIDs should be generated by an appropriate uuid library (e.g.: ramsey/uuid). It is
recommended to use UUIDv4 random identifiers, unless you require re-generating UUIDs for
the same initial value., (*39)
Like the other behaviours to use UniversallyIdentifiable, implement the contract
and optionally use the trait:, (*40)
use Somnambulist\Doctrine\Contracts\UniversallyIdentifiable as UniversallyIdentifiableContract;
use Somnambulist\Doctrine\Traits\UniversallyIdentifiable;
class MyEntity implements UniversallyIdentifiableContract
{
use UniversallyIdentifiable;
}
This will ensure that this entity will be uniquely identifiable in any system - very useful
when exposing entities in an API., (*41)
Be sure to add a UUID field definition to your entity mapping files:, (*42)
uniqueConstraints:
uniq_table_name_here_uuid:
columns: [ uuid ]
fields:
uuid:
type: guid
It is a good idea to add a unique constraint to the UUID field just in case., (*43)
Note: that when using UUIDs you should ensure that this is a requirement in the constructor
of your entity., (*44)
Additional: you may wish to use ramsey/uuid-doctrine
so that UUIDs are always hydrated as
objects. In this instance set the type: to "uuid" and ensure your entity uses UuidInterface
as the type hint., (*45)
Versionable
Versionable adds a simple "version" property that is incremented on each update. The trait
sets the default (un-persisted) value to 0 (zero) with prePersist raising this to 1 (one)., (*46)
Be sure to add the following to you mapping files:, (*47)
fields:
version:
type: integer
The listener will then increment the version every time the entity is updated., (*48)
Others
In addition to the main behaviours there are several additional contracts / traits:, (*49)
- Identifiable - adds id / getId
- Nameable - adds name / getName
- NumericallySortable - adds ordinal / getOrdinal / updateSortingOrder
- Publishable - adds publishedAt / getPublishedAt / isPublished / publishAt / unPublish
- IdentifiableWithTimestamps - Identifiable, Timestampable
- Trackable - Identifiable, Nameable, Blamable, Timestampable
- GloballyTrackable - Identifiable, Nameable, Blamable, Timestampable, UniversallyIdentifiable
NumericallySortable adds a simple "ordinal" field to allow records to be sorted by an incrementing
integer value. This needs to be manually tracked in your entities e.g.: on add/remove against a colection
add a "renumber" method call that will iterate and re-number the items in the collection. A simple
CanRenumberCollection interface/trait is included but you may need something more sophisticated., (*50)
Trackable / GloballyTrackable wrap up the other traits / contracts providing a convenient
way to add everything either as an internal entity (Trackable) or a potentially externally facing
entity (GloballyTrackable)., (*51)
MakeEntityCommand
A helper command has been added for quickly generating the entity stub, repository and a repository
interface. This command presumes that your app folder structure will follow:, (*52)
- app/Contracts/*
- app/Repositories/*
- app/Support/*
The entity class will be created wherever the classname is set e.g.: App\Entities\MyEntity will be
created in app/Entities. If your base namespace is e.g: SomeProject\SomeModule, and the entity name
is SomeProject\SomeModule\Entities\MyEntity, the path will be: app/Entities., (*53)
The command will create an AppEntityRepository if it does not already exist., (*54)
To use the command, add it to the list of commands in your Console/Kernel.php file. Then you can
call it using:, (*55)
php artisan make:entity 'App\Entities\MyEntity'
Optionally you can add various options to add behaviour:, (*56)
php artisan make:entity 'App\Entities\MyEntity' -tps
Will make the entity Trackable, Publishable and Sluggable. Not all options can be used together.
If you select an in-compatible set of options, you will receive an error., (*57)
This command can be extended to add other options. Simple override the behaviourOptionMappings, (*58)
Links