Commit efe1d5b8 authored by Ivan Chepurnyi's avatar Ivan Chepurnyi

Merge pull request #53 from steverice/dev

EAV attributes can be loaded from fixture file
parents a2e81d5f 934fcdec
......@@ -33,6 +33,9 @@ class EcomDev_PHPUnit_Model_Fixture
// Configuration path for eav loaders
const XML_PATH_FIXTURE_EAV_LOADERS = 'phpunit/suite/fixture/eav';
// Configuration path for attribute loaders
const XML_PATH_FIXTURE_ATTRIBUTE_LOADERS = 'phpunit/suite/fixture/attribute';
// Default eav loader class node in loaders configuration
const DEFAULT_EAV_LOADER_NODE = 'default';
......@@ -42,6 +45,9 @@ class EcomDev_PHPUnit_Model_Fixture
// Default eav loader class alias
const DEFAULT_EAV_LOADER_CLASS = 'ecomdev_phpunit/fixture_eav_default';
// Default attribute loader class alias
const DEFAULT_ATTRIBUTE_LOADER_CLASS = 'ecomdev_phpunit/fixture_attribute_default';
// Key for storing fixture data into storage
const STORAGE_KEY_FIXTURE = 'fixture';
......@@ -51,6 +57,9 @@ class EcomDev_PHPUnit_Model_Fixture
// Key for loaded entities by EAV loaders
const STORAGE_KEY_ENTITIES = 'entities';
// Key for loaded attributes by attribute loaders
const STORAGE_KEY_ATTRIBUTES = 'attributes';
// Key for loaded cache options
const STORAGE_KEY_CACHE_OPTIONS = 'cache_options';
......@@ -266,6 +275,16 @@ class EcomDev_PHPUnit_Model_Fixture
return $this->getScope() === self::SCOPE_LOCAL;
}
/**
* Check that current fixture scope is equal to SCOPE_DEFAULT
*
* @return boolean
*/
public function isScopeDefault()
{
return $this->getScope() === self::SCOPE_DEFAULT;
}
/**
* Loads fixture files from test case annotations
*
......@@ -422,7 +441,7 @@ class EcomDev_PHPUnit_Model_Fixture
}
}
// Clear fixture for getting rid of duoble processing
// Clear fixture for getting rid of double processing
$this->_fixture = array();
return $this;
}
......@@ -677,7 +696,26 @@ class EcomDev_PHPUnit_Model_Fixture
*/
protected function _getEavLoader($entityType)
{
$loaders = Mage::getConfig()->getNode(self::XML_PATH_FIXTURE_EAV_LOADERS);
return $this->_getComplexLoader($entityType, 'EAV');
}
/**
* Retrieves the loader for a particular entity type and data type
*
* @throws InvalidArgumentException
* @param string $entityType
* @param string $dataType
* @return EcomDev_PHPUnit_Model_Mysql4_Fixture
*/
protected function _getComplexLoader($entityType, $dataType)
{
if(!$dataType) {
throw new InvalidArgumentException('Must specify a data type for the loader');
}
$reflection = EcomDev_Utils_Reflection::getRelflection($this);
$loaders = Mage::getConfig()->getNode($reflection->getConstant("XML_PATH_FIXTURE_{$dataType}_LOADERS"));
if (isset($loaders->$entityType)) {
$classAlias = (string)$loaders->$entityType;
......@@ -887,4 +925,102 @@ class EcomDev_PHPUnit_Model_Fixture
return $this;
}
/**
* Retrieves attribute loader for a particular entity type
*
* @param string $entityType
* @return EcomDev_PHPUnit_Model_Mysql4_Fixture_Attribute_Abstract
*/
protected function _getAttributeLoader($entityType)
{
return $this->_getComplexLoader($entityType, 'ATTRIBUTE');
}
/**
* Applies fixture EAV attribute values
*/
protected function _applyAttributes($attributes)
{
if (!is_array($attributes)) {
throw new InvalidArgumentException(
'Attributes part should be an associative list with rows as value and attribute code as key'
);
}
if (!$this->getStorageData(self::STORAGE_KEY_ATTRIBUTES, self::SCOPE_DEFAULT)) {
// since attributes are being used, we need to load all previously-existing
// attributes into default scope
$ignoreCleanup = array();
foreach(array_keys($attributes) as $entityType) {
$ignoreCleanup[$entityType] = $this->_getAttributeLoader(self::DEFAULT_SHARED_FIXTURE_NAME)
->setFixture($this)
->setOptions($this->_options)
->loadDefaultAttributes($entityType);
}
$this->setStorageData(self::STORAGE_KEY_ATTRIBUTES, $ignoreCleanup, self::SCOPE_DEFAULT);
}
$this->getResource()->beginTransaction();
foreach ($attributes as $entityType => $values) {
$this->_getAttributeLoader($entityType)
->setFixture($this)
->setOptions($this->_options)
->loadAttribute($entityType, $values);
}
$this->getResource()->commit();
$this->setStorageData(self::STORAGE_KEY_ATTRIBUTES, array_keys($attributes));
return $this;
}
/**
* Clean applied attribute data
*
* @param array $attributes
* @return EcomDev_PHPUnit_Model_Fixture
*/
protected function _discardAttributes($attributes)
{
// Ignore cleaning of attributes if they existed before fixtures were loaded
$ignoreCleanUp = $this->getStorageData(self::STORAGE_KEY_ATTRIBUTES, self::SCOPE_DEFAULT);
if($ignoreCleanUp === null) $ignoreCleanUp = array();
// Ignore cleaning of attributes if shared fixture loaded something for them
if ($this->isScopeLocal() && $this->getStorageData(self::STORAGE_KEY_ATTRIBUTES, self::SCOPE_SHARED)) {
$ignoreCleanUp = array_merge_recursive(
$ignoreCleanUp,
$this->getStorageData(self::STORAGE_KEY_ENTITIES, self::SCOPE_SHARED)
);
}
$this->getResource()->beginTransaction();
foreach ($attributes as $entityType => $values) {
$attributeCodes = array();
foreach ($values as $value) {
if (isset($value['attribute_code'])
&& !in_array($value['attribute_code'], $ignoreCleanUp[$entityType])) {
$attributeCodes[] = $value['attribute_code'];
}
}
if (!empty($attributeCodes)) {
$this->_getAttributeLoader(self::DEFAULT_SHARED_FIXTURE_NAME)
->cleanAttributes($entityType, $attributeCodes);
}
}
$this->getResource()->commit();
foreach (array_keys($attributes) as $entityType) {
$this->_getAttributeLoader(self::DEFAULT_SHARED_FIXTURE_NAME)->resetAttributesAutoIncrement($entityType);
}
$this->_getAttributeLoader(self::DEFAULT_SHARED_FIXTURE_NAME)->resetAttributesAutoIncrement();
return $this;
}
}
......@@ -25,8 +25,12 @@
*/
interface EcomDev_PHPUnit_Model_Fixture_Interface extends EcomDev_PHPUnit_Model_Test_Loadable_Interface
{
/** Local scope - used for fixtures that apply only to the current test */
const SCOPE_LOCAL = 'local';
/** Shared scope - used for fixtures that apply to the current test class */
const SCOPE_SHARED = 'shared';
/** Default scope - used for storing data that exists in database before tests are run */
const SCOPE_DEFAULT = 'default';
/**
* Sets fixture options
......@@ -84,6 +88,14 @@ interface EcomDev_PHPUnit_Model_Fixture_Interface extends EcomDev_PHPUnit_Model_
*/
public function setScope($scope);
/**
* Check that current fixture scope is equal to SCOPE_DEFAULT
*
* @abstract
* @return boolean
*/
public function isScopeDefault();
/**
* Check that current fixture scope is equal to SCOPE_SHARED
*
......
<?php
/**
* PHP Unit test suite for Magento
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://opensource.org/licenses/osl-3.0.php
*
* @category EcomDev
* @package EcomDev_PHPUnit
* @copyright Copyright (c) 2012 EcomDev BV (http://www.ecomdev.org)
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
* @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
* @author Steve Rice <srice@endertech.com>
*/
abstract class EcomDev_PHPUnit_Model_Mysql4_Fixture_Attribute_Abstract
extends EcomDev_PHPUnit_Model_Mysql4_Fixture_Complex_Abstract
{
protected $_setupModel = 'Mage_Eav_Model_Entity_Setup';
/**
* @param string $entityType
* @return array
*/
public function loadDefaultAttributes($entityType)
{
/** @var $eavConfig Mage_Eav_Model_Config */
$eavConfig = Mage::getSingleton('eav/config');
$attributeCodes = $eavConfig->getEntityAttributeCodes($entityType);
return $attributeCodes;
}
/**
* Loads EAV attribute into DB tables
*
* @throws UnexpectedValueException
* @throws InvalidArgumentException
* @param string $entityType
* @param array $values
*/
public function loadAttribute($entityType, $values)
{
/** @var $eavConfig Mage_Eav_Model_Config */
$eavConfig = Mage::getSingleton('eav/config');
/** @var $entityTypeModel Mage_Eav_Model_Entity_Type */
$entityTypeModel = $eavConfig->getEntityType($entityType);
$entityModel = $entityTypeModel->getEntity();
//use entity model to figure out setup class
$entityReflection = EcomDev_Utils_Reflection::getRelflection($entityModel);
$classArray = explode('_', $entityReflection->getName());
$moduleName = $classArray[0] . '_' . $classArray[1];
$eavSetupModel = $this->_getSetupModelForModule($moduleName);
foreach ($values as $value) {
if (!isset($value['attribute_code'])) {
throw new InvalidArgumentException('Attribute definition must contain attribute_code');
}
/** @var $eavSetupModel Mage_Eav_Model_Entity_Setup */
$eavSetupModel->addAttribute($entityTypeModel->getEntityTypeCode(), $value['attribute_code'], $value);
}
}
/**
* Remove fixture-generated attributes from database
*
* @param string $entityType
* @param array $attributeCodes
* @return EcomDev_PHPUnit_Model_Mysql4_Fixture_Attribute_Abstract
* @throws EcomDev_PHPUnit_Model_Mysql4_Fixture_Exception
*/
public function cleanAttributes($entityType, array $attributeCodes)
{
$eavSetup = new Mage_Eav_Model_Entity_Setup('core_setup');
try {
//delete entry from eav/attribute and allow FK cascade to delete all related values
$this->_getWriteAdapter()
->delete(
$this->getTable('eav/attribute'),
array(
'entity_type_id = ?' => $eavSetup->getEntityTypeId($entityType),
'attribute_code IN (?)' => $attributeCodes,
)
);
$this->_getWriteAdapter()->commit();
} catch (Exception $e) {
throw new EcomDev_PHPUnit_Model_Mysql4_Fixture_Exception(
sprintf('Unable to clear records for a table "%s"', 'eav/attribute'),
$e
);
}
return $this;
}
/**
* Reset autoincrement value of all EAV attribute tables or those associated with an entity type
*
* @throws EcomDev_PHPUnit_Model_Mysql4_Fixture_Exception
* @param string $entityType
* @return EcomDev_PHPUnit_Model_Mysql4_Fixture_Attribute_Abstract
*/
public function resetAttributesAutoIncrement($entityType = null)
{
//@TODO track which tables are altered
if ($entityType !== null) {
/** @var $eavConfig Mage_Eav_Model_Config */
$eavConfig = Mage::getSingleton('eav/config');
/** @var $entityTypeModel Mage_Eav_Model_Entity_Type */
$entityTypeModel = $eavConfig->getEntityType($entityType);
$this->resetTableAutoIncrement($entityTypeModel->getAdditionalAttributeTable());
} else {
//@TODO don't hardcode these
$this->resetTableAutoIncrement('eav/attribute');
$this->resetTableAutoIncrement('eav/attribute_set');
$this->resetTableAutoIncrement('eav/attribute_group');
$this->resetTableAutoIncrement('eav/attribute_label');
$this->resetTableAutoIncrement('eav/attribute_option');
$this->resetTableAutoIncrement('eav/attribute_option_value');
}
return $this;
}
/**
* Reset autoincrement value of a table
*
* @param string $table
* @return EcomDev_PHPUnit_Model_Mysql4_Fixture_Attribute_Abstract
* @throws EcomDev_PHPUnit_Model_Mysql4_Fixture_Exception
*/
public function resetTableAutoIncrement($table)
{
try {
//reset table auto_increment to maximum value in table
$this->_getWriteAdapter()->query("ALTER TABLE `{$this->getTable($table)}` AUTO_INCREMENT = 1");
} catch (Exception $e) {
throw new EcomDev_PHPUnit_Model_Mysql4_Fixture_Exception(
sprintf('Unable to reset autoincrement for table "%s"', $table),
$e
);
}
return $this;
}
/**
* Get the setup model used by a Magento module
*
* @param $moduleName
* @return mixed
* @throws UnexpectedValueException
*/
protected function _getSetupModelForModule($moduleName)
{
$resources = Mage::getConfig()->getNode('global/resources')->children();
$resourceName = 'eav_setup';
$className = 'Mage_Eav_Model_Entity_Setup';
foreach ($resources as $resName => $resource) {
if (!$resource->setup) {
continue;
}
if (isset($resource->setup->module) && $resource->setup->module == $moduleName
&& isset($resource->setup->class)) {
$className = $resource->setup->getClassName();
$resourceName = $resName;
break;
}
}
$setupModel = new $className($resourceName);
$setupReflection = EcomDev_Utils_Reflection::getRelflection($setupModel);
if (!$setupReflection->hasMethod('addAttribute')) {
throw new UnexpectedValueException('Problem loading EAV setup model');
}
return $setupModel;
}
}
<?php
/**
* PHP Unit test suite for Magento
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://opensource.org/licenses/osl-3.0.php
*
* @category EcomDev
* @package EcomDev_PHPUnit
* @copyright Copyright (c) 2012 EcomDev BV (http://www.ecomdev.org)
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
* @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
* @author Steve Rice <srice@endertech.com>
*/
class EcomDev_PHPUnit_Model_Mysql4_Fixture_Attribute_Default
extends EcomDev_PHPUnit_Model_Mysql4_Fixture_Attribute_Abstract
{
}
<?php
/**
* PHP Unit test suite for Magento
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://opensource.org/licenses/osl-3.0.php
*
* @category EcomDev
* @package EcomDev_PHPUnit
* @copyright Copyright (c) 2012 EcomDev BV (http://www.ecomdev.org)
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
* @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
* @author Steve Rice <srice@endertech.com>
*/
abstract class EcomDev_PHPUnit_Model_Mysql4_Fixture_Complex_Abstract extends EcomDev_PHPUnit_Model_Mysql4_Fixture
{
/**
* Fixture options
*
* @var array
*/
protected $_options = array();
/**
* Fixture model
*
* @var EcomDev_PHPUnit_Model_Fixture_Interface
*/
protected $_fixture = null;
/**
* Inject fixture model into complex loader
*
* @param EcomDev_PHPUnit_Model_Fixture_Interface $fixture
* @return EcomDev_PHPUnit_Model_Mysql4_Fixture_Complex_Abstract
*/
public function setFixture($fixture)
{
$this->_fixture = $fixture;
return $this;
}
/**
* Set fixture options
*
* @param array $options
* @return EcomDev_PHPUnit_Model_Mysql4_Fixture_Complex_Abstract
*/
public function setOptions(array $options)
{
$this->_options = $options;
return $this;
}
}
......@@ -20,7 +20,8 @@
* Base implementation of EAV fixtures loader
*
*/
abstract class EcomDev_PHPUnit_Model_Mysql4_Fixture_Eav_Abstract extends EcomDev_PHPUnit_Model_Mysql4_Fixture
abstract class EcomDev_PHPUnit_Model_Mysql4_Fixture_Eav_Abstract
extends EcomDev_PHPUnit_Model_Mysql4_Fixture_Complex_Abstract
{
/**
* List of indexers required to build
......@@ -29,20 +30,6 @@ abstract class EcomDev_PHPUnit_Model_Mysql4_Fixture_Eav_Abstract extends EcomDev
*/
protected $_requiredIndexers = array();
/**
* Fixture options
*
* @var array
*/
protected $_options = array();
/**
* Fixture model
*
* @var EcomDev_PHPUnit_Model_Fixture_Interface
*/
protected $_fixture = null;
/**
* Retrieve required indexers for re-building
*
......@@ -53,29 +40,6 @@ abstract class EcomDev_PHPUnit_Model_Mysql4_Fixture_Eav_Abstract extends EcomDev
return $this->_requiredIndexers;
}
/**
* Sets fixture model to EAV loader
*
* @param EcomDev_PHPUnit_Model_Fixture_Interface $fixture
*/
public function setFixture($fixture)
{
$this->_fixture = $fixture;
return $this;
}
/**
* Set fixture options
*
* @param array $options
* @return EcomDev_PHPUnit_Model_Mysql4_Fixture_Eav_Abstract
*/
public function setOptions(array $options)
{
$this->_options = $options;
return $this;
}
/**
* Add indexer by specific code to required indexers list
*
......@@ -98,6 +62,7 @@ abstract class EcomDev_PHPUnit_Model_Mysql4_Fixture_Eav_Abstract extends EcomDev
*/
public function cleanEntity($entityType)
{
/** @var $entityTypeModel Mage_Eav_Model_Entity_Type */
$entityTypeModel = Mage::getSingleton('eav/config')->getEntityType($entityType);
$this->cleanTable($entityTypeModel->getEntityTable());
return $this;
......@@ -123,6 +88,7 @@ abstract class EcomDev_PHPUnit_Model_Mysql4_Fixture_Eav_Abstract extends EcomDev
}
}
/** @var $entityTypeModel Mage_Eav_Model_Entity_Type */
$entityTypeModel = Mage::getSingleton('eav/config')->getEntityType($entityType);
......@@ -160,12 +126,13 @@ abstract class EcomDev_PHPUnit_Model_Mysql4_Fixture_Eav_Abstract extends EcomDev
// Preparing simple attributes records
foreach ($entityTypeModel->getAttributeCollection() as $attribute) {
/** @var $attribute Mage_Eav_Model_Entity_Attribute */
$attributeBackendTable = $attribute->getBackendTable();
if (!$attribute->isStatic()
&& $attributeBackendTable
&& isset($attributeTableColumns[$attributeBackendTable])) {
// Prepearing data for insert per attribute table
// Preparing data for insert per attribute table
$attributeRecords = $this->_getAttributeRecords(
$row,
$attribute,
......
......@@ -70,6 +70,12 @@
<fixture>
<!-- Default model for loading of fixtures -->
<model>ecomdev_phpunit/fixture</model>
<attribute>
<!-- Fixture loaders for EAV attributes
Default can be used but does not support extra attribute table configuration -->
<default>ecomdev_phpunit/fixture_attribute_default</default>
<!--<catalog_product>ecomdev_phpunit/fixture_attribute_catalog_product</catalog_product>-->
</attribute>
<eav>
<!-- Here goes the list of fixture loaders for EAV
If no fixture loader is specified for entity, then default will be used
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment