PageRenderTime 56ms CodeModel.GetById 31ms RepoModel.GetById 0ms app.codeStats 0ms

/src/Faker/ORM/Doctrine/EntityPopulator.php

http://github.com/fzaninotto/Faker
PHP | 251 lines | 166 code | 33 blank | 52 comment | 26 complexity | 496d85c572c9ae4b475438aff148a9cb MD5 | raw file
  1. <?php
  2. namespace Faker\ORM\Doctrine;
  3. use Doctrine\Common\Persistence\ObjectManager;
  4. use Doctrine\Common\Persistence\Mapping\ClassMetadata;
  5. /**
  6. * Service class for populating a table through a Doctrine Entity class.
  7. */
  8. class EntityPopulator
  9. {
  10. /**
  11. * @var ClassMetadata
  12. */
  13. protected $class;
  14. /**
  15. * @var array
  16. */
  17. protected $columnFormatters = array();
  18. /**
  19. * @var array
  20. */
  21. protected $modifiers = array();
  22. /**
  23. * Class constructor.
  24. *
  25. * @param ClassMetadata $class
  26. */
  27. public function __construct(ClassMetadata $class)
  28. {
  29. $this->class = $class;
  30. }
  31. /**
  32. * @return string
  33. */
  34. public function getClass()
  35. {
  36. return $this->class->getName();
  37. }
  38. /**
  39. * @param $columnFormatters
  40. */
  41. public function setColumnFormatters($columnFormatters)
  42. {
  43. $this->columnFormatters = $columnFormatters;
  44. }
  45. /**
  46. * @return array
  47. */
  48. public function getColumnFormatters()
  49. {
  50. return $this->columnFormatters;
  51. }
  52. public function mergeColumnFormattersWith($columnFormatters)
  53. {
  54. $this->columnFormatters = array_merge($this->columnFormatters, $columnFormatters);
  55. }
  56. /**
  57. * @param array $modifiers
  58. */
  59. public function setModifiers(array $modifiers)
  60. {
  61. $this->modifiers = $modifiers;
  62. }
  63. /**
  64. * @return array
  65. */
  66. public function getModifiers()
  67. {
  68. return $this->modifiers;
  69. }
  70. /**
  71. * @param array $modifiers
  72. */
  73. public function mergeModifiersWith(array $modifiers)
  74. {
  75. $this->modifiers = array_merge($this->modifiers, $modifiers);
  76. }
  77. /**
  78. * @param \Faker\Generator $generator
  79. * @return array
  80. */
  81. public function guessColumnFormatters(\Faker\Generator $generator)
  82. {
  83. $formatters = array();
  84. $nameGuesser = new \Faker\Guesser\Name($generator);
  85. $columnTypeGuesser = new ColumnTypeGuesser($generator);
  86. foreach ($this->class->getFieldNames() as $fieldName) {
  87. if ($this->class->isIdentifier($fieldName) || !$this->class->hasField($fieldName)) {
  88. continue;
  89. }
  90. $size = isset($this->class->fieldMappings[$fieldName]['length']) ? $this->class->fieldMappings[$fieldName]['length'] : null;
  91. if ($formatter = $nameGuesser->guessFormat($fieldName, $size)) {
  92. $formatters[$fieldName] = $formatter;
  93. continue;
  94. }
  95. if ($formatter = $columnTypeGuesser->guessFormat($fieldName, $this->class)) {
  96. $formatters[$fieldName] = $formatter;
  97. continue;
  98. }
  99. }
  100. foreach ($this->class->getAssociationNames() as $assocName) {
  101. if ($this->class->isCollectionValuedAssociation($assocName)) {
  102. continue;
  103. }
  104. $relatedClass = $this->class->getAssociationTargetClass($assocName);
  105. $unique = $optional = false;
  106. if ($this->class instanceof \Doctrine\ORM\Mapping\ClassMetadata) {
  107. $mappings = $this->class->getAssociationMappings();
  108. foreach ($mappings as $mapping) {
  109. if ($mapping['targetEntity'] == $relatedClass) {
  110. if ($mapping['type'] == \Doctrine\ORM\Mapping\ClassMetadata::ONE_TO_ONE) {
  111. $unique = true;
  112. $optional = isset($mapping['joinColumns'][0]['nullable']) ? $mapping['joinColumns'][0]['nullable'] : false;
  113. break;
  114. }
  115. }
  116. }
  117. } elseif ($this->class instanceof \Doctrine\ODM\MongoDB\Mapping\ClassMetadata) {
  118. $mappings = $this->class->associationMappings;
  119. foreach ($mappings as $mapping) {
  120. if ($mapping['targetDocument'] == $relatedClass) {
  121. if ($mapping['type'] == \Doctrine\ODM\MongoDB\Mapping\ClassMetadata::ONE && $mapping['association'] == \Doctrine\ODM\MongoDB\Mapping\ClassMetadata::REFERENCE_ONE) {
  122. $unique = true;
  123. $optional = isset($mapping['nullable']) ? $mapping['nullable'] : false;
  124. break;
  125. }
  126. }
  127. }
  128. }
  129. $index = 0;
  130. $formatters[$assocName] = function ($inserted) use ($relatedClass, &$index, $unique, $optional) {
  131. if (isset($inserted[$relatedClass])) {
  132. if ($unique) {
  133. $related = null;
  134. if (isset($inserted[$relatedClass][$index]) || !$optional) {
  135. $related = $inserted[$relatedClass][$index];
  136. }
  137. $index++;
  138. return $related;
  139. }
  140. return $inserted[$relatedClass][mt_rand(0, count($inserted[$relatedClass]) - 1)];
  141. }
  142. return null;
  143. };
  144. }
  145. return $formatters;
  146. }
  147. /**
  148. * Insert one new record using the Entity class.
  149. * @param ObjectManager $manager
  150. * @param bool $generateId
  151. * @return EntityPopulator
  152. */
  153. public function execute(ObjectManager $manager, $insertedEntities, $generateId = false)
  154. {
  155. $obj = $this->class->newInstance();
  156. $this->fillColumns($obj, $insertedEntities);
  157. $this->callMethods($obj, $insertedEntities);
  158. if ($generateId) {
  159. $idsName = $this->class->getIdentifier();
  160. foreach ($idsName as $idName) {
  161. $id = $this->generateId($obj, $idName, $manager);
  162. $this->class->reflFields[$idName]->setValue($obj, $id);
  163. }
  164. }
  165. $manager->persist($obj);
  166. return $obj;
  167. }
  168. private function fillColumns($obj, $insertedEntities)
  169. {
  170. foreach ($this->columnFormatters as $field => $format) {
  171. if (null !== $format) {
  172. // Add some extended debugging information to any errors thrown by the formatter
  173. try {
  174. $value = is_callable($format) ? $format($insertedEntities, $obj) : $format;
  175. } catch (\InvalidArgumentException $ex) {
  176. throw new \InvalidArgumentException(sprintf(
  177. "Failed to generate a value for %s::%s: %s",
  178. get_class($obj),
  179. $field,
  180. $ex->getMessage()
  181. ));
  182. }
  183. // Try a standard setter if it's available, otherwise fall back on reflection
  184. $setter = sprintf("set%s", ucfirst($field));
  185. if (is_callable(array($obj, $setter))) {
  186. $obj->$setter($value);
  187. } else {
  188. $this->class->reflFields[$field]->setValue($obj, $value);
  189. }
  190. }
  191. }
  192. }
  193. private function callMethods($obj, $insertedEntities)
  194. {
  195. foreach ($this->getModifiers() as $modifier) {
  196. $modifier($obj, $insertedEntities);
  197. }
  198. }
  199. /**
  200. * @param ObjectManager $manager
  201. * @return int|null
  202. */
  203. private function generateId($obj, $column, ObjectManager $manager)
  204. {
  205. /* @var $repository \Doctrine\Common\Persistence\ObjectRepository */
  206. $repository = $manager->getRepository(get_class($obj));
  207. $result = $repository->createQueryBuilder('e')
  208. ->select(sprintf('e.%s', $column))
  209. ->getQuery()
  210. ->execute();
  211. $ids = array_map('current', $result->toArray());
  212. $id = null;
  213. do {
  214. $id = mt_rand();
  215. } while (in_array($id, $ids));
  216. return $id;
  217. }
  218. }