Skip to content

Use view models instead of database model in your blade files and JSON responses.

License

Notifications You must be signed in to change notification settings

engageinteractive/laravel-view-models

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

23 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Laravel View Models

Build Status Total Downloads Latest Stable Version License

A straight forward pattern for using mappers/view models instead of database model in your blade files and JSON responses.

Installation

composer require engageinteractive/laravel-view-models

Mappers

Create a mapper that can build view models for your Eloquent model:

namespace App\Domain\Posts;

use EngageInteractive\LaravelViewModels\Mapper;

use App\Domain\Posts\Post;

class PostShowMapper extends Mapper
{
    /**
     * Map a Post to a basic PHP array.
     *
     * @param \App\Domain\Posts\Post
     * @return array
     */
    public function map(Post $post)
    {
        return $post->only('title', 'author_name');
    }
}

Ask for an instance of the Mapper in your controller via the container:

namespace App\Domain\Posts;

use App\Domain\Posts\Post;
use App\Domain\Posts\PostMapper;
use App\Http\Controllers\Controller;

class PostController extends Controller
{
    /**
     * Show a Post.
     *
     * @param \App\Domain\Posts\Post
     * @param \App\Domain\Posts\PostMapper
     * @return \Illuminate\Views\View
     */
    public function show(Post $post, PostShowMapper $model)
    {
        return view('post.show', [
            'model' => $mapper->one($post),
        ]),
    }
}

View models

Create a view model, to build data to pass into your view:

namespace App\Domain\Posts;

use EngageInteractive\LaravelViewModels\ViewModel;
use Illuminate\Support\Str;

class PostViewModel extends ViewModel
{
    protected $post;

    /**
     * Intialise the View ViewModel.
     *
     * @param \App\Domain\Posts\Post
     * @return void
     */
    public function __construct(Post $post): void
    {
        $this->post = $post;
    }
    
    /**
     * Returns the post title in title-case.
     *
     * @return string
     */
    public function postTitle(): string
    {
        if (!isset($this->post->title)) {
            return 'Untitled';
        }

        return Str::title($this->post->title);
    }
}

Pass the ViewModel array into the view:

namespace App\Domain\Posts;

use App\Domain\Posts\Post;
use App\Domain\Posts\PostViewModel;
use App\Http\Controllers\Controller;

class PostController extends Controller
{
    /**
     * Show a Post.
     *
     * @param \App\Domain\Posts\Post
     * @return \Illuminate\Views\View
     */
    public function show(Post $post)
    {
        $model = new PostViewModel($post);

        return view('post.show', $model->array()),
    }
}

Below is an example of the data passed into the view:

[
    'model' => [
        'post_title' => 'This Is The Title',
    ],
]

Combining View models and Mappers

First, create a mapper for posts.

namespace App\Domain\Posts;

use EngageInteractive\LaravelViewModels\Mapper;

use App\Domain\Posts\Post;

class PostsMapper extends Mapper
{
    /**
     * Map a Post to a basic PHP array.
     *
     * @param \App\Domain\Posts\Post
     * @return array
     */
    public function map(Post $post)
    {
        return $post->only('title', 'author_name');
    }
}

Create a ViewModel, and call the mapper.

namespace App\Domain\Posts;

use EngageInteractive\LaravelViewModels\ViewModel;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Str;

class PostArchiveViewModel extends ViewModel
{
    protected $posts;

    /**
     * Initialise the View model.
     *
     * @param \Illuminate\Database\Eloquent\Collection
     * @return void
     */
    public function __construct(Collection $posts): void
    {
        $this->posts = $posts;
    }
    
    /**
     * Returns an array of posts.
     *
     * @return string
     */
    public function posts(): array
    {
        return (new PostsMapper)->all($this->posts);
    }

    /**
     * Returns the application home URI.
     *
     * @return string
     */
    public function HomeUri(): string
    {
        return route('home');
    }
}

Pass the view model into the view, with the posts mapped into the required format.

namespace App\Domain\Posts;

use App\Domain\Posts\Post;
use App\Domain\Posts\PostArchiveViewModel;
use App\Http\Controllers\Controller;

class PostArchiveController extends Controller
{
    /**
     * Show a Post.
     *
     * @return \Illuminate\Views\View
     */
    public function show()
    {
        $posts = Post::all();
        $model = new PostArchiveViewModel($posts);

        return view('post-archive.show', $model->array()),
    }
}

Laravel Compatibility

Works on Laravel 5.5+.

License

Laravel View Models is open-sourced software licensed under the MIT license.

About

Use view models instead of database model in your blade files and JSON responses.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 3

  •  
  •  
  •  

Languages