Adding View models to a Laravel project

Since the beggining of 2017 I started to experiment with different kind of codes and patterns I didn't used before.

One of that changes came in November when I was developing the code of this other blog. I saw that I was duplicating a lot of code inside my controllers on the methods for create and edit a resource, in which I use the same blade file.

Some data of that view depends on the model I'm editing or creating. For example, if it's an existing record the title should be Edit post: {$post->title} instead of Create a post. That logic applies to the form action and form method too.

I created a main FormViewModel, and every view model dedicated to a form extends it.

abstract class FormViewModel
{

    public $model;
    public $title;
    public $action;
    public $method;

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

        $this->setTitle();

        $this->setAction();

        $this->setMethod();
    }
}

This view models are forced to declare the methods called on the constructor

protected abstract function setTitle();

protected abstract function setAction();

protected abstract function setMethod();

This is an implementation of the setTitle method in the CategoryDetailViewModel:

protected function setTitle()
{
    $this->title = $this->model->exists
        ? "Edit Category: {$this->model->name}"
        : "Create Category";
}

They can also add more logic in their own constructor, like the PostDetailViewModel:

public function __construct(Post $post)
{
    parent::__construct($post);

    $this->published_at = $this->model->exists
        ? $this->model->published_at->format('Y-m-d\TH:i')
        : Carbon::now()->format('Y-m-d\TH:i');

    $this->categories = Category::select('id', 'name')->get();
}

Using the view models is very easy, the controller only needs to pass this object to the view

public function edit(Theme $theme)
{
    return view('backend.themes.edit', [
        'view' => new ThemeDetailViewModel($theme)
    ]);
}

and the view use the object properties and methods

@section('content')
    <h1>{{ $view->title }}</h1>
    
    <form method="POST" action="{{ $view->action }}">
        {{ method_field($view->method) }}
        {{ csrf_field() }}
        ...
    </form>
@endsection

Found a typo? Edit this post.
Special thanks to Dieter for the amazing code of this blog.

Got any hints?
No, I'm afraid not.
However if you search within yourself, then...
Cut it out, ok?
I asked for a hint not the crazy philosophies of a Father Christmas look-a-like.
Heed my words, bold adventurer, and your path will lead to wisdom and..
There's just no reasoning with him...
I'm totally stuck as what to do.
I really wish I could help you but I'm just a clueless old fool.
Never a truer word was spoken.
Still clueless?
I'm afraid so.
Still look like a Father Christmas?
I'm afraid so.
Good.
Calypso from Fleur de Lys Simon The Sorcerer