2

I am using laravel backpack to build a backoffice administration and im stuck at this, that is maybe a very basic doubt.

Im in a case where i have:

Table Event:

id - name - themeID - more fields...

Table Theme:

id - name

So, a theme can have various events and a event can have various themes, i have some doubts on how to achieve this, what i did:

Theme.php

<?php

namespace App\Models;

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

class Theme extends Model
{
    use CrudTrait;

     /*
    |--------------------------------------------------------------------------
    | GLOBAL VARIABLES
    |--------------------------------------------------------------------------
    */

    protected $table = 'themes';
    //protected $primaryKey = 'id';
    // public $timestamps = false;
    // protected $guarded = ['id'];
    protected $fillable = ['name'];
    // protected $hidden = [];
    // protected $dates = [];

    /*
    |--------------------------------------------------------------------------
    | FUNCTIONS
    |--------------------------------------------------------------------------
    */

    /*
    |--------------------------------------------------------------------------
    | RELATIONS
    |--------------------------------------------------------------------------
    */

    public function Theme() {
      return $this->hasMany('App\Models\Event');
    }

    /*
    |--------------------------------------------------------------------------
    | SCOPES
    |--------------------------------------------------------------------------
    */

    /*
    |--------------------------------------------------------------------------
    | ACCESORS
    |--------------------------------------------------------------------------
    */

    /*
    |--------------------------------------------------------------------------
    | MUTATORS
    |--------------------------------------------------------------------------
    */
}

Event.php

    <?php

namespace App\Models;

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

class Event extends Model
{
    use CrudTrait;

     /*
    |--------------------------------------------------------------------------
    | GLOBAL VARIABLES
    |--------------------------------------------------------------------------
    */

    protected $table = 'events';
    //protected $primaryKey = 'id';
    // public $timestamps = false;
    // protected $guarded = ['id'];
    protected $fillable = ['name','theme','schedules','themeID','countyID','event_typeID','offered_conditionID','alone_with_typeID','tagID',
    'advertiserID','event_languageID','special_priceID','start_date','end_date','price','photos','space_name','address','description','facebook_url',
    'external_url1','featured_image','available_vacancies','gps_coordinates','external_url2','featured','status','start_featured_date','end_featured_date'];

    // protected $hidden = [];
    // protected $dates = [];

    /*
    |--------------------------------------------------------------------------
    | FUNCTIONS
    |--------------------------------------------------------------------------
    */

    /*
    |--------------------------------------------------------------------------
    | RELATIONS
    |--------------------------------------------------------------------------
    */

    public function Event() {
        return $this->hasOne('App\Models\EventSubType');
        return $this->hasMany('App\Models\SpecialPrice');
        return $this->hasMany('App\Models\PriceTypes');
        return $this->hasMany('App\Models\Tag');
        // return $this->hasMany('App\Models\County');
        return $this->hasMany('App\Models\County');
        return $this->hasMany('App\Models\EventHasSpecialPrice');
    }

    public function themes()
    {
        return $this->belongsToMany('App\Models\Theme');
    }

    /*
    |--------------------------------------------------------------------------
    | SCOPES
    |--------------------------------------------------------------------------
    */

    /*
    |--------------------------------------------------------------------------
    | ACCESORS
    |--------------------------------------------------------------------------
    */

    /*
    |--------------------------------------------------------------------------
    | MUTATORS
    |--------------------------------------------------------------------------
    */
}

EventCrudController.php

    <?php

namespace App\Http\Controllers\Admin;

use Backpack\CRUD\app\Http\Controllers\CrudController;

// VALIDATION: change the requests to match your own file names if you need form validation
use App\Http\Requests\EventRequest as StoreRequest;
use App\Http\Requests\EventRequest as UpdateRequest;

class EventCrudController extends CrudController
{

    public function setUp()
    {

        /*
        |--------------------------------------------------------------------------
        | BASIC CRUD INFORMATION
        |--------------------------------------------------------------------------
        */
        $this->crud->setModel('App\Models\Event');
        $this->crud->setRoute(config('backpack.base.route_prefix') . '/events');
        $this->crud->setEntityNameStrings('event', 'events');

        /*
        |--------------------------------------------------------------------------
        | BASIC CRUD INFORMATION
        |--------------------------------------------------------------------------
        */

       /* $this->crud->addColumn([
            'label' => "Theme", // Table column heading
            'type' => "select_multiple",
            'name' => 'themes', // the column that contains the ID of that connected entity;
            'entity' => 'themes', // the method that defines the relationship in your Model
            'attribute' => "name", // foreign key attribute that is shown to user
            'model' => 'App\Models\Theme', // foreign key model
            'pivot' => true,
        ]); */

        $this->crud->setFromDb();

        $this->crud->addFields([
        // This is the field im trying to get working
          [
              'label' => 'Theme',
              'type' => 'select_multiple',
              'name' => 'themeID',
              'entity'=> 'Event',
              'attribute' => 'name', // Column which user see in select box
              'model' => 'App\Models\Theme' // Model which contain FK
          ],
          [
              'label' => 'District',
              'type' => 'select2',
              'name' => 'countyID',
              'entity'=> 'district',
              'attribute' => 'name', // Column which user see in select box
              'model' => 'App\Models\District' // Model which contain FK
          ],
          [
              'label' => 'Event Type',
              'type' => 'select2',
              'name' => 'event_typeID',
              'entity'=> 'EventType',
              'attribute' => 'name', // Column which user see in select box
              'model' => 'App\Models\EventType' // Model which contain FK
          ],
          [
              'label' => 'Offered Conditions',
              'type' => 'select2',
              'name' => 'offered_conditionID',
              'entity'=> 'OfferedCondition',
              'attribute' => 'name', // Column which user see in select box
              'model' => 'App\Models\OfferedCondition' // Model which contain FK
          ],
          [
              'label' => 'Alone With Types',
              'type' => 'select2',
              'name' => 'alone_with_typeID',
              'entity'=> 'AloneWithType',
              'attribute' => 'name', // Column which user see in select box
              'model' => 'App\Models\AloneWithType' // Model which contain FK
          ],
          [
              'label' => 'Tags',
              'type' => 'select2',
              'name' => 'tagID',
              'entity'=> 'Tag',
              'attribute' => 'name', // Column which user see in select box
              'model' => 'App\Models\Tag' // Model which contain FK
          ],
          [
              'label' => 'Advertiser',
              'type' => 'select2',
              'name' => 'advertiserID',
              'entity'=> 'Advertiser',
              'attribute' => 'name', // Column which user see in select box
              'model' => 'App\Models\Advertiser' // Model which contain FK
          ],
          [
              'label' => 'Event Language',
              'type' => 'select2',
              'name' => 'event_languageID',
              'entity'=> 'Event_language',
              'attribute' => 'name', // Column which user see in select box
              'model' => 'App\Models\EventLanguage' // Model which contain FK
          ],
          [
              'label' => 'Special Price',
              'type' => 'select2',
              'name' => 'special_priceID',
              'entity'=> 'SpecialPrice',
              'attribute' => 'name', // Column which user see in select box
              'model' => 'App\Models\SpecialPrice' // Model which contain FK
        ]
        ]);

        /* $this->crud->addField([
              'label' => "Images",
              'name' => "photos",
              'type' => 'image_multiple',
              'upload' => true,
              'crop' => true, // set to true to allow cropping, false to disable
              'aspect_ratio' => 0, // ommit or set to 0 to allow any aspect ratio
          ]); */

        // $this->crud->addFields($array_of_arrays, 'update/create/both');
        // $this->crud->removeField('name', 'update/create/both');
        // $this->crud->removeFields($array_of_names, 'update/create/both');

        // ------ CRUD COLUMNS
        // $this->crud->addColumn(); // add a single column, at the end of the stack
        // $this->crud->addColumns(); // add multiple columns, at the end of the stack
        // $this->crud->removeColumn('column_name'); // remove a column from the stack
        // $this->crud->removeColumns(['column_name_1', 'column_name_2']); // remove an array of columns from the stack
        // $this->crud->setColumnDetails('column_name', ['attribute' => 'value']); // adjusts the properties of the passed in column (by name)
        // $this->crud->setColumnsDetails(['column_1', 'column_2'], ['attribute' => 'value']);

        // ------ CRUD BUTTONS
        // possible positions: 'beginning' and 'end'; defaults to 'beginning' for the 'line' stack, 'end' for the others;
        // $this->crud->addButton($stack, $name, $type, $content, $position); // add a button; possible types are: view, model_function
        // $this->crud->addButtonFromModelFunction($stack, $name, $model_function_name, $position); // add a button whose HTML is returned by a method in the CRUD model
        // $this->crud->addButtonFromView($stack, $name, $view, $position); // add a button whose HTML is in a view placed at resources\views\vendor\backpack\crud\buttons
        // $this->crud->removeButton($name);
        // $this->crud->removeButtonFromStack($name, $stack);

        // ------ CRUD ACCESS
        // $this->crud->allowAccess(['list', 'create', 'update', 'reorder', 'delete']);
        // $this->crud->denyAccess(['list', 'create', 'update', 'reorder', 'delete']);

        // ------ CRUD REORDER
        // $this->crud->enableReorder('label_name', MAX_TREE_LEVEL);
        // NOTE: you also need to do allow access to the right users: $this->crud->allowAccess('reorder');

        // ------ CRUD DETAILS ROW
        // $this->crud->enableDetailsRow();
        // NOTE: you also need to do allow access to the right users: $this->crud->allowAccess('details_row');
        // NOTE: you also need to do overwrite the showDetailsRow($id) method in your EntityCrudController to show whatever you'd like in the details row OR overwrite the views/backpack/crud/details_row.blade.php

        // ------ REVISIONS
        // You also need to use \Venturecraft\Revisionable\RevisionableTrait;
        // Please check out: https://laravel-backpack.readme.io/docs/crud#revisions
        // $this->crud->allowAccess('revisions');

        // ------ AJAX TABLE VIEW
        // Please note the drawbacks of this though:
        // - 1-n and n-n columns are not searchable
        // - date and datetime columns won't be sortable anymore
        // $this->crud->enableAjaxTable();

        // ------ DATATABLE EXPORT BUTTONS
        // Show export to PDF, CSV, XLS and Print buttons on the table view.
        // Does not work well with AJAX datatables.
        // $this->crud->enableExportButtons();

        // ------ ADVANCED QUERIES
        // $this->crud->addClause('active');
        // $this->crud->addClause('type', 'car');
        // $this->crud->addClause('where', 'name', '==', 'car');
        // $this->crud->addClause('whereName', 'car');
        // $this->crud->addClause('whereHas', 'posts', function($query) {
        //     $query->activePosts();
        // });
        // $this->crud->addClause('withoutGlobalScopes');
        // $this->crud->addClause('withoutGlobalScope', VisibleScope::class);
        // $this->crud->with(); // eager load relationships
        // $this->crud->orderBy();
        // $this->crud->groupBy();
        // $this->crud->limit();
    }

    public function store(StoreRequest $request)
       {

     /*
      // Setup storage
      $attribute_name = "photos";
      $disk = "uploads";
      $destination_path = "/uploads/projects";

        // Then get images from request
        $input = $request->all();
        $images = $input[$attribute_name];
        $imageArray = [];
        // Now iterate images
      foreach ($images as $value) {
          // Store on disk and add to array
          if (starts_with($value, 'data:image'))
          {
                // 0. Make the image
                $image = \Image::make($value);
                // 1. Generate a filename.
                $filename = md5($value.time()).'.jpg';
                // 2. Store the image on disk.
                \Storage::disk($disk)->put($destination_path.'/'.$filename, $image->stream());
                // 3. Save the path to the database
                array_push($imageArray, $destination_path.'/'.$filename);
            }
        }

        // Update $request with new array
        $request->request->set($attribute_name, $imageArray);
        */
            // Save $request
        $redirect_location = parent::storeCrud($request);
        // your additional operations after save here
        // use $this->data['entry'] or $this->crud->entry
        return $redirect_location;
    }

    public function update(UpdateRequest $request)
    {
        // Setup storage
        $attribute_name = "images";
        $disk = "uploads";
        $destination_path = "/uploads/projects";
        // Then get images from request
        $input = $request->all();
        $images = $input[$attribute_name];
        $imageArray = [];
        // Now iterate images
        foreach ($images as $value) {
            // Store on disk and add to array
            if (starts_with($value, 'data:image'))
            {
                // 0. Make the image
                $image = \Image::make($value);
                // 1. Generate a filename.
                $filename = md5($value.time()).'.jpg';
                // 2. Store the image on disk.
                \Storage::disk($disk)->put($destination_path.'/'.$filename, $image->stream());
                // 3. Save the path to the database
                array_push($imageArray, $destination_path.'/'.$filename);
            } else {
                array_push($imageArray, $value);
            }
        }
        // Update $request with new array
        $request->request->set($attribute_name, $imageArray);
        // your additional operations before save here
        $redirect_location = parent::updateCrud($request);
        // your additional operations after save here
        // use $this->data['entry'] or $this->crud->entry
        return $redirect_location;
    }

    /* public function store(StoreRequest $request)
    {
        // your additional operations before save here
        $redirect_location = parent::storeCrud();
        // your additional operations after save here
        // use $this->data['entry'] or $this->crud->entry
        return $redirect_location;
    }

    public function update(UpdateRequest $request)
    {
        // your additional operations before save here
        $redirect_location = parent::updateCrud();
        // your additional operations after save here
        // use $this->data['entry'] or $this->crud->entry
        return $redirect_location;
    } */
}

Do i need a pivot table ? What am i missing ? I find little documentation on this.

The error im getting is the following one:

Array to string conversion, he tries to save on the field array('1','2') and the error happens there.

  • Hi Duarte. I don't think your relationships are setup correctly. Your event() relationship, on the Event model, doesn't make much sense to me, unless you plan to reference an element to itself. But even in that case, too many returns in one funcgion. Only the first one will be run. Take a harder look at the Laravel documentation on rationships - it explains everything very clearly. Don't skim :-) Read :-) – tabacitu Jul 06 '17 at 09:44

1 Answers1

1

As explained by @tabacitu, your relations are wrong. You got one of them right, but every relationship should be defined like the one bellow, and not on the construct method as you did:

public function themes()
{
    return $this->belongsToMany('App\Models\Theme');
}

You can find all the information you need reading the Laravel docs about Eloquent Relationship.

Once you have that setup, you can make this work

$this->crud->addFields([
      // This is the field im trying to get working
      [
          'label' => 'Theme',
          'type' => 'select_multiple',
          'name' => 'themeID',
          'entity'=> 'themes', // <-- this is the relation method name
          'attribute' => 'name', // Column which user see in select box
          'model' => 'App\Models\Theme' // Model which contain FK
      ],
Stephen Rauch
  • 47,830
  • 31
  • 106
  • 135
Claudson Martins
  • 348
  • 1
  • 3
  • 14