What would you like to ride on a highway: a city bike or a Tesla car? To move fast, we have to feel safe.
Last month I had made a head jump to Laravel ecosystem. The migration went very well, as most of the code is intuitive. There was just one clear bottle-neck: the array configs.
Sometimes, I remove config that was not needed. But sometimes, a crucial line is missing, and Laravel throws an error about missing service.
Let's take the config/view.php
as an example:
<?php
return [
/*
|--------------------------------------------------------------------------
| View Storage Paths
|--------------------------------------------------------------------------
|
| Most templating systems load templates from disk. Here you may specify
| an array of paths that should be checked for your views. Of course
| the usual Laravel view path has already been registered for you.
|
*/
'paths' => [
resource_path('views'),
],
/*
|--------------------------------------------------------------------------
| Compiled View Path
|--------------------------------------------------------------------------
|
| This option determines where all the compiled Blade templates will be
| stored for your application. Typically, this is within the storage
| directory. However, as usual, you are free to change this value.
|
*/
'compiled' => env(
'VIEW_COMPILED_PATH',
realpath(storage_path('framework/views'))
),
];
There are too many comments to read the code between the lines.
It's unclear what is a parameter name and what is a user-defined value. Both of them look like strings.
The env()
hides the type of the value. Is it a string? Is it an array or a boolean? We have to open the file and read the comment to know.
What other options can we use in this config?
The rest of the framework is quite polished for developer experience, so these arrays stand out.
string[]
, but/**
* @param array<class-string<\Illuminate\Support\ServiceProvider>> $providers
*/
I had a clear idea for a fluent config builder that would be generated based on /config
directory
from Laravel skeleton. I asked on Twitter to avoid the wheel invention: "has someone built this?"
I got a tip for the must-read What about config builders? post by Brent Roose.
Wow, that's it! Where can I download it?
But when I reached Brent, I got a reply: "it's just an idea, no package".
Yet I was thrilled that an established Laravel developer has a similar opinion. It's time to build it!
composer require tomasvotruba/punchcard
/config
directoryThe following code provides the same configuration as above. I've been using it on this very website for over a week.
// config/view.php
use TomasVotruba\PunchCard\ViewConfig;
return ViewConfig::make()
->paths([__DIR__ . '/../resources/views'])
->compiled(__DIR__ . '/../storage/framework/views)
->toArray();
The ViewConfig
is a very simple class but very powerful thanks to all the type declarations:
<?php
namespace TomasVotruba\PunchCard;
class ViewConfig
{
/**
* @var string[]
*/
private array $paths = [];
private ?string $compiled = null;
public static function make(): self
{
return new self();
}
/*
|--------------------------------------------------------------------------
| View Storage Paths
|--------------------------------------------------------------------------
|
| Most templating systems load templates from disk. Here you may specify
| an array of paths that should be checked for your views. Of course
| the usual Laravel view path has already been registered for you.
|
*/
/**
* @param string[] $paths
*/
public function paths(array $paths): self
{
$this->paths = $paths;
return $this;
}
/*
|--------------------------------------------------------------------------
| Compiled View Path
|--------------------------------------------------------------------------
|
| This option determines where all the compiled Blade templates will be
| stored for your application. Typically, this is within the storage
| directory. However, as usual, you are free to change this value.
|
*/
public function compiled(string $compiled): self
{
$this->compiled = $compiled;
return $this;
}
/**
* @return array<string, mixed[]>
*/
public function toArray(): array
{
return [
'paths' => $this->paths,
'compiled' => $this->compiled,
];
}
}
The configs are generated on package release, so they're always up-to-date with Laravel and available to your autoload and IDE. No magic or fake @methods
, just pure PHP.
This is my first Laravel package, so I want your feedback: How can I improve it? More practical with less code? More strict when it comes to nested objects?
The repository is here: TomasVotruba/punchcard
Thank you, and happy coding!
Do you learn from my contents or use open-souce packages like Rector every day?
Consider supporting it on GitHub Sponsors.
I'd really appreciate it!