Laravel 进阶任务笔记

在任务开始,我们会扩展一下新建的数据库表移植文件。刚建立的移植文件只有两列,手动添加如下:

public function up()
    {
        Schema::create('tasks', function (Blueprint $table) {
            $table->increments('id');
            $table->integer('user_id')->index();
            $table->string('name');
            $table->timestamps();
        });
    }

再次使用命令进行建表:

php artisan migrate

创建Model:

php artisan make:model Task

这一次我们会在新建的Model里添加一个属性:

<?php

namespace App;

use IlluminateDatabaseEloquentModel;

class Task extends Model
{
    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = ['name'];
}

通过fillable,我们声明name属性为mass-assignable。目前理解mass-assignable的意思是允许不同类型的赋值。

Models定义以后,我们现在需要对他们的关系进行声明。

在User中定义和Task的关系:

class User extends Authenticatable
{
    // Other Eloquent Properties...

    /**
     * Get all of the tasks for the user.
     */
    public function tasks()
    {
        return $this->hasMany(Task::class);
    }
}

在Task中定义和User的关系:

class Task extends Model
{
    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = ['name'];

    /**
     * Get the user that owns the task.
     */
    public function user()
    {
        return $this->belongsTo(User::class);
    }
}

现在我们使用控制器来组织我们的Router。因为用户认证是常用的功能,因此laravel中已经集成了此功能。命令如下:

php artisan make:auth --views

之后在Router中添加如下行:

Route::auth();
protected $redirectTo = '/tasks';

这样就能自动注册用户授权,并将非法用户重定向至/tasks。

同时我们也需要将重定向在中间件app/Middleware/RedirectIfAuthenticated.php中定义:

return redirect('/tasks');

 在进阶任务中,我们使用Controller进行业务逻辑的设计。在目录app/Http/Controllers下创建一个TaskController的artisan语法如下:

php artisan make:controller TaskController

创建好controller后,就可以在Router里根据url对应controller中的业务逻辑:

Route::get('/tasks', 'TaskController@index');
Route::post('/task', 'TaskController@store');
Route::delete('/task/{task}', 'TaskController@destroy');

使用Controller后我们就可以方便的用中间件对所有Controller里的业务进行用户权限管理,只需要在刚才创建的TaskController中加入:

class TaskController extends Controller
{
    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('auth');
    }
}

定义视图的方法和基本任务中的一致,只是部分文件存储的路径不同,之后就可以在控制器中定义我们的业务逻辑:

public function index(Request $request)
{
    return view('tasks.index');
}

存储task的方法和基本任务中的一样,只不过现在需要在Controller中定义。

public function store(Request $request)
{
    $this->validate($request, [
        'name' => 'required|max:255',
    ]);
  $request->user()->tasks()->create([
        'name' => $request->name,
    ]);

    return redirect('/tasks');
 }

可以发现储存时的验证和我们基本任务中router的有所区别。因为Controller类本身就支持validate,因此验证失败后errors变量会自动被压入session中,并且重定向至访问前的页面。

创建任务时,我们可以使用user和task的关系,通过此创建方法,可以自动设置task对应的userId。

这时候,我们的主页面还需要加入展示任务的功能,代码如下:

public function index(Request $request)
{
    $tasks = Task::where('user_id', $request->user()->id)->get();

    return view('tasks.index', [
        'tasks' => $tasks,
    ]);
}

这里用where查询获得任务,并将tasks传参给tasks.index

然而数据的逻辑我们还需要通过在Task Model中定义TaskRepository进行管理。因为Model就是针对特定表的操作集合。针对不同的业务逻辑,我们可能会有不同的对表的操作,因此为了方便重用,我们应该将所有的操作注册。

我们在app目录下新建Repositories目录,并创建TaskRepository类:

namespace AppRepositories;

use AppUser;
use AppTask;

class TaskRepository
{
    /**
     * Get all of the tasks for a given user.
     *
     * @param  User  $user
     * @return Collection
     */
    public function forUser(User $user)
    {
        return Task::where('user_id', $user->id)
                    ->orderBy('created_at', 'asc')
                    ->get();
    }
}

接下来我们需要将Repository引入我们的Controller:

namespace AppHttpControllers;

use AppTask;
use AppHttpRequests;
use IlluminateHttpRequest;
use AppHttpControllersController;
use AppRepositoriesTaskRepository;

class TaskController extends Controller
{
    /**
     * The task repository instance.
     *
     * @var TaskRepository
     */
    protected $tasks;

    /**
     * Create a new controller instance.
     *
     * @param  TaskRepository  $tasks
     * @return void
     */
    public function __construct(TaskRepository $tasks)
    {
        $this->middleware('auth');

        $this->tasks = $tasks;
    }

    /**
     * Display a list of all of the user's task.
     *
     * @param  Request  $request
     * @return Response
     */
    public function index(Request $request)
    {
        return view('tasks.index', [
            'tasks' => $this->tasks->forUser($request->user()),
        ]);
    }
}

数据展示和删除的view视图和基本任务一致,不重复了。

接下来就是和基本任务中有所区别的地方,Router中我们使用Destroy方法:

Route::delete('/task/{task}', 'TaskController@destroy');

/**
 * Destroy the given task.
 *
 * @param  Request  $request
 * @param  Task  $task
 * @return Response
 */
public function destroy(Request $request, Task $task)
{
    //
}

上面是Router文件,下面是Controller文件中的对应方法。可以看到这里有个隐式传参,{task}会自动传递给$task变量。

由于此次我们引入了用户权限机制,我们担心在删除过程中用户随意传递task_id,因此我们需要建立Policy防止这一情况。Policy可以将授权逻辑进行整合处理。通常一个Policy对应一个Model。我们通过artisan创建app/Policies/TaskPolicy.php文件:

php artisan make:policy TaskPolicy

我们需要在TaskPolicy中声明某方法所需要的权限。如此处,Destroy方法需要确认用户的taskid和此taskid是否对应:

<?php

namespace AppPolicies;

use AppUser;
use AppTask;
use IlluminateAuthAccessHandlesAuthorization;

class TaskPolicy
{
    use HandlesAuthorization;

    /**
     * Determine if the given user can delete the given task.
     *
     * @param  User  $user
     * @param  Task  $task
     * @return bool
     */
    public function destroy(User $user, Task $task)
    {
        return $user->id === $task->user_id;
    }
}

之后我们需要将Task Model和TaskPolicy进行关联,在文件app/Providers/AuthServiceProvider.php的$policies变量中声明:

/**
 * The policy mappings for the application.
 *
 * @var array
 */
protected $policies = [
    'AppTask' => 'AppPoliciesTaskPolicy',
];

这样所有对Task的授权都会交予TaskPolicy。

现在重新回到我们的Controller:

public function destroy(Request $request, Task $task)
{
    $this->authorize('destroy', $task);
  $task->delete();

    return redirect('/tasks');
 }

当前用户会被自动传参,因此不需要额外传递。如果授权失败,将会跳转至403页面。

原文地址:https://www.cnblogs.com/xiaoxiaff/p/5270985.html