<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
andanteproject / nullable-embeddable-bundle example snippets
// ... use statements
use Andante\NullableEmbeddableBundle\Attribute\NullableEmbeddable;
use Andante\NullableEmbeddableBundle\PropertyAccess\PropertyAccessor;
use Andante\NullableEmbeddableBundle\Result;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Embeddable]
#[NullableEmbeddable(processor: static function (PropertyAccessor $propertyAccessor, object $embeddableObject): Result {
// We check if the 'code' property is uninitialized.
if ($propertyAccessor->isUninitialized($embeddableObject, 'code')) {
return Result::SHOULD_BE_NULL;
}
return Result::KEEP_INITIALIZED;
})]
class Country
{
public function __construct(
#[ORM\Column(type: Types::STRING, length: 2, nullable: true)]
private string $code,
) {
}
// ... getters and setters
}
declare(strict_types=1);
namespace Andante\NullableEmbeddableBundle;
use Andante\NullableEmbeddableBundle\Exception\UnexpectedEmbeddableClassException;
use Andante\NullableEmbeddableBundle\PropertyAccess\PropertyAccessor;
use Symfony\Component\PropertyAccess\PropertyPathInterface;
interface ProcessorInterface
{
/**
* @throws UnexpectedEmbeddableClassException
*/
public function analyze(PropertyAccessor $propertyAccessor, object $embeddableObject, PropertyPathInterface $propertyPath, object $rootEntity, mixed $embeddedConfig): Result;
}
declare(strict_types=1);
namespace App\Entity;
use Andante\NullableEmbeddableBundle\Attribute\NullableEmbeddable;
use Doctrine\ORM\Mapping as ORM;
use App\Processor\AddressEmbeddableProcessor; // Your custom processor
#[ORM\Embeddable]
#[NullableEmbeddable(processor: AddressEmbeddableProcessor::class)]
class Address
{
// ... properties, getters, setters
}
declare(strict_types=1);
namespace App\Processor;
use Andante\NullableEmbeddableBundle\ProcessorInterface;
use Andante\NullableEmbeddableBundle\PropertyAccess\PropertyAccessor;
use Andante\NullableEmbeddableBundle\Result;
use Andante\NullableEmbeddableBundle\Exception\UnexpectedEmbeddableClassException;
use App\Entity\Address;
use Symfony\Component\PropertyAccess\PropertyPathInterface;
class AddressEmbeddableProcessor implements ProcessorInterface
{
public function analyze(PropertyAccessor $propertyAccessor, object $embeddableObject, PropertyPathInterface $propertyPath, object $rootEntity, mixed $embeddedConfig): Result
{
if (!$embeddableObject instanceof Address) {
throw UnexpectedEmbeddableClassException::create(Address::class, $embeddableObject);
}
if (
null === $propertyAccessor->getValue($embeddableObject, 'street')
&& null === $propertyAccessor->getValue($embeddableObject, 'city')
&& null === $propertyAccessor->getValue($embeddableObject, 'country')
) {
return Result::SHOULD_BE_NULL;
}
return Result::KEEP_INITIALIZED;
}
}
declare(strict_types=1);
namespace App\Entity;
use Andante\NullableEmbeddableBundle\Attribute\NullableEmbeddable;
use Andante\NullableEmbeddableBundle\Exception\UnexpectedEmbeddableClassException;
use Andante\NullableEmbeddableBundle\PropertyAccess\PropertyAccessor;
use Andante\NullableEmbeddableBundle\Result;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Embeddable]
#[NullableEmbeddable(processor: static function (PropertyAccessor $propertyAccessor, object $embeddableObject): Result {
if (!$embeddableObject instanceof Address) {
throw UnexpectedEmbeddableClassException::create(Address::class, $embeddableObject);
}
if (
null === $propertyAccessor->getValue($embeddableObject, 'street')
&& null === $propertyAccessor->getValue($embeddableObject, 'city')
&& null === $propertyAccessor->getValue($embeddableObject, 'country')
) {
return Result::SHOULD_BE_NULL;
}
return Result::KEEP_INITIALIZED;
})]
class Address
{
#[ORM\Column(type: Types::STRING, nullable: true)]
private ?string $street = null;
#[ORM\Column(type: Types::STRING, nullable: true)]
private ?string $city = null;
#[ORM\Embedded(class: Country::class, columnPrefix: 'country_')]
private ?Country $country = null;
// ... getters and setters
}
declare(strict_types=1);
namespace App\Entity;
use Andante\NullableEmbeddableBundle\Attribute\NullableEmbeddable;
use Andante\NullableEmbeddableBundle\Exception\UnexpectedEmbeddableClassException;
use Andante\NullableEmbeddableBundle\PropertyAccess\PropertyAccessor;
use Andante\NullableEmbeddableBundle\Result;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Embeddable]
#[NullableEmbeddable(processor: static function (PropertyAccessor $propertyAccessor, object $embeddableObject): Result {
if (!$embeddableObject instanceof Country) {
throw UnexpectedEmbeddableClassException::create(Country::class, $embeddableObject);
}
if ($propertyAccessor->isUninitialized($embeddableObject, 'code')) {
return Result::SHOULD_BE_NULL;
}
return Result::KEEP_INITIALIZED;
})]
class Country
{
#[ORM\Column(type: Types::STRING, length: 255, nullable: true)]
private ?string $name = null;
public function __construct(
#[ORM\Column(type: Types::STRING, length: 2, nullable: true)]
private string $code,
) {
}
// ... getters and setters
}
// BAD - Don't do this:
private bool $enabled = true; // Doctrine gets NULL from DB but property shows true
// GOOD - Do this instead:
public function __construct(
private bool $enabled = true,
) {}
#[ORM\Embeddable]
#[NullableEmbeddable(processor: /* ... */)]
class Address
{
// ERROR: Property has non-null default outside constructor
// private bool $isPrimary = false;
// ERROR: Column is not nullable (neither PHP type nor explicit attribute)
// #[ORM\Column(type: Types::STRING)]
// private string $street;
// CORRECT: Column is nullable via PHP type (Doctrine infers nullable: true)
#[ORM\Column(type: Types::STRING)]
private ?string $street = null;
// ALSO CORRECT: Column explicitly nullable (even with non-nullable PHP type)
#[ORM\Column(type: Types::STRING, nullable: true)]
private string $city;
// CORRECT: Uninitialized embedded property (will remain uninitialized when the parent is null)
#[ORM\Embedded(class: Country::class)]
private Country $country;
// ALSO CORRECT: Embedded property initialized to null
#[ORM\Embedded(class: Region::class)]
private ?Region $region = null;
// CORRECT: Default value in constructor
public function __construct(
#[ORM\Column(type: Types::BOOLEAN, nullable: true)]
private bool $isPrimary = false,
) {}
}
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
if ('prod' === $containerConfigurator->env()) {
$containerConfigurator->extension('andante_nullable_embeddable', [
'metadata_cache_warmer_enabled' => true,
]);
}
};
Loading please wait ...
Before you can download the PHP files, the dependencies should be resolved. This can take some minutes. Please be patient.