vendor/bestit/commercetools-odm/src/DocumentManager.php line 213

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace BestIt\CommercetoolsODM;
  4. use BestIt\CommercetoolsODM\Helper\QueryHelperAwareTrait;
  5. use BestIt\CommercetoolsODM\Mapping\ClassMetadataInterface;
  6. use Commercetools\Commons\Helper\QueryHelper;
  7. use Commercetools\Core\Client;
  8. use Commercetools\Core\Request\AbstractApiRequest;
  9. use Commercetools\Core\Request\AbstractCreateRequest;
  10. use Commercetools\Core\Request\AbstractDeleteRequest;
  11. use Commercetools\Core\Request\AbstractUpdateRequest;
  12. use Doctrine\Common\Persistence\Mapping\ClassMetadata;
  13. use Doctrine\Common\Persistence\Mapping\ClassMetadataFactory;
  14. use Doctrine\Common\Persistence\ObjectRepository;
  15. use DomainException;
  16. use InvalidArgumentException;
  17. use Psr\Log\LoggerAwareTrait;
  18. use Psr\Log\NullLogger;
  19. use ReflectionClass;
  20. use function class_exists;
  21. use function sprintf;
  22. /**
  23. * Basic manager for the commercetools processes.
  24. *
  25. * @author lange <lange@bestit-online.de>
  26. * @package BestIt\CommercetoolsODM
  27. * @todo Add api for multiple clients.
  28. */
  29. class DocumentManager implements DocumentManagerInterface
  30. {
  31. use ClientAwareTrait;
  32. use LoggerAwareTrait;
  33. use MetadataFactoryAwareTrait;
  34. use QueryHelperAwareTrait;
  35. /**
  36. * The unit of work for this manager.
  37. *
  38. * @var UnitOfWorkInterface
  39. */
  40. private $unitOfWork;
  41. /**
  42. * DocumentManager constructor.
  43. *
  44. * @param ClassMetadataFactory $metadataFactory
  45. * @param Client $client
  46. * @param QueryHelper $queryHelper
  47. * @param RepositoryFactoryInterface $repositoryFactory
  48. * @param UnitOfWorkFactoryInterface $unitOfWorkFactory
  49. */
  50. public function __construct(
  51. ClassMetadataFactory $metadataFactory,
  52. Client $client,
  53. QueryHelper $queryHelper,
  54. /**
  55. * The repository factory.
  56. */
  57. private RepositoryFactoryInterface $repositoryFactory,
  58. /**
  59. * The factory for the unit of work.
  60. */
  61. private UnitOfWorkFactoryInterface $unitOfWorkFactory
  62. ) {
  63. $this
  64. ->setClient($client)
  65. ->setMetadataFactory($metadataFactory)
  66. ->setQueryHelper($queryHelper)
  67. ->setLogger(new NullLogger());
  68. }
  69. /**
  70. * Clears the ObjectManager. All objects that are currently managed
  71. * by this ObjectManager become detached.
  72. *
  73. * @param string|null $objectName if given, only objects of this type will get detached.
  74. * @phpcsSuppress SlevomatCodingStandard.TypeHints.TypeHintDeclaration.MissingParameterTypeHint
  75. *
  76. * @return void
  77. */
  78. #[\Override]
  79. public function clear($objectName = null)
  80. {
  81. }
  82. /**
  83. * Checks if the $document is part of the current UnitOfWork and therefore managed.
  84. *
  85. * @param mixed $document
  86. *
  87. * @return bool
  88. */
  89. #[\Override]
  90. public function contains($document): bool
  91. {
  92. return $this->getUnitOfWork()->contains($document);
  93. }
  94. /**
  95. * Returns a request class for fetching/updating/deleting documents using the request map of the given class name.
  96. *
  97. * @throws InvalidArgumentException
  98. *
  99. * @param string $className
  100. * @param string $requestType
  101. * @param mixed $args The optional arguments.
  102. *
  103. * @return AbstractCreateRequest|AbstractUpdateRequest|AbstractDeleteRequest|AbstractApiRequest
  104. */
  105. #[\Override]
  106. public function createRequest(string $className, string $requestType = self::REQUEST_TYPE_QUERY, ...$args)
  107. {
  108. $requestType = $this->getRequestClass($className, $requestType);
  109. return (new ReflectionClass($requestType))->newInstanceArgs($args);
  110. }
  111. /**
  112. * Detaches an object from the ObjectManager, causing a managed object to
  113. * become detached. Unflushed changes made to the object if any
  114. * (including removal of the object), will not be synchronized to the database.
  115. * Objects which previously referenced the detached object will continue to
  116. * reference it.
  117. *
  118. * @param mixed $object The object to detach.
  119. *
  120. * @return void
  121. */
  122. #[\Override]
  123. public function detach($object)
  124. {
  125. $this->getUnitOfWork()->detach($object);
  126. }
  127. /**
  128. * Detaches the given object after flush.
  129. *
  130. * @param mixed $object
  131. *
  132. * @return void
  133. */
  134. #[\Override]
  135. public function detachDeferred($object)
  136. {
  137. $this->getUnitOfWork()->detachDeferred($object);
  138. }
  139. /**
  140. * Finds an object by its identifier.
  141. *
  142. * This is just a convenient shortcut for getRepository($className)->find($id).
  143. *
  144. * @param string $className The class name of the object to find.
  145. * @param mixed $id The identity of the object to find.
  146. *
  147. * @phpcsSuppress SlevomatCodingStandard.TypeHints.TypeHintDeclaration.MissingParameterTypeHint
  148. * @phpcsSuppress BestIt.TypeHints.ReturnTypeDeclaration.MissingReturnTypeHint
  149. *
  150. * @return mixed The found object.
  151. */
  152. #[\Override]
  153. public function find($className, $id)
  154. {
  155. return $this->repositoryFactory->getRepository($this, $className)->find($id);
  156. }
  157. /**
  158. * Flushes all changes to objects that have been queued up to now to the database.
  159. * This effectively synchronizes the in-memory state of managed objects with the
  160. * database.
  161. *
  162. * @return void
  163. */
  164. #[\Override]
  165. public function flush()
  166. {
  167. $this->getUnitOfWork()->flush();
  168. }
  169. /**
  170. * Returns the ClassMetadata descriptor for a class.
  171. *
  172. * The class name must be the fully-qualified class name without a leading backslash
  173. * (as it is returned by get_class($obj)).
  174. *
  175. * @param string $className
  176. * @phpcsSuppress SlevomatCodingStandard.TypeHints.TypeHintDeclaration.MissingParameterTypeHint
  177. * @todo Create a setter and lazy loading for this.
  178. *
  179. * @return ClassMetadata
  180. */
  181. #[\Override]
  182. public function getClassMetadata($className): ClassMetadata
  183. {
  184. return $this->getMetadataFactory()->getMetadataFor($className);
  185. }
  186. /**
  187. * Gets the repository for a class.
  188. *
  189. * @param string $className
  190. * @phpcsSuppress SlevomatCodingStandard.TypeHints.TypeHintDeclaration.MissingParameterTypeHint
  191. *
  192. * @return ObjectRepository
  193. */
  194. #[\Override]
  195. public function getRepository($className): ObjectRepository
  196. {
  197. return $this->repositoryFactory->getRepository($this, $className);
  198. }
  199. /**
  200. * Returns the full qualified class name for the given request type.
  201. *
  202. * @todo Remove out of this class!
  203. *
  204. * @param string $className The class name for which the request is fetched.
  205. * @param string $requestType The type of the request or the request class name it self.
  206. *
  207. * @return string
  208. */
  209. #[\Override]
  210. public function getRequestClass(string $className, string $requestType): string
  211. {
  212. if (!class_exists($requestType)) {
  213. $metadata = $this->getClassMetadata($className);
  214. if (!($metadata instanceof ClassMetadataInterface)) {
  215. throw new InvalidArgumentException('The given metadata class was of the wrong type.');
  216. }
  217. $map = $metadata->getRequestClassMap();
  218. if (!$map) {
  219. throw new InvalidArgumentException(sprintf(
  220. 'There is no request map for %s / %s.',
  221. $className,
  222. $requestType
  223. ));
  224. }
  225. $requestType = $map->{'get' . $requestType}();
  226. if (!class_exists($requestType)) {
  227. throw new DomainException(sprintf(
  228. 'The request type %s for class %s is not declared.',
  229. $requestType,
  230. $className
  231. ));
  232. }
  233. }
  234. return $requestType;
  235. }
  236. /**
  237. * Returns the unit of work for this manager.
  238. *
  239. * @return UnitOfWorkInterface
  240. */
  241. #[\Override]
  242. public function getUnitOfWork(): UnitOfWorkInterface
  243. {
  244. if (!$this->unitOfWork) {
  245. $this->setUnitOfWork($this->unitOfWorkFactory->getUnitOfWork($this));
  246. }
  247. return $this->unitOfWork;
  248. }
  249. /**
  250. * Helper method to initialize a lazy loading proxy or persistent collection.
  251. *
  252. * This method is a no-op for other objects.
  253. *
  254. * @param mixed $obj
  255. *
  256. * @return void
  257. */
  258. #[\Override]
  259. public function initializeObject($obj)
  260. {
  261. }
  262. /**
  263. * Merges the state of a detached object into the persistence context
  264. * of this ObjectManager and returns the managed copy of the object.
  265. * The object passed to merge will not become associated/managed with this ObjectManager.
  266. *
  267. * @param mixed $object
  268. * @phpcsSuppress BestIt.TypeHints.ReturnTypeDeclaration.MissingReturnTypeHint
  269. *
  270. * @return object
  271. */
  272. #[\Override]
  273. public function merge($object)
  274. {
  275. $this->getUnitOfWork()->registerAsManaged($object, $object->getId(), $object->getVersion());
  276. return $object;
  277. }
  278. /**
  279. * This method uses a callback to modify the given object to get conflict resolution in case of a 409 error.
  280. *
  281. * @param mixed $object
  282. * @param callable $change The callback is called with the given object.
  283. *
  284. * @return mixed Returns the changed object.
  285. */
  286. #[\Override]
  287. public function modify($object, callable $change)
  288. {
  289. return $this->getUnitOfWork()->modify($object, $change);
  290. }
  291. /**
  292. * Tells the ObjectManager to make an instance managed and persistent.
  293. *
  294. * The object will be entered into the database as a result of the flush operation.
  295. *
  296. * NOTE: The persist operation always considers objects that are not yet known to
  297. * this ObjectManager as NEW. Do not pass detached objects to the persist operation.
  298. *
  299. * @param mixed $object The instance to make managed and persistent.
  300. *
  301. * @return void
  302. */
  303. #[\Override]
  304. public function persist($object)
  305. {
  306. $this->getUnitOfWork()->scheduleSave($object);
  307. }
  308. /**
  309. * Refreshes the persistent state of an object from the database,
  310. * overriding any local changes that have not yet been persisted.
  311. *
  312. * @param mixed $object The object to refresh.
  313. * @param mixed $overwrite Commercetools returns a representation of the object for many update actions, so use
  314. * this responds directly.
  315. * @return void
  316. */
  317. #[\Override]
  318. public function refresh($object, $overwrite = null)
  319. {
  320. $this->getUnitOfWork()->refresh($object, $overwrite);
  321. }
  322. /**
  323. * Removes an object instance.
  324. *
  325. * A removed object will be removed from the database as a result of the flush operation.
  326. *
  327. * @param mixed $object The object instance to remove.
  328. *
  329. * @return void
  330. */
  331. #[\Override]
  332. public function remove($object)
  333. {
  334. $this->getUnitOfWork()->scheduleRemove($object);
  335. }
  336. /**
  337. * Sets the unit of work for this manager.
  338. *
  339. * @param UnitOfWorkInterface $unitOfWork
  340. *
  341. * @return DocumentManager
  342. */
  343. protected function setUnitOfWork(UnitOfWorkInterface $unitOfWork): DocumentManager
  344. {
  345. $this->unitOfWork = $unitOfWork;
  346. return $this;
  347. }
  348. }