Skip to content

Commit

Permalink
Merge pull request #1 from dotkernel/doctrine-metadata
Browse files Browse the repository at this point in the history
Doctrine metadata
  • Loading branch information
MarioRadu authored Jan 13, 2021
2 parents 28d6ea9 + 1f19f30 commit a1c5e25
Show file tree
Hide file tree
Showing 6 changed files with 239 additions and 2 deletions.
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2020 DotKernel
Copyright (c) 2021 DotKernel

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Provides metadata and strategies for extracting and rendering Doctrine entities
### Requirements
- PHP >= 7.4
- mezzio/mezzio-hal >= 1.3.1,
- doctrine >= ?
- doctrine >=

https://github.com/mezzio/mezzio-hal/pull/8

Expand Down
39 changes: 39 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"name": "dotkernel/dot-doctrine-metadata",
"type": "library",
"description": "DotKernel wrapper that sits on top of mezzio-hal package and resolves the doctrine proxy issues. ",
"license": "MIT",
"homepage": "https://github.com/dotkernel/dot-doctrine-metadata",
"authors": [
{
"name": "DotKernel Team",
"email": "[email protected]"
}
],
"keywords": [
"dotkernel",
"api",
"metadata",
"doctrine",
"laminas",
"mezzio",
"doctrine-proxy",
"doctrine-entities",
"doctrine-metadata",
"mezzio-hal"
],
"require": {
"php": "^7.4",
"mezzio/mezzio-hal": "^2.0",
"doctrine/orm": "^2.8"
},
"require-dev": {
"phpunit/phpunit": "^9.1",
"squizlabs/php_codesniffer": "^3.5"
},
"autoload": {
"psr-4": {
"Dot\\DoctrineMetadata\\": "src"
}
}
}
32 changes: 32 additions & 0 deletions src/ConfigProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php


namespace Dot\DoctrineMetadata;

use Dot\DoctrineMetadata\Factory\DoctrineMetadataMapFactory;
use Mezzio\Hal\Metadata\MetadataMap;

class ConfigProvider
{
/**
* @return array
*/
public function __invoke(): array
{
return [
'dependencies' => $this->getDependencies(),
];
}

/**
* @return array
*/
public function getDependencies(): array
{
return [
'factories' => [
MetadataMap::class => DoctrineMetadataMapFactory::class,
],
];
}
}
132 changes: 132 additions & 0 deletions src/Factory/DoctrineMetadataMapFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
<?php


namespace Dot\DoctrineMetadata\Factory;


use Dot\DoctrineMetadata\Metadata\DoctrineMetadataMap;
use Mezzio\Hal\Metadata\AbstractMetadata;
use Mezzio\Hal\Metadata\Exception\InvalidConfigException;
use Mezzio\Hal\Metadata\MetadataFactoryInterface;
use Mezzio\Hal\Metadata\MetadataMap;
use Psr\Container\ContainerInterface;

class DoctrineMetadataMapFactory
{
public function __invoke(ContainerInterface $container): MetadataMap
{
$config = $container->has('config') ? $container->get('config') : [];
$metadataMapConfig = $config[MetadataMap::class] ?? [];

if (! is_array($metadataMapConfig)) {
throw InvalidConfigException::dueToNonArray($metadataMapConfig);
}

$metadataFactories = $config['mezzio-hal']['metadata-factories'] ?? [];

return $this->populateMetadataMapFromConfig(
new DoctrineMetadataMap(),
$metadataMapConfig,
$metadataFactories
);
}

private function populateMetadataMapFromConfig(
MetadataMap $metadataMap,
array $metadataMapConfig,
array $metadataFactories
): MetadataMap {
foreach ($metadataMapConfig as $metadata) {
if (! is_array($metadata)) {
throw InvalidConfigException::dueToNonArrayMetadata($metadata);
}
$this->injectMetadata($metadataMap, $metadata, $metadataFactories);
}
return $metadataMap;
}

private function injectMetadata(MetadataMap $metadataMap, array $metadata, array $metadataFactories): void
{
if (! isset($metadata['__class__'])) {
throw InvalidConfigException::dueToMissingMetadataClass();
}

if (! class_exists($metadata['__class__'])) {
throw InvalidConfigException::dueToInvalidMetadataClass($metadata['__class__']);
}

$metadataClass = $metadata['__class__'];
if (! in_array(AbstractMetadata::class, class_parents($metadataClass), true)) {
throw InvalidConfigException::dueToNonMetadataClass($metadataClass);
}

if (isset($metadataFactories[$metadataClass])) {
// A factory was registered. Use it!
$metadataMap->add($this->createMetadataViaFactoryClass(
$metadataClass,
$metadata,
$metadataFactories[$metadataClass]
));
return;
}

// No factory was registered. Use the deprecated factory method.
$metadataMap->add($this->createMetadataViaFactoryMethod(
$metadataClass,
$metadata
));
}

/**
* Uses the registered factory class to create the metadata instance.
*
* @param string $metadataClass
* @param array $metadata
* @param string $factoryClass
* @return AbstractMetadata
*/
private function createMetadataViaFactoryClass(
string $metadataClass,
array $metadata,
string $factoryClass
): AbstractMetadata {
if (! in_array(MetadataFactoryInterface::class, class_implements($factoryClass), true)) {
throw InvalidConfigException::dueToInvalidMetadataFactoryClass($factoryClass);
}

$factory = new $factoryClass();
/** @var MetadataFactoryInterface $factory */
return $factory->createMetadata($metadataClass, $metadata);
}

/**
* Call the factory method in this class namend "createMyMetadata(array $metadata)".
*
* This function is to ensure backwards compatibility with versions prior to 0.6.0.
*
* @param string $metadataClass
* @param array $metadata
* @return AbstractMetadata
*/
private function createMetadataViaFactoryMethod(string $metadataClass, array $metadata): AbstractMetadata
{
$normalizedClass = $this->stripNamespaceFromClass($metadataClass);
$method = sprintf('create%s', $normalizedClass);

if (! method_exists($this, $method)) {
throw InvalidConfigException::dueToUnrecognizedMetadataClass($metadataClass);
}

return $this->$method($metadata);
}

/**
* @param string $class
* @return string
*/
private function stripNamespaceFromClass(string $class): string
{
$segments = explode('\\', $class);
return array_pop($segments);
}
}
34 changes: 34 additions & 0 deletions src/Metadata/DoctrineMetadataMap.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php


namespace Dot\DoctrineMetadata\Metadata;

use Mezzio\Hal\Metadata\MetadataMap;
use Doctrine\Common\Util\ClassUtils;
use Mezzio\Hal\Metadata\AbstractMetadata;

class DoctrineMetadataMap extends MetadataMap
{
/**
* Overwrites the $class namespace, ensuring it will always be a real class namespace, not a proxy representation.
*
* @param string $class
* @return bool
*/
public function has(string $class) : bool
{
$class = ClassUtils::getRealClass($class);
return parent::has($class);
}

/**
* Overwrites the $class namespace, ensuring it will always be a real class namespace, not a proxy representation.
*
* @param string $class
* @return AbstractMetadata
*/
public function get(string $class) : AbstractMetadata {
$class = ClassUtils::getRealClass($class);
return parent::get($class);
}
}

0 comments on commit a1c5e25

Please sign in to comment.