├── .travis.yml ├── .travis └── bundle.sh ├── README.md ├── composer.json ├── modman ├── phpunit.xml.dist ├── src ├── app │ ├── code │ │ └── community │ │ │ └── IntegerNet │ │ │ └── Anonymizer │ │ │ ├── Model │ │ │ ├── Anonymizer.php │ │ │ └── Bridge │ │ │ │ ├── Entity │ │ │ │ ├── Abstract.php │ │ │ │ ├── Address │ │ │ │ │ ├── Abstract.php │ │ │ │ │ ├── CustomerAddress.php │ │ │ │ │ ├── OrderAddress.php │ │ │ │ │ └── QuoteAddress.php │ │ │ │ ├── Customer.php │ │ │ │ ├── Enterprise │ │ │ │ │ ├── Giftregistry.php │ │ │ │ │ └── GiftregistryPerson.php │ │ │ │ ├── NewsletterSubscriber.php │ │ │ │ └── Order.php │ │ │ │ └── Iterator.php │ │ │ ├── Test │ │ │ ├── Model │ │ │ │ ├── Anonymizer.php │ │ │ │ └── Bridge │ │ │ │ │ └── Entity │ │ │ │ │ ├── Abstract.php │ │ │ │ │ ├── Customer.php │ │ │ │ │ ├── CustomerAddress.php │ │ │ │ │ ├── Giftregistry.php │ │ │ │ │ ├── GiftregistryPerson.php │ │ │ │ │ ├── NewsletterSubscriber.php │ │ │ │ │ ├── Order.php │ │ │ │ │ ├── OrderAddress.php │ │ │ │ │ ├── QuoteAddress.php │ │ │ │ │ ├── expectations │ │ │ │ │ └── bridge.yaml │ │ │ │ │ └── providers │ │ │ │ │ ├── testCustomerAddressBridge.yaml │ │ │ │ │ ├── testCustomerBridge.yaml │ │ │ │ │ ├── testGiftregistryBridge.yaml │ │ │ │ │ ├── testGiftregistryPersonBridge.yaml │ │ │ │ │ ├── testNewsletterSubscriberBridge.yaml │ │ │ │ │ ├── testOrderAddressBridge.yaml │ │ │ │ │ ├── testOrderBridge.yaml │ │ │ │ │ └── testQuoteAddressBridge.yaml │ │ │ └── fixtures │ │ │ │ ├── customers.yaml │ │ │ │ └── enterprise.yaml │ │ │ └── etc │ │ │ └── config.xml │ └── etc │ │ └── modules │ │ └── IntegerNet_Anonymizer.xml ├── lib │ ├── IntegerNet │ │ └── Anonymizer │ │ │ ├── AnonymizableValue.php │ │ │ ├── Anonymizer.php │ │ │ ├── Implementor │ │ │ ├── AnonymizableEntity.php │ │ │ └── CollectionIterator.php │ │ │ ├── Provider.php │ │ │ └── Updater.php │ └── n98-magerun │ │ └── modules │ │ └── IntegerNet_Anonymizer │ │ ├── n98-magerun.yaml │ │ └── src │ │ └── IntegerNet │ │ └── Anonymizer │ │ └── AnonymizeCommand.php └── shell │ └── anonymize.php └── test ├── IntegerNet └── Anonymizer │ ├── AnonymizerTest.php │ ├── Mock │ ├── AnonymizableMock.php │ └── CollectionMock.php │ ├── ProviderTest.php │ └── UpdaterTest.php └── bootstrap.php /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | php: 3 | - 5.6 4 | - 7.0 5 | - 7.1 6 | env: 7 | - MAGENTO_VERSION=magento-mirror-1.9.3.10 8 | - MAGENTO_VERSION=magento-mirror-1.9.2.2 9 | - MAGENTO_VERSION=magento-mirror-1.9.1.0 10 | script: 11 | - composer install --dev --no-interaction 12 | - phpunit 13 | - curl -sSL https://raw.githubusercontent.com/schmengler/MageTestStand/master/setup.sh | bash 14 | before_deploy: .travis/bundle.sh 15 | deploy: 16 | provider: releases 17 | api_key: 18 | secure: YBCy2em9MOCaxS5cG+MqUO0kcW7ELPXHSs6mpM/fG+CcKaSOlrEuXmxgaCC9OJsj3aybZJ7WeiuxphLpv7CcgN5/pv+RC1RyEU/5Mt13/fG4P4YNKCEmDPsSnPQVtLKQJIWby9jf0ZhznjJJ/SvwGYmfGF0mn3/yINg2eNF/f3Y= 19 | file: 20 | - "integernet-anonymizer.zip" 21 | - "integernet-anonymizer.tar.gz" 22 | skip_cleanup: true 23 | on: 24 | tags: true -------------------------------------------------------------------------------- /.travis/bundle.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | ################################################################################ 3 | # # 4 | # This script is used by Travis CI to create a downloadable build for each # 5 | # release with all dependencies, for manual installation. # 6 | # # 7 | ################################################################################ 8 | 9 | set -e 10 | set -x 11 | if [ "$TRAVIS_TAG" == "" ]; then 12 | exit 0 13 | fi 14 | cd $TRAVIS_BUILD_DIR 15 | RELEASE_DIR=integernet-anonymizer-${TRAVIS_TAG} 16 | mkdir -p ${RELEASE_DIR} 17 | cp -rf src/* ${RELEASE_DIR}/ 18 | cp -rf .modman/psr0autoloader/app ${RELEASE_DIR}/ 19 | cp -rf .modman/psr0autoloader/shell ${RELEASE_DIR}/ 20 | cp -rf vendor/fzaninotto/faker/src/Faker ${RELEASE_DIR}/lib/ 21 | zip -r integernet-anonymizer.zip ${RELEASE_DIR} 22 | tar -czf integernet-anonymizer.tar.gz ${RELEASE_DIR} 23 | printf "\x1b[32mBundled release ${TRAVIS_TAG}\x1b[0m" -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | IntegerNet_Anonymizer 2 | ===================== 3 | This module allows anonymizing customer data in a sensible way. It uses dummy data provided by Faker and maintains associations like customer address <=> order address. 4 | 5 | Facts 6 | ----- 7 | 8 | | Branch | Build Status | Code Quality | 9 | | ------ | ------------ | ------------ | 10 | | master | [![Build Status (master)](https://travis-ci.org/integer-net/Anonymizer.svg?branch=master)](https://travis-ci.org/integer-net/Anonymizer) | [![Scrutinizer Code Quality (master](https://scrutinizer-ci.com/g/integer-net/Anonymizer/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/integer-net/Anonymizer/?branch=master) | 11 | | development | [![Build Status (development)](https://travis-ci.org/integer-net/Anonymizer.svg?branch=development)](https://travis-ci.org/integer-net/Anonymizer) | [![Scrutinizer Code Quality (development](https://scrutinizer-ci.com/g/integer-net/Anonymizer/badges/quality-score.png?b=development)](https://scrutinizer-ci.com/g/integer-net/Anonymizer/?branch=development) | 12 | 13 | - version: 2.0.0 14 | - extension key: integer-net/anonymizer 15 | - [extension on GitHub](https://github.com/integer-net/Anonymizer) 16 | - [direct download link](https://github.com/integer-net/Anonymizer/archive/master.zip) 17 | 18 | Usage 19 | ----------- 20 | Run the anonymizer via command line: 21 | 22 | cd shell 23 | php anonymizer.php 24 | 25 | To display progress in real time: 26 | 27 | php anonymizer.php --progress 28 | 29 | To only update the progress display every 100 entities: 30 | 31 | php anonymizer.php --progress 100 32 | 33 | If you have n98-magerun installed, you can also use this command: 34 | 35 | n98-magerun db:anonymize 36 | 37 | **Be aware that the process will run very long if you have more than a few thousand orders. Consider deleting old sales data first.** 38 | 39 | [![asciicast](https://asciinema.org/a/9j4kylm874s4legd8ddbj494m.png)](https://asciinema.org/a/9j4kylm874s4legd8ddbj494m) 40 | 41 | 42 | Requirements 43 | ------------ 44 | - PHP >= 5.4 45 | - [Faker](https://github.com/fzaninotto/faker) 46 | - [Magento-PSR-0-Autoloader](https://github.com/magento-hackathon/Magento-PSR-0-Autoloader) 47 | 48 | Compatibility 49 | ------------- 50 | - Magento CE 1.7, 1.8, 1.9 51 | - Magento EE 1.12, 1.13, 1.14 52 | 53 | Installation Instructions 54 | ------------------------- 55 | 1. Install via composer: `composer require integer-net/anonymizer` 56 | 2. Configure Magento-PSR-0-Autoloader to use the composer autoloader. Add this to the `global` node of your `app/etc/local.xml`: 57 | 58 | 59 | 60 | Alternatively download the archive from the [Github release page](https://github.com/integer-net/Anonymizer/releases) and extract it into your installation. It contains the Faker library and no additional configuration is required. 61 | 62 | Support 63 | ------- 64 | If you have any issues with this extension, open an issue on [GitHub](https://github.com/integer-net/Anonymizer/issues). 65 | 66 | Contribution 67 | ------------ 68 | Any contribution is highly appreciated. The best way to contribute code is to open a [pull request on GitHub](https://help.github.com/articles/using-pull-requests). 69 | 70 | Developer 71 | --------- 72 | Fabian Schmengler, [integer_net GmbH](http://www.integer-net.de) 73 | 74 | Twitter: [@fschmengler](https://twitter.com/fschmengler) [@integer_net](https://twitter.com/integer_net) 75 | 76 | Licence 77 | ------- 78 | [OSL - Open Software Licence 3.0](http://opensource.org/licenses/osl-3.0.php) 79 | 80 | Copyright 81 | --------- 82 | © 2015 integer_net GmbH 83 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "integer-net/anonymizer", 3 | "license": "OSL-3.0", 4 | "type": "magento-module", 5 | "description": "Anonymizes all Customer Data", 6 | "require": { 7 | "fzaninotto/faker": ">=1.0", 8 | "firegento/psr0autoloader": ">=0.1.0" 9 | }, 10 | "autoload": { 11 | "psr-4": { 12 | "IntegerNet\\Anonymizer\\": "src/lib/IntegerNet/Anonymizer" 13 | } 14 | }, 15 | "autoload-dev": { 16 | "psr-4": { 17 | "IntegerNet\\Anonymizer\\": "test/IntegerNet/Anonymizer" 18 | } 19 | }, 20 | "require-dev": { 21 | "ecomdev/ecomdev_phpunit": "dev-dev@dev", 22 | "aoepeople/composer-installers": "*" 23 | }, 24 | "repositories": [ 25 | { 26 | "type": "composer", 27 | "url": "https://packages.firegento.com" 28 | } 29 | ], 30 | "authors":[ 31 | { 32 | "name":"Fabian Schmengler", 33 | "email":"fs@integer-net.de" 34 | } 35 | ] 36 | } -------------------------------------------------------------------------------- /modman: -------------------------------------------------------------------------------- 1 | src/app/code/community/IntegerNet/Anonymizer app/code/community/IntegerNet/Anonymizer 2 | src/app/etc/modules/* app/etc/modules/ 3 | src/lib/IntegerNet/* lib/IntegerNet/ 4 | src/lib/n98-magerun/modules/IntegerNet_Anonymizer lib/n98-magerun/modules/IntegerNet_Anonymizer 5 | 6 | @shell cp -fu $MODULE/src/shell/* $PROJECT/shell/ -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | ./test/ 16 | 17 | 18 | 19 | 20 | 21 | ./src/ 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/app/code/community/IntegerNet/Anonymizer/Model/Anonymizer.php: -------------------------------------------------------------------------------- 1 | 9 | */ 10 | 11 | class IntegerNet_Anonymizer_Model_Anonymizer 12 | { 13 | /** 14 | * @var \IntegerNet\Anonymizer\Updater 15 | */ 16 | protected $_updater; 17 | 18 | public function __construct() 19 | { 20 | $anonymizer = new \IntegerNet\Anonymizer\Anonymizer(); 21 | $this->_updater = new \IntegerNet\Anonymizer\Updater($anonymizer); 22 | } 23 | protected function _getEntityModels() 24 | { 25 | $entityModelsConfigXml = Mage::getConfig()->getNode('global/integernet_anonymizer/entity_models'); 26 | 27 | $entityModelsConfigArray = $entityModelsConfigXml->asArray(); 28 | $entityModelsConfigArray = $this->_sortEntityModelsConfig($entityModelsConfigArray); 29 | 30 | $entityModels = []; 31 | 32 | foreach ($entityModelsConfigArray as $entityModelsConfig) { 33 | $entityModel = Mage::getModel($entityModelsConfig['class']); 34 | if ($entityModel instanceof IntegerNet_Anonymizer_Model_Bridge_Entity_Abstract 35 | && $entityModel->entityExists()) { 36 | $entityModels[] = $entityModelsConfig['class']; 37 | } 38 | } 39 | 40 | return $entityModels; 41 | } 42 | protected function _sortEntityModelsConfig($entityModelsConfig) 43 | { 44 | usort( 45 | $entityModelsConfig, 46 | function ($entityModel1, $entityModel2) { 47 | return strcmp($entityModel1['sort'], $entityModel2['sort']); 48 | } 49 | ); 50 | return $entityModelsConfig; 51 | } 52 | /** 53 | * @param resource $stream stream resource used for output (for example opened file pointer or STDOUT) 54 | */ 55 | public function setOutputStream($stream) 56 | { 57 | $this->_updater->setOutputStream($stream); 58 | } 59 | /** 60 | * @param boolean $showProgress True if progress should be output (default is true) 61 | */ 62 | public function setShowProgress($showProgress) 63 | { 64 | $this->_updater->setShowProgress($showProgress); 65 | } 66 | /** 67 | * @param $steps How often progress output should be refreshed (default is 1 = after every entity update; example: 10 = every 10 entity updates) 68 | */ 69 | public function setProgressSteps($steps) 70 | { 71 | $this->_updater->setProgressSteps($steps); 72 | } 73 | 74 | public function anonymizeAll() 75 | { 76 | /** @var Varien_Db_Adapter_Interface $connection */ 77 | $connection = Mage::getSingleton('core/resource')->getConnection('core_write'); 78 | $connection->beginTransaction(); 79 | try { 80 | foreach ($this->_getEntityModels() as $entityModelAlias) { 81 | /** @var IntegerNet_Anonymizer_Model_Bridge_Entity_Abstract $entityModel */ 82 | $entityModel = Mage::getModel($entityModelAlias); 83 | while ($collectionIterator = $entityModel->getCollectionIterator()) { 84 | $this->_updater->update($collectionIterator, $entityModel); 85 | } 86 | } 87 | $connection->commit(); 88 | } catch (\Exception $e) { 89 | $connection->rollBack(); 90 | throw $e; 91 | } 92 | } 93 | public function anonymizeStore() 94 | { 95 | //TODO different locales per store 96 | } 97 | protected function _clearPaymentData() 98 | { 99 | //TODO UPDATE sales_flat_order_payment SET additional_data=NULL, additional_information=NULL 100 | } 101 | } -------------------------------------------------------------------------------- /src/app/code/community/IntegerNet/Anonymizer/Model/Bridge/Entity/Abstract.php: -------------------------------------------------------------------------------- 1 | 11 | */ 12 | abstract class IntegerNet_Anonymizer_Model_Bridge_Entity_Abstract 13 | implements IntegerNet\Anonymizer\Implementor\AnonymizableEntity 14 | { 15 | const ROWS_PER_QUERY = 50000; 16 | /** 17 | * @var string 18 | */ 19 | protected $_identifier; 20 | /** 21 | * @var Mage_Core_Model_Abstract 22 | */ 23 | protected $_entity; 24 | /** 25 | * @var string|null is overridden with entity type code if the model is a EAV entity 26 | */ 27 | protected $_entityType = null; 28 | /** 29 | * @var string[] 30 | */ 31 | protected $_formattersByAttribute = array(); 32 | /** 33 | * @var string[] Specifies attributes that will be loaded 34 | */ 35 | protected $_attributesUsedForIdentifier = array(); 36 | /** 37 | * @var string[] 38 | */ 39 | protected $_uniqueAttributes = array(); 40 | /** 41 | * @var AnonymizableValue[] 42 | */ 43 | protected $_values; 44 | /** 45 | * @var int Current page of collection for chunking 46 | */ 47 | protected $currentPage = 0; 48 | 49 | /** 50 | * Returns identifier, for example the customer email address. Entities with the same identifier will get the same 51 | * anonymized values. 52 | * 53 | * Important: The return value must not be affected by anonymization! 54 | * 55 | * @return string 56 | */ 57 | public function getIdentifier() 58 | { 59 | return $this->_identifier; 60 | } 61 | 62 | /** 63 | * Sets identifier based on current entity 64 | * 65 | * @return void 66 | */ 67 | abstract protected function _setIdentifier(); 68 | 69 | /** 70 | * @return AnonymizableValue[] 71 | */ 72 | public function getValues() 73 | { 74 | if ($this->_values === null) { 75 | $this->_values = array(); 76 | foreach ($this->_formattersByAttribute as $attribute => $formatter) { 77 | $this->_values[$attribute] = new AnonymizableValue( 78 | $formatter, $this->_entity->getDataUsingMethod($attribute), 79 | in_array($attribute, $this->_uniqueAttributes)); 80 | } 81 | } 82 | return $this->_values; 83 | } 84 | 85 | /** 86 | * Sets raw data from database 87 | * 88 | * @param string[] $data 89 | * @return void 90 | */ 91 | public function setRawData($data) 92 | { 93 | $this->_entity->addData($data); 94 | // reset derived attributes: 95 | $this->_setIdentifier(); 96 | $this->_values = null; 97 | } 98 | 99 | /** 100 | * Update values in database 101 | * 102 | * @return void 103 | */ 104 | public function updateValues() 105 | { 106 | $resource = $this->_entity->getResource(); 107 | $staticAttributes = array(); 108 | foreach ($this->getValues() as $attributeCode => $value) { 109 | if (!$resource instanceof Mage_Eav_Model_Entity_Abstract) { 110 | $staticAttributes[$attributeCode] = $value->getValue(); 111 | continue; 112 | } 113 | $attribute = Mage::getSingleton('eav/config')->getAttribute($this->_entityType, $attributeCode); 114 | if ($attribute->isStatic()) { 115 | $staticAttributes[$attributeCode] = $value->getValue(); 116 | continue; 117 | } 118 | $this->_entity->setData($attributeCode, $value->getValue()); 119 | $resource->saveAttribute($this->_entity, $attributeCode); 120 | } 121 | if (!empty($staticAttributes)) { 122 | $this->_entity->addData($staticAttributes); 123 | if ($resource instanceof Mage_Eav_Model_Entity_Abstract) { 124 | $resource->isPartialSave(true); 125 | } 126 | try { 127 | $resource->save($this->_entity); 128 | } catch (Mage_Customer_Exception $e) { 129 | // 'This customer email already exists' 130 | //TODO instead exclude all customers with @example.* email addresses from the customer collection 131 | // AND from associated collections as well 132 | } 133 | } 134 | } 135 | 136 | /** 137 | * Reset to empty instance 138 | * 139 | * @return void 140 | */ 141 | public function clearInstance() 142 | { 143 | $this->_entity->setData(array()); 144 | $this->_entity->clearInstance(); 145 | // reset derived attributes 146 | $this->setRawData(array()); 147 | } 148 | 149 | /** 150 | * @return IntegerNet_Anonymizer_Model_Bridge_Iterator|null 151 | */ 152 | public function getCollectionIterator() 153 | { 154 | /** @var Varien_Data_Collection_Db $collection */ 155 | $collection = $this->_entity->getCollection(); 156 | $fields = array_unique(array_merge( 157 | array_keys($this->_formattersByAttribute), 158 | $this->_attributesUsedForIdentifier 159 | )); 160 | if ($collection instanceof Mage_Eav_Model_Entity_Collection_Abstract) { 161 | $collection->addAttributeToSelect($fields, 'left'); 162 | } elseif ($collection instanceof Mage_Core_Model_Resource_Db_Collection_Abstract) { 163 | $collection->addFieldToSelect($fields); 164 | } 165 | $iterationOffset = $this->currentPage * self::ROWS_PER_QUERY; 166 | if ($collection->getSize() <= $iterationOffset) { 167 | return null; 168 | } 169 | $this->currentPage++; 170 | $collection->getSelect()->limitPage($this->currentPage, self::ROWS_PER_QUERY); 171 | /** @var IntegerNet_Anonymizer_Model_Bridge_Iterator $iterator */ 172 | $iterator = Mage::getModel('integernet_anonymizer/bridge_iterator', $collection); 173 | $iterator->setIterationOffset($iterationOffset); 174 | return $iterator; 175 | } 176 | 177 | /** 178 | * Check if the entity exists 179 | * @return bool 180 | */ 181 | public function entityExists() 182 | { 183 | return (bool)$this->_entity; 184 | } 185 | } -------------------------------------------------------------------------------- /src/app/code/community/IntegerNet/Anonymizer/Model/Bridge/Entity/Address/Abstract.php: -------------------------------------------------------------------------------- 1 | 9 | */ 10 | abstract class IntegerNet_Anonymizer_Model_Bridge_Entity_Address_Abstract 11 | extends IntegerNet_Anonymizer_Model_Bridge_Entity_Abstract 12 | { 13 | protected $_formattersByAttribute = array( 14 | 'firstname' => 'firstName', 15 | 'lastname' => 'lastName', 16 | 'middlename' => 'firstName', 17 | 'prefix' => 'title', 18 | 'suffix' => 'suffix', 19 | 'company' => 'company', 20 | 'city' => 'city', 21 | 'street' => 'streetAddress', 22 | 'telephone' => 'phoneNumber', 23 | 'fax' => 'phoneNumber', 24 | 'vat_id' => 'randomNumber' // 'vat' provider is not implemented for most counries 25 | ); 26 | 27 | /** 28 | * Sets identifier based on current entity 29 | * 30 | * @return void 31 | */ 32 | protected function _setIdentifier() 33 | { 34 | $customerId = $this->_entity->getCustomerId(); 35 | if ($customerId) { 36 | $this->_identifier = $customerId; 37 | return; 38 | } 39 | $entityId = $this->_entity->getId(); 40 | if ($entityId) { 41 | $this->_identifier = $this->getEntityName() . $entityId; 42 | return; 43 | } 44 | $this->_identifier = null; 45 | } 46 | 47 | } -------------------------------------------------------------------------------- /src/app/code/community/IntegerNet/Anonymizer/Model/Bridge/Entity/Address/CustomerAddress.php: -------------------------------------------------------------------------------- 1 | 9 | */ 10 | class IntegerNet_Anonymizer_Model_Bridge_Entity_Address_CustomerAddress 11 | extends IntegerNet_Anonymizer_Model_Bridge_Entity_Address_Abstract 12 | { 13 | protected $_attributesUsedForIdentifier = array( 14 | 'parent_id' 15 | ); 16 | 17 | protected $_entityType = 'customer_address'; 18 | 19 | function __construct() 20 | { 21 | $this->_entity = Mage::getModel('customer/address'); 22 | } 23 | 24 | /** 25 | * Returns name of entity as translatable string 26 | * 27 | * @return string 28 | */ 29 | function getEntityName() 30 | { 31 | return 'Customer Address'; 32 | } 33 | 34 | 35 | } -------------------------------------------------------------------------------- /src/app/code/community/IntegerNet/Anonymizer/Model/Bridge/Entity/Address/OrderAddress.php: -------------------------------------------------------------------------------- 1 | 9 | */ 10 | class IntegerNet_Anonymizer_Model_Bridge_Entity_Address_OrderAddress 11 | extends IntegerNet_Anonymizer_Model_Bridge_Entity_Address_Abstract 12 | { 13 | protected $_attributesUsedForIdentifier = array( 14 | 'customer_id' 15 | ); 16 | 17 | function __construct() 18 | { 19 | $this->_entity = Mage::getModel('sales/order_address'); 20 | } 21 | 22 | /** 23 | * Returns name of entity as translatable string 24 | * 25 | * @return string 26 | */ 27 | function getEntityName() 28 | { 29 | return 'Order Address'; 30 | } 31 | 32 | } -------------------------------------------------------------------------------- /src/app/code/community/IntegerNet/Anonymizer/Model/Bridge/Entity/Address/QuoteAddress.php: -------------------------------------------------------------------------------- 1 | 9 | */ 10 | class IntegerNet_Anonymizer_Model_Bridge_Entity_Address_QuoteAddress 11 | extends IntegerNet_Anonymizer_Model_Bridge_Entity_Address_Abstract 12 | { 13 | protected $_attributesUsedForIdentifier = array( 14 | 'customer_id' 15 | ); 16 | 17 | function __construct() 18 | { 19 | $this->_entity = Mage::getModel('sales/quote_address'); 20 | } 21 | 22 | /** 23 | * Returns name of entity as translatable string 24 | * 25 | * @return string 26 | */ 27 | function getEntityName() 28 | { 29 | return 'Quote Address'; 30 | } 31 | 32 | 33 | } -------------------------------------------------------------------------------- /src/app/code/community/IntegerNet/Anonymizer/Model/Bridge/Entity/Customer.php: -------------------------------------------------------------------------------- 1 | 9 | */ 10 | class IntegerNet_Anonymizer_Model_Bridge_Entity_Customer extends IntegerNet_Anonymizer_Model_Bridge_Entity_Abstract 11 | { 12 | protected $_entityType = 'customer'; 13 | 14 | protected $_formattersByAttribute = array( 15 | 'email' => 'safeEmail', 16 | 'firstname' => 'firstName', 17 | 'lastname' => 'lastName', 18 | 'middlename' => 'firstName', 19 | 'prefix' => 'title', 20 | 'suffix' => 'suffix', 21 | 'taxvat' => 'randomNumber' // 'vat' provider is not implemented for most counries 22 | ); 23 | protected $_uniqueAttributes = array( 24 | 'email' 25 | ); 26 | 27 | function __construct() 28 | { 29 | $this->_entity = Mage::getModel('customer/customer'); 30 | } 31 | 32 | protected function _setIdentifier() 33 | { 34 | $this->_identifier = $this->_entity->getId(); 35 | } 36 | 37 | /** 38 | * Returns name of entity as translatable string 39 | * 40 | * @return string 41 | */ 42 | function getEntityName() 43 | { 44 | return 'Customer'; 45 | } 46 | 47 | 48 | } -------------------------------------------------------------------------------- /src/app/code/community/IntegerNet/Anonymizer/Model/Bridge/Entity/Enterprise/Giftregistry.php: -------------------------------------------------------------------------------- 1 | 9 | */ 10 | class IntegerNet_Anonymizer_Model_Bridge_Entity_Enterprise_Giftregistry 11 | extends IntegerNet_Anonymizer_Model_Bridge_Entity_Abstract 12 | { 13 | 14 | protected $_formattersByAttribute = array( 15 | 'title' => 'sentence', 16 | 'message' => 'paragraph', 17 | 'shipping_address' => 'address', 18 | 'custom_values' => 'null', 19 | ); 20 | 21 | 22 | function __construct() 23 | { 24 | $this->_entity = Mage::getModel('enterprise_giftregistry/entity'); 25 | } 26 | 27 | /** 28 | * Sets identifier based on current entity 29 | * 30 | * @return void 31 | */ 32 | protected function _setIdentifier() 33 | { 34 | $entityId = $this->_entity->getId(); 35 | if ($entityId) { 36 | $this->_identifier = '_gift_registry_' . $entityId; 37 | } else { 38 | $this->_identifier = ''; 39 | } 40 | } 41 | 42 | /** 43 | * Returns name of entity as translatable string 44 | * 45 | * @return string 46 | */ 47 | function getEntityName() 48 | { 49 | return 'Gift Registry'; 50 | } 51 | 52 | 53 | } -------------------------------------------------------------------------------- /src/app/code/community/IntegerNet/Anonymizer/Model/Bridge/Entity/Enterprise/GiftregistryPerson.php: -------------------------------------------------------------------------------- 1 | 9 | */ 10 | class IntegerNet_Anonymizer_Model_Bridge_Entity_Enterprise_GiftregistryPerson 11 | extends IntegerNet_Anonymizer_Model_Bridge_Entity_Abstract 12 | { 13 | 14 | protected $_formattersByAttribute = array( 15 | 'email' => 'safeEmail', 16 | 'firstname' => 'firstName', 17 | 'lastname' => 'lastName', 18 | 'custom_values' => 'null', 19 | ); 20 | 21 | 22 | function __construct() 23 | { 24 | $this->_entity = Mage::getModel('enterprise_giftregistry/person'); 25 | } 26 | 27 | /** 28 | * Sets identifier based on current entity 29 | * 30 | * @return void 31 | */ 32 | protected function _setIdentifier() 33 | { 34 | $this->_identifier = $this->_entity->getEmail(); 35 | } 36 | 37 | /** 38 | * Returns name of entity as translatable string 39 | * 40 | * @return string 41 | */ 42 | function getEntityName() 43 | { 44 | return 'Gift Registry Person'; 45 | } 46 | 47 | 48 | } -------------------------------------------------------------------------------- /src/app/code/community/IntegerNet/Anonymizer/Model/Bridge/Entity/NewsletterSubscriber.php: -------------------------------------------------------------------------------- 1 | 9 | */ 10 | class IntegerNet_Anonymizer_Model_Bridge_Entity_NewsletterSubscriber 11 | extends IntegerNet_Anonymizer_Model_Bridge_Entity_Abstract 12 | { 13 | 14 | protected $_attributesUsedForIdentifier = array( 15 | 'customer_id' 16 | ); 17 | protected $_formattersByAttribute = array( 18 | 'subscriber_email' => 'safeEmail', 19 | ); 20 | 21 | function __construct() 22 | { 23 | $this->_entity = Mage::getModel('newsletter/subscriber'); 24 | } 25 | 26 | /** 27 | * Sets identifier based on current entity 28 | * 29 | * @return void 30 | */ 31 | protected function _setIdentifier() 32 | { 33 | $this->_identifier = $this->_entity->getCustomerId() ?: $this->_entity->getEmail(); 34 | } 35 | 36 | /** 37 | * Returns name of entity as translatable string 38 | * 39 | * @return string 40 | */ 41 | function getEntityName() 42 | { 43 | return 'Newsletter Subscriber'; 44 | } 45 | 46 | 47 | } -------------------------------------------------------------------------------- /src/app/code/community/IntegerNet/Anonymizer/Model/Bridge/Entity/Order.php: -------------------------------------------------------------------------------- 1 | 9 | */ 10 | class IntegerNet_Anonymizer_Model_Bridge_Entity_Order extends IntegerNet_Anonymizer_Model_Bridge_Entity_Abstract 11 | { 12 | protected $_entityType = 'order'; 13 | 14 | protected $_attributesUsedForIdentifier = array( 15 | 'customer_id', 'increment_id' 16 | ); 17 | 18 | protected $_formattersByAttribute = array( 19 | 'customer_email' => 'safeEmail', 20 | 'customer_firstname' => 'firstName', 21 | 'customer_lastname' => 'lastName', 22 | 'customer_middlename' => 'firstName', 23 | 'customer_prefix' => 'title', 24 | 'customer_suffix' => 'suffix', 25 | 'customer_taxvat' => 'randomNumber' // 'vat' provider is not implemented for most counries 26 | ); 27 | protected $_uniqueAttributes = array( 28 | 'customer_email' 29 | ); 30 | 31 | function __construct() 32 | { 33 | $this->_entity = Mage::getModel('sales/order'); 34 | } 35 | 36 | protected function _setIdentifier() 37 | { 38 | $this->_identifier = $this->_entity->getCustomerId(); 39 | } 40 | 41 | /** 42 | * Returns name of entity as translatable string 43 | * 44 | * @return string 45 | */ 46 | function getEntityName() 47 | { 48 | return 'Order'; 49 | } 50 | 51 | } -------------------------------------------------------------------------------- /src/app/code/community/IntegerNet/Anonymizer/Model/Bridge/Iterator.php: -------------------------------------------------------------------------------- 1 | 9 | */ 10 | class IntegerNet_Anonymizer_Model_Bridge_Iterator implements \IntegerNet\Anonymizer\Implementor\CollectionIterator 11 | { 12 | /** 13 | * @var Mage_Eav_Model_Entity_Collection_Abstract|Mage_Core_Model_Resource_Db_Collection_Abstract 14 | */ 15 | protected $_collection; 16 | /** 17 | * @var Mage_Core_Model_Resource_Iterator 18 | */ 19 | protected $_iterator; 20 | /** 21 | * @var string[] 22 | */ 23 | protected $_data; 24 | /** 25 | * @var int Iteration counter 26 | */ 27 | protected $_iteration; 28 | /** 29 | * @var int Iteration counter offset for chunking 30 | */ 31 | protected $_iterationOffset = 0; 32 | 33 | public function __construct(Varien_Data_Collection_Db $collection) 34 | { 35 | $this->_collection = $collection; 36 | $this->_iterator = Mage::getResourceModel('core/iterator'); 37 | } 38 | 39 | /** 40 | * @return Mage_Core_Model_Resource_Db_Collection_Abstract|Mage_Eav_Model_Entity_Collection_Abstract 41 | */ 42 | public function getCollection() 43 | { 44 | return $this->_collection; 45 | } 46 | 47 | /** 48 | * @param callable $callable 49 | * @return mixed 50 | */ 51 | function walk(/*callable*/ $callable) // PHP 5.3 52 | { 53 | $self = $this; // PHP 5.3 54 | $this->_iterator->walk($this->_collection->getSelect(), array( 55 | function($args) use ($callable, $self) { 56 | $self->_setIteration($args['idx']); 57 | $self->_setRawData($args['row']); 58 | $callable($self); 59 | } 60 | )); 61 | $this->_afterWalk(); 62 | } 63 | 64 | public function _setRawData($data) 65 | { 66 | $this->_data = $data; 67 | } 68 | public function _setIteration($iteration) 69 | { 70 | $this->_iteration = $iteration; 71 | } 72 | public function setIterationOffset($offset) 73 | { 74 | $this->_iterationOffset = $offset; 75 | } 76 | 77 | /** 78 | * Returns raw data from database 79 | * 80 | * @return mixed 81 | */ 82 | function getRawData() 83 | { 84 | return $this->_data; 85 | } 86 | 87 | /** 88 | * Returns number of iteration 89 | * 90 | * @return int 91 | */ 92 | function getIteration() 93 | { 94 | return $this->_iterationOffset + $this->_iteration; 95 | } 96 | 97 | /** 98 | * Returns total size of collection 99 | * 100 | * @return mixed 101 | */ 102 | function getSize() 103 | { 104 | return $this->_collection->getSize(); 105 | } 106 | 107 | /** 108 | * Additional processing at the end: 109 | * - update grid tables 110 | * 111 | * @return void 112 | */ 113 | protected function _afterWalk() 114 | { 115 | $entityResource = $this->_collection->getResource(); 116 | if ($entityResource instanceof Mage_Sales_Model_Resource_Order_Abstract) { 117 | $entityResource->updateGridRecords($this->_collection->getAllIds()); 118 | } 119 | } 120 | 121 | } -------------------------------------------------------------------------------- /src/app/code/community/IntegerNet/Anonymizer/Test/Model/Anonymizer.php: -------------------------------------------------------------------------------- 1 | 9 | */ 10 | 11 | class IntegerNet_Anonymizer_Test_Model_Anonymizer extends EcomDev_PHPUnit_Test_Case 12 | { 13 | /** 14 | * @test 15 | * @loadFixture customers.yaml 16 | */ 17 | public function testAnonymizeAllCommunity() 18 | { 19 | $this->_testAnonymizeAll(); 20 | } 21 | 22 | /** 23 | * @test 24 | */ 25 | public function isEnterprise() 26 | { 27 | if (Mage::getEdition() !== Mage::EDITION_ENTERPRISE) { 28 | $this->markTestSkipped('Skipping test for Magento Enterprise'); 29 | } 30 | } 31 | /** 32 | * @test 33 | * @depends isEnterprise 34 | * @loadFixture customers.yaml 35 | * @loadFixture enterprise.yaml 36 | */ 37 | public function testAnonymizeAllEnterprise() 38 | { 39 | $this->_testAnonymizeAll(); 40 | //TODO EE assertions 41 | $this->markTestIncomplete(); 42 | } 43 | 44 | /** 45 | * 46 | */ 47 | protected function _testAnonymizeAll() 48 | { 49 | // TEST PRE CONDITIONS 50 | 51 | /** @var Mage_Sales_Model_Resource_Order_Grid_Collection $orderGridCollection */ 52 | $orderGridCollection = Mage::getResourceModel('sales/order_grid_collection'); 53 | $orderGridData = $orderGridCollection->addFieldToFilter('entity_id', 1)->getFirstItem(); 54 | $this->assertEquals('Testname Testname', $orderGridData->getShippingName()); 55 | $this->assertEquals('Testname Testname', $orderGridData->getBillingName()); 56 | $this->assertEquals('1000000001', $orderGridData->getIncrementId(), 'Precondition: Increment ID in grid'); 57 | 58 | // RUN ANONYMIZER 59 | 60 | /** @var IntegerNet_Anonymizer_Model_Anonymizer $anonymizer */ 61 | $anonymizer = Mage::getModel('integernet_anonymizer/anonymizer'); 62 | $anonymizer->anonymizeAll(); 63 | 64 | // TEST POST CONDITIONS 65 | 66 | $customer = Mage::getModel('customer/customer')->load(2); 67 | $this->assertNotEquals('test2@test.de', $customer->getData('email')); 68 | $this->assertNotEquals('Testname', $customer->getData('firstname')); 69 | $this->assertNotEquals('Testname', $customer->getData('lastname')); 70 | 71 | $customerAddress = $customer->getDefaultBillingAddress(); 72 | $this->assertNotEquals('Testname', $customerAddress->getData('firstname')); 73 | $this->assertNotEquals('Testname', $customerAddress->getData('lastname')); 74 | $this->assertNotEquals('ACME GmbH', $customerAddress->getData('company')); 75 | $this->assertNotEquals('Buxtehude', $customerAddress->getData('city')); 76 | $this->assertNotEquals('Am Arm 1', $customerAddress->getData('street')); 77 | $this->assertNotEquals('555-12345', $customerAddress->getData('telephone')); 78 | $this->assertNotEquals('555-12345', $customerAddress->getData('fax')); 79 | $this->assertNotEquals('DE 987654321', $customerAddress->getData('vat_id')); 80 | $this->assertEquals('67890', $customerAddress->getData('postcode')); 81 | $this->assertEquals('DE', $customerAddress->getCountryId()); 82 | 83 | $quote = Mage::getModel('sales/quote')->load(1); 84 | $quoteAddress = $quote->getBillingAddress(); 85 | $this->assertEquals($customerAddress->getCustomerId(), $quoteAddress->getCustomerId(), 86 | 'Quote address and customer address refer to the same customer'); 87 | $this->assertNotEquals($customerAddress->getData('lastname'), $quoteAddress->getData('lastname'), 88 | 'Different values stay different'); 89 | $this->assertNotEquals($customerAddress->getData('lastname'), $quoteAddress->getData('lastname'), 90 | 'Different values stay different'); 91 | $this->assertEquals($customerAddress->getData('company'), $quoteAddress->getData('company'), 92 | 'Same values stay the same'); 93 | 94 | $this->assertNotEquals('Somebody', $quoteAddress->getData('firstname')); 95 | $this->assertNotEquals('Else', $quoteAddress->getData('lastname')); 96 | $this->assertNotEquals('ACME GmbH', $quoteAddress->getData('company')); 97 | $this->assertNotEquals('Buxtehude', $quoteAddress->getData('city')); 98 | $this->assertNotEquals('Am Arm 1', $quoteAddress->getData('street')); 99 | $this->assertNotEquals('555-12345', $quoteAddress->getData('telephone')); 100 | $this->assertNotEquals('555-12345', $quoteAddress->getData('fax')); 101 | $this->assertNotEquals('DE 987654321', $quoteAddress->getData('vat_id')); 102 | $this->assertEquals('67890', $quoteAddress->getData('postcode')); 103 | $this->assertEquals('DE', $quoteAddress->getCountryId()); 104 | 105 | /** @var Mage_Sales_Model_Order $order */ 106 | $order = Mage::getModel('sales/order')->load(1); 107 | $this->assertEquals('1000000001', $order->getIncrementId(), 'Increment ID should be unchanged'); 108 | $this->assertNotEquals('test2@test.de', $order->getCustomerEmail()); 109 | $this->assertNotEquals('Testname', $order->getCustomerFirstname()); 110 | $this->assertNotEquals('J', $order->getCustomerMiddlename()); 111 | $this->assertNotEquals('Testname', $order->getCustomerLastname()); 112 | $this->assertNotEquals('Kaiser', $order->getCustomerPrefix()); 113 | $this->assertNotEquals('der Große', $order->getCustomerSuffix()); 114 | 115 | $orderAddress = $order->getBillingAddress(); 116 | $this->assertEquals($quoteAddress->getCustomerId(), $orderAddress->getCustomerId(), 117 | 'Quote address and customer address refer to the same customer'); 118 | $this->assertNotEquals($quoteAddress->getData('lastname'), $orderAddress->getData('lastname'), 119 | 'Different values stay different'); 120 | $this->assertNotEquals($quoteAddress->getData('lastname'), $orderAddress->getData('lastname'), 121 | 'Different values stay different'); 122 | $this->assertEquals($quoteAddress->getData('company'), $orderAddress->getData('company'), 123 | 'Same values stay the same'); 124 | 125 | $this->assertNotEquals('Testname', $orderAddress->getData('firstname')); 126 | $this->assertNotEquals('Testname', $orderAddress->getData('lastname')); 127 | $this->assertNotEquals('ACME GmbH', $orderAddress->getData('company')); 128 | $this->assertNotEquals('Buxtehude', $orderAddress->getData('city')); 129 | $this->assertNotEquals('Am Arm 1', $orderAddress->getData('street')); 130 | $this->assertNotEquals('555-12345', $orderAddress->getData('telephone')); 131 | $this->assertNotEquals('555-12345', $orderAddress->getData('fax')); 132 | $this->assertNotEquals('DE 987654321', $orderAddress->getData('vat_id')); 133 | $this->assertEquals('67890', $orderAddress->getData('postcode')); 134 | $this->assertEquals('DE', $orderAddress->getCountryId()); 135 | 136 | /** @var Mage_Sales_Model_Resource_Order_Grid_Collection $orderGridCollection */ 137 | $orderGridCollection = Mage::getResourceModel('sales/order_grid_collection'); 138 | $orderGridData = $orderGridCollection->addFieldToFilter('entity_id', 1)->getFirstItem(); 139 | $this->assertNotEquals('Testname Testname', $orderGridData->getShippingName()); 140 | $this->assertNotEquals('Testname Testname', $orderGridData->getBillingName()); 141 | $this->assertEquals($orderAddress->getName(), $orderGridData->getBillingName()); 142 | $this->assertEquals('1000000001', $orderGridData->getIncrementId(), 'Increment ID in grid should be unchanged'); 143 | 144 | $subscriber = Mage::getModel('newsletter/subscriber')->load(1); 145 | $this->assertNotEquals('guest1@example.com', $subscriber->getSubscriberEmail()); 146 | 147 | 148 | $guestQuote = Mage::getModel('sales/quote')->load(2); 149 | $guestQuoteAddress = $guestQuote->getBillingAddress(); 150 | $otherGuestQuote = Mage::getModel('sales/quote')->load(3); 151 | $otherGuestQuoteAddress = $otherGuestQuote->getBillingAddress(); 152 | 153 | $this->assertNotEquals($guestQuoteAddress->getData('firstname'), $otherGuestQuoteAddress->getData('firstname')); 154 | $this->assertNotEquals($guestQuoteAddress->getData('lastname'), $otherGuestQuoteAddress->getData('lastname')); 155 | $this->assertNotEquals($guestQuoteAddress->getData('company'), $otherGuestQuoteAddress->getData('company')); 156 | $this->assertNotEquals($guestQuoteAddress->getData('city'), $otherGuestQuoteAddress->getData('city')); 157 | $this->assertNotEquals($guestQuoteAddress->getData('street'), $otherGuestQuoteAddress->getData('street')); 158 | $this->assertNotEquals($guestQuoteAddress->getData('telephone'), $otherGuestQuoteAddress->getData('telephone')); 159 | $this->assertNotEquals($guestQuoteAddress->getData('fax'), $otherGuestQuoteAddress->getData('fax')); 160 | $this->assertNotEquals($guestQuoteAddress->getData('vat_id'), $otherGuestQuoteAddress->getData('vat_id')); 161 | 162 | } 163 | } -------------------------------------------------------------------------------- /src/app/code/community/IntegerNet/Anonymizer/Test/Model/Bridge/Entity/Abstract.php: -------------------------------------------------------------------------------- 1 | 9 | */ 10 | abstract class IntegerNet_Anonymizer_Test_Model_Bridge_Entity_Abstract extends EcomDev_PHPUnit_Test_Case 11 | { 12 | /** 13 | * @param $bridge 14 | * @param $expected 15 | */ 16 | protected function _testGetValues(IntegerNet_Anonymizer_Model_Bridge_Entity_Abstract $bridge, 17 | Mage_Core_Model_Abstract $model, Varien_Object $expected) 18 | { 19 | $bridge->setRawData($model->getData()); 20 | $this->assertEquals($expected['identifier'], $bridge->getIdentifier(), 'Identifier'); 21 | $actualValues = $bridge->getValues(); 22 | reset($actualValues); 23 | foreach ($expected['values'] as $expectedValue) { 24 | $this->assertInstanceOf(IntegerNet\Anonymizer\AnonymizableValue::__CLASS, 25 | current($actualValues), 'Value instance'); 26 | $this->assertEquals($expectedValue['formatter'], 27 | current($actualValues)->getFakerFormatter(), 'Value formatter'); 28 | $this->assertEquals($expectedValue['value'], 29 | current($actualValues)->getValue(), 'Value'); 30 | if (!empty($expectedValue['unique'])) { 31 | $this->assertTrue(current($actualValues)->isUnique(), 'Unique'); 32 | } 33 | next($actualValues); 34 | } 35 | } 36 | 37 | /** 38 | * @param $bridge 39 | */ 40 | protected function _updateValues($bridge) 41 | { 42 | $bridge->updateValues(); 43 | 44 | $this->assertNotEquals('', $bridge->getIdentifier()); 45 | $bridge->clearInstance(); 46 | $this->assertEquals('', $bridge->getIdentifier()); 47 | foreach ($bridge->getValues() as $value) { 48 | $this->logicalOr( 49 | $this->isEmpty($value->getValue()), 50 | $this->equalTo(array('')) 51 | ); 52 | } 53 | } 54 | 55 | /** 56 | * @param $id 57 | * @param $bridge 58 | * @return mixed 59 | */ 60 | protected function _loadEntityByCollection($idField, $id, $bridge) 61 | { 62 | $entity = $bridge->getCollectionIterator()->getCollection() 63 | ->addFieldToFilter($idField, $id) 64 | ->getFirstItem(); 65 | return $entity; 66 | } 67 | } -------------------------------------------------------------------------------- /src/app/code/community/IntegerNet/Anonymizer/Test/Model/Bridge/Entity/Customer.php: -------------------------------------------------------------------------------- 1 | 9 | */ 10 | 11 | /** 12 | * @group IntegerNet_Anonymizer 13 | */ 14 | class IntegerNet_Anonymizer_Test_Model_Bridge_Entity_Customer 15 | extends IntegerNet_Anonymizer_Test_Model_Bridge_Entity_Abstract 16 | { 17 | /** 18 | * @param $customerId 19 | * @test 20 | * @dataProvider dataProvider 21 | * @dataProviderFile testCustomerBridge.yaml 22 | * @loadExpectation bridge.yaml 23 | * @loadFixture customers.yaml 24 | */ 25 | public function testGetValues($customerId) 26 | { 27 | /** @var IntegerNet_Anonymizer_Model_Bridge_Entity_Customer $bridge */ 28 | $bridge = Mage::getModel('integernet_anonymizer/bridge_entity_customer'); 29 | /** @var Mage_Customer_Model_Customer $customer */ 30 | $customer = $this->_loadEntityByCollection('entity_id', $customerId, $bridge); 31 | $expected = $this->expected('customer_%d', $customerId); 32 | 33 | $this->_testGetValues($bridge, $customer, $expected); 34 | } 35 | 36 | /** 37 | * @param $customerId 38 | * @test 39 | * @dataProvider dataProvider 40 | * @dataProviderFile testCustomerBridge.yaml 41 | * @loadFixture customers.yaml 42 | */ 43 | public function testUpdateValues($customerId) 44 | { 45 | static $changedEmail = 'changed@example.com', 46 | $changedMiddlename = 'trouble'; 47 | 48 | /** @var IntegerNet_Anonymizer_Model_Bridge_Entity_Customer $bridge */ 49 | $bridge = Mage::getModel('integernet_anonymizer/bridge_entity_customer'); 50 | 51 | $bridge->setRawData(array( 52 | 'entity_id' => $customerId, 53 | 'email' => $changedEmail, 54 | 'middlename' => $changedMiddlename 55 | )); 56 | 57 | $this->_updateValues($bridge); 58 | 59 | $customer = Mage::getModel('customer/customer')->load($customerId); 60 | $this->assertEquals($changedMiddlename, $customer->getMiddlename()); 61 | $this->assertEquals($changedEmail, $customer->getEmail()); 62 | } 63 | 64 | } -------------------------------------------------------------------------------- /src/app/code/community/IntegerNet/Anonymizer/Test/Model/Bridge/Entity/CustomerAddress.php: -------------------------------------------------------------------------------- 1 | 9 | */ 10 | 11 | /** 12 | * @group IntegerNet_Anonymizer 13 | */ 14 | class IntegerNet_Anonymizer_Test_Model_Bridge_Entity_CustomerAddress 15 | extends IntegerNet_Anonymizer_Test_Model_Bridge_Entity_Abstract 16 | { 17 | /** 18 | * @param $customerAddressId 19 | * @test 20 | * @dataProvider dataProvider 21 | * @dataProviderFile testCustomerAddressBridge.yaml 22 | * @loadExpectation bridge.yaml 23 | * @loadFixture customers.yaml 24 | */ 25 | public function testGetValues($customerAddressId) 26 | { 27 | /** @var IntegerNet_Anonymizer_Model_Bridge_Entity_CustomerAddress $bridge */ 28 | $bridge = Mage::getModel('integernet_anonymizer/bridge_entity_address_customerAddress'); 29 | /** @var Mage_Customer_Model_Address $customerAddress */ 30 | $customerAddress = $this->_loadEntityByCollection('entity_id', $customerAddressId, $bridge); 31 | $expected = $this->expected('customer_address_%d', $customerAddressId); 32 | 33 | $this->_testGetValues($bridge, $customerAddress, $expected); 34 | } 35 | 36 | /** 37 | * @param $customerAddressId 38 | * @test 39 | * @dataProvider dataProvider 40 | * @dataProviderFile testCustomerAddressBridge.yaml 41 | * @loadFixture customers.yaml 42 | */ 43 | public function testUpdateValues($customerAddressId) 44 | { 45 | static $changedMiddlename = 'trouble', 46 | $changedStreet = "New Street\nSecond Line"; 47 | 48 | /** @var IntegerNet_Anonymizer_Model_Bridge_Entity_Address_CustomerAddress $bridge */ 49 | $bridge = Mage::getModel('integernet_anonymizer/bridge_entity_address_customerAddress'); 50 | 51 | /** @var Mage_Customer_Model_Address $customerAddress */ 52 | $dataProvider = Mage::getModel('customer/address')->load($customerAddressId); 53 | $bridge->setRawData($dataProvider->load($customerAddressId)->getData()); 54 | $bridge->getValues()['middlename']->setValue($changedMiddlename); 55 | $bridge->getValues()['street']->setValue($changedStreet); 56 | 57 | $this->_updateValues($bridge); 58 | 59 | $customerAddress = Mage::getModel('customer/address')->load($customerAddressId); 60 | $this->assertEquals($changedMiddlename, $customerAddress->getMiddlename()); 61 | $this->assertEquals($changedStreet, $customerAddress->getStreetFull()); 62 | } 63 | 64 | 65 | } -------------------------------------------------------------------------------- /src/app/code/community/IntegerNet/Anonymizer/Test/Model/Bridge/Entity/Giftregistry.php: -------------------------------------------------------------------------------- 1 | 9 | */ 10 | 11 | /** 12 | * @group IntegerNet_Anonymizer 13 | */ 14 | class IntegerNet_Anonymizer_Test_Model_Bridge_Entity_Giftregistry 15 | extends IntegerNet_Anonymizer_Test_Model_Bridge_Entity_Abstract 16 | { 17 | /** 18 | * @test 19 | */ 20 | public function isEnterprise() 21 | { 22 | if (Mage::getEdition() !== Mage::EDITION_ENTERPRISE) { 23 | $this->markTestSkipped('Skipping test for Magento Enterprise'); 24 | } 25 | } 26 | 27 | /** 28 | * @param $registryId 29 | * @test 30 | * @depends isEnterprise 31 | * @dataProvider dataProvider 32 | * @dataProviderFile testGiftregistryBridge.yaml 33 | * @loadExpectation bridge.yaml 34 | * @loadFixture customers.yaml 35 | * @loadFixture enterprise.yaml 36 | */ 37 | public function testGetValues($registryId) 38 | { 39 | /** @var IntegerNet_Anonymizer_Model_Bridge_Entity_Enterprise_Giftregistry $bridge */ 40 | $bridge = Mage::getModel('integernet_anonymizer/bridge_entity_enterprise_giftregistry'); 41 | /** @var Enterprise_GiftRegistry_Model_Entity $registry */ 42 | $registry = $this->_loadEntityByCollection('entity_id', $registryId, $bridge); 43 | $expected = $this->expected('giftregistry_%d', $registryId); 44 | 45 | $this->_testGetValues($bridge, $registry, $expected); 46 | } 47 | 48 | /** 49 | * @param $registryId 50 | * @test 51 | * @depends isEnterprise 52 | * @dataProvider dataProvider 53 | * @dataProviderFile testGiftregistryBridge.yaml 54 | * @loadFixture customers.yaml 55 | * @loadFixture enterprise.yaml 56 | */ 57 | public function testUpdateValues($registryId) 58 | { 59 | static $changedTitle = 'Changed Gift Registry Title'; 60 | 61 | /** @var IntegerNet_Anonymizer_Model_Bridge_Entity_Enterprise_Giftregistry $bridge */ 62 | $bridge = Mage::getModel('integernet_anonymizer/bridge_entity_enterprise_giftregistry'); 63 | 64 | $dataProvider = Mage::getModel('enterprise_giftregistry/entity'); 65 | $bridge->setRawData($dataProvider->load($registryId)->setId($registryId)->getData()); 66 | $bridge->getValues()['title']->setValue($changedTitle); 67 | 68 | $this->_updateValues($bridge); 69 | 70 | $registry = Mage::getModel('enterprise_giftregistry/entity')->load($registryId); 71 | $this->assertEquals($changedTitle, $registry->getTitle()); 72 | } 73 | } -------------------------------------------------------------------------------- /src/app/code/community/IntegerNet/Anonymizer/Test/Model/Bridge/Entity/GiftregistryPerson.php: -------------------------------------------------------------------------------- 1 | 9 | */ 10 | 11 | /** 12 | * @group IntegerNet_Anonymizer 13 | */ 14 | class IntegerNet_Anonymizer_Test_Model_Bridge_Entity_GiftregistryPerson 15 | extends IntegerNet_Anonymizer_Test_Model_Bridge_Entity_Abstract 16 | { 17 | /** 18 | * @test 19 | */ 20 | public function isEnterprise() 21 | { 22 | if (Mage::getEdition() !== Mage::EDITION_ENTERPRISE) { 23 | $this->markTestSkipped('Skipping test for Magento Enterprise'); 24 | } 25 | } 26 | 27 | /** 28 | * @param $personId 29 | * @test 30 | * @depends isEnterprise 31 | * @dataProvider dataProvider 32 | * @dataProviderFile testGiftregistryPersonBridge.yaml 33 | * @loadExpectation bridge.yaml 34 | * @loadFixture customers.yaml 35 | * @loadFixture enterprise.yaml 36 | */ 37 | public function testGetValues($personId) 38 | { 39 | /** @var IntegerNet_Anonymizer_Model_Bridge_Entity_Enterprise_GiftregistryPerson $bridge */ 40 | $bridge = Mage::getModel('integernet_anonymizer/bridge_entity_enterprise_giftregistryPerson'); 41 | /** @var Enterprise_GiftRegistry_Model_Person $person */ 42 | $person = $this->_loadEntityByCollection('person_id', $personId, $bridge); 43 | $expected = $this->expected('giftregistry_person_%d', $personId); 44 | 45 | $this->_testGetValues($bridge, $person, $expected); 46 | } 47 | 48 | /** 49 | * @param $registryId 50 | * @test 51 | * @depends isEnterprise 52 | * @dataProvider dataProvider 53 | * @dataProviderFile testGiftregistryPersonBridge.yaml 54 | * @loadFixture customers.yaml 55 | * @loadFixture enterprise.yaml 56 | */ 57 | public function testUpdateValues($registryId) 58 | { 59 | static $changedEmail = 'changed@email.com'; 60 | 61 | /** @var IntegerNet_Anonymizer_Model_Bridge_Entity_Enterprise_GiftregistryPerson $bridge */ 62 | $bridge = Mage::getModel('integernet_anonymizer/bridge_entity_enterprise_giftregistryPerson'); 63 | 64 | $dataProvider = Mage::getModel('enterprise_giftregistry/person');; 65 | $bridge->setRawData($dataProvider->load($registryId)->setId($registryId)->getData()); 66 | $bridge->getValues()['email']->setValue($changedEmail); 67 | 68 | $this->_updateValues($bridge); 69 | 70 | $person = Mage::getModel('enterprise_giftregistry/person')->load($registryId); 71 | $this->assertEquals($changedEmail, $person->getEmail()); 72 | } 73 | } -------------------------------------------------------------------------------- /src/app/code/community/IntegerNet/Anonymizer/Test/Model/Bridge/Entity/NewsletterSubscriber.php: -------------------------------------------------------------------------------- 1 | 9 | */ 10 | 11 | /** 12 | * @group IntegerNet_Anonymizer 13 | */ 14 | class IntegerNet_Anonymizer_Test_Model_Bridge_Entity_NewsletterSubscriber 15 | extends IntegerNet_Anonymizer_Test_Model_Bridge_Entity_Abstract 16 | { 17 | /** 18 | * @param $subscriberId 19 | * @test 20 | * @dataProvider dataProvider 21 | * @dataProviderFile testNewsletterSubscriberBridge.yaml 22 | * @loadExpectation bridge.yaml 23 | * @loadFixture customers.yaml 24 | */ 25 | public function testGetValues($subscriberId) 26 | { 27 | /** @var IntegerNet_Anonymizer_Model_Bridge_Entity_NewsletterSubscriber $bridge */ 28 | $bridge = Mage::getModel('integernet_anonymizer/bridge_entity_newsletterSubscriber'); 29 | /** @var Mage_Newsletter_Model_Subscriber $subscriber */ 30 | $subscriber = $this->_loadEntityByCollection('subscriber_id', $subscriberId, $bridge); 31 | $expected = $this->expected('newsletter_subscriber_%d', $subscriberId); 32 | 33 | $this->_testGetValues($bridge, $subscriber, $expected); 34 | } 35 | 36 | /** 37 | * @param $subscriberId 38 | * @test 39 | * @dataProvider dataProvider 40 | * @dataProviderFile testNewsletterSubscriberBridge.yaml 41 | * @loadFixture customers.yaml 42 | */ 43 | public function testUpdateValues($subscriberId) 44 | { 45 | static $changedEmail = 'changed@example.com'; 46 | 47 | /** @var IntegerNet_Anonymizer_Model_Bridge_Entity_NewsletterSubscriber $bridge */ 48 | $bridge = Mage::getModel('integernet_anonymizer/bridge_entity_newsletterSubscriber'); 49 | 50 | $dataProvider = Mage::getModel('newsletter/subscriber'); 51 | $bridge->setRawData($dataProvider->load($subscriberId)->getData()); 52 | $bridge->getValues()['subscriber_email']->setValue($changedEmail); 53 | 54 | $this->_updateValues($bridge); 55 | 56 | $subscriber = Mage::getModel('newsletter/subscriber')->load($subscriberId); 57 | $this->assertEquals($changedEmail, $subscriber->getSubscriberEmail()); 58 | } 59 | } -------------------------------------------------------------------------------- /src/app/code/community/IntegerNet/Anonymizer/Test/Model/Bridge/Entity/Order.php: -------------------------------------------------------------------------------- 1 | 9 | */ 10 | 11 | /** 12 | * @group IntegerNet_Anonymizer 13 | */ 14 | class IntegerNet_Anonymizer_Test_Model_Bridge_Entity_Order 15 | extends IntegerNet_Anonymizer_Test_Model_Bridge_Entity_Abstract 16 | { 17 | /** 18 | * @param $orderId 19 | * @test 20 | * @dataProvider dataProvider 21 | * @dataProviderFile testOrderBridge.yaml 22 | * @loadExpectation bridge.yaml 23 | * @loadFixture customers.yaml 24 | */ 25 | public function testGetValues($orderId) 26 | { 27 | /** @var IntegerNet_Anonymizer_Test_Model_Bridge_Entity_Order $bridge */ 28 | $bridge = Mage::getModel('integernet_anonymizer/bridge_entity_order'); 29 | /** @var Mage_Sales_Model_Order $order */ 30 | $order = $this->_loadEntityByCollection('entity_id', $orderId, $bridge); 31 | $expected = $this->expected('order_%d', $orderId); 32 | 33 | $this->_testGetValues($bridge, $order, $expected); 34 | } 35 | 36 | /** 37 | * @param $orderId 38 | * @param $customerId 39 | * @test 40 | * @dataProvider dataProvider 41 | * @dataProviderFile testOrderBridge.yaml 42 | * @loadFixture customers.yaml 43 | */ 44 | public function testUpdateValues($orderId, $customerId) 45 | { 46 | static $changedEmail = 'changed@example.com', 47 | $changedMiddlename = 'trouble'; 48 | 49 | /** @var IntegerNet_Anonymizer_Model_Bridge_Entity_Order $bridge */ 50 | $bridge = Mage::getModel('integernet_anonymizer/bridge_entity_order'); 51 | 52 | $bridge->setRawData(array( 53 | 'entity_id' => $orderId, 54 | 'increment_id' => '1000000001', 55 | 'customer_id' => $customerId, 56 | 'customer_email' => $changedEmail, 57 | 'customer_middlename' => $changedMiddlename 58 | )); 59 | 60 | $this->_updateValues($bridge); 61 | 62 | $order = Mage::getModel('sales/order')->load($orderId); 63 | $this->assertEquals($changedMiddlename, $order->getCustomerMiddlename()); 64 | $this->assertEquals($changedEmail, $order->getCustomerEmail()); 65 | $this->assertNotEmpty($order->getIncrementId(), 'Increment ID should not be empty'); 66 | } 67 | 68 | } -------------------------------------------------------------------------------- /src/app/code/community/IntegerNet/Anonymizer/Test/Model/Bridge/Entity/OrderAddress.php: -------------------------------------------------------------------------------- 1 | 9 | */ 10 | 11 | /** 12 | * @group IntegerNet_Anonymizer 13 | */ 14 | class IntegerNet_Anonymizer_Test_Model_Bridge_Entity_OrderAddress 15 | extends IntegerNet_Anonymizer_Test_Model_Bridge_Entity_Abstract 16 | { 17 | /** 18 | * @param $orderAddressId 19 | * @test 20 | * @dataProvider dataProvider 21 | * @dataProviderFile testOrderAddressBridge.yaml 22 | * @loadExpectation bridge.yaml 23 | * @loadFixture customers.yaml 24 | */ 25 | public function testGetValues($orderAddressId) 26 | { 27 | /** @var IntegerNet_Anonymizer_Model_Bridge_Entity_Address_QuoteAddress $bridge */ 28 | $bridge = Mage::getModel('integernet_anonymizer/bridge_entity_address_orderAddress'); 29 | /** @var Mage_Sales_Model_Quote_Address $orderAddress */ 30 | $orderAddress = $this->_loadEntityByCollection('entity_id', $orderAddressId, $bridge); 31 | $expected = $this->expected('order_address_%d', $orderAddressId); 32 | 33 | $this->_testGetValues($bridge, $orderAddress, $expected); 34 | } 35 | 36 | /** 37 | * @param $orderAddressId 38 | * @test 39 | * @dataProvider dataProvider 40 | * @dataProviderFile testOrderAddressBridge.yaml 41 | * @loadFixture customers.yaml 42 | */ 43 | public function testUpdateValues($orderAddressId) 44 | { 45 | static $changedMiddlename = 'trouble', 46 | $changedStreet = "New Street\nSecond Line"; 47 | 48 | /** @var IntegerNet_Anonymizer_Model_Bridge_Entity_Address_OrderAddress $bridge */ 49 | $bridge = Mage::getModel('integernet_anonymizer/bridge_entity_address_orderAddress'); 50 | 51 | $dataProvider = Mage::getModel('sales/order_address'); 52 | $bridge->setRawData($dataProvider->load($orderAddressId)->getData()); 53 | $bridge->getValues()['middlename']->setValue($changedMiddlename); 54 | $bridge->getValues()['street']->setValue($changedStreet); 55 | 56 | $this->_updateValues($bridge); 57 | 58 | $orderAddress = Mage::getModel('sales/order_address')->load($orderAddressId); 59 | $this->assertEquals($changedMiddlename, $orderAddress->getMiddlename()); 60 | $this->assertEquals($changedStreet, $orderAddress->getStreetFull()); 61 | } 62 | } -------------------------------------------------------------------------------- /src/app/code/community/IntegerNet/Anonymizer/Test/Model/Bridge/Entity/QuoteAddress.php: -------------------------------------------------------------------------------- 1 | 9 | */ 10 | 11 | /** 12 | * @group IntegerNet_Anonymizer 13 | */ 14 | class IntegerNet_Anonymizer_Test_Model_Bridge_Entity_QuoteAddress 15 | extends IntegerNet_Anonymizer_Test_Model_Bridge_Entity_Abstract 16 | { 17 | /** 18 | * @param $quoteAddressId 19 | * @test 20 | * @dataProvider dataProvider 21 | * @dataProviderFile testQuoteAddressBridge.yaml 22 | * @loadExpectation bridge.yaml 23 | * @loadFixture customers.yaml 24 | */ 25 | public function testGetValues($quoteAddressId) 26 | { 27 | /** @var IntegerNet_Anonymizer_Model_Bridge_Entity_Address_QuoteAddress $bridge */ 28 | $bridge = Mage::getModel('integernet_anonymizer/bridge_entity_address_quoteAddress'); 29 | /** @var Mage_Sales_Model_Quote_Address $quoteAddress */ 30 | $quoteAddress = $this->_loadEntityByCollection('address_id', $quoteAddressId, $bridge); 31 | $expected = $this->expected('quote_address_%d', $quoteAddressId); 32 | 33 | $this->_testGetValues($bridge, $quoteAddress, $expected); 34 | } 35 | 36 | /** 37 | * @param $quoteAddressId 38 | * @test 39 | * @dataProvider dataProvider 40 | * @dataProviderFile testQuoteAddressBridge.yaml 41 | * @loadFixture customers.yaml 42 | */ 43 | public function testUpdateValues($quoteAddressId) 44 | { 45 | static $changedMiddlename = 'trouble', 46 | $changedStreet = "New Street\nSecond Line"; 47 | 48 | /** @var IntegerNet_Anonymizer_Model_Bridge_Entity_Address_QuoteAddress $bridge */ 49 | $bridge = Mage::getModel('integernet_anonymizer/bridge_entity_address_quoteAddress'); 50 | 51 | $dataProvider = Mage::getModel('sales/quote_address'); 52 | $bridge->setRawData($dataProvider->load($quoteAddressId)->getData()); 53 | $bridge->getValues()['middlename']->setValue($changedMiddlename); 54 | $bridge->getValues()['street']->setValue($changedStreet); 55 | 56 | $this->_updateValues($bridge); 57 | 58 | $quoteAddresss = Mage::getModel('sales/quote_address')->load($quoteAddressId); 59 | $this->assertEquals($changedMiddlename, $quoteAddresss->getMiddlename()); 60 | $this->assertEquals($changedStreet, $quoteAddresss->getStreetFull()); 61 | } 62 | 63 | } -------------------------------------------------------------------------------- /src/app/code/community/IntegerNet/Anonymizer/Test/Model/Bridge/Entity/expectations/bridge.yaml: -------------------------------------------------------------------------------- 1 | customer_1: 2 | identifier: '1' 3 | values: 4 | - formatter: safeEmail 5 | value: test@test.de 6 | unique: true 7 | - formatter: firstName 8 | value: Testname 9 | - formatter: lastName 10 | value: Testname 11 | - formatter: firstName 12 | value: J 13 | - formatter: title 14 | value: Kaiser 15 | - formatter: suffix 16 | value: "der Große" 17 | - formatter: randomNumber 18 | value: DE 123456789 19 | customer_address_1: 20 | identifier: '1' 21 | values: 22 | - formatter: firstName 23 | value: Testname 24 | - formatter: lastName 25 | value: Testname 26 | - formatter: firstName 27 | value: J 28 | - formatter: title 29 | value: Kaiser 30 | - formatter: suffix 31 | value: III. 32 | - formatter: company 33 | value: Testfirma 34 | - formatter: city 35 | value: Testingen 36 | - formatter: streetAddress 37 | value: [ Teststraße 42 ] 38 | - formatter: phoneNumber 39 | value: 555-123-1 40 | - formatter: phoneNumber 41 | value: 555-123-2 42 | - formatter: randomNumber 43 | value: DE 123456789 44 | quote_address_1: 45 | identifier: '2' 46 | values: 47 | - formatter: firstName 48 | value: Somebody 49 | - formatter: lastName 50 | value: Else 51 | - formatter: firstName 52 | value: 53 | - formatter: title 54 | value: 55 | - formatter: suffix 56 | value: 57 | - formatter: company 58 | value: ACME GmbH 59 | - formatter: city 60 | value: Buxtehude 61 | - formatter: streetAddress 62 | value: [ Am Arm 1 ] 63 | - formatter: phoneNumber 64 | value: 555-12345 65 | - formatter: phoneNumber 66 | value: 555-12345 67 | - formatter: randomNumber 68 | value: DE 987654321 69 | order_address_1: 70 | identifier: '2' 71 | values: 72 | - formatter: firstName 73 | value: Testname 74 | - formatter: lastName 75 | value: Testname 76 | - formatter: firstName 77 | value: K 78 | - formatter: title 79 | value: Dr. phil. 80 | - formatter: suffix 81 | value: 82 | - formatter: company 83 | value: ACME GmbH 84 | - formatter: city 85 | value: Buxtehude 86 | - formatter: streetAddress 87 | value: [ Am Arm 1 ] 88 | - formatter: phoneNumber 89 | value: 555-12345 90 | - formatter: phoneNumber 91 | value: 555-12345 92 | - formatter: randomNumber 93 | value: DE 987654321 94 | order_1: 95 | identifier: '2' 96 | values: 97 | - formatter: safeEmail 98 | value: test2@test.de 99 | - formatter: firstName 100 | value: Testname 101 | - formatter: lastName 102 | value: Testname 103 | - formatter: firstName 104 | value: J 105 | - formatter: title 106 | value: Kaiser 107 | - formatter: suffix 108 | value: III 109 | - formatter: randomNumber 110 | value: DE 987654321 111 | newsletter_subscriber_1: 112 | identifier: 'guest1@example.com' 113 | values: 114 | - formatter: safeEmail 115 | value: guest1@example.com 116 | newsletter_subscriber_2: 117 | identifier: 'guest2@example.com' 118 | values: 119 | - formatter: safeEmail 120 | value: guest2@example.com 121 | newsletter_subscriber_3: 122 | identifier: '1' 123 | values: 124 | - formatter: safeEmail 125 | value: test@test.de 126 | giftregistry_1: 127 | identifier: '_gift_registry_1' 128 | values: 129 | - formatter: sentence 130 | value: My Gift Registry 131 | - formatter: paragraph 132 | value: My Private Message 133 | - formatter: address 134 | value: Something something somewhere 135 | - formatter: 'null' 136 | value: 137 | foo: 'bar' 138 | giftregistry_person_1: 139 | identifier: 'b.schenkter@example.com' 140 | values: 141 | - formatter: safeEmail 142 | value: b.schenkter@example.com 143 | - formatter: firstName 144 | value: Bernd 145 | - formatter: lastName 146 | value: Schenkter 147 | - formatter: 'null' 148 | value: 'a:1:{s:3:"foo";s:3:"bar";}' 149 | -------------------------------------------------------------------------------- /src/app/code/community/IntegerNet/Anonymizer/Test/Model/Bridge/Entity/providers/testCustomerAddressBridge.yaml: -------------------------------------------------------------------------------- 1 | customer_address_1: 2 | id: 1 -------------------------------------------------------------------------------- /src/app/code/community/IntegerNet/Anonymizer/Test/Model/Bridge/Entity/providers/testCustomerBridge.yaml: -------------------------------------------------------------------------------- 1 | customer_1: 2 | id: 1 -------------------------------------------------------------------------------- /src/app/code/community/IntegerNet/Anonymizer/Test/Model/Bridge/Entity/providers/testGiftregistryBridge.yaml: -------------------------------------------------------------------------------- 1 | giftregistry_1: 2 | id: 1 -------------------------------------------------------------------------------- /src/app/code/community/IntegerNet/Anonymizer/Test/Model/Bridge/Entity/providers/testGiftregistryPersonBridge.yaml: -------------------------------------------------------------------------------- 1 | giftregistry_person_1: 2 | id: 1 -------------------------------------------------------------------------------- /src/app/code/community/IntegerNet/Anonymizer/Test/Model/Bridge/Entity/providers/testNewsletterSubscriberBridge.yaml: -------------------------------------------------------------------------------- 1 | newsletter_subscriber_1: 2 | id: 1 3 | newsletter_subscriber_2: 4 | id: 2 5 | newsletter_subscriber_3: 6 | id: 3 7 | -------------------------------------------------------------------------------- /src/app/code/community/IntegerNet/Anonymizer/Test/Model/Bridge/Entity/providers/testOrderAddressBridge.yaml: -------------------------------------------------------------------------------- 1 | order_address_1: 2 | id: 1 -------------------------------------------------------------------------------- /src/app/code/community/IntegerNet/Anonymizer/Test/Model/Bridge/Entity/providers/testOrderBridge.yaml: -------------------------------------------------------------------------------- 1 | order_1: 2 | id: 1 3 | customer_id: 1 -------------------------------------------------------------------------------- /src/app/code/community/IntegerNet/Anonymizer/Test/Model/Bridge/Entity/providers/testQuoteAddressBridge.yaml: -------------------------------------------------------------------------------- 1 | quote_address_1: 2 | id: 1 -------------------------------------------------------------------------------- /src/app/code/community/IntegerNet/Anonymizer/Test/fixtures/customers.yaml: -------------------------------------------------------------------------------- 1 | eav: 2 | customer: 3 | - entity_id: 1 4 | website_id: 1 5 | increment_id: 1000000001 6 | email: test@test.de 7 | firstname: Testname 8 | lastname: Testname 9 | middlename: J 10 | prefix: Kaiser 11 | suffix: "der Große" 12 | taxvat: DE 123456789 13 | group_id: 1 14 | store_id: 1 15 | is_active: 1 16 | attribute_set_id: 0 17 | default_billing: 1 18 | default_shipping: 2 19 | - entity_id: 2 20 | website_id: 1 21 | increment_id: 1000000002 22 | email: test2@test.de 23 | firstname: Testname 24 | lastname: Testname 25 | middlename: K 26 | prefix: Dr. phil. 27 | suffix: 28 | group_id: 1 29 | store_id: 1 30 | is_active: 1 31 | attribute_set_id: 0 32 | default_billing: 4 33 | default_shipping: 4 34 | - entity_id: 3 35 | website_id: 1 36 | increment_id: 1000000003 37 | email: test3@test.de 38 | firstname: Test 39 | lastname: Test 40 | group_id: 1 41 | store_id: 1 42 | is_active: 1 43 | attribute_set_id: 0 44 | customer_address: 45 | - entity_id: 1 46 | parent_id: 1 47 | attribute_set_id: 0 48 | is_default_billing: 1 49 | firstname: Testname 50 | lastname: Testname 51 | middlename: J 52 | prefix: Kaiser 53 | suffix: III. 54 | company: Testfirma 55 | postcode: 12345 56 | city: Testingen 57 | street: Teststraße 42 58 | telephone: 555-123-1 59 | fax: 555-123-2 60 | vat_id: DE 123456789 61 | country_id: DE 62 | region_id: 88 63 | - entity_id: 2 64 | parent_id: 1 65 | attribute_set_id: 0 66 | is_default_shipping: 1 67 | firstname: Testname 68 | lastname: Testname 69 | middlename: J 70 | prefix: Kaiser 71 | suffix: III. 72 | company: Testfirma 73 | postcode: 12345 74 | city: Anderswo 75 | street: Testweg 3 76 | telephone: (0)555-123-11 77 | fax: (0)555-123-12 78 | vat_id: DE 123456789 79 | country_id: DE 80 | region_id: 88 81 | - entity_id: 3 82 | parent_id: 1 83 | attribute_set_id: 0 84 | - entity_id: 4 85 | parent_id: 2 86 | attribute_set_id: 0 87 | is_default_billing: 1 88 | is_default_shipping: 1 89 | firstname: Testname 90 | lastname: Testname 91 | middlename: K 92 | prefix: Dr. phil. 93 | suffix: 94 | company: ACME GmbH 95 | postcode: 67890 96 | city: Buxtehude 97 | street: Am Arm 1 98 | telephone: 555-12345 99 | fax: 555-12345 100 | vat_id: DE 987654321 101 | country_id: DE 102 | region_id: 88 103 | 104 | tables: 105 | sales/quote: 106 | - entity_id: 1 107 | customer_id: 2 108 | - entity_id: 2 109 | customer_id: null 110 | - entity_id: 3 111 | customer_id: null 112 | sales/order: 113 | - entity_id: 1 114 | increment_id: 1000000001 115 | quote_id: 1 116 | billing_address_id: 1 117 | customer_id: 2 118 | customer_email: test2@test.de 119 | customer_firstname: Testname 120 | customer_lastname: Testname 121 | customer_middlename: J 122 | customer_prefix: Kaiser 123 | customer_suffix: III 124 | customer_taxvat: DE 987654321 125 | - entity_id: 2 126 | increment_id: 1000000002 127 | quote_id: 2 128 | billing_address_id: 2 129 | customer_email: guest@guest.de 130 | customer_firstname: Gast 131 | customer_lastname: Gast 132 | sales/order_grid: 133 | - entity_id: 1 134 | increment_id: 1000000001 135 | customer_id: 2 136 | shipping_name: Testname Testname 137 | billing_name: Testname Testname 138 | #TODO invoice, creditmemo 139 | sales/quote_address: 140 | - address_id: 1 141 | address_type: billing 142 | quote_id: 1 143 | customer_id: 2 144 | customer_address_id: 4 145 | firstname: Somebody 146 | lastname: Else 147 | middlename: 148 | prefix: 149 | suffix: 150 | company: ACME GmbH 151 | postcode: 67890 152 | city: Buxtehude 153 | street: Am Arm 1 154 | telephone: 555-12345 155 | fax: 555-12345 156 | vat_id: DE 987654321 157 | country_id: DE 158 | region_id: 88 159 | - address_id: 2 160 | address_type: billing 161 | quote_id: 2 162 | customer_id: null 163 | customer_address_id: null 164 | firstname: Gast 165 | lastname: Gast 166 | middlename: 167 | prefix: 168 | suffix: 169 | company: Gastro 170 | postcode: 111222 171 | city: Gastdorf 172 | street: Gaststraße 1 173 | telephone: 174 | fax: 175 | vat_id: 176 | country_id: DE 177 | region_id: 88 178 | - address_id: 3 179 | address_type: billing 180 | quote_id: 3 181 | customer_id: null 182 | customer_address_id: null 183 | firstname: Anderer 184 | lastname: Gast 185 | middlename: 186 | prefix: 187 | suffix: 188 | company: 189 | postcode: 333444 190 | city: Gastburg 191 | street: Gastweg 2 192 | telephone: 193 | fax: 194 | vat_id: 195 | country_id: DE 196 | region_id: 89 197 | sales/order_address: 198 | - entity_id: 1 199 | address_type: billing 200 | parent_id: 1 201 | customer_id: 2 202 | customer_address_id: 4 203 | firstname: Testname 204 | lastname: Testname 205 | middlename: K 206 | prefix: Dr. phil. 207 | suffix: 208 | company: ACME GmbH 209 | postcode: 67890 210 | city: Buxtehude 211 | street: Am Arm 1 212 | telephone: 555-12345 213 | fax: 555-12345 214 | vat_id: DE 987654321 215 | country_id: DE 216 | region_id: 88 217 | - entity_id: 2 218 | address_type: billing 219 | parent_id: 2 220 | customer_id: null 221 | customer_address_id: null 222 | firstname: Gast 223 | lastname: Gast 224 | middlename: 225 | prefix: 226 | suffix: 227 | company: Gastro 228 | postcode: 111222 229 | city: Gastdorf 230 | street: Gaststraße 1 231 | telephone: 232 | fax: 233 | vat_id: 234 | country_id: DE 235 | region_id: 88 236 | sales/quote_item: [] 237 | sales/order_item: [] 238 | newsletter/subscriber: 239 | - subscriber_id: 1 240 | customer_id: 0 241 | subscriber_email: guest1@example.com 242 | - subscriber_id: 2 243 | customer_id: 0 244 | subscriber_email: guest2@example.com 245 | - subscriber_id: 3 246 | customer_id: 1 247 | subscriber_email: test@test.de 248 | -------------------------------------------------------------------------------- /src/app/code/community/IntegerNet/Anonymizer/Test/fixtures/enterprise.yaml: -------------------------------------------------------------------------------- 1 | tables: 2 | enterprise_giftregistry/entity: 3 | - entity_id: 1 4 | type_id: 1 5 | customer_id: 2 6 | title: My Gift Registry 7 | message: My Private Message 8 | shipping_address: Something something somewhere 9 | custom_values: 'a:1:{s:3:"foo";s:3:"bar";}' 10 | enterprise_giftregistry/person: 11 | - person_id: 1 12 | entity_id: 1 13 | firstname: Bernd 14 | lastname: Schenkter 15 | email: b.schenkter@example.com 16 | custom_values: 'a:1:{s:3:"foo";s:3:"bar";}' -------------------------------------------------------------------------------- /src/app/code/community/IntegerNet/Anonymizer/etc/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 1.0.0 6 | 7 | 8 | 9 | 10 | 11 | IntegerNet_Anonymizer_Model 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | integernet_anonymizer/bridge_entity_customer 22 | 100 23 | 24 | 25 | integernet_anonymizer/bridge_entity_address_customerAddress 26 | 200 27 | 28 | 29 | integernet_anonymizer/bridge_entity_address_quoteAddress 30 | 300 31 | 32 | 33 | integernet_anonymizer/bridge_entity_address_orderAddress 34 | 400 35 | 36 | 37 | integernet_anonymizer/bridge_entity_newsletterSubscriber 38 | 500 39 | 40 | 41 | integernet_anonymizer/bridge_entity_enterprise_giftregistry 42 | 600 43 | 44 | 45 | integernet_anonymizer/bridge_entity_enterprise_giftregistryPerson 46 | 700 47 | 48 | 49 | 50 | integernet_anonymizer/bridge_entity_order 51 | 800 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /src/app/etc/modules/IntegerNet_Anonymizer.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | true 6 | community 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/lib/IntegerNet/Anonymizer/AnonymizableValue.php: -------------------------------------------------------------------------------- 1 | 9 | */ 10 | 11 | namespace IntegerNet\Anonymizer; 12 | 13 | 14 | class AnonymizableValue 15 | { 16 | const __CLASS = __CLASS__; 17 | /** 18 | * @var string 19 | */ 20 | private $formatter; 21 | /** 22 | * @var string 23 | */ 24 | private $value; 25 | /** 26 | * @var bool 27 | */ 28 | private $unique; 29 | 30 | public function __construct($formatter, $value, $unique = false) 31 | { 32 | $this->formatter = $formatter; 33 | $this->value = $value; 34 | $this->unique = (bool) $unique; 35 | } 36 | /** 37 | * @return string 38 | */ 39 | public function getFakerFormatter() 40 | { 41 | return $this->formatter; 42 | } 43 | 44 | /** 45 | * If the value is optional, returns probability of presence. 46 | * 1.0 = not optional 47 | * 0.0 = always empty 48 | * 49 | * @return float 50 | */ 51 | public function getOptionalWeight() 52 | { 53 | //TODO use this 54 | //TODO or add a FakerFormatterOptions property for more customizability 55 | return 1.0; 56 | } 57 | 58 | public function isUnique() 59 | { 60 | return $this->unique; 61 | } 62 | 63 | /** 64 | * @return mixed 65 | */ 66 | public function getValue() 67 | { 68 | return $this->value; 69 | } 70 | 71 | /** 72 | * @param mixed $value 73 | * @return void 74 | */ 75 | public function setValue($value) 76 | { 77 | $this->value = $value; 78 | } 79 | } -------------------------------------------------------------------------------- /src/lib/IntegerNet/Anonymizer/Anonymizer.php: -------------------------------------------------------------------------------- 1 | provider = $provider; 32 | $this->provider->initialize($locale); 33 | } 34 | 35 | /** 36 | * @param AnonymizableEntity[] $inputData 37 | */ 38 | public function anonymize(array $inputData) 39 | { 40 | foreach ($inputData as $entity) { 41 | foreach ($entity->getValues() as $value) { 42 | $value->setValue($this->provider->getFakerData( 43 | $value->getFakerFormatter(), $this->_getFieldIdentifier($entity, $value), $value->isUnique())); 44 | } 45 | } 46 | } 47 | 48 | /** 49 | * Returns identifier for a field, based on entity and current value. This is used to map real data to fake 50 | * data in the same way for each unique entity identifier (i.e. customer id) 51 | * 52 | * @param AnonymizableEntity $entity 53 | * @param AnonymizableValue $value 54 | * @return string 55 | */ 56 | private function _getFieldIdentifier(AnonymizableEntity $entity, AnonymizableValue $value) 57 | { 58 | return sprintf('%s|%s', $entity->getIdentifier(), join('', (array)$value->getValue())); 59 | } 60 | 61 | public function resetUniqueGenerator() 62 | { 63 | $this->provider->resetUniqueGenerator(); 64 | } 65 | } -------------------------------------------------------------------------------- /src/lib/IntegerNet/Anonymizer/Implementor/AnonymizableEntity.php: -------------------------------------------------------------------------------- 1 | 9 | */ 10 | 11 | namespace IntegerNet\Anonymizer\Implementor; 12 | 13 | 14 | use IntegerNet\Anonymizer\AnonymizableValue; 15 | 16 | interface AnonymizableEntity 17 | { 18 | /** 19 | * Returns name of entity as translatable string 20 | * 21 | * @return string 22 | */ 23 | function getEntityName(); 24 | /** 25 | * Returns identifier, for example the customer email address. Entities with the same identifier will get the same 26 | * anonymized values. 27 | * 28 | * Important: The return value must not be affected by anonymization! 29 | * 30 | * @return string 31 | */ 32 | function getIdentifier(); 33 | 34 | /** 35 | * Returns anonymizable value objects as array with attribute codes as keys 36 | * 37 | * @return AnonymizableValue[] 38 | */ 39 | function getValues(); 40 | 41 | /** 42 | * Sets raw data from database 43 | * 44 | * @param string[] $data 45 | * @return void 46 | */ 47 | function setRawData($data); 48 | 49 | /** 50 | * Update values in database 51 | * 52 | * @return void 53 | */ 54 | function updateValues(); 55 | 56 | /** 57 | * Reset to empty instance 58 | * 59 | * @return void 60 | */ 61 | function clearInstance(); 62 | 63 | } -------------------------------------------------------------------------------- /src/lib/IntegerNet/Anonymizer/Implementor/CollectionIterator.php: -------------------------------------------------------------------------------- 1 | 9 | */ 10 | 11 | namespace IntegerNet\Anonymizer\Implementor; 12 | 13 | 14 | interface CollectionIterator 15 | { 16 | 17 | /** 18 | * @param callable $callable 19 | * @return mixed 20 | */ 21 | function walk(/*callable*/ $callable); 22 | 23 | /** 24 | * Returns raw data from database 25 | * 26 | * @return mixed 27 | */ 28 | function getRawData(); 29 | 30 | /** 31 | * Returns number of iteration 32 | * 33 | * @return int 34 | */ 35 | function getIteration(); 36 | 37 | /** 38 | * Returns total size of collection 39 | * 40 | * @return mixed 41 | */ 42 | function getSize(); 43 | } -------------------------------------------------------------------------------- /src/lib/IntegerNet/Anonymizer/Provider.php: -------------------------------------------------------------------------------- 1 | 9 | */ 10 | 11 | namespace IntegerNet\Anonymizer; 12 | 13 | 14 | use Faker\Factory; 15 | 16 | class Provider 17 | { 18 | const __CLASS = __CLASS__; 19 | 20 | /** 21 | * @var \Faker\Generator 22 | */ 23 | private $faker; 24 | 25 | private $salt; 26 | 27 | /** 28 | * Initializes Faker, generates new salt for RNG seeds 29 | * 30 | * @param string|null $locale 31 | * @return void 32 | */ 33 | public function initialize($locale = null) 34 | { 35 | if ($locale === null) { 36 | $locale = Factory::DEFAULT_LOCALE; 37 | } 38 | $this->faker = Factory::create($locale); 39 | $this->salt = sha1(uniqid('', true)); 40 | } 41 | 42 | /** 43 | * Resets the UniqueGenerator of Faker, this should be used after anonymizing a database table with 44 | * unique values to free memory and allow the same values in other tables 45 | * 46 | * @return void 47 | */ 48 | public function resetUniqueGenerator() 49 | { 50 | $this->faker->unique(true); 51 | } 52 | 53 | /** 54 | * Return fake data from given Faker provider, always return the same data for each ($formatter, $identifier) 55 | * combination after initialized. 56 | * 57 | * @param $formatter 58 | * @param $identifier 59 | * @return mixed 60 | */ 61 | public function getFakerData($formatter, $identifier, $unique = false) 62 | { 63 | $faker = $this->faker; 64 | if ($formatter === 'null') { 65 | return $faker->optional(0)->randomDigit; 66 | } 67 | if ($unique) { 68 | $faker = $faker->unique(); 69 | } 70 | $this->seedRng($formatter.$identifier); 71 | $result = $faker->format($formatter); 72 | $this->resetRng(); 73 | return $result; 74 | } 75 | 76 | /** 77 | * @param $identifier 78 | */ 79 | private function seedRng($identifier) 80 | { 81 | $this->faker->seed(hexdec(hash("crc32b", $identifier . $this->salt))); 82 | } 83 | 84 | private function resetRng() 85 | { 86 | //$this->faker->seed(); 87 | //TODO use above as soon as pr 543 has been merged 88 | mt_srand(); 89 | } 90 | } -------------------------------------------------------------------------------- /src/lib/IntegerNet/Anonymizer/Updater.php: -------------------------------------------------------------------------------- 1 | 9 | */ 10 | namespace IntegerNet\Anonymizer; 11 | 12 | use IntegerNet\Anonymizer\Implementor\AnonymizableEntity; 13 | use IntegerNet\Anonymizer\Implementor\CollectionIterator; 14 | 15 | class Updater 16 | { 17 | const __CLASS = __CLASS__; 18 | 19 | /** 20 | * @var Anonymizer 21 | */ 22 | private $anonymizer; 23 | /** 24 | * @var null|resource 25 | */ 26 | private $outputStream = null; 27 | /** 28 | * @var bool 29 | */ 30 | private $showProgress = true; 31 | /** 32 | * @var int 33 | */ 34 | private $progressSteps = 1; 35 | 36 | /** 37 | * @var AnonymizableEntity 38 | */ 39 | private $entityModel; 40 | 41 | public function __construct(Anonymizer $anonymizer) 42 | { 43 | $this->anonymizer = $anonymizer; 44 | } 45 | /** 46 | * @param null|resource $stream writable stream resource or null if no output required 47 | */ 48 | public function setOutputStream($stream) 49 | { 50 | $this->outputStream = $stream; 51 | } 52 | 53 | /** 54 | * @param boolean $showProgress 55 | */ 56 | public function setShowProgress($showProgress) 57 | { 58 | $this->showProgress = $showProgress; 59 | } 60 | 61 | /** 62 | * @param int $progressSteps 63 | */ 64 | public function setProgressSteps($progressSteps) 65 | { 66 | $this->progressSteps = $progressSteps; 67 | } 68 | 69 | public function update(CollectionIterator $iterator, AnonymizableEntity $entityModel) 70 | { 71 | $this->entityModel = $entityModel; 72 | $this->outputStart(); 73 | $iterator->walk(array($this, 'updateCurrentRow')); 74 | $this->anonymizer->resetUniqueGenerator(); 75 | $this->outputDone(); 76 | $this->entityModel = null; 77 | } 78 | 79 | /** 80 | * @param CollectionIterator $iterator 81 | */ 82 | public function updateCurrentRow(CollectionIterator $iterator) 83 | { 84 | $this->entityModel->setRawData($iterator->getRawData()); 85 | $this->anonymizer->anonymize(array($this->entityModel)); 86 | $this->entityModel->updateValues(); 87 | $this->entityModel->clearInstance(); 88 | $this->outputIteratorStatus($iterator); 89 | } 90 | 91 | private function outputStart() 92 | { 93 | if (is_resource($this->outputStream) && get_resource_type($this->outputStream) === 'stream') { 94 | fwrite($this->outputStream, sprintf("Updater started at %s.\n", date('H:i:s'))); 95 | } 96 | } 97 | 98 | /** 99 | * @param CollectionIterator $iterator 100 | */ 101 | private function outputIteratorStatus(CollectionIterator $iterator) 102 | { 103 | if ($this->showProgress && (($iterator->getIteration() + 1) % $this->progressSteps === 0) 104 | && is_resource($this->outputStream) && get_resource_type($this->outputStream) === 'stream' 105 | ) { 106 | fwrite($this->outputStream, sprintf("\rUpdating %s: %s/%s - Memory usage %s Bytes", 107 | $this->entityModel->getEntityName(), 108 | str_pad($iterator->getIteration() + 1, strlen($iterator->getSize()), ' '), $iterator->getSize(), 109 | number_format(memory_get_usage()))); 110 | } 111 | } 112 | 113 | private function outputDone() 114 | { 115 | if (is_resource($this->outputStream) && get_resource_type($this->outputStream) === 'stream') { 116 | fwrite($this->outputStream, sprintf("\nUpdater finished at %s.\n\n", date('H:i:s'))); 117 | } 118 | } 119 | } -------------------------------------------------------------------------------- /src/lib/n98-magerun/modules/IntegerNet_Anonymizer/n98-magerun.yaml: -------------------------------------------------------------------------------- 1 | autoloaders: 2 | IntegerNet\Anonymizer\AnonymizeCommand: %module%/src 3 | 4 | commands: 5 | customCommands: 6 | - IntegerNet\Anonymizer\AnonymizeCommand -------------------------------------------------------------------------------- /src/lib/n98-magerun/modules/IntegerNet_Anonymizer/src/IntegerNet/Anonymizer/AnonymizeCommand.php: -------------------------------------------------------------------------------- 1 | 9 | */ 10 | 11 | namespace IntegerNet\Anonymizer; 12 | 13 | use N98\Magento\Command\AbstractMagentoCommand; 14 | use Symfony\Component\Console\Input\InputInterface; 15 | use Symfony\Component\Console\Output\OutputInterface; 16 | use Symfony\Component\Console\Output\StreamOutput; 17 | 18 | class AnonymizeCommand extends AbstractMagentoCommand 19 | { 20 | protected function configure() 21 | { 22 | $this 23 | ->setName('db:anonymize') 24 | ->setDescription('Anonymize customer data'); 25 | } 26 | 27 | /** 28 | * @param \Symfony\Component\Console\Input\InputInterface $input 29 | * @param \Symfony\Component\Console\Output\OutputInterface $output 30 | * @return int|void 31 | */ 32 | protected function execute(InputInterface $input, OutputInterface $output) 33 | { 34 | $this->detectMagento($output, true); 35 | if ($this->initMagento()) { 36 | $this->registerPsr0Autoloader(); 37 | /** @var \IntegerNet_Anonymizer_Model_Anonymizer $anonymizer */ 38 | $anonymizer = \Mage::getModel('integernet_anonymizer/anonymizer'); 39 | if ($output instanceof StreamOutput) { 40 | $anonymizer->setOutputStream($output->getStream()); 41 | } else { 42 | //TODO allow OutputInterface in Anonymizer? 43 | //TODO pass ansi/no-ansi configuration to Anonymizer and use colors 44 | ob_start(); 45 | $anonymizer->setOutputStream(STDOUT); 46 | $output->write(ob_get_clean()); 47 | } 48 | $anonymizer->anonymizeAll(); 49 | } 50 | } 51 | private function registerPsr0Autoloader() 52 | { 53 | \Mage::getConfig()->init()->loadEventObservers('global'); 54 | \Mage::app()->addEventArea('global'); 55 | \Mage::dispatchEvent('add_spl_autoloader'); 56 | } 57 | } -------------------------------------------------------------------------------- /src/shell/anonymize.php: -------------------------------------------------------------------------------- 1 | 9 | */ 10 | 11 | require_once 'abstract.php'; 12 | require_once 'autoloader_initializer.php'; 13 | 14 | class IntegerNet_Anonymizer_Shell extends AutoloaderInitializer 15 | { 16 | /** 17 | * Run script 18 | */ 19 | public function run() 20 | { 21 | ini_set('memory_limit', '1024M'); 22 | /** @var IntegerNet_Anonymizer_Model_Anonymizer $anonymizer */ 23 | $anonymizer = Mage::getModel('integernet_anonymizer/anonymizer'); 24 | $anonymizer->setOutputStream(STDOUT); 25 | $anonymizer->setShowProgress((bool) $this->getArg('progress')); 26 | $anonymizer->setProgressSteps((int) $this->getArg('progress')); 27 | $anonymizer->anonymizeAll(); 28 | } 29 | 30 | public function usageHelp() 31 | { 32 | return <<run(); -------------------------------------------------------------------------------- /test/IntegerNet/Anonymizer/AnonymizerTest.php: -------------------------------------------------------------------------------- 1 | getMock(Provider::__CLASS); 23 | $provider->expects($this->once())->method('initialize'); 24 | $provider->expects($this->exactly(count($expectedValues)))->method('getFakerData') 25 | ->willReturnCallback(function($formatter, $identifier) { 26 | return sprintf('%s_%s', $formatter, explode('|', $identifier, 2)[0]); 27 | }); 28 | 29 | $anonymizer = new Anonymizer($provider, 'de_DE'); 30 | $anonymizer->anonymize($inputData); 31 | 32 | reset($expectedValues); 33 | /** @var AnonymizableMock $anonymizedEntity */ 34 | foreach ($inputData as $anonymizedEntity) { 35 | foreach ($anonymizedEntity->getValues() as $anonymizedValue) { 36 | $this->assertEquals(current($expectedValues), $anonymizedValue->getValue()); 37 | next($expectedValues); 38 | } 39 | } 40 | } 41 | 42 | /** 43 | * Provider::getFakerData() should be called with 44 | * - identifier as combination of entity identifier and current value 45 | * - unique key parameter for values marked as unique 46 | * 47 | * @test 48 | */ 49 | public function testGetFakerDataParameters() 50 | { 51 | $provider = $this->getMock(Provider::__CLASS); 52 | $provider->expects($this->once())->method('initialize'); 53 | $provider->expects($this->exactly(2))->method('getFakerData') 54 | ->withConsecutive( 55 | array('email', 'email@example.com|email@example.com', true), 56 | array('name', 'email@example.com|Mr. Email', false)); 57 | 58 | $anonymizer = new Anonymizer($provider, 'de_DE'); 59 | $anonymizer->anonymize([new AnonymizableMock(['email' => 'email@example.com', 'name' => 'Mr. Email'], 'email')]); 60 | 61 | } 62 | 63 | public static function getAnonymizableData() 64 | { 65 | return array( 66 | array( 67 | 'inputData' => array( 68 | new AnonymizableMock(['email' => 'max.mustermann@example.com', 'firstName' => 'Max', 'lastName' => 'Mustermann']), 69 | new AnonymizableMock(['email' => 'max.mustermann2@example.com', 'firstName' => 'Max', 'lastName' => 'Mustermann']), 70 | new AnonymizableMock(['email' => 'maxi.musterfrau@example.com', 'firstName' => 'Maxi', 'lastName' => 'Musterfrau']), 71 | new AnonymizableMock(['email' => 'max.mustermann@example.com', 'firstName' => 'Max', 'lastName' => 'Mustermann', 'streetAddress' => 'Musterstraße 42']), 72 | ), 73 | 'expectedValues' => array( 74 | 'email_max.mustermann@example.com', 'firstName_max.mustermann@example.com', 'lastName_max.mustermann@example.com', 75 | 'email_max.mustermann2@example.com', 'firstName_max.mustermann2@example.com', 'lastName_max.mustermann2@example.com', 76 | 'email_maxi.musterfrau@example.com', 'firstName_maxi.musterfrau@example.com', 'lastName_maxi.musterfrau@example.com', 77 | 'email_max.mustermann@example.com', 'firstName_max.mustermann@example.com', 'lastName_max.mustermann@example.com', 'streetAddress_max.mustermann@example.com' 78 | ) 79 | ) 80 | ); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /test/IntegerNet/Anonymizer/Mock/AnonymizableMock.php: -------------------------------------------------------------------------------- 1 | 9 | */ 10 | 11 | namespace IntegerNet\Anonymizer\Mock; 12 | 13 | 14 | use IntegerNet\Anonymizer\Implementor\AnonymizableEntity; 15 | use IntegerNet\Anonymizer\AnonymizableValue; 16 | 17 | /** 18 | * Dumb implementation of AnonymizableEntity that generates AnonymizableValue instances from test data 19 | * 20 | * @package IntegerNet\Anonymizer\Mock 21 | */ 22 | class AnonymizableMock implements AnonymizableEntity 23 | { 24 | const __CLASS = __CLASS__; 25 | 26 | private $data = array(); 27 | private $identifier = ''; 28 | private $uniqueKey = null; 29 | 30 | /** 31 | * @param mixed[] $data data in the form [formatter => value], the first entry will be used as identifier 32 | * @param string|null $uniqueKey 33 | */ 34 | function __construct($data = array(), $uniqueKey = null) 35 | { 36 | $this->uniqueKey = $uniqueKey; 37 | $this->setRawData($data); 38 | } 39 | 40 | /** 41 | * @return string 42 | */ 43 | function getIdentifier() 44 | { 45 | return $this->identifier; 46 | } 47 | 48 | /** 49 | * @return AnonymizableValue[] 50 | */ 51 | function getValues() 52 | { 53 | return $this->data; 54 | } 55 | 56 | /** 57 | * Sets raw data from database 58 | * 59 | * @param string[] $data 60 | * @return void 61 | */ 62 | function setRawData($data) 63 | { 64 | foreach ($data as $key => $value) { 65 | $this->data[] = new AnonymizableValue($key, $value, $this->uniqueKey === $key); 66 | } 67 | if (!empty($this->data)) { 68 | $this->identifier = reset($this->data)->getValue(); 69 | } 70 | } 71 | 72 | /** 73 | * Update values in database 74 | * 75 | * @return mixed 76 | */ 77 | function updateValues() 78 | { 79 | // method stub. Should be mocked with PHPUnit to set expectations 80 | } 81 | 82 | /** 83 | * Reset to empty instance 84 | * 85 | * @return mixed 86 | */ 87 | function clearInstance() 88 | { 89 | $this->data = array(); 90 | $this->identifier = ''; 91 | } 92 | 93 | /** 94 | * Returns name of entity as translatable string 95 | * 96 | * @return string 97 | */ 98 | function getEntityName() 99 | { 100 | return 'Mock'; 101 | } 102 | 103 | } 104 | -------------------------------------------------------------------------------- /test/IntegerNet/Anonymizer/Mock/CollectionMock.php: -------------------------------------------------------------------------------- 1 | 9 | */ 10 | 11 | namespace IntegerNet\Anonymizer\Mock; 12 | 13 | 14 | use IntegerNet\Anonymizer\Implementor\CollectionIterator; 15 | 16 | /** 17 | * Dumb implementation of CollectionIterator that iterates over an array of data 18 | * 19 | * @package IntegerNet\Anonymizer\Mock 20 | */ 21 | class CollectionMock extends \ArrayIterator implements CollectionIterator 22 | { 23 | const __CLASS = __CLASS__; 24 | 25 | /** 26 | * @param callable $callable 27 | * @return mixed 28 | */ 29 | function walk(/*callable*/ $callable) 30 | { 31 | foreach ($this as $row) { 32 | $callable($this); 33 | } 34 | } 35 | 36 | /** 37 | * Returns raw data from database 38 | * 39 | * @return mixed 40 | */ 41 | function getRawData() 42 | { 43 | return $this->current(); 44 | } 45 | 46 | /** 47 | * Returns number of iteration 48 | * 49 | * @return int 50 | */ 51 | function getIteration() 52 | { 53 | return $this->key(); 54 | } 55 | 56 | /** 57 | * Returns total size of collection 58 | * 59 | * @return mixed 60 | */ 61 | function getSize() 62 | { 63 | return $this->count(); 64 | } 65 | 66 | } -------------------------------------------------------------------------------- /test/IntegerNet/Anonymizer/ProviderTest.php: -------------------------------------------------------------------------------- 1 | 9 | */ 10 | 11 | namespace IntegerNet\Anonymizer; 12 | 13 | 14 | class ProviderTest extends \PHPUnit_Framework_TestCase 15 | { 16 | public function testDeterministicValues() 17 | { 18 | $provider = new Provider(); 19 | $provider->initialize('de_DE'); 20 | $aName = $provider->getFakerData('name', 'a@example.com'); 21 | $aRandomNumber = mt_rand(); 22 | $aDifferentName = $provider->getFakerData('name', 'b@example.com'); 23 | $aSameName = $provider->getFakerData('name', 'a@example.com'); 24 | $this->assertNotEquals($aName, $aDifferentName, 'Name should be different for different identifier (email address)'); 25 | $this->assertEquals($aName, $aSameName, 'Name should be equal for same identifier (email address)'); 26 | $this->assertNotEquals($aRandomNumber, mt_rand(), 'The provider should not have side effects on mt_rand.'); 27 | 28 | $provider->initialize('de_DE'); 29 | $aNameAfterReinitialize = $provider->getFakerData('name', 'a@example.com'); 30 | $this->assertNotEquals($aName, $aNameAfterReinitialize, 'Names should be different each anonymization process.'); 31 | } 32 | public function testNullFormatter() 33 | { 34 | $provider = new Provider(); 35 | $provider->initialize('de_DE'); 36 | $nulledData = $provider->getFakerData('null', 'a@example.com'); 37 | $this->assertEquals(null, $nulledData); 38 | } 39 | public function testUniqueData() 40 | { 41 | $provider = new Provider(); 42 | $provider->initialize('de_DE'); 43 | $randomDigits = array(); 44 | for ($d = 0; $d < 10; ++$d) { 45 | $randomDigits[] = $provider->getFakerData('randomDigit', 'a@example.com', true); 46 | } 47 | sort($randomDigits); 48 | $this->assertEquals(range(0,9), $randomDigits, '10 unique digits should be all from 0..9'); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /test/IntegerNet/Anonymizer/UpdaterTest.php: -------------------------------------------------------------------------------- 1 | 9 | */ 10 | 11 | namespace IntegerNet\Anonymizer; 12 | 13 | 14 | use IntegerNet\Anonymizer\Mock\AnonymizableMock; 15 | use IntegerNet\Anonymizer\Mock\CollectionMock; 16 | 17 | class UpdaterTest extends \PHPUnit_Framework_TestCase 18 | { 19 | /** 20 | * @var Anonymizer|\PHPUnit_Framework_MockObject_MockObject 21 | */ 22 | private $anonymizerMock; 23 | /** 24 | * @var Updater 25 | */ 26 | private $updater; 27 | 28 | protected function setUp() 29 | { 30 | $this->anonymizerMock = $this->getMock(Anonymizer::__CLASS, array('anonymize', 'resetUniqueGenerator'), array(), '', false); 31 | $this->updater = new Updater($this->anonymizerMock); 32 | } 33 | 34 | /** 35 | * @test 36 | * @dataProvider getCollectionData 37 | */ 38 | public function testUpdater($collectionData) 39 | { 40 | $entityCount = count($collectionData); 41 | 42 | $this->anonymizerMock->expects($this->exactly(1))->method('resetUniqueGenerator'); 43 | $this->anonymizerMock->expects($this->exactly($entityCount))->method('anonymize'); 44 | 45 | $entityModel = $this->getEntityMock(); 46 | foreach ($collectionData as $i => $entityData) { 47 | $entityModel->expects($this->at($i * 3))->method('setRawData') 48 | ->with($entityData); 49 | $entityModel->expects($this->at($i * 3 + 1))->method('updateValues'); 50 | $entityModel->expects($this->at($i * 3 + 2))->method('clearInstance'); 51 | } 52 | $entityModel->expects($this->exactly($entityCount))->method('setRawData'); 53 | $entityModel->expects($this->exactly($entityCount))->method('updateValues'); 54 | $entityModel->expects($this->exactly($entityCount))->method('clearInstance'); 55 | 56 | $collectionIterator = new CollectionMock($collectionData); 57 | 58 | $this->updater->update($collectionIterator, $entityModel); 59 | } 60 | 61 | private function getEntityMock() 62 | { 63 | return $this->getMock(AnonymizableMock::__CLASS, array('setRawData', 'updateValues', 'clearInstance')); 64 | } 65 | 66 | /** 67 | * @test 68 | * @dataProvider getCollectionData 69 | */ 70 | public function testOutputControl($collectionData) 71 | { 72 | $stream = fopen('php://temp', 'r+'); 73 | $this->updater->setOutputStream($stream); 74 | $this->updater->update(new CollectionMock($collectionData), $this->getEntityMock()); 75 | $actualOutput = stream_get_contents($stream, -1, 0); 76 | $this->assertContains('Updater started at', $actualOutput); 77 | $this->assertContains('Updating Mock: 1/5 ', $actualOutput); 78 | $this->assertContains('Updating Mock: 2/5 ', $actualOutput); 79 | $this->assertContains('Updating Mock: 3/5 ', $actualOutput); 80 | $this->assertContains('Updating Mock: 4/5 ', $actualOutput); 81 | $this->assertContains('Updating Mock: 5/5 ', $actualOutput); 82 | $this->assertContains('Updater finished at', $actualOutput); 83 | fclose($stream); 84 | 85 | $stream = fopen('php://temp', 'r+'); 86 | $this->updater->setOutputStream($stream); 87 | $this->updater->setProgressSteps(2); 88 | $this->updater->update(new CollectionMock($collectionData), $this->getEntityMock()); 89 | $actualOutput = stream_get_contents($stream, -1, 0); 90 | $this->assertContains('Updater started at', $actualOutput); 91 | $this->assertNotContains('Updating Mock: 1/5 ', $actualOutput); 92 | $this->assertContains('Updating Mock: 2/5 ', $actualOutput); 93 | $this->assertNotContains('Updating Mock: 3/5 ', $actualOutput); 94 | $this->assertContains('Updating Mock: 4/5 ', $actualOutput); 95 | $this->assertNotContains('Updating Mock: 5/5 ', $actualOutput); 96 | $this->assertContains('Updater finished at', $actualOutput); 97 | fclose($stream); 98 | 99 | $stream = fopen('php://temp', 'r+'); 100 | $this->updater->setOutputStream($stream); 101 | $this->updater->setShowProgress(false); 102 | $this->updater->update(new CollectionMock($collectionData), $this->getEntityMock()); 103 | $actualOutput = stream_get_contents($stream, -1, 0); 104 | $this->assertContains('Updater started at', $actualOutput); 105 | $this->assertNotContains('Updating ', $actualOutput); 106 | $this->assertContains('Updater finished at', $actualOutput); 107 | fclose($stream); 108 | 109 | } 110 | 111 | public static function getCollectionData() 112 | { 113 | return array( 114 | array( 115 | 'collectionData' => array( 116 | array('email' => 'death@example.com', 'name' => 'Death'), 117 | array('email' => 'pestilence@example.com', 'name' => 'Pestilence'), 118 | array('email' => 'famine@example.com', 'name' => 'Famine'), 119 | array('email' => 'war@example.com', 'name' => 'War'), 120 | array('email' => 'ronny@example.com', 'name' => 'Ronny') 121 | ) 122 | ) 123 | ); 124 | } 125 | 126 | } 127 | -------------------------------------------------------------------------------- /test/bootstrap.php: -------------------------------------------------------------------------------- 1 |