Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to map Laravel/Eloquent results to custom class

I'm looking for a way to map the results of Laravel / Eloquent database queries to custom classes, rather than the default Eloquent class.

Does Laravel / Eloquent include any built-in facility for doing this? If not, is there a suitable place to 'hook' into the result generation code and do the necessary mapping?

As an example, this is roughly what I'd like to achieve:

class User extends Eloquent {}

class MyUser
{
    protected $name;

    public function getName() {
        return $this->name;
    }

    public function setName($name) {
        $this->name = $name;
        return $this;
    }
}

$users = User::all();

// $users should now contain an array of MyUser instances

Motivation / Reason for question

The motivation behind this question is to find a way in which queries can produce objects or arrays of objects that are completely framework-independent. This is because the Laravel app in question needs to be able to pass its results to other non-Laravel systems, so hence Plain Old PHP Objects (such as MyUser) make the most sense.

like image 417
coatesap Avatar asked Feb 03 '14 10:02

coatesap


1 Answers

Laravel will not give you something like that, but you can do with PHP. Inject your Eloquent User class into your custom class, Laravel will inject it for you automatically. Use the object inside your class as you wish and, if you need to call one or another Eloquent method, you can just provide fallbacks to the Eloquent User object.

A good option is to use the repository pattern, where your class will expect to receive an implementation of a repository interface, for that you have to:

Create the interface for your user repository, all repositories, including your Eloquent model, must implement this interface. This is a contract to let you switch the implementation of the repository whenever you want, without having to touch your class. It also will make your class framework agnostic.

interface UserRepositoryInterface {

}

Your implementations of this repository could be:

class EloquentUser extends Eloquent implements UserRepositoryInterface {

}

class DoctrineUser extends DoctrineWhatever implements UserRepositoryInterface {

}

Create your class

class User extends Eloquent {}

class MyUser
{
    protected $name;

    public function __construct(UserRepositoryInterface $user)
    {
        $this->userRepository = $user;
    }

    public function __call($name, $arguments)
    {
        return call_user_func_array(array($this->userRepository,$name), $arguments);
    }

    public static function __callStatic($name, $arguments)
    {
        return call_user_func_array(array('User',$name), $arguments);
    }

    public function getName() {
        return $this->userRepository->name;
    }

    public function setName($name) {
        $this->name = $name;
        return $this;
    }
}

Now in Laravel to select the implementation you just have to

App::bind('UserRepositoryInterface', 'EloquentUser');

To switch to doctrine, you just have to

App::bind('UserRepositoryInterface', 'DoctrineUser');

And if you need to use this class outside Laravel, you just have to instantiate it, passing whatever implementation of the repository you want:

$user = new MyUser(new DoctrineUser);

No more ties to Laravel.

like image 155
Antonio Carlos Ribeiro Avatar answered Oct 22 '22 17:10

Antonio Carlos Ribeiro