The image illustrates a simplified process for creating a new entity.
The Symfony app utilizes DBAL migration commands. The CLI app is primarily used for executing migrations.
The CLI app relies on a database connection and utilizes Doctrine DBAL for establishing connections.
No pre-configured connection information is available. To set up a connection in non-docker environments, you need to follow these steps:
- Create a new file named connection.php in the root folder.
- The contents of this file will be automatically included in the application.
#connection.php
use Drobotik\Eav\Database\Connection;
$config = [
// connection settings
]
$connection = Connection::get($config)
Choose a driver that best suits your requirements.
Migrate:
$ php eav migrations:migrate latest
Rollback:
$ php eav migrations:migrate first
The Domain is used solely as a wrapper for performing import and export operations. It provides a convenient interface for managing the import/export functionality within the library.
use Drobotik\Eav\Domain;
use Drobotik\Eav\Export\ExportManager();
use Drobotik\Eav\Import\ImportManager();
$domain = new Domain();
$domain->setExportManager(new ExportManager());
$domain->setImportManager(new ImportManager());
$exportManager = $domain->getExportManager();
$importManager = $domain->getImportManager();
$domain->import();
$domainKey = 1;
$attributeSetKey = 2;
$filters = [];
$columns = ['name', 'size', 'weight']
$domain->export($domainKey, $attributeSetKey, $filters, $columns);
The Entity model is a robust CRUD model that simplifies working with the EAV (Entity-Attribute-Value) data structure. It serves as the primary model for working with individual data records, making it well-suited for single record operations. However, it is not recommended for bulk usage or performing operations on a large number of records simultaneously.
use Drobotik\Eav\Entity;
$entityKey = 1;
$domainKey = 2;
$attributeSetKey = 3;
$entity = new Entity();
// SETUP
$entity->setDomainKey($entityKey);
$entity->setKey($domainKey);
$entity->getAttributeSet()->setKey($attributeSetKey)
// FIND
$result = $entity->find();
$data = $result->getData();
$fields = $entity->getBag();
// EDIT record attributes
$fields->setField('name', 'Tom');
$fields->setField('type', 'Jerry');
// remove record attribute value
$fields->removeField('age');
// it will be ignored since there are no attributes in the attribute set.
$fields->setField('not_existing_attribute', '');
// VALIDATE
// validate attributes and values
$result = $entity->validate(); // result from laravel validator
$result->getData(); // validation array
$result->getCode(); // just for internal use
$result->getMessage(); // human message
// SAVE
// before-save hooks for attribute strategy
// values will be inserted, updated, or deleted
// after-save hooks for attribute strategy
$entity->save();
// DELETE
// entity with corresponded values will be deleted
$entity->delete();
Entity create (without $entity->setKey())
use Drobotik\Eav\Entity;
$domainKey = 2;
$attributeSetKey = 3;
$entity = new Entity();
// SETUP
$entity->setDomainKey($entityKey);
$entity->getAttributeSet()->setKey($attributeSetKey);
$fields = $entity->getBag();
$fields->setField('name', 'Tom');
$fields->setField('type', 'Cat');
$entity->save();
Other features
use Drobotik\Eav\Entity;
use Drobotik\Eav\AttributeSet;
/* Override attributeSet */
$entity = new Entity();
$attrSet = new AttributeSet();
$entity->setAttributeSet($attrSet);
/* CRUD gnome doing all routine jobs for 'Entity' */
$gnome = $entity->getGnome();
/* toArray */
$entity->toArray();
More examples:
tests/Eav/Entity/EntityAcceptanceTest.php
This class serves as a wrapper for Attribute Containers and is an integral part of Entity.
use Drobotik\Eav\Entity;
use Drobotik\Eav\AttributeSet;
use Drobotik\Eav\AttributeContainer;
$attributeSetKey = 1;
$set = new AttributeSet();
$set->setKey($attributeSetKey);
/*
* Making a new database query to retrieve corresponding attributes.
* Initializing the Attribute containers
* Initializing Attribute, Strategy, Value, and other objects
* Retrieving values from the database if they exist
*/
$set->fetchContainers();
/*
* It is possible to force the rebuilding
* of all Attribute container arrays from scratch
*/
$set->fetchContainers(true);
/*
* Other methods
*/
$set->hasContainer('test');
$set->getContainer('test');
$set->pushContainer(new AttributeContainer());
$set->getContainers(); // AttributeContainer[] keyBy name
$set->resetContainers(); // []
$set->setEntity(new Entity());
$set->getEntity(); // Entity
Attribute groups are utilized to categorize attributes into subsections. It is important to note that without a group, an attribute set is unable to fetch containers.
Please see Pivot.
The Attribute class represents attribute data retrieved from the database. It plays a crucial role in managing how data should be saved and determining the source of initial data. An important component of the Attribute class is the AttributeStrategy class, which handles all CRUD operations related to attribute values.
use Drobotik\Eav\Attribute;
use Drobotik\Eav\Strategy;
use Drobotik\Eav\Enum\_ATTR;
use Drobotik\Eav\Enum\ATTR_TYPE;
$attribute = new Attribute();
$bag = $attribute->getBag();
$bag->setField(_ATTR::NAME->column(), 'price')
$bag->setField(_ATTR::TYPE->column(), ATTR_TYPE::DECIMAL->value())
$bag->setField(_ATTR::STRATEGY->column(), Strategy::class);
$type = $attribute->getType(); // ATTR_TYPE::DECIMAL
$valueModelTable = $type->valueTable(); // ATTR_TYPE::DECIMAL->valueTable()
$typeName = $type->value(); // ATTR_TYPE::DECIMAL->value()
// ...
$attribute->getName();
$attribute->getStrategy();
$attribute->getSource();
$attribute->getDefaultValue();
$attribute->getDescription();
The AttributeContainer class is extensively utilized by the AttributeSet to construct and store attribute containers for each attribute in the AttributeSet.
use Drobotik\Eav\AttributeContainer;
use Drobotik\Eav\AttributeSet;
use Drobotik\Eav\Attribute;
use Drobotik\Eav\AttributeSetAction;
use Drobotik\Eav\Strategy;
use Drobotik\Eav\Value\ValueAction;
use Drobotik\Eav\Value\ValueValidator;
use Drobotik\Eav\Value\ValueManager;
$container = new \Drobotik\Eav\AttributeContainer();
$container->setAttributeSet(new AttributeSet());
$container->getAttributeSet();
$container->setAttribute(new Attribute());
$container->getAttribute();
$container->setAttributeSetAction(new AttributeSetAction());
$container->getAttributeSetAction();
$container->setStrategy(new Strategy());
$container->getStrategy();
$container->setValueAction(new ValueAction());
$container->getValueAction();
$container->setValueValidator(new ValueValidator());
$container->getValueValidator();
$container->setValueManager(new ValueManager());
$container->getValueManager();
The strategy class is frequently employed to customize manipulations with specific attributes or to introduce new features. The current strategy includes predefined CRUD operations and validation for Attribute EAV values.
use Drobotik\Eav\Strategy;
$strategy = new Strategy();
$strategy->delete();
$strategy->create();
$strategy->delete();
$strategy->validate();
$strategy->save();
$strategy->find()
$strategy->beforeCreate();
$strategy->beforeUpdate();
$strategy->beforeDelete();
$strategy->afterCreate();
$strategy->afterUpdate();
$strategy->afterDelete();
$strategy->rules();
$strategy->isCreate();
$strategy->isUpdate();
The helper class is utilized to initialize attribute objects. The AttributeSet employs this action when fetching attributes.
use Drobotik\Eav\AttributeSetAction;
use Drobotik\Eav\AttributeContainer;
use Drobotik\Eav\Model\AttributeModel;
$action = new AttributeSetAction();
$action->setAttributeContainer(new AttributeContainer());
$record = new AttributeModel();
$record->setName('test');
$action->initialize($record);
// more internal methods
$action->initializeStrategy($record);
$action->initializeValueManager();
The Value class is an internal object used to handle EAV (Entity-Attribute-Value) values. It can store two types of values: runtimeValue and storedValue.
The runtimeValue represents a dynamic value that is intended to be saved in the database but has not been stored yet.
On the other hand, the storedValue represents a value that has already been stored in the database.
use Drobotik\Eav\Value\ValueManager;
$value = new ValueManager();
$value->setStored(123);
$value->getValue(); // 123
$value->setRuntime(456);
$value->getValue(); // 456
$value->IsEquivalent() // false
$value->isRuntime(); // true
$value->clearRuntime();
$value->isRuntime(); // false
$value->isStored(); // true
Before working with EAV (Entity-Attribute-Value) data, it is necessary to specify the structure of the attribute set. If an attribute is not linked in the pivot table, both the attribute and its corresponding data will not be fetched by the AttributeSet.
use Drobotik\Eav\Model\PivotModel;
use \Drobotik\Eav\Enum\_PIVOT;
$domainKey = 1
$setKey = 2
$groupKey = 3
$attributeKey = 4
$model = new PivotModel();
$model->findOne($domainKey, $setKey, $groupKey, $attributeKey);
$model->create([
_PIVOT::DOMAIN_ID->column() => $domainKey,
_PIVOT::SET_ID->column() => $setKey,
_PIVOT::GROUP_ID->column() => $groupKey,
_PIVOT::ATTR_ID->column() => $attributeKey
]);
Attribute import: During the import process, the attribute import functionality creates new attributes that are linked to the attribute set. These attributes are specifically added and associated with the attribute set.
Data Import: The Data Import feature is responsible for importing values for attributes that belong to the attribute set. It handles the import of actual data associated with the attributes.
Before starting the process, the data is divided into two parts: new entities to create and entities to update.
New entities to create: For new entities, a bulk import query is used, which offers fast processing. However, it is recommended to avoid using a large chunk size to prevent the query from becoming too large.
Entities to update: The process further divides entities to update into three categories: new values, values to update, and values to create.
use SplFileObject;
use League\Csv\Reader;
use Drobotik\Eav\Driver\CsvDriver;
use Drobotik\Eav\Import\Content\Worker as ContentWorker;
use Drobotik\Eav\Import\ImportContainer;
use \Drobotik\Eav\Import\ImportManager;
// import operation requires a data source.
// In this example, the source is a CSV file
$file = new SplFileObject('dir/data.csv', 'r');
$reader = Reader::createFromFileObject($file);
$reader->setDelimiter(',');
$reader->setHeaderOffset(0);
$driver = new CsvDriver();
// the index or line number from which to start
$driver->setCursor(0);
// the import data will be imported in chunks,
// after each iteration default state will be restored
$driver->setChunkSize(50); // recommended to not use large chunks
$driver->setReader($reader);
// this worker will insert data to database
$contentWorker = new ContentWorker();
// import DI container
$importContainer = new ImportContainer();
$importContainer->setContentWorker($contentWorker);
// the main handler that orchestrates the execution of all necessary operations
$importManager = new ImportManager();
$importManager->setContainer($importContainer);
During the import process, the AttributesWorker component will retrieve column names from the source data. These column names will then be validated. If any of the column names do not correspond to existing attributes (new attributes) or attributes that are not linked with the attribute set, the process will raise an exception and provide the names of the attributes that need to be addressed.
To ensure the import process works correctly, a configuration for these attributes needs to be provided. This configuration will facilitate the creation of the necessary attributes before proceeding with the data import.
use Drobotik\Eav\Import\Attributes\Config;
use Drobotik\Eav\Import\Attributes\ConfigAttribute;
use Drobotik\Eav\Import\Attributes\Worker as AttributesWorker;
use Drobotik\Eav\Import\ImportContainer;
$groupKey = 1;
$ageAttribute = new ConfigAttribute()
$ageAttribute->setFields([
_ATTR::NAME->column() => "age",
_ATTR::TYPE->column() => ATTR_TYPE::INT->value()
]);
$ageAttribute->setGroupKey($groupKey);
$noteAttribute = new ConfigAttribute()
$noteAttribute->setFields([
_ATTR::NAME->column() => "note",
_ATTR::TYPE->column() => ATTR_TYPE::TEXT->value()
]);
$noteAttribute->setGroupKey($groupKey);
$config = new Config();
$config->appendAttribute($ageAttribute);
$config->appendAttribute($noteAttribute);
$attributesWorker = new AttributesWorker();
$attributesWorker->setConfig($config);
/* ... */
/** @var ImportContainer $importContainer */
$importContainer->setAttributesWorker($attributesWorker);
See more comprehensive examples in the tests/Eav/ImportManager/ImportManagerAcceptanceTest.php
The export mechanism is divided into two sections: setup and querying data.
The setup section involves configuring the driver and main classes. In this example, the CsvDriver setup is used.
The querying data section involves utilizing an internal query builder within the library. The idea for the query builder originates from jquery query builder.
The query builder generates a custom query based on the provided configuration.
use SplFileObject;
use League\Csv\Writer;
use Drobotik\Eav\Driver\CsvDriver;
use Drobotik\Eav\Export\ExportManager;
use Drobotik\Eav\QueryBuilder\QueryBuilder;
// specify where to write
$file = new SplFileObject(d'/dir/data.csv','w');
$writer = Writer::createFromFileObject($file);
$driver = new CsvDriver();
$driver->setWriter($writer);
$manager = new ExportManager();
$manager->setDriver($driver);
// query builder config
$filters = [
QB_CONFIG::CONDITION => QB_CONDITION::AND,
QB_CONFIG::RULES => [
[
QB_CONFIG::NAME => "size",
QB_CONFIG::OPERATOR => QB_OPERATOR::LESS->name(),
QB_CONFIG::VALUE => 10000
],
[
QB_CONFIG::CONDITION => QB_CONDITION::OR->name(),
QB_CONFIG::RULES => [
[
QB_CONFIG::NAME => "name",
QB_CONFIG::OPERATOR => QB_OPERATOR::CONTAINS->name(),
QB_CONFIG::VALUE => 'sit quisquam'
],
[
QB_CONFIG::NAME => "name",
QB_CONFIG::OPERATOR => QB_OPERATOR::EQUAL->name(),
QB_CONFIG::VALUE => 'et dolores'
]
],
]
],
];
$domainKey = 1;
$setKey = 2;
$resultColumns = ["size", "name"]
$manager->run(domainKey, $setKey, $filters, $resultColumns); // file created
Sometimes, it may be necessary to pre-generate certain EAV data in advance.
This is a collection of common 'create' methods for various entities such as domain, attribute, group, entity, values. These methods are extensively utilized during application testing, but they can also be employed during runtime if required.
The entity factory is a configurable entity creation tool. By providing it with the necessary attribute configuration, it can generate an entity with all the corresponding attributes and values. This factory is primarily used for testing purposes. However, it should be noted that performance may be slow when dealing with a large number of entities.