4.3. Entity-Attribute-Value (EAV)

The Entity–attribute–value (EAV) pattern in order to implement EAV model with PHP.

4.3.1. Purpose

The Entity–attribute–value (EAV) model is a data model to describe entities where the number of attributes (properties, parameters) that can be used to describe them is potentially vast, but the number that will actually apply to a given entity is relatively modest.

4.3.2. UML Diagram

EAV UML Diagram

4.3.3. Code

You can also find this code on GitHub

Entity.php

 1<?php
 2
 3declare(strict_types=1);
 4
 5namespace DesignPatterns\More\EAV;
 6
 7use SplObjectStorage;
 8
 9class Entity implements \Stringable
10{
11    /**
12     * @var SplObjectStorage<Value,Value>
13     */
14    private $values;
15
16    /**
17     * @param Value[] $values
18     */
19    public function __construct(private string $name, array $values)
20    {
21        $this->values = new SplObjectStorage();
22
23        foreach ($values as $value) {
24            $this->values->attach($value);
25        }
26    }
27
28    public function __toString(): string
29    {
30        $text = [$this->name];
31
32        foreach ($this->values as $value) {
33            $text[] = (string) $value;
34        }
35
36        return join(', ', $text);
37    }
38}

Attribute.php

 1<?php
 2
 3declare(strict_types=1);
 4
 5namespace DesignPatterns\More\EAV;
 6
 7use SplObjectStorage;
 8
 9class Attribute implements \Stringable
10{
11    private SplObjectStorage $values;
12
13    public function __construct(private string $name)
14    {
15        $this->values = new SplObjectStorage();
16    }
17
18    public function addValue(Value $value): void
19    {
20        $this->values->attach($value);
21    }
22
23    public function getValues(): SplObjectStorage
24    {
25        return $this->values;
26    }
27
28    public function __toString(): string
29    {
30        return $this->name;
31    }
32}

Value.php

 1<?php
 2
 3declare(strict_types=1);
 4
 5namespace DesignPatterns\More\EAV;
 6
 7class Value implements \Stringable
 8{
 9    public function __construct(private Attribute $attribute, private string $name)
10    {
11        $attribute->addValue($this);
12    }
13
14    public function __toString(): string
15    {
16        return sprintf('%s: %s', (string) $this->attribute, $this->name);
17    }
18}

4.3.4. Test

Tests/EAVTest.php

 1<?php
 2
 3declare(strict_types=1);
 4
 5namespace DesignPatterns\More\EAV\Tests;
 6
 7use DesignPatterns\More\EAV\Attribute;
 8use DesignPatterns\More\EAV\Entity;
 9use DesignPatterns\More\EAV\Value;
10use PHPUnit\Framework\TestCase;
11
12class EAVTest extends TestCase
13{
14    public function testCanAddAttributeToEntity(): void
15    {
16        $colorAttribute = new Attribute('color');
17        $colorSilver = new Value($colorAttribute, 'silver');
18        $colorBlack = new Value($colorAttribute, 'black');
19
20        $memoryAttribute = new Attribute('memory');
21        $memory8Gb = new Value($memoryAttribute, '8GB');
22
23        $entity = new Entity('MacBook Pro', [$colorSilver, $colorBlack, $memory8Gb]);
24
25        $this->assertEquals('MacBook Pro, color: silver, color: black, memory: 8GB', (string) $entity);
26    }
27}