SoftDeleteableWalker.php 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. <?php
  2. namespace Gedmo\SoftDeleteable\Query\TreeWalker;
  3. use Doctrine\ORM\Query\SqlWalker;
  4. use Doctrine\ORM\Query\AST\DeleteStatement;
  5. use Doctrine\ORM\Query\AST\DeleteClause;
  6. use Doctrine\ORM\Query\Exec\SingleTableDeleteUpdateExecutor;
  7. use Gedmo\SoftDeleteable\SoftDeleteableListener;
  8. use Gedmo\SoftDeleteable\Query\TreeWalker\Exec\MultiTableDeleteExecutor;
  9. /**
  10. * This SqlWalker is needed when you need to use a DELETE DQL query.
  11. * It will update the "deletedAt" field with the actual date, instead
  12. * of actually deleting it.
  13. *
  14. * @author Gustavo Falco <comfortablynumb84@gmail.com>
  15. * @author Gediminas Morkevicius <gediminas.morkevicius@gmail.com>
  16. * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
  17. */
  18. class SoftDeleteableWalker extends SqlWalker
  19. {
  20. protected $conn;
  21. protected $platform;
  22. protected $listener;
  23. protected $configuration;
  24. protected $alias;
  25. protected $deletedAtField;
  26. protected $meta;
  27. /**
  28. * {@inheritDoc}
  29. */
  30. public function __construct($query, $parserResult, array $queryComponents)
  31. {
  32. parent::__construct($query, $parserResult, $queryComponents);
  33. $this->conn = $this->getConnection();
  34. $this->platform = $this->conn->getDatabasePlatform();
  35. $this->listener = $this->getSoftDeleteableListener();
  36. $this->extractComponents($queryComponents);
  37. }
  38. /**
  39. * {@inheritDoc}
  40. */
  41. public function getExecutor($AST)
  42. {
  43. switch (true) {
  44. case ($AST instanceof DeleteStatement):
  45. $primaryClass = $this->getEntityManager()->getClassMetadata($AST->deleteClause->abstractSchemaName);
  46. return ($primaryClass->isInheritanceTypeJoined())
  47. ? new MultiTableDeleteExecutor($AST, $this, $this->meta, $this->platform, $this->configuration)
  48. : new SingleTableDeleteUpdateExecutor($AST, $this);
  49. default:
  50. throw new \Gedmo\Exception\UnexpectedValueException('SoftDeleteable walker should be used only on delete statement');
  51. }
  52. }
  53. /**
  54. * Change a DELETE clause for an UPDATE clause
  55. *
  56. * @param DeleteClause $deleteClause
  57. *
  58. * @return string The SQL.
  59. */
  60. public function walkDeleteClause(DeleteClause $deleteClause)
  61. {
  62. $em = $this->getEntityManager();
  63. $class = $em->getClassMetadata($deleteClause->abstractSchemaName);
  64. $tableName = $class->getTableName();
  65. $this->setSQLTableAlias($tableName, $tableName, $deleteClause->aliasIdentificationVariable);
  66. $quotedTableName = $class->getQuotedTableName($this->platform);
  67. $quotedColumnName = $class->getQuotedColumnName($this->deletedAtField, $this->platform);
  68. $sql = 'UPDATE '.$quotedTableName.' SET '.$quotedColumnName.' = '.$this->platform->getCurrentTimestampSQL();
  69. return $sql;
  70. }
  71. /**
  72. * Get the currently used SoftDeleteableListener
  73. *
  74. * @throws \Gedmo\Exception\RuntimeException - if listener is not found
  75. *
  76. * @return SoftDeleteableListener
  77. */
  78. private function getSoftDeleteableListener()
  79. {
  80. if (is_null($this->listener)) {
  81. $em = $this->getEntityManager();
  82. foreach ($em->getEventManager()->getListeners() as $event => $listeners) {
  83. foreach ($listeners as $hash => $listener) {
  84. if ($listener instanceof SoftDeleteableListener) {
  85. $this->listener = $listener;
  86. break;
  87. }
  88. }
  89. if ($this->listener) {
  90. break;
  91. }
  92. }
  93. if (is_null($this->listener)) {
  94. throw new \Gedmo\Exception\RuntimeException('The SoftDeleteable listener could not be found.');
  95. }
  96. }
  97. return $this->listener;
  98. }
  99. /**
  100. * Search for components in the delete clause
  101. *
  102. * @param array $queryComponents
  103. *
  104. * @return void
  105. */
  106. private function extractComponents(array $queryComponents)
  107. {
  108. $em = $this->getEntityManager();
  109. foreach ($queryComponents as $alias => $comp) {
  110. if (!isset($comp['metadata'])) {
  111. continue;
  112. }
  113. $meta = $comp['metadata'];
  114. $config = $this->listener->getConfiguration($em, $meta->name);
  115. if ($config && isset($config['softDeleteable']) && $config['softDeleteable']) {
  116. $this->configuration = $config;
  117. $this->deletedAtField = $config['fieldName'];
  118. $this->meta = $meta;
  119. }
  120. }
  121. }
  122. }