8000 [Mapper] Object to Object mapper component · symfony/symfony@199baf7 · GitHub
[go: up one dir, main page]

Skip to content

Commit 199baf7

Browse files
committed
[Mapper] Object to Object mapper component
1 parent 4b659cb commit 199baf7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+1398
-0
lines changed

composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@
8686
"symfony/ldap": "self.version",
8787
"symfony/lock": "self.version",
8888
"symfony/mailer": "self.version",
89+
"symfony/object-mapper": "self.version",
8990
"symfony/messenger": "self.version",
9091
"symfony/mime": "self.version",
9192
"symfony/monolog-bridge": "self.version",
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
/Tests export-ignore
2+
/phpunit.xml.dist export-ignore
3+
/.git* export-ignore
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
Please do not submit any Pull Requests here. They will be closed.
2+
---
3+
4+
Please submit your PR here instead:
5+
https://github.com/symfony/symfony
6+
7+
This repository is what we call a "subtree split": a read-only subset of that main repository.
8+
We're looking forward to your PR there!
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
name: Check subtree split
2+
3+
on:
4+
pull_request_target:
5+
6+
jobs:
7+
close-pull-request:
8+
runs-on: ubuntu-latest
9+
10+
steps:
11+
- name: Close pull request
12+
uses: actions/github-script@v6
13+
with:
14+
script: |
15+
if (context.repo.owner === "symfony") {
16+
github.rest.issues.createComment({
17+
owner: "symfony",
18+
repo: context.repo.repo,
19+
issue_number: context.issue.number,
20+
body: `
21+
Thanks for your Pull Request! We love contributions.
22+
23+
However, you should instead open your PR on the main repository:
24+
https://github.com/symfony/symfony
25+
26+
This repository is what we call a "subtree split": a read-only subset of that main repository.
27+
We're looking forward to your PR there!
28+
`
29+
});
30+
31+
github.rest.pulls.update({
32+
owner: "symfony",
33+
repo: context.repo.repo,
34+
pull_number: context.issue.number,
35+
state: "closed"
36+
});
37+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
vendor/
2+
composer.lock
3+
phpunit.xml
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\ObjectMapper\Attribute;
13+
14+
/**
15+
* Configures a class or a property to map to.
16+
*
17+
* @experimental
18+
*
19+
* @author Antoine Bluchet <soyuka@gmail.com>
20+
*
21+
* @psalm-type CallableType =
22+
*/
23+
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
24+
readonly class Map
25+
{
26+
/**
27+
* @param string|class-string|null $source The property or the class to map from
28+
* @param string|class-string|null $target The property or the class to map to
29+
* @param string|bool|callable(mixed $value, object $object): bool|null $if A boolean, Symfony service name or a callable that instructs whether to map
30+
* @param (string|callable(mixed $value, object $object): mixed)|(string|callable(mixed $value, object $object): mixed)[]|null $transform A Symfony service name or a callable that transform the value during mapping
31+
*/
32+
public function __construct(
33+
public ?string $target = null,
34+
public ?string $source = null,
35+
public mixed $if = null,
36+
public mixed $transform = null,
37+
) {
38+
}
39+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
CHANGELOG
2+
=========
3+
4+
7.2
5+
---
6+
7+
* Add the component as experimental
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\ObjectMapper\Exception;
13+
14+
/**
15+
* @experimental
16+
*
17+
* @author Antoine Bluchet <soyuka@gmail.com>
18+
*/
19+
interface ExceptionInterface extends \Throwable
20+
{
21+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\ObjectMapper\Exception;
13+
14+
/**
15+
* @experimental
16+
*
17+
* @author Antoine Bluchet <soyuka@gmail.com>
18+
*/
19+
class MappingException extends RuntimeException
20+
{
21+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\ObjectMapper\Exception;
13+
14+
/**
15+
* @experimental
16+
*
17+
* @author Antoine Bluchet <soyuka@gmail.com>
18+
*/
19+
final class MappingTransformException extends RuntimeException
20+
{
21+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\ObjectMapper\Exception;
13+
14+
/**
15+
* @experimental
16+
*
17+
* @author Antoine Bluchet <soyuka@gmail.com>
18+
*/
19+
class ReflectionException extends \ReflectionException implements ExceptionInterface
20+
{
21+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\ObjectMapper\Exception;
13+
14+
/**
15+
* @experimental
16+
*
17+
* @author Antoine Bluchet <soyuka@gmail.com>
18+
*/
19+
class RuntimeException extends \RuntimeException implements ExceptionInterface
20+
{
21+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
Copyright (c) 2024-present Fabien Potencier
2+
3+
Permission is hereby granted, free of charge, to any person obtaining a copy
4+
of this software and associated documentation files (the "Software"), to deal
5+
in the Software without restriction, including without limitation the rights
6+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
copies of the Software, and to permit persons to whom the Software is furnished
8+
to do so, subject to the following conditions:
9+
10+
The above copyright notice and this permission notice shall be included in all
11+
copies or substantial portions of the Software.
12+
13+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19+
THE SOFTWARE.
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\ObjectMapper\Metadata;
13+
14+
/**
15+
* Factory to create Mapper metadata.
16+
*
17+
* @experimental
18+
*
19+
* @author Antoine Bluchet <soyuka@gmail.com>
20+
*/
21+
interface MapperMetadataFactoryInterface
22+
{
23+
/**
24+
* @param array<string, mixed> $context
25+
*
26+
* @return list<Mapping>
27+
*/
28+
public function create(object $object, ?string $property = null, array $context = []): array;
29+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\ObjectMapper\Metadata;
13+
14+
/**
15+
* Configures a class or a property to map to.
16+
*
17+
* @internal
18+
*
19+
* @author Antoine Bluchet <soyuka@gmail.com>
20+
*
21+
* @psalm-type CallableType = string|callable(mixed $value, object $object): mixed
22+
*/
23+
readonly class Mapping
24+
{
25+
/**
26+
* @param string|class-string|null $source The property or the class to map from
27+
* @param string|class-string|null $target The property or the class to map to
28+
* @param string|bool|callable(mixed $value, object $object): bool|null $if A boolean, Symfony service name or a callable that instructs whether to map
29+
* @param CallableType|CallableType[]|null $transform A Symfony service name or a callable that transform the value during mapping
30+
*/
31+
public function __construct(
32+
public ?string $target = null,
33+
public ?string $source = null,
34+
public mixed $if = null,
35+
public mixed $transform = null,
36+
) {
37+
}
38+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\ObjectMapper\Metadata;
13+
14+
use Symfony\Component\ObjectMapper\Attribute\Map;
15+
use Symfony\Component\ObjectMapper\Exception\ReflectionException;
16+
17+
/**
18+
* @internal
19+
*
20+
* @author Antoine Bluchet <soyuka@gmail.com>
21+
*/
22+
final class ReflectionMapperMetadataFactory implements MapperMetadataFactoryInterface
23+
{
24+
public function create(object $object, ?string $property = null, array $context = []): array
25+
{
26+
try {
27+
$refl = new \ReflectionClass($object);
28+
$mapTo = [];
29+
foreach (($property ? $refl->getProperty($property) : $refl)->getAttributes(Map::class) as $mapAttribute) {
30+
$map = $mapAttribute->newInstance();
31+
$mapTo[] = new Mapping(source: $map->source, target: $map->target, if: $map->if, transform: $map->transform);
32+
}
33+
34+
return $mapTo;
35+
} catch (\ReflectionException $e) {
36+
throw new ReflectionException($e->getMessage(), $e->getCode(), $e);
37+
}
38+
}
39+
}

0 commit comments

Comments
 (0)
0