sylius/attribute
Sylius Attribute component provides a flexible attribute system for PHP apps: define attribute types, store values, and attach them to resources. Used across Sylius to add custom fields and metadata with validation and persistence support.
Installation
composer require sylius/attribute
Add to config/app.php under providers:
Sylius\Component\Attribute\AttributeServiceProvider::class,
Publish Config (Optional)
php artisan vendor:publish --provider="Sylius\Component\Attribute\AttributeServiceProvider" --tag="sylius_attribute:config"
Check config/sylius_attribute.php for default settings.
First Use Case: Defining Attributes
use Sylius\Component\Attribute\Model\AttributeInterface;
use Sylius\Component\Attribute\Model\AttributeValueInterface;
// Define an attribute (e.g., for a product)
$attribute = new Attribute();
$attribute->setType('string'); // or 'integer', 'boolean', 'float', 'datetime', 'json'
$attribute->setCode('color');
$attribute->setLabel('Color');
// Save via Doctrine (if using Sylius' ORM integration)
$em->persist($attribute);
$em->flush();
Key Classes to Know
Attribute – Represents a configurable property (e.g., "Size", "Weight").AttributeValue – Stores the value of an attribute for a specific entity (e.g., a product’s "Size: M").AttributeRepository – Fetches attributes by code/type.AttributeService – Handles value validation and type casting.For Products (or any entity):
// Assign an attribute value to an entity (e.g., Product)
$product = $productRepository->find(1);
$attribute = $attributeRepository->findOneBy(['code' => 'color']);
$attributeValue = new AttributeValue();
$attributeValue->setAttribute($attribute);
$attributeValue->setValue('red'); // Raw value (casted to type later)
$product->addAttributeValue($attributeValue);
$em->persist($product);
$em->flush();
Retrieving Values:
$color = $product->getAttributeValue('color')->getValue(); // Returns 'red' (string)
Use the AttributeService to validate/cast values:
$attributeService = $this->container->get('sylius_attribute.attribute_service');
// Validate and cast a value
$validatedValue = $attributeService->validateAndCastValue(
$attribute,
'blue', // raw input
$product // entity (optional, for context)
);
Supported Types:
string, integer, boolean, float, datetime (ISO-8601), json (array/object).Check if an entity has an attribute:
if ($product->hasAttribute('color')) {
$value = $product->getAttributeValue('color')->getValue();
}
Bulk Assignment (e.g., CSV import):
$data = [
'color' => 'green',
'size' => 'L',
'weight' => 2.5,
];
foreach ($data as $code => $value) {
$attribute = $attributeRepository->findOneBy(['code' => $code]);
if ($attribute) {
$product->addAttributeValue($attribute, $value);
}
}
Use Sylius\Component\Attribute\Form\Type\AttributeType for Symfony forms:
use Sylius\Component\Attribute\Form\Type\AttributeType;
$builder->add('color', AttributeType::class, [
'attribute' => $attributeRepository->findOneBy(['code' => 'color']),
'required' => false,
]);
Listen for attribute.value.set or attribute.value.removed events (if using Sylius’ event system):
$dispatcher->addListener(
'attribute.value.set',
function (AttributeValueEvent $event) {
// Log or process changes
}
);
Type Mismatches
null or invalid data to validateAndCastValue() throws exceptions.try {
$validated = $attributeService->validateAndCastValue($attribute, $rawValue);
} catch (InvalidArgumentException $e) {
// Handle error (e.g., show user feedback)
}
Circular References in JSON
json type attributes will break serialization.json_encode() with JSON_THROW_ON_ERROR or flatten data.Doctrine Proxy Conflicts
Sylius\Component\Attribute\Model\AttributeSubjectInterface to avoid proxy issues.getAttributeValues() and addAttributeValue() methods.Attribute Code Uniqueness
color) must be unique across the system. Duplicates cause EntityManager errors.$existing = $attributeRepository->findOneBy(['code' => 'color']);
if ($existing && $existing->getId() !== $attribute->getId()) {
throw new \RuntimeException('Attribute code "color" already exists.');
}
Check Raw Values
Use getRawValue() to inspect uncasted data:
$rawValue = $attributeValue->getRawValue(); // Bypasses type casting
Enable Attribute Logging
Add to config/sylius_attribute.php:
'debug' => env('APP_DEBUG', false),
Logs validation errors and casting steps.
Database Schema
Ensure your attribute_value table has:
value column (type: text for JSON, string for others).type column (to store the attribute’s type).Custom Value Processors
Override type casting logic by implementing Sylius\Component\Attribute\ValueProcessor\ValueProcessorInterface:
class CustomJsonProcessor implements ValueProcessorInterface {
public function process($value, AttributeInterface $attribute): ?string {
// Custom JSON handling
return json_encode($value, JSON_THROW_ON_ERROR);
}
}
Register in config/sylius_attribute.php:
'value_processors' => [
'json' => App\CustomJsonProcessor::class,
],
Attribute Filters
Extend Sylius\Component\Attribute\Filter\AttributeFilter to add custom filtering logic (e.g., for search).
Attribute Events Dispatch custom events for attribute changes:
$dispatcher->dispatch(new AttributeUpdatedEvent($attribute, $oldValue, $newValue));
Cache Attribute Lookups Cache frequently accessed attributes by code:
$attribute = Cache::remember("attribute_{$code}", 3600, function () use ($code) {
return $attributeRepository->findOneBy(['code' => $code]);
});
Batch Attribute Value Updates
Use Doctrine’s BATCH_SIZE for bulk operations:
$em->getConnection()->getConfiguration()->setSQLLogger(null); // Disable logging
$em->flush();
$em->getConnection()->getConfiguration()->setSQLLogger($logger);
Avoid N+1 Queries Eager-load attribute values:
$products = $productRepository->findBy([], [
'attributeValues' => ['attribute' => 'color']
]);
How can I help you explore Laravel packages today?