Skip to content
This repository has been archived by the owner on Jul 28, 2022. It is now read-only.

Adding Resources

Rodolfo Ruiz edited this page Jul 19, 2018 · 9 revisions

For example, we are going to add Categories resource to the project. You will be able to create, read, update and delete records if you follow the steps below:

  • Model

    • generate model and migration
php artisan make:model Models/Category --migration
  • Category Model Class
<?php

namespace App\Models;

use App\Traits\Eloquent\SearchLikeTrait;
use App\Traits\Models\FillableFields;
use Illuminate\Database\Eloquent\Model;

class Category extends Model
{
    use FillableFields, SearchLikeTrait;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name', 'url',
    ];

    /**
     * @return mixed
     */
    public function getRecordTitle()
    {
        return $this->name;
    }
}
  • CreateCategoriesTable Migration Class
<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateCategoriesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('categories', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->text('url');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('categories');
    }
}
  • Policy

php artisan make:policy CategoryPolicy --model=Category
  • CategoryPolicy Policy Class
<?php

namespace App\Policies;

use App\User;
use App\Models\Category;
use Illuminate\Auth\Access\HandlesAuthorization;

class CategoryPolicy
{
    use HandlesAuthorization;

    /**
     * @param User $user
     * @param $ability
     * @return bool
     */
    public function before(User $user, $ability)
    {
        if ($user->isAdmin()) {
            return true;
        }
    }

    /**
     * Determine whether the user can manage records.
     *
     * @param  \App\User $user
     * @return mixed
     */
    public function manage(User $user)
    {
        return $user->isAdmin();
    }

    /**
     * Determine whether the user can list models.
     *
     * @param  User $user
     * @return mixed
     */
    public function viewList(User $user)
    {
        return $user->isAdmin();
    }

    /**
     * Determine whether the user can view the record.
     *
     * @param  \App\User  $user
     * @param  \App\Models\Category  $record
     * @return mixed
     */
    public function view(User $user, Category $record)
    {
        return $user->isAdmin();
    }

    /**
     * Determine whether the user can create records.
     *
     * @param  \App\User  $user
     * @return mixed
     */
    public function create(User $user)
    {
        return $user->isAdmin();
    }

    /**
     * Determine whether the user can update the record.
     *
     * @param  \App\User  $user
     * @param  \App\Models\Category  $record
     * @return mixed
     */
    public function update(User $user, Category $record)
    {
        return $user->isAdmin();
    }

    /**
     * Determine whether the user can delete the record.
     *
     * @param  \App\User  $user
     * @param  \App\Models\Category  $record
     * @return mixed
     */
    public function delete(User $user, Category $record)
    {
        return $user->isAdmin();
    }
}
    /**
     * The policy mappings for the application.
     *
     * @var array
     */
    protected $policies = [
        \App\User::class => \App\Policies\UserPolicy::class,
        \App\Models\Category::class => \App\Policies\CategoryPolicy::class,
    ];
  • Controller

php artisan make:controller Admin/CategoriesController

This boilerplate provides a ResourceController trait that will handle authorization and the typical "CRUD" routes. You just have to focus on the unique settings for every controller like:

  • $resourceAlias => resource views path.
  • $resourceRoutesAlias => route prefix.
  • $resourceModel => what model to use to interact with the database.
  • $resourceTitle => title to show when listing, editing and creating.
  • resourceStoreValidationData => function to validate values when creating the record
  • resourceUpdateValidationData($record) => function to validate values when updating the record.
  • getSearchRecords(Request $request, $perPage = 15, $search = null) => function to filter and list records.
<?php

namespace App\Http\Controllers\Admin;

use App\Models\Category;
use App\Traits\Controllers\ResourceController;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

class CategoriesController extends Controller
{
    use ResourceController;

    /**
     * @var string
     */
    protected $resourceAlias = 'admin.categories';

    /**
     * @var string
     */
    protected $resourceRoutesAlias = 'admin::categories';

    /**
     * Fully qualified class name
     *
     * @var string
     */
    protected $resourceModel = Category::class;

    /**
     * @var string
     */
    protected $resourceTitle = 'Categories';

     /**
     * Used to validate store.
     *
     * @return array
     */
    private function resourceStoreValidationData()
    {
        return [
            'rules' => [
                'name' => 'required|min:3|max:255'
                'url' => 'required|url'
            ],
            'messages' => [],
            'attributes' => [],
        ];
    }

    /**
     * Used to validate update.
     *
     * @param $record
     * @return array
     */
    private function resourceUpdateValidationData($record)
    {
        return $this->resourceStoreValidationData();
    }

    /**
     * @param \Illuminate\Http\Request $request
     * @param null $record
     * @return array
     */
    private function getValuesToSave(Request $request, $record = null)
    {
        $values = $request->only([
            'name', 'url',
        ]);

        return $values;
    }

    /**
     * Retrieve the list of the resource.
     *
     * @param \Illuminate\Http\Request $request
     * @param int $perPage
     * @param string|null $search
     * @return \Illuminate\Support\Collection
     */
    private function getSearchRecords(Request $request, $perPage = 15, $search = null)
    {
        $query = $this->getResourceModel()::when(! empty($search), function ($query) use ($search) {
            $query->like('name', $search);
        });

        return $query->paginate($perPage);
    }
}
  • Routes

    /**
     * // Matches The "/admin/*" URLs
     */
    Route::group(['prefix' => 'admin', 'namespace' => 'Admin', 'as' => 'admin::'], function () {
        /**
         * Admin Access
         */
        Route::group(['middleware' => 'admin'], function () {
            /**
             * Admin Index
             * // Route named "admin::index"
             */
            Route::get('/', ['as' => 'index', 'uses' => 'IndexController@index']);

            /**
             * Manage Users.
             * // Routes name "admin.users.*"
             */
            Route::resource('users', 'UsersController');

            /**
             * Manage Categories.
             * // Routes name "admin.categories.*"
             */
            Route::resource('categories', 'CategoriesController');
        });
    });
  • Views

    • Because the powerfull ResourceController trait is reusing the resources views you only have to create the form and the table sub-views. Optionally you can create a sub-view "_search" when you want to filter by multiple fields. Create "categories" directory under "admin" directory and the following views:
      • form.blade.php (you do not have to include form tag, only the fields)
      • table.blade.php
      • _search.blade.php (optional.)
/* form.blade.php */
<div class="col-md-12">
    <div class="form-group margin-b-5 margin-t-5{{ $errors->has('name') ? ' has-error' : '' }}">
        <label for="name">Name *</label>
        <input type="text" class="form-control" name="name" placeholder="Name" value="{{ old('name', $record->name) }}" required>

        @if ($errors->has('name'))
            <span class="help-block">
                <strong>{{ $errors->first('name') }}</strong>
            </span>
        @endif
    </div>
    <!-- /.form-group -->
</div>
<!-- /.col-md-12 -->

<div class="col-md-12">
    <div class="form-group margin-b-5 margin-t-5{{ $errors->has('url') ? ' has-error' : '' }}">
        <label for="url">URL *</label>
        <input type="text" class="form-control" name="url" placeholder="URL" value="{{ old('url', $record->url) }}" required>

        @if ($errors->has('url'))
            <span class="help-block">
                <strong>{{ $errors->first('url') }}</strong>
            </span>
        @endif
    </div>
    <!-- /.form-group -->
</div>
<!-- /.col-md-12 -->
/* table.blade.php */
<div class="table-responsive list-records">
    <table class="table table-hover table-bordered">
        <thead>
            <th>#</th>
            <th>ID</th>
            <th>Name</th>
            <th style="width: 100px;">Actions</th>
        </thead>
        <tbody>
        @foreach ($records as $record)
            <?php
            $tableCounter++;
            $editLink = route($resourceRoutesAlias.'.edit', $record->id);
            $deleteLink = route($resourceRoutesAlias.'.destroy', $record->id);
            $formId = 'formDeleteModel_'.$record->id;

            $canUpdate = Auth::user()->can('update', $record);
            $canDelete = Auth::user()->can('delete', $record);
            ?>
            <tr>
                <td>{{ $tableCounter }}</td>
                <td>
                    @if ($canUpdate)
                        <a href="{{ $editLink }}">{{ $record->id }}</a>
                    @else {{ $record->id }} @endif
                </td>
                <td class="table-text">
                    <a href="{{ $editLink }}">{{ $record->name }}</a>
                </td>
                <!-- we will also add show, edit, and delete buttons -->
                <td>
                    <div class="btn-group">
                        @if ($canUpdate)
                            <a href="{{ $editLink }}" class="btn btn-info btn-sm"><i class="fa fa-edit"></i></a>
                        @endif
                        @if ($canDelete)
                            <a href="#" class="btn btn-danger btn-sm btnOpenerModalConfirmModelDelete"
                               data-form-id="{{ $formId }}"><i class="fa fa-trash-o"></i></a>
                        @endif
                    </div>
                    @if ($canDelete)
                        <!-- Delete Record Form -->
                        <form id="{{ $formId }}" action="{{ $deleteLink }}" method="POST"
                              style="display: none;" class="hidden form-inline">
                            {{ csrf_field() }}
                            {{ method_field('DELETE') }}
                            <button type="submit" class="btn btn-danger">Delete</button>
                        </form>
                    @endif
                </td>
            </tr>
        @endforeach
        </tbody>
    </table>
</div>
/* _search.blade.php */
<div class="box-body padding">
    <!-- Search -->
    <div class="box-tools">
        <form id="form-advanced-search" class="form" role="form" method="GET" action="{{ $_listLink }}">
            <div class="row">
                <div class="col-md-3">
                    <div class="form-group margin-b-5 margin-t-5">
                        <label for="search">Name</label>
                        <input type="text" name="search" class="form-control" value="{{ $search }}" placeholder="Name">
                    </div>
                    <!-- /.form-group -->
                </div>
                <!-- /.col-md-3 -->
            </div>

            <hr class="margin-b-5 margin-t-5">

            <div class="row">
                <div class="col-md-3 col-lg-2">
                    <div class="form-group margin-b-5 margin-t-5">
                        <label for="per_page">Show</label>
                        <select name="per_page" class="form-control select2" data-placeholder="Show" data-allow-clear="true" style="width: 100%;">
                            <option value="" @if ($perPage == '') selected @endif></option>
                            <option value="15" @if ($perPage == 15) selected @endif>15</option>
                            <option value="25" @if ($perPage == 25) selected @endif>25</option>
                            <option value="50" @if ($perPage == 50) selected @endif>50</option>
                            <option value="100" @if ($perPage == 100) selected @endif>100</option>
                        </select>
                    </div>
                    <!-- /.form-group -->
                </div>
                <!-- /.col-md-2 -->

                <div class="col-md-6 col-md-offset-3 col-lg-4 col-lg-offset-4 text-center">
                    <div class="form-group margin-b-5 margin-t-5" style="margin-top: 20px;">
                        <button type="submit" class="btn btn-primary margin-r-5 margin-l-5"><i class="fa fa-search"></i> Search</button>
                        <a href="{{ $_listLink }}" class="btn btn-warning margin-r-5 margin-l-5"><i class="fa fa-eraser"></i> Reset</a>
                    </div>
                </div>
                <!-- /.col-md-4 -->
            </div>

            <hr class="margin-b-5 margin-t-5">
        </form>
    </div>
    <!-- END Search -->
</div>
<!-- sidebar menu: : style can be found in sidebar.less -->
<ul class="sidebar-menu" data-widget="tree">
    <li class="header">MAIN NAVIGATION</li>
    <li class="{{ \App\Utils::checkRoute(['dashboard::index', 'admin::index']) ? 'active': '' }}">
        <a href="{{ route('dashboard::index') }}">
            <i class="fa fa-dashboard"></i> <span>Dashboard</span>
        </a>
    </li>
    @if (Auth::user()->can('manage', \App\User::class))
        <li class="{{ \App\Utils::checkRoute(['admin::users.index', 'admin::users.create']) ? 'active': '' }}">
            <a href="{{ route('admin::users.index') }}">
                <i class="fa fa-user-secret"></i> <span>Users</span>
            </a>
        </li>
    @endif

    @if (Auth::user()->can('manage', \App\Models\Category::class))
        <li class="{{ \App\Utils::checkRoute(['admin::categories.index', 'admin::categories.create']) ? 'active': '' }}">
            <a href="{{ route('admin::categories.index') }}">
                <i class="fa fa-tags"></i> <span>Categories</span>
            </a>
        </li>
    @endif

</ul>
Clone this wiki locally