In the following example you will see a minimalistic implementation of the component_attribute_model_attribute-subject-interface
.
<?php
namespace App\Model;
use Doctrine\Common\Collections\Collection;
use Sylius\Component\Attribute\Model\AttributeSubjectInterface;
use Sylius\Component\Attribute\Model\AttributeValueInterface;
class Shirt implements AttributeSubjectInterface
{
private Collection $attributes;
public function getAttributes(): Collection
{
return $this->attributes;
}
public function setAttributes(Collection $attributes): void
{
foreach ($attributes as $attribute) {
$this->addAttribute($attribute);
}
}
public function addAttribute(AttributeValueInterface $attribute): void
{
if (!$this->hasAttribute($attribute)) {
$attribute->setSubject($this);
$this->attributes->add($attribute);
}
}
public function removeAttribute(AttributeValueInterface $attribute): void
{
if ($this->hasAttribute($attribute)) {
$attribute->setSubject(null);
$this->attributes->removeElement($attribute);
}
}
public function hasAttribute(AttributeValueInterface $attribute): bool
{
return $this->attributes->contains($attribute);
}
public function hasAttributeByCodeAndLocale($attributeCode, $localeCode = null): bool
{
return (bool) $this->getAttributeByCodeAndLocale($attributeCode, $localeCode);
}
public function getAttributeByCodeAndLocale(string $attributeCode, string $localeCode = null): ?AttributeValueInterface
{
return $this->attributes->filter(fn (AttributeValueInterface $attribute) => $attributeCode === $attribute->getCode() &&
($attribute->getLocaleCode() === $localeCode || null === $attribute->getLocaleCode()))
->first();
}
public function getAttributesByLocale(string $localeCode, string $fallbackLocaleCode, ?string $baseLocaleCode = null): Collection
{
return $this->attributes->filter(function (AttributeValueInterface $attribute) use ($localeCode) {
return $attribute->getLocaleCode() === $localeCode;
}
);
}
// Optional: you can search attributes by name
public function hasAttributeByName(string $attributeName): bool
{
return (bool) $this->getAttributeByName($attributeName);
}
public function getAttributeByName(string $attributeName): Collection
{
return $this->attributes->filter(fn ($attribute) => $attributeName === $attribute->getName());
}
}
Note
An implementation similar to the one above has been done in the component_product_model_product
model.
Once we have our class we can characterize it with attributes.
<?php
use App\Model\Shirt;
use Sylius\Component\Attribute\Model\Attribute;
use Sylius\Component\Attribute\Model\AttributeValue;
use Sylius\Component\Attribute\AttributeType\TextAttributeType;
use Sylius\Component\Attribute\Model\AttributeValueInterface;
$attribute = new Attribute();
$attribute->setName('Size');
$attribute->setType(TextAttributeType::TYPE);
$attribute->setStorageType(AttributeValueInterface::STORAGE_TEXT);
$smallSize = new AttributeValue();
$mediumSize = new AttributeValue();
$smallSize->setAttribute($attribute);
$mediumSize->setAttribute($attribute);
$smallSize->setValue('S');
$mediumSize->setValue('M');
$shirt = new Shirt();
$shirt->addAttribute($smallSize);
$shirt->addAttribute($mediumSize);
Or you can just add all attributes needed using a class implementing Doctrine's Collection
interface, e.g. the ArrayCollection
class.
Warning
Beware! It's really important to set proper attribute storage type, which should reflect value type that is set in AttributeValue.
<?php
use Doctrine\Common\Collections\ArrayCollection;
$attributes = new ArrayCollection();
$attributes->add($smallSize);
$attributes->add($mediumSize);
$shirt->setAttributes($attributes);
Note
Notice that you don't actually add an component_attribute_model_attribute
to the subject, instead you need to add every component_attribute_model_attribute-value
assigned to the attribute.
<?php
$shirt->getAttributes(); // returns an array containing all set attributes
$shirt->hasAttribute($smallSize); // returns true
$shirt->hasAttribute($hugeSize); // returns false
If you are using the optional functions that checks attributes by name you can access them by this value
<?php
$shirt->hasAttributeByName('Size'); // returns true
$shirt->getAttributeByName('Size'); // returns $smallSize
<?php
// in example implementation, removeAttribute function checks if collection has attribute
$shirt->hasAttribute($smallSize); // returns true
$shirt->removeAttribute($smallSize);
$shirt->hasAttribute($smallSize); // now returns false