laravel笔记

laravel进阶预备

Route的正则约束

可以通过路由实例上的 where 方法来约束路由参数的格式。where 方法接收参数名和一个正则表达式来定义该参数如何被约束:

Route::get('user/{name}', function ($name) {
    // name 必须是字母且不能为空
})->where('name', '[A-Za-z]+');

Route::get('user/{id}', function ($id) {
    // id 必须是数字
})->where('id', '[0-9]+');

Route::get('user/{id}/{name}', function ($id, $name) {
    // 同时指定 id 和 name 的数据格式
})->where(['id' => '[0-9]+', 'name' => '[a-z]+']);

路由缓存

注:路由缓存不会作用于基于闭包的路由。要使用路由缓存,必须将闭包路由转化为控制器路由。

如果你的应用完全基于控制器路由,可以使用 Laravel 的路由缓存,使用路由缓存将会极大降低注册所有应用路由所花费的时间开销,在某些案例中,路由注册速度甚至能提高100倍!想要生成路由缓存,只需执行 Artisan 命令 route:cache:

php artisan route:cache

运行完成后,每次请求都会从缓存中读取路由,所以如果你添加了新的路由需要重新生成路由缓存。因此,只有在项目部署阶段才需要运行 route:cache 命令,本地开发环境完全无此必要。

想要移除缓存路由文件,使用route:clear命令即可

消息状态写法

@foreach (['danger', 'warning', 'success', 'info'] as $msg)
  @if(session()->has($msg))
    <div class="flash-message">
      <p class="alert alert-{{ $msg }}">
        {{ session()->get($msg) }}
      </p>
    </div>
  @endif
@endforeach

Createing方法

creating 用于监听模型被创建之前的事件,created 用于监听模型被创建之后的事件。接下来我们要生成的用户激活令牌需要在用户模型创建之前生成,因此需要监听的是 creating 方法。

在用户模型中添加 creating 方法如下

<?php

namespace App\Models;
.
.
.
class User extends Authenticatable
{
    .
    .
    .
    protected $hidden = ['password', 'remember_token'];

    public static function boot()
    {
        parent::boot();

        static::creating(function ($user) {
            $user->activation_token = str_random(30);
        });
    }
    .
    .
    .
}

boot 方法会在用户模型类完成初始化之后进行加载,因此我们对事件的监听需要放在该方法中。


模型工厂的写法

例子一:
database/factories/UserFactory.php

<?php

use Faker\Generator as Faker;

/*
|--------------------------------------------------------------------------
| Model Factories
|--------------------------------------------------------------------------
|
| This directory should contain each of the model factory definitions for
| your application. Factories provide a convenient way to generate new
| model instances for testing / seeding your application's database.
|
*/

$factory->define(App\Models\User::class, function (Faker $faker) {
    $date_time = $faker->date . ' ' . $faker->time;
    static $password;

    return [
        'name' => $faker->name,
        'email' => $faker->safeEmail,
        'is_admin' => false,
        'activated' => true,
        'password' => $password ?: $password = bcrypt('secret'),
        'remember_token' => str_random(10),
        'created_at' => $date_time,
        'updated_at' => $date_time,
    ];
});

database/seeds/UsersTableSeeder.php

<?php

use Illuminate\Database\Seeder;
use App\Models\User;

class UsersTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        $users = factory(User::class)->times(50)->make();
        User::insert($users->makeVisible(['password', 'remember_token'])->toArray());

        $user = User::find(1);
        $user->name = 'Aufree';
        $user->email = 'aufree@yousails.com';
        $user->password = bcrypt('password');
        $user->is_admin = true;
        $user->activated = true;
        $user->save();
    }
}

再举例子:
database/factories/StatusFactory.php

<?php

use Faker\Generator as Faker;

$factory->define(App\Models\Status::class, function (Faker $faker) {
    $date_time = $faker->date . ' ' . $faker->time;
    return [
        'content'    => $faker->text(),
        'created_at' => $date_time,
        'updated_at' => $date_time,
    ];
});

创建一个 StatusesTableSeeder 文件来对微博假数据进行批量生成:database/seeds/StatusesTableSeeder.php

通过 app() 方法来获取一个 Faker 容器 的实例,并借助 randomElement 方法来取出用户 id 数组中的任意一个元素并赋值给微博的 user_id,使得每个用户都拥有不同数量的微博。

<?php

use Illuminate\Database\Seeder;
use App\Models\User;
use App\Models\Status;

class StatusesTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        $user_ids = ['1','2','3'];
        $faker = app(Faker\Generator::class);

        $statuses = factory(Status::class)->times(100)->make()->each(function ($status) use ($faker, $user_ids) {
            $status->user_id = $faker->randomElement($user_ids);
        });

        Status::insert($statuses->toArray());
    }
}

在 DatabaseSeeder 类中指定调用微博数据填充文件:

<?php

use Illuminate\Database\Seeder;
use Illuminate\Database\Eloquent\Model;

class DatabaseSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        Model::unguard();

        $this->call(UsersTableSeeder::class);
        $this->call(StatusesTableSeeder::class);

        Model::reguard();
    }
}

重置填充数据库:
php artisan migrate:refresh --seed

模型创建的名字空间

我们新建的模型文件都要统一放置在 app/Models 文件夹下,为此我们在创建一个新的模型对象时,需要在模型名称前面加上 Models 目录。
php artisan make:model Models/SampleModel

友好化和语言转换

$status->created_at->diffForHuman();
我们发现 diffForHumans 为我们生成的时间是英文的,如果要使用中文时间,则需要对 Carbon 进行本地化设置。Carbon 是 PHP DateTime 的一个简单扩展,Laravel 将其默认集成到了框架中。对 Carbon 进行本地化的设置很简单,只在 AppServiceProvider 中调用 Carbon 的 setLocale 方法即可,AppServiceProvider 是框架的核心,在 Laravel 启动时,会最先加载该文件。

app/Providers/AppServiceProvider.php

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Carbon\Carbon;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        Carbon::setLocale('zh');
    }

    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}

Model和View交互示例

resources/views/statuses/_status.blade.php

<li id="status-{{ $status->id }}"> <a href="{{ route('users.show', $user->id )}}"> <img src="{{ $user->gravatar() }}" alt="{{ $user->name }}" class="gravatar"/> </a> <span class="user"> <a href="{{ route('users.show', $user->id )}}">{{ $user->name }}</a> </span> <span class="timestamp"> {{ $status->created_at->diffForHumans() }} </span> <span class="content">{{ $status->content }}</span> </li>

resources/views/users/show.blade.php

@extends('layouts.default')
@section('title', $user->name)
@section('content')
<div class="row">
  <div class="col-md-offset-2 col-md-8">
    <div class="col-md-12">
      <div class="col-md-offset-2 col-md-8">
        <section class="user_info">
          @include('shared._user_info', ['user' => $user])
        </section>
      </div>
    </div>
    <div class="col-md-12">
      @if (count($statuses) > 0)
        <ol class="statuses">
          @foreach ($statuses as $status)
            @include('statuses._status')
          @endforeach
        </ol>
        {!! $statuses->render() !!}
      @endif
    </div>
  </div>
</div>
@stop

每个模型符合RESTful框架的定义路由

为了符合RESTful框架,咱们使用resource方法,再次回顾:一个参数为资源名称,第二个参数为控制器名称
Route::resource(‘users’,’UsersController’);
等价为

Route::get('/users', 'UsersController@index')->name('users.index');
Route::get('/users/{user}', 'UsersController@show')->name('users.show');
Route::get('/users/create', 'UsersController@create')->name('users.create');
Route::post('/users', 'UsersController@store')->name('users.store');
Route::get('/users/{user}/edit', 'UsersController@edit')->name('users.edit');
Route::patch('/users/{user}', 'UsersController@update')->name('users.update');
Route::delete('/users/{user}', 'UsersController@destroy')->name('users.destroy');

Alt text
Route::resource('statuses', 'StatusesController', ['only' => ['store', 'destroy']]);
第三个参数等价为指定只使用RESTful的中的哪几个
Alt text


添加中间件过滤的位置

在控制器的开头添加中间件的权限过滤,比如需要登陆后才能操作:app/Http/Controllers/StatusesController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Http\Requests;

class StatusesController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth');
    }
}

有对应关系的模型创建时的注意

当我们在创建微博的时候,需要通过以下方式来进行创建。这样创建的微博会自动与用户进行关联,还用到了Auth::user()方法

Auth::user()->statuses()->create([
    'content' => $request->content
]);

最终在控制器下添加的方法如下:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Http\Requests;
use App\Models\Status;
use Auth;

class StatusesController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth');
    }

    public function store(Request $request)
    {
        $this->validate($request, [
            'content' => 'required|max:140'
        ]);

        Auth::user()->statuses()->create([
            'content' => $request->content
        ]);
        return redirect()->back();
    }
}

能更新的字段要添加fillable字段

解决的办法很简单,在微博模型的 fillable 属性中允许更新微博的 content 字段即可。

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Status extends Model
{
    protected $fillable = ['content'];

    public function user()
    {
        return $this->belongsTo(User::class);
    }
}

动态流

在开始之前,我们需要在用户模型中定义一个 feed 方法,该方法将当前用户发布过的所有微博从数据库中取出,并根据创建时间来倒序排序。在后面我们为用户增加关注人的功能之后,将使用该方法来获取当前用户关注的人发布过的所有微博动态。现在的 feed 方法定义如下:

<?php

namespace App\Models;
.
.
.

class User extends Authenticatable
{
    .
    .
    .
    public function feed()
    {
        return $this->statuses()
                    ->orderBy('created_at', 'desc');
    }
}

由于我们在用户模型中已定义好了 feed 方法,因此我们可以在主页对应的控制器动作 home 中使用该方法来获取用户的微博动态。

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

use App\Http\Requests;
use App\Http\Controllers\Controller;

use App\Models\Status;
use Auth;

class StaticPagesController extends Controller
{

    public function home()
    {
        $feed_items = [];
        if (Auth::check()) {
            $feed_items = Auth::user()->feed()->paginate(30);
        }

        return view('static_pages/home', compact('feed_items'));
    }

    public function help()
    {
        return view('static_pages/help');
    }

    public function about()
    {
        return view('static_pages/about');
    }
}

动态流的局部视图:

@if (count($feed_items)) <ol class="statuses"> @foreach ($feed_items as $status) @include('statuses._status', ['user' => $status->user]) @endforeach {!! $feed_items->render() !!} </ol> @endif

权限控制的删除操作

使用授权策略来搞权限控制:举例子,删除微博,要求当前用户和微博所属用户id相同
$ php artisan make:policy StatusPolicy
app/Policies/StatusPolicy.php

<?php

namespace App\Policies;

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

class StatusPolicy
{
    use HandlesAuthorization;

    public function destroy(User $user, Status $status)
    {
        return $user->id === $status->user_id;
    }
}

添加完权限还得在:AuthServiceProvider对授权策略进行配置才能正常使用:
app/Providers/AuthServiceProvider.php

<?php

namespace App\Providers;

use Illuminate\Contracts\Auth\Access\Gate as GateContract;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;

class AuthServiceProvider extends ServiceProvider
{
    /**
     * The policy mappings for the application.
     *
     * @var array
     */
    protected $policies = [
        'App\Model' => 'App\Policies\ModelPolicy',
        \App\Models\User::class  => \App\Policies\UserPolicy::class,
        \App\Models\Status::class  => \App\Policies\StatusPolicy::class,
    ];

    /**
     * Register any application authentication / authorization services.
     *
     * @param  \Illuminate\Contracts\Auth\Access\Gate  $gate
     * @return void
     */
    public function boot(GateContract $gate)
    {
        $this->registerPolicies($gate);

        //
    }
}

接下来我们要在用户发布过的每一条微博旁边加上一个删除按钮,因此需要把删除按钮加到渲染单条微博的局部视图上。并且删除按钮必须是微博的作者本人才能看到,我们可以很方便的利用 Laravel 授权策略提供的 @can Blade 命令,在 Blade 模板中做授权判断。
resources/views/statuses/_status.blade.php

@can方法是对有权更新’destroy’的人可以看到

 @can('destroy', $status) <form action="{{ route('statuses.destroy', $status->id) }}" method="POST"> {{ csrf_field() }} {{ method_field('DELETE') }} <button type="submit" class="btn btn-sm btn-danger status-delete-btn">删除</button> </form> @endcan

而statuses的删除方法:

public function destroy(Status $status) { $this->authorize('destroy', $status); $status->delete(); session()->flash('success', '微博已被成功删除!'); return redirect()->back(); }

最后还需要进行删除的授权:如果不通过会返回403错误——资源不可o

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值