ORM.php 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. <?php
  2. namespace Gedmo\Translatable\Mapping\Event\Adapter;
  3. use Doctrine\DBAL\Types\Type;
  4. use Doctrine\ORM\Query;
  5. use Doctrine\ORM\Mapping\ClassMetadataInfo;
  6. use Gedmo\Mapping\Event\Adapter\ORM as BaseAdapterORM;
  7. use Gedmo\Translatable\Mapping\Event\TranslatableAdapter;
  8. use Gedmo\Tool\Wrapper\AbstractWrapper;
  9. /**
  10. * Doctrine event adapter for ORM adapted
  11. * for Translatable behavior
  12. *
  13. * @author Gediminas Morkevicius <gediminas.morkevicius@gmail.com>
  14. * @package Gedmo\Translatable\Mapping\Event\Adapter
  15. * @subpackage ORM
  16. * @link http://www.gediminasm.org
  17. * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
  18. */
  19. final class ORM extends BaseAdapterORM implements TranslatableAdapter
  20. {
  21. /**
  22. * {@inheritDoc}
  23. */
  24. public function usesPersonalTranslation($translationClassName)
  25. {
  26. return $this
  27. ->getObjectManager()
  28. ->getClassMetadata($translationClassName)
  29. ->getReflectionClass()
  30. ->isSubclassOf('Gedmo\Translatable\Entity\MappedSuperclass\AbstractPersonalTranslation')
  31. ;
  32. }
  33. /**
  34. * {@inheritDoc}
  35. */
  36. public function getDefaultTranslationClass()
  37. {
  38. return 'Gedmo\\Translatable\\Entity\\Translation';
  39. }
  40. /**
  41. * {@inheritDoc}
  42. */
  43. public function loadTranslations($object, $translationClass, $locale, $objectClass)
  44. {
  45. $em = $this->getObjectManager();
  46. $wrapped = AbstractWrapper::wrap($object, $em);
  47. $result = array();
  48. if ($this->usesPersonalTranslation($translationClass)) {
  49. // first try to load it using collection
  50. $found = false;
  51. foreach ($wrapped->getMetadata()->associationMappings as $assoc) {
  52. $isRightCollection = $assoc['targetEntity'] === $translationClass
  53. && $assoc['mappedBy'] === 'object'
  54. && $assoc['type'] === ClassMetadataInfo::ONE_TO_MANY
  55. ;
  56. if ($isRightCollection) {
  57. $collection = $wrapped->getPropertyValue($assoc['fieldName']);
  58. foreach ($collection as $trans) {
  59. if ($trans->getLocale() === $locale) {
  60. $result[] = array(
  61. 'field' => $trans->getField(),
  62. 'content' => $trans->getContent()
  63. );
  64. }
  65. }
  66. $found = true;
  67. break;
  68. }
  69. }
  70. // if collection is not set, fetch it through relation
  71. if (!$found) {
  72. $dql = 'SELECT t.content, t.field FROM ' . $translationClass . ' t';
  73. $dql .= ' WHERE t.locale = :locale';
  74. $dql .= ' AND t.object = :object';
  75. $q = $em->createQuery($dql);
  76. $q->setParameters(compact('object', 'locale'));
  77. $result = $q->getArrayResult();
  78. }
  79. } else {
  80. // load translated content for all translatable fields
  81. $objectId = $wrapped->getIdentifier();
  82. // construct query
  83. $dql = 'SELECT t.content, t.field FROM ' . $translationClass . ' t';
  84. $dql .= ' WHERE t.foreignKey = :objectId';
  85. $dql .= ' AND t.locale = :locale';
  86. $dql .= ' AND t.objectClass = :objectClass';
  87. // fetch results
  88. $q = $em->createQuery($dql);
  89. $q->setParameters(compact('objectId', 'locale', 'objectClass'));
  90. $result = $q->getArrayResult();
  91. }
  92. return $result;
  93. }
  94. /**
  95. * {@inheritDoc}
  96. */
  97. public function findTranslation(AbstractWrapper $wrapped, $locale, $field, $translationClass, $objectClass)
  98. {
  99. $em = $this->getObjectManager();
  100. // first look in identityMap, will save one SELECT query
  101. foreach ($em->getUnitOfWork()->getIdentityMap() as $className => $objects) {
  102. if ($className === $translationClass) {
  103. foreach ($objects as $trans) {
  104. $isRequestedTranslation = !$trans instanceof Proxy
  105. && $trans->getLocale() === $locale
  106. && $trans->getField() === $field
  107. ;
  108. if ($isRequestedTranslation) {
  109. if ($this->usesPersonalTranslation($translationClass)) {
  110. $isRequestedTranslation = $trans->getObject() === $wrapped->getObject();
  111. } else {
  112. $isRequestedTranslation = $trans->getForeignKey() === $wrapped->getIdentifier()
  113. && $trans->getObjectClass() === $wrapped->getMetadata()->name
  114. ;
  115. }
  116. }
  117. if ($isRequestedTranslation) {
  118. return $trans;
  119. }
  120. }
  121. }
  122. }
  123. $qb = $em->createQueryBuilder();
  124. $qb->select('trans')
  125. ->from($translationClass, 'trans')
  126. ->where(
  127. 'trans.locale = :locale',
  128. 'trans.field = :field'
  129. )
  130. ;
  131. $qb->setParameters(compact('locale', 'field'));
  132. if ($this->usesPersonalTranslation($translationClass)) {
  133. $qb->andWhere('trans.object = :object');
  134. $qb->setParameter('object', $wrapped->getObject());
  135. } else {
  136. $qb->andWhere('trans.foreignKey = :objectId');
  137. $qb->andWhere('trans.objectClass = :objectClass');
  138. $qb->setParameter('objectId', $wrapped->getIdentifier());
  139. $qb->setParameter('objectClass', $objectClass);
  140. }
  141. $q = $qb->getQuery();
  142. $q->setMaxResults(1);
  143. $result = $q->getResult();
  144. if ($result) {
  145. return array_shift($result);
  146. }
  147. return null;
  148. }
  149. /**
  150. * {@inheritDoc}
  151. */
  152. public function removeAssociatedTranslations(AbstractWrapper $wrapped, $transClass, $objectClass)
  153. {
  154. $qb = $this
  155. ->getObjectManager()
  156. ->createQueryBuilder()
  157. ->delete($transClass, 'trans')
  158. ;
  159. if ($this->usesPersonalTranslation($transClass)) {
  160. $qb->where('trans.object = :object');
  161. $qb->setParameter('object', $wrapped->getObject());
  162. } else {
  163. $qb->where(
  164. 'trans.foreignKey = :objectId',
  165. 'trans.objectClass = :class'
  166. );
  167. $qb->setParameter('objectId', $wrapped->getIdentifier());
  168. $qb->setParameter('class', $objectClass);
  169. }
  170. return $qb->getQuery()->getSingleScalarResult();
  171. }
  172. /**
  173. * {@inheritDoc}
  174. */
  175. public function insertTranslationRecord($translation)
  176. {
  177. $em = $this->getObjectManager();
  178. $meta = $em->getClassMetadata(get_class($translation));
  179. $data = array();
  180. foreach ($meta->getReflectionProperties() as $fieldName => $reflProp) {
  181. if (!$meta->isIdentifier($fieldName)) {
  182. $data[$meta->getColumnName($fieldName)] = $reflProp->getValue($translation);
  183. }
  184. }
  185. $table = $meta->getTableName();
  186. if (!$em->getConnection()->insert($table, $data)) {
  187. throw new \Gedmo\Exception\RuntimeException('Failed to insert new Translation record');
  188. }
  189. }
  190. /**
  191. * {@inheritDoc}
  192. */
  193. public function getTranslationValue($object, $field, $value = false)
  194. {
  195. $em = $this->getObjectManager();
  196. $wrapped = AbstractWrapper::wrap($object, $em);
  197. $meta = $wrapped->getMetadata();
  198. $type = Type::getType($meta->getTypeOfField($field));
  199. if ($value === false) {
  200. $value = $wrapped->getPropertyValue($field);
  201. }
  202. return $type->convertToDatabaseValue($value, $em->getConnection()->getDatabasePlatform());
  203. }
  204. /**
  205. * {@inheritDoc}
  206. */
  207. public function setTranslationValue($object, $field, $value)
  208. {
  209. $em = $this->getObjectManager();
  210. $wrapped = AbstractWrapper::wrap($object, $em);
  211. $meta = $wrapped->getMetadata();
  212. $type = Type::getType($meta->getTypeOfField($field));
  213. $value = $type->convertToPHPValue($value, $em->getConnection()->getDatabasePlatform());
  214. $wrapped->setPropertyValue($field, $value);
  215. }
  216. }