विस्तृत जांच के बाद मुझे पता चला कि मैं जो कुछ चाहता था उसके करीब कुछ करने के कई तरीके हैं, लेकिन उनमें से सभी में कुछ minuses हैं। अंत में मैंने CustomHydrators का उपयोग करने का निर्णय लिया है। ऐसा लगता है कि ओआरएम के साथ प्रबंधित नहीं किए गए गुणों को ResultSetMapping के साथ फ़ील्ड के रूप में मैप नहीं किया जा सकता है, लेकिन स्केलर के रूप में प्राप्त किया जा सकता है और मैन्युअल रूप से एक इकाई से जुड़ा जा सकता है (क्योंकि PHP फ्लाई पर ऑब्जेक्ट गुणों को संलग्न करने की अनुमति देता है)। हालांकि, परिणामस्वरूप आप सिद्धांत से प्राप्त होते हैं कैश में रहता है। इसका मतलब है कि उस तरीके से सेट की गई संपत्ति रीसेट हो सकती है यदि आप कोई अन्य क्वेरी करते हैं जिसमें इन इकाइयों को भी शामिल किया जाएगा।
ऐसा करने का एक और तरीका यह क्षेत्र सीधे सिद्धांत के मेटाडेटा कैश में जोड़ रहा था। मैं एक CustomHydrator में कर की कोशिश की है कि:
protected function getClassMetadata($className)
{
if (! isset($this->_metadataCache[$className])) {
$this->_metadataCache[$className] = $this->_em->getClassMetadata($className);
if ($className === "SomeBundle\Entity\Product") {
$this->insertField($className, "ReviewsCount");
}
}
return $this->_metadataCache[$className];
}
protected function insertField($className, $fieldName) {
$this->_metadataCache[$className]->fieldMappings[$fieldName] = ["fieldName" => $fieldName, "type" => "text", "scale" => 0, "length" => null, "unique" => false, "nullable" => true, "precision" => 0];
$this->_metadataCache[$className]->reflFields[$fieldName] = new \ReflectionProperty($className, $fieldName);
return $this->_metadataCache[$className];
}
हालांकि, उस विधि को भी साथ संस्थाओं की गुण रीसेट समस्या थी। तो, मेरा अंतिम समाधान सिर्फ stdClass उपयोग करने के लिए एक ही संरचना प्राप्त करने के लिए गया था, लेकिन सिद्धांत के द्वारा प्रबंधित नहीं:
namespace SomeBundle;
use PDO;
use Doctrine\ORM\Query\ResultSetMapping;
class CustomHydrator extends \Doctrine\ORM\Internal\Hydration\ObjectHydrator {
public function hydrateAll($stmt, $resultSetMapping, array $hints = array()) {
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
$result = [];
foreach($resultSetMapping->entityMappings as $root => $something) {
$rootIDField = $this->getIDFieldName($root, $resultSetMapping);
foreach($data as $row) {
$key = $this->findEntityByID($result, $row[$rootIDField]);
if ($key === null) {
$result[] = new \stdClass();
end($result);
$key = key($result);
}
foreach ($row as $column => $field)
if (isset($resultSetMapping->columnOwnerMap[$column]))
$this->attach($result[$key], $field, $this->getPath($root, $resultSetMapping, $column));
}
}
return $result;
}
private function getIDFieldName($entityAlias, ResultSetMapping $rsm) {
foreach ($rsm->fieldMappings as $key => $field)
if ($field === 'ID' && $rsm->columnOwnerMap[$key] === $entityAlias) return $key;
return null;
}
private function findEntityByID($array, $ID) {
foreach($array as $index => $entity)
if (isset($entity->ID) && $entity->ID === $ID) return $index;
return null;
}
private function getPath($root, ResultSetMapping $rsm, $column) {
$path = [$rsm->fieldMappings[$column]];
if ($rsm->columnOwnerMap[$column] !== $root)
array_splice($path, 0, 0, $this->getParent($root, $rsm, $rsm->columnOwnerMap[$column]));
return $path;
}
private function getParent($root, ResultSetMapping $rsm, $entityAlias) {
$path = [];
if (isset($rsm->parentAliasMap[$entityAlias])) {
$path[] = $rsm->relationMap[$entityAlias];
array_splice($path, 0, 0, $this->getParent($root, $rsm, array_search($rsm->parentAliasMap[$entityAlias], $rsm->relationMap)));
}
return $path;
}
private function attach($object, $field, $place) {
if (count($place) > 1) {
$prop = $place[0];
array_splice($place, 0, 1);
if (!isset($object->{$prop})) $object->{$prop} = new \stdClass();
$this->attach($object->{$prop}, $field, $place);
} else {
$prop = $place[0];
$object->{$prop} = $field;
}
}
}
उस वर्ग आप किसी भी संरचना हो और किसी भी संस्थाओं जैसे आप चाहें संलग्न कर सकते हैं के साथ:
$sql = '
SELECT p.*, COUNT(r.id)
FROM products p
LEFT JOIN reviews r ON p.id = r.product_id
';
$em = $this->getDoctrine()->getManager();
$rsm = new ResultSetMapping();
$rsm->addEntityResult('SomeBundle\Entity\Product', 'p');
$rsm->addFieldResult('p', 'COUNT(id)', 'reviewsCount');
$query = $em->createNativeQuery($sql, $rsm);
$em->getConfiguration()->addCustomHydrationMode('CustomHydrator', 'SomeBundle\CustomHydrator');
$results = $query->getResult('CustomHydrator');
आशा है कि किसी की मदद कर सकता है :)
मुझे ऐसा नहीं लगता है। क्या आपने नामित प्रश्नों का उपयोग करने पर विचार किया है [उदाहरण] (http://stackoverflow.com/questions/12016378/doctrine2-named-queries)? –
हां। मैंने टॉमसज़ मेडिसकी के जवाब पर मेरी टिप्पणी में मूल प्रश्नों की समस्या देखी। समस्या यह है कि वे इकाइयों के साथ स्केलर्स को एक साथ लौटते हैं, जबकि मैं चाहता हूं कि वे गंदगी से बचने के लिए संस्थाओं के खेतों में रहें। – Multis