美文网首页
andersao/l5-repository实践记录

andersao/l5-repository实践记录

作者: 某不科学的XX | 来源:发表于2017-06-26 22:48 被阅读0次

    创建model

    php artisan make:entity Article
     Would you like to create a Presenter? [y|N] (yes/no) [no]:
      y 
    App\Transformers\ArticleTransformerPresenter created successfully.
     Would you like to create a Transformer? [y|N] (yes/no) [no]:
      y
    Transformer created successfully.
     Would you like to create a Validator? [y|N] (yes/no) [no]:
      y
    Validator created successfully.
     Would you like to create a Controller? [y|N] (yes/no) [no]:
     y
    Request created successfully.
    Request created successfully.
    Controller created successfully.
    Repository created successfully.
    Bindings created successfully
    

    生成或修改了以下文件

    • Model 模型文件
    • Presenters 常用于前端模板格式化输出 (可能不准确)

    Presenters function as a wrapper and renderer for objects.

    • Transformer 用于model数据格式化输出
    • Validator 验证器
    • CreateRequest 创建数据请求
    • UpdateRequest 更新数据请求
    • Controller RESTfull控制器
    • Repository 资料库与资料库接口
     php artisan make:repository "Blog\Post"
     php artisan make:repository "Blog\Post" --fillable="title,content"
     php artisan make:entity Cat --fillable="title:string,content:text" --rules="title=>required|min:2, content=>sometimes|min:10"
    
    • Bindings 在Providers/RepositoryServiceProvider.php中注册
    php artisan make:bindings Cats //可单独使用
    $this->app->bind(\App\Repositories\ArticleRepository::class, \App\Repositories\ArticleRepositoryEloquent::class); 
    
    • 添加了对应的数据库迁移文件

    添加模型字段 数据库迁移 测试数据填充

     $table->increments('id');
     $table->String('title',150)->comment('标题');
     $table->String('author',50)->comment('作者');
     $table->text('article')->comment('文章');
     $table->softDeletes()->comment('软删除');
     $table->timestamps();
    
    • 修改model文件添加字段
     protected $fillable = [
            'title',
            'author',
            'article'
        ];
    
    • 为了方便数据库的填充使用factories工厂文件与seeds种子文件

    =>工厂文件

    $factory->define(App\Entities\Article::class, function (Faker\Generator $faker) {
    
        return [
            'title' => $faker->sentence,
            'author'=> $faker->name,
            'article'=> $faker->text,
    //        'img' => $faker->url,
    //        'content' => $faker->text,
    //        'sort' => $faker->randomDigit,
    //        'pageviews' => $faker->randomDigit,
    //        'tag' => $faker->randomDigit,
    //        'status' => $faker->randomElement([-1, 0, 1]),
        ];
    });
    

    =>种子文件

    //创建种子文件
    artisan make:seeder ArticleTableSeeder
    //修改种子文件
    public function run()
        {
            $article = factory('App\Entities\Article',50)->create();
        }
    //修改DatabasesSeeder
     public function run()
        {
             //$this->call(UsersTableSeeder::class);
            $this->call(ArticleTableSeeder::class);
        }
    

    执行迁移与填充

    php artisan  migrate 
    php artisan  db:seed
    //或者直接使用下面的
    php artisan migrate:refresh --seed
    

    注册服务 添加路由 尝试输出

    • 注册服务
    //在AppServiceProvider的register中添加 
    $this->app->register(RepositoryServiceProvider::class);
    
    • 添加路由
    //在路由文件中添加 
    Route::resource('article', ArticlesController::class);
    
    • 修改控制器并访问地址
    public function index()
        {
            $this->repository->pushCriteria(app('Prettus\Repository\Criteria\RequestCriteria'));
            $articles = $this->repository->all();
    
            if (request()->wantsJson()) {
    
                return response()->json([
                    'data' => $articles,
                ]);
            }
    
            dd($articles);
            return $articles->toJSON();
    //        return view('articles.index', compact('articles'));
        }
    

    访问 http://192.168.10.10:90/article
    正常返回json格式数据

    简单的搜索功能实现

    • 在ArticleRepositoryEloquent中添加允许搜索字段
    //格式  字段=>搜索方式  默认搜索方式为 =
    protected $fieldSearchable = [
            'id'=>'=',
            'title'=>'like',
            'author'
        ];
    
    select * from `articles` where (`articles`.`id` = 'Ratione' or `articles`.`title` like '%Ratione%' or `articles`.`author` = 'Ratione') and (`articles`.`id` = 'Ratione' or `articles`.`title` like '%Ratione%' or `articles`.`author` = 'Ratione')
    


    http://192.168.10.10:90/article?search=Ratione&searchFields=title:like

    select * from `articles` where (`articles`.`title` like '%Ratione%') and (`articles`.`title` like '%Ratione%')
    


    http://192.168.10.10:90/article?search=id:15;title:Ratione&searchFields=title:like;id:=

    select * from `articles` where (`articles`.`id` = '15' or `articles`.`title` like '%Ratione%') and (`articles`.`id` = '15' or `articles`.`title` like '%Ratione%')
    

    正常返回json格式数据

    过滤功能的实现

    select `id`, `author` from `articles`
    


    http://192.168.10.10:90/article?filter=id;author&orderBy=id&sortedBy=desc

    select `id`, `author` from `articles` order by `id` desc, `id` desc
    

    关联查询功能实现

    • TODO

    普通的删除添加与修改功能的实现

    • 为了方便测试可以关闭csrf验证并修改updateRepository与createRepository中的用户权限验证

    1.注释掉http/Kernel.php中的

    \App\Http\Middleware\VerifyCsrfToken::class
    

    2.修改updateRepository与createRepository中的authorize()

    public function authorize()
        {
            return true;
        }
    
    namespace App\Entities;
    use Illuminate\Database\Eloquent\Model;
    use Prettus\Repository\Contracts\Transformable;
    use Prettus\Repository\Traits\TransformableTrait;
    use Illuminate\Database\Eloquent\SoftDeletes;
    class Article extends Model implements Transformable
    {
        use TransformableTrait;
        use SoftDeletes;
        protected $fillable = [
            'title',
            'author',
            'article'
        ];
    }
    

    使用postman用delete方法访问http://192.168.10.10:90/article/7
    数据库中文章并没有被直接删除,而且搜索与访问均失败
    软删除后如果想要强制删除可在控制器中添加,或者在资料库与资料库接口中扩展

    public function forceDestroy($id)
        {
            $deleted = $this->repository->find($id)->forceDelete();
    
            if (request()->wantsJson()) {
    
                return response()->json([
                    'message' => 'Article forceDelete.',
                    'deleted' => $deleted,
                ]);
            }
    
            return redirect()->back()->with('message', 'Article forceDelete.');
        }
    

    数据库中文章被删除

    缓存的使用

    • 这里需要在repository中添加缓存trait
    use Prettus\Repository\Contracts\CacheableInterface;
    use Prettus\Repository\Traits\CacheableRepository;
    class ArticleRepositoryEloquent extends BaseRepository implements ArticleRepository
    {
        /**
         * 开启缓存
         *
         */
    use CacheableRepository;
    ......
    }
    
    //为了方便,修改redis配置文件,使其可以后台运行,并可以远程连接
    //关于远程连接bind
    //这里很多人会误以为绑定的ip应该是请求来源的ip。其实不然,这里应该绑定的是你redis服务器本身接受请求的ip。http://www.2cto.com/database/201507/419799.html
    redis-server ./redis.conf
    

    然后修改.env文件,如果之前使用过file缓存更换为redis后,redis无法使用,则说明laravel配置被缓存了,需要删除该缓存

    artisan config:clear
    artisan cache:clear
    
    • 可以发现如果重复上述查找,修改,删除,添加测试,数据库并不会每次都会进行查询,而且通过RedisDesktopManager可以清楚的看见会有对象缓存进去。
    • 进行不同条件的检索时会有不同的对象缓存进redis,所以如果不是相同条件进行检索,还是会对数据库进行操作
    • 在任何的修改,删除(包括软删除),添加后,redis缓存都会被清除
    • 并发性能测试
      安装siege后进行测试,执行命令
    siege -c 255 -r 1 http://192.168.10.10:90/article 
    

    不使用缓存时

    vagrant@homestead:/usr/local/etc$ ../siege/src/siege -c 255 -r 1 http://192.168.10.10:90/article
    ** SIEGE 4.0.3rc3
    ** Preparing 255 concurrent users for battle.
    The server is now under siege...
    Transactions:                    255 hits
    Availability:                 100.00 %
    Elapsed time:                  39.52 secs
    Data transferred:               5.50 MB
    Response time:                 18.80 secs
    Transaction rate:               6.45 trans/sec
    Throughput:                     0.14 MB/sec
    Concurrency:                  121.30
    Successful transactions:         255
    Failed transactions:               0
    Longest transaction:           39.45
    Shortest transaction:           1.44
    

    使用缓存时

    vagrant@homestead:/usr/local/etc$ ../siege/src/siege -c 255 -r 1 http://192.168.10.10:90/article
    ** SIEGE 4.0.3rc3
    ** Preparing 255 concurrent users for battle.
    The server is now under siege...
    Transactions:                    255 hits
    Availability:                 100.00 %
    Elapsed time:                  52.13 secs
    Data transferred:               5.33 MB
    Response time:                 34.30 secs
    Transaction rate:               4.89 trans/sec
    Throughput:                     0.10 MB/sec
    Concurrency:                  167.77
    Successful transactions:         255
    Failed transactions:               0
    Longest transaction:           52.08
    Shortest transaction:          16.37
    

    结果让我有点吃惊。。。开了比没开居然还稍微差点,关闭调试模式也一样。不知道是我电脑性能不行还是因为查询结构太简单导致的。。。。。。也可能是其他地方没有使用redis比如session之类

    TODO

    过滤器

    • 可以修改Validator文件,也可以分别修改Create与Update的Request文件。其中Request优先级高于Validator,而且Validator文件中无法正常添加使用自定义错误信息,原因可能是Valitdator插件对应版本为laravel4,作者已经不再维护了。。。。。不过可以尝试使用这个方法https://github.com/andersao/laravel-validator/issues/21
      Validator中
    protected $rules = [
            ValidatorInterface::RULE_CREATE => [
                'title' => 'required|max:50',
                'text'  => 'min:3',
                'author'=> 'required|max:8'
    
            ],
            ValidatorInterface::RULE_UPDATE => [
                'title' => 'required',
    
            ],
       ];
    //  错误信息不能正常调出。
    //    protected $messages= [
    //            'title.required' => 'attt.',
    //            'min' => 'minnn.',
    //            'author.max' => 'maxxxx.',
    //    ];
    //    public function messages()
    //    {
    //        return $this->messages;
    //    }
    

    CreateRequest中

    public function rules()
        {
            return [
                'title' => 'required|max:15',
                'text'  => 'min:6',
                'author'=> 'required|max:7'
            ];
        }
    
        public function messages()
        {
            return [
    
                'title.required' => '请填写标题.',
                'min' => '低于最小字数.',
                'author.max' => '超过字数限制.',
    
            ];
        }
    

    格式化输出

    • 顾名思义他只控制输出格式,因此即便是只输出部分字段,他还是会从数据库中选择所有字段。通过修改Transform文件然后在仓库中或者控制器中注册Presenter,即可格式化输出。默认为json格式输出。
      修改Transform文件如下后,访问
    public function transform(Article $model)
        {
            return [
                'id'         => (int) $model->id,
    
                /* place your other model properties here */
                '标题' =>$model->title,
                '作者' =>$model->author,
                'article' =>$model->article,
    
                'created_at' => $model->created_at,
    //            'updated_at' => $model->updated_at
            ];
        }
    

    修改仓库

    public function presenter()
        {
            return "App\\Presenters\\ArticlePresenter";
        }
    

    或者修改控制器

    public function __construct(ArticleRepository $repository, ArticleValidator $validator)
        {
            $this->repository = $repository;
            $this->repository->setPresenter("App\\Presenters\\ArticlePresenter");
            $this->validator  = $validator;
        }
    
    • 当然也可以通过修改Model文件来格式化输出。但优先级比Transform文件低。
      Model文件
    namespace App\Entities;
    use Illuminate\Database\Eloquent\Model;
    use Prettus\Repository\Contracts\Transformable;
    use Prettus\Repository\Traits\TransformableTrait;
    use Illuminate\Database\Eloquent\SoftDeletes;
    use Prettus\Repository\Traits\PresentableTrait;
    class Article extends Model implements Transformable
    {
        use TransformableTrait;
        use SoftDeletes;
        use PresentableTrait;
        protected $fillable = [
            'title',
            'author',
            'article'
        ];
        public function transform()
        {
            return [
                'id'         => (int) $this->id,
                /* place your other model properties here */
                '标题' =>$this->title,
                '作者' =>$this->author,
                '文章' =>$this->article,
                'created_at' => $this->created_at,
                'updated_at' => $model->updated_at
            ];
        }
    }
    

    控制器

    public function __construct(ArticleRepository $repository, ArticleValidator $validator)
        {
            $this->repository = $repository;
            //$this->repository->setPresenter("App\\Presenters\\ArticlePresenter");
            $this->repository->setPresenter("Prettus\\Repository\\Presenter\\ModelFractalPresenter");
            $this->validator  = $validator;
        }
    

    或者修改仓库

    public function presenter()
        {
            return "Prettus\\Repository\\Presenter\\ModelFractalPresenter";
        }
    
    • 当然也可以跳过该自定义格式或者只在部分地方使用
    public function show($id)
        {
    //部分函数内跳过
            $this->repository->skipPresenter();
    //在部分函数内使用
            $this->repository->setPresenter("App\\Presenters\\ArticlePresenter");
            $article = $this->repository->find($id);
    
            if (request()->wantsJson()) {
    
                return response()->json([
                    'data' => $article,
                ]);
            }
    //        return $article->toJSON();
            return $article;
    //        return view('articles.show', compact('article'));
        }
    

    转载请注明出处,谢谢=.=

    相关文章

      网友评论

          本文标题:andersao/l5-repository实践记录

          本文链接:https://www.haomeiwen.com/subject/spekcxtx.html