【问题标题】:Laravel - where to store common model functions & how to access them from controllers?Laravel - 在哪里存储常用模型函数以及如何从控制器访问它们?
【发布时间】:2017-05-30 21:16:25
【问题描述】:

我的许多模型大部分都使用了一些函数
因此集中存储它们而不是重复代码是有意义的。

例如,我有一个函数可以从我需要的任何表中找到随机行:

function getRandomRow() {
    $rowCount = DB::connection('mydatabasename')
                ->table('my_table_name')
                ->selectRaw("FLOOR(RAND() * COUNT(*)) AS offset")
                ->first();

    $offset = $rowCount->offset;

    $randomRow = DB::connection('mydatabasename')
                    ->table('my_table_name')
                    ->select()
                    ->offset($offset)
                    ->limit(1)
                    ->first();

    return $randomRow;
}

我查看了inheritance(扩展)和traits - 以及docs on polymorphic relations - 但不清楚哪个最有效以及如何访问表名(与正在使用的模型相关联) 在通用函数中。

我的问题:
- 我应该把这个功能放在哪里,以便所有型号都可以使用它?
- 如何编写代码以使'my_table_name' 使用正确的模型表?

【问题讨论】:

  • 您找到解决方案了吗?我在下面发布了我的解决方案

标签: php laravel model-view-controller model extends


【解决方案1】:

我找到的最简单的解决方案是创建一个父模型/类 - 正如 this answer 中提到的另一个问题 - 对于当前示例,我们称之为 BaseModel

对于 Laravel,它与其他模型一起存储,直接在 App 目录中

...在我的情况下,父模型/类可以是abstract,因为它不需要拥有自己的表(也意味着只能通过子模型访问BaseModel 函数):

namespace App;

use Illuminate\Database\Eloquent\Model;

abstract class BaseModel extends Model
{
    // ...put common model functions here
}

实现此功能的技巧(BaseModel 函数需要访问子模型的表)是:
- 让每个子模型/班级extend BaseModel 班级
- 确保在所有子模型中定义了 $table - 如 here 所述:

class MyFunkyModel extends BaseModel
{
    protected $table = 'funktown';

    // ...put child specific functions here

}

表示$this->table可以在BaseModel抽象父类中引用子模型/类的指定$table

namespace App;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB;

abstract class BaseModel extends Model
{
    function getRandomRow() {
        $rowCount = DB::connection('mydatabasename')
                        ->table($this->table)
                        ->selectRaw("FLOOR(RAND() * COUNT(*)) AS offset")
                        ->first();

        $offset = $rowCount->offset;

        $profileRow = DB::connection('mydatabasename')
                        ->table($this->table)
                        ->select()
                        ->offset($offset)
                        ->limit(1)
                        ->first();

        return $profileRow;
    }
}

现在,您可以从控制器访问存储在 BaseModel 中的任何功能,只需通过子模型:

namespace App\Http\Controllers;

use App\MyFunkyModel;
use App\MySeriousModel;
use App\MyHappyModel;

class MyController extends Controller
{
    public function getRandomName($type){
        switch ($type) {
            case 'funky':
                $modelFunky = new MyFunkyModel;
                $funkyRow = $modelFunky->getRandomRow();
                $randomName = $funkyRow->funky_name_column;
                break;
            case 'serious':
                $modelSerious = new MySeriousModel;
                $seriousRow = $modelSerious->getRandomRow();
                $randomName = $seriousRow->serious_name_column;
                break;
            case 'happy':
                $modelHappy = new MyHappyModel;
                $happyRow = $modelHappy->getRandomRow();
                $randomName = $happyRow->happy_name_column;
                break;
        return $randomName;
    }
}

【讨论】:

    【解决方案2】:

    您可以同时使用inheritancetrait。但强烈建议使用Eloquent 模型而不是DB::table()。原因是如果表名以某种方式更改,您必须在任何地方更改它。使用Eloquent,您只需在模型中提及一次表名。

    protected $table = 'new_table_name'
    

    使用继承

    BaseModelclass 构造如下。

    class BaseModel extends Model {
        public static function getRandomRow()
        {
            $rowCount = self::selectRaw("FLOOR(RAND() * COUNT(*)) AS offset")
                ->first();
    
            $offset = $rowCount->offset;
    
            $randomRow = self::select()
                ->offset($offset)
                ->limit(1)
                ->first();
    
            return $randomRow;
        }
    }
    
    class YourModel extends BaseModel {
        // getRandomRow() available here
    }
    

    使用特征

    按如下方式构建您的 traitclass

    trait BaseTrait {
        public static function getRandomRow()
        {
            $rowCount = self::selectRaw("FLOOR(RAND() * COUNT(*)) AS offset")
                ->first();
    
            $offset = $rowCount->offset;
    
            $randomRow = self::select()
                ->offset($offset)
                ->limit(1)
                ->first();
    
            return $randomRow;
        }
    }
    
    class YourClass {
        use BaseTrait;
        // getRandomRow() available here
    }
    

    无论哪种方式,您都可以访问您的方法,例如

    class yourController {
        public function youMethod()
        {
            $rows = YourModel::getRandomRow();
        }
    }
    

    【讨论】:

    • 感谢您的回复。是否有任何理由使用静态函数 - 虽然 Traits 和 Helpers 显然是必要的 - 具有继承类型 BaseModel ?虽然这在技术上是可行的,但它会创建在某些方面不一致的代码 - 模型中的一半函数将由 MyModel->modelFunction() 调用,一半由 MyModel::modelFunction() 调用 - 这是编码中的另一个加速(记住哪些函数在 MyModel , 并且在BaseModel)。
    • 也感谢关于 Eloquent vs Query Builder 的建议——我们发现 Eloquent 对复杂查询的限制太大——所以我们只使用 Query Builder。此外,您可以在 QB 中使用 $this->table 以避免重复表名 - 这使得它与 Eloquent 相同。我们的表名称很少更改,而且现在大多数 IDE 都具有相当出色的查找/替换功能 - 所以我不确定这是否会破坏交易。
    猜你喜欢
    • 1970-01-01
    • 2017-12-12
    • 2014-04-25
    • 2023-03-14
    • 2013-08-09
    • 1970-01-01
    • 2014-12-24
    • 1970-01-01
    • 2013-02-04
    相关资源
    最近更新 更多