Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 13 additions & 11 deletions src/Illuminate/Support/Manager.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,14 @@ public function __construct(Container $container)
/**
* Get the default driver name.
*
* @return string|null
* @return \BackedEnum|\UnitEnum|string|null
*/
abstract public function getDefaultDriver();

/**
* Get a driver instance.
*
* @param string|null $driver
* @param \BackedEnum|\UnitEnum|string|null $driver
* @return mixed
*
* @throws \InvalidArgumentException
Expand All @@ -75,56 +75,58 @@ public function driver($driver = null)
// If the given driver has not been created before, we will create the instances
// here and cache it so we can return it next time very quickly. If there is
// already a driver created by this name, we'll just return that instance.
return $this->drivers[$driver] ??= $this->createDriver($driver);
return $this->drivers[enum_value($driver)] ??= $this->createDriver($driver);
}

/**
* Create a new driver instance.
*
* @param string $driver
* @param \BackedEnum|\UnitEnum|string $driver
* @return mixed
*
* @throws \InvalidArgumentException
*/
protected function createDriver($driver)
{
$driverName = enum_value($driver);

// First, we will determine if a custom driver creator exists for the given driver and
// if it does not we will check for a creator method for the driver. Custom creator
// callbacks allow developers to build their own "drivers" easily using Closures.
if (isset($this->customCreators[$driver])) {
if (isset($this->customCreators[$driverName])) {
return $this->callCustomCreator($driver);
}

$method = 'create'.Str::studly($driver).'Driver';
$method = 'create'.Str::studly($driverName).'Driver';

if (method_exists($this, $method)) {
return $this->$method();
}

throw new InvalidArgumentException("Driver [$driver] not supported.");
throw new InvalidArgumentException("Driver [$driverName] not supported.");
}

/**
* Call a custom driver creator.
*
* @param string $driver
* @param \BackedEnum|\UnitEnum|string $driver
* @return mixed
*/
protected function callCustomCreator($driver)
{
return $this->customCreators[$driver]($this->container);
return $this->customCreators[enum_value($driver)]($this->container);
}

/**
* Register a custom driver creator Closure.
*
* @param string $driver
* @param \BackedEnum|\UnitEnum|string $driver
* @param \Closure $callback
* @return $this
*/
public function extend($driver, Closure $callback)
{
$this->customCreators[$driver] = $callback;
$this->customCreators[enum_value($driver)] = $callback;

return $this;
}
Expand Down
49 changes: 49 additions & 0 deletions tests/Integration/Support/Fixtures/EnumManager.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

namespace Illuminate\Tests\Integration\Support\Fixtures;

use BackedEnum;
use Illuminate\Support\Manager;
use UnitEnum;

class EnumManager extends Manager
{
protected BackedEnum|UnitEnum|null $defaultDriver = null;

public function useAsDefault(BackedEnum|UnitEnum|null $default)
{
$this->defaultDriver = $default;

return $this;
}

/**
* Get the default driver name.
*
* @return string|null
*/
public function getDefaultDriver()
{
return $this->defaultDriver;
}

public function createMysqlDriver()
{
return new class('@mysql')
{
public function __construct(public readonly string $name)
{
}
};
}

public function createMariaDbDriver()
{
return new class('@mariadb')
{
public function __construct(public readonly string $name)
{
}
};
}
}
8 changes: 8 additions & 0 deletions tests/Integration/Support/Fixtures/EnumManager/Bar.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

namespace Illuminate\Tests\Integration\Support\Fixtures\EnumManager;

enum Bar: string
{
case MariaDb = 'mariadb';
}
8 changes: 8 additions & 0 deletions tests/Integration/Support/Fixtures/EnumManager/Foo.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

namespace Illuminate\Tests\Integration\Support\Fixtures\EnumManager;

enum Foo
{
case MySql;
}
85 changes: 85 additions & 0 deletions tests/Integration/Support/ManagerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

namespace Illuminate\Tests\Integration\Support;

use Illuminate\Tests\Integration\Support\Fixtures\EnumManager;
use Illuminate\Tests\Integration\Support\Fixtures\EnumManager\Bar;
use Illuminate\Tests\Integration\Support\Fixtures\EnumManager\Foo;
use Illuminate\Tests\Integration\Support\Fixtures\NullableManager;
use InvalidArgumentException;
use Orchestra\Testbench\TestCase;
Expand All @@ -14,4 +17,86 @@ public function testDefaultDriverCannotBeNull()

(new NullableManager($this->app))->driver();
}

public function testDefaultDriverCanBeUnitEnum()
{
$driver = (new EnumManager($this->app))
->useAsDefault(Foo::MySql)
->driver();

$this->assertEquals('@mysql', $driver->name);
}

public function testDefaultDriverCanBeBackedEnum()
{
$driver = (new EnumManager($this->app))
->useAsDefault(Bar::MariaDb)
->driver();

$this->assertEquals('@mariadb', $driver->name);
}

public function testExtend()
{
$manager = (new NullableManager($this->app))
->extend('myDriver', static fn () => new class('@my-driver')
{
public function __construct(public readonly string $name)
{
}
});

$concrete = $manager->driver('myDriver');
$this->assertEquals('@my-driver', $concrete->name);

$manager->extend('myDriver', static fn () => new class('@my-driver-overrode')
{
public function __construct(public readonly string $name)
{
}
});
$cachedConcrete = $manager->driver('myDriver');
$this->assertEquals('@my-driver', $cachedConcrete->name);

$manager->forgetDrivers();
$concrete = $manager->driver('myDriver');
$this->assertEquals('@my-driver-overrode', $concrete->name);
}

public function testExtendUsingEnum()
{
$concrete = (new EnumManager($this->app))
->useAsDefault(Bar::MariaDb)
->extend(Bar::MariaDb, fn () => new class('@mariadb-extended')
{
public function __construct(public readonly string $name)
{
}
})
->driver();
$this->assertEquals('@mariadb-extended', $concrete->name);

$concrete = (new EnumManager($this->app))
->useAsDefault(Foo::MySql)
->extend(Foo::MySql, fn () => new class('@mysql-extended')
{
public function __construct(public readonly string $name)
{
}
})
->driver();
$this->assertEquals('@mysql-extended', $concrete->name);
}

public function testOthers()
{
$manager = (new EnumManager($this->app))
->useAsDefault(Bar::MariaDb);

$default = $manager->driver();
$this->assertEquals('@mariadb', $default->name);

$other = $manager->driver(Foo::MySql);
$this->assertEquals('@mysql', $other->name);
}
}