PHP类型提示抽象方法的实现 - 存储库模式

时间:2016-01-14 23:31:56

标签: php laravel phpstorm repository-pattern type-hinting

问题

是否可以使用模型/存储库模式在PhpStorm中获取行代码?

我的设置

我正在使用Laravel并实现Laracasts视频中描述的存储库模式。

守则

以下是模型在Laravel中如何工作的基本示例,以及如何无法获得模型属性的代码完成。

此代码适用于打印' billy'因为它应该,但属性$ name不是类型提示,不会在PhpStorm内完成代码。类型提示是优先考虑父属性定义类型而不是子元素,这对我来说似乎很奇怪。

<?php

// Models
abstract class Model {
    public $sqlTableName;

    public function findFromDatabase($id)
    {
        $model = new $this;

        // This would be grabbed using table name and $id
        $fakeDatabaseRow = ['name' => 'billy', 'job' => 'engineer'];

        foreach ($fakeDatabaseRow as $column => $value) {
            $model->$column = $value;
        }

        return $model;
    }
}

class User extends Model {
    public $name;
    public $job;

    public $sqlTableName = 'users';
}

// Repositories
abstract class RepositoryBase {
    /**
     * @var Model
     */
    public $model;

    public function find($id)
    {
        $this->model = $this->model->findFromDatabase(1);

        return $this->model;
    }
}

class UserRepository extends RepositoryBase {
    /**
     * @var User
     */
    public $model;

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

// Run
$model = new User();

$userRepository = new UserRepository($model);

echo $userRepository->find(1)->name;

丑陋的修复

实际获得代码完成的唯一方法似乎是使用新的php doc块重新定义子函数:

class UserRepository extends RepositoryBase {
    /**
     * @var User
     */
    public $model;

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

    // I need to replace this function for every different repository
    // even though they are all the same
    /**
     * @param $id
     * @return User
     */
    public function find($id)
    {
        return parent::find($id);
    }
}

但是,我有数百个模型,存储库和存储库功能。重写每个实现中的所有函数将是一项巨大的工作。

有没有办法让PhpStorm使用孩子的类型提示声明而不是父母而不必重新声明方法?

2 个答案:

答案 0 :(得分:2)

我无法找到解决方案,在我最初发布此问题的上下文中使用模型和存储库进行正确的类型提示。

妥协解决方案

在进一步研究了存储库和mvc php模式后,我得出结论,使用更具体和详细的​​存储库函数。

错误的方式

例如,我在我的控制器/逻辑类中使用存储库基本函数,如下所示:

$users =
    $userRepository->where('created_at', '<', '2016-01-18 19:21:20')->where(
            'permission_level',
            'admin'
        )->orderBy('created_at')->get('id');

$posts =
    $postRepository->where('posted_on', '<', '2016-01-18 19:21:20')
        ->where('content', '!=', 'null')
        ->chunk(
            function ($posts) {
                // do things
            }
        );

正确的方式

现在我为特定存储库中的所有代码编写单独的数据库逻辑函数,因此我的核心类/控制器最终看起来像这样:

$users = $userRepository->getAdminIdsCreatedBeforeDate('2016-01-18 19:21:20');
$posts = $postRepository->chunkFilledPostsBeforeDate('2016-01-18 19:21:20', function() {});

这样,所有数据库逻辑都被移动到特定的存储库,我可以输入提示它返回的模型。这种方法也使代码更容易阅读,并进一步将您的核心逻辑与Eloquent分开。

答案 1 :(得分:0)

您可以使用abstract关键字来卸载方法的实现。

abstract class Model {
    abstract public function find($id);
}

强制任何扩展Model的对象实现该功能。

我希望这是有道理的。