二 笔记片段

路由:

         会员列表页面:/admin/member/index                           get类型

         会员的添加页面:/admin/member/add                          any类型

         异步头像上传地址:/admin/uploader/webuploader                     post类型

         异步四级联动数据获取:/admin/member/getAreaById             get类型

添加路由

Route::group(['prefix'=>'admin'],function () {
    Route::get('public/login',  'Admin\PublicController@login')->name('login');
    Route::post('public/check', 'Admin\PublicController@check');
    Route::get('public/logout', 'Admin\PublicController@logout');
});
Route::group(['prefix'=>'admin','middleware'=>['auth:admin','checkrbac']],function () {
    Route::get('index/index','Admin\IndexController@index');
    Route::get('index/welcome','Admin\IndexController@welcome');
    Route::get('manager/index','Admin\Managercontroller@index');
    Route::get('auth/index','Admin\AuthController@index');
    Route::any('auth/add','Admin\AuthController@add');
    Route::get('role/index','Admin\RoleController@index');
    Route::any('role/assign','Admin\RoleController@assign');
    Route::any('member/index','Admin\MemberController@index');
    Route::any('member/add','Admin\MemberController@add');
    Route::any('member/getAreaById','Admin\MemberController@getAreaById');
    Route::any('uploader/webuploader','Admin\UploaderController@webuploader');

});

控制器文件:

添加控制器   php artisan make:controller Admin/MemberController

模型文件:

创建命令: php artisan make:model Admin/Member

定义模型规范

protected $table = 'member'; //绑定模型关联的表 member

①创建index方法,获取数据,展示视图

public function index(){
        $data = Member::get();
        return view('admin.member.index',compact('data'));
    }

②创建需要的视图文件  目录 resources\views\admin\member

文件名 index.blade.php

 

模板调用

 @foreach($data as $val)
            <tr class="text-c">
                <td><input type="checkbox" value="1" name=""></td>
                <td>{{$val->id}}</td>
                <td>{{$val->username}}</td>
                <td><img src="{{$val->avatar}}" width="60" /></td>
                <td>@if($val->gender=='1')男@elseif($val->gender=='2')女@else保密@endif</td>
                <td>{{$val->mobile}}</td>
                <td >{{$val->email}}</td>
                <td>{{$val->created_at}}</td>
                <td class="td-status">
                    @if($val->status=='1')
                    <span class="label label-danger radius">已停用</span></td>
                @else
                    <span class="label label-success radius">已启用</span></td>
                @endif
                <td class="td-status">@if($val->type==1)学生@else 老师 @endif</th>
                <td class="td-manage"><a style="text-decoration:none" onClick="member_stop(this,'10001')" href="javascript:;" title="停用"><i class="Hui-iconfont">&#xe631;</i></a> <a title="编辑" href="javascript:;" onclick="member_edit('编辑','member-add.html','4','','510')" class="ml-5" style="text-decoration:none"><i class="Hui-iconfont">&#xe6df;</i></a> <a style="text-decoration:none" class="ml-5" onClick="change_password('修改密码','change-password.html','10001','600','270')" href="javascript:;" title="修改密码"><i class="Hui-iconfont">&#xe63f;</i></a> <a title="删除" href="javascript:;" onclick="member_del(this,'1')" class="ml-5" style="text-decoration:none"><i class="Hui-iconfont">&#xe6e2;</i></a></td>
            </tr>
            @endforeach

 调用其他数据表内容

$country=DB::table('area')->where('pid',0)->get();

post数据
 if(Input::method() =='POST'){
            $result = Member::insert([
                'username'        =>        Input::get('username'),
                'password'        =>        bcrypt('password'),
                'gender'        =>        Input::get('gender'),
                'mobile'        =>        Input::get('mobile'),
                'email'            =>        Input::get('email'),
                'avatar'        =>        '/statics/avatar.jpg',
                'country_id'    =>        Input::get('country_id'),
                'province_id'    =>        Input::get('province_id'),
                'city_id'        =>        Input::get('city_id'),
                'county_id'        =>        Input::get('county_id'),
                'type'            =>        Input::get('type'),
                'status'        =>        Input::get('status'),
                'created_at'    =>        date('Y-m-d H:i:s')
            ]);
            //返回输出
            return $result ? '1' : '0';
 
知识点
{{ route('users.edit', Auth::id()) }} //模型文件调用资源路由示范  /users/1/edit
{{ route('users.show', Auth::id()) }} //模型文件调用资源路由示范 /users/1

路由文件
Route::resource('users', 'UsersController', ['only' => ['show', 'update', 'edit']]);


 数据表中添加单独的字段

php artisan make:migration add_avatar_and_introduction_to_users_table --table=users
public function up()
 {
 Schema::table('users', function (Blueprint $table) {
 $table->string('avatar')->nullable();
 $table->string('introduction')->nullable();
 });
 }

 php artisan migrate

 知识点

public function show(User $user)
 {
 return view('users.show', compact('user'));
 }

User 是User模型

 Laravel 会自动解析定义在控制器方法(变量名匹配路由片段)中的 Eloquent 模型类型声明。在上面代码中,由于 show() 方法传参时声明了类型 —— Eloquent 模型 User ,对应的变量名 $user 会匹配路由片段中的 {user} ,这样,Laravel 会自动注入与请求 URI 中传入的 ID 对应的用户模型实例。 此功能称为 ,是『约定优于配置』设计范式的体现,同时满足以下两种情况,此功能即会自动启 用:

1). 路由声明时必须使用 Eloquent 模型的单数小写格式来作为 路由片段参数,User 对应 {user} :

Route::get('/users/{user}', 'UsersController@show')->name('users.show');

 上面路由部分讲过,在使用资源路由 Route::resource('users', 'UsersController'); 时,默认已经包含了上面的声 明。

2). 控制器方法传参中必须包含对应的 Eloquent 模型类型 提示,并且是有序的:

public function show(User $user)
{
 return view('users.show', compact('user'));
}

 

当请求 http://larabbs.test/users/1 并且满足以上两个条件时,Laravel 将会自动查找 ID 为 1 的用户并赋值到变量 $user 中,如果数据库中找不到对应的模型实例,会自动生成 HTTP 404 响应,例如此刻我们只注册了 Summer 和 Monkey 用 户,数据库里只有两条数据,当我们访问 http://larabbs.test/users/3 ID 为 3 的用户时:

则会返回404

3. 继续看 show() 方法里的代码:

return view('users.show', compact('user'));

我们将用户对象变量 $user 通过 方法转化为一个关联数组,并作为第二个参数传递给 view 方法,将 变量数据传递到视图中。 show 方法添加完成之后,在视图中,我们即可直接使用 $user 变量来获取 view 方法传递给视图的用户数据。

重点
 php artisan make:request UserRequest

<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class UserRequest extends FormRequest
{
 public function authorize()
 {
 return true;
 }
 public function rules()
 {
 return [
 //
 ];
 }
}

表单请求验证(FormRequest)的工作机制,是利用 Laravel 提供的依赖注入功能,在控制器方法,如上面我们的 update() 方法声明中,传参 UserRequest。这将触发表单请求类的自动验证机制,验证发生在 UserRequest 中,并使 用此文件中方法 rules() 定制的规则,只有当验证通过时,才会执行 控制器 update() 方法中的代码。否则抛出异 常,并重定向至上一个页面,附带验证失败的信息。 authorize() 方法是表单验证自带的另一个功能 —— 权限验证,本课程中我们不会使用此功能,关于用户授权,我们 将会在后面章节中使用更具扩展性的方案,此处我们 return true; ,意味所有权限都通过即可。 接下来我们需要定制 rules() 方法,如下:

app/Http/Requests/UserRequest.php
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Auth;
class UserRequest extends FormRequest
{
 public function authorize()
 {
 return true;
 }
 public function rules()
 {
 return [
 'name' => 'required|between:3,25|regex:/^[A-Za-z0-9\-\_]+$/|unique:users,name,' . Auth::id(),
 'email' => 'required|email',
 'introduction' => 'max:80',
 ];
 }
}

 

 /5、头像上传

<div class="form-group mb-4">
 <label for="" class="avatar-label">用户头像</label>
 <input type="file" name="avatar" class="form-control-file">
 @if($user->avatar)
 <br>
 <img class="thumbnail img-responsive" src="{{ $user->avatar }}" width="200" />
 @endif
 </div>

在 Laravel 中,我们可直接通过请求对象 (Request) 来获取用户上传的文件,如以下两种方法:

$file = $request->file('avatar');
// 第二种方法,可读性更高
$file = $request->avatar;
在控制器中 测试
dd($request->avatar);

打印出来是图片文件名称的字符串,与我们的预期不符,图片上传后通过 $request 取到的应是图片对象。 经过一番仔细检查后,发现是因为我们忘记为表单添加 enctype="multipart/form-data" 声明了。请记住,在图片或 者文件上传时,为表单添加此句声明是必须的。

6、 存储用户上传图片

我们可以将『图片上传』核心操作做成一个工具类:

app/Handlers/ImageUploadHandler.php

<?php
namespace App\Handlers;
class ImageUploadHandler
{
 // 只允许以下后缀名的图片文件上传
 protected $allowed_ext = ["png", "jpg", "gif", 'jpeg'];
 public function save($file, $folder, $file_prefix)
 {
 // 构建存储的文件夹规则,值如:uploads/images/avatars/201709/21/
 // 文件夹切割能让查找效率更高。
 $folder_name = "uploads/images/$folder/" . date("Ym/d", time());
 // 文件具体存储的物理路径,`public_path()` 获取的是 `public` 文件夹的物理路径。
 // 值如:/home/vagrant/Code/larabbs/public/uploads/images/avatars/201709/21/
 $upload_path = public_path() . '/' . $folder_name;
 // 获取文件的后缀名,因图片从剪贴板里黏贴时后缀名为空,所以此处确保后缀一直存在
 $extension = strtolower($file->getClientOriginalExtension()) ?: 'png';
 // 拼接文件名,加前缀是为了增加辨析度,前缀可以是相关数据模型的 ID
 // 值如:1_1493521050_7BVc9v9ujP.png
 $filename = $file_prefix . '_' . time() . '_' . str_random(10) . '.' . $extension;
 // 如果上传的不是图片将终止操作
 if ( ! in_array($extension, $this->allowed_ext)) {
 return false;
 }
$file->move($upload_path, $filename);
return [
'path' => config('app.url') . "/$folder_name/$filename"
];
}
}

我们将使用 app/Handlers 文件夹来存放本项目的工具类,『工具类(utility class)』是指一些跟业务逻辑相关性不强 的类, Handlers 意为 处理器 ,ImageUploadHandler 意为图片上传处理器,简单易懂。 接下来我们需要在 UsersController 里调用(注意顶部 use 引入):

app/Http/Controllers/UsersController.php

 
use App\Handlers\ImageUploadHandler;
 
public function update(UserRequest $request, ImageUploadHandler $uploader, User $user){
        $data = $request->all();
        //dd($data);
        if($request->avatar){
            $result = $uploader->save($request->avatar, 'avatars', $user->id);
            if($result){
                $data['avatar'] = $result['path'];
            }else{
                //上传有错误  withErrors可以携带回错误信
                return back()->withErrors(['上传图片格式只支持png, jpg, gif, jpeg这四种格式']);
            }
        }
        $user->update($data);
        return redirect()->route('users.show', $user->id)->with('success', '个人资料更新成功');
    }

 


1. 因为我们使用了命名空间,所以需要在顶部加载 use App\Handlers\ImageUploadHandler; ; 2. $data = $request->all(); 赋值 $data 变量,以便对更新数据的操作; 3. 以下代码处理了图片上传的逻辑,注意 if ($result) 的判断是因为 ImageUploadHandler 对文件后缀名做 了限定,不允许的情况下将返回 falseif ($request->avatar) { $result = $uploader->save($request->avatar, 'avatars', $user->id); if ($result) { $data['avatar'] = $result['path']; } }

 

 7、 图片验证

app/Http/Requests/UserRequest.php

public function rules()
 {
 return [
 'name' => 'required|between:3,25|regex:/^[A-Za-z0-9\-\_]+$/|unique:users,name,' . Auth::id(),
 'email' => 'required|email',
 'introduction' => 'max:80',
 'avatar' => 'mimes:jpeg,bmp,png,gif|dimensions:min_width=208,min_height=208',
 ];
 }
public function messages()
 {
 return [
 'avatar.mimes' =>'头像必须是 jpeg, bmp, png, gif 格式的图片',
 'avatar.dimensions' => '图片的清晰度不够,宽和高需要 208px 以上',
 'name.unique' => '用户名已被占用,请重新填写',
 'name.regex' => '用户名只支持英文、数字、横杆和下划线。',
 'name.between' => '用户名必须介于 3 - 25 个字符之间。',
 'name.required' => '用户名不能为空。',
 ];
 }

1. rules() 方法中新增了图片比例验证规则 ,仅允许上传宽和高都大于 208px 的图片;

2. messages() 方法中新增了头像出错时的提示信息。

 8、裁剪图片

1、

 composer require intervention/image

2、配置信息

php artisan vendor:publish --provider=Intervention\Image\ImageServiceProviderLaravelRecent

3. 开始裁剪

我们将裁切的逻辑写在 ImageUploadHandler 中,请将以下代码替换: app/Handlers/ImageUploadHandler.php

<?php
namespace App\Handlers;
use Image;
class ImageUploadHandler
{
 protected $allowed_ext = ["png", "jpg", "gif", 'jpeg'];
 public function save($file, $folder, $file_prefix, $max_width = false)
 {
 // 构建存储的文件夹规则,值如:uploads/images/avatars/201709/21/
 // 文件夹切割能让查找效率更高。
 $folder_name = "uploads/images/$folder/" . date("Ym/d", time());
 // 文件具体存储的物理路径,`public_path()` 获取的是 `public` 文件夹的物理路径。
 // 值如:/home/vagrant/Code/larabbs/public/uploads/images/avatars/201709/21/
 $upload_path = public_path() . '/' . $folder_name;
 // 获取文件的后缀名,因图片从剪贴板里黏贴时后缀名为空,所以此处确保后缀一直存在
 $extension = strtolower($file->getClientOriginalExtension()) ?: 'png';
 // 拼接文件名,加前缀是为了增加辨析度,前缀可以是相关数据模型的 ID
 // 值如:1_1493521050_7BVc9v9ujP.png
 $filename = $file_prefix . '_' . time() . '_' . str_random(10) . '.' . $extension;
 // 如果上传的不是图片将终止操作
 if ( ! in_array($extension, $this->allowed_ext)) {
 return false;
 }
 // 将图片移动到我们的目标存储路径中
 $file->move($upload_path, $filename);
 // 如果限制了图片宽度,就进行裁剪
 if ($max_width && $extension != 'gif') {
 // 此类中封装的函数,用于裁剪图片
 $this->reduceSize($upload_path . '/' . $filename, $max_width);
 }
 return [
 'path' => config('app.url') . "/$folder_name/$filename"
 ];
 }
 public function reduceSize($file_path, $max_width)
 {
 // 先实例化,传参是文件的磁盘物理路径
 $image = Image::make($file_path);
 // 进行大小调整的操作
 $image->resize($max_width, null, function ($constraint) {
 // 设定宽度是 $max_width,高度等比例双方缩放
 $constraint->aspectRatio();
 // 防止裁图时图片尺寸变大
 $constraint->upsize();
 });
 // 对图片修改后进行保存
 $image->save();
 }
}

 此次新增 reduceSize() 方法,以及此方法的调用。

以上的 save() 方法中,我们新增了 $max_width 参数,用来指定最大图片宽度,我们修改 UsersController 的 update() 方法中的调用,修改为:

$result = $uploader->save($request->avatar, 'avatars', $user->id, 416);

 

9 授权访问

存在两个问题

1、未登录用户可以访问 edit 和 update 动作

2、 登录用户可以更新其它用户的个人信息,登录 Summer 用户然后访问 Monkey 用户的编辑资料页面

限制游客访问

我们使用 Laravel 提供身份验证(Auth)中间件来过滤未登录用户的 edit , update 动作:

app/Http/Controllers/UsersController.php

public function __construct()
 {
 $this->middleware('auth', ['except' => ['show']]);
 }

__construct 是 PHP 的构造器方法,当一个类对象被创建之前该方法将会被调用。我们在 __construct 方法中调 用了 middleware 方法,该方法接收两个参数,第一个为中间件的名称,第二个为要进行过滤的动作。我们通过 except 方法来设定 指定动作 不使用 Auth 中间件进行过滤,意为 —— 除了此处指定的动作以外,所有其他动作都必 须登录用户才能访问,类似于黑名单的过滤机制。相反的还有 only 白名单方法,将只过滤指定动作。我们提倡在控制 器 Auth 中间件使用中,首选 except 方法,这样的话,当你新增一个控制器方法时,默认是安全的,此为最佳实践。 Laravel 提供的 Auth 中间件在过滤指定动作时,如该用户未通过身份验证(未登录用户),将会被重定向到登录页面:

用户只能编辑自己的资料

使用以下命令来生成一个名为 UserPolicy 的授权策略类文件,用于管理用户模型的授权

 php artisan make:policy UserPolicy

所有生成的授权策略文件都会被放置在 app/Policies 文件夹下。 让我们为默认生成的用户授权策略添加 update 方法,用于用户更新时的权限验证。

app/Policies/UserPolicy.php

public function update(User $currentUser, User $user)
 {
 return $currentUser->id === $user->id;
 }

 

update 方法接收两个参数,第一个参数默认为当前登录用户实例,第二个参数则为要进行授权的用户实例。当两个 id
相同时,则代表两个用户是相同用户,用户通过授权,可以接着进行下一个操作。如果 id 不相同的话,将抛出 403 异常
信息来拒绝访问。
使用授权策略需要注意以下两点:
1. 我们并不需要检查 $currentUser 是不是 NULL。未登录用户,框架会自动为其 所有权限 返回 false2. 调用时,默认情况下,我们 不需要 传递当前登录用户至该方法内,因为框架会自动加载当前登录用户(接着看下
去,后面有例子);
接下来我们还需要在 AuthServiceProvider 类中对授权策略进行注册。 AuthServiceProvider 包含了一个
policies 属性,该属性用于将各种模型对应到管理它们的授权策略上。我们需要为用户模型 User 指定授权策略
UserPolicy 。

app/Providers/AuthServiceProvider.php

protected $policies = [
 'App\Model' => 'App\Policies\ModelPolicy',
 \App\Models\User::class => \App\Policies\UserPolicy::class,
 ];

 

授权策略定义完成之后,我们便可以在控制器中使用 authorize 方法来检验用户是否授权。默认的 App\Http\Controllers\Controller 控制器基类包含了 Laravel 的 AuthorizesRequests trait。此 trait 提供了 authorize 方法,它可以被用于快速授权一个指定的行为,当无权限运行该行为时会抛出 HttpException。 authorize 方法接收两个参数,第一个为授权策略的名称,第二个为进行授权验证的数据。 我们需要为 edit 和 update 方法加上这行:

$this->authorize('update', $user);

这里 update 是指授权类里的 update 授权方法, $user 对应传参 update 授权方法的第二个参数。正如 上面定义 update 授权方法时候提起的,调用时,默认情况下,我们 不需要 传递第一个参数,也就是当前登录用 户至该方法内,因为框架会 自动 加载当前登录用户。

书写的位置如下: app/Http/Controllers/UsersController.php

public function edit(User $user)
 {
 $this->authorize('update', $user);
 return view('users.edit', compact('user'));
 }
 public function update(UserRequest $request, ImageUploadHandler $uploader, User $user)
 {
 $this->authorize('update', $user);
 $data = $request->all();

 

 10 git相关

laravel数据回滚 

 php artisan migrate:rollback

还原修改文件到原始状态:

git checkout .

 

git clean -f -d

 

命令 git clean 作用是清理项目, -f 是强制清理文件的设置, -d 选项命令连文件夹一并清除。

 


posted @ 2020-03-26 19:37  _callback  阅读(276)  评论(0编辑  收藏  举报