Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP Type Hinting Implementation of Abstract Method - Repository Pattern

Question

Is it possible to get row code completion inside PhpStorm using a model/repository pattern?

My Setup

I am using Laravel and implementing the repository pattern as described in a Laracasts video.

The Code

Here is a basic example of how models work inside Laravel and how it seems impossible to get code completion for model attributes.

This code works and prints out 'billy' as it should, however the attribute $name is not type hinted and will not be code-completed inside PhpStorm. The type hinting is prioritizing the parent attribute definition type rather than the child, which seems strange to me.

<?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;

An Ugly Fix

The only to actually get code completion seems to be to re-define the child function with a new php doc block:

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);
    }
}

However I have hundreds of models, repositories, and repository functions. It would be a massive job to re-write all the functions inside each implementation.

Is there a way to get PhpStorm to use the child's type hinting declaration rather than the parents without having to re-declare the method?

like image 675
magnito Avatar asked Nov 08 '22 21:11

magnito


1 Answers

I was unable to find a solution to get proper type hinting with model and repositories in the context I posted this question originally.


Compromised Solution

After further studying of repository and mvc php patterns I came to the conclusion to use more specific and detailed repository functions.


The Wrong Way

For example, I was using repository base functions inside my controllers/logic classes like this:

$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
            }
        );

The Right Way

Now I code separate database logic functions for all my needs inside the specific repositories, so my core classes/controllers end up looking like this:

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

This way all the database logic is moved to the specific repository and I can type hint it's returned models. This methodology also results in cleaner easier to read code and further separates your core logic from Eloquent.

like image 103
magnito Avatar answered Nov 14 '22 21:11

magnito