2
0

Repository.php 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. <?php
  2. namespace PhpDevCommunity\PaperORM\Repository;
  3. use LogicException;
  4. use PhpDevCommunity\PaperORM\Entity\EntityInterface;
  5. use PhpDevCommunity\PaperORM\EntityManager;
  6. use PhpDevCommunity\PaperORM\Expression\Expr;
  7. use PhpDevCommunity\PaperORM\Hydrator\EntityHydrator;
  8. use PhpDevCommunity\PaperORM\Mapper\ColumnMapper;
  9. use PhpDevCommunity\PaperORM\Mapper\EntityMapper;
  10. use PhpDevCommunity\PaperORM\Proxy\ProxyInterface;
  11. use PhpDevCommunity\PaperORM\Query\Fetcher;
  12. use PhpDevCommunity\PaperORM\Query\QueryBuilder;
  13. use PhpDevCommunity\PaperORM\Serializer\SerializerToDb;
  14. abstract class Repository
  15. {
  16. private EntityManager $em;
  17. public function __construct(EntityManager $em)
  18. {
  19. $this->em = $em;
  20. }
  21. /**
  22. * Get the name of the table associated with this repository.
  23. *
  24. * @return string The name of the table.
  25. */
  26. final public function getTableName(): string
  27. {
  28. $entityName = $this->getEntityName();
  29. return EntityMapper::getTable($entityName);
  30. }
  31. /**
  32. * Get the name of the model associated with this repository.
  33. *
  34. * @return class-string<EntityInterface> The name of the model.
  35. */
  36. abstract public function getEntityName(): string;
  37. public function find(int $pk): Fetcher
  38. {
  39. $entityName = $this->getEntityName();
  40. $primaryKeyColumn = ColumnMapper::getPrimaryKeyColumnName($entityName);
  41. return $this->findBy()->where(Expr::equal($primaryKeyColumn, $pk))->first();
  42. }
  43. public function findBy(array $arguments = []): Fetcher
  44. {
  45. $expressions = [];
  46. foreach ($arguments as $key => $value) {
  47. $expressions[] = Expr::equal($key, $value);
  48. }
  49. return (new Fetcher($this->qb(), true))->where(...$expressions);
  50. }
  51. public function where(Expr ...$expressions): Fetcher
  52. {
  53. return (new Fetcher($this->qb(), true))->where(...$expressions);
  54. }
  55. public function insert(object $entityToInsert): int
  56. {
  57. $this->checkEntity($entityToInsert);
  58. if ($entityToInsert->getPrimaryKeyValue() !== null) {
  59. throw new LogicException(static::class . sprintf(' Cannot insert an entity %s with a primary key ', get_class($entityToInsert)));
  60. }
  61. $qb = \PhpDevCommunity\Sql\QueryBuilder::insert($this->getTableName());
  62. $values = [];
  63. foreach ((new SerializerToDb($entityToInsert))->serialize() as $key => $value) {
  64. $keyWithoutBackticks = str_replace("`", "", $key);
  65. $qb->setValue($key, ":$keyWithoutBackticks");
  66. $values[$keyWithoutBackticks] = $value;
  67. }
  68. $rows = $this->em->getConnection()->executeStatement($qb, $values);
  69. $lastInsertId = $this->em->getConnection()->getPdo()->lastInsertId();
  70. if ($rows > 0) {
  71. $primaryKeyColumn = ColumnMapper::getPrimaryKeyColumnName($entityToInsert);
  72. (new EntityHydrator($this->em->getCache()))->hydrate($entityToInsert, [$primaryKeyColumn => $lastInsertId]);
  73. }
  74. return $rows;
  75. }
  76. public function update(object $entityToUpdate): int
  77. {
  78. $this->checkEntity($entityToUpdate, true);
  79. if ($entityToUpdate->getPrimaryKeyValue() === null) {
  80. throw new LogicException(static::class . sprintf(' Cannot update an entity %s without a primary key ', get_class($entityToUpdate)));
  81. }
  82. /**
  83. * @var ProxyInterface|EntityInterface $entityToUpdate
  84. */
  85. if (!$entityToUpdate->__wasModified()) {
  86. return 0;
  87. }
  88. $qb = \PhpDevCommunity\Sql\QueryBuilder::update($this->getTableName())
  89. ->where(
  90. sprintf('`%s` = %s',
  91. ColumnMapper::getPrimaryKeyColumnName($this->getEntityName()),
  92. $entityToUpdate->getPrimaryKeyValue()
  93. )
  94. );
  95. $values = [];
  96. foreach ((new SerializerToDb($entityToUpdate))->serialize($entityToUpdate->__getPropertiesModified()) as $key => $value) {
  97. $keyWithoutBackticks = str_replace("`", "", $key);
  98. $qb->set($key, ":$keyWithoutBackticks");
  99. $values[$keyWithoutBackticks] = $value;
  100. }
  101. $rows = $this->em->getConnection()->executeStatement($qb, $values);
  102. if ($rows > 0) {
  103. $entityToUpdate->__reset();
  104. }
  105. return $rows;
  106. }
  107. public function delete(object $entityToDelete): int
  108. {
  109. /**
  110. * @var ProxyInterface|EntityInterface $entityToUpdate
  111. */
  112. $this->checkEntity($entityToDelete, true);
  113. if ($entityToDelete->getPrimaryKeyValue() === null) {
  114. throw new LogicException(static::class . sprintf(' Cannot delete an entity %s without a primary key ', get_class($entityToDelete)));
  115. }
  116. $qb = \PhpDevCommunity\Sql\QueryBuilder::delete($this->getTableName())
  117. ->where(
  118. sprintf('`%s` = %s',
  119. ColumnMapper::getPrimaryKeyColumnName($this->getEntityName()),
  120. $entityToDelete->getPrimaryKeyValue()
  121. )
  122. );
  123. $rows = $this->em->getConnection()->executeStatement($qb);
  124. if ($rows > 0) {
  125. $entityToDelete->__destroy();
  126. }
  127. return $rows;
  128. }
  129. public function qb(): QueryBuilder
  130. {
  131. $queryBuilder = new QueryBuilder($this->em);
  132. return $queryBuilder->select($this->getEntityName(), []);
  133. }
  134. private function checkEntity(object $entity, bool $proxy = false): void
  135. {
  136. $entityName = $this->getEntityName();
  137. if (!$entity instanceof $entityName) {
  138. throw new LogicException($entityName . ' Cannot insert an entity of type ' . get_class($entity));
  139. }
  140. if ($proxy && (!$entity instanceof ProxyInterface || !$entity->__isInitialized())) {
  141. throw new LogicException($entityName . ' Cannot use an entity is not a proxy');
  142. }
  143. }
  144. }