Нашел сегодня еще одну очень неприятную багу. На самом деле она очень серьезная, и в отдельных случаях может не только доставить неудобства, но и к серьезным ошибкам привести. Когда мы выполняем modx−>getCollection(class), мы получаем массив объектов. Но это не простой нумерованный массив (типа array(0 => object, 1 => object) и т.д.). В этом массиве у нас каждый ключ — это id объекта, то есть ключи часто идут не по порядку (3,7,9,57 и т.д.). Те, кто использует ->getMany(), знают — этот метод возвращает связанные объекты. По сути этот метод внутри себя выполняет тот же самый getCollection(). Но проблема кроется всего в одной строчке: this−>relatedObjects[alias]= array_merge(this−>relatedObjects[alias], collection);Тоестьвсесвязанныеобъектыпопадаютвобщиймассивthis->_relatedObjects. Уточняю: getMany() не просто делает выборку getCollection(), но и набивает эти объекты в общий пулл связанных объектов. И с этим массивом связанных объектов this−>relatedObjectsможно(аиногдаинужно)работать.Таквот,проблемавтом,чтоarraymergeнесохраняетключи−idобъектов,анабиваетвсевновыйнумерованныймассив.Фокусхорошодемонстрируетвотэтотпример:<?phpa = array(
2=>'object'
);
b=arraymerge(a, array(
5=>'object',
7 => 'object',
));
print_r(b);Навыходемыполучаем:Array([0]=>object[1]=>object[2]=>object)Последствия(отнеудобствдопроблем)Неудобствозаключаетсявотвчем:Допустим,мызнаем,чтоужеполучаливсезависимыеобъекты,итеперьпростохотимпроверитьналичиеобъектапоегоid.Унашихобъектовестьid−шники7,9и12.Поидеемыимеемвозможностьпоidобратитьсякключумассива,тоестьobject->_relatedObjects[alias][7]долженнамвернутьнужныйнамобъект.Аннет.Из−заэтойбагиунастамтеперьмассивсключами0,1,2…Тоестьобъектмыужепотеряли.Ачтопроизойдет,еслимыопятьвыполнимobject->getMany()? По сути 3 объекта он уже в себе имеет. Но из-за этой фишки с array_merge, мы получим уже 6 объектов, так как в новом массиве объектов ключи 7,9 и 12, а в текущем массиве 0,1,2, и теперь станет еще и 3,4,5. А если у нас id-шники 3453,6757,90980 и мы выполним getMany() много раз? :-) Еще пример. if(!room=modx->getObject('modResource', 107)){return '';}
// Получаем все связанные объекты
vars=room->getMany('Variables');
print count($room->_relatedObjects['Variables']); // Считаем - 2 объекта
// Получаем один из имеющихся объектов
var=current(room->_relatedObjects['Variables']);
// Добавляем его же
room−>addMany(var);
print count(room−>relatedObjects[′Variables′]);//Уже3объектаПосутиэтотожесамое,простодругимпутем.Носутьвчем:вотоднастрочкаизэтогометодаthis->_relatedObjects[alias][objpk]= $obj; То есть затирается элемент массива объектов с ключем id этого объекта. Но по нашей схеме в зависимости от того, какой id у объекта, он во-первых, может затереть вообще другой объект (а тот мог быть измененным, а значит при сохранении главного объекта этот объект уже не будет сохранен), а во-вторых, этот новый объект может встать или впереди, или позади своей же копии, но эти две копии могут отличаться (новый объект перед добавлением изменили), так вот в зависимости от их очередности, при сохранении главного объекта, эти объекты будут сохранены, и не факт, что в правильной исторической последовательности. Вот как-то так…