Looking to hire Laravel developers? Try LaraJobs

laravel-utilities maintained by chiiya

Description
Common utilities for laravel projects
Author
Last update
2026/05/29 17:02 (dev-master)
License
Downloads
9 660

Comments
comments powered by Disqus

Laravel Utilities

Latest Version on Packagist GitHub Code Style Action Status Total Downloads

Common classes and utilities for Laravel projects.

Installation

You can install the package via composer:

composer require chiiya/laravel-utilities

You can optionally publish the config file with:

php artisan vendor:publish --tag="utilities-config"

This is the contents of the published config file:

return [
    /*
    |--------------------------------------------------------------------------
    | Temporary path
    |--------------------------------------------------------------------------
    | Used for downloads and unzipping files.
    */
    'tmp_path' => storage_path('tmp'),
];

Usage

Simple extension of the Laravel Command that prints execution time after completion.

use Chiiya\Common\Commands\TimedCommand;  
  
class SendEmails extends TimedCommand
{
    protected $signature = 'mail:send {user}';
    
    public function handle(DripEmailer $drip)
    {
        $drip->send(User::find($this->argument('user')));
    }  
$ php artisan mail:send 1
> Execution time: 0.1s  

Trait to set the sender (return path) for mailables for e.g. bounce handling.

use Chiiya\Common\Mail\SetsSender;
  
class OrderShipped extends Mailables
{
    use SetsSender;

    public function build(): self
    {
        return $this
            ->subject('Order shipped')
            ->markdown('emails.orders.shipped')
            ->sender('return@example.com');
    }
}

View presenter similar to the no longer maintained laracasts/presenter package. Useful for doing some manipulations before displaying data.

use Chiiya\Common\Presenter\Presenter;

/** @extends Presenter<User> */  
class UserPresenter extends Presenter
{
    public function name(): string
    {
        return $this->first_name.' '.$this->last_name;
    }
}
use Chiiya\Common\Presenter\PresentableTrait;
  
class User extends Model
{
    /** @use PresentableTrait<UserPresenter> */
    use PresentableTrait;
    
    protected string $presenter = UserPresenter::class;
}
<h1>Hello, {{ $user->present()->name }}</h1>

Base repository for usage of the repository pattern. It provides get, find, index, search, count, create, update and delete methods for the configured $model. Most methods accept an optional $filters parameter, that may be used to apply the filters configured in the applyFilters method to your queries.

A general recommendation is to only use repositories as a place to store your complex queries and/or queries that are used repeatedly in multiple places, since otherwise they might be considered an anti-pattern. For more complex queries it can however be useful to separate them from your services. Repositories also serve as a way to self-document those queries by using descriptive method names. This way developers don't have to parse database queries and try to understand their purpose when going through your application logic.

use Chiiya\Common\Repositories\AbstractRepository;

/**
 * @extends AbstractRepository<Post>
 */
class PostRepository extends AbstractRepository
{
    protected string $model = Post::class;

    /**
     * @return Collection<Post>
     */
    public function postsDiscussedYesterday()
    {
        return $this->newQuery()
            ->whereHas('comments', function (Builder $builder) {
                $builder
                    ->where('created_at', '>=', now()->subDay()->startOfDay())
                    ->where('created_at', '<=', now()->subDay()->endOfDay());
            })
            ->get();
    }

    /**
     * @inheritDoc
     */
    protected function applyFilters(Builder $builder, array $parameters): Builder
    {
        if (isset($parameters['title'])) {
            $builder->where('title', '=', $parameters['title']);
        }

        return $builder;
    }
}
// Find by primary key
$post = $repository->get(10);
// Find (first) by filters
$post = $repository->find(['title' => 'Lorem ipsum']);
// List all entities, optionally filtered
$posts = $repository->index();
$posts = $repository->index(['title' => 'Lorem ipsum']);
// Count entities, optionally filtered
$count = $repository->count();
$count = $repository->count(['title' => 'Lorem ipsum']);
// Create new entity
$post = $repository->create(['title' => 'Some title']);
// Update entity
$repository->update($post, ['title' => 'Lorem ipsum']);
// Delete entity
$repository->delete($post);

// Custom methods
$posts = $repository->postsDiscussedYesterday();

Service class for efficiently generating large amounts of random, unique codes in memory for later processing.

use Chiiya\Common\Services\CodeService::class;
          
class CouponService {
    public function __construct(
        private CodeService $service,
    ) {}
          
    public function generateCodes()
    {
        // Optional, import previously exported codes so that we don't generate codes that already exist
        $this->service->import(storage_path('app/exports'));
        // Generate specified amount of random codes using the given pattern and character set
        $this->service->generate(
            1_000_000,
            '####-####-####',
            CodeService::SET_NUMBERS_AND_UPPERCASE,
        );
        // Get generated codes for further processing
        $codes = $this->service->getCodes();
        // ... e.g. bulk insert $codes into database
        // Export newly generated codes into (batched) CSV files. Optionally specify the amount of codes per file
        $this->service->export(storage_path('app/exports'));
        $this->service->export(path: storage_path('app/exports'), perFile: 500_000);
    }
}

Small wrapper around the openspout/openspout csv reader for high-performance reading of CSV files:

$reader = resolve(\Chiiya\Common\Services\CsvReader::class);
$reader->open('/path/to/file.csv');
foreach ($reader->rows() as $row) {
    $values = $row->toArray();
}
$reader->close();

Small wrapper around the openspout/openspout csv writer:

$writer = resolve(\Chiiya\Common\Services\CsvWriter::class);
$writer->open('/path/to/file.csv');
$writer->write(['Value 1', 'Value 2']);
$writer->close();

Small wrapper around the openspout/openspout excel reader for high-performance reading of XLS/XLSX files:

$reader = resolve(\Chiiya\Common\Services\ExcelReader::class);
$reader->open('/path/to/file.xlsx');
foreach ($reader->getSheetIterator() as $sheet) {
    foreach ($sheet->getRowIterator() as $row) {
        $values = $row->toArray();
    }
}
$reader->close();

Small wrapper around the openspout/openspout excel writer:

$writer = resolve(\Chiiya\Common\Services\ExcelWriter::class);
$writer->open('/path/to/file.xlsx');
$writer->setCurrentSheetName('Sheet 1');
$writer->addHeaderRow(['Name', 'Email']);
$writer->write(['John Doe', 'john.doe@example.com']);
$writer->addSheet('Sheet 2');
$writer->write(['Value 1', 'Value 2']);
$writer->close();

Utility class for downloading files from a remote URL.

$downloader = resolve(\Chiiya\Common\Services\FileDownloader::class);
$file = $downloader->download('https://example.com/path/to/file.txt');
dump($file->getPath());
$file->delete();

Utility class for zipping and unzipping .zip files.

// Unzipping
$zipper = resolve(\Chiiya\Common\Services\Zipper::class);
$location = $zipper->unzip('/path/to/file.zip');

// Zipping
$zipper->create('documents.zip')->addDirectory('/path/to/directory')->close();
$path = $zipper->getZipPath();

// Or with files
$zipper
    ->create('documents.zip')
    ->addFiles([
        '/path/to/file1',
        '/path/to/file2',
    ])
    ->close();
$path = $zipper->getZipPath();

Changelog

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

Contributing

Please see CONTRIBUTING for details.

License

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