### Run Doctrine Extensions Example Source: https://github.com/doctrine-extensions/doctrineextensions/blob/main/README.md Steps to set up and run the example provided with Doctrine Extensions. Ensure you have Composer installed and configure your database connection in `example/em.php`. ```bash composer install ``` ```bash php example/bin/console ``` ```bash php example/bin/console orm:schema-tool:create ``` ```bash php example/bin/console app:print-category-translation-tree ``` -------------------------------- ### Example Usage of Sluggable Handlers Source: https://github.com/doctrine-extensions/doctrineextensions/blob/main/doc/sluggable.md Demonstrates the creation and persistence of Company and User entities, showing how the slugs are generated and updated. ```php setTitle('KnpLabs'); $em->persist($company); $gedi = new User; $gedi->setUsername('Gedi'); $gedi->setCompany($company); $em->persist($gedi); $em->flush(); echo $gedi->getSlug(); // outputs "knplabs/gedi" $company->setTitle('KnpLabs Nantes'); $em->persist($company); $em->flush(); echo $gedi->getSlug(); // outputs "knplabs-nantes/gedi" ``` -------------------------------- ### Basic Sluggable Usage Example Source: https://github.com/doctrine-extensions/doctrineextensions/blob/main/doc/sluggable.md Demonstrates how to create an Article entity, set its fields, persist it, and flush to generate the slug. ```php setTitle('the title'); $article->setCode('my code'); $this->em->persist($article); $this->em->flush(); echo $article->getSlug(); // prints: the-title-my-code ``` -------------------------------- ### Run Doctrine Extensions Tests Source: https://github.com/doctrine-extensions/doctrineextensions/blob/main/README.md Use these commands to set up Docker containers, enter the PHP environment, install dependencies, and run the test suite. ```bash docker compose up -d ``` ```bash docker compose exec php bash ``` ```bash composer install ``` ```bash vendor/bin/phpunit ``` -------------------------------- ### Custom FileInfo Implementation Source: https://github.com/doctrine-extensions/doctrineextensions/blob/main/doc/uploadable.md Provides an example of creating a custom class that implements the FileInfoInterface to handle files from sources other than direct uploads, such as URLs or existing server files. This example sets `isUploadedFile` to false to use the `copy` function. ```php use Gedmo\Uploadable\FileInfo\FileInfoInterface; class CustomFileInfo implements FileInfoInterface { protected $path; protected $name; protected $size; protected $type; protected $filename; protected $error = 0; public function __construct($path) { $this->path = $path; // Now, process the file and fill the rest of the properties. } // This returns the actual path of the file public function getTmpName() { return $this->path; } // This returns the filename public function getName() { return $this->name; } // This returns the file size in bytes public function getSize() { return $this->size; } // This returns the mime type public function getType() { return $this->type; } public function getError() { // This should return 0, as it's only used to return the codes from PHP file upload errors. return $this->error; } // If this method returns true, it will produce that the extension uses "move_uploaded_file" function to move // the file. If it returns false, the extension will use the "copy" function. public function isUploadedFile() { return false; } } ``` -------------------------------- ### Changelog Entry Example Source: https://github.com/doctrine-extensions/doctrineextensions/blob/main/CONTRIBUTING.md Format for adding an entry to the changelog, including the extension name and GitHub issue number if applicable. ```markdown ## [Unreleased] ### Fixed - Loggable: Allow emoji in the docs (#123) ``` -------------------------------- ### Install Doctrine Extensions for ORM Source: https://github.com/doctrine-extensions/doctrineextensions/blob/main/doc/frameworks/laminas.md Use this Composer command to install Doctrine Extensions and required dependencies for Doctrine ORM. ```shell composer require doctrine/dbal doctrine/doctrine-module doctrine/doctrine-orm-module doctrine/orm gedmo/doctrine-extensions ``` -------------------------------- ### Install Doctrine Extensions with Composer Source: https://github.com/doctrine-extensions/doctrineextensions/blob/main/README.md Use Composer to install the Doctrine Extensions package. This is the primary method for integrating the extensions into your project. ```bash composer require gedmo/doctrine-extensions ``` -------------------------------- ### Install Doctrine Extensions for MongoDB ODM Source: https://github.com/doctrine-extensions/doctrineextensions/blob/main/doc/frameworks/laminas.md Use this Composer command to install Doctrine Extensions and required dependencies for MongoDB ODM. ```shell composer require doctrine/doctrine-module doctrine/doctrine-mongo-odm-module doctrine/mongodb-odm gedmo/doctrine-extensions ``` -------------------------------- ### Persisting Entities with Personal Translations Source: https://github.com/doctrine-extensions/doctrineextensions/blob/main/doc/translatable.md Example demonstrating how to create and persist entities with multiple personal translations for different locales and fields. ```php setTitle('Food'); $food->addTranslation(new Entity\CategoryTranslation('lt', 'title', 'Maistas')); $fruits = new Entity\Category; $fruits->setParent($food); $fruits->setTitle('Fruits'); $fruits->addTranslation(new Entity\CategoryTranslation('lt', 'title', 'Vaisiai')); $fruits->addTranslation(new Entity\CategoryTranslation('ru', 'title', 'rus trans')); $em->persist($food); $em->persist($fruits); $em->flush(); ``` -------------------------------- ### XML Configuration for IP Traceable Source: https://github.com/doctrine-extensions/doctrineextensions/blob/main/doc/ip_traceable.md Configure the IP traceable extension using XML mapping files. This example sets the 'updatedFromIp' field to be updated on 'update' actions. ```xml ``` -------------------------------- ### Full Uploadable Entity Configuration with Annotations Source: https://github.com/doctrine-extensions/doctrineextensions/blob/main/doc/uploadable.md An example of a fully configured Uploadable entity using annotations, demonstrating options for path, callback, filename generator, overwrite, and number appending. ```php getRepository(Category::class); echo $repo->childCount($food); // 3 (all descendants) echo $repo->childCount($food, true); // 2 (direct children only) $path = $repo->getPath($carrots); // [Food, Vegetables, Carrots] ``` -------------------------------- ### Usage Example: 'nullify' ReferenceIntegrity Source: https://github.com/doctrine-extensions/doctrineextensions/blob/main/doc/reference_integrity.md Demonstrates the 'nullify' behavior. When a Type document is removed, its reference in the associated Article document is automatically set to null. ```php setTitle('My Article'); $type = new Type; $type->setTitle('Published'); $article->setType($type); $em->persist($article); $em->persist($type); $em->flush(); $type = $em->getRepository('Document\Type')->findByTitle('Published'); $em->remove($type); $em->flush(); $article = $em->getRepository('Document\Article')->findByTitle('My Article'); $article->getType(); // won't be referenced to Type anymore ``` -------------------------------- ### IpTraceable Listener Setup and Usage in PHP Source: https://context7.com/doctrine-extensions/doctrineextensions/llms.txt Sets up the IpTraceable listener, allowing direct IP value provision or using a provider. Demonstrates logging IP on entity creation and field change. ```php // --- Listener setup --- use Gedmo\IpTraceable\IpTraceableListener; $ipTraceableListener = new IpTraceableListener(); // Provide IP directly $ipTraceableListener->setIpValue($_SERVER['REMOTE_ADDR'] ?? '127.0.0.1'); // Or via a provider implementing Gedmo\Tool\IpAddressProviderInterface // $ipTraceableListener->setIpAddressProvider($provider); $em->getEventManager()->addEventSubscriber($ipTraceableListener); // --- Usage --- $article = new Article(); $em->persist($article); $em->flush(); echo $article->createdFromIp; // "127.0.0.1" $article->published = true; $em->flush(); echo $article->publishedFromIp; // "127.0.0.1" // Use traits for convenience: // use Gedmo\IpTraceable\Traits\IpTraceableEntity; // adds $createdFromIp and $updatedFromIp ``` -------------------------------- ### Listener Setup and Usage Source: https://context7.com/doctrine-extensions/doctrineextensions/llms.txt Initialize the LoggableListener, set the username, and add it as an event subscriber to your entity manager. Log entries are automatically created on persist and flush operations. ```php // --- Listener setup --- use Gedmo\Loggable\LoggableListener; $loggableListener = new LoggableListener(); $loggableListener->setUsername('admin'); $em->getEventManager()->addEventSubscriber($loggableListener); ``` ```php // --- Create and update (log entries are created automatically) --- $article = new Article(); $article->title = 'Version 1'; $em->persist($article); $em->flush(); // creates log entry: action=create, version=1 $article->title = 'Version 2'; $em->flush(); // creates log entry: action=update, version=2 $article->title = 'Version 3'; $em->flush(); // creates log entry: action=update, version=3 ``` -------------------------------- ### Translatable Listener Setup Source: https://context7.com/doctrine-extensions/doctrineextensions/llms.txt Configure the TranslatableListener with default locale, translatable locale, and fallback settings. Add the listener as an event subscriber to the entity manager. ```php use Gedmo\Translatable\TranslatableListener; $translatableListener = new TranslatableListener(); $translatableListener->setDefaultLocale('en'); $translatableListener->setTranslatableLocale('en'); $translatableListener->setTranslationFallback(true); // fall back to default locale $em->getEventManager()->addEventSubscriber($translatableListener); ``` -------------------------------- ### Annotation Configuration for IP Traceable Source: https://github.com/doctrine-extensions/doctrineextensions/blob/main/doc/ip_traceable.md Configure the IP traceable extension using annotations. This example sets the 'updatedFromIp' field. Note: Support for annotations is deprecated and will be removed in 4.0. ```php ``` -------------------------------- ### Retrieve Tree as HTML Source: https://github.com/doctrine-extensions/doctrineextensions/blob/main/doc/tree.md Generate an HTML tree structure (ul - li) from the category hierarchy. This example loads all children and uses default decoration. ```php getRepository(Category::class); $htmlTree = $repo->childrenHierarchy( null, /* starting from root nodes */ false, /* true: load all children, false: only direct */ [ 'decorate' => true, 'representationField' => 'slug', 'html' => true ] ); ``` -------------------------------- ### Attribute Configuration for IP Traceable Source: https://github.com/doctrine-extensions/doctrineextensions/blob/main/doc/ip_traceable.md Configure the IP traceable extension using attributes on your entity class properties. This example shows setting the 'updatedFromIp' field. ```php ``` -------------------------------- ### Implement Symfony Actor Provider Source: https://github.com/doctrine-extensions/doctrineextensions/blob/main/doc/utils/actor-provider.md Example of an actor provider implementation using Symfony's Security components. It retrieves the current user from the token storage. ```php namespace App\Utils; use Gedmo\Tool\ActorProviderInterface; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; final class SymfonyActorProvider implements ActorProviderInterface { private TokenStorageInterface $tokenStorage; public function __construct(TokenStorageInterface $tokenStorage) { $this->tokenStorage = $tokenStorage; } /** * @return object|string|null */ public function getActor() { $token = $this->tokenStorage->getToken(); return $token ? $token->getUser() : null; } } ``` -------------------------------- ### Initiating Transaction with Pessimistic Lock Source: https://github.com/doctrine-extensions/doctrineextensions/blob/main/doc/transaction-safety.md Demonstrates how to start a transaction and acquire a pessimistic lock on a Shop entity to prevent concurrent modifications. This is crucial for maintaining data integrity during atomic updates of related entities like Categories. ```php getEntityManager(); $conn = $em->getConnection(); $categoryRepository = $em->getRepository("App\Entity\Category"); // start transaction $conn->beginTransaction(); try { // select shop for update - locks it for any read attempts until this transaction ends ``` -------------------------------- ### Usage Example: 'pull' ReferenceIntegrity Source: https://github.com/doctrine-extensions/doctrineextensions/blob/main/doc/reference_integrity.md Demonstrates the 'pull' behavior for ReferenceMany associations. When a Type document is removed from a collection, it is automatically removed from the Article's types list. ```php setTitle('My Article'); $type1 = new Type; $type1->setTitle('Published'); $type2 = new Type; $type2->setTitle('Info'); $article->addType($type1); $article->addType($type2); $em->persist($article); $em->persist($type1); $em->persist($type2); $em->flush(); $type2 = $em->getRepository('Document\Type')->findByTitle('Info'); $em->remove($type2); $em->flush(); $article = $em->getRepository('Document\Article')->findByTitle('My Article'); $article->getTypes(); // will only contain $type1 ('Published') ``` -------------------------------- ### Advanced HTML Tree with Custom Decorators and Routes Source: https://github.com/doctrine-extensions/doctrineextensions/blob/main/doc/tree.md Generate an HTML tree using custom root/child decorators and a node decorator that utilizes controller routes for generating links. This example also demonstrates limiting levels. ```php childrenHierarchy(null, false, [ 'decorate' => true, 'rootOpen' => static function (array $tree): ?string { if ([] !== $tree && 0 == $tree[0]['lvl']) { return '
'; } return null; }, 'rootClose' => static function (array $child): ?string { if ([] !== $child && 0 == $child[0]['lvl']) { return '
'; } return null; }, 'childOpen' => '', 'childClose' => '', 'nodeDecorator' => static function (array $node) use (&$controller): ?string { if (1 == $node['lvl']) { return '

'.$node['title'].'

'; } if ($node["isVisibleOnHome"]) { return ' $node['id']]).'">'.$node['title'].' '; } return null; } ]); ``` -------------------------------- ### Custom IP Address Provider Implementation Source: https://github.com/doctrine-extensions/doctrineextensions/blob/main/doc/utils/ip-address-provider.md Implement the `IpAddressProviderInterface` to provide IP addresses. This example uses Symfony's HttpFoundation component to retrieve the client's IP address. Ensure the `RequestStack` is available in your application's service container. ```php namespace App\Utils; use Gedmo\Tool\IpAddressProviderInterface; use Symfony\Component\HttpFoundation\RequestStack; final class RequestIpAddressProvider implements IpAddressProviderInterface { private RequestStack $requestStack; public function __construct(RequestStack $requestStack) { $this->requestStack = $requestStack; } public function getAddress(): ?string { $request = $this->requestStack->getMainRequest(); return $request ? $request->getClientIp() : null; } } ``` -------------------------------- ### Entity Setup for Translatable Fields Source: https://context7.com/doctrine-extensions/doctrineextensions/llms.txt Define an entity that implements the Translatable interface and mark fields for translation using the Gedmo\Translatable annotation. You can also override the global locale per entity instance. ```php title = 'Food'; $fruits = new Category(); $fruits->title = 'Fruits'; $fruits->parent = $food; $veggies = new Category(); $veggies->title = 'Vegetables'; $veggies->parent = $food; $carrots = new Category(); $carrots->title = 'Carrots'; $carrots->parent = $veggies; $em->persist($food); $em->persist($fruits); $em->persist($veggies); $em->persist($carrots); $em->flush(); // DB: food(1-8), fruits(2-3), vegetables(4-7), carrots(5-6) ``` -------------------------------- ### XML Configuration for Blameable Field Source: https://github.com/doctrine-extensions/doctrineextensions/blob/main/doc/blameable.md Configure a field as blameable using XML mapping. This example sets the 'updatedBy' field on update. ```xml ``` -------------------------------- ### Test Sluggable Behavior Source: https://github.com/doctrine-extensions/doctrineextensions/blob/main/doc/sluggable.md Demonstrates how to create an entity, set its fields, persist it, and then retrieve the generated slug. ```php setTitle('the title'); $article->setCode('my code'); $this->em->persist($article); $this->em->flush(); echo $article->getSlug(); // prints: The_Title_My_Code ``` -------------------------------- ### Sluggable Annotation Mapping Example Source: https://github.com/doctrine-extensions/doctrineextensions/blob/main/doc/sluggable.md Defines an Article document with a slug generated from 'title' and 'code' fields using Doctrine ODM annotations. ```php id; } public function setTitle($title) { $this->title = $title; } public function getTitle() { return $this->title; } public function setCode($code) { $this->code = $code; } public function getCode() { return $this->code; } public function getSlug() { return $this->slug; } } ``` -------------------------------- ### PHP: Creating and Saving Tree Entities Source: https://github.com/doctrine-extensions/doctrineextensions/blob/main/doc/tree.md Demonstrates how to create new category entities, set their parent-child relationships, and persist them to generate a tree structure. Ensure the entity manager is available for persisting and flushing changes. ```php setTitle('Food'); $fruits = new Category(); $fruits->setTitle('Fruits'); $fruits->setParent($food); $vegetables = new Category(); $vegetables->setTitle('Vegetables'); $vegetables->setParent($food); $carrots = new Category(); $carrots->setTitle('Carrots'); $carrots->setParent($vegetables); $this->em->persist($food); $this->em->persist($fruits); $this->em->persist($vegetables); $this->em->persist($carrots); $this->em->flush(); ``` -------------------------------- ### Basic Sluggable Usage and Regeneration Source: https://context7.com/doctrine-extensions/doctrineextensions/llms.txt Demonstrates basic usage of the Sluggable behavior, including entity instantiation, persistence, and slug regeneration by setting the slug field to null. ```php // --- Basic usage --- $article = new Article(); $article->title = 'Hello World'; $article->code = 'hw'; $em->persist($article); $em->flush(); echo $article->slug; // "hello-world-hw" echo $article->fixedSlug; // "Hello_World" // Regenerate slug by setting to null $article->slug = null; $em->flush(); // Set manually (Sluggable ensures uniqueness) $article->slug = 'custom-slug'; $em->flush(); echo $article->slug; // "custom-slug" (or "custom-slug-1" if taken) ``` -------------------------------- ### ReferenceManyEmbed Attribute Example Source: https://github.com/doctrine-extensions/doctrineextensions/blob/main/doc/attributes.md Use ReferenceManyEmbed to establish a reference between objects in different databases or object managers, similar to MongoDB ODM's ReferenceMany. ```php */ #[Gedmo\ReferenceManyEmbed(type: 'entity', class: Comment::class, identifier: 'metadata.commentId')] private Collection $comments; public function __construct() { $this->comments = new ArrayCollection(); } } ``` -------------------------------- ### Setting Default Upload Path and Processing Files Source: https://github.com/doctrine-extensions/doctrineextensions/blob/main/doc/uploadable.md Demonstrates how to set a default upload path on the listener and process uploaded files from the $_FILES array, associating them with entities. ```php setDefaultPath('/my/app/web/upload'); if (isset($_FILES['images']) && is_array($_FILES['images'])) { foreach ($_FILES['images'] as $fileInfo) { $file = new File(); $listener->addEntityFileInfo($file, $fileInfo); // You can set the file info directly with a FileInfoInterface object, like this: // // $listener->addEntityFileInfo($file, new FileInfoArray($fileInfo)); // // Or create your own class which implements FileInfoInterface // // $listener->addEntityFileInfo($file, new MyOwnFileInfo($fileInfo)); $em->persist($file); } } $em->flush(); ``` -------------------------------- ### Using Repository Functions for Tree Operations Source: https://github.com/doctrine-extensions/doctrineextensions/blob/main/doc/tree.md Demonstrates various repository functions for interacting with tree structures, such as finding nodes, counting children, retrieving paths, verifying tree integrity, recovering corrupted trees, and removing nodes. ```php getRepository(Category::class); $food = $repo->findOneByTitle('Food'); echo $repo->childCount($food); // prints: 3 echo $repo->childCount($food, true/*direct*/); // prints: 2 $children = $repo->children($food); // $children contains: // 3 nodes $children = $repo->children($food, false, 'title'); // will sort the children by title $carrots = $repo->findOneByTitle('Carrots'); $path = $repo->getPath($carrots); /* $path contains: 0 => Food 1 => Vegetables 2 => Carrots */ $stringPath = $repo->getPathAsString([ 'includeNode' => false, 'separator' => '/', 'stringMethod' => 'getTitle', ]); // $stringPath is 'Food/Vegetables' // verification and recovery of tree // can return TRUE if tree is valid, or array of errors found on tree $repo->verify(); // if tree has errors it will try to fix all tree nodes $repo->recover([ 'flush' => false, // Do not auto-flush each entity manager after each node is recovered 'treeRootNode' => $rootNode, // Only recover the $rootNode tree (when you have a forest with multiple root nodes) 'skipVerify' => false, // Try to verify the tree first and do not attempt recovery if not necessary 'sortByField' => 'hierarchy', // Reorder sibling nodes by this field during recovery 'sortDirection' => 'DESC', ]); $em->flush(); // important: flush recovered nodes, unless you used ['flush' => true] // For large trees normal recovery can take a while, use this if speed is a priority. // No need to flush as it operates outside the entity manager (see phpdoc for side effects) $repo->recoverFast([ 'sortByField' => 'hierarchy', // Reorder sibling nodes by this field during recovery 'sortDirection' => 'DESC', ]); // UNSAFE: be sure to backup before running this method when necessary, if you can use $em->remove($node); // which would cascade to children // single node removal $vegies = $repo->findOneByTitle('Vegetables'); $repo->removeFromTree($vegies); $em->clear(); // clear cached nodes // it will remove this node from tree and reparent all children // reordering the tree $food = $repo->findOneByTitle('Food'); $repo->reorder($food, 'title'); // it will reorder all "Food" tree node left-right values by the title ``` -------------------------------- ### Shop Entity Definition Source: https://github.com/doctrine-extensions/doctrineextensions/blob/main/doc/transaction-safety.md Defines the basic Shop entity for an e-commerce platform. No specific setup is required beyond standard Doctrine entity mapping. ```php name = $name; return $this; } public function getName() { return $this->name; } } ``` -------------------------------- ### Configure Blameable Attribute for Creation Source: https://github.com/doctrine-extensions/doctrineextensions/blob/main/doc/attributes.md Use the Blameable attribute to track the user who created an entity. This example sets the `createdBy` field upon entity creation. ```php name = 'Alpha'; $a->category = 'tech'; $b = new Item(); $b->name = 'Beta'; $b->category = 'tech'; $em->persist($a); $em->persist($b); $em->flush(); // $a->position === 0, $b->position === 1 // --- Insert at specific position --- $c = new Item(); $c->name = 'Zero'; $c->category = 'tech'; $c->position = 0; $em->persist($c); $em->flush(); // $c->position===0, $a->position===1, $b->position===2 // --- Reorder by setting position --- $b->position = 0; $em->flush(); // $b->position===0, $c->position===1, $a->position===2 // --- Move to end with -1 --- $c->position = -1; $em->flush(); // --- Query by group --- /** @var SortableRepository $repo */ $repo = $em->getRepository(Item::class); $items = $repo->getBySortableGroupsQuery(['category' => 'tech'])->getResult(); foreach ($items as $item) { echo $item->position . ': ' . $item->name . PHP_EOL; } // 0: Beta // 1: Alpha // 2: Zero (was moved to end via -1) ``` -------------------------------- ### Register ORM Listeners for Doctrine Behavioral Extensions Source: https://context7.com/doctrine-extensions/doctrineextensions/llms.txt Manually attach all Doctrine Behavioral Extension listeners to an ORM EntityManager. This setup is required for the extensions to function. ```php getEventManager(); // Register each extension as an event subscriber $evm->addEventSubscriber(new TreeListener()); $evm->addEventSubscriber(new SluggableListener()); $evm->addEventSubscriber(new SortableListener()); $evm->addEventSubscriber(new SoftDeleteableListener()); $timestampableListener = new TimestampableListener(); $timestampableListener->setClock(new Symfony Components Clock NativeClock()); // optional PSR-20 clock $evm->addEventSubscriber($timestampableListener); $blameableListener = new BlameableListener(); $blameableListener->setUserValue('admin'); // or set an object $evm->addEventSubscriber($blameableListener); $ipTraceableListener = new IpTraceableListener(); $ipTraceableListener->setIpValue('127.0.0.1'); $evm->addEventSubscriber($ipTraceableListener); $loggableListener = new LoggableListener(); $loggableListener->setUsername('admin'); $evm->addEventSubscriber($loggableListener); $translatableListener = new TranslatableListener(); $translatableListener->setDefaultLocale('en'); $translatableListener->setTranslatableLocale('en'); $evm->addEventSubscriber($translatableListener); // Register the soft-deleteable ORM filter $em->getConfiguration()->addFilter('soft-deleteable', Gedmo SoftDeleteable Filter SoftDeleteableFilter::class); $em->getFilters()->enable('soft-deleteable'); ``` -------------------------------- ### Inject IP Address Provider into Listener Source: https://github.com/doctrine-extensions/doctrineextensions/blob/main/doc/utils/ip-address-provider.md After creating your IP address provider, inject it into the relevant extension listener using the `setIpAddressProvider` method. This ensures the extension uses your custom logic for retrieving IP addresses. ```php /** @var Gedmo\IpTraceable\IpTraceableListener $listener */ $listener->setIpAddressProvider($provider); ``` -------------------------------- ### Inserting Nodes in Different Positions Source: https://github.com/doctrine-extensions/doctrineextensions/blob/main/doc/tree.md Illustrates how to insert new nodes into the tree at specific positions, such as the first child, last child, or as a sibling to an existing node. ```php setTitle('Food'); $fruits = new Category(); $fruits->setTitle('Fruits'); $vegetables = new Category(); $vegetables->setTitle('Vegetables'); $carrots = new Category(); $carrots->setTitle('Carrots'); $treeRepository ->persistAsFirstChild($food) ->persistAsFirstChildOf($fruits, $food) ->persistAsLastChildOf($vegetables, $food) ->persistAsNextSiblingOf($carrots, $fruits); $em->flush(); ``` -------------------------------- ### Slug Attribute Basic Example Source: https://github.com/doctrine-extensions/doctrineextensions/blob/main/doc/attributes.md Configure the Slug attribute to specify the field for storing the generated slug. The 'fields' parameter is mandatory and lists the source fields for slug generation. ```php id; } public function setTitle($title) { $this->title = $title; } public function getTitle() { return $this->title; } public function setCode($code) { $this->code = $code; } public function getCode() { return $this->code; } public function getSlug() { return $this->slug; } public function getUniqueSlug() { return $this->uniqueSlug; } } ``` -------------------------------- ### Setting IP Address Provider or Value Source: https://github.com/doctrine-extensions/doctrineextensions/blob/main/doc/ip_traceable.md You can set the IP address to be recorded either through an IP address provider service implementing Gedmo\Tool\IpAddressProviderInterface or by directly calling the listener's setIpValue method. ```php // The $provider must be an implementation of Gedmo\Tool\IpAddressProviderInterface $listener->setIpAddressProvider($provider); $listener->setIpValue('127.0.0.1'); ```