Skip to content

Commit

Permalink
Merge pull request #544 from grantholle/invokable-attribute-handlers
Browse files Browse the repository at this point in the history
Allow invokable classes and closures to be used in attribute handlers
  • Loading branch information
stevebauman authored Jun 22, 2023
2 parents 43e5e0f + d3a0310 commit 98e8c4e
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 11 deletions.
35 changes: 26 additions & 9 deletions src/Import/Hydrators/AttributeHydrator.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace LdapRecord\Laravel\Import\Hydrators;

use Closure;
use Illuminate\Database\Eloquent\Model as EloquentModel;
use Illuminate\Support\Arr;
use LdapRecord\Models\Model as LdapModel;
Expand All @@ -14,15 +15,27 @@ class AttributeHydrator extends Hydrator
public function hydrate(LdapModel $object, EloquentModel $eloquent): void
{
foreach ($this->getSyncAttributes() as $eloquentField => $ldapField) {
if ($this->isAttributeHandler($ldapField)) {
app($ldapField)->handle($object, $eloquent);
if (! $this->isAttributeHandler($ldapField)) {
$eloquent->{$eloquentField} = is_string($ldapField)
? $object->getFirstAttribute($ldapField)
: $ldapField;

continue;
}

$eloquent->{$eloquentField} = is_string($ldapField)
? $object->getFirstAttribute($ldapField)
: $ldapField;
if ($ldapField instanceof Closure) {
$ldapField($object, $eloquent);

continue;
}

if (is_callable($handler = app($ldapField))) {
$handler($object, $eloquent);

continue;
}

$handler->handle($object, $eloquent);
}
}

Expand All @@ -34,15 +47,19 @@ protected function getSyncAttributes(): array
return (array) Arr::get(
$this->config,
'sync_attributes',
$default = ['name' => 'cn', 'email' => 'mail']
['name' => 'cn', 'email' => 'mail']
);
}

/**
* Determines if the given handler value is a class that contains the 'handle' method.
* Determines if the given value is an attribute handler.
*/
protected function isAttributeHandler($handler): bool
protected function isAttributeHandler(mixed $value): bool
{
return is_string($handler) && class_exists($handler) && method_exists($handler, 'handle');
if ($value instanceof Closure) {
return true;
}

return class_exists($value) && (method_exists($value, '__invoke') || method_exists($value, 'handle'));
}
}
60 changes: 58 additions & 2 deletions tests/Unit/EloquentHydratorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,48 @@ public function test_attribute_hydrator()
{
$entry = new Entry(['bar' => 'baz']);
$model = new TestHydratorModelStub;
AttributeHydrator::with(['sync_attributes' => ['foo' => 'bar']])
->hydrate($entry, $model);

AttributeHydrator::with([
'sync_attributes' => ['foo' => 'bar'],
])->hydrate($entry, $model);

$this->assertEquals('baz', $model->foo);
}

public function test_attribute_hydrator_can_use_handle_function_of_class()
{
$entry = new Entry(['bar' => 'baz']);
$model = new TestHydratorModelStub;

AttributeHydrator::with([
'sync_attributes' => [TestAttributeHandlerHandleStub::class],
])->hydrate($entry, $model);

$this->assertEquals('baz', $model->foo);
}

public function test_attribute_hydrator_can_use_invokable_class()
{
$entry = new Entry(['bar' => 'baz']);
$model = new TestHydratorModelStub;

AttributeHydrator::with(['sync_attributes' => [
TestAttributeHandlerInvokableStub::class,
]])->hydrate($entry, $model);

$this->assertEquals('baz', $model->foo);
}

public function test_attribute_hydrator_can_use_inline_function()
{
$entry = new Entry(['bar' => 'baz']);
$model = new TestHydratorModelStub;

AttributeHydrator::with(['sync_attributes' => [
function ($object, $eloquent) {
$eloquent->foo = $object->getFirstAttribute('bar');
},
]])->hydrate($entry, $model);

$this->assertEquals('baz', $model->foo);
}
Expand Down Expand Up @@ -116,3 +156,19 @@ class TestHydratorModelStub extends Model implements LdapAuthenticatable
{
use AuthenticatesWithLdap;
}

class TestAttributeHandlerHandleStub
{
public function handle($object, $eloquent)
{
$eloquent->foo = $object->getFirstAttribute('bar');
}
}

class TestAttributeHandlerInvokableStub
{
public function __invoke($object, $eloquent)
{
$eloquent->foo = $object->getFirstAttribute('bar');
}
}

0 comments on commit 98e8c4e

Please sign in to comment.