# Using static factory methods with Laravel models

One limitation of the PHP language is the inability to create multiple [constructors](https://en.wikipedia.org/wiki/Constructor_(object-oriented_programming)). In Java, for example, you can create different constructors as long as they have unique [method signatures](https://en.wikipedia.org/wiki/Type_signature#Method_signature). This allows the programmer to create distinct ways to create the same object depending on the situation. Because the PHP language lacks this feature, we solve this problem using different [software design patterns](https://en.wikipedia.org/wiki/Software_design_pattern). Most of the time, we just create a [factory](https://en.wikipedia.org/wiki/Factory_(object-oriented_programming)). The factory then deals with these different use-cases for creating an object. One lesser known type of factory pattern is the [static factory method pattern](https://books.google.com/books?id=ka2VUBqHiWkC&pg=PA5#v=onepage&q&f=false). This pattern allows us to address the multiple constructor problem. But it allows us to do so without needing to create a factory class which we might not need otherwise. Now, I've written about [how to use the static factory method pattern with WordPress](https://carlalexander.ca/static-factory-method-pattern-wordpress/) before. But, as I've used [Laravel](https://en.wikipedia.org/wiki/Laravel) more with client projects and building [Ymir](https://ymirapp.com), I feel it's worth revisiting it in that context as well. Specifically, I think it's worth looking at how you can use it with [Eloquent](https://laravel.com/docs/master/eloquent) models.

# Static factory methods are already in Eloquent

Eloquent has several ways of initializing new model objects. It has a constructor which you can use. But there are also the `Model::create` and `Model::make` methods that map to Eloquent `Builder` class. (There are also more use case specific methods such as `Model::firstOrCreate` or `Model::firstOrNew`.) These methods are static factory methods themselves. The issue is that they're very generic. They all take `attributes` as their parameter. That's because these methods will [mass assign](https://laravel.com/docs/master/eloquent#mass-assignment) these attributes to the model when you create it. (Well, that's unless the model has the attributes guarded.) If you don't want to use mass assignment, you need to assign each attribute one at a time. # An excellent starting point

The great thing about these methods being generic is that we can use them as a starting point for our own methods. What we'll do is create our own methods, which will then call either the `create` or `make` static methods. Let's look at an example. ```
namespace App;
 
use Illuminate\Database\Eloquent\Model;

class BlogPost extends Model
{
    /**
     * Make a new BlogPost object from the given User object and save it to the database.
     */
    public static function createFromUser(User $author, string $title): self
    {
        return self::create([
            'user_id' => $author->id,
            'title' => $title,
        ]);
    }

    // ...
}
```

Above is a model called `BlogPost`. The class has a static factory method called `createFromUser`. The method has two parameters: `author` and `title` which we [type hinted](https://www.php.net/manual/en/functions.arguments.php#functions.arguments.type-declaration). The ability to have type hints is another reason why creating custom static factory methods can be beneficial. It allows you to have increased [type safety](https://en.wikipedia.org/wiki/Type_safety). This is something that I always value when writing code. The rest of the static factory method just calls the generic `Model::create` method. We pass it an array with the attributes we want it to assign to the new `BlogPost` object. The array contains the ID of the user who authored the post and the title. ## What about the make method?

For a lot of Laravel developers, the `createFromUser` method will be enough. But I tend to prefer to use the `make` method and delay saving the model until I'm done modifying it. So what I'd need is a `makeFromUser` static factory method. Having both a `createFromUser` and `makeFromUser` method is actually quite easy to do. We can just do the same thing that Laravel does with `create` and `make`. If you look at the `create` and `make` methods in the `Builder` class, they look like this: ```
namespace Illuminate\Database\Eloquent;

class Builder
{
    // ...

    public function create(array $attributes = [])
    {
        return tap($this->newModelInstance($attributes), function ($instance) {
            $instance->save();
        });
    }

    // ...

    public function make(array $attributes = [])
    {
        return $this->newModelInstance($attributes);
    }

    // ...
}
```

Basically, the only difference between both methods is the use of the [`tap`](https://laravel.com/docs/master/helpers#method-tap) helper function to save the model we made. That's it. So we can just do the same thing when building our `createFromUser` and `makeFromUser` methods. ```
namespace App;
 
use Illuminate\Database\Eloquent\Model;

class BlogPost extends Model
{
    /**
     * Make a new BlogPost object from the given User object and save it to the database.
     */
    public static function createFromUser(User $author, string $title): self
    {
        return tap(self::makeFromUser($author, $title))->save()
    }

    /**
     * Make a new BlogPost object from the given User object.
     */
    public static function makeFromUser(User $author, string $title): self
    {
        return self::make([
            'user_id' => $author->id,
            'title' => $title,
        ]);
    }

    // ...
}
```

Normally, the `save` method returns a boolean value. So we'd have to break everything into multiple lines of code. By using `tap` helper function, we can use the `save` method, but still return the new `BlogPost` post object. # Another example: Form Requests

Static factory methods are great with other Eloquent models. But they also synergize well with other Laravel features. One of those is [form requests](https://laravel.com/docs/7.x/validation#form-request-validation). Form requests are a cool feature that let you create custom `Request` classes. These custom `Request` classes are convenient for storing all your validation code. But you can also use them to offer helper methods for interacting with an HTTP request. ```
<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class CreateBlogPostRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     */
    public function authorize(): bool
    {
        return true;
    }

    /**
     * Determine if the user is authorized to make this request.
     */
    public function getTitle(): string
    {
        return $this->get('title');
    }

    /**
     * Get the validation rules that apply to the request.
     */
    public function rules(): array
    {
        return [
            'title' => 'required|string',
        ];
    }
}
```

So above is the `CreateBlogPostRequest` class which we can use to create our `BlogPost` objects. It has three methods: `authorize`, `getTitle` and `rules`. The `authorize` method determines if the current user can process the request. We just return `true` which means any user can process this request. Meanwhile, the `getTitle` method just returns the `title` value from the request. This is why the `rules` method, which returns the validation rules to use with the request, has validation rules for `title`. We need to make sure it's always present and that it's a string. ## Creating the static factory method for the form request

Now, we can just update our `BlogPost` class. We'll add a static factory method that takes a `CreateBlogPostRequest` object as an argument. You can see the modified class below. ```
namespace App;
 
use App\Http\Requests\CreateBlogPostRequest;
use Illuminate\Database\Eloquent\Model;

class BlogPost extends Model
{
    /**
     * Make a new BlogPost object from the given form request object and save it to the database.
     */
    public static function createFromRequest(CreateBlogPostRequest $request): self
    {
        return tap(self::makeFromRequest($request))->save()
    }

    /**
     * Make a new BlogPost object from the given form request object.
     */
    public static function makeFromRequest(CreateBlogPostRequest $request): self
    {
        return self::makeFromUser($request->user(), $request->getTitle());
    }

    // ...
}
```

We added two new static factory methods: `makeFromRequest` and `createFromRequest`. These two methods behave the same as our previous two static factory methods. The create method calls the make method and saves the model using the `tap` function. The interesting thing is what we do in the `makeFromRequest` method. We use the returned values from the `CreateBlogPostRequest` methods and pass them to the `makeFromUser` method. This lets us leverage our code from the other static factory method while offering an alternative way to create a `BlogPost` object. # When should you use a traditional factory?

As you can see, static factory methods are often more than sufficient for your model creation needs. That said, there are cases where I've had to use a traditional factory class combined with static factory methods. A common one is if your model has a [one-to-many relationship](https://en.wikipedia.org/wiki/One-to-many_(data_model)) and you need to create both the parent and child models at the same time. ```
namespace App;
 
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;

class Database extends Model
{
    // ...

    public function users(): HasMany
    {
        return $this->hasMany(DatabaseUser::class, 'database_id');
    }

    // ...
}
```

To demonstrate this, let's take the `Database` model shown above. It has a one-to-many relationship with the `DatabaseUser` model. When creating a `Database` object, you'll want to at least add one `DatabaseUser` for the admin user. Now, you could create a static factory method in the `Database` class that also creates the `DatabaseUser` object. But I feel like it defeats the purpose of the static factory method which is to be a custom constructor. This is really a situation where you'd want a factory class like this one. ```
namespace App\Factories;
 
use App\Database;
use App\DatabaseUser;

class DatabaseFactory
{
    public function create(string $name, string $username, string $password): Database
    {
        $database = Database::create([
            'name' => $name,
        ]);

        $database->users()->create([
            'username' => $username,
            'password' => $password,
        ]);

        return $database;
    }
}
```

So the `DatabaseFactory` class above has a single method called `create`. You pass it three arguments: `name`, `username` and `password`. We then use these three arguments to create our `Database` and `DatabaseUser` objects in the database. The method starts by creating the `Database` object. We then call the `users` method which returns the `HasMany` relationship object. We then call its [`create`](https://laravel.com/docs/master/eloquent-relationships#the-create-method) method which will create the `DatabaseUser` and associate it with the `Database` object. We finish by returning the created `Database` object. And like that, our `create` method created two objects in the database at once. This would have made less sense as a static factory method in the `Database` class. ## Combining with static factory methods

That said, this doesn't mean that you can't use static factory methods with a factory class. Both factory patterns serve different purposes, so there's nothing wrong with using them both at the same time. ```
namespace App\Factories;
 
use App\Database;
use App\DatabaseUser;

class DatabaseFactory
{
    public function create(string $name, string $username, string $password): Database
    {
        $database = Database::createFromName($name);

        DatabaseUser::createFromDatabase($database, $username, $password);

        return $database;
    }
}
```

Here's the `DatabaseFactory` class updated to use static factory methods. We create the `Database` object using the `createFromName` method. We then pass it to the `createFromDatabase` static factory method to create the `DatabaseUser` object. # Bringing a bit more structure to your Eloquent models

So that wraps up our look at static factory methods. Like all software patterns, you don't want to use them for every problem you encounter. But, with Eloquent, they've been an invaluable tool to bring some structure to creating model objects.