@@ -188,18 +188,18 @@ public function getIsNullExpression(Expr\Variable $input): Expr
188188 /*
189189 * Use the property fetch to read the value
190190 *
191- * isset($input->property_name)
191+ * isset($input->property_name) && null === $input->property_name
192192 */
193- return new Expr \BooleanNot (new Expr \Isset_ ([new Expr \PropertyFetch ($ input , $ this ->accessor )]));
193+ return new Expr \BinaryOp \ LogicalAnd ( new Expr \ BooleanNot (new Expr \Isset_ ([new Expr \PropertyFetch ($ input , $ this ->accessor )])), new Expr \ BinaryOp \ Identical ( new Expr \ ConstFetch ( new Name ( ' null ' )), new Expr \ PropertyFetch ( $ input , $ this -> accessor ) ));
194194 }
195195
196196 if (self ::TYPE_ARRAY_DIMENSION === $ this ->type ) {
197197 /*
198198 * Use the array dim fetch to read the value
199199 *
200- * isset($input['property_name'])
200+ * isset($input['property_name']) && null === $input->property_name
201201 */
202- return new Expr \BooleanNot (new Expr \Isset_ ([new Expr \ArrayDimFetch ($ input , new Scalar \ String_ ( $ this ->accessor ))] ));
202+ return new Expr \BinaryOp \ LogicalAnd ( new Expr \ BooleanNot (new Expr \Isset_ ([new Expr \PropertyFetch ($ input , $ this -> accessor )])), new Expr \ BinaryOp \ Identical ( new Expr \ ConstFetch ( new Name ( ' null ' )), new Expr \ PropertyFetch ( $ input , $ this ->accessor )));
203203 }
204204
205205 if (self ::TYPE_SOURCE === $ this ->type ) {
@@ -212,6 +212,52 @@ public function getIsNullExpression(Expr\Variable $input): Expr
212212 throw new CompileException ('Invalid accessor for read expression ' );
213213 }
214214
215+ public function getIsUndefinedExpression (Expr \Variable $ input ): Expr
216+ {
217+ if (\in_array ($ this ->type , [self ::TYPE_METHOD , self ::TYPE_SOURCE ])) {
218+ /*
219+ * false
220+ */
221+ return new Expr \ConstFetch (new Name ('false ' ));
222+ }
223+
224+ if (self ::TYPE_PROPERTY === $ this ->type ) {
225+ if ($ this ->private ) {
226+ /*
227+ * When the property is private we use the extract callback that can read this value
228+ *
229+ * @see \AutoMapper\Extractor\ReadAccessor::getExtractIsUndefinedCallback()
230+ *
231+ * $this->extractIsUndefinedCallbacks['property_name']($input)
232+ */
233+ return new Expr \FuncCall (
234+ new Expr \ArrayDimFetch (new Expr \PropertyFetch (new Expr \Variable ('this ' ), 'extractIsUndefinedCallbacks ' ), new Scalar \String_ ($ this ->accessor )),
235+ [
236+ new Arg ($ input ),
237+ ]
238+ );
239+ }
240+
241+ /*
242+ * Use the property fetch to read the value
243+ *
244+ * !isset($input->property_name)
245+ */
246+ return new Expr \BooleanNot (new Expr \Isset_ ([new Expr \PropertyFetch ($ input , $ this ->accessor )]));
247+ }
248+
249+ if (self ::TYPE_ARRAY_DIMENSION === $ this ->type ) {
250+ /*
251+ * Use the array dim fetch to read the value
252+ *
253+ * !array_key_exists('property_name', $input)
254+ */
255+ return new Expr \BooleanNot (new Expr \FuncCall (new Name ('array_key_exists ' ), [new Arg (new Scalar \String_ ($ this ->accessor )), new Arg ($ input )]));
256+ }
257+
258+ throw new CompileException ('Invalid accessor for read expression ' );
259+ }
260+
215261 /**
216262 * Get AST expression for binding closure when dealing with a private property.
217263 */
@@ -261,6 +307,38 @@ public function getExtractIsNullCallback(string $className): ?Expr
261307 return null ;
262308 }
263309
310+ /*
311+ * Create extract is null callback for this accessor
312+ *
313+ * \Closure::bind(function ($object) {
314+ * return !isset($object->property_name) && null === $object->property_name;
315+ * }, null, $className)
316+ */
317+ return new Expr \StaticCall (new Name \FullyQualified (\Closure::class), 'bind ' , [
318+ new Arg (
319+ new Expr \Closure ([
320+ 'params ' => [
321+ new Param (new Expr \Variable ('object ' )),
322+ ],
323+ 'stmts ' => [
324+ new Stmt \Return_ (new Expr \BinaryOp \LogicalAnd (new Expr \BooleanNot (new Expr \Isset_ ([new Expr \PropertyFetch (new Expr \Variable ('object ' ), $ this ->accessor )])), new Expr \BinaryOp \Identical (new Expr \ConstFetch (new Name ('null ' )), new Expr \PropertyFetch (new Expr \Variable ('object ' ), $ this ->accessor )))),
325+ ],
326+ ])
327+ ),
328+ new Arg (new Expr \ConstFetch (new Name ('null ' ))),
329+ new Arg (new Scalar \String_ ($ className )),
330+ ]);
331+ }
332+
333+ /**
334+ * Get AST expression for binding closure when dealing with a private property.
335+ */
336+ public function getExtractIsUndefinedCallback (string $ className ): ?Expr
337+ {
338+ if ($ this ->type !== self ::TYPE_PROPERTY || !$ this ->private ) {
339+ return null ;
340+ }
341+
264342 /*
265343 * Create extract is null callback for this accessor
266344 *
0 commit comments