How to reuse models in Laravel
伊谢尔伦
伊谢尔伦 2017-05-16 16:53:44
0
5
708

Our company is now usingLaravelto develop projects, and also added theBizlayer and theRepositorieslayer to implement business logic encapsulation, butThere is no code in model.
When writing code inController, the problem that bothers me is how to reuseBizobjects,Repositoriesobjects andModelObject.
When I usedYiito develop projects before, there was a factory mode, so when callingModel, basically nonewwas used, all bytes were usedXXX::model()To call, it is enough for an object to be new once, which can effectively save memory.
Controller code:

$productModel = Product::model()->getList('xxxxxxxxx');

How simple, is there any?

In

Laravel,Modelseems to have no factory. To call it, an instance is required. IfRepositoriesencapsulates 5 methods, each one is used.Model, then I called these 5 methods inController, andModelwas new 5 times.
Currently I see a way on the Internet, which is to inject the Model object into the constructor ofRepositoriesand put it in the private member variable of Repositories, so that all five methods call the private variable of the current class. That's it. But it is troublesome to use. When writing code in Controller, you need to write like this:

$xxxBiz = new XXXBiz(\xxx\xxx\Repositories);

You need to write this in Repositories:

$xxxRepositories = new XXXRepositories(\xxx\xx\xxxModel);

When creating a newBiz, theRepositoriesobject must also be passed in, and the namespace is still long. I basically spell strings, and the writing code is very efficient. Low, I still need to open this file to spell out the name.

I would like to ask how you solve the problem of reuse of logical layer classes such as Model when developing projects with Laravel?

伊谢尔伦
伊谢尔伦

小伙看你根骨奇佳,潜力无限,来学PHP伐。

reply all (5)
漂亮男人

0x0 Preface

Interesting question, Yii is also recognized in the industry as a framework with higher performance than Laravel. So I wanted to look at the specific implementation of the two major frameworks just from the structure of ActiveRecord.

0x1 Eloquent framework for Laravel

It’s easy to use relational queries in Laravel:

$user = User::find(1);

I didn’t find the find method in the User class, WTF, what happened! ?

The base class of User is Model, which uses static calling, so the __callStatic magic method of Model will be called:

public static function __callStatic($method, $parameters) { // $method = 'find'; // $parameters = [1]; // 实例化当前类,即 User 模块 $instance = new static; // 调用当前实例的 find 方法 return call_user_func_array([$instance, $method], $parameters); }

In fact, it is to call the __call magic method again:

public function __call($method, $parameters) { //... $query = $this->newQuery(); return call_user_func_array([$query, $method], $parameters); }

Tracing back to the source, we found that the find method actually comes from IlluminateDatabaseEloquentBuilder, and this class internally uses the implementation of IlluminateDatabaseQueryBuilder.

Wait a minute, what’s the difference betweenIlluminateDatabaseEloquentBuilderandIlluminateDatabaseQueryBuilder?

In fact, EloquentBuilder is a further encapsulation of QueryBuilder to better implement relational object query.

So, the actual process is:

In other words, every time youstatically callthe Model method, the Model will be instantiated and the process will be completed.

0x2 CActiveRecord in Yii 1.1

Since the questioner uses the model method, it should be version 1.1. The module inherits from CActiveRecord (in Yii2, it inherits from YiidbActiveRecord).

Okay, guys, now use Yii to implement relational query, first define:

class User extends CActiveRecord { public static function model($className=__CLASS__) { return parent::model($className); } }

Enquiry:

$user = User::model()->findAllByPk(1);

Obviously the query object comes from model, let’s see how the parent class implements this function:

public static function model($className=__CLASS__) { // 如果已经实例化了则直接返回该实例 if(isset(self::$_models[$className])) return self::$_models[$className]; else { // 初始化,并将保存当前实例 $model=self::$_models[$className]=new $className(null); $model->attachBehaviors($model->behaviors()); return $model; } }

findAllByPk method is directly encapsulated inside CActiveRecord:

public function findByPk($pk,$condition='',$params=array()) { // ... $criteria = $this->getCommandBuilder()->createPkCriteria($this->getTableSchema(), $pk, $condition, $params, $prefix); return $this->query($criteria); }

So the process is:

0x3 Dependency injection using Laravel

Under normal circumstances (parameterless constructor or injected parameters have been configured), Laravel will automatically instantiate it for you:

user = $user; } }

So you can reuse the same object easily:

class Repository { protected $user; public __construct(User $user) { $this->user = $user; } public function first() { $this->user->first(); } public function find(Request $request, $id) { if (Gate::denies('view', $request->user())) { abort(403); } return $this->user->find($id); } public function excited() { return $this->user->where('name', 'bigNews')->get(); } }

After implementing the warehouse, do you need to instantiate it manually:

$repo = new App\Repositories\Repository(new App\User());

No, this is not in line with Laravel's philosophy, you can do it as simple as:

first(); }

Yes, that’s right, you don’t need to manually construct, pass in the User instance, etc., everything is just a simple automatic injection. And the questioner noticed that a namespace is used here, so you only need to use it once. (Of course, if you don’t want to spell such a long namespace, then it’s time for you to change to an IDE. You can use Alt + Enter to quickly import in PhpStorm

0x4 Finally

For the issue of static and non-static overhead, there is a discussion on StackOverflow: http://stackoverflow.com/questions/14727...

So in the final analysis, it still depends on business needs 23333

    阿神

    Through dependency injection
    It can be injected directly into the Controller
    You can read this article
    http://slides.com/howtomakeaturn/model#/

      小葫芦

      I assume you don’t know much about Laravel yet.

      First, Laravel’s Model is also a model, which does not require explicit instantiation. The calling method is as follows (extracted from official documentation):

      $flights = App\Flight::where('active', 1) ->orderBy('name', 'desc') ->take(10) ->get();

      Second, your description is wrong. What you are looking for is not the factory pattern, but the singleton pattern. The object only needs to be instantiated once during the life cycle of a request. In Laravel, you need to use an IOC (inversion of control) container or service container. Like this:

      // 先绑定需要实例化的对象或者服务 $this->app->singleton('FooBar', function ($app) { return new FooBar($app['SomethingElse']); }); // 调用对象或服务有多种方式,比如以下两种: // 第一种 $fooBar = $this->app->make('FooBar'); // 显式解析 $fooBar = $this->app['FooBar']; // 像访问数组一样调用之前被显式解析(实例化)过的对象或服务 // 第二种 // 通过类型声明(type hinting)来自动解析,无需显式解析(实例化),直接调用,请参考最后附上的文档 // 除了单例模式外,当然还支持工厂模式,即每次调用,返回一个新的实例,像下面这样: $this->app->bind('HelpSpot\API', function ($app) { return new HelpSpot\API($app['HttpClient']); });

      The above is just a simple excerpt. For specific usage, please refer to Laravel’s official excellent documentation. The link is as follows:
      Service Container (IOC container/service container)

        洪涛

        Our company inherits a BaseRepository, which is defined in BaseRepository

        protected function getUserCouponModel($new = false) { if (is_null($this->userCouponModel) || true === $new) { $this->userCouponModel = new UserCouponModel(); } return $this->userCouponModel; }

        CouponRepository

        public function create($couponID) { $attributes = [ 'couponID' => $couponID, ]; return $this->getUserCouponModel(true)->create($attributes); }

        Similar in Biz, inherit a BaseBiz, and then write the method like this

        public function create($fields) { return $this->getCouponRepository()->create($fields); }
        Called in

        Controller

        $biz = new Biz(); $biz->create($fields);

        Controller ---> Biz ---> Repository

          淡淡烟草味

          This is what I did, create this function in the underlying model
          Modify bootstrap/app.php and AppServiceProvider.php
          For details, please refer to Service Provider

          static public function load(){ return app()->make(get_called_class()); }

          Just call Foo::load() in the controller

            Latest Downloads
            More>
            Web Effects
            Website Source Code
            Website Materials
            Front End Template
            About us Disclaimer Sitemap
            php.cn:Public welfare online PHP training,Help PHP learners grow quickly!