Skip to content

Commit 5964c72

Browse files
committed
wip
1 parent d83308f commit 5964c72

19 files changed

+228
-308
lines changed

src/Mapper.php

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
namespace OpenSoutheners\LaravelDataMapper;
44

5+
use ArrayAccess;
6+
use Countable;
57
use Illuminate\Database\Eloquent\Model;
68
use Illuminate\Foundation\Http\FormRequest;
79
use Illuminate\Http\Request;
@@ -21,17 +23,9 @@ final class Mapper
2123

2224
protected ?string $throughClass = null;
2325

24-
protected ?MappingValue $fromMappingValue = null;
25-
26-
protected ?string $property = null;
27-
28-
protected array $propertyTypes = [];
29-
30-
protected bool $runningFromMapper = false;
31-
3226
public function __construct(mixed $input)
3327
{
34-
if (is_array($input) && count($input) === 1) {
28+
if ((is_array($input) || $input instanceof Countable) && count($input) === 1) {
3529
$input = reset($input);
3630
}
3731

@@ -62,7 +56,7 @@ protected function takeDataFrom(mixed $input): mixed
6256
is_object($input->route()) ? $input->route()->parameters() : [],
6357
$input instanceof FormRequest ? $input->validated() : $input->all()
6458
),
65-
$input instanceof Collection => $input->all(),
59+
$input instanceof Collection => $input,
6660
$input instanceof Model => $input,
6761
is_object($input) => $this->extractProperties($input),
6862
default => $input,
@@ -88,24 +82,35 @@ public function through(string $class): static
8882
public function to(?string $output = null)
8983
{
9084
$output ??= $this->dataClass;
91-
92-
// if (is_array($this->data)) {
93-
// $reflectionClass = $this->fromMappingValue?->class ?? $output ? new ReflectionClass($output) : null;
94-
// } else {
95-
// $reflectionClass = $output ? new ReflectionClass($output) : null;
96-
// }
97-
98-
$mappingDataValue = new MappingValue(
85+
86+
if (!$this->throughClass && (is_array($this->data) || $this->data instanceof Collection)) {
87+
$this->throughClass = is_array($this->data) ? 'array' : Collection::class;
88+
}
89+
90+
$mappingValue = new MappingValue(
9991
data: $this->data,
100-
allMappingData: (! $this->runningFromMapper ? $this->fromMappingValue?->allMappingData : $this->data) ?? [],
101-
types: $this->propertyTypes,
10292
objectClass: $output,
10393
collectClass: $this->throughClass,
10494
);
95+
96+
$mapper = Collection::make(ServiceProvider::getMappers())
97+
->map(fn ($mapper) => ['mapper' => $mapper, 'score' => $mapper->score($mappingValue)])
98+
->sortByDesc('score')
99+
// ->dd()
100+
->first();
101+
102+
// dump($mappingValue);
103+
// dump($mapper);
104+
// if ($this->data instanceof Collection) {
105+
// return;
106+
// }
107+
//
108+
if (!$mapper || $mapper['score'] === 0) {
109+
return $mappingValue->data;
110+
}
111+
112+
$mapper = $mapper['mapper'];
105113

106-
return app(Pipeline::class)
107-
->through(ServiceProvider::getMappers())
108-
->send($mappingDataValue)
109-
->then(fn (MappingValue $mappingValue) => $mappingValue->data);
114+
return $mapper($mappingValue);
110115
}
111116
}

src/Mappers/BackedEnumDataMapper.php

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,29 +3,23 @@
33
namespace OpenSoutheners\LaravelDataMapper\Mappers;
44

55
use BackedEnum;
6+
use Illuminate\Support\Collection;
67
use OpenSoutheners\LaravelDataMapper\MappingValue;
7-
use ReflectionEnum;
88

99
final class BackedEnumDataMapper extends DataMapper
1010
{
11-
/**
12-
* Assert that this mapper resolves property with types given.
13-
*/
14-
public function assert(MappingValue $mappingValue): bool
11+
public function assert(MappingValue $mappingValue): array
1512
{
16-
return is_subclass_of($mappingValue->preferredTypeClass, BackedEnum::class)
17-
&& gettype($mappingValue->data) === (new ReflectionEnum($mappingValue->preferredTypeClass))->getBackingType()->getName();
13+
return [
14+
is_string($mappingValue->data) || is_int($mappingValue->data),
15+
is_subclass_of($mappingValue->objectClass, BackedEnum::class),
16+
];
1817
}
1918

20-
/**
21-
* Resolve mapper that runs once assert returns true.
22-
*/
2319
public function resolve(MappingValue $mappingValue): void
2420
{
25-
$mappingValue->data = $mappingValue->preferredTypeClass::tryFrom($mappingValue->data) ?? (
26-
count($mappingValue->types) > 1
27-
? $mappingValue->data
28-
: null
29-
);
21+
$mappingValue->data = $mappingValue->data instanceof Collection
22+
? $mappingValue->data->mapInto($mappingValue->objectClass)
23+
: $mappingValue->objectClass::tryFrom($mappingValue->data);
3024
}
3125
}

src/Mappers/CarbonDataMapper.php

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,32 +5,38 @@
55
use Carbon\CarbonImmutable;
66
use Carbon\CarbonInterface;
77
use Illuminate\Support\Carbon;
8+
use Illuminate\Support\Collection;
89
use OpenSoutheners\LaravelDataMapper\MappingValue;
910

1011
final class CarbonDataMapper extends DataMapper
1112
{
12-
/**
13-
* Assert that this mapper resolves property with types given.
14-
*/
15-
public function assert(MappingValue $mappingValue): bool
13+
public function assert(MappingValue $mappingValue): array
1614
{
17-
return in_array(gettype($mappingValue->data), ['string', 'integer'], true)
18-
&& ($mappingValue->preferredTypeClass === CarbonInterface::class
19-
|| is_subclass_of($mappingValue->preferredTypeClass, CarbonInterface::class));
15+
return [
16+
is_a($mappingValue->objectClass, CarbonInterface::class, true),
17+
in_array(gettype($mappingValue->data), ['string', 'integer'], true),
18+
is_iterable($mappingValue->data),
19+
];
2020
}
2121

22-
/**
23-
* Resolve mapper that runs once assert returns true.
24-
*/
2522
public function resolve(MappingValue $mappingValue): void
2623
{
27-
$mappingValue->data = match (true) {
28-
gettype($mappingValue->data) === 'integer' || is_numeric($mappingValue->data) => Carbon::createFromTimestamp($mappingValue->data),
29-
default => Carbon::make($mappingValue->data),
24+
$mappingValue->data = is_array($mappingValue->data) || $mappingValue->data instanceof Collection
25+
? Collection::make($mappingValue->data)->map(fn ($item) => $this->resolveCarbon($item, $mappingValue->objectClass))
26+
: $this->resolveCarbon($mappingValue->data, $mappingValue->objectClass);
27+
}
28+
29+
private function resolveCarbon($value, string $objectClass): CarbonInterface
30+
{
31+
$carbonObject = match (true) {
32+
gettype($value) === 'integer' || is_numeric($value) => Carbon::createFromTimestamp($value),
33+
default => Carbon::make($value),
3034
};
3135

32-
if ($mappingValue->preferredTypeClass === CarbonImmutable::class) {
33-
$mappingValue->data = $mappingValue->data->toImmutable();
36+
if ($objectClass === CarbonImmutable::class) {
37+
return $carbonObject->toImmutable();
3438
}
39+
40+
return $carbonObject;
3541
}
3642
}

src/Mappers/CollectionDataMapper.php

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,17 @@
1111

1212
final class CollectionDataMapper extends DataMapper
1313
{
14-
/**
15-
* Assert that this mapper resolves property with types given.
16-
*/
17-
public function assert(MappingValue $mappingValue): bool
14+
public function assert(MappingValue $mappingValue): array
1815
{
19-
return $mappingValue->collectClass === 'array'
20-
|| ($mappingValue->collectClass === Collection::class && is_array($mappingValue->data))
21-
|| ($mappingValue->collectClass === Collection::class && is_string($mappingValue->data) && str_contains($mappingValue->data, ','))
22-
|| $mappingValue->objectClass === Collection::class
23-
|| $mappingValue->objectClass === EloquentCollection::class;
16+
if (is_a($mappingValue->objectClass, Collection::class, true)) {
17+
return [true];
18+
}
19+
20+
return [
21+
!is_a($mappingValue->data, Collection::class),
22+
$mappingValue->collectClass === 'array' || $mappingValue->collectClass === Collection::class,
23+
$mappingValue->collectClass === Collection::class && is_array($mappingValue->data) || $mappingValue->collectClass === Collection::class && is_string($mappingValue->data) && str_contains($mappingValue->data, ','),
24+
];
2425
}
2526

2627
/**
@@ -42,16 +43,12 @@ public function resolve(MappingValue $mappingValue): void
4243

4344
$collection = $collection->filter();
4445

45-
if ($mappingValue->collectClass === 'array') {
46-
$mappingValue->data = $collection->all();
47-
48-
return;
49-
}
50-
5146
if ($mappingValue->objectClass && $mappingValue->objectClass !== Collection::class) {
52-
$collection = $collection->map(fn ($value) => map($value)->to($mappingValue->objectClass));
47+
$collection = map($collection)->to($mappingValue->objectClass);
5348
}
5449

55-
$mappingValue->data = $collection;
50+
$mappingValue->data = $mappingValue->collectClass === 'array'
51+
? $collection->all()
52+
: $collection;
5653
}
5754
}

src/Mappers/DataMapper.php

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,50 @@
33
namespace OpenSoutheners\LaravelDataMapper\Mappers;
44

55
use Closure;
6+
use Illuminate\Support\Facades\Log;
67
use OpenSoutheners\LaravelDataMapper\MappingValue;
78

89
abstract class DataMapper
910
{
1011
/**
11-
* Assert that this mapper resolves property with types given.
12+
* Assertions count that this mapper resolves property with types given.
13+
*
14+
* @return array<boolean>
1215
*/
13-
abstract public function assert(MappingValue $mappingValue): bool;
16+
abstract public function assert(MappingValue $mappingValue): array;
1417

1518
/**
1619
* Resolve mapper that runs once assert returns true.
1720
*/
1821
abstract public function resolve(MappingValue $mappingValue): void;
19-
20-
public function __invoke(MappingValue $mappingValue, Closure $next)
22+
23+
public function score(MappingValue $mappingValue): float
2124
{
22-
if (! $this->assert($mappingValue)) {
23-
return $next($mappingValue);
25+
$assertions = $this->assert($mappingValue);
26+
27+
$total = count($assertions);
28+
29+
$positive = count(array_filter($assertions));
30+
31+
if ($total === 0) {
32+
return 0.0;
2433
}
25-
34+
35+
return $positive / $total;
36+
}
37+
38+
public function __invoke(MappingValue $mappingValue)
39+
{
40+
if (config('app.debug')) {
41+
Log::withContext([
42+
'mappingData' => $mappingValue->data,
43+
'toClass' => $mappingValue->objectClass,
44+
'throughClass' => $mappingValue->collectClass,
45+
])->info('Mapping using class: '.static::class);
46+
}
47+
2648
$this->resolve($mappingValue);
27-
28-
return $next($mappingValue);
49+
50+
return $mappingValue->data;
2951
}
3052
}

src/Mappers/GenericObjectDataMapper.php

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,32 @@
22

33
namespace OpenSoutheners\LaravelDataMapper\Mappers;
44

5+
use Illuminate\Support\Arr;
6+
use Illuminate\Support\Collection;
57
use OpenSoutheners\LaravelDataMapper\MappingValue;
68
use stdClass;
79

810
use function OpenSoutheners\ExtendedPhp\Strings\is_json_structure;
911

1012
final class GenericObjectDataMapper extends DataMapper
1113
{
12-
/**
13-
* Assert that this mapper resolves property with types given.
14-
*/
15-
public function assert(MappingValue $mappingValue): bool
14+
public function assert(MappingValue $mappingValue): array
1615
{
17-
return $mappingValue->preferredTypeClass === stdClass::class
18-
&& (is_array($mappingValue->data) || is_json_structure($mappingValue->data));
16+
return [
17+
$mappingValue->objectClass === stdClass::class,
18+
is_json_structure($mappingValue->data) || (is_array($mappingValue->data) && Arr::isAssoc($mappingValue->data)) || (is_array($mappingValue->data[0] ?? null) && Arr::isAssoc($mappingValue->data[0])),
19+
];
1920
}
2021

21-
/**
22-
* Resolve mapper that runs once assert returns true.
23-
*/
2422
public function resolve(MappingValue $mappingValue): void
2523
{
26-
$mappingValue->data = is_array($mappingValue->data)
27-
? (object) $mappingValue->data
28-
: json_decode($mappingValue->data);
24+
$mappingValue->data = $mappingValue->data instanceof Collection
25+
? $mappingValue->data->map(fn($item) => $this->newObjectInstance($item))
26+
: $this->newObjectInstance($mappingValue->data);
27+
}
28+
29+
protected function newObjectInstance(mixed $data): stdClass
30+
{
31+
return is_array($data) ? (object) $data : json_decode($data);
2932
}
3033
}

src/Mappers/MapeableObjectMapper.php

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,13 @@
77

88
class MapeableObjectMapper extends DataMapper
99
{
10-
/**
11-
* Assert that this mapper resolves property with types given.
12-
*/
13-
public function assert(MappingValue $mappingValue): bool
10+
public function assert(MappingValue $mappingValue): array
1411
{
15-
return is_a($mappingValue->objectClass, MapeableObject::class, true);
12+
return [
13+
is_a($mappingValue->objectClass, MapeableObject::class, true),
14+
];
1615
}
1716

18-
/**
19-
* Resolve mapper that runs once assert returns true.
20-
*/
2117
public function resolve(MappingValue $mappingValue): void
2218
{
2319
app($mappingValue->objectClass)->mappingFrom($mappingValue);

0 commit comments

Comments
 (0)