Installation:
composer require letsdrink/ouzo-goodies
Ensure your project uses PHP 8.4+ (required for full functionality).
First Use Case: Replace verbose array operations with fluent syntax:
use Ouzo\Goodies\Arrays;
use Ouzo\Goodies\Functions;
$filteredNames = Arrays::map($users, Functions::extractField('name'))
->filter(Functions::notEmpty())
->toArray();
Key Entry Points:
Ouzo\Goodies\Arrays for collection operationsOuzo\Goodies\Assert for fluent assertionsOuzo\Goodies\Mock for test mockingsrc/Ouzo/Goodies/ for class implementationstests/ directory for practical usage patterns// Traditional Laravel approach
$processed = collect($items)
->filter(fn($item) => $item['active'])
->map(fn($item) => $item['name'])
->unique()
->values()
->toArray();
// Ouzo Goodies equivalent
$processed = FluentArray::from($items)
->filter(Functions::extractField('active'))
->map(Functions::extractField('name'))
->unique()
->toArray();
// Traditional PHPUnit
$this->assertCount(3, $users);
$this->assertContains('John', $users);
$this->assertStringStartsWith('J', $users[0]);
// Ouzo Goodies
Assert::thatArray($users)
->hasSize(3)
->contains('John');
Assert::thatString($users[0]['name'])
->startsWith('J');
// Traditional mocking
$mock = $this->createMock(UserRepository::class);
$mock->method('find')->willReturn($user);
// Ouzo Goodies
$mock = Mock::create(UserRepository::class);
Mock::when($mock)->find(1)->thenReturn($user);
// Traditional Carbon
$futureDate = now()->addYears(1)->addMonths(2);
// Ouzo Goodies
$futureDate = Clock::now()
->plusYears(1)
->plusMonths(2)
->format();
Service Container Integration:
// Bind Ouzo utilities as singletons
$this->app->singleton(FluentArray::class, fn() => new FluentArray([]));
Collection Macros:
// Extend Laravel Collections with Ouzo methods
collect([])->macro('ouzoMap', function($callback) {
return FluentArray::from($this->all())
->map($callback)
->toArray();
});
TestCase Setup:
use Ouzo\Goodies\Assert;
use Ouzo\Goodies\Mock;
class TestCase extends \Tests\TestCase {
protected function setUp(): void {
Mock::resetAll();
}
protected function assertArrayContainsKeyValue($array, $key, $value) {
Assert::thatArray($array)->containsKey($key)->containsValue($value);
}
}
array_find(), array_any() directly when possible (they delegate to Ouzo under the hood)PHP 8.4 Requirements:
array_find(), array_any(), array_all() won't work on older PHP versions#[Deprecated] attributes may trigger IDE warningsFluent Method Chaining:
// This won't work - FluentArray methods return self
FluentArray::from($items)->filter()->map(); // Missing closures!
// Correct:
FluentArray::from($items)
->filter(Functions::extractField('active'))
->map(Functions::extractField('name'));
Mock Verification:
// Forgetting to verify calls
Mock::verify($mock)->method('arg'); // Must be called after test
Clock Timezone:
// Defaults to system timezone - set explicitly if needed
Clock::setTimezone('UTC');
Assertion Failures:
Assert::thatArray($users)->hasSize(3); // Shows actual size if failed
Mock Debugging:
// Inspect mock interactions
Mock::verify($mock)->method('arg')->times(1);
Mock::verify($mock)->method('nonexistent')->times(0);
FluentArray Inspection:
// Debug intermediate states
$fluent = FluentArray::from($items)
->filter(/* ... */)
->tap(fn($arr) => logger()->debug('Filtered:', $arr));
Custom Comparators:
use Ouzo\Goodies\Comparator;
$customComparator = Comparator::create(function($a, $b) {
return $a->priority <=> $b->priority;
});
Arrays::sort($items, $customComparator);
Custom Assertions:
Assert::extend('isValidEmail', function($string) {
return filter_var($string, FILTER_VALIDATE_EMAIL) !== false;
});
Assert::thatString($email)->isValidEmail();
Fluent Function Composition:
$transform = FluentFunctions::extractField('name')
->removePrefix('user_')
->prepend('User: ');
// Reuse across multiple operations
Arrays::map($users, $transform);
Clock Defaults:
Clock::setTimezone()Mock Behavior:
nullMock::setDefaultReturnValue($value)Assertion Strictness:
Assert::that()->strict() for type-sensitive comparisonsFunction Composition:
// Create reusable transformations
$toUpper = FluentFunctions::create(fn($s) => strtoupper($s));
Arrays::map($strings, $toUpper);
Path Operations:
// Cross-platform path handling
$normalized = Path::normalize('/var//user/../home');
// => '/var/home'
Cache Utilities:
// Simple in-memory cache
Cache::set('key', $value, 3600);
$value = Cache::get('key');
Dynamic Proxies:
// Create partial mocks
$partialMock = Mock::create(Service::class, [
'method1' => fn() => 'hardcoded',
'method2' => fn() => throw new \RuntimeException()
]);
How can I help you explore Laravel packages today?