• Stars
    star
    1,100
  • Rank 40,499 (Top 0.9 %)
  • Language
    PHP
  • License
    MIT License
  • Created almost 4 years ago
  • Updated 24 days ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Store strongly typed application settings

Store strongly typed application settings

Latest Version on Packagist Tests PHPStan Style Total Downloads

This package allows you to store settings in a repository (database, Redis, ...) and use them through an application without hassle. You can create a settings class as such:

class GeneralSettings extends Settings
{
    public string $site_name;
    
    public bool $site_active;
    
    public static function group(): string
    {
        return 'general';
    }
}

If you want to use these settings somewhere in your application, you can inject them, since we register them in the Laravel Container. For example, in a controller:

class GeneralSettingsController
{
    public function show(GeneralSettings $settings){
        return view('settings.show', [
            'site_name' => $settings->site_name,
            'site_active' => $settings->site_active    
        ]);
    }
}

You can update the settings as such:

class GeneralSettingsController
{
    public function update(
        GeneralSettingsRequest $request,
        GeneralSettings $settings
    ){
        $settings->site_name = $request->input('site_name');
        $settings->site_active = $request->input('site_active');
        
        $settings->save();
        
        return redirect()->back();
    }
}

Let's take a look at how to create your own settings classes.

Support us

Image

We invest a lot of resources into creating best in class open source packages. You can support us by buying one of our paid products.

We highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using. You'll find our address on our contact page. We publish all received postcards on our virtual postcard wall.

Installation

You can install the package via composer:

composer require spatie/laravel-settings

You can publish and run the migrations with:

php artisan vendor:publish --provider="Spatie\LaravelSettings\LaravelSettingsServiceProvider" --tag="migrations"
php artisan migrate

You can publish the config file with:

php artisan vendor:publish --provider="Spatie\LaravelSettings\LaravelSettingsServiceProvider" --tag="settings"

This is the contents of the published config file:

return [

    /*
     * Each settings class used in your application must be registered, you can
     * add them (manually) here.
     */
    'settings' => [

    ],

    /*
     * The path where the settings classes will be created.
     */
    'setting_class_path' => app_path('Settings'),

    /*
     * In these directories settings migrations will be stored and ran when migrating. A settings 
     * migration created via the make:settings-migration command will be stored in the first path or
     * a custom defined path when running the command.
     */
    'migrations_paths' => [
        database_path('settings'),
    ]

    /*
     * When no repository is set for a settings class, the following repository
     * will be used for loading and saving settings.
     */
    'default_repository' => 'database',

    /*
     * Settings will be stored and loaded from these repositories.
     */
    'repositories' => [
        'database' => [
            'type' => Spatie\LaravelSettings\SettingsRepositories\DatabaseSettingsRepository::class,
            'model' => null,
            'table' => null,
            'connection' => null,
        ],
        'redis' => [
            'type' => Spatie\LaravelSettings\SettingsRepositories\RedisSettingsRepository::class,
            'connection' => null,
            'prefix' => null,
        ],
    ],

    /*
     * The contents of settings classes can be cached through your application,
     * settings will be stored within a provided Laravel store and can have an
     * additional prefix.
     */
    'cache' => [
        'enabled' => env('SETTINGS_CACHE_ENABLED', false),
        'store' => null,
        'prefix' => null,
    ],

    /*
     * These global casts will be automatically used whenever a property within
     * your settings class isn't the default PHP type.
     */
    'global_casts' => [
        DateTimeInterface::class => Spatie\LaravelSettings\SettingsCasts\DateTimeInterfaceCast::class,
        DateTimeZone::class => Spatie\LaravelSettings\SettingsCasts\DateTimeZoneCast::class,
     // Spatie\DataTransferObject\DataTransferObject::class => Spatie\LaravelSettings\SettingsCasts\DtoCast::class,
        Spatie\LaravelData\Data::class => Spatie\LaravelSettings\SettingsCasts\DataCast::class,
    ],

    /*
     * The package will look for settings in these paths and automatically
     * register them.
     */
    'auto_discover_settings' => [
        app_path('Settings'),
    ],

    /*
     * Automatically discovered settings classes can be cached, so they don't
     * need to be searched each time the application boots up.
     */
    'discovered_settings_cache_path' => base_path('bootstrap/cache'),
];

Usage

The package is built around settings classes, which are classes with public properties that extend from Settings. They also have a static method group that should return a string.

You can create multiple groups of settings, each with their settings class. You could, for example, have GeneralSettings with the general group and BlogSettings with the blog group. It's up to you how to structure these groups.

Although it is possible to use the same group for different settings classes, we advise you not to use the same group for multiple settings classes.

use Spatie\LaravelSettings\Settings;

class GeneralSettings extends Settings
{
    public string $site_name;
    
    public bool $site_active;
    
    public static function group(): string
    {
        return 'general';
    }
}

You can generate a new settings class using this artisan command. Before you do, please check if the setting_class_path is correctly set. You can also specify a path option, which is optional.

    php artisan make:setting SettingName --group=groupName 

Now, you will have to add this settings class to the settings.php config file in the settings array, so it can be loaded by Laravel:

    /*
     * Each settings class used in your application must be registered, you can
     * add them (manually) here.
     */
    'settings' => [
        GeneralSettings::class
    ],

Each property in a settings class needs a default value that should be set in its migration. You can create a migration as such:

php artisan make:settings-migration CreateGeneralSettings

This command will create a new file in database/settings where you can add the properties and their default values:

use Spatie\LaravelSettings\Migrations\SettingsMigration;

class CreateGeneralSettings extends SettingsMigration
{
    public function up(): void
    {
        $this->migrator->add('general.site_name', 'Spatie');
        $this->migrator->add('general.site_active', true);
    }
}

We add the properties site_name and site_active here to the general group with values Spatie and true. More on migrations later.

You should migrate your database to add the properties:

php artisan migrate

Now, when you want to use the site_name property of the GeneralSettings settings class, you can inject it into your application:

class IndexController
{
    public function __invoke(GeneralSettings $settings){
        return view('index', [
            'site_name' => $settings->site_name,
        ]);
    }
}

Or use it to load it somewhere in your application as such:

function getName(): string{
    return app(GeneralSettings::class)->site_name;
}

Updating the settings can be done as such:

class SettingsController
{
    public function __invoke(GeneralSettings $settings, GeneralSettingsRequest $request){
        $settings->site_name = $request->input('site_name');
        $settings->site_active = $request->boolean('site_active');
        
        $settings->save();
        
        return redirect()->back();
    }
}

Selecting a repository

Settings will be stored and loaded from the repository. There are two types of repositories database and redis. And it is possible to create multiple repositories for these types. For example, you could have two database repositories, one that goes to a settings table in your database and another that goes to a global_settings table.

You can explicitly set the repository of a settings class by implementing the repository method:

class GeneralSettings extends Settings
{
    public string $site_name;
    
    public bool $site_active;
    
    public static function group(): string
    {
        return 'general';
    }
    
    public static function repository(): ?string
    {
        return 'global_settings';
    }
}

When a repository is not set for a settings class, the default_repository in the settings.php config file will be used.

Creating settings migrations

Before you can load/update settings, you will have to migrate them. Though this might sound a bit strange at the beginning, it is quite logical. You want to have some default settings to start with when you're creating a new application. And what would happen if we change a property of a settings class? Our code would change, but our data doesn't.

That's why the package requires migrations each time you're changing/creating your settings classes' structure. These migrations will run next to the regular Laravel database migrations, and we've added some tooling to write them as quickly as possible.

Creating a settings migration works just like you would create a regular database migration. You can run the following command:

php artisan make:settings-migration CreateGeneralSettings

This will add a migration to the application/database/settings directory:

use Spatie\LaravelSettings\Migrations\SettingsMigration;

class CreateGeneralSettings extends SettingsMigration
{
    public function up(): void
    {

    }
}

We haven't added a down method, but this can be added if desired. In the up method, you can change the settings data in the repository when migrating. There are a few default operations supported:

Adding a property

You can add a property to a settings group as such:

public function up(): void
{
    $this->migrator->add('general.timezone', 'Europe/Brussels');
}

We've added a timezone property to the general group, which is being used by GeneralSettings. You should always give a default value for a newly created setting. In this case, this is the Europe/Brussels timezone.

If the property in the settings class is nullable, it's possible to give null as a default value.

Renaming a property

It is possible to rename a property:

public function up(): void
{
    $this->migrator->rename('general.timezone', 'general.local_timezone');
}

You can also move a property to another group:

public function up(): void
{
    $this->migrator->rename('general.timezone', 'country.timezone');
}

Updating a property

It is possible to update the contents of a property:

public function up(): void
{
    $this->migrator->update(
        'general.timezone', 
        fn(string $timezone) => return 'America/New_York'
    );
}

As you can see, this method takes a closure as an argument, which makes it possible to update a value based upon its old value.

Deleting a property

public function up(): void
{
    $this->migrator->delete('general.timezone');
}

Operations in group

When you're working on a big settings class with many properties, it can be a bit cumbersome always to have to prepend the settings group. That's why you can also perform operations within a settings group:

public function up(): void
{
    $this->migrator->inGroup('general', function (SettingsBlueprint $blueprint): void {
        $blueprint->add('timezone', 'Europe/Brussels');
        
        $blueprint->rename('timezone', 'local_timezone');
        
        $blueprint->update('timezone', fn(string $timezone) => return 'America/New_York');
        
        $blueprint->delete('timezone');
    });
}

Typing properties

It is possible to create a settings class with regular PHP types:

class RegularTypeSettings extends Settings
{
    public string $a_string;
    
    public bool $a_bool;
    
    public int $an_int;
    
    public float $a_float;
    
    public array $an_array;
    
    public static function group(): string
    {
        return 'regular_type';
    }
}

Internally the package will convert these types to JSON and save them as such in the repository. But what about types like DateTime and Carbon or your own created types? Although these types can be converted to JSON, building them back up again from JSON isn't supported.

That's why you can specify casts within this package. There are two ways to define these casts: locally or globally.

Local casts

Local casts work on one specific settings class and should be defined for each property:

class DateSettings extends Settings
{
    public DateTime $birth_date;
    
    public static function group(): string
    {
        return 'date';
    }
    
    public static function casts(): array
    {
        return [
            'birth_date' => DateTimeInterfaceCast::class
        ];
    }
}

The DateTimeInterfaceCast can be used for properties with types like DateTime, DateTimeImmutable, Carbon and CarbonImmutable. You can also use an already constructed cast. It becomes handy when you need to pass some extra arguments to the cast:

class DateSettings extends Settings
{
    public $birth_date;
    
    public static function group(): string
    {
        return 'date';
    }
    
    public static function casts(): array
    {
        return [
            'birth_date' => new DateTimeInterfaceWithTimeZoneCast(DateTime::class, 'Europe/Brussels')
        ];
    }
}

As you can see, we provide DateTime::class to the cast, so it knows what type of DateTime it should use because the birth_date property was not typed, and the cast couldn't infer the type to use.

You can also provide arguments to a cast without constructing it:

class DateSettings extends Settings
{
    public $birth_date;
    
    public static function group(): string
    {
        return 'date';
    }
    
    public static function casts(): array
    {
        return [
            'birth_date' => DateTimeInterfaceCast::class.':'.DateTime::class
        ];
    }
}

Global casts

Local casts are great for defining types for specific properties of the settings class. But it's a lot of work to define a local cast for each regularly used type like a DateTime. Global casts try to simplify this process.

You can define global casts in the global_casts array of the package configuration. We've added some default casts to the configuration that can be handy:

'global_casts' => [
    DateTimeInterface::class => Spatie\LaravelSettings\SettingsCasts\DateTimeInterfaceCast::class,
    DateTimeZone::class => Spatie\LaravelSettings\SettingsCasts\DateTimeZoneCast::class,
 // Spatie\DataTransferObject\DataTransferObject::class => Spatie\LaravelSettings\SettingsCasts\DtoCast::class,
    Spatie\LaravelData\Data::class => Spatie\LaravelSettings\SettingsCasts\DataCast::class,
],

A global cast can work on:

  • a specific type (DateTimeZone::class)
  • a type that implements an interface (DateTimeInterface::class)
  • a type that extends from another class (Data::class)

In your settings class, when you use a DateTime property (which implements DateTimeInterface), you no longer have to define local casts:

class DateSettings extends Settings
{
    public DateTime $birth_date;
    
    public static function group(): string
    {
        return 'date';
    }
}

The package will automatically find the cast and will use it to transform the types between the settings class and repository.

Typing properties

There are quite a few options to type properties. You could type them in PHP:

class DateSettings extends Settings
{
    public DateTime $birth_date;
    
    public ?int $a_nullable_int;
    
    public static function group(): string
    {
        return 'date';
    }
}

Or you can use docblocks:

class DateSettings extends Settings
{
    /** @var \DateTime  */
    public $birth_date;
    
    /** @var ?int  */
    public $a_nullable_int;
    
    /** @var int|null  */
    public $another_nullable_int;
    
    /** @var int[]|null  */
    public $an_array_of_ints_or_null;
    
    public static function group(): string
    {
        return 'date';
    }
}

Docblocks can be very useful to type arrays of objects:

class DateSettings extends Settings
{
    /** @var array<\DateTime>  */
    public array $birth_dates;
    
    // OR

    /** @var \DateTime[]  */
    public array $birth_dates_alternative;

    public static function group(): string
    {
        return 'date';
    }
}

Locking properties

When you want to disable the ability to update the value of a setting, you can add a lock to it:

$dateSettings->lock('birth_date');

It is now impossible to update the value of birth_date. When trying to overwrite birth_date and saving settings, the package will load the old value of birth_date from the repository, and it looks like nothing happened.

You can also lock multiple settings at once:

$dateSettings->lock('birth_date', 'name', 'email');

You can get all the locked settings:

$dateSettings->getLockedProperties(); // ['birth_date']

Unlocking settings can be done as such:

$dateSettings->unlock('birth_date', 'name', 'email');

Checking if a setting is currently locked can be done as such:

$dateSettings->isLocked('birth_date');

Checking if a setting is currently unlocked can be done as such:

$dateSettings->isUnlocked('birth_date');

Encrypting properties

Some properties in your settings class can be confidential, like API keys, for example. It is possible to encrypt some of your properties, so it won't be possible to read them when your repository data was compromised.

Adding encryption to the properties of your settings class can be done as such. By adding the encrypted static method to your settings class and list all the properties that should be encrypted:

class GeneralSettings extends Settings
{
    public string $site_name;
    
    public bool $site_active;
    
    public static function group(): string
    {
        return 'general';
    }
    
    public static function encrypted(): array
    {
        return [
            'site_name'
        ];
    }
}

Using encryption in migrations

Creating and updating encrypted properties in migrations works a bit differently than non-encrypted properties.

Instead of calling the add method to create a new property, you should use the addEncrypted method:

public function up(): void
{
    $this->migrator->addEncrypted('general.site_name', 'Spatie');
}

The same goes for the update method, which should be replaced by updateEncrypted:

public function up(): void
{
    $this->migrator->updateEncrypted(
        'general.site_name', 
        fn(string $siteName) => return 'Space'
    );
}

You can make a non-encrypted property encrypted in a migration:

public function up(): void
{
    $this->migrator->add('general.site_name', 'Spatie');

    $this->migrator->encrypt('general.site_name');
}

Or make an encrypted property non-encrypted:

public function up(): void
{
    $this->migrator->addEncrypted('general.site_name', 'Spatie');

    $this->migrator->decrypt('general.site_name');
}

Of course, you can use these methods when using inGroup migration operations.

Faking settings classes

In tests, it is sometimes desired that some settings classes can be quickly used with values different from the default ones you've written in your migrations. That's why you can fake settings. Faked settings classes will be registered in the container. And you can overwrite some or all the properties in the settings class:

DateSettings::fake([
    'birth_date' => new DateTime('16-05-1994')
]);

Now, when the DateSettings settings class is injected somewhere in your application, the birth_date property will be DateTime('16-05-1994').

If all properties are overwritten, no calls to repositories will be made. If only some properties are overwritten, the package will first add the overwritten properties and then load the missing settings from the repository. It is possible to explicitly throw an MissingSettings exception when a property is not overwritten in a fake method call like this:

DateSettings::fake([
    'birth_date' => new DateTime('16-05-1994')
], false);

Caching settings

It takes a small amount of time to load a settings class from a repository. When you've got many settings classes, these added small amounts of time can grow quickly out of hand. The package has built-in support for caching stored settings using the Laravel cache.

You should first enable the cache within the settings.php config file:

'cache' => [
    'enabled' => env('SETTINGS_CACHE_ENABLED', false),
    'store' => null,
    'prefix' => null,
],

We suggest you enable caching in production by adding SETTINGS_CACHE_ENABLED=true to your .env file. It is also possible to define a store for the cache, which should be one of the stores you defined in the cache.php config file. If no store were defined, the default cache store would be taken. To avoid conflicts within the cache, you can also define a prefix that will be added to each cache entry.

That's it. The package is now smart enough to cache the settings the first time they're loaded. Whenever the settings are edited, the package will refresh the settings.

You can always clear the cached settings with the following command:

php artisan settings:clear-cache

Auto discovering settings classes

Each settings class you create should be added to the settings array within the settings.php config file. When you've got a lot of settings, this can be quickly forgotten.

That's why it is also possible to auto-discover settings classes. The package will look through your application and tries to discover settings classes. You can specify the paths where will be searched in the config auto_discover_settings array. By default, this is the application's app path.

Autodiscovering settings require some extra time before your application is booted up. That's why it is possible to cache them using the following command:

php artisan settings:discover

You can clear this cache by running:

php artisan settings:clear-discovered

Writing your own casters

A caster is a class implementing the SettingsCast interface:

interface SettingsCast
{
    /**
     * Will be used to when retrieving a value from the repository, and
     * inserting it into the settings class.
     */
    public function get($payload);

    /**
     * Will be used to when retrieving a value from the settings class, and
     * inserting it into the repository.
     */
    public function set($payload);
}

A created caster can be used for local and global casts, but there are slight differences between them. The package will always try to inject the type of property it is casting. This type is a class string and will be provided as a first argument when constructing the caster. When it cannot deduce the type, null will be used as the first argument.

An example of such caster with a type injected is a simplified DtoCast:

class DtoCast implements SettingsCast
{
    private string $type;

    public function __construct(?string $type)
    {
        $this->type = $type;
    }

    public function get($payload): Data
    {
        return $this->type::from($payload);
    }

    public function set($payload): array
    {
        return $payload->toArray();
    }
}

The above is a caster for the spatie/laravel-data package, within its constructor, the type will be a specific Data class, for example, SongData::class. In the get method, the caster will construct a Data::class with the repository properties. The caster receives a Data::class as payload in the set method and converts it to an array for safe storing in the repository.

Local casts

When using a local cast, there are a few different possibilities to deduce the type:

// By the type of property

class CastSettings extends Settings 
{
    public DateTime $birth_date;
    
    public static function casts(): array
    {
        return [
            'birth_date' => DateTimeInterfaceCast::class
        ];
    }
    
    ...
}
// By the docblock of a property

class CastSettings extends Settings
{
    /** @var \DateTime  */
    public $birth_date;
    
    public static function casts(): array
    {
        return [
            'birth_date' => DateTimeInterfaceCast::class
        ];
    }
    
    ...
}
// By explicit definition

class CastSettings extends Settings
{
    public $birth_date;
    
    public static function casts(): array
    {
        return [
            'birth_date' => DateTimeInterfaceCast::class.':'.DateTime::class
        ];
    }
    
    ...
}

In that last case: by explicit definition, it is possible to provide extra arguments that will be passed to the constructor:

class CastSettings extends Settings
{
    public $birth_date;
    
    public static function casts(): array
    {
        return [
            'birth_date' => DateTimeWthTimeZoneInterfaceCast::class.':'.DateTime::class.',Europe/Brussels'
        ];
    }
    
    ...
}

Although in this case, it might be more readable to construct the caster within the settings class:

class CastSettings extends Settings
{
    public $birth_date;
    
    public static function casts(): array
    {
        return [
            'birth_date' => new DateTimeWthTimeZoneInterfaceCast(DateTime::class, 'Europe/Brussels')
        ];
    }
    
    ...
}

Global casts

When using global casts, the package will again try to deduce the type of property it's casting. In this case, it can only use the property type or infer the type of the property's docblock.

A global cast should be configured in the settings.php config file and always has a specific (set) of type(s) it works on. These types can be a particular class, a group of classes implementing an interface, or a group of classes extending from another class.

A good example here is the DateTimeInterfaceCast we've added by default in the config. It is defined in the config as such:

    ...

    'global_casts' => [
        DateTimeInterface::class => Spatie\LaravelSettings\SettingsCasts\DateTimeInterfaceCast::class,
    ],
    
    ...

Whenever the package detects a Carbon, CarbonImmutable, DateTime, or DateTimeImmutable type as the type of one of a settings class's properties. It will use the DateTimeInterfaceCast as a caster. This because Carbon, CarbonImmutable, DateTime and DateTimeImmutable all implement DateTimeInterface. The key that was used in settings.php to represent the cast.

The type injected in the caster will be the type of the property. So let's say you have a property with the type DateTime within your settings class. When casting this property, the DateTimeInterfaceCast will receive DateTime:class as a type.

Repositories

There are two types of repositories included in the package, the redis and database repository. You can create multiple repositories for one type in the setting.php config file. And each repository can be configured.

Database repository

The database repository has two optional configuration options:

  • model the Eloquent model used to load/save properties to the database
  • table the table used in the database
  • connection the connection to use when interacting with the database

Redis repository

The Redis repository also has two optional configuration options:

  • prefix an optional prefix that will be prepended to the keys
  • connection the connection to use when interacting with Redis

Caching

It is possible to add a custom caching configuration per repository, by adding a cache configuration like the default one to your repository config within the settings.php config file:

    'repositories' => [
        'landlord' => [
            'type' => Spatie\LaravelSettings\SettingsRepositories\DatabaseSettingsRepository::class,
            'model' => null,
            'table' => null,
            'connection' => 'landlord',
            'cache' => [
                'enabled' => env('SETTINGS_CACHE_ENABLED', false),
                'store' => null,
                'prefix' => 'landlord',
                'ttl' => null,
            ],
        ],
        
        ...
    ],

Creating your own repository type

It is possible to create your own types of repositories. A repository is a class which implements SettingsRepository:

interface SettingsRepository
{
    /**
     * Get all the properties in the repository for a single group
     */
    public function getPropertiesInGroup(string $group): array;

    /**
     * Check if a property exists in a group
     */
    public function checkIfPropertyExists(string $group, string $name): bool;

    /**
     * Get the payload of a property
     */
    public function getPropertyPayload(string $group, string $name);

    /**
     * Create a property within a group with a payload
     */
    public function createProperty(string $group, string $name, $payload): void;

    /**
     * Update the payloads of properties within a group.
     */
    public function updatePropertiesPayload(string $group, array $properties): void;

    /**
     * Delete a property from a group
     */
    public function deleteProperty(string $group, string $name): void;

    /**
     * Lock a set of properties for a specific group
     */
    public function lockProperties(string $group, array $properties): void;

    /**
     * Unlock a set of properties for a group
     */
    public function unlockProperties(string $group, array $properties): void;

    /**
     * Get all the locked properties within a group
     */
    public function getLockedProperties(string $group): array;
}

All these functions should be implemented to interact with the type of storage you're using. The payload parameters are raw values(int, bool, float, string, array). Within the database, and redis repository types, These raw values are converted to JSON. But this is not required.

It is required to return raw values again in the getPropertiesInGroup and getPropertyPayload methods.

Each repository's constructor will receive a $config array that the user-defined for the repository within the application settings.php config file. It is possible to add other dependencies to the constructor. They will be injected when the repository is created.

Refreshing settings

You can refresh the values and locked properties within the settings class. This can be useful if you change something within your repository and want to see it reflected within your settings:

$settings->refresh();

You should only refresh settings when the repository values were changed when the settings class was already loaded.

Events

The package will emit a series of events when loading/saving settings classes:

  • LoadingSettings whenever settings are loaded from the repository but not yet inserted in the settings class
  • SettingsLoaded after settings are loaded into the settings class
  • SavingSettings whenever settings are saved to the repository but are not yet cast or encrypted
  • SettingsSaved after settings are stored within the repository

Testing

composer test

Changelog

Please see CHANGELOG for more information on what has changed recently.

Contributing

Please see CONTRIBUTING for details.

Security

If you've found a bug regarding security please mail [email protected] instead of using the issue tracker.

Credits

License

The MIT License (MIT). Please see License File for more information.

More Repositories

1

laravel-permission

Associate users with roles and permissions
PHP
11,600
star
2

laravel-medialibrary

Associate files with Eloquent models
PHP
5,427
star
3

laravel-backup

A package to backup your Laravel app
PHP
5,337
star
4

laravel-activitylog

Log activity inside your Laravel app
PHP
5,128
star
5

browsershot

Convert HTML to an image, PDF or string
PHP
4,434
star
6

laravel-query-builder

Easily build Eloquent queries from API requests
PHP
3,675
star
7

laravel-analytics

A Laravel package to retrieve pageviews and other data from Google Analytics
PHP
2,948
star
8

image-optimizer

Easily optimize images using PHP
PHP
2,450
star
9

async

Easily run code asynchronously
PHP
2,401
star
10

crawler

An easy to use, powerful crawler implemented in PHP. Can execute Javascript.
PHP
2,400
star
11

laravel-responsecache

Speed up a Laravel app by caching the entire response
PHP
2,248
star
12

data-transfer-object

Data transfer objects with batteries included
PHP
2,220
star
13

laravel-translatable

Making Eloquent models translatable
PHP
2,030
star
14

laravel-sitemap

Create and generate sitemaps with ease
PHP
2,011
star
15

dashboard.spatie.be

The source code of dashboard.spatie.be
PHP
1,940
star
16

laravel-fractal

An easy to use Fractal wrapper built for Laravel and Lumen applications
PHP
1,845
star
17

package-skeleton-laravel

A skeleton repository for Spatie's Laravel Packages
PHP
1,714
star
18

laravel-collection-macros

A set of useful Laravel collection macros
PHP
1,602
star
19

laravel-newsletter

Manage Mailcoach and MailChimp newsletters in Laravel
PHP
1,570
star
20

period

Complex period comparisons
PHP
1,515
star
21

checklist-going-live

The checklist that is used when a project is going live
1,489
star
22

laravel-tags

Add tags and taggable behaviour to your Laravel app
PHP
1,454
star
23

opening-hours

Query and format a set of opening hours
PHP
1,340
star
24

schema-org

A fluent builder Schema.org types and ld+json generator
PHP
1,284
star
25

eloquent-sortable

Sortable behaviour for Eloquent models
PHP
1,268
star
26

laravel-cookie-consent

Make your Laravel app comply with the crazy EU cookie law
PHP
1,268
star
27

laravel-sluggable

An opinionated package to create slugs for Eloquent models
PHP
1,236
star
28

laravel-searchable

Pragmatically search through models and other sources
PHP
1,217
star
29

pdf-to-image

Convert a pdf to an image
PHP
1,207
star
30

once

A magic memoization function
PHP
1,159
star
31

laravel-honeypot

Preventing spam submitted through forms
PHP
1,134
star
32

laravel-mail-preview

A mail driver to quickly preview mail
PHP
1,134
star
33

laravel-image-optimizer

Optimize images in your Laravel app
PHP
1,121
star
34

laravel-google-calendar

Manage events on a Google Calendar
PHP
1,119
star
35

regex

A sane interface for php's built in preg_* functions
PHP
1,097
star
36

laravel-data

Powerful data objects for Laravel
PHP
1,073
star
37

image

Manipulate images with an expressive API
PHP
1,064
star
38

array-to-xml

A simple class to convert an array to xml
PHP
1,056
star
39

laravel-multitenancy

Make your Laravel app usable by multiple tenants
PHP
1,020
star
40

laravel-uptime-monitor

A powerful and easy to configure uptime and ssl monitor
PHP
997
star
41

db-dumper

Dump the contents of a database
PHP
987
star
42

laravel-model-states

State support for models
PHP
968
star
43

laravel-view-models

View models in Laravel
PHP
963
star
44

simple-excel

Read and write simple Excel and CSV files
PHP
930
star
45

laravel-web-tinker

Tinker in your browser
JavaScript
925
star
46

laravel-webhook-client

Receive webhooks in Laravel apps
PHP
908
star
47

laravel-db-snapshots

Quickly dump and load databases
PHP
889
star
48

laravel-mix-purgecss

Zero-config Purgecss for Laravel Mix
JavaScript
887
star
49

laravel-schemaless-attributes

Add schemaless attributes to Eloquent models
PHP
880
star
50

blender

The Laravel template used for our CMS like projects
PHP
879
star
51

calendar-links

Generate add to calendar links for Google, iCal and other calendar systems
PHP
877
star
52

laravel-webhook-server

Send webhooks from Laravel apps
PHP
870
star
53

laravel-menu

Html menu generator for Laravel
PHP
854
star
54

phpunit-watcher

A tool to automatically rerun PHPUnit tests when source code changes
PHP
831
star
55

laravel-failed-job-monitor

Get notified when a queued job fails
PHP
826
star
56

laravel-model-status

Easily add statuses to your models
PHP
818
star
57

laravel-schedule-monitor

Monitor scheduled tasks in a Laravel app
PHP
800
star
58

form-backend-validation

An easy way to validate forms using back end logic
JavaScript
800
star
59

temporary-directory

A simple class to work with a temporary directory
PHP
796
star
60

laravel-feed

Easily generate RSS feeds
PHP
789
star
61

laravel-server-monitor

Don't let your servers just melt down
PHP
769
star
62

fork

A lightweight solution for running code concurrently in PHP
PHP
751
star
63

enum

Strongly typed enums in PHP supporting autocompletion and refactoring
PHP
737
star
64

laravel-tail

An artisan command to tail your application logs
PHP
726
star
65

valuestore

Easily store some values
PHP
722
star
66

laravel-package-tools

Tools for creating Laravel packages
PHP
722
star
67

laravel-event-sourcing

The easiest way to get started with event sourcing in Laravel
PHP
716
star
68

geocoder

Geocode addresses to coordinates
PHP
709
star
69

pdf-to-text

Extract text from a pdf
PHP
707
star
70

ssh

A lightweight package to execute commands over an SSH connection
PHP
696
star
71

menu

Html menu generator
PHP
688
star
72

laravel-url-signer

Create and validate signed URLs with a limited lifetime
PHP
685
star
73

ssl-certificate

A class to validate SSL certificates
PHP
675
star
74

laravel-route-attributes

Use PHP 8 attributes to register routes in a Laravel app
PHP
674
star
75

laravel-validation-rules

A set of useful Laravel validation rules
PHP
663
star
76

url

Parse, build and manipulate URL's
PHP
659
star
77

laravel-html

Painless html generation
PHP
654
star
78

laravel-health

Check the health of your Laravel app
PHP
648
star
79

laravel-event-projector

Event sourcing for Artisans πŸ“½
PHP
642
star
80

laravel-server-side-rendering

Server side rendering JavaScript in your Laravel application
PHP
636
star
81

vue-tabs-component

An easy way to display tabs with Vue
JavaScript
626
star
82

macroable

A trait to dynamically add methods to a class
PHP
621
star
83

laravel-csp

Set content security policy headers in a Laravel app
PHP
614
star
84

laravel-blade-javascript

A Blade directive to export variables to JavaScript
PHP
608
star
85

laravel-cors

Send CORS headers in a Laravel application
PHP
607
star
86

laravel-translation-loader

Store your translations in the database or other sources
PHP
602
star
87

vue-table-component

A straight to the point Vue component to display tables
JavaScript
591
star
88

activitylog

A very simple activity logger to monitor the users of your website or application
PHP
586
star
89

http-status-check

CLI tool to crawl a website and check HTTP status codes
PHP
584
star
90

phpunit-snapshot-assertions

A way to test without writing actual testΒ cases
PHP
584
star
91

laravel-queueable-action

Queueable actions in Laravel
PHP
584
star
92

laravel-short-schedule

Schedule artisan commands to run at a sub-minute frequency
PHP
579
star
93

laravel-onboard

A Laravel package to help track user onboarding steps
PHP
579
star
94

freek.dev

The sourcecode of freek.dev
PHP
571
star
95

server-side-rendering

Server side rendering JavaScript in a PHP application
PHP
568
star
96

laravel-pdf

Create PDF files in Laravel apps
PHP
563
star
97

string

String handling evolved
PHP
558
star
98

ray

Debug with Ray to fix problems faster
PHP
540
star
99

laravel-http-logger

Log HTTP requests in Laravel applications
PHP
538
star
100

laravel-blade-x

Use custom HTML components in your Blade views
PHP
533
star