Skip to content

Resource guide

WARNING

This article is outdated and may contain information that are not in use anymore

Add listener

tbc.

Add Tab

tbc.

Delete Statements

There are three different statements in doctrine to delete. This entry shows your possibilities and help you to decide which statement should use.

To understand the statements we will apply them on an example. Think of books and chapters, where book is the parent and chapter is the child and owning entity.

image

Orphan Removal

Orphan removal delete a child entity on flush if its relation changed. So you need to apply orphan removal on book. You will use Orphan removal every time you use child elements that can be added and deleted. For example in a CollectionType in Symfony forms. Orphan removal don't have any effects if you just delete books. So if a book will be deleted, the chapter entities still exists.

yaml
Book:
    oneToMany:
        chapters:
            targetEntity: Chapter
            mappedBy: book
            orphanRemoval: true

Chapter:
    manyToOne:
        book:
            targetEntity: Book

So change mean, if you call a setter and change the current member variable of chapter.

php
<?php

$chapter->setBook($book);     // Set it first time
$em->flush();

$chapter->setBook($book);     // nothing changed
$chapter->setBook($otherBook) // member variable changed
$chapter->setOtherBook($book) // member variable changed
$em->flush();                 // Orphan removal will be triggered

So if you work with the book class, you need to add setter to it, because chapter is the child but the owning entity

php
<?php

class Book {

    public function addChapter(Chapter $chapter)
    {
        $chapter->setBook($this); // This line need to be added
        $this->chapters[] = $chapter;
        return $this;
    }

    public function removeChapter(Chapter $chapter)
    {
        $chapter->setBook(null); // This line need to be added
        $this->chapters->removeElement($chapter);
    }

Cascade Remove

Cascade remove will call a doctrine remove on all child elements if it was called on the parent. You apply a cascade remove on the parent entity. Normally you use it, if the child element only exists with a parent. So a chapter never exists alone, it will need a book.

yaml
Book:
    oneToMany:
        chapters:
            cascade: ['remove']
            targetEntity: Chapter
            mappedBy: book

Chapter:
    manyToOne:
        book:
            targetEntity: Book
php
<?php

$book->addChapter($chapter)
$em->remove($book);
$em->flush();   // chapter will also be deleted, $em->remove($chapter) will be called automatically

On Delete Cascade

On delete cascade is a mysql feature and will remove all child elements if the parent was deleted. So it's like the cascade remove from doctrine, but you need to apply it on the child entity instead of the parent. Because it's a mysql feature, doctrine won't take notice if the child will be deleted. Normally that's that a problem, as long as you don't work with the child after you delete the parent. Like cascade remove, you use it if the child element only exists with a parent.

yaml
Book:
    oneToMany:
        chapters:
            targetEntity: Chapter
            mappedBy: book

Chapter:
    manyToOne:
        book:
            targetEntity: Book
            joinColumn:
                onDelete: CASCADE
php
<?php

$book->addChapter($chapter)
$em->remove($book);
$em->flush();   // chapter will also be deleted by mysql. You should avoid to go on working with $chapter

Extend from resource

Sometime you wan't add more properties to an enhavo entity. This is simple done by some configuration. But first of all you have to extend the class.

php
namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 */
class Page extends Enhavo\Bundle\PageBundle\Entity\Page
{
    // .. add your properties and mapping information
}

Extend doctrine

Now you have to add mapping information to the EnhavoDoctrineExtensionBundle

yaml
enhavo_doctrine_extension:
    metadata:
        App\Entity\Page:
            extends: Enhavo\Bundle\PageBundle\Entity\Page
            discrName: 'app'

Change Resource

If the entity you want to extend is a sylius resource (Check it it implements the ResourceInterface). Then you also have to change the model configuration. If it's not a sylius resource you can skip this step.

yaml
enhavo_page:
    resources:
        page:
            classes:
                model: App\Entity\Page

Update doctrine interface

In some cases you also have to update the interface information in doctrine. This is needed for other entities that will refer to your extended entity.

yaml
doctrine:
    orm:
        resolve_target_entities:
            Enhavo\Bundle\PageBundle\Model\PageInterface: App\Entity\Page

Making a resource sortable

Sometimes the instances of your resource need to be in a specific order that can be changed by the user. An example would be the entries of a menu, or slides in a slider.

For this example, we will use the entity Slide from EnhavoSliderBundle.

Add position property

The first thing your resource needs to have is an integer property to save it's position in the order. In this example it will be called position.

php
class Slider {

    //...

    /**
     * @var integer
     **/
    protected position;

    /**
     * @param integer $position
     */
    public function setPosition($position)
    {
        $this->position = $position;
    }

    /**
     * @return integer
     */
    public function getPosition()
    {
        return $this->position;
    }

    //...

}

This property also needs to be added to the Doctrine definitions, of course.

Generate routes

If you are creating a new resource rather than modifying an existing one, you can use the route generator command (see CRUD Routing generator). It has an optional parameter sorting that, if set to the property name defined above, adds route configurations for sortable resources.

Add route changes manually

If you are not creating a new resource but rather modifying an existing one, here are the route configurations to do manually to activate sortable behaviour.

1. Add routes for moving items to new positions

There are two routes specifically for moving the resource item to its new position. These are not present by default, they are only needed for sortable resources.

Note: If you changed the pagination value in the table route, you need to add the same value to the move_to_page route as well (defaults: _sylius: paginate: x)

yaml
enhavo_slider_slide_move_after:
    options:
        expose: true
    path: /enhavo/slider/slide/move-after/{id}/{target}
    methods: [POST]
    defaults:
        _controller: {{ app }}.controller.{{ resource }}:moveAfterAction

enhavo_slider_slide_move_to_page:
    options:
        expose: true
    path: /enhavo/slider/slide/move-to-page/{id}/{page}/{top}
    methods: [POST]
    defaults:
        _controller: {{ app }}.controller.{{ resource }}:moveDownAction

2. Modify table route

The table route defines the view where the user can see a table of all the resource items. You need to modify this route so that the items appear in the right order. Also you have to add an extra column to the table to display the drag/drop button for moving the item.

yaml
enhavo_slider_slide_table:
    options:
        expose: true
    path: /enhavo/slider/slide/table
    methods: [GET]
    defaults:
        _controller: enhavo_slider.controller.slide:tableAction
        _sylius:
            sortable: true              # add sortable
            sorting:                    # add sorting
                position: desc          # [property name]:[sort order], can be "desc" or "asc"
            viewer:
                columns:
                    # ... other columns
                    position:                                                  # add this column
                        type: position                                         #

Commented lines are new.

3. Modify create route

If a new item of the resource is created, it needs an initial value for its sorting position. Therefore, you also need to modify the create route.

yaml
enhavo_slider_slide_create:
    options:
        expose: true
    path: /enhavo/slider/slide/create
    methods: [GET,POST]
    defaults:
        _controller: enhavo_slider.controller.slide:createAction
        _sylius:
            sortable: true  # add sortable

Commented lines are new.

If the value of initial is "max" (default), the newly created item will have an initial position value that is the current maximum value plus one. If your sorting order defined in previous routes is "desc", this means that the new item will be the new first element, else it will be the last. A value of "min" will set the initial value to 0 and shift all existing items up by one, which can be slow for large amounts of data and is not recommended.