├── .gitignore ├── LICENSE.txt ├── README.md ├── composer.json ├── modman ├── src └── app │ ├── code │ └── community │ │ └── Hackathon │ │ └── MageTrashApp │ │ ├── Adminhtml │ │ └── Block │ │ │ └── System │ │ │ └── Config │ │ │ └── Form │ │ │ └── Fieldset │ │ │ └── Modules │ │ │ └── MageTrashApp.php │ │ ├── Block │ │ └── Adminhtml │ │ │ └── System │ │ │ └── Config │ │ │ └── Form │ │ │ └── Fieldset │ │ │ └── Modules │ │ │ ├── MageTrashApp.php │ │ │ └── Rewind.php │ │ ├── Helper │ │ └── Data.php │ │ ├── Model │ │ ├── Adminhtml │ │ │ └── Config │ │ │ │ └── Data.php │ │ ├── CoreResource.php │ │ ├── Observer.php │ │ ├── PearWrapper.php │ │ ├── Resource │ │ │ ├── Resource.php │ │ │ └── Setup.php │ │ └── Uninstall.php │ │ ├── Test │ │ ├── Config │ │ │ └── Config.php │ │ ├── Helper │ │ │ └── DataTest.php │ │ └── Model │ │ │ └── Observer.php │ │ ├── controllers │ │ └── Adminhtml │ │ │ └── indexController.php │ │ └── etc │ │ ├── adminhtml.xml │ │ ├── config.xml │ │ ├── doc.uninstall.txt │ │ └── system.xml │ └── etc │ └── modules │ └── Hackathon_MageTrashApp.xml └── tests └── app ├── code └── community │ └── Hackathon │ └── MageTrashAppTest │ ├── Test │ └── Model │ │ ├── Observer.php │ │ └── _data │ │ └── fx-config.yaml │ └── etc │ └── config.xml └── etc └── modules └── Hackathon_MageTrashAppTest.xml /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .idea 3 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/magento-hackathon/MageTrashApp/d17704da4214cb76cc325386a3e3b335470e3d7b/LICENSE.txt -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | MageTrashApp 2 | ============ 3 | 4 | Clean uninstallation or deactivation of Magento modules 5 | 6 | ## Functionality ## 7 | 8 | Provides the capability to fully disable and uninstall Magento extensions 9 | 10 | Uninstall features: 11 | 12 | 1. Will run a sql uninstall script for module (must be called `uninstall.php` and be in sql directory) 13 | 2. Will attempt to uninstall using PEAR packaging commands (as in Magento Connect) 14 | 3. If not package found then will use uninstall file specified in module `config.xml` (by default, it is `etc/uninstall.txt`) 15 | 16 | Install script features: 17 | 18 | 1. Delete core_resource to force Magento to run install/upgrade scripts. 19 | 2. Rewind core_resource to force Magento to run some install/upgrade scripts. 20 | 21 | 22 | ## Instructions ## 23 | 24 | 1. Install module (modman file provided) 25 | 2. Refresh cache and re-sign into Magento Admin 26 | 3. Under `System > Configuration > Advanced` you will see MageTrashApp 27 | 4. For each module you have options to enable, disable, Uninstall 28 | 5. For each module you have options to delete or rewind `core_resource` 29 | 30 | 31 | 32 | ## For Developers of modules ## 33 | Place a file `uninstall.txt` into the folder `etc/` of your module to allow to be triggered by this module when you uninstall it. 34 | If you wish to change the name of this `uninstall.txt` file to something different, just set into the `config.xml` file of your module, the following: 35 | 36 | 37 | ... 38 | 39 | myuninstallfile.txt 40 | 41 | 42 | 43 | The format of the content should start from the Magento root path. For example: you want to uninstall the module `Namespace_Mymodule` placed into the community code pool. 44 | Just add the following lines to the file: 45 | 46 | app/code/community/Namespace/Mymodule 47 | app/etc/modules/Namespace_Mymodule.xml 48 | js/mynamespace/ 49 | skin/frontend/base/default/images/mynapespace 50 | 51 | If you have modman, you can copy the modman file into the `etc` folder of your module (app/code/.../Mynamespace/Mymodule/etc/) and rename it to `uninstall.txt` file. In this case, the second part of each line will be taken to uninstall your module. 52 | For example: 53 | 54 | src/app/code/community/Namespace/Mymodule app/code/community/Namespace/Mymodule 55 | src/app/etc/modules/Namespace_Mymodule.xml app/etc/modules/Namespace_Mymodule.xml 56 | 57 | ## Further Information 58 | 59 | ### Core Contributors 60 | 61 | * Tom Kadwill 62 | * Sylvain Rayé 63 | * wsakaren 64 | * Damian Luszczymak 65 | 66 | ### Current Status of Project 67 | 68 | Complete and working. 69 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name":"magento-hackathon/hackathon_magetrashapp", 3 | "type":"magento-module", 4 | "license":"OSL-3.0", 5 | "homepage":"https://github.com/magento-hackathon/MageTrashApp", 6 | "description":"Clean uninstallation or deactivation of Magento modules", 7 | "authors":[ 8 | { 9 | "name":"Sylvain Rayé" 10 | }, 11 | { 12 | "name":"Tom Kadwill" 13 | }, 14 | { 15 | "name":"wsakaren" 16 | }, 17 | { 18 | "name":"Damian Luszczymak" 19 | } 20 | ], 21 | "require":{ 22 | "magento-hackathon/magento-composer-installer":"*" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /modman: -------------------------------------------------------------------------------- 1 | src/app/code/community/Hackathon/MageTrashApp app/code/community/Hackathon/MageTrashApp 2 | src/app/etc/modules/* app/etc/modules/ 3 | tests/app/code/community/Hackathon/MageTrashAppTest app/code/community/Hackathon/MageTrashAppTest 4 | tests/app/etc/modules/* app/etc/modules/ 5 | -------------------------------------------------------------------------------- /src/app/code/community/Hackathon/MageTrashApp/Adminhtml/Block/System/Config/Form/Fieldset/Modules/MageTrashApp.php: -------------------------------------------------------------------------------- 1 | _getHeaderHtml($element); 16 | 17 | $modules = array_keys((array)Mage::getConfig()->getNode('modules')->children()); 18 | 19 | $dispatchResult = new Varien_Object($modules); 20 | Mage::dispatchEvent( 21 | 'magetrashapp_system_config_magetrashapp_manage_extns_render_before', 22 | array('modules' => $dispatchResult) 23 | ); 24 | $modules = $dispatchResult->toArray(); 25 | 26 | sort($modules); 27 | 28 | foreach ($modules as $moduleName) { 29 | $moduleStatus = Mage::getConfig()->getModuleConfig($moduleName)->is('active', 'true'); 30 | 31 | if ($moduleName==='Mage_Adminhtml' ||$moduleName==='Hackathon_MageTrashApp' 32 | || stripos($moduleName,'Mage_') !== false) { 33 | continue; 34 | } 35 | $html.= $this->_getFieldHtml($element, $moduleName,$moduleStatus); 36 | } 37 | $html .= $this->_getFooterHtml($element); 38 | 39 | return $html; 40 | } 41 | 42 | protected function _getDummyElement() 43 | { 44 | if (empty($this->_dummyElement)) { 45 | $this->_dummyElement = new Varien_Object(array('show_in_default'=>1, 'show_in_website'=>1)); 46 | } 47 | return $this->_dummyElement; 48 | } 49 | 50 | protected function _getFieldRenderer() 51 | { 52 | if (empty($this->_fieldRenderer)) { 53 | $this->_fieldRenderer = Mage::getBlockSingleton('adminhtml/system_config_form_field'); 54 | } 55 | return $this->_fieldRenderer; 56 | } 57 | 58 | 59 | 60 | protected function _getValues() 61 | { 62 | if (empty($this->_values)) { 63 | $this->_values = array( 64 | array('label'=>Mage::helper('adminhtml')->__('Disabled'), 'value'=>0), 65 | array('label'=>Mage::helper('adminhtml')->__('Enabled'), 'value'=>1), 66 | array('label'=>Mage::helper('adminhtml')->__('Uninstall'), 'value'=>2), 67 | ); 68 | } 69 | return $this->_values; 70 | } 71 | 72 | 73 | protected function _getFieldHtml($fieldset, $moduleName,$moduleStatus) 74 | { 75 | 76 | $e = $this->_getDummyElement(); 77 | 78 | $field = $fieldset->addField($moduleName, 'select', 79 | array( 80 | 'name' => 'groups[manage_extns][fields]['.$moduleName.'][value]', 81 | 'label' => $moduleName, 82 | 'value' => (int)$moduleStatus, 83 | 'values' => $this->_getValues(), 84 | 'inherit' => true, 85 | 'can_use_default_value' => $this->getForm()->canUseDefaultValue($e), 86 | 'can_use_website_value' => $this->getForm()->canUseWebsiteValue($e), 87 | ))->setRenderer($this->_getFieldRenderer()); 88 | 89 | return $field->toHtml(); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/app/code/community/Hackathon/MageTrashApp/Block/Adminhtml/System/Config/Form/Fieldset/Modules/MageTrashApp.php: -------------------------------------------------------------------------------- 1 | _getHeaderHtml($element); 16 | 17 | $modules = array_keys((array)Mage::getConfig()->getNode('modules')->children()); 18 | 19 | $dispatchResult = new Varien_Object($modules); 20 | Mage::dispatchEvent( 21 | 'magetrashapp_system_config_magetrashapp_manage_extns_render_before', 22 | array('modules' => $dispatchResult) 23 | ); 24 | $modules = $dispatchResult->toArray(); 25 | 26 | sort($modules); 27 | 28 | foreach ($modules as $moduleName) { 29 | $moduleStatus = Mage::getConfig()->getModuleConfig($moduleName)->is('active', 'true'); 30 | 31 | if ($moduleName==='Mage_Adminhtml' ||$moduleName==='Hackathon_MageTrashApp' 32 | || stripos($moduleName,'Mage_') !== false) { 33 | continue; 34 | } 35 | $html.= $this->_getFieldHtml($element, $moduleName,$moduleStatus); 36 | } 37 | $html .= $this->_getFooterHtml($element); 38 | 39 | return $html; 40 | } 41 | 42 | protected function _getDummyElement() 43 | { 44 | if (empty($this->_dummyElement)) { 45 | $this->_dummyElement = new Varien_Object(array('show_in_default'=>1, 'show_in_website'=>1)); 46 | } 47 | return $this->_dummyElement; 48 | } 49 | 50 | protected function _getFieldRenderer() 51 | { 52 | if (empty($this->_fieldRenderer)) { 53 | $this->_fieldRenderer = Mage::getBlockSingleton('adminhtml/system_config_form_field'); 54 | } 55 | return $this->_fieldRenderer; 56 | } 57 | 58 | 59 | 60 | protected function _getValues() 61 | { 62 | if (empty($this->_values)) { 63 | $this->_values = array( 64 | array('label'=>Mage::helper('adminhtml')->__('Disabled'), 'value'=>0), 65 | array('label'=>Mage::helper('adminhtml')->__('Enabled'), 'value'=>1), 66 | array('label'=>Mage::helper('adminhtml')->__('Uninstall'), 'value'=>2), 67 | ); 68 | } 69 | return $this->_values; 70 | } 71 | 72 | 73 | protected function _getFieldHtml($fieldset, $moduleName,$moduleStatus) 74 | { 75 | 76 | $e = $this->_getDummyElement(); 77 | 78 | $field = $fieldset->addField($moduleName, 'select', 79 | array( 80 | 'name' => 'groups[manage_extns][fields]['.$moduleName.'][value]', 81 | 'label' => $moduleName, 82 | 'value' => (int)$moduleStatus, 83 | 'values' => $this->_getValues(), 84 | 'inherit' => true, 85 | 'can_use_default_value' => $this->getForm()->canUseDefaultValue($e), 86 | 'can_use_website_value' => $this->getForm()->canUseWebsiteValue($e), 87 | ))->setRenderer($this->_getFieldRenderer()); 88 | 89 | return $field->toHtml(); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/app/code/community/Hackathon/MageTrashApp/Block/Adminhtml/System/Config/Form/Fieldset/Modules/Rewind.php: -------------------------------------------------------------------------------- 1 | _getHeaderHtml($element); 15 | 16 | $modules = array_keys((array)Mage::getConfig()->getNode('modules')->children()); 17 | 18 | $dispatchResult = new Varien_Object($modules); 19 | Mage::dispatchEvent( 20 | 'magetrashapp_system_config_magetrashapp_manage_extns_render_before', 21 | array('modules' => $dispatchResult) 22 | ); 23 | $modules = $dispatchResult->toArray(); 24 | 25 | sort($modules); 26 | 27 | foreach ($modules as $moduleName) { 28 | if ($moduleName==='Mage_Adminhtml' || $moduleName==='Hackathon_MageTrashApp' 29 | || stripos($moduleName,'Mage_') !== false) { 30 | continue; 31 | } 32 | 33 | $resName = Mage::helper('magetrashapp')->getResourceName($moduleName); 34 | if($resName===null) continue; 35 | $number = Mage::getResourceSingleton('core/resource')->getDbVersion($resName); 36 | if (!$resName || $resName == $number) { 37 | continue; 38 | } 39 | 40 | $html.= $this->_getFieldHtml($element, $moduleName); 41 | } 42 | $html .= $this->_getFooterHtml($element); 43 | return $html; 44 | } 45 | 46 | protected function _getDummyElement() 47 | { 48 | if (empty($this->_dummyElement)) { 49 | $this->_dummyElement = new Varien_Object(array('show_in_default'=>1, 'show_in_website'=>1)); 50 | } 51 | return $this->_dummyElement; 52 | } 53 | 54 | protected function _getFieldRenderer() 55 | { 56 | if (empty($this->_fieldRenderer)) { 57 | $this->_fieldRenderer = Mage::getBlockSingleton('adminhtml/system_config_form_field'); 58 | } 59 | return $this->_fieldRenderer; 60 | } 61 | 62 | /** 63 | * @param $moduleName 64 | * @return array 65 | */ 66 | protected function _getValues($moduleName) 67 | { 68 | $nameSpaceModule = str_replace('_', '/', $moduleName); 69 | $resName = Mage::helper('magetrashapp')->getResourceName($moduleName); 70 | $community = Mage::getBaseDir('code') . DS . 'community' . DS; 71 | 72 | $sqlScriptPath = $community . $nameSpaceModule . DS . 'sql' . DS . $resName . DS. '*.*'; 73 | 74 | $valuesArray = array( 75 | array('label'=>Mage::helper('adminhtml')->__('Do nothing'), 'value'=>2), 76 | array('label'=>Mage::helper('adminhtml')->__('Delete core_resource'), 'value'=>0) 77 | ); 78 | 79 | // Loop through all sql files and create a value for each 80 | foreach(glob($sqlScriptPath) as $filename){ 81 | $filename = explode("-",basename($filename)); 82 | 83 | $number = ""; 84 | foreach ($filename as $part) { 85 | if (strpos($part, ".php")) { 86 | $part = str_replace('.php', '', $part); 87 | $number = $part; 88 | } 89 | } 90 | 91 | $sqlVersionsArray[] = array('label'=>Mage::helper('adminhtml')->__( 92 | 'Rewind core_resource: ' . $number), 'value'=>'1_' . $number 93 | ); 94 | } 95 | 96 | if (!empty($sqlVersionsArray)) { 97 | $valuesArray = array_merge($valuesArray, array_reverse($sqlVersionsArray)); 98 | } 99 | 100 | return $valuesArray; 101 | } 102 | 103 | 104 | protected function _getFieldHtml($fieldset, $moduleName) 105 | { 106 | 107 | $e = $this->_getDummyElement(); 108 | 109 | $field = $fieldset->addField($moduleName . '_Rewind', 'select', 110 | array( 111 | 'name' => 'groups[rewind_extns][fields]['.$moduleName.'][value]', 112 | 'label' => $moduleName, 113 | 'value' => 2, 114 | 'values' => $this->_getValues($moduleName), 115 | 'inherit' => true, 116 | 'can_use_default_value' => $this->getForm()->canUseDefaultValue($e), 117 | 'can_use_website_value' => $this->getForm()->canUseWebsiteValue($e), 118 | ))->setRenderer($this->_getFieldRenderer()); 119 | 120 | return $field->toHtml(); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/app/code/community/Hackathon/MageTrashApp/Helper/Data.php: -------------------------------------------------------------------------------- 1 | activateModule($moduleName,false); 15 | 16 | // Check the dependencies first and allow the rest of the process otherwise block it 17 | $dependencies = $this->checkDependencies($moduleName); 18 | if (count($dependencies) > 0) { 19 | Mage::throwException( 20 | $this->__('The module %s has dependencies with the module(s) %s. Please fix that before to remove this module.', $moduleName, implode(',', $dependencies)) 21 | ); 22 | return; 23 | } 24 | 25 | /* @var $uninstallModel Hackathon_MageTrashApp_Model_Uninstall */ 26 | $uninstallModel = Mage::getModel('magetrashapp/uninstall'); 27 | 28 | // We need to trigger SQL uninstall scripts 29 | Mage::dispatchEvent('magetrashapp_before_sql_uninstall'); 30 | $uninstallModel->uninstallSqlCommand($moduleName); 31 | Mage::dispatchEvent('magetrashapp_after_sql_uninstall'); 32 | 33 | // We need to remove all package files based on uninstall.txt file or modman file 34 | Mage::dispatchEvent('magetrashapp_before_package_uninstall'); 35 | $uninstallModel->processUninstallPackage($moduleName); 36 | Mage::dispatchEvent('magetrashapp_after_package_uninstall'); 37 | Mage::getSingleton('adminhtml/session')->addSuccess($moduleName.' has been uninstalled.'); 38 | 39 | // Do the cleanup of the config here because we need the old config until this point 40 | Mage::app()->getStore()->resetConfig(); 41 | } 42 | 43 | /** 44 | * 45 | * @param string $moduleName 46 | * @return boolean | array 47 | */ 48 | protected function checkDependencies ($moduleName) 49 | { 50 | $moduleDepends = array(); 51 | foreach (Mage::getConfig()->getNode('modules')->children() as $parentName => $module) { 52 | if ($parentName == $moduleName) { 53 | continue; 54 | } 55 | 56 | if ($module->depends) { 57 | foreach ($module->depends->children() as $name => $depend) { 58 | if ($name === $moduleName && (bool) Mage::getConfig()->getModuleConfig($moduleName)->is('active', 'true')) { 59 | $moduleDepends[] = $parentName; 60 | } 61 | } 62 | } 63 | } 64 | 65 | return $moduleDepends; 66 | } 67 | 68 | /** 69 | * Activate/Deactivate a Magento module 70 | * 71 | * @param string $name 72 | * @return string 73 | */ 74 | public function activateModule($name,$activateFlag = true) 75 | { 76 | $isDeactivationPossible = true; 77 | if (count($this->checkDependencies($name)) > 0) { 78 | $isDeactivationPossible = false; 79 | } 80 | 81 | 82 | if ($isDeactivationPossible) { 83 | $status = ''; 84 | $xmlPath = Mage::getBaseDir() . DS . 'app' . DS . 'etc' . DS . 'modules' . DS . $name .'.xml'; 85 | if (file_exists($xmlPath)) { 86 | $xmlObj = new Varien_Simplexml_Config($xmlPath); 87 | 88 | $xmlObj->setNode( 89 | 'modules/'.$name.'/active', 90 | $activateFlag ? 'true' : 'false' 91 | ); 92 | 93 | if (is_writable($xmlPath)) { 94 | $xmlData = $xmlObj->getNode()->asNiceXml(); 95 | @file_put_contents($xmlPath, $xmlData); 96 | if ($activateFlag) { 97 | $status = $this->__('The module "%s" has been successfully activated.', $name); 98 | } else { 99 | $status = $this->__('The module "%s" has been successfully deactivated.', $name); 100 | } 101 | } else { 102 | $status = $this->__('File %s is not writable.', $xmlPath); 103 | } 104 | } else { 105 | $status = $this->__( 106 | 'Module %s is probably not installed. File %s does not exist.', 107 | $name, 108 | $xmlPath 109 | ); 110 | } 111 | } else { 112 | $status = $this->__('Module can\'t be deactivated because it is a dependency of another module which is still active.'); 113 | } 114 | 115 | return $status; 116 | } 117 | 118 | public function rrmdir($dir) 119 | { 120 | if (is_dir($dir)) { 121 | $objects = scandir($dir); 122 | foreach ($objects as $object) { 123 | if ($object != "." && $object != "..") { 124 | if (filetype($dir."/".$object) == "dir") $this->rrmdir($dir."/".$object); else unlink($dir."/".$object); 125 | } 126 | } 127 | reset($objects); 128 | rmdir($dir); 129 | } 130 | } 131 | 132 | /** 133 | * Delete Core Resource for specified module 134 | * 135 | * @param $moduleName 136 | */ 137 | public function deleteCoreResource($moduleName) 138 | { 139 | $resName = $this->getResourceName($moduleName); 140 | $number = Mage::getResourceSingleton('core/resource')->getDbVersion($resName); 141 | 142 | Mage::getModel('magetrashapp/coreresource')->deleteCoreResource($moduleName, $resName, $number); 143 | } 144 | 145 | /** 146 | * Rewind Core Resource for specified module 147 | * 148 | * @param $moduleName 149 | * @param $number 150 | */ 151 | public function rewindCoreResource ($moduleName, $number) 152 | { 153 | $resName = Mage::helper('magetrashapp')->getResourceName($moduleName); 154 | 155 | Mage::getModel('magetrashapp/coreresource')->rewindCoreResource($moduleName, $resName, $number); 156 | } 157 | 158 | /** 159 | * Get resource name from config.xml node 160 | * 161 | * @param $moduleName 162 | * @return mixed 163 | */ 164 | public function getResourceName($moduleName) { 165 | $config = Mage::app()->getConfig(); 166 | $xmlPath = $config->getModuleDir('etc', $moduleName) . DS . 'config.xml'; 167 | 168 | if (file_exists($xmlPath)) { 169 | $xmlObj = new Varien_Simplexml_Config($xmlPath); 170 | 171 | $resourceNode = $xmlObj->getNode('global/resources'); 172 | if ($resourceNode) { 173 | $resourceNode = $resourceNode->asArray(); 174 | if(!is_array($resourceNode)) return; 175 | reset($resourceNode); 176 | $resName = key($resourceNode); 177 | return $resName; 178 | } 179 | } 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /src/app/code/community/Hackathon/MageTrashApp/Model/Adminhtml/Config/Data.php: -------------------------------------------------------------------------------- 1 | _validate(); 16 | $this->_getScope(); 17 | 18 | Mage::dispatchEvent('model_config_data_save_before', array('object' => $this)); 19 | 20 | $section = $this->getSection(); 21 | $website = $this->getWebsite(); 22 | $store = $this->getStore(); 23 | $groups = $this->getGroups(); 24 | $scope = $this->getScope(); 25 | $scopeId = $this->getScopeId(); 26 | 27 | if (empty($groups)) { 28 | return $this; 29 | } 30 | 31 | $sections = Mage::getModel('adminhtml/config')->getSections(); 32 | /* @var $sections Mage_Core_Model_Config_Element */ 33 | 34 | $oldConfig = $this->_getConfig(true); 35 | 36 | $deleteTransaction = Mage::getModel('core/resource_transaction'); 37 | /* @var $deleteTransaction Mage_Core_Model_Resource_Transaction */ 38 | $saveTransaction = Mage::getModel('core/resource_transaction'); 39 | /* @var $saveTransaction Mage_Core_Model_Resource_Transaction */ 40 | 41 | // Extends for old config data 42 | $oldConfigAdditionalGroups = array(); 43 | 44 | foreach ($groups as $group => $groupData) { 45 | /** 46 | * Map field names if they were cloned 47 | */ 48 | $groupConfig = $sections->descend($section.'/groups/'.$group); 49 | 50 | if ($clonedFields = !empty($groupConfig->clone_fields)) { 51 | if ($groupConfig->clone_model) { 52 | $cloneModel = Mage::getModel((string)$groupConfig->clone_model); 53 | } else { 54 | Mage::throwException('Config form fieldset clone model required to be able to clone fields'); 55 | } 56 | $mappedFields = array(); 57 | $fieldsConfig = $sections->descend($section.'/groups/'.$group.'/fields'); 58 | 59 | if ($fieldsConfig->hasChildren()) { 60 | foreach ($fieldsConfig->children() as $field => $node) { 61 | foreach ($cloneModel->getPrefixes() as $prefix) { 62 | $mappedFields[$prefix['field'].(string)$field] = (string)$field; 63 | } 64 | } 65 | } 66 | } 67 | // set value for group field entry by fieldname 68 | // use extra memory 69 | $fieldsetData = array(); 70 | foreach ($groupData['fields'] as $field => $fieldData) { 71 | $fieldsetData[$field] = (is_array($fieldData) && isset($fieldData['value'])) 72 | ? $fieldData['value'] : null; 73 | } 74 | 75 | foreach ($groupData['fields'] as $field => $fieldData) { 76 | $field = ltrim($field, '/'); 77 | $fieldConfig = $sections->descend($section . '/groups/' . $group . '/fields/' . $field); 78 | if (!$fieldConfig && $clonedFields && isset($mappedFields[$field])) { 79 | $fieldConfig = $sections->descend($section . '/groups/' . $group . '/fields/' 80 | . $mappedFields[$field]); 81 | } 82 | if (!$fieldConfig) { 83 | $node = $sections->xpath($section .'//' . $group . '[@type="group"]/fields/' . $field); 84 | if ($node) { 85 | $fieldConfig = $node[0]; 86 | } 87 | } 88 | 89 | /** 90 | * Get field backend model 91 | */ 92 | // HACKATHON START 93 | if ($fieldConfig) { 94 | $backendClass = $fieldConfig->backend_model; 95 | if (!$backendClass) { 96 | $backendClass = 'core/config_data'; 97 | } 98 | } else { 99 | $backendClass = 'core/config_data'; 100 | } 101 | // HACKATHON END 102 | 103 | 104 | /** @var $dataObject Mage_Core_Model_Config_Data */ 105 | $dataObject = Mage::getModel($backendClass); 106 | if (!$dataObject instanceof Mage_Core_Model_Config_Data) { 107 | Mage::throwException('Invalid config field backend model: '.$backendClass); 108 | } 109 | 110 | $dataObject 111 | ->setField($field) 112 | ->setGroups($groups) 113 | ->setGroupId($group) 114 | ->setStoreCode($store) 115 | ->setWebsiteCode($website) 116 | ->setScope($scope) 117 | ->setScopeId($scopeId) 118 | ->setFieldConfig($fieldConfig) 119 | ->setFieldsetData($fieldsetData) 120 | ; 121 | 122 | if (!isset($fieldData['value'])) { 123 | $fieldData['value'] = null; 124 | } 125 | 126 | $path = $section . '/' . $group . '/' . $field; 127 | 128 | /** 129 | * Look for custom defined field path 130 | */ 131 | if (is_object($fieldConfig)) { 132 | $configPath = (string)$fieldConfig->config_path; 133 | if (!empty($configPath) && strrpos($configPath, '/') > 0) { 134 | if (!Mage::getSingleton('admin/session')->isAllowed($configPath)) { 135 | Mage::throwException('Access denied.'); 136 | } 137 | // Extend old data with specified section group 138 | $groupPath = substr($configPath, 0, strrpos($configPath, '/')); 139 | if (!isset($oldConfigAdditionalGroups[$groupPath])) { 140 | $oldConfig = $this->extendConfig($groupPath, true, $oldConfig); 141 | $oldConfigAdditionalGroups[$groupPath] = true; 142 | } 143 | $path = $configPath; 144 | } 145 | } 146 | 147 | $inherit = !empty($fieldData['inherit']); 148 | 149 | $dataObject->setPath($path) 150 | ->setValue($fieldData['value']); 151 | 152 | if (isset($oldConfig[$path])) { 153 | $dataObject->setConfigId($oldConfig[$path]['config_id']); 154 | 155 | /** 156 | * Delete config data if inherit 157 | */ 158 | if (!$inherit) { 159 | $saveTransaction->addObject($dataObject); 160 | } 161 | else { 162 | $deleteTransaction->addObject($dataObject); 163 | } 164 | } 165 | elseif (!$inherit) { 166 | $dataObject->unsConfigId(); 167 | $saveTransaction->addObject($dataObject); 168 | } 169 | } 170 | } 171 | 172 | $deleteTransaction->delete(); 173 | $saveTransaction->save(); 174 | 175 | return $this; 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /src/app/code/community/Hackathon/MageTrashApp/Model/CoreResource.php: -------------------------------------------------------------------------------- 1 | AddNotice('No CoreResource version found for:'. $moduleName); 16 | } else { 17 | Mage::register('isSecureArea', true); 18 | $resource = Mage::getResourceSingleton('magetrashapp/resource'); 19 | $resource->deleteDbVersion($resName, $number); 20 | Mage::unregister('isSecureArea'); 21 | 22 | if ($resource->getDbVersion($resName) == $resName) { 23 | Mage::getSingleton('adminhtml/session')->AddNotice('CoreResource Deleted for:'. $moduleName); 24 | } 25 | } 26 | } 27 | 28 | /** 29 | * Reset Core Resource to specified version 30 | * 31 | * @param $moduleName 32 | * @param $resName 33 | * @param $number 34 | */ 35 | public function rewindCoreResource ($moduleName, $resName, $number) 36 | { 37 | Mage::register('isSecureArea', true); 38 | $resource = Mage::getResourceSingleton('core/resource'); 39 | $resource->setDbVersion($resName, $number); 40 | Mage::unregister('isSecureArea'); 41 | 42 | if ($resource->getDbVersion($resName) == $number) { 43 | Mage::getSingleton('adminhtml/session')->AddNotice($moduleName . 44 | ' CoreResource version rewound to: ' .$number); 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /src/app/code/community/Hackathon/MageTrashApp/Model/Observer.php: -------------------------------------------------------------------------------- 1 | getNode('modules')->children()); 9 | 10 | $dispatchResult = new Varien_Object($modules); 11 | 12 | $modules = $dispatchResult->toArray(); 13 | 14 | foreach ($modules as $moduleName) { 15 | if ($moduleName==='Mage_Adminhtml' ||$moduleName==='Hackathon_MageTrashApp' 16 | || stripos($moduleName,'Mage_') !== false) { 17 | continue; 18 | } 19 | 20 | $configFlag = Mage::getStoreConfig('magetrashapp/manage_extns/' . $moduleName); 21 | 22 | 23 | switch ($configFlag) { 24 | case Hackathon_MageTrashApp_Helper_Data::ENABLE: 25 | Mage::helper('magetrashapp')->activateModule($moduleName); 26 | break; 27 | case Hackathon_MageTrashApp_Helper_Data::DISABLE: 28 | $this->disableModules[] = $moduleName; 29 | Mage::helper('magetrashapp')->activateModule($moduleName, false); 30 | 31 | break; 32 | case Hackathon_MageTrashApp_Helper_Data::UNINSTALL: 33 | Mage::helper('magetrashapp')->uninstallModule($moduleName); 34 | break; 35 | default: 36 | break; 37 | 38 | } 39 | 40 | $configFlag = Mage::getStoreConfig('magetrashapp/rewind_extns/' . $moduleName); 41 | 42 | if ($configFlag != 0) { 43 | $version = substr($configFlag, 2); 44 | $configFlag = $configFlag[0]; 45 | } elseif (is_null($configFlag)) { 46 | continue; 47 | } 48 | 49 | switch ($configFlag) { 50 | case Hackathon_MageTrashApp_Helper_Data::DELETE: 51 | Mage::helper('magetrashapp')->deleteCoreResource($moduleName); 52 | break; 53 | case Hackathon_MageTrashApp_Helper_Data::REWIND: 54 | Mage::helper('magetrashapp')->rewindCoreResource($moduleName, $version); 55 | break; 56 | default: 57 | break; 58 | 59 | } 60 | 61 | } 62 | 63 | 64 | } 65 | 66 | 67 | } -------------------------------------------------------------------------------- /src/app/code/community/Hackathon/MageTrashApp/Model/PearWrapper.php: -------------------------------------------------------------------------------- 1 | getConfig(); 56 | $this->getSingleConfig(); 57 | //$this->getFrontend(); 58 | } 59 | 60 | /** 61 | * Destructor, sends Console footer if Console started 62 | */ 63 | public function __destruct() 64 | { 65 | if ($this->_consoleStarted) { 66 | $this->_consoleFooter(); 67 | } 68 | } 69 | 70 | /** 71 | * Initialize instance 72 | * 73 | * @return Maged_Connect 74 | */ 75 | public static function getInstance() 76 | { 77 | if (!self::$_instance) { 78 | self::$_instance = new self; 79 | } 80 | return self::$_instance; 81 | } 82 | 83 | /** 84 | * Retrieve object of config and set it to Mage_Connect_Command 85 | * 86 | * @return Mage_Connect_Config 87 | */ 88 | public function getConfig() 89 | { 90 | if (!$this->_config) { 91 | $this->_config = new Mage_Connect_Config(); 92 | $ftp=$this->_config->__get('remote_config'); 93 | if(!empty($ftp)){ 94 | $packager = new Mage_Connect_Packager(); 95 | list($cache, $config, $ftpObj) = $packager->getRemoteConf($ftp); 96 | $this->_config=$config; 97 | $this->_sconfig=$cache; 98 | } 99 | $this->_config->magento_root = dirname(dirname(__FILE__)).DS.'..'; 100 | //Mage_Connect_Command::setConfigObject($this->_config); 101 | } 102 | return $this->_config; 103 | } 104 | 105 | /** 106 | * Retrieve object of single config and set it to Mage_Connect_Command 107 | * 108 | * @param bool $reload 109 | * @return Mage_Connect_Singleconfig 110 | */ 111 | public function getSingleConfig($reload = false) 112 | { 113 | if(!$this->_sconfig || $reload) { 114 | $this->_sconfig = new Mage_Connect_Singleconfig( 115 | 116 | Mage::getModuleDir('etc','Hackathon_MageTrashApp').DIRECTORY_SEPARATOR 117 | . self::DEFAULT_SCONFIG_FILENAME 118 | ); 119 | } 120 | Mage_Connect_Command::setSconfig($this->_sconfig); 121 | return $this->_sconfig; 122 | 123 | } 124 | 125 | /** 126 | * Retrieve object of frontend and set it to Mage_Connect_Command 127 | * 128 | * @return Maged_Connect_Frontend 129 | */ 130 | public function getFrontend() 131 | { 132 | if (!$this->_frontend) { 133 | $this->_frontend = new Maged_Connect_Frontend(); 134 | Mage_Connect_Command::setFrontendObject($this->_frontend); 135 | } 136 | return $this->_frontend; 137 | } 138 | 139 | /** 140 | * Retrieve lof from frontend 141 | * 142 | * @return array 143 | */ 144 | public function getLog() 145 | { 146 | return $this->getFrontend()->getLog(); 147 | } 148 | 149 | /** 150 | * Retrieve output from frontend 151 | * 152 | * @return array 153 | */ 154 | public function getOutput() 155 | { 156 | return $this->getFrontend()->getOutput(); 157 | } 158 | 159 | /** 160 | * Clean registry 161 | * 162 | * @return Maged_Connect 163 | */ 164 | public function cleanSconfig() 165 | { 166 | $this->getSingleConfig()->clear(); 167 | return $this; 168 | } 169 | 170 | /** 171 | * Delete directory recursively 172 | * 173 | * @param string $path 174 | * @return Maged_Connect 175 | */ 176 | public function delTree($path) { 177 | if (@is_dir($path)) { 178 | $entries = @scandir($path); 179 | foreach ($entries as $entry) { 180 | if ($entry != '.' && $entry != '..') { 181 | $this->delTree($path.DS.$entry); 182 | } 183 | } 184 | @rmdir($path); 185 | } else { 186 | @unlink($path); 187 | } 188 | return $this; 189 | } 190 | 191 | /** 192 | * Run commands from Mage_Connect_Command 193 | * 194 | * @param string $command 195 | * @param array $options 196 | * @param array $params 197 | * @return boolean|Mage_Connect_Error 198 | */ 199 | public function run($command, $options=array(), $params=array()) 200 | { 201 | @set_time_limit(0); 202 | @ini_set('memory_limit', '256M'); 203 | 204 | if (empty($this->_cmdCache[$command])) { 205 | Mage_Connect_Command::getCommands(); 206 | /** 207 | * @var $cmd Mage_Connect_Command 208 | */ 209 | $cmd = Mage_Connect_Command::getInstance($command); 210 | if ($cmd instanceof Mage_Connect_Error) { 211 | return $cmd; 212 | } 213 | $this->_cmdCache[$command] = $cmd; 214 | } else { 215 | /** 216 | * @var $cmd Mage_Connect_Command 217 | */ 218 | $cmd = $this->_cmdCache[$command]; 219 | } 220 | $ftp=$this->getConfig()->remote_config; 221 | if(strlen($ftp)>0){ 222 | $options=array_merge($options, array('ftp'=>$ftp)); 223 | } 224 | $cmd->run($command, $options, $params); 225 | if ($cmd->ui()->hasErrors()) { 226 | return false; 227 | } else { 228 | return true; 229 | } 230 | } 231 | 232 | /** 233 | * Set remote Config by URI 234 | * 235 | * @param $uri 236 | * @return Maged_Connect 237 | */ 238 | public function setRemoteConfig($uri) 239 | { 240 | $this->getConfig()->remote_config=$uri; 241 | return $this; 242 | } 243 | 244 | 245 | } 246 | -------------------------------------------------------------------------------- /src/app/code/community/Hackathon/MageTrashApp/Model/Resource/Resource.php: -------------------------------------------------------------------------------- 1 | $resName, 16 | 'version' => $version, 17 | ); 18 | 19 | if ($this->getDbVersion($resName)) { 20 | self::$_versions[$resName] = $resName; 21 | return $this->_getWriteAdapter()->delete($this->getMainTable(), 22 | array('code = ?' => $resName)); 23 | } else { 24 | self::$_versions[$resName] = $version; 25 | return $this->_getWriteAdapter()->insert($this->getMainTable(), $dbModuleInfo); 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /src/app/code/community/Hackathon/MageTrashApp/Model/Resource/Setup.php: -------------------------------------------------------------------------------- 1 | addNotice('Invoking uninstall file for resource'.$resourceName); 9 | 10 | $connection = Mage::getSingleton('core/resource')->getConnection($resourceName); 11 | 12 | $connection->disallowDdlCache(); 13 | 14 | try { 15 | // run sql uninstall php 16 | $result = include $fileName; 17 | // remove core_resource 18 | if ($result) { 19 | Mage::getSingleton('adminhtml/session')-> 20 | addNotice('Removing core resource '.$resourceName); 21 | $this->deleteTableRow('core/resource', 'code', $resourceName); 22 | } 23 | 24 | } catch (Exception $e) { 25 | $result = false; 26 | Mage::log($e); 27 | Mage::getSingleton('adminhtml/session')-> 28 | addWarning('Running uninstall failed for resource '.$resourceName); 29 | } 30 | 31 | $connection->allowDdlCache(); 32 | 33 | return $result; 34 | 35 | } 36 | 37 | } -------------------------------------------------------------------------------- /src/app/code/community/Hackathon/MageTrashApp/Model/Uninstall.php: -------------------------------------------------------------------------------- 1 | AddNotice('Running SQL Unininstall for Module:'.$moduleName); 14 | 15 | $result = false; 16 | 17 | $resources = Mage::getConfig()->getNode('global/resources')->children(); 18 | foreach ($resources as $resName => $resource) { 19 | if (!$resource->setup) { 20 | continue; 21 | } 22 | 23 | if (isset($resource->setup->module)) { 24 | $testModName = (string)$resource->setup->module; 25 | if ($testModName==$moduleName) { 26 | $resourceName = $resName; 27 | } 28 | } 29 | } 30 | 31 | if (empty($resourceName)) { 32 | return $result; 33 | } 34 | 35 | $fileName = $this->_getUninstallSQLFile($moduleName,$resourceName); 36 | 37 | if (!is_null($fileName) ) { 38 | 39 | $resource = new Hackathon_MageTrashApp_Model_Resource_Setup($resourceName); 40 | $result = $resource->runUninstallSql($fileName,$resourceName); 41 | 42 | } else { 43 | Mage::getSingleton('adminhtml/session')->addNotice('Unable to find uninstall script for:'. $moduleName); 44 | } 45 | 46 | return $result; 47 | 48 | } 49 | 50 | /** 51 | * Gets the Uninstall file contents if present 52 | * 53 | * Lifted and modified from Mage_Core_Resource_Setup::_getAvailableDbFiles() 54 | * 55 | * @return bool 56 | */ 57 | protected function _getUninstallSQLFile($moduleName,$resourceName) { 58 | 59 | 60 | $filesDir = Mage::getModuleDir('sql', $moduleName) . DS . $resourceName; 61 | if (!is_dir($filesDir) || !is_readable($filesDir)) { 62 | return null; 63 | } 64 | 65 | $uninstallFile = null; 66 | $regExpDb = sprintf('#^.*%s\.(php|sql)$#i', 'uninstall'); 67 | $handlerDir = dir($filesDir); 68 | while (false !== ($file = $handlerDir->read())) { 69 | $matches = array(); 70 | if (preg_match($regExpDb, $file, $matches)) { 71 | $uninstallFile = $filesDir . DS . $file; 72 | break; 73 | } 74 | } 75 | $handlerDir->close(); 76 | 77 | return $uninstallFile; 78 | } 79 | 80 | 81 | /** 82 | * Options for uninstall are: 83 | * 1. Pear 84 | * 2. Using uninstall.sql and file as specified in config.xml 85 | * Format of the file must be modman??? 86 | * @param $moduleName 87 | */ 88 | public function processUninstallPackage($moduleName) 89 | { 90 | // if (!$this->processPearUninstall($moduleName)) { 91 | $this->processFileBasedUninstall($moduleName); 92 | // } 93 | } 94 | 95 | /** 96 | * Attempts to uninstall Pear 97 | * 98 | * @param $moduleName 99 | */ 100 | protected function processPearUninstall($moduleName) { 101 | Mage::log("facebook foo"); 102 | $command = 'uninstall'; 103 | $params[] = 'community'; 104 | $params[] = $moduleName; 105 | Mage_Connect_Command_Install::registerCommands(); // needed for init 106 | $pear = new Mage_Connect_Command_Install(); 107 | 108 | // we need a config obj 109 | 110 | /* @var $config Hackathon_MageTrashApp_Model_PearWrapper */ 111 | $config = Mage::getModel('magetrashapp/pearWrapper'); 112 | $bla = $config->getConfig(); 113 | 114 | /*$config = new Mage_Connect_Config(); 115 | $ftp=$config->__get('remote_config'); 116 | if(!empty($ftp)){ 117 | $packager = new Mage_Connect_Packager(); 118 | list($cache, $config, $ftpObj) = $packager->getRemoteConf($ftp); 119 | $config; 120 | } 121 | $config->magento_root = dirname(dirname(__FILE__)).DS.'..';DS.'..'; 122 | */ 123 | 124 | $pear->setConfigObject($bla); 125 | 126 | $result = $pear->doUninstall($command,array(),$params); 127 | 128 | $bla = 'dfdf'; 129 | 130 | } 131 | 132 | /** 133 | * Attempts to uninstall Pear 134 | * 135 | * @param $moduleName 136 | */ 137 | protected function processFileBasedUninstall($moduleName) 138 | { 139 | $magentoRoot = dirname(Mage::getRoot()); 140 | 141 | $config = Mage::app()->getConfig(); 142 | $configModule = $config->getModuleConfig($moduleName); 143 | 144 | /* @var $configFile Mage_Core_Model_Config_Base */ 145 | $configFile = Mage::getModel('core/config_base'); 146 | 147 | /* @var $helper Hackathon_MageTrashApp_Helper_Data */ 148 | $helper = Mage::helper('magetrashapp'); 149 | 150 | // if ($configModule->is('active', true)) { 151 | // Mage::throwException( $helper->__('The module %s must be disabled before to uninstall.', $moduleName)); 152 | // return; 153 | // } 154 | 155 | $etc = $config->getModuleDir('etc', $moduleName) . DS . 'config.xml'; 156 | $configFile->loadFile($etc); 157 | 158 | $element = $configFile->getNode('uninstall'); 159 | 160 | if (!empty($element) && !$element->filename) { 161 | $filename = $element->filename; 162 | } else { 163 | $filename = 'uninstall.txt'; 164 | } 165 | 166 | $uninstallFile = $config->getModuleDir('etc', $moduleName) . DS . $filename; 167 | 168 | if (file_exists($uninstallFile)) { 169 | $handle = fopen($uninstallFile, 'r'); 170 | while ($line = fgets($handle)) { 171 | $line = preg_replace('/\s+/', '%%%', $line); 172 | $lines = explode('%%%', $line); 173 | 174 | if (count($lines) > 2) { // modman file format, we take the second argument because it should be the path of the target installation 175 | $pathsToDelete[] = $magentoRoot . DS . trim($lines[1], '/'); 176 | } else { 177 | $pathsToDelete[] = $magentoRoot . DS . trim($lines[0], '/'); 178 | } 179 | } 180 | if (!feof($handle)) { 181 | $helper->__('A problem occured while trying to get access to the uninstall file.'); 182 | } 183 | fclose($handle); 184 | 185 | foreach ($pathsToDelete as $dest) { 186 | if(file_exists($dest) && (is_file($dest) || is_link($dest))) { 187 | unlink($dest); 188 | } else if (file_exists($dest)) { 189 | $helper->rrmdir($dest); 190 | } 191 | } 192 | return true; 193 | } 194 | return false; 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /src/app/code/community/Hackathon/MageTrashApp/Test/Config/Config.php: -------------------------------------------------------------------------------- 1 | assertModelAlias('magetrashapp/observer','Hackathon_MageTrashApp_Model_Observer'); 6 | } 7 | 8 | } -------------------------------------------------------------------------------- /src/app/code/community/Hackathon/MageTrashApp/Test/Helper/DataTest.php: -------------------------------------------------------------------------------- 1 | Hackthon_MageTrashApp_Helper_Data = new Hackthon_MageTrashApp_Helper_Data(/* parameters */); 25 | } 26 | 27 | /** 28 | * Cleans up the environment after running a test. 29 | */ 30 | protected function tearDown() 31 | { 32 | // TODO Auto-generated DataTest::tearDown() 33 | $this->Hackthon_MageTrashApp_Helper_Data = null; 34 | parent::tearDown (); 35 | } 36 | 37 | /** 38 | * Constructs the test case. 39 | */ 40 | public function __construct() 41 | { 42 | // TODO Auto-generated constructor 43 | } 44 | 45 | /** 46 | * Tests whether extension uses the old-style admin routing (not compatible with SUPEE-6788). 47 | * 48 | * @test 49 | */ 50 | public function testGetOldAdminRouting() 51 | { 52 | $routers = Mage::getConfig()->getNode('admin/routers'); 53 | $offendingExtensions = array(); 54 | foreach ($routers[0] as $router) { 55 | $name = $router->args->module; 56 | if ($name != 'Mage_Adminhtml') { 57 | $offendingExtensions[] = $router->args->module; 58 | } 59 | } 60 | $this->assertEquals( 61 | count($offendingExtensions), 62 | 0, 63 | 'This extension uses old-style admin routing which is not compatible with SUPEE-6788 / Magento 1.9.2.2+' 64 | ); 65 | } 66 | } -------------------------------------------------------------------------------- /src/app/code/community/Hackathon/MageTrashApp/Test/Model/Observer.php: -------------------------------------------------------------------------------- 1 | model = Mage::getModel('magetrashapp/observer'); 10 | } 11 | 12 | } -------------------------------------------------------------------------------- /src/app/code/community/Hackathon/MageTrashApp/controllers/Adminhtml/indexController.php: -------------------------------------------------------------------------------- 1 | getRequest()->getParam('module_name'); 8 | 9 | try { 10 | Mage::helper()->uninstallModule($moduleName); 11 | } catch (Exception $e) { 12 | 13 | } 14 | } 15 | 16 | 17 | public function activateModule () 18 | { 19 | 20 | } 21 | 22 | public function deactivateModule () 23 | { 24 | 25 | } 26 | } -------------------------------------------------------------------------------- /src/app/code/community/Hackathon/MageTrashApp/etc/adminhtml.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | Mage Trash App 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/app/code/community/Hackathon/MageTrashApp/etc/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 1.0.1 13 | 14 | 15 | 16 | 17 | 18 | Hackathon_MageTrashApp_Block 19 | 20 | 21 | Hackathon_MageTrashApp_Block_Adminhtml 22 | 23 | 24 | 25 | 26 | Hackathon_MageTrashApp_Helper 27 | 28 | 29 | 30 | 31 | Hackathon_MageTrashApp_Model 32 | magetrashapp_resource 33 | 34 | 35 | Hackathon_MageTrashApp_Model_Resource 36 | 37 | 38 | 39 | Hackathon_MageTrashApp_Model_Adminhtml_Config_Data 40 | 41 | 42 | 43 | 44 | 45 | 46 | Hackathon_MageTrashApp 47 | 48 | 49 | core_setup 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | Hackathon_MageTrashApp_Model_Observer 58 | saveConfig 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | Hackathon_MageTrashApp 70 | 71 | 72 | 73 | 74 | 75 | 76 | uninstall.txt 77 | 78 | 79 | -------------------------------------------------------------------------------- /src/app/code/community/Hackathon/MageTrashApp/etc/doc.uninstall.txt: -------------------------------------------------------------------------------- 1 | Place a file uninstall.txt into the folder etc/ of your module to allow to be triggered by this module when you deinstall it. 2 | If you wish to change the name of this uninstall.txt file to something different, just set into the config.xml file of your module, the following: 3 | 4 | ... 5 | 6 | myuninstallfile.txt 7 | 8 | 9 | 10 | The format of the content should start from the Magento Root path. For example: you want to deinstall the module Namepspace_Mymodule placed into the community code pool 11 | Just do: 12 | app/code/community/Namespace/Mymodule 13 | app/etc/modules/Namespace_Mymodule.xml 14 | js/mynamespace/ 15 | skin/frontend/base/default/images/mynapespace 16 | 17 | If you have modman, you could copy the file of modman into the etc folder. In this case, the second part of each line will be taken to uninstall your module. 18 | For example: 19 | src/app/code/community/Namespace/Mymodule app/code/community/Namespace/Mymodule 20 | src/app/etc/modules/Namespace_Mymodule.xml app/etc/modules/Namespace_Mymodule.xml -------------------------------------------------------------------------------- /src/app/code/community/Hackathon/MageTrashApp/etc/system.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | advanced 8 | text 9 | 999 10 | 1 11 | 1 12 | 1 13 | 14 | 15 | 16 | text 17 | magetrashapp_adminhtml/system_config_form_fieldset_modules_mageTrashApp 18 | 20 19 | 1 20 | 1 21 | 1 22 | 23 | 24 | 25 | text 26 | magetrashapp_adminhtml/system_config_form_fieldset_modules_rewind 27 | 30 28 | 1 29 | 1 30 | 1 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /src/app/etc/modules/Hackathon_MageTrashApp.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | true 6 | community 7 | 8 | 9 | -------------------------------------------------------------------------------- /tests/app/code/community/Hackathon/MageTrashAppTest/Test/Model/Observer.php: -------------------------------------------------------------------------------- 1 | observerModel = Mage::getModel('magetrashapp/observer'); 11 | 12 | $sessionMock = $this->getModelMockBuilder('adminhtml/session') 13 | ->disableOriginalConstructor() // This one removes session_start and other methods usage 14 | ->setMethods(null) // Enables original methods usage, because by default it overrides all methods 15 | ->getMock(); 16 | $this->replaceByMock('singleton', 'adminhtml/session', $sessionMock); 17 | } 18 | 19 | /** 20 | * Test Observer 21 | * @loadFixture config 22 | */ 23 | public function testObserver() { 24 | $resource = Mage::getResourceSingleton('core/resource'); 25 | $number = $resource->getDbVersion('smtppro_setup'); 26 | 27 | Mage::log($number); 28 | 29 | //$result = EcomDev_Utils_Reflection::invokeRestrictedMethod( //TODO: fix so doesn't blow up DB! 30 | // $this->observerModel, 'saveConfig', array('')); 31 | } 32 | } -------------------------------------------------------------------------------- /tests/app/code/community/Hackathon/MageTrashAppTest/Test/Model/_data/fx-config.yaml: -------------------------------------------------------------------------------- 1 | config: 2 | default/carriers/tracker1/preurl: royal_mail -------------------------------------------------------------------------------- /tests/app/code/community/Hackathon/MageTrashAppTest/etc/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /tests/app/etc/modules/Hackathon_MageTrashAppTest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | true 6 | community 7 | 8 | 9 | --------------------------------------------------------------------------------