Проблема Magento getSingleton() против getModel()

Я хочу перебрать массив идентификаторов продуктов в Magento. В цикле я показываю некоторые пользовательские атрибуты продуктов как:

foreach ($products as $product) {
   $model = Mage::getSingleton('catalog/product')->load($product['id']);
   echo '<br>' . $model->getCredits();
}

Проблема в том, что если значение getCredits() для первого элемента true, то все последующие элементы показывают true, даже если они не имеют значения true.

Но когда я использую Mage::getModel() вместо Mage::getSingleton(), значения атрибута отображаются корректно.

Может кто-нибудь объяснить эту разницу?

Ответ 1

Mage:: getModel() всегда будет возвращать новый объект для данной модели:

/**
 * Retrieve model object
 *
 * @link    Mage_Core_Model_Config::getModelInstance
 * @param   string $modelClass
 * @param   array|object $arguments
 * @return  Mage_Core_Model_Abstract|false
 */
public static function getModel($modelClass = '', $arguments = array())
{
    return self::getConfig()->getModelInstance($modelClass, $arguments);
}

Mage:: getSingleton() проверяет, существует ли объект данной модели и возвращает, если это произойдет. Если он не существует, он создаст новый объект данной модели и поместит в реестр, что он уже существует. Следующий вызов не вернет новый объект, кроме существующего:

/**
 * Retrieve model object singleton
 *
 * @param   string $modelClass
 * @param   array $arguments
 * @return  Mage_Core_Model_Abstract
 */
public static function getSingleton($modelClass='', array $arguments=array())
{
    $registryKey = '_singleton/'.$modelClass;
    if (!self::registry($registryKey)) {
        self::register($registryKey, self::getModel($modelClass, $arguments));
    }
    return self::registry($registryKey);
}

В вашем случае вы всегда хотите совершенно новый объект/модель продукта, поскольку каждый продукт уникален...

Ответ 2

getModel будет возвращать новый экземпляр запрашиваемой модели каждый раз.
getSingleton всегда возвращает тот же экземпляр. Это реализация шаблона проектирования Singleton для Magento.
Существует и другой аспект, который вы должны иметь в виду. Метод load не удаляет все данные, которые вы установили на экземпляре продукта. Например, если вы это сделаете:

$model = Mage::getModel('catalog/product')->setData('some_field_that_does_not_exist', 1);
$model->load(3);
echo $model->getData('some_field_that_does_not_exist'); //this prints 1

Это относится к вам. При использовании getSingleton во второй раз вы получаете тот же экземпляр продукта, что и в первый раз. А при вызове load значение для credits не перезаписывается, потому что такого значения для вновь загруженного продукта нет.
Вывод: не используйте getSingleton. Используйте getModel. Или, если вы хотите использовать getSingleton, используйте $model->setData(array()) перед вызовом load. Это будет reset все атрибуты.

Ответ 3

вы используете Singleton, если хотите только один экземпляр объекта в целом приложении. Поэтому, когда вы используете getSingleton, он всегда возвращает тот же объект, который может иметь некоторые ранее загруженные данные.

Итак, в этом случае, когда цикл начинается, он создает новый объект (конечно, только если это не было сделано раньше в каком-либо другом месте в magento) и загружает данные для $product ['id']. В следующей итерации цикла он принимает тот же объект с предыдущими данными идентификатора продукта и загружает в него новые данные $product ['id']. Вот почему могут возникнуть некоторые проблемы.

Если вы хотите иметь два разных продукта, вы должны использовать getModel.

Ответ 4

Прежде всего, я хотел бы объяснить difference between Mage::getSingleton() and Mage::getModel() functions.

Когда вы вызываете функцию Mage::getSingleton('catalog/product'), magento будет искать в памяти, есть ли какой-либо объект. Если нет, он создаст новый объект для класса Mage_catalog_Model_product. В первой итерации цикла foreach это происходит. Но со второй итерации, когда magento ищет в памяти объект класса Mage_catalog_Model_product, он найдет объект, который был вызван в первой итерации. Таким образом, magento не создаст никакого нового объекта, и вместо этого он вызовет тот же объект, который уже находится в памяти.

НО,

Если вы используете Mage::getModel('catalog/product), эта функция всегда создает новый объект класса Mage_catalog_Model_product в памяти всякий раз, когда вы его вызываете. Таким образом, в цикле эта функция создаст один объект на итерацию.

Ответ 5

Вы найдете разницу между getModel() и getSingleton() в других ответах.

Но если вы хотите ускорить свой код, если у вас есть коллекция, сделайте следующее:

$products->addAttributeToSelect('credits');

foreach ($products as $product) {
   echo '<br>' . $product->getCredits();
}

Поэтому вам не нужно загружать каждый продукт, что очень трудоемко.