• 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页面。

  • 相关阅读:
    CF263E Rhombus
    AtCoder Grand Contest 034
    Docker C/S 架构逻辑图
    使用filledeat modules配置
    filebeat分别收集多个类型日志
    ELK部署收集日志
    ES界面
    Django下的post请求访问出现403错误
    Django配置(urls.py)
    Day-1 python
  • 原文地址:https://www.cnblogs.com/xiaoxiaff/p/5270985.html
Copyright © 2020-2023  润新知