让更好用的Laravel来构建web应用

袁栩栩 2015-12-23 

Laravel - 可能是全球最好用的PHP框架

Lumen

Laravel特点和优点

  • Blade模板引擎
  • 强大的RESTful Routing
  • Eloquent ORM
  • Migration & Seed
  • Artisan 控制台
  • Laravel Elixir
  • Composer

   ......

  • ServiceProvider,Contracts,Facades

最新版本5.2

  • Auth Scaffolding
  • Implicit model binding
  • Appending output from scheduled tasks
  • Form Array Validation
  • Collections Wildcards
  • Middleware Groups
  • Rate Limiting

   ......

更好用的Laravel ?

那些官方手册里不会告诉你的干货!

不同的环境如何调用不同的配置文件?

比如本机开发环境调用.env.local配置,预览环境调用.env.preview配置,线上直接调用.env配置

// bootstrap/app.php
$environment = getenv('DEV_ENV') ? '.' . getenv('DEV_ENV') : '';
$app->loadEnvironmentFrom('.env'.$environment);

设置webserver 变量 DEV_ENV=local

export DEV_ENV=local

面向对象设计和编程的SOLID

SRP 单一责任原则
OCP 开发封闭原则
LSP 里氏替换原则
DIP 依赖倒置原则
ISP 接口分离原则

为什么很多开源项目中用Repositories 而不用 Model?

  • 不要把数据库操作写在Controller中
  • Model会变得很大怎么办
  • 解耦 & SOLID

将Model注入到Repository,Repository注入到Controller

<?php namespace App\Models;

use Illuminate\Auth\Authenticatable;
use Illuminate\Auth\Passwords\CanResetPassword;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
use Illuminate\Database\Eloquent\Model;
use Zizaco\Entrust\Traits\EntrustUserTrait;

/**
 * App\Models\User
 *
 * @property integer $id
 * @property string $name
 * @property string $email
 * @property string $password
 * @property string $remember_token
 * @property \Carbon\Carbon $created_at
 * @property \Carbon\Carbon $updated_at
 * @property-read \Illuminate\Database\Eloquent\Collection|\Config::get('entrust.role')[] $roles
 * @method static \Illuminate\Database\Query\Builder|\App\Models\User whereId($value)
 * @method static \Illuminate\Database\Query\Builder|\App\Models\User whereName($value)
 * @method static \Illuminate\Database\Query\Builder|\App\Models\User whereEmail($value)
 * @method static \Illuminate\Database\Query\Builder|\App\Models\User wherePassword($value)
 * @method static \Illuminate\Database\Query\Builder|\App\Models\User whereRememberToken($value)
 * @method static \Illuminate\Database\Query\Builder|\App\Models\User whereCreatedAt($value)
 * @method static \Illuminate\Database\Query\Builder|\App\Models\User whereUpdatedAt($value)
 */
class User extends Model implements AuthenticatableContract, CanResetPasswordContract {

    use Authenticatable, CanResetPassword, EntrustUserTrait;

    /**
     * The database table used by the model.
     *
     * @var string
     */
    protected $table = 'users';

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name',
        'email',
        'password'
    ];

    /**
     * The attributes excluded from the model's JSON form.
     *
     * @var array
     */
    protected $hidden = [
        'password',
        'remember_token'
    ];

}

app/Models/User.php

app/Repositories/UserRepository.php

<?php namespace App\Repositories;

use App\Models\User;
use App\Repositories\BaseRepository;

class UserRepository extends BaseRepository {
    protected $user;

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

    /**
     * Store user
     * @param $inputs
     * @return bool
     */
    public function store($inputs)
    {
        $user = new $this->user;
        $user->name = $inputs['name'];
        $user->email = $inputs['email'];
        $user->password = bcrypt($inputs['password']);
        if ($user->save()) {
            return $user->id;
        }
        return false;
    }

    /**
     * Get user list
     * @param int $perPage
     * @return mixed
     */
    public function userList($perPage = 20)
    {
        return $this->user->orderBy('id', 'DESC')->paginate($perPage);
    }

    /**
     * Attach roles to user
     * @param $userId
     * @param $roles
     */
    public function attachRole($userId, $roles)
    {
        foreach ($roles as $role) {
            $this->user->find($userId)->attachRole($role);
        }
    }

    /**
     * Update User
     * @param $id
     * @param $inputs
     */
    public function update($id, $inputs)
    {
        ....
    }

    /**
     * Destroy user by id
     * @param int $id
     * @return bool|null
     */
    public function destroy($id)
    {
        $user = $this->user->find($id);
        if (!$user) {
            return false;
        }
        $user->roles()->detach();
        Cache::forget('user:menus:' . $id);
        return $user->delete();
    }

}

app/Controllers/UserController.php

<?php namespace App\Http\Controllers\;

use App\Http\Controllers\BaseController;
......
use App\Repositories\UserRepository;

class UserController extends BaseController {
    protected $userRepository;
    protected $roleRepository;


    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct(UserRepository $userRepository, RoleRepository $roleRepository)
    {
        parent::__construct();
        $this->userRepository = $userRepository;
        $this->roleRepository = $roleRepository;
    }

    /**
     * Display a listing of the resource.
     *
     * @return Response
     */
    public function index()
    {
        $users = $this->userRepository->userList(static::PER_PAGE_NUM);
        $users->setPath('');    
        ......
    }

   

    /**
     * Store a newly created resource in storage.
     *
     * @return Response
     */
    public function store(CreateRequest $createRequest)
    {
        $userId = $this->userRepository->store($createRequest->all());
        if ($userId && ($roles = $createRequest->input('roles', []))) {
            $this->userRepository->attachRole($userId, $roles);
        }
        $alert = [
            'type' => $userId ? 'success' : 'warning',
            'data' => $userId ? ['新用户创建成功'] : ['用户创建失败'],
        ];
        ......
    }

    ......

}

使用Service给Controller减肥

  • Controller方法中的逻辑代码太长
  • Controller中的逻辑代码复用

A控制器调用B控制器的方法

  • 一个逻辑中涉及到多Respository
  • 解耦

app/Services/OrderService.php

<?php
namespace App\Services;

use Illuminate\Support\Facades\DB;
use App\Repositories\OrderRepository;
use App\Repositories\ProductRepository;

class OrderService
{
    protected $orderRepository;
    protected $productRepository;

    /**
     * OrderService constructor.
     * @param OrderRepository $orderRepository
     * @param ProductRepository $productRepository
     */
    public function __construct(OrderRepository $orderRepository, ProductRepository $productRepository)
    {
        $this->orderRepository = $orderRepository;
        $this->productRepository = $productRepository;
    }

    /**
     * 结算
     * @param $id   商品ID
     * @param $status  订单状态
     * @param $num  购买数量
     */
    public function checkout($id, $status, $num)
    {
        DB::transaction(function () use ($id, $status, $num) {
            $productId = $this->orderRepository->updateStatus($id);
            $this->productRepository->stockMinusNum($productId);
        });
    }
}

app/Repositories/OrderRepository.php

<?php
namespace App\Respositories;
......
use App\Models\Order;

class OrderRepository extends BaseRepository
{
    protected $order;

    /**
     * OrderRepository constructor.
     * @param Order $order
     */
    public function __construct(Order $order)
    {
        $this->order = $order;
    }

    /**
     * 改变订单状态
     * @param integer $id
     * @return integer
     */
    function updateStatus($id,$status)
    {
        $order = $this->find($id);
        $order->status = $status;
        $productId = $order->product_id;
        $order->save();
        return $productId;
    }
}

app/Repositories/ProductRepository.php

<?php
namespace App\Respositories;
......
use App\Models\Product;

class ProductRepository extends BaseRepository
{
    protected $product;

    /**
     * ProductRepository constructor.
     * @param Product $product
     */
    public function __construct(Product $product)
    {
        $this->product = $product;
    }

    /**
     * 减少库存
     *
     * @param integer $productId
     */
    function stockMinusNum($productId,$num)
    {
        $product = $this->find($productId);
        $product->stock = $product->stock - $num;
        $product->save();
    }
}

app/Http/Controllers/OrderController.php

<?php
namespace App\Http\Controllers;

use App\Http\Requests;
use App\Services\OrderService;

class OrderController extends Controller
{
    protected $orderService;

    /**
     * OrderController constructor.
     * @param OrderService $orderService
     */
    public function __construct(OrderService $orderService)
    {
        $this->orderService = $orderService;
    }

    /**
     * @param $id
     * @return \Illuminate\Http\Response
     */
    public function store($id, $status, $num)
    {
        $this->orderService->checkout($id, $status, $num);
    }
}

实用的Debug调试工具

自定义函数放在哪?

  • 新建app/helpers.php,写入自定义函数
  • app/Providers/AppServiceProvider.php
/**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        require_once(app_path('helpers.php'));
    }

更多实用技巧

学习资源 & 中文社区

Better use of laravel to build web applications

By ryanyuan

Better use of laravel to build web applications

让更好用的laravel来构建web应用

  • 5,228