We use cookies on this site to enhance your user experience
By clicking the Accept button, you agree to us doing so. More info on our cookie policy
We use cookies on this site to enhance your user experience
By clicking the Accept button, you agree to us doing so. More info on our cookie policy
Published: Jul 4, 2023 by C.S. Rhymes
Sometimes it’s difficult to decide where to put code, trying to figure out where it really belongs. Laravel has a predefined folder structure that you can keep to for most scenarios, but I wasn’t sure whether the settings should be kept in a config file, a class, or somewhere else. In the end I decided to use an enum.
I had been reading an article about enums on stitcher.io and thought this would be a good way of limiting the available options that users could select as their social network in their profile page, but also a good way of storing more related information.
I created a simple enum to store the options, but made it a backed enum so it had a string value which I could store in the database.
<?php
namespace App\Enums;
enum SocialNetwork: string
{
case FACEBOOK = 'facebook';
case TWITTER = 'twitter';
case YOUTUBE = 'youtube';
}
Laravel also has a useful feature that lets you cast the value as an enum in the relevant model.
<?php
namespace App\Models;
use App\Enums\SocialNetwork;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class SocialProfile extends Model
{
use HasFactory;
protected $casts = [
'social_network' => SocialNetwork::class,
];
}
This means you can interact with the enum instance instead of just the string value out of the database and have access to the enums methods too. We will come back to this a bit later.
Next I wanted to check that the option selected was a valid enum option. Again, Laravel makes this super easy using the Enum validation rule. This checks that the value of the social_network
in the request is a valid value of the enum.
use App\Enums\SocialNetwork;
use Illuminate\Validation\Rules\Enum;
$request->validate([
'social_network' => [new Enum(SocialNetwork::class)],
]);
As well as just defining options, enums also allow additional methods. You can even use the enum within the method too.
I wanted a way of storing the valid domains for each of the enum options, so I created a match statement that used the enum value and returned an array of valid domains.
<?php
namespace App\Enums;
enum SocialNetwork: string
{
case FACEBOOK = 'facebook';
case TWITTER = 'twitter';
case YOUTUBE = 'youtube';
public function domains(): array
{
return match ($this) {
SocialNetwork::FACEBOOK => [
'facebook.com',
'fb.me',
'fb.com',
],
SocialNetwork::TWITTER => [
'twitter.com',
't.co',
],
SocialNetwork::YOUTUBE => [
'youtube.com',
'youtu.be',
],
};
}
}
Another useful thing about this is if I needed to add a new social network in future I have only one place to add the definition and the domains. I can easily add Instagram as an option in the enum and everywhere I use the enum the code should be updated.
I wanted to ensure that the url someone entered into a form was a domain from one of my predefined social networks. Rather than writing a list of domains again in this rule, we can use the SocialNetwork::cases()
method to list out the valid cases. We can then use array_map()
to pull out all of the valid domains for each case.
The domains are a nested array, so I made use of the flatten collection method to create a single level array.
Finally we can check if the url (the value passed into the rule) matches one of the allowed domains. If it doesn’t then it triggers the validation failure.
<?php
namespace App\Rules;
use App\Enums\SocialNetwork;
use Closure;
use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Support\Str;
class SocialNetworkRule implements ValidationRule
{
/**
* Get the allowed domains from the SocialNetwork enum
* and ensure at least one matches the value.
*
* @param \Closure(string): \Illuminate\Translation\PotentiallyTranslatedString $fail
*/
public function validate(string $attribute, mixed $value, Closure $fail): void
{
$allowedDomains = array_map(
fn (SocialNetwork $socialNetwork) => $socialNetwork->domains(),
SocialNetwork::cases()
);
$domains = collect($allowedDomains)
->flatten()
->all();
if (! Str::contains($value, $domains)) {
$fail('The :attribute field must be a valid social network.');
}
}
}
In another place in my Laravel app I wanted to get the social network from a link. This method loops through the cases and checks if the link is within the array of domains. If it is, then return the value of the enum. If it doesn’t match then it returns null.
use Illuminate\Support\Str;
public function getNetwork(string $link): string|null
{
foreach (SocialNetwork::cases() as $case) {
if (Str::contains($link, $case->domains())) {
return $case->value;
}
}
return null;
}
I hope this has given you some inspiration for how you could use enums in future Laravel projects.
Photo by Tricia Gray on StockSnap
Share
Latest Posts
There has been a lot of discussion on Threads recently about becoming a writer, but don’t give up your day job. I have seen a lot of arguments from all sides, some people saying they became a successful full time writer, others saying they would never give up their job, then there are others who became writers full time then went back to another job. Writing has always been a hobby for me, but this discussion has made me think more about why I write.
Version 1.1.0 of Bulma clean theme has been released. It has a small update that allows you to easily add social media links to the footer of your site.
A small village with a big mystery!