appique / support
Useful utilities and helpers for Laravel applications
Requires
- php: ^8.3
- illuminate/contracts: ^11.0||^12.0
Requires (Dev)
- larastan/larastan: ^3.0
- laravel/pint: ^1.14
- nunomaduro/collision: ^8.1.1
- orchestra/testbench: ^10.0.0||^9.0.0
- pestphp/pest: ^3.0
- pestphp/pest-plugin-arch: ^3.0
- pestphp/pest-plugin-laravel: ^3.0
- phpstan/extension-installer: ^1.3
- phpstan/phpstan-deprecation-rules: ^2.0
- phpstan/phpstan-phpunit: ^2.0
- spatie/laravel-ray: ^1.35
README
Introduction
A collection of utilities, helpers, and extensions for Laravel applications.
Requirements
- PHP 8.3 or higher
- Laravel 11.x or 12.x
Installation
You can install the package via composer:
composer require appique/support
Features
🔧 Helpers
ArrayHelper
Array manipulation with dot notation support:
use Appique\Support\Helpers\ArrayHelper; // Set values with dot notation $data = []; ArrayHelper::set($data, 'user.profile.name', 'John Doe'); // Result: ['user' => ['profile' => ['name' => 'John Doe']]] // Set with closure evaluation ArrayHelper::set($data, 'timestamp', fn() => now()); // Set multiple values using wildcards $data = [ 'users' => [ ['name' => 'John'], ['name' => 'Jane'] ] ]; ArrayHelper::set($data, 'users.*.active', true); // All users now have 'active' => true
StringHelper
String utilities with Unicode support and data masking:
use Appique\Support\Helpers\StringHelper; // Remove non-ASCII characters StringHelper::removeNonAscii('Héllö Wörld!'); // 'Hello World!' // Check if value is integer-like StringHelper::isIntegerish('123'); // true StringHelper::isIntegerish('1.23'); // false // Mask specific keys in arrays $data = [ 'password' => 'secret123', 'username' => 'john' ]; $masked = StringHelper::maskKeys(['password'], $data); // Result: ['password' => 's*******3', 'username' => 'john'] // Mask sensitive data StringHelper::mask('4532015112830366'); // '453**********366' StringHelper::mask('secret', '*', 1); // 's****t'
CacheHelper
Encrypted caching with automatic cleanup of corrupted entries:
use Appique\Support\Helpers\CacheHelper; // Store sensitive data encrypted CacheHelper::encryptAndPut('api.token', $sensitiveToken, 3600); // Retrieve and decrypt (automatically removes corrupted entries) $token = CacheHelper::getAndDecrypt('api.token');
- Stores all cached values encrypted
- Automatically removes corrupted/tampered cache entries when detected
- Returns null for missing or invalid data
- No try-catch blocks needed
🔌 Collection Methods
Additional methods for Laravel Collections. You can use them in two ways:
Option 1: Global Mixins
Register the mixin once (e.g., in AppServiceProvider
) to make methods available on all Laravel Collections:
// In AppServiceProvider::boot() use Illuminate\Support\Collection; use Appique\Support\Mixins\CollectionMixin; Collection::mixin(new CollectionMixin); // Then use anywhere in your application $admin = User::where('role', 'admin') ->get() ->oneOrThrow('Expected exactly one admin'); $product = Product::where('sku', $sku) ->get() ->oneOrNull('Multiple products with same SKU');
Option 2: Using the CollectionExtension Trait
For custom collection classes:
use Appique\Support\Traits\CollectionExtension; class CustomCollection extends \Illuminate\Support\Collection { use CollectionExtension; } $collection = new CustomCollection($users); $admin = $collection ->where('role', 'admin') ->oneOrThrow();
Available Methods
// oneOrThrow() - Get exactly one item or throw exception $winner = collect(['Alice'])->oneOrThrow('No single winner found'); // Returns 'Alice' collect(['Alice', 'Bob'])->oneOrThrow('Multiple winners found'); // Throws exception // oneOrNull() - Get one item or null (allows 0 or 1 item) $single = collect(['item'])->oneOrNull('Multiple items found'); // Returns 'item' $empty = collect([])->oneOrNull(); // Returns null collect([1, 2, 3])->oneOrNull('Too many results'); // Throws exception // firstOrThrow() - Get first item or throw exception if empty $first = collect(['a', 'b', 'c'])->firstOrThrow('No items'); // Returns 'a' collect([])->firstOrThrow('Collection is empty'); // Throws exception // throwIfEmpty() - Ensure collection has at least one item collect(['data'])->throwIfEmpty('No data available'); // Continues normally collect([])->throwIfEmpty('No data available'); // Throws exception // throwIfNotEmpty() - Ensure collection is empty collect([])->throwIfNotEmpty('Collection should be empty'); // Continues normally collect(['item'])->throwIfNotEmpty('Collection should be empty'); // Throws exception // copy() - Create a shallow copy of the collection $original = new CustomCollection([1, 2, 3]); $backup = $original->copy(); // New CustomCollection instance with same items
🎯 HasMethodMemoization Trait
Memoization with parameter-based caching and reset capability. Unlike Laravel's once()
helper, this trait supports
caching different results for different parameters:
use Appique\Support\Traits\HasMethodMemoization; class DataProcessor { use HasMethodMemoization; public function process(string $input, int $complexity = 1): string { // Cache keys are optional - use them to cache different results for different parameters return $this->memoize( fn() => $this->someExpensiveOperation($input, $complexity), $input, // Optional: First cache key $complexity // Optional: Second cache key ); } public function processGlobal(): array { // Without cache keys, the result is cached once per instance return $this->memoize( fn() => $this->someExpensiveGlobalOperation() // No cache keys = same result for all calls ); } public function clearCache(): void { // Reset all memoized values $this->resetMemoization(); } } // Usage $processor = new DataProcessor(); // Each call with different parameters is cached separately $result1 = $processor->process('hello', 1); // Runs expensive operation $result1 = $processor->process('hello', 1); // Returns cached result $result2 = $processor->process('hello', 2); // Different complexity = new cache entry $result3 = $processor->process('world', 1); // Different input = new cache entry // Clear cache when needed $processor->clearCache(); $result1 = $processor->process('hello', 1); // Runs expensive operation again
🛠️ Console Tools
ClassGenerator
Generate classes from stub templates:
use Appique\Support\Console\ClassGenerator; // Generates app/Services/UserService.php ClassGenerator::make('UserService', 'service.stub') ->inAppNamespace('Services') ->placeholders(['model' => 'User']) ->create(); // Generates tests/Unit/Services/UserServiceTest.php ClassGenerator::make('UserServiceTest', 'test.stub') ->inTestNamespace('Unit', 'Services') ->create(); // Generates database/factories/UserFactory.php ClassGenerator::make('UserFactory', 'factory.stub') ->inFactoriesNamespace() ->create(); // Generates app/Models/User.php ClassGenerator::make('App\\Models\\User', 'model.stub') ->create();
Stubs use simple placeholders: {{ class }}
, {{ namespace }}
, {{ model }}
etc.
Testing
Run the test suite:
composer test
Run tests with coverage:
composer test-coverage
Run static analysis:
composer analyse
Fix code style:
composer format
Run all checks in one go:
composer check
Changelog
Please see CHANGELOG for more information on recent changes.
Contributing
Contributions are welcome! Please see CONTRIBUTING for details.
Development Setup
- Fork the repository
- Clone your fork
- Install dependencies:
composer install
- Create a feature branch
- Make your changes
- Run checks:
composer check
(formats code, runs static analysis, and tests) - Submit a pull request
Security
Please review our security policy on how to report security vulnerabilities.
Credits
License
The MIT License (MIT). Please see License File for more information.
Acknowledgments
This package was inspired by the Laravel community, particularly:
- Spatie for their excellent Laravel packages and Package Skeleton
- The Laravel framework team for creating this amazing ecosystem