• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

orisai / object-mapper / 29745748821

20 Jul 2026 09:29AM UTC coverage: 88.132%. First build
29745748821

push

github

mabar
PHPStan: analysis fixes

12 of 19 new or added lines in 4 files covered. (63.16%)

5859 of 6648 relevant lines covered (88.13%)

121.05 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

40.22
/src/Callbacks/AfterMappingCallback.php
1
<?php declare(strict_types = 1);
2

3
namespace Orisai\ObjectMapper\Callbacks;
4

5
use Nette\Utils\Helpers;
6
use Orisai\Exceptions\Logic\InvalidArgument;
7
use Orisai\ObjectMapper\Args\Args;
8
use Orisai\ObjectMapper\Args\ArgsChecker;
9
use Orisai\ObjectMapper\Callbacks\Context\CallbackBaseContext;
10
use Orisai\ObjectMapper\Callbacks\Context\ObjectContext;
11
use Orisai\ObjectMapper\MappedObject;
12
use Orisai\ObjectMapper\Meta\Context\MetaContext;
13
use Orisai\ObjectMapper\Meta\Runtime\PhpMethodMeta;
14
use Orisai\ObjectMapper\Processing\ObjectHolder;
15
use ReflectionClass;
16
use ReflectionMethod;
17
use ReflectionNamedType;
18
use ReflectionParameter;
19
use ReflectionType;
20
use Reflector;
21
use function array_map;
22
use function assert;
23
use function in_array;
24
use function is_a;
25
use function sprintf;
26

27
/**
28
 * @implements Callback<AfterMappingCallbackArgs>
29
 *
30
 * @internal
31
 */
32
final class AfterMappingCallback implements Callback
33
{
34

35
        public const Method = 'method';
36

37
        private function __construct()
38
        {
39
                // Static constructor is required
40
        }
×
41

42
        public static function resolveArgs(
43
                array $args,
44
                MetaContext $context,
45
                Reflector $reflector
46
        ): AfterMappingCallbackArgs
47
        {
48
                $checker = new ArgsChecker($args, self::class);
16✔
49
                $checker->checkAllowedArgs([self::Method]);
16✔
50

51
                $checker->checkRequiredArg(self::Method);
16✔
52
                $methodName = $checker->checkString(self::Method);
16✔
53

54
                if (!$reflector instanceof ReflectionClass) {
16✔
55
                        throw InvalidArgument::create()
×
56
                                ->withMessage(sprintf(
×
57
                                        '"%s" can be defined only above a class.',
×
58
                                        self::class,
×
59
                                ));
×
60
                }
61

62
                $method = self::validateMethod($reflector, $methodName);
16✔
63

64
                if ($method->isStatic()) {
16✔
65
                        throw InvalidArgument::create()
×
66
                                ->withMessage(sprintf(
×
67
                                        '"%s" must be used with a non-static method.',
×
68
                                        self::class,
×
69
                                ));
×
70
                }
71

72
                return new AfterMappingCallbackArgs(
16✔
73
                        PhpMethodMeta::from($method),
16✔
74
                );
16✔
75
        }
76

77
        /**
78
         * @param ReflectionClass<MappedObject> $class
79
         */
80
        private static function validateMethod(ReflectionClass $class, string $methodName): ReflectionMethod
81
        {
82
                $method = self::validateMethodExistence($class, $methodName);
16✔
83

84
                self::validateMethodSignature($method);
16✔
85

86
                return $method;
16✔
87
        }
88

89
        /**
90
         * @param ReflectionClass<MappedObject> $class
91
         */
92
        private static function validateMethodExistence(ReflectionClass $class, string $methodName): ReflectionMethod
93
        {
94
                if (!$class->hasMethod($methodName)) {
16✔
95
                        $methods = array_map(
×
96
                                static fn (ReflectionMethod $method): string => $method->getName(),
×
97
                                $class->getMethods(),
×
98
                        );
×
99
                        $hint = Helpers::getSuggestion($methods, $methodName);
×
100

101
                        throw InvalidArgument::create()
×
102
                                ->withMessage(sprintf(
×
103
                                        'Argument "%s" given to "%s" is expected to be existing method of "%s", "%s" given.%s',
×
104
                                        self::Method,
×
105
                                        self::class,
×
106
                                        $class->getName(),
×
107
                                        $methodName,
×
108
                                        $hint !== null ? sprintf(' Did you mean "%s"?', $hint) : '',
×
109
                                ));
×
110
                }
111

112
                return $class->getMethod($methodName);
16✔
113
        }
114

115
        private static function validateMethodSignature(ReflectionMethod $method): void
116
        {
117
                [$paramContext] = self::validateParametersCount($method);
16✔
118

119
                self::validateClassMethodSignature($method, $paramContext);
16✔
120
        }
121

122
        /**
123
         * @return array{ReflectionParameter|null}
124
         */
125
        private static function validateParametersCount(ReflectionMethod $method): array
126
        {
127
                $requiredCount = $method->getNumberOfRequiredParameters();
16✔
128
                if ($requiredCount > 1) {
16✔
129
                        throw InvalidArgument::create()
×
130
                                ->withMessage(sprintf(
×
131
                                        'Callback method %s::%s should have only 1 required parameter, %s required parameters given',
×
132
                                        $method->getDeclaringClass()->getName(),
×
133
                                        $method->getName(),
×
134
                                        $requiredCount,
×
135
                                ));
×
136
                }
137

138
                $parameters = $method->getParameters();
16✔
139

140
                return [
16✔
141
                        $parameters[0] ?? null,
16✔
142
                ];
16✔
143
        }
144

145
        /**
146
         * afterClass(MappedObjectContext $context): void|never
147
         */
148
        private static function validateClassMethodSignature(
149
                ReflectionMethod $method,
150
                ?ReflectionParameter $paramContext
151
        ): void
152
        {
153
                if ($paramContext !== null) {
16✔
154
                        self::validateClassMethodContextParam($method, $paramContext);
×
155
                }
156

157
                self::validateClassMethodReturn($method);
16✔
158
        }
159

160
        protected static function validateClassMethodReturn(ReflectionMethod $method): void
161
        {
162
                $type = self::getTypeName($method->getReturnType());
16✔
163

164
                if (in_array($type, ['void', 'never'], true)) {
16✔
165
                        return;
16✔
166
                }
167

168
                throw InvalidArgument::create()
×
169
                        ->withMessage(sprintf(
×
170
                                'Return type of class callback method %s::%s should be "void" or "never" instead of %s',
×
171
                                $method->getDeclaringClass()->getName(),
×
172
                                $method->getName(),
×
173
                                $type ?? 'none',
×
174
                        ));
×
175
        }
176

177
        private static function validateClassMethodContextParam(
178
                ReflectionMethod $method,
179
                ReflectionParameter $paramContext
180
        ): void
181
        {
182
                if (
183
                        ($type = self::getTypeName($paramContext->getType())) === null
×
184
                        || !is_a($type, ObjectContext::class, true)
×
185
                ) {
186
                        throw InvalidArgument::create()
×
187
                                ->withMessage(sprintf(
×
188
                                        'Second parameter of class callback method %s::%s should have "%s" type instead of %s',
×
189
                                        $method->getDeclaringClass()->getName(),
×
190
                                        $method->getName(),
×
191
                                        ObjectContext::class,
×
192
                                        $type ?? 'none',
×
193
                                ));
×
194
                }
195
        }
196

197
        protected static function getTypeName(?ReflectionType $type): ?string
198
        {
199
                if (!$type instanceof ReflectionNamedType) {
16✔
200
                        return null;
×
201
                }
202

203
                return $type->getName();
16✔
204
        }
205

206
        public static function getArgsType(): string
207
        {
208
                return AfterMappingCallbackArgs::class;
16✔
209
        }
210

211
        /**
212
         * @param AfterMappingCallbackArgs $args
213
         * @return mixed
214
         */
215
        public static function invoke(
216
                $data,
217
                Args $args,
218
                ObjectHolder $holder,
219
                CallbackBaseContext $context
220
        )
221
        {
222
                $meta = $args->meta;
8✔
223
                $method = $meta->method;
8✔
224

225
                $instance = $holder->getInstance();
8✔
226

227
                if ($meta->isPublic) {
8✔
228
                        $instance->$method($context);
8✔
229
                } else {
230
                        // phpcs:disable SlevomatCodingStandard.Functions.StaticClosure.ClosureNotStatic
NEW
231
                        $bound = (fn () => $instance->$method($context))
×
NEW
232
                                ->bindTo($instance, $meta->declaringClass);
×
233
                        // phpcs:enable
NEW
234
                        assert($bound !== null);
×
NEW
235
                        $bound();
×
236
                }
237

238
                return [];
8✔
239
        }
240

241
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc