/vendor/jms/cg/src/CG/Proxy/Enhancer.php

https://github.com/nattaphat/hgis · PHP · 158 lines · 93 code · 25 blank · 40 comment · 10 complexity · dad36789a563dac22811b86cf28d47ae MD5 · raw file

  1. <?php
  2. /*
  3. * Copyright 2011 Johannes M. Schmitt <schmittjoh@gmail.com>
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. namespace CG\Proxy;
  18. use CG\Core\NamingStrategyInterface;
  19. use CG\Generator\Writer;
  20. use CG\Generator\PhpMethod;
  21. use CG\Generator\PhpDocblock;
  22. use CG\Generator\PhpClass;
  23. use CG\Core\AbstractClassGenerator;
  24. /**
  25. * Class enhancing generator implementation.
  26. *
  27. * This class enhances existing classes by generating a proxy and leveraging
  28. * different generator implementation.
  29. *
  30. * There are several built-in generator such as lazy-initializing objects, or
  31. * a generator for creating AOP joinpoints.
  32. *
  33. * @author Johannes M. Schmitt <schmittjoh@gmail.com>
  34. */
  35. class Enhancer extends AbstractClassGenerator
  36. {
  37. private $generatedClass;
  38. private $class;
  39. private $interfaces;
  40. private $generators;
  41. public function __construct(\ReflectionClass $class, array $interfaces = array(), array $generators = array())
  42. {
  43. if (empty($generators) && empty($interfaces)) {
  44. throw new \RuntimeException('Either generators, or interfaces must be given.');
  45. }
  46. $this->class = $class;
  47. $this->interfaces = $interfaces;
  48. $this->generators = $generators;
  49. }
  50. /**
  51. * Creates a new instance of the enhanced class.
  52. *
  53. * @param array $args
  54. * @return object
  55. */
  56. public function createInstance(array $args = array())
  57. {
  58. $generatedClass = $this->getClassName($this->class);
  59. if (!class_exists($generatedClass, false)) {
  60. eval($this->generateClass());
  61. }
  62. $ref = new \ReflectionClass($generatedClass);
  63. return $ref->newInstanceArgs($args);
  64. }
  65. public function writeClass($filename)
  66. {
  67. if (!is_dir($dir = dirname($filename))) {
  68. if (false === @mkdir($dir, 0777, true)) {
  69. throw new \RuntimeException(sprintf('Could not create directory "%s".', $dir));
  70. }
  71. }
  72. if (!is_writable($dir)) {
  73. throw new \RuntimeException(sprintf('The directory "%s" is not writable.', $dir));
  74. }
  75. file_put_contents($filename, "<?php\n\n".$this->generateClass());
  76. }
  77. /**
  78. * Creates a new enhanced class
  79. *
  80. * @return string
  81. */
  82. public final function generateClass()
  83. {
  84. static $docBlock;
  85. if (empty($docBlock)) {
  86. $writer = new Writer();
  87. $writer
  88. ->writeln('/**')
  89. ->writeln(' * CG library enhanced proxy class.')
  90. ->writeln(' *')
  91. ->writeln(' * This code was generated automatically by the CG library, manual changes to it')
  92. ->writeln(' * will be lost upon next generation.')
  93. ->writeln(' */')
  94. ;
  95. $docBlock = $writer->getContent();
  96. }
  97. $this->generatedClass = PhpClass::create()
  98. ->setDocblock($docBlock)
  99. ->setParentClassName($this->class->name)
  100. ;
  101. $proxyClassName = $this->getClassName($this->class);
  102. if (false === strpos($proxyClassName, NamingStrategyInterface::SEPARATOR)) {
  103. throw new \RuntimeException(sprintf('The proxy class name must be suffixed with "%s" and an optional string, but got "%s".', NamingStrategyInterface::SEPARATOR, $proxyClassName));
  104. }
  105. $this->generatedClass->setName($proxyClassName);
  106. if (!empty($this->interfaces)) {
  107. $this->generatedClass->setInterfaceNames(array_map(function($v) { return '\\'.$v; }, $this->interfaces));
  108. foreach ($this->getInterfaceMethods() as $method) {
  109. $method = PhpMethod::fromReflection($method);
  110. $method->setAbstract(false);
  111. $this->generatedClass->setMethod($method);
  112. }
  113. }
  114. if (!empty($this->generators)) {
  115. foreach ($this->generators as $generator) {
  116. $generator->generate($this->class, $this->generatedClass);
  117. }
  118. }
  119. return $this->generateCode($this->generatedClass);
  120. }
  121. /**
  122. * Adds stub methods for the interfaces that have been implemented.
  123. */
  124. protected function getInterfaceMethods()
  125. {
  126. $methods = array();
  127. foreach ($this->interfaces as $interface) {
  128. $ref = new \ReflectionClass($interface);
  129. $methods = array_merge($methods, $ref->getMethods());
  130. }
  131. return $methods;
  132. }
  133. }