public function read($model, $name, &$dbValues, $transformatorClass = TransformatorInterface::class) { if (!$dbValues) { $fieldMeta = ManganMeta::create($model)->field($name); $model->{$name} = $fieldMeta->default; return; } /** * NOTE: Documents must be sorted as $dbRefs, * however mongo does not guarantiee sorting by list of id's. * This require sorting in php. * If document has composite key this must be taken care too * while comparision for sorting is made. */ $refs = []; $unsortedRefs = []; $pks = []; $sort = []; // Collect primary keys foreach ($dbValues as $key => $dbValue) { $dbValue['_class'] = DbRef::class; $dbRef = $transformatorClass::toModel($dbValue); // Collect keys separatelly for each type $pks[$dbRef->class][$key] = $dbRef->pk; $sort[$key] = $dbRef->pk; } // Fetch all types of db ref's en masse $i = 0; $unsortedPks = []; foreach ($pks as $referenced => $pkValues) { if (empty($referenced)) { continue; } // Find all referenced documents $refModel = new $referenced(); $found = (new RawFinder($refModel))->findAllByPk($pkValues); if (!$found) { continue; } foreach ($found as $document) { // Collect unsorted documents $unsortedRefs[$i] = $document; // Collect pk's $unsortedPks[$i] = PkManager::getFromArray($document, $refModel); $i++; } } // Find existing documents $existing = []; foreach ($model->{$name} as $key => $document) { foreach ($sort as $i => $pk) { if (PkManager::compare($pk, $document)) { // Set existing document with key same as in sort $existing[$i] = $document; } } } // Sort as stored ref foreach ($sort as $key => $pk) { foreach ($unsortedRefs as $i => $document) { if (PkManager::compare($pk, $unsortedPks[$i])) { if (array_key_exists($key, $existing)) { // Update existing instance $refs[$key] = $transformatorClass::toModel($document, $existing[$key], $existing[$key]); } else { // Create new instance $refs[$key] = $transformatorClass::toModel($document); } } } } $model->{$name} = $refs; }