laravel5.4新特性

Posted 爱做梦的小懒猫

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了laravel5.4新特性相关的知识,希望对你有一定的参考价值。

http://www.cnblogs.com/webskill/category/1067140.html

laravel 5.4 新特性

component and slot

使用:

1.component panel

<article class="message">
  <div class="message-header">
    <p>Hello World</p>
    <button class="delete" aria-label="delete"></button>
  </div>
  <div class="message-body">
    Lorem ipsum dolor sit amet, consectetur adipiscing elit. <strong>Pellentesque risus mi</strong>, tempus quis placerat ut, porta nec nulla. Vestibulum rhoncus ac ex sit amet fringilla. Nullam gravida purus diam, et dictum <a>felis venenatis</a> efficitur. Aenean ac <em>eleifend lacus</em>, in mollis lectus. Donec sodales, arcu et sollicitudin porttitor, tortor urna tempor ligula, id porttitor mi magna a neque. Donec dui urna, vehicula et sem eget, facilisis sodales sem.
  </div>
</article>

2.其中header和body需要传入变量

<article class="message">
  <div class="message-header">
    <p>{{$title}}</p>
    <button class="delete" aria-label="delete"></button>
  </div>
  <div class="message-body">
    {{$content}}
  </div>
</article>

3.views.components.index 中 需要引用component模版panel

@component(\'components.panel\')
    @slot(\'title\')
        hello world
    @endslot
    @slot(\'content\')
        have a nice day
    @endslot
@endcomponent

4.如果要传入默认content

panel.blade.php修改如下:

 <article class="message">
    <div class="message-header">
      <p>{{$title}}</p>
      <button class="delete" aria-label="delete"></button>
    </div>
    <div class="message-body">
      {{$slot}}
    </div>
  </article>

index.blade.php修改如下

@component(\'components.panel\')
    @slot(\'title\')
        hello world
    @endslot
        have a nice day
@endcomponent

//可多来几个:

@component(\'components.panel\')
    @slot(\'title\')
        hello world
    @endslot
    have a nice day123
@endcomponent

5.还可以这样给默认值:title默认为laravel

panel.blade.php修改如下:
  
     <article class="message">
        <div class="message-header">
          <p>{{$title ?? \'laravel\'}}</p>
          <button class="delete" aria-label="delete"></button>
        </div>
        <div class="message-body">
          {{$slot}}
        </div>
      </article>
index.blade.php修改如下
    
    @component(\'components.panel\')
            have a nice day
    @endcomponent

laravel 邮件

本文使用qq邮箱

env邮件配置:

MAIL_FROM_ADDRESS = 17******92@qq.com
MAIL_FROM_NAME = listen~

MAIL_DRIVER=smtp
MAIL_HOST=smtp.qq.com
MAIL_PORT=465
MAIL_USERNAME=17*******2@qq.com
MAIL_PASSWORD= ****** //这个是你的qq授权码
MAIL_ENCRYPTION=ssl
MAIL_ENCRYPTION=ssl
  1. 创建邮件类

     php artisan make:mail welcomeToMiya
    
  2. 修改welcomeToMiya.php视图

         public function build()
         {
             return $this->view(\'email.welcome\');
         }
    
  3. 使用

         //发送邮件
         Route::get(\'/mail\',function(){
             \\Illuminate\\Support\\Facades\\Mail::to(\'2861166132@qq.com\')->send(new \\App\\Mail\\welcomeToLaravist());
         });
    
  4. 传参 修改 welcomeToMiya.php

         public $user;
     
         public function __construct(User $user)
         {
             $this->user = $user;
         }
    
  5. 传参 修改 web.php

     //发送邮件
     Route::get(\'/mail\',function(){
         $user = \\App\\User::find(1);
         \\Illuminate\\Support\\Facades\\Mail::to(\'2861166132@qq.com\')->send(new \\App\\Mail\\welcomeToLaravist($user));
     });
    

发邮件还可以这样:

public function sendTo($user,$subject,$view,$data){
        //也可以使用Mail::send
        Mail::send($view,$data,function ($message) use ($user,$subject){
            $message->to($user->email)->subject($subject);
        });
    }

使用sendcloud:
参考github: https://github.com/NauxLiu/Laravel-SendCloud

notification 通知

= mail篇 ### =

 public function via($notifiable)
{
    return [\'mail\'];
}

1.新建notification类

php artisan make:notification PostNotification

2.设置路由

//notification 注意默认发送到user模型中的email邮箱账号 所以要确认user邮箱可用
Route::get(\'/notification\',function(){
    $user = \\App\\User::find(1);
    $post = \\App\\Post::find(2);
    $user->notify(new \\App\\Notifications\\PostNotification($post));
});

3.访问/notification 收到邮件

4.常用设置方法 PostNotification.php

 public function toMail($notifiable)
{
    return (new MailMessage)
        ->subject(\'A post published\'.$this->post->title) //自定义主体
        ->success()  //定义按钮颜色
                ->line(\'The introduction to the notification.\')
                ->action(\'Notification Action\', url(\'/\'))
                ->line(\'Thank you for using our application!\');
}

=database篇 ### =

将通知都存储在数据库里

1.修改PostNotification.php

public function via($notifiable)
{
    //return [\'mail\'];
    return [\'database\'];
}

2.创建notification迁移文件

 php artisan notifications:table
 php artisan migrate

3.PostNotification.php 中可添加 toDatabase方法 如果没写的话默认用的是toArray方法

4.修改web.php

5.查看当前用户下的notifications

6.新建一个notification

php artisan make:notification UserSubscribe

7.UserSubscribe.php 修改如下

public function via($notifiable)
{
    return [\'database\'];
}

/**
 * Get the array representation of the notification.
 *
 * @param  mixed  $notifiable
 * @return array
 */
public function toArray($notifiable)
{
    return [
        \'subscribed_at\' => Carbon::now()
    ];
}

8.修改web.php

//notification
Route::get(\'/notification\', function () {
    $user = \\App\\User::find(1);
    $post = \\App\\Post::find(2);
    //$user->notify(new \\App\\Notifications\\PostNotification($post));
    $user->notify(new \\App\\Notifications\\UserSubscribe());
});

9.再次查看当前用户的notifications

10.列出未读notifications并标识为已读

web.php

//notification
Route::get(\'/show-notification\', function () {
    return view(\'notifications.index\');
});

//标识未读
Route::delete(\'user/notification\',function (){
    Auth::user()->unreadNotifications->markAsRead();
    return redirect()->back();
});

notifications.index.blade

@extends(\'app\')

@section(\'content\')
    <h1>我的通知:</h1>
    <ul>
    @foreach(Auth::user()->unreadNotifications as $notification)
        @include(\'notifications/\'.snake_case( class_basename($notification->type) ))
    @endforeach
    </ul>
    <form action="/user/notification" method="POST">
        {{csrf_field()}}
        {{method_field(\'DELETE\')}}
        <input type="submit" value="标识已读">
    </form>
@stop

user_subscribe.blade.php

<h2>user</h2>
{{$notification->data[\'subscribed_at\'][\'date\']}}

post_notification.blade.php

<h2>post</h2>
<li>{{$notification->data[\'title\']}}</li>

标识某条已读

$user->refresh()->unreadNotifications->where(\'id\',\'57bb0e0e-8d35-4da8-850b-121a5317c9b9\')->first()->markAsRead();

总结:

database

  • php artisan make:notification someNotification
  • 对于需要传入的参数做修改 例如依赖模式 Post $post
  • php artisan notification:table
  • 获取notification $user->notifications
  • 标识已读 所有的 $user->unreadNotifications->markAsRead()
    单条标识:$user->refresh()->unreadNotifications->where(\'id\',\'57bb0e0e-8d35-4da8-850b-121a5317c9b9\')->first()->markAsRead();

laravel 邮件使用markdown

php artisan make:mail lessonPublished --markdown="emails.published"    

这个命令不仅创建了email类文件 还生成了视图文件 并把视图也写好了 return $this->markdown(\'emails.published\'\')
可根据需要修改 也可修改email markdown模版 php artisan vendor:publish

发送邮件

Route::get("sendmail",function(){
    $email = new \\App\\Mail\\LessionPublished(\\App\\User::first());
    Mail::to(\\App|User::first())->send($email);
})

toggle

toggle方法主要用于多对多关系中,attach detach 比如点赞 收藏

1.user表

2.post表 title content

3.中间表 favoriate user_id post_id

4.user中定义关系

     public function favorites(){
        return $this->belongsToMany(Post::class,\'favoriates\'); //第二个参数中间表
    }

5.关联关系

做法一:

在tinker中操作

$user = App\\User::find(1);
$post = App\\Post::find(2);
$user->favorite()->attach($post);
查看结果:$user->refresh()->favorite

//取消收藏
 $user->favorite()->detach($post);

做法二:toggle 不用去判断用户有没有收藏该文章 用户收藏了则取消收藏 反之则收藏

$user->favorite()->toggle($post);

实时facade###

  1. 创建一个目录叫services
    创建一个weibo类

     <?php
     namespace App\\Services;
     class weibo
     {
         protected $http;
     
         public function __construct(Http $http)
         {
             $this->http = $http;
         }
     
         public function publish($status){
             $this->http->post($status);
         }
     }
    

创建一个Http类

<?php
namespace App\\Services;
class Http
{
    public function __construct()
    {
    }

    public function post($status){
        return dd(\'I post a post\'.$status);
    }
}

路由修改

use Facades\\App\\Services\\weibo;

//facade
Route::get(\'facade\',function (){
   weibo::publish(\'这是一条微博\');
});

现在访问就有了:"I post a post这是一条微博"

事件监听

方法一:
web.php

Event::listen(\'eloquent.created: App\\post\',function(){
    dump(\'A post was created\');
});

Route::get(\'/event53\',function(){
    \\App\\post::create([\'title\'=>\'Title\',\'content\'=>\'My Body\']);
});

方法二:

注释掉

Event::listen(\'eloquent.created: App\\post\',function(){
        dump(\'A post was created\');
    });

post模型中定义事件

<?php

namespace App;

use App\\Events\\PostWasPublished;
use Illuminate\\Database\\Eloquent\\Model;

class post extends Model
{
    protected $guarded = array();
    protected $events = [
       \'created\' => PostWasPublished::class
    ];
}

修改EventServiceProvider.php 中的$listen属性 创建事件和事件监听文件

protected $listen = [
    \'App\\Events\\PostWasPublished\' => [
        \'App\\Listeners\\PostWasPublishedListener\',
    ],
];

执行 php artisan event:generate

** 还可以依赖注入 **

App\\Events\\PostWasPublished.php

public $post;

public function __construct($post)
{
    $this->post = $post;
}

App\\Listeners\\PostWasPublishedListener.php

 public function handle(PostWasPublished $event)
     {
         dump($event->post->toArray());
     } 

方法三:普通路由触发event

app/Providers/EventServiceProvider.php

protected $listen = [
        \'App\\Events\\UserSignUp\' => [
            \'App\\Listeners\\UserSignUpListener\',
        ],
    ];

UserSignUp.php

 use App\\User;
 public $user;
 public function __construct(User $user)
 {
     $this->user = $user;
 }   

UserSignUpListener.php

public function handle(UserSignUp $event)
{
    dd($event->user->name);
}

web.php

Route::get(\'/eventroute\',function(){
    $user = \\App\\User::find(1);
   event(new \\App\\Events\\UserSignUp($user));
});       

console command

php artisan make:command hello

进入app/console/commands/hello.php

修改singniture和handle

protected $signature = \'lara:hello\';

public function handle()
    {
        $this->info(\'hello my girl\');
    }

app/console/kernel.php $commands属性修改 添加刚才的类

App\\Console\\Commands\\hello::class

传参:php artisan lara:hello alice

protected $signature = \'lara:hello{name=Bool}\'; //? 可有可无
protected $signature = \'lara:hello{name=Bool}\'; //? 可有可无

 public function handle()
    {
        $this->info(\'hello my girl \'.$this->argument(\'name\'));
    }

默认值:protected $signature = \'lara:hello{name=Bool}\';

定时任务

新建一个test.sh

 #!/bin/bash
 
 echo "hello world";
 
 php test.php

test.php

this is a test for crontab

$ cronatab -e

* * * * * /var/www/test.sh 2>&1 >> /var/www/test.log

laravel 定时任务:

$ php artisan make:conmmand logInfo

修改 ap/console/command/logInfo.php

protected $description = \'log Info\';
 public function handle()
    {
        Log::info(\'It works\');
    }

kernel中注册 app/console/kernel.php

protected $commands = [
        //
        hello::class,
        logInfo::class
    ];

    /**
     * Define the application\'s command schedule.
     *
     * @param  \\Illuminate\\Console\\Scheduling\\Schedule  $schedule
     * @return void
     */
    protected function schedule(Schedule $schedule)
    {
         $schedule->command(\'log:info\')
                  ->everyMinute();
    }    

$ crontab -e 
* * * * * php /var/www/lara/leaning/artisan schedule:run >> /dev/null 2>&1

middleware###

php artisan make:middleware isAdminMiddleware

user表增加is_admin字段 值为 Y/N

模型user.php

 public function isAdmin(){
        return  $this->is_admin == 1;
 }

修改isAdminMiddleware

public function handle($request, Closure $next)
{
    info( $request->user()); //等价于 Auth::user()
    if($request->user() && $request->user()->isAdmin()){
        return $next($request);
    }
    return redirect(\'/\');
}

web.php

Auth::loginUsingId(2);

Route::group([\'prefix\'=>\'admin\',\'middleware\'=>\'isAdmin\'],function (){
    Route::get(\'users\',function (){
        return \'admin only\';
    });
});

controller中可以这样设置

public function __construct(){
    $this->middleware(\'admin\',[\'only\'=>[\'store\',\'update\']]);
}

app/Http/Kernel.php

 protected $routeMiddleware = [
        \'isAdmin\' => isAdminMiddleware::class
    ];
}

视图绑定变量###

app下新建一个类 Status

<?php

namespace App;

class Status
{
    public function total(){
        return 45;
    }
}

路由以前的做法是这样

Route::get(\'/status\',function(\\App\\Status $status){
    return view(\'status\',compact(\'status\'));
});

status.blade.php

<h1>Status</h1>

{{$status->total()}}

模板绑定变量这样写:

路由:不传递任何变量

Route::get(\'/status\',function(){
    return view(\'status\');
});

模板中注入变量:status.blade.php

@inject(\'status\',\'App\\Status\')

本地化Model Factory###

tinker:

factory(User::class,5)->create() //会写库
//或 
factory(User::class,5)->make() //不会写库

App/Providers/AppServiceProvider.php

use Faker\\Generator as FakerGenerator;
use Faker\\Factory as FakerFactory;

 public function boot()
    {
        $this->app->singleton(FakerGenerator::class,function (){
            return FakerFactory::create(\'zh_CN\');
        });
    }

再次用tinker生成的数据就是中文的了

DB::table(\'users\')->truncate() 会将user表的数据全部删除

分页###

路由:

Route::get(\'/lessons\',function(){
    $lessons = \\App\\Lesson::paginate(15);
    return view(\'lessons\',compact(\'lessons\'));
});

模板

@extends(\'app\')

@section(\'content\')
    <h1>Lessons</h1>
    @foreach($lessons->chunk(3) as $row)
    <div class="row">
        @foreach($row as $lesson)
            <div class="col-md-4">
                <h2>{{ $lesson->title  }}</h2>
                <img style="width:100%; " src="{{$lesson->imageUrl}}" alt="">
                <div class="body">
                    {{$lesson->intro}}
                </div>
            </div>
        @endforeach
    </div>
    @endforeach

    {!! $lessons->render() !!}
    {{ $lessons->appends([\'type\'=>\'article\'])->links(\'vendor.pagination.bootstrap-4\')  }}
@stop

分页两种方式都可以

{!! $lessons->render() !!}
{{ $lessons->appends([\'type\'=>\'article\'])->links(\'vendor.pagination.bootstrap-4\') }}

造测试数据 给article分配userId###

$factory->define(\\App\\Article::class, function (Faker\\Generator $faker) {
    $userIds= \\App\\User::pluck(\'id\')->toArray();
    return [
        \'title\' => $faker->sentence,
        \'content\' => $faker->paragraph,
        \'user_id\' => $faker->randomElements($userIds)[0]
    ];
});

find 可以传入 id 也可以传入数组

App\\User::find([2,3])  

with eager loading###

user.php

 public function posts(){
    return $this->hasMany(Post::class)
 }   

路由:获取当前用户下的所有post

 这里的post只的就是对应的关系
 $posts = \\App\\User::with(\'posts\')->get()

多态关联###

应用场景:评论属于文章 属于lesson

php artisan make:model comment -m

comment migration

 public function up()
    {
        Schema::create(\'comments\', function (Blueprint $table) {
            $table->increments(\'id\');
            $table->integer(\'commentable_id\');
            $table->string(\'commentable_type\');
            $table->text(\'body\');
            $table->timestamps();
        });
    }

comment.php 模型

 class comment extends Model
 {
     public function commentable(){
         return $this->morphTo();
     }
 }

post.php 模型

 use App\\comment;
 class post extends Model
 {
     protected $guarded = array();
     protected $events = [
        \'created\' => PostWasPublished::class
     ];
     public function comments(){
         return $this->morphMany(comment::class,\'commentable\');
     }
 }

lesson.php 模型

class Lesson extends Model
{
    protected $guarded = array();

    public function comments(){
        return $this->morphMany(comment::class,\'commentable\');
    }
}

使用:

  • 给某个lesson添加评论

      $lesson = App\\Lesson::find(1);
      $lesson->unguard();
      $lesson->comments()->create(["body"=>"nice lesson"]);
    
  • 通过评论来查看属于哪个post

      $comment = App\\comment::find(1);
      $comment->commentable
    

有用的小方法###

  • dd( $article->created_at->diffForHumans() ); //几分钟前
  • Config::get(\'database.default\');
  • app(\'config\')[\'database\'][\'default\']
  • Hash::make(\'password\')
  • app(\'hash\')->make(\'password\')
  • config(\'services\')
  • \\Auth::login($user) //自动登录
  • Auth::check() //检查是否登录
  • 密码;bcrypt(str_random(16))
  • model中设置 $hidden = [\'title\'] //有时您可能想要限制能出现在数组或 JSON 格式的属性数据,比如密码字段。只要在模型里增加 hidden 属性即可

acl权限

AuthServiceProvider.php

public function boot()
    {
        $this->registerPolicies();

        Gate::define(\'show-post\',function ($user,$article){
            return $user->id ###  $article->user_id;
        });
    }

controller.php 测试当前用户是否有权限(当前post的id是否是当前用户)访问当前post,如果没权限访问则报错403

 public function show($id){
        $article = Article::findOrFail($id);
        //dd( $article->created_at->diffForHumans() );

        //12 minits ago 如果需要中文可以
        //可以在app/Providers/AppServiceProvider.php的boot()方法加上:
        //\\Carbon\\Carbon::setLocale(\'zh\');

        if(Gate::denies(\'show-post\',$article)){
            abort(403,\'sorry\');
        };

        //也可以这么写
       // $this->authorize(\'show-post\',$article);

        return view(\'articles.show\',compact(\'article\'));
    }    

如果要在blade中运用 则全部注释掉

     public function show($id){
            $article = Article::findOrFail($id);
            //dd( $article->created_at->diffForHumans() );
    
            //12 minits ago 如果需要中文可以
            //可以在app/Providers/AppServiceProvider.php的boot()方法加上:
            //\\Carbon\\Carbon::setLocale(\'zh\');
    
            //if(Gate::denies(\'show-post\',$article)){
            //abort(403,\'sorry\');
            //};
    
            //也可以这么写
           // $this->authorize(\'show-post\',$article);
    
            return view(\'articles.show\',compact(\'article\'));
     }

模版中使用

     @extends(\'app\')
        
        @section(\'content\')
            <h2>{{$article->title}}</h2>
            <div>{{$article->content}}</div>
        
            @can(\'show-post\',$article)
                <a href="">编辑</a>
            @endcan
        
    @stop

使用policy###

policy的使用是为了更方便的创建用户权限规则 避免了在AuthServiceProvider中定义一长串的规则

   php artisan make:policy ArticlePolicy

添加policy 规则:

   public function editArticle($user,$article){
           return $user->id ###  $article->user_id;
       }

AuthServiceProvider.php中注册该ArticlePolicy

   protected $policies = [
           \'App\\Article\' => \'App\\Policies\\ArticlePolicy\',
       ];

控制器使用:

   if(Gate::denies(\'editArticle\',$article)){
                   abort(403,\'sorry\');
                   };  

模版中使用:

    @extends(\'app\')
                
            @section(\'content\')
                <h2>{{$article->title}}</h2>
                <div>{{$article->content}}</div>
            
                @can(\'editArticle\',$article)
                    <a href="">编辑</a>
                @endcan
            
            @stop 

用户权限

php artisan make:model Permission
php artisan make:model Role
php artisan make:migration create_roles_table --create=roles

编辑迁移文件:

 public function up()
    {
        Schema::create(\'roles\', function (Blueprint $table) {
            $table->increments(\'id\');
            $table->string(\'name\');//admin.member
            $table->string(\'label\')->nullable();//注册会员
            $table->timestamps();
        });
        Schema::create(\'permissions\', function (Blueprint $table) {
            $table->increments(\'id\');
            $table->string(\'name\');//admin.member
            $table->string(\'label\')->nullable();//注册会员
            $table->timestamps();
        });
        Schema::create(\'permission_role\', function (Blueprint $table) {
            $table->integer(\'permission_id\')->unsigned();
            $table->integer(\'role_id\')->unsigned();

            $table->foreign(\'permission_id\')
                    ->references(\'id\')
                    ->on(\'permissions\')
                    ->onDelete(\'cascade\');

            $table->foreign(\'role_id\')
                ->references(\'id\')
                ->on(\'roles\')
                ->onDelete(\'cascade\');

            $table->primary([\'permission_id\',\'role_id\']);
        });
        Schema::create(\'role_user\', function (Blueprint $table) {
            $table->integer(\'user_id\')->unsigned();
            $table->integer(\'role_id\')->unsigned();

            $table->foreign(\'user_id\')
                ->references(\'id\')
                ->on(\'users\')
                ->onDelete(\'cascade\');

            $table->foreign(\'role_id\')
                ->references(\'id\')
                ->on(\'roles\')
                ->onDelete(\'cascade\');

            $table->primary([\'user_id\',\'role_id\']);

        });
    }

定义关系:

  • role.php

    public function permissions(){
    return $this->belongsToMany(Permission::class);
    }
    public function givePermission(Permission $permission){
    return $this->permissions()->save($permission);
    }

  • permission.php

      public function roles(){
          return $this->belongsToMany(Role::class);
      }
    
  • user.php

        public function roles(){
              return $this->belongsToMany(Role::class);
          }
      
          public function hasRole($role){
              //如果传入的是字符串
              if( is_string($role) ){
                  return $this->roles->contains(\'name\',$role);
              }
              //如果传入的是collection  intersect 只的是 $role 和 $this->roles()有没有交集
              return !!$role->intersect( $this->roles )->count();
          }
    

tinker 创建一个role 一个permission 并把permission指派给这个role

       $role->givePermission($permission)
      
      也可以直接
      
      $role->permissions()->save($permission)
      
      $user->roles()->save($role) 给用户分配角色
      $user->roles()->detach($role) 删除角色

authServiceProvider.php

       public function boot()
          {
              $this->registerPolicies();
      
              foreach ( $this->getPermission() as $permission ){
                  Gate::define( $permission->name,function (User $user) use($permission){
                      return $user->hasRole($permission->roles);
                  });
              }
          }
          protected function getPermission(){
              return Permission::with(\'roles\')->get();
          }

blade中这样使用:

    @can(\'edit\')
           <a href="">编辑edit</a>
    @endcan

service container:

class Barz{}

class Foo{
    public $bar;

    public function __construct(Barz $barz)
    {
        $this->bar = $barz;
    }
}
//如果有app绑定的优先找绑定的
App::bind(\'Foo\',function (){
    dd(12);
    return new Foo(new BarZ());
});
Route::get(\'container\',function (Foo $foo){
    dd($foo);
});

App绑定后路由里不再需要依赖注入

Route::get(\'container1\',function (){
    dd(app(\'Foo\'));
});

service实战 向IOC 容器添加自己的类

  • 添加一个自己的类

App\\Services\\Billing\\Stripe.php

<?php 
namespace App\\Services\\Billing;
class Stripe
{
    public function charge(){
        dd(\'charged\') ;
    }
}
  • 新建一个provider

      php artisan make:provider BillingServiceProvider
    
  • 注入服务 BillingServiceProvider.php , 注意要在app.php中注入这个provider

      public function register()
          {
              $this->app->bind(\'billing\',function(){
                  return new Stripe();
              });
          }
    
  • 访问 两种方法均可:

      Route::get(\'container2\',function (){
          dd(app(\'billing\')->charge());
      });
      
      //或
      
      Route::get(\'container2\',function (\\App\\Services\\Billing\\Stripe $stripe){
          dd($stripe->charge());
      });
    

结合interface

重构代码:

  • 定义接口:App\\Billing\\BillingInterface.php
    public function charge(array $data);

  • 定义类:App\\Biling\\PingBilling.php

      class PingBilling implements BillingInterface{
      	public function charge($data){
      		//todo
      	}
      }
    
  • 声明serviceprovider 把PingBilling这个类放到ioc container中 BillingServiceProvider

$this->app->bind(\'billing\',\'App\\Biling\\PingBilling\')

  • app.php 添加 BillingServiceProvider

控制器中调用 app(\'billing\')->charge($data)

=facade### =

每个facade例如 Route 类 返回的其实都是个字符串,关键是继成了Facade类, Facade有个 __callStatic 方法,在一个类中执行一个不存在的静态方法时 该方法会被触发

Facade.php

public static function __callStatic($method, $args)
    {
        $instance = static::getFacadeRoot();

        if (! $instance) {
            throw new RuntimeException(\'A facade root has not been set.\');
        }

        return $instance->$method(...$args);
    }

__callStatic 执行了 $instance = static::getFacadeRoot(); 生成一个实例,解析的结果是 app(\'mailer\')

public static function getFacadeRoot()
    {
	//static::getFacadeAccessor() 指的就是 mailer,    这句解析的结果就是 app(\'mailer\') 其实就是Mailer这个类,到这里就必然有个provider绑定mailer 可在provider中查找
        return static::resolveFacadeInstance(static::getFacadeAccessor());
    }

目标:我希望我创建一个AjaxResponse的facade,这样能直接在controller中这样使用:

\\AjaxResponse::success();

返回

{
    code: "0"
    result: {

    }
}

步骤:

  • step1: 在app/Services文件夹中创建类

      <?php namespace App\\Services;
      
      class AjaxResponse {
      
          protected function ajaxResponse($code, $message, $data = null)
          {
              $out = [
                  \'code\' => $code,
                  \'message\' => $message,
              ];
      
              if ($data !== null) {
                  $out[\'result\'] = $data;
              }
      
              return response()->json($out);
          }
      
          public function success($data = null)
          {
              $code = ResultCode::Success;
              return $this->ajaxResponse(0, \'\', $data);
          }
      
          public function fail($message, $extra = [])
          {
              return $this->ajaxResponse(1, $message, $extra);
          }
      }
    

    这个AjaxResponse是具体的实现类

  • step2: 创建provider

      <?php namespace App\\Providers;
      
      use Illuminate\\Support\\ServiceProvider;
      
      class AjaxResponseServiceProvider extends ServiceProvider {
      
          public function register()
          {
              $this->app->singleton(\'AjaxResponseService\', function () {
                  return new \\App\\Services\\AjaxResponse();
              });
          }
      }
    

这里我们在register的时候定义了这个Service名字为AjaxResponseService

  • step3:在app/Facades文件夹中创建类

      <?php namespace App\\Facades;
      
      use Illuminate\\Support\\Facades\\Facade;
      
      class AjaxResponseFacade extends Facade {
      
          protected static function getFacadeAccessor() { return \'AjaxResponseService\'; }
      
      }
    
  • step4:好了,下面我们只需要到app.php中挂载上这两个东东就可以了

      <?php
      
      return [
      
          ...
      
          \'providers\' => [
              ...
              \'App\\Providers\\RouteServiceProvider\',
      
              \'App\\Providers\\AjaxResponseServiceProvider\',
      
          ],
      
      
          \'aliases\' => [
              ...
      
              \'Validator\' => \'Illuminate\\Support\\Facades\\Validator\',
              \'View\'      => \'Illuminate\\Support\\Facades\\View\',
      
              \'AjaxResponse\' => \'App\\Facades\\AjaxResponseFacade\',
      
          ],
      
      ];
    

使用name和email登录

postLogin 方法:

$field = filter_var($request->input(\'username\'), FILTER_VALIDATE_EMAIL) ? \'email\' : \'username\';
    $request->merge([$field => $request->get(\'username\')]);

if(Auth::guard(\'admin\')->attempt( $request->only($field, \'password\'),
        $request->remember)
    ){
        //if successful,then intend the user to their intended location
        return redirect()->intended(route(\'admin.dashboard\'));
    }else{
        //if unsuccessful,then redirect back to the login with the form data
        return redirect()->back()->withInput($request->only(\'username\',\'remember\'));
    }

api

$lessons = Lesson::all();
\\Response::json([
	\'status\' => \'success\',
	\'status_code\' => 200,
	\'data\'   => $lessons->toArray()
]);

= 字段映射 ### =

$lessons = Lesson::all();
\\Response::json([
	\'status\' => \'success\',
	\'status_code\' => 200,
	\'data\'   => $this->transform($lessons->toArray())
]);

public function transform($lessons){
	return array_map(function($lesson){
		return [
			\'title\' => $lesson[\'title\'],
			\'content\' => $lesson[\'body\'],
			\'is_free\' => (boolean)$lesson[\'free\']
		];
	},$lessons);
}

注意 这个transform 是处理 collection的数据 all()
如果要处理elequent model 比如 Lesson::find(1)这样的数据需要这么处理transform方法,collection 用transformCollection方法:

public function transformCollection($lessons){
	return array_map([$this,\'transform\'],$lessons);
}

public function transform($lesson){
	return [
			\'title\' => $lesson[\'title\'],
			\'content\' => $lesson[\'body\'],
			\'is_free\' => (boolean)$lesson[\'free\']
		];
}

= 代码重构 ### =

比如有个article也需要使用transform

  • 新建一个类 App\\Transformer\\Transformer.php

      <?php
    
      namespace App\\Transformer;
      
      abstract class Transformer
      {
          /**
           * @param $items
           * @return array
           */
          public function transformCollection($items){
              return array_map([$this,\'transform\'],$items);
          }
      
          /**
           * @param $item
           * @return mixed
           */
          public abstract function transform($item);//抽象方法不用写大括号
      }
    
  • 新建LessonTransform 并继承Transformer类 App\\Transformer\\LessonTransform .php

    namespace App\\Transformer; class LessonTransformer extends Transformer { /** * @param $lesson * @return array */ public function transform($lesson){ return [ \'title\' => $lesson[\'title\'], \'content\' => $lesson[\'intro\'] ]; } }
  • Lesson控制器中依赖注入 并调用Transformer中的方法

    protected $lessonTransformer;

      public function __construct(LessonTransformer $lessonTransformer)
      {
          $this->lessonTransformer = $lessonTransformer;
      }
      /**
       * Display a listing of the resource.
       *
       * @return \\Illuminate\\Http\\Response
       */
      public function index()
      {
          $lessons = Lesson::all();
          return \\Response::json([
              \'status\' => \'success\',
              \'status_code\' => 200,
              \'data\'   => $this->lessonTransformer->transformCollection($lessons->toArray())
          ]);
      }
      
      public function show($id)
      {
          $lesson = Lesson::find($id);
          return \\Response::json([
              \'status\' => \'success\',
              \'status_code\' => 200,
              \'data\'   => $this->lessonTransformer->transform($lesson)
          ]);
      }	
    

= 错误提示 ### =

1.新建一个ApiController.php

<?php

namespace App\\Http\\Controllers;

use Illuminate\\Http\\Request;

class ApiController extends Controller
{
    protected $statusCode = 200;

    /**
     * @return int
     */
    public function getStatusCode(): int
    {
        return $this->statusCode;
    }

    /**
     * @param int $statusCode
     */
    public function setStatusCode(int $statusCode)
    {
        $this->statusCode = $statusCode;
        return $this;
    }
    public function responseNotFound( $message = \'Not Found\' ){
        return $this->responseError($message);
    }
    private function responseError($message){
        return $this->response([
            \'status\' => \'fail\',
            \'status_code\' => $this->getStatusCode(),
            \'message\' => $message
        ]);
    }
    public function response($data){
        return \\Response::json($data);
    }
}

2.控制器:LessonController.php 集成ApiController.php

 public function show($id)
    {
        $lesson = Lesson::find($id);
        if( !$lesson ) {
           return  $this->setStatusCode(500)->responseNotFound();
        }
        return $this->response([
            \'status\' => \'success\',
            \'data\'   => $this->lessonTransformer->transform($lesson)
        ]);
    }

这时候访问 transformer/2689 就会返回ApiController中的错误信息

{
	"status": "fail",
	"status_code": 404,
	"message": "Not Found"
}

= postman禁用token ### =

app\\kernel.php 注释掉verifyCsrfToken.php

api验证有三种:

= auth.basic 基础验证### =

控制器构造方法中:

public function __construct(){
	$this->middleware(\'auth.basic\',[\'only\'=>[\'store\',\'update\']]);
}

laravel 有用的小方法

[http://www.cnblogs.com/webskill/p/7463488.html ]

laravel package

  1. 根目录下新建目录 packages/Laravist/Hasher/src

  2. composer 自动加载 并 设置命名空间

    "autoload": {
    "classmap": [
    "database/seeds",
    "database/factories"
    ],
    "psr-4": {
    "App\\": "app/",
    "Laravist\\Hasher\\":"package/Laravist/Hasher/src/"
    }
    },

  3. src下新建一个类:Md5Hasher.php

     <?php
     namespace Laravist\\Hasher;
     class Md5hasher
     {
         public function make($value,array $options = []){
             $salt = isset($options[\'salt\']) ? $options[\'salt\'] : \'\';
             return hash(\'md5\',$value.$salt);
         }
         public function check($value,$hashvalue,array $options = []){
             $salt = isset($options[\'salt\']) ? $options[\'salt\'] : \'\';
             return hash(\'md5\',$value.$salt) ###  $hashvalue;
         }
     }
    
  4. 加载这个类:
    php artisan make:provider Md5HashProvider 移到 src下

  5. Md5HashProvider 中注册使用方法:

     public function register()
         {
             $this->app->singleton(\'md5hash\',function (){
                 return new Md5hasher();
             });
         }
    
  6. tinker中使用

     app(\'md5hasher\')->make(\'password\')
    

自定义错误提示

resources/lang/en/validation.php

找到custom


\'custom\' => [
\'attribute-name\' => [
\'rule-name\' => \'custom-message\',
],
],
改成:
\'custom\' => [
\'name\' => [
\'required\' => \'用户名不能为空\',
],
],

使用第三方插件 markdown

  1. hyperDown github上 找到Parser.php app下新建文件 App\\Markdown\\Parser.php 注意命名空间

  2. App\\Markdown\\Markdown.php

    <?php
     
    namespace App\\Markdown;
    
    
    class Markdown
    {
        protected $parser;
     
        public function __construct(Parser $parser)
        {
            $this->parser = $parser;
        }
        public function markdown($text){
             $html = $this->parser->makeHtml($text);
             return $html;
        }
    }
    
    
    composer dump-autoload
    
  3. 控制器中使用

      protected $markdown;
         public function __construct(Markdown $markdown)
         {
             $this->markdown = $markdown;
             $this->middleware(\'auth\',[\'only\'=>[\'create\',\'store\',\'edit\',\'update\']]);
         }
     public function show($id)
         {
             $discussion = Discussion::findOrFail($id);
             $html = $this->markdown->markdown($discussion->body) ;
             return view(\'forum.detail\',compact(\'discussion\',\'html\'));
         }
    
  4. view中使用
    {!! $html !!}

storage###

图片上传使用 storage_path(\'app/public\') 这种的时候 默认图片上传到 storage/app/public 下面 , 需要 php artisan storage:link 链到 public目录下

模糊查询###

$topics = \\App\\Topic::select([\'id\',\'name\'])
    ->where(\'name\',\'like\',\'%\'.$request->query(\'q\').\'%\')
    ->get();

helper###

App下建 Support/hellper.php

比如 Auth::guard(\'api\')->user()->id 用的非常多,把它做成helper

helper.php

<?php

if(!!function_exists(\'user\')){
    function user($driver=null){
        if ($driver){
            return app(\'auth\')->guard($driver)->user();
        }
        return app(\'auth\')->user();
    }
}

composer.json

"autoload": {
        "files":[
          "App/Support/helper.php"
        ],
        "classmap": [
            "database/seeds",
            "database/factories"
        ],
        "psr-4": {
            "App\\\\": "app/"
        }
    },	

可直接在控制器或blade中使用 user() 或者 user(\'api\')

with 和 wherehas###

with: 选择所有的model, 每个model 关联的translations 根据条件进行过滤,结果只有 title like $query 的translations不为空, 其他model的translations为空

return $this->model->with([
        \'translations\' => function($q)use($query){
            $q->where(\'title\',\'like\',"%{$query}%")
            ->select(\'product_id\',\'title\');
        }
    ])

wherehas: 选出满足条件的 model, 不是所有的model

$this->model->whereHas(\'translations\', function($q)use($query){
              $q->where(\'title\', \'like\', "%{$query}%");
    })->get();

以上是关于laravel5.4新特性的主要内容,如果未能解决你的问题,请参考以下文章

Java 8 新特性总结

laravel5.4 关于数据填充的知识

ES7-Es8 js代码片段

[译文]React v16(新特性)

laravel5.4菜鸟进阶001

如何通过单击片段内的线性布局从片段类开始新活动?下面是我的代码,但这不起作用