Revision: Tue, 16 Aug 2022 19:49:12 GMT

Custom behaviors (Extension)

Custom behaviors are the primary way of adding functionality for entities. Behaviors might be anything from a great way to work with dates like Carbon or a behavior that allows you to create slug from Post title property. You have the ability to create your own behaviors and share them with the community.

Custom behaviors are classes that allow implementing custom logic for your entities. They extend Cycle\ORM\Entity\Behavior\Schema\BaseModifier and implement the custom logic in abstract methods.

Example

In the following example we will show you how it is simple to create a custom behavior:

Attribute

At first, you have to describe the attribute (annotation) that will be used in an entity.

use Cycle\ORM\Entity\Behavior\Schema\BaseModifier;
use Cycle\ORM\Entity\Behavior\Schema\RegistryModifier;
use Cycle\Schema\Registry;
use Doctrine\Common\Annotations\Annotation\Attribute;
use Doctrine\Common\Annotations\Annotation\Attributes;
use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;
use Doctrine\Common\Annotations\Annotation\Target;

/**
 * @Annotation
 * @NamedArgumentConstructor()
 * @Target({"CLASS"})
 */
#[\Attribute(\Attribute::TARGET_CLASS), NamedArgumentConstructor]
final class Sluggable extends BaseModifier
{
    public function __construct(
        // Properties should present in your entity with `[#Column(type: 'string')]` attribute
        private string $field = 'slug',     
        private string $from = 'title'
    ) {
    }

    protected function getListenerClass(): string
    {
        return SluggableListener::class;
    }

    protected function getListenerArgs(): array
    {
        // Will be passed to the listener constructor
        return [
            'field' => $this->field,
            'from' => $this->from
        ];
    }
}

Attribute listener

Then you have to describe listener connected with Sluggable attribute via Sluggable::getListenerClass method.

use Cycle\ORM\Entity\Behavior\Attribute\Listen;
use Cycle\ORM\Entity\Behavior\Event\Mapper\Command\OnCreate;
use Cycle\ORM\Entity\Behavior\Event\Mapper\Command\OnUpdate;
use Cocur\Slugify\Slugify;

final class SluggableListener
{
    public function construct(
        private Slugify $slugify,
        private ORMInterface $orm,
        private string $field
        private string $from
    ) {
    }

    #[Listen(OnCreate::class)]
    #[Listen(OnUpdate::class)]
    public function invoke(OnCreate|OnUpdate $event): void
    {
        $slug = $this->slugify->slugify($event->state->getData()[$this->from]);
        $isExist = $this->orm->getRepository($event->role)->findOne([$this->field => $slug]) !== null;
        
        if ($isExist) {
            $slug .= '-' . time();
        }
        
        $event->state->register($this->field, $slug);
    }
} 

Available events:

Example of usage

use Cycle\Annotated\Annotation\Column;
use Cycle\Annotated\Annotation\Entity;

#[Entity]
#[Sluggable(
    field: 'slug', 
    from: 'title'
)]
class Comment
{
    #[Column(type: 'primary')]
    private int $id;

    #[Column(type: 'string')]
    private string $title;

    #[Column(type: 'string')]
    private string $slug = '';
}
Edit this page