lundi 4 septembre 2017

Laravel backpack CRUD unexpected data on delete with cascade

I've installed Backpack CRUD in my project and ran across a problem.

I've got a categories CRUD page, where it should be possible to have an infinite level of re-ordering. It should also be possible to set a parent_id to each category, which is a self-join and is not required.

The problem is whenever I delete a category which has one or more children categories, only the selected category is deleted out the view. When I refresh the page manually, the children categories are also deleted. By that I noticed the page uses AJAX to refresh its data.

The category and children category are deleted out the database.

My CRUD controller looks like this:

<?php

namespace App\Http\Controllers\Admin;

use App\Models\Statement\StatementCategory;
use Backpack\CRUD\app\Http\Controllers\CrudController;

use Backpack\CRUD\app\Http\Requests\CrudRequest as StoreRequest;
use Backpack\CRUD\app\Http\Requests\CrudRequest as UpdateRequest;

class CategoryCRUDController extends CrudController
{
    public function __construct()
    {
        parent::__construct();

        $this->crud->setModel(StatementCategory::class);
        $this->crud->setRoute(config('backpack.base.route_prefix').'/categories');
        $this->crud->setEntityNameStrings('category', 'categories');

        $this->crud->allowAccess('reorder');

        # Enable infinite reorder
        $this->crud->enableReorder('name', 0);

        # Add the columns
        $this->crud->addColumn([
                                'name' => 'name',
                                'label' => 'Label',
                            ]);
        $this->crud->addColumn([
                                'label' => 'Parent',
                                'type' => 'select',
                                'name' => 'parent_id',
                                'entity' => 'parent',
                                'attribute' => 'name',
                                'model' => "\App\Models\Statement\StatementCategory",
                            ]);


        # Add the fields
        $this->crud->addField([
                                'name' => 'name',
                                'label' => 'Label',
                            ]);

        $this->crud->addField([
            'label' => 'Parent',
            'type' => 'select',
            'name' => 'parent_id',
            'entity' => 'parent',
            'attribute' => 'name',
            'model' => "\App\Models\Statement\StatementCategory",
        ], 'create');

        $currentCategoryID = \Route::input('category');

        if($currentCategoryID != null) {
            # Get all the statement categories without the current one and it's children
            $categoriesWithoutCurrentAndCurrentChildren = StatementCategory::all()->where('parent_id', '!=', $currentCategoryID)->where('id', '!=', $currentCategoryID)->pluck('name', 'id');

            # Add the categories only to the update page
            $this->crud->addField([
                'label' => 'Parent',
                'type' => 'select_from_array',
                'name' => 'parent_id',
                # Add the empty option
                'options' => ['' => '-'] + $categoriesWithoutCurrentAndCurrentChildren->toArray()
            ], 'update');
        }
    }

    public function store(StoreRequest $request)
    {
        return parent::storeCrud($request);
    }

    public function update(UpdateRequest $request)
    {
        return parent::updateCrud($request);
    }
}

Where my StatementCategory class looks like this:

<?php

namespace App\Models\Statement;

use Backpack\CRUD\CrudTrait;
use Illuminate\Database\Eloquent\Model;

/**
 * @package App
 */
class StatementCategory extends Model
{
    use CrudTrait;

    /**
     * @var array $fillable Columns for mass assignment
     */
    protected $fillable = ['name', 'parent_id'];

    /**
     * Retrieves the parent of this category
     */
    public function parent()
    {
        return $this->belongsTo(StatementCategory::class, 'parent_id');
    }

    /**
     * Retrieves the children categories of this category
     */
    public function children()
    {
        return $this->hasMany(StatementCategory::class, 'parent_id');
    }
}

I'm using MySQL for my database, my table looks like this:

CREATE TABLE `statement_categories` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(100) NOT NULL,
  `parent_id` int(11) DEFAULT NULL,
  `lft` int(10) unsigned DEFAULT NULL,
  `rgt` int(10) unsigned DEFAULT NULL,
  `depth` int(10) unsigned DEFAULT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `updated_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `id_UNIQUE` (`id`),
  UNIQUE KEY `name_UNIQUE` (`name`),
  KEY `fk_statement_categories_statement_categories1_idx` (`parent_id`),
  CONSTRAINT `fk_statement_categories_statement_categories1`
    FOREIGN KEY (`parent_id`) REFERENCES `statement_categories` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8;

How can I make it so that the children rows also get deleted out of the view?



via Chebli Mohamed

Aucun commentaire:

Enregistrer un commentaire