-
Notifications
You must be signed in to change notification settings - Fork 13
classes
Here I will explain some of the classes which name may sound not really obvious (will omit things like Cache
or Repository
).
I wanted to keep the trait as light and clean as possible and also make this as testable as possible. Is for this reason Interactor
class has got the responsability of handling the interactions within the model. This class performs the set
and get
operations of the EAV attributes. When trying to access to a model attribute, if it corresponds to an EAV attribute, this class contains the logic for providing its value, create a new value instance, update collections or any other set/get interaction.
When reading values there are not too much things to check, if the value exists, we'll just format and provide it, otherwise we'll return null
or empty collections.
When setting values it gets a little bit more compled. We have 3 things to consider at the moment when setting values:
- Setting a single value which does not exist in database so we have to create the new model instance and relate to attribute and entity.
- Update the content for an existing single value model (database row).
- Replace an existing (or empty) collection of values with a new one so we have to trash the previous stored values (delete from database).
Eavquent let the user register multivalued attributes. In order to make playing with collections easier, I have included a new collection type which just extends Illuminate\Database\Eloquent\Collection
and provide some extra functionality. This class let us add and remove (remove yet to implement) values from the attribute. What it basically does is to let the user play with a collection class without having to worry about creating Value
model instances. A bit of code will help here:
// This is how it works
$entity->cities->add('Barcelona');
// And this is what you would have to do without this collection:
$value = new Varchar(['content' => 'Barcelona', 'attribute_id' => 1, 'entity_type' => 'App\Company', 'entity_id' => 1]);
$entity->cities->push($value);
// You could also pass an array
$entity->cities->add(['Barcelona', 'Paris']);
Collections may get improved and add more features but enough for the moment. Value base model replaces the Eloquent method newCollection
method in order to return this type of collections when playing with multivalued attributes.
This class is responsible for fetching the attributes from database and cache them. Attribute details are cached as they are unlikely to change once the user has performed its set-up. This class will provide a list of the registered attributes as well as the attributes related to a given entity. It works like this:
// Fetch all the attributes registered
$attributes = $manager->get();
// Fetch all the attributes registered for a given entity
$attributes = $manager->get(App\Product::class);
// Refresh the cache
$manager->refresh();
This is a very simple class. It just creates a ValueType
model instance based on the attribute the value will be linked to. Some code will make this very easy:
$builder = new Builder;
$product = Product::find(1);
$attribute = Attribute(['code' => 'size', 'model' => 'Devio\Eavquent\Value\Data\Varchar', ...]);
$builder->build($product, $attribute, 'Large');
// Behind the scenes this will create an instance of the `Varchar` class and link its attributes to the given entity and attribute instance so will provide something like:
// Varchar(['content' => 'Large', 'attribute_id' => $attribute->id, 'entity_id' => $product->id, 'entity_type' => 'App\Product'])
This will provide a model ready to be saved just callig its save
method which will be triggered when saving the main entity.
When entity values are replaced, set to null or just removed from collections, we have to perform a DELETE
query to our database to really remove those value rows. The Trash
class is responsible of storing all those values that have to be deleted when the entity gets saved. It store values like:
echo $company->cities;
// ['Paris', 'Berlin']
$company->cities = ['Milan', 'New York'];
// Paris and Berlin value models are in the trash queue now (only because they really exist in database)
$company->cities = ['Tokio', 'London'];
// Milan and New York are no queued for deletion as they were never saved so do not really exist in database
This class creates the Eloquent relations to the attribute values based on their type. If they are multivlaued, it will provide a hasMany
relation, otherwise just a hasOne
. This class creates closures that return this kind of relathions and may be called straight from the entity model. These closures are stored in $attributeRelations
property in the Eavquent trait.
This class is the most important and let the other classes play together. The first thing it does then it's added to a model is to bootstrap itself (Eloquent feature):
https://github.com/IsraelOrtuno/Eavquent/blob/master/src/Eavquent.php#L59-L70
Nothing very special here, just setting the event listeners for saving, add the global scope and fetch the attributes related to this entity.
The next method is more important and is triggered when the model really exists. This method boots the model instance:
https://github.com/IsraelOrtuno/Eavquent/blob/master/src/Eavquent.php#L75-L84
It calls the RelationBuilder
class which adds the relation methods to the $attributeRelations
array. These relations may be called as usual as we are overriding the magic method __call
looking for these calls https://github.com/IsraelOrtuno/Eavquent/blob/master/src/Eavquent.php#L424-L426 so we can do:
$entity->cities();
This will provide a HasMany
relation object.
Most of the methods of this trait are simply getters or readers. Just a few Eloquent methods have been overwriten:
// In order to include attributes as relations when converting to array/json
relationsToArray();
// In order to make sure any new instance is booted
newInstance()
// Value collections need to know what entity and attribute they are playing with.
// This method makes sure when setting a new collection relation they are just linked.
setRelation()
// This overwriten method includes just a copule of lines which lets Eloquent
// use our attribute relations as part of the model. https://github.com/IsraelOrtuno/Eavquent/blob/master/src/Eavquent.php#L182-L184
// By the way, the rest of the lines will be deleted as Taylor merged my PR for 5.1 and 5.2 and makes them useless
getRelationValue()