metadata = $metadata; } /** * Get pattern for specified groups. * * @param array $groups Serialization groups. * * @return array */ public function getPattern(array $groups) { sort($groups); $key = serialize($groups); if (! isset($this->cache[$key])) { $properties = $this->metadata->getProperties($groups); $this->cache[$key] = []; if ($this->metadata->implementsInterface(EntityInterface::class)) { $this->cache[$key]['type'] = '@string@'; } foreach ($properties as $property) { $this->cache[$key][$property->getName()] = $this->generateProperty($property, $groups); } } return $this->cache[$key]; } /** * Convert from entity metadata type to PHPMatcher type. * * @param PropertyMetadata $property A PropertyMetadata instance. * @param array $groups A serialization groups. * * @return string */ private function generateProperty(PropertyMetadata $property, array $groups) { $type = $property->getType(); switch ($type) { // Associated object - another entity. // Use entity expander with same serialization groups. case PropertyMetadata::TYPE_ENTITY: $type = \app\c\entityFqcnToShort($property->getActualType()); $expander = "entity('{$type}', '". implode(',', $groups) ."')"; $type = "@object@.{$expander}"; if ($property->isNullable()) { $type = "@wildcard@.oneOf(isEmpty(), {$expander})"; } break; // Enum type. case PropertyMetadata::TYPE_ENUM: $type = '@string@'; break; // Collection of associated entities. case PropertyMetadata::TYPE_COLLECTION: $type = \app\c\entityFqcnToShort($property->getActualType()); $reflection = new \ReflectionClass($property->getActualType()); if ($reflection->isAbstract()) { $type = '@array@'; } else { $expander = "entity('{$type}', '" . implode(',', $groups) . "')"; $type = "@array@.every({$expander})"; if ($property->isNullable()) { $type = "@wildcard@.oneOf(isEmpty(), every({$expander}))"; } } break; // For double type also use integer type checker. case PropertyMetadata::TYPE_DOUBLE: $type = "@wildcard@.oneOf(type('integer'), type('double'))"; if ($property->isNullable()) { $type = "@wildcard@.oneOf(isEmpty(), type('integer'), type('double'))"; } break; // For DateTime instances use 'string' matcher with 'isDateTime' // expander. case PropertyMetadata::TYPE_DATE: $type = '@string@.isDateTime()'; if ($property->isNullable()) { $type = '@wildcard@.oneOf(isEmpty(), isDateTime())'; } break; // Process inline objects. case PropertyMetadata::TYPE_GROUP: $type = '@object@'; if ($property->isNullable()) { $type = '@wildcard@'; } break; // Other types like string, integer and etc. default: if ($property->isNullable()) { $type = "@wildcard@.oneOf(isEmpty(), type('$type'))"; } else { $type = '@'. $type .'@'; } } return $type; } }