Skip to content

Commit

Permalink
speed up hydration a bit
Browse files Browse the repository at this point in the history
  • Loading branch information
kaleta committed Jun 17, 2022
1 parent ca1e0c9 commit 3cc01dd
Show file tree
Hide file tree
Showing 2 changed files with 218 additions and 251 deletions.
157 changes: 66 additions & 91 deletions Hydrator/ReadOnlyHydrator.php
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -9,29 +9,20 @@

class ReadOnlyHydrator extends SimpleObjectHydrator
{
const HYDRATOR_NAME = 'readOnly';
public const HYDRATOR_NAME = 'readOnly';

/** @var string[] */
protected $proxyFilePathsCache = [];
protected array $proxyFilePathsCache = [];
protected array $proxyNamespacesCache = [];
protected array $proxyClassNamesCache = [];
protected ?string $proxyDirectoryCache = null;

/** @var string[] */
protected $proxyNamespacesCache = [];

/** @var string[] */
protected $proxyClassNamesCache = [];

/**
* @param ClassMetadata $classMetaData
* @param array $data
* @return mixed
* @throws \Exception
*/
protected function createEntity(ClassMetadata $classMetaData, array $data)
protected function createEntity(ClassMetadata $classMetaData, array $data): object
{
$className = $this->getEntityClassName($classMetaData, $data);
$this->generateProxyFile($classMetaData, $data);
$proxyFilePath = $this->generateProxyFile($classMetaData, $data);

require_once($proxyFilePath);

require_once($this->getProxyFilePath($className));
$proxyClassName = $this->getProxyNamespace($className) . '\\' . $this->getProxyClassName($className);
$entity = new $proxyClassName(array_keys($data));

Expand All @@ -40,103 +31,95 @@ protected function createEntity(ClassMetadata $classMetaData, array $data)
return $entity;
}

/**
* @param ClassMetadata $classMetaData
* @param array $data
* @return $this
*/
protected function generateProxyFile(ClassMetadata $classMetaData, array $data)
protected function generateProxyFile(ClassMetadata $classMetaData, array $data): string
{
$entityClassName = $this->getEntityClassName($classMetaData, $data);

$proxyFilePath = $this->getProxyFilePath($entityClassName);
if (file_exists($proxyFilePath) === false) {
$proxyMethodsCode = implode("\n\n", $this->getPhpForProxyMethods($classMetaData, $entityClassName));
$proxyNamespace = $this->getProxyNamespace($entityClassName);
$proxyClassName = $this->getProxyClassName($entityClassName);
$generator = static::class;
$readOnlyInterface = ReadOnlyEntityInterface::class;

$php = <<<PHP
if (file_exists($proxyFilePath)) {
return $proxyFilePath;
}

$proxyMethodsCode = implode("\n\n", $this->getPhpForProxyMethods($classMetaData, $entityClassName));

$proxyNamespace = $this->getProxyNamespace($entityClassName);
$proxyClassName = $this->getProxyClassName($entityClassName);

$generator = static::class;
$readOnlyInterface = ReadOnlyEntityInterface::class;

$php = <<<PHP
<?php
namespace $proxyNamespace;
/**
* DO NOT EDIT THIS FILE - IT WAS CREATED BY $generator
*/
* DO NOT EDIT THIS FILE - IT WAS CREATED BY $generator
*/
class $proxyClassName extends \\$entityClassName implements \\$readOnlyInterface
{
protected \$loadedProperties;
protected \$loadedProperties;
public function __construct(array \$loadedProperties)
{
\$this->loadedProperties = \$loadedProperties;
}
public function __construct(array \$loadedProperties)
{
\$this->loadedProperties = \$loadedProperties;
}
$proxyMethodsCode
public function isReadOnlyPropertiesLoaded(array \$properties)
{
\$return = true;
foreach (\$properties as \$property) {
if (in_array(\$property, \$this->loadedProperties) === false) {
\$return = false;
break;
}
public function isReadOnlyPropertiesLoaded(array \$properties)
{
\$return = true;
foreach (\$properties as \$property) {
if (in_array(\$property, \$this->loadedProperties) === false) {
\$return = false;
break;
}
return \$return;
}
public function assertReadOnlyPropertiesAreLoaded(array \$properties)
{
foreach (\$properties as \$property) {
if (in_array(\$property, \$this->loadedProperties) === false) {
throw new \steevanb\DoctrineReadOnlyHydrator\Exception\PropertyNotLoadedException(\$this, \$property);
}
return \$return;
}
public function assertReadOnlyPropertiesAreLoaded(array \$properties)
{
foreach (\$properties as \$property) {
if (in_array(\$property, \$this->loadedProperties) === false) {
throw new \steevanb\DoctrineReadOnlyHydrator\Exception\PropertyNotLoadedException(\$this, \$property);
}
}
}
}
PHP;
file_put_contents($proxyFilePath, $php);
}
file_put_contents($proxyFilePath, $php);

return $this;
return $proxyFilePath;
}

/**
* @param string $entityClassName
* @return string
*/
public function getProxyFilePath($entityClassName)
public function getProxyFilePath(string $entityClassName): string
{
if (isset($this->proxyFilePathsCache[$entityClassName]) === false) {
if (!isset($this->proxyFilePathsCache[$entityClassName])) {
$fileName = str_replace('\\', '_', $entityClassName) . '.php';
$this->proxyFilePathsCache[$entityClassName] = $this->getProxyDirectory() . DIRECTORY_SEPARATOR . $fileName;

if($this->proxyDirectoryCache === null) {
$this->proxyDirectoryCache = $this->getProxyDirectory();
}

$this->proxyFilePathsCache[$entityClassName] = $this->proxyDirectoryCache . DIRECTORY_SEPARATOR . $fileName;
}

return $this->proxyFilePathsCache[$entityClassName];
}

/**
* @param string $entityClassName
* @return string
*/
protected function getProxyNamespace($entityClassName)
protected function getProxyNamespace(string $entityClassName): string
{
if (isset($this->proxyNamespacesCache[$entityClassName]) === false) {
$this->proxyNamespacesCache[$entityClassName] =
'ReadOnlyProxies\\' . substr($entityClassName, 0, strrpos($entityClassName, '\\'));
$this->proxyNamespacesCache[$entityClassName] = 'ReadOnlyProxies\\' . substr($entityClassName, 0, strrpos($entityClassName, '\\'));
}

return $this->proxyNamespacesCache[$entityClassName];
}

/**
* @param string $entityClassName
* @return string
*/
protected function getProxyClassName($entityClassName)
protected function getProxyClassName(string $entityClassName): string
{
if (isset($this->proxyClassNamesCache[$entityClassName]) === false) {
$this->proxyClassNamesCache[$entityClassName] =
Expand All @@ -150,17 +133,15 @@ protected function getProxyClassName($entityClassName)
* As Doctrine\ORM\EntityManager::newHydrator() call new FooHydrator($this), we can't set parameters to Hydrator.
* So, we will use proxyDirectory from Doctrine\Common\Proxy\AbstractProxyFactory.
* It's directory used by Doctrine\ORM\Internal\Hydration\ObjectHydrator.
*
* @return string
*/
protected function getProxyDirectory()
protected function getProxyDirectory(): string
{
/** @var ProxyGenerator $proxyGenerator */
$proxyGenerator = $this->getPrivatePropertyValue($this->_em->getProxyFactory(), 'proxyGenerator');

$directory = $this->getPrivatePropertyValue($proxyGenerator, 'proxyDirectory');

$readOnlyDirectory = $directory . DIRECTORY_SEPARATOR . 'ReadOnly';
if (is_dir($readOnlyDirectory) === false) {
if (!is_dir($readOnlyDirectory)) {
mkdir($readOnlyDirectory, 0775, true);
}

Expand Down Expand Up @@ -200,13 +181,7 @@ protected function getUsedProperties(\ReflectionMethod $reflectionMethod, $prope
return array_keys($return);
}

/**
* @param ClassMetadata $classMetaData
* @param string $entityClassName
* @return array
* @throws PrivateMethodShouldNotAccessPropertiesException
*/
protected function getPhpForProxyMethods(ClassMetadata $classMetaData, $entityClassName)
protected function getPhpForProxyMethods(ClassMetadata $classMetaData, string $entityClassName): array
{
$return = [];
$reflectionClass = new \ReflectionClass($entityClassName);
Expand Down Expand Up @@ -333,7 +308,7 @@ protected function getPhpForParameter(\ReflectionParameter $parameter)
} else {
$types = [$types];
}

$values = [];
$hasNull = false;
$needsNull = false;
Expand Down Expand Up @@ -399,7 +374,7 @@ protected function getFullQualifiedClassName($className)
{
return '\\' . ltrim($className, '\\');
}

/**
* @param \ReflectionType $reflectionType
* @return string
Expand Down
Loading

0 comments on commit 3cc01dd

Please sign in to comment.