├── .gitignore ├── LICENSE ├── composer.json ├── modman ├── readme.md ├── samples └── components │ ├── attribute-sets.yaml │ ├── attributes.yaml │ ├── categories.yaml │ ├── config.yaml │ ├── customer-groups.yaml │ ├── html │ └── footer_block_1.html │ ├── media.yaml │ ├── pages.yaml │ ├── products.yaml │ ├── related-products.yaml │ ├── sql.yaml │ ├── sql │ └── sitemap.sql │ ├── static-blocks.yaml │ ├── tax.yaml │ ├── users.yaml │ └── websites.yaml └── src ├── app ├── code │ └── community │ │ └── Cti │ │ └── Configurator │ │ ├── Helper │ │ ├── Components │ │ │ ├── Abstract.php │ │ │ ├── AttributeSets.php │ │ │ ├── Attributes.php │ │ │ ├── Categories.php │ │ │ ├── Config.php │ │ │ ├── CustomerGroups.php │ │ │ ├── Media.php │ │ │ ├── Pages.php │ │ │ ├── Products.php │ │ │ ├── RelatedProducts.php │ │ │ ├── Sql.php │ │ │ ├── StaticBlocks.php │ │ │ ├── Tax.php │ │ │ ├── Users.php │ │ │ └── Website.php │ │ └── Data.php │ │ └── etc │ │ └── config.xml └── etc │ └── modules │ └── Cti_Configurator.xml └── shell └── configurator.php /.gitignore: -------------------------------------------------------------------------------- 1 | .settings 2 | .buildpath 3 | .project 4 | .idea 5 | .DS_Store -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 CTI Digital 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ctidigital/magento-configurator", 3 | "description": "Magento Configurator", 4 | "type": "magento-module", 5 | "license": "MIT", 6 | "authors": [ 7 | { 8 | "name": "CTI Digital", 9 | "email": "sales@ctidigital.com" 10 | } 11 | ], 12 | "require": {} 13 | } 14 | -------------------------------------------------------------------------------- /modman: -------------------------------------------------------------------------------- 1 | ## CTI Digital Magento Configurator 2 | 3 | src/app/code/community/Cti/Configurator app/code/community/Cti/Configurator 4 | src/app/etc/modules/Cti_Configurator.xml app/etc/modules/Cti_Configurator.xml 5 | src/shell/configurator.php shell/configurator.php -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Magento Configurator 2 | 3 | A Magento module initially created by [CTI Digital] to create and maintain database variables using files. This module aims to bring the following benefits to a Magento developer's work flow: 4 | 5 | - Install Magento from scratch with important database based configuration ready. 6 | - Share and collaborate configuration with other colleagues using your own versioning system. 7 | - Keep versions of your configurations using your own versioning system. 8 | - Split your configuration based on the environment you're developing on. 9 | 10 | If you're interested about finding out more about the background of the configurator, watch this lightning talk by [Rick Steckles] at Mage Titans in Manchester on [YouTube]. 11 | 12 | ### Version 13 | 0.15.0 14 | 15 | ## Installation 16 | 17 | ### Using Modman 18 | ```sh 19 | $ cd 20 | $ modman clone https://github.com/ctidigital/magento-configurator.git 21 | ``` 22 | ### Traditionally 23 | 24 | Download and copy the contents of the `src/` folder into your Magento base directory. 25 | 26 | ## How To Use 27 | Firstly, we'll need to configure our components. You can find how to configure your component under the heading "Components". 28 | 29 | In your magento directory you can run the configurator using: 30 | ```sh 31 | $ cd /shell 32 | $ php configurator.php 33 | ``` 34 | 35 | ### List Available Components 36 | ```sh 37 | $ php configurator.php --list-components 38 | ``` 39 | 40 | ### Run Specific Components 41 | ```sh 42 | $ php configurator.php --run-components "media,pages,staticBlocks" 43 | ``` 44 | 45 | ## Components 46 | 47 | ### Websites & Stores 48 | This is generally the first component that should be configured when starting a project. This is used to create and maintain your websites, stores and store views and is controlled using a YAML which will require to be located in `app/etc/components/websites.yaml`. The general structure follows: 49 | ``` 50 | - websites: 51 | - website_code_1: 52 | name: Website Name 53 | - store_groups: 54 | - 55 | name: Store Group Name 56 | root_category: Default Category 57 | stores: 58 | - store_code_1: 59 | name: Default Store View Name 60 | - store_code_2: 61 | name: Store View Name 2 62 | - 63 | name: Store Group Name 2 64 | root_category: New Root Category 65 | stores: 66 | - store_code_3: 67 | name: Store View Name 3 68 | - website_code_2: 69 | name: Website Name 2 70 | - store_groups: 71 | - 72 | name: Store Group Name 3 73 | root_category: Default Category 74 | stores: 75 | - store_code_4: 76 | name: Store View Name 4 77 | ``` 78 | 79 | The YAML follows a tree structure which supports the following rules: 80 | - Many websites can be created 81 | - A website can have many store groups 82 | - A store group branch can have many store views 83 | 84 | Sort orders will automatically be created based on the order the YAML is written. 85 | 86 | ### Core Config Data 87 | 88 | After your websites have been correctly set up this is required to set up the core configuration elements for default (global), website level, and store view level. The end nodes require a `path` and a `value` which will be set in your Magento's `core_config_data`. If you don't know what the path should be, you can find it out by looking at the module's system.xml file or save a page with the configuration from within Magento's admin followed by saving the relevant section in System->Configuration and looking it up within your database's `core_config_data` table. The file will require to be in 89 | `app/etc/components/config.yaml`. You can also find our `config.yaml` file as an example on how to structure the file. 90 | 91 | #### Default 92 | ``` 93 | - global: 94 | core_config: 95 | - 96 | path: design/package/name 97 | value: base 98 | - 99 | path: design/theme/default 100 | value: default 101 | ``` 102 | 103 | #### Inheritables 104 | Sometimes we need to group configurations for use in many but not all websites or store views so in order to keep our YAML structure neat and tidy there is also support for grouped configurations. For example, some websites might share the same PayPal payment configuration. 105 | 106 | ``` 107 | - grouped: 108 | - paypal: 109 | core_config: 110 | - 111 | path: payment/pbridge/profilestatus 112 | value: 0 113 | - 114 | path: payment/paypal_express/active 115 | value: 1 116 | - 117 | path: payment/paypal_express_bml/active 118 | value: 0 119 | ``` 120 | 121 | #### Websites 122 | Should we require website specific configurations this can be defined as so: 123 | ``` 124 | - websites: 125 | - base: 126 | core_config: 127 | - 128 | path: general/locale/timezone 129 | value: Europe/London 130 | ``` 131 | We can also inherit our group configurations using the inherit key as so: 132 | ``` 133 | - websites: 134 | - base: 135 | inherit: 136 | - paypal 137 | core_config: 138 | - 139 | path: general/locale/timezone 140 | value: Europe/London 141 | ``` 142 | #### Stores 143 | Similarly to websites, we can define store view level configuration which also has inheritance support as so: 144 | ``` 145 | - stores: 146 | - default: 147 | core_config: 148 | - 149 | path: general/locale/code 150 | value: en_GB 151 | ``` 152 | #### Encrypted Values 153 | Some core magento fields also encrypts our configuration so we can define this as so: 154 | ``` 155 | - 156 | path: paypal/wpp/api_password 157 | value: 111111111 158 | encrypted: 1 159 | ``` 160 | ### Product Attributes 161 | The file that is used to maintain product attributes can be found in `app/etc/components/attributes.yaml`. This allows you to modify your custom attributes as well as maintain the attribute options using this file. 162 | 163 | Here is a basic required structure for an attribute 164 | ``` 165 | - attributes: 166 | - attribute_code: 167 | frontend_label: Attribute Code 168 | frontend_input: select 169 | product_types: 170 | - simple 171 | - configurable 172 | - bundle 173 | - grouped 174 | ``` 175 | Here is the basic structure of a typical attribute with its default values: 176 | ``` 177 | - attributes: 178 | - attribute_code: 179 | is_global: 0 180 | is_visible: 1 181 | is_searchable: 0 182 | is_filterable: 0 183 | is_comparable: 0 184 | is_visible_on_front: 0 185 | is_html_allowed_on_front: 0 186 | is_filterable_in_search: 0 187 | used_in_product_listing: 0 188 | used_for_sort_by: 0 189 | is_configurable: 0 190 | is_visible_in_advanced_search: 0 191 | position: 0 192 | is_wysiwyg_enabled: 0 193 | is_used_for_promo_rules: 0 194 | default_value_text: '' 195 | default_value_yesno: 0 196 | default_value_date: '' 197 | default_value_textarea: '' 198 | is_unique: 0 199 | is_required: 0 200 | frontend_input: boolean 201 | search_weight: 1 202 | ``` 203 | We can also specify product options for select type attributes as so: 204 | ``` 205 | - attributes: 206 | - colour: 207 | frontend_label: Colour 208 | frontend_input: select 209 | product_types: 210 | - simple 211 | options: 212 | - Red 213 | - Green 214 | - Yellow 215 | - Blue 216 | - Purple 217 | - Pink 218 | - Orange 219 | ``` 220 | 221 | We can also specify store labels for attributes as so: 222 | ``` 223 | - attributes: 224 | - attribute_code: 225 | frontend_label: Attribute Code 226 | frontend_input: select 227 | - store_labels: 228 | default: Default Store Label 229 | en: Label for store code en 230 | ``` 231 | 232 | Please note, certain attribute configurations follow certain rules so do ensure you're familiar with how Magento product attributes work in order to make best use of this component. An attribute's configuration elements are simply fields in the `catalog_eav_attribute` table with a few exceptions. 233 | 234 | ### Attribute Sets 235 | 236 | Having created out custom product attributes these will need to be included as part of an attribute set. For this we will require the file `app/etc/components/attribute-sets.yaml` and the contents of the file will follow as so: 237 | ``` 238 | - attribute_sets: 239 | - 240 | name: Example Attribute Set 241 | inherit: Attribute Set to Inherit (Default) 242 | groups: 243 | - 244 | name: Attribute Group Name (General) 245 | attributes: 246 | - attribute_code 247 | - attribute_code2 248 | ``` 249 | 250 | Using ```inherit: ``` will use an existing attribute set as a skeleton for your new attribute sets. By default, it will inherit attribute set named ```Default``` which must already exists in your Magento install. 251 | 252 | Please use our sample file as an example. 253 | ### Other Components 254 | 255 | There are many other components to help populate Magento which you can view from ```samples/components```. These can help you bootstrap your Magneto install with relevant sample/configuration data. 256 | 257 | #### Limitations 258 | - Cannot move attributes between attribute groups. 259 | - Cannot remove existing attributes from attribute sets. 260 | 261 | ## Development 262 | 263 | Want to contribute? Great! We've tried to structure the module to make it extendable so should you wish to contribute then it should be fairly easy. There are a few rules you have to follow though. 264 | 265 | ### Config.xml 266 | Firstly, within `app/code/community/Cti/Configurator/etc/config.xml` you will find the following xml: 267 | 268 | ``` 269 | ... 270 | 271 | 272 | 273 | cti_configurator/components_website 274 | cti_configurator/components_config 275 | 276 | 277 | 278 | ... 279 | ``` 280 | Here you can define any components you wish to contribute. Should you wish to extend to create your own component within your own module, you can do so by adding your own component helper alias within your own module's `config.xml`. 281 | 282 | ### Component Helper 283 | 284 | You'll need to create a helper class within the module, preferably in a Components subfolder and it should extend `Cti_Configurator_Helper_Components_Abstract` which will require you to: 285 | - Specify a unique component name for logging processes and event dispatches `$this->_componentName`. 286 | - Specify the file you wish to process by assigning an absolute path to the variable `$this->_filePath1`. 287 | - (optional) Specify `$this->_filePath2` as a way of splitting your configuration between environments. 288 | - Create a protected `_processFile()` function to parse your file(s) (and merge) into a format of your choice. 289 | - Create a protected `_processComponent()` function to process the data you've acquired from the file you've processed. 290 | 291 | The abstract function should handle the rest. You can look at our `Helper/Components/Website.php` and `Helper/Components/Config.php` as a guide to how you should structure your component helper. 292 | 293 | ## Roadmap 294 | 295 | - Create a component for Admin Users & Roles 296 | - Better CLI Logging 297 | - Write Tests 298 | 299 | License 300 | ---- 301 | 302 | MIT 303 | 304 | 305 | [CTI Digital]:http://www.ctidigital.com/ 306 | [YouTube]:https://www.youtube.com/watch?v=u9zHaX8G5_0 307 | [Rick Steckles]:https://twitter.com/rick_steckles -------------------------------------------------------------------------------- /samples/components/attribute-sets.yaml: -------------------------------------------------------------------------------- 1 | - attribute_sets: 2 | - 3 | name: Shirts 4 | inherit: Default 5 | groups: 6 | - 7 | name: General 8 | attributes: 9 | - colour 10 | - color 11 | - 12 | name: Prices 13 | attributes: 14 | - rrp 15 | - 16 | name: Example Attribute Set 2 17 | inherit: Default 18 | groups: 19 | - 20 | name: Prices 21 | attributes: 22 | - rrp -------------------------------------------------------------------------------- /samples/components/attributes.yaml: -------------------------------------------------------------------------------- 1 | - attributes: 2 | - colour: 3 | is_global: 1 4 | frontend_label: Colour 5 | frontend_input: select 6 | is_configurable: 1 7 | is_visible_on_front: 1 8 | is_filterable: 1 9 | is_searchable: 1 10 | is_visible_in_advanced_search: 0 11 | product_types: 12 | - simple 13 | options: 14 | - Red 15 | - Green 16 | - Yellow 17 | - Blue 18 | - Purple 19 | - Pink 20 | - Orange 21 | - Brown 22 | - rrp: 23 | frontend_label: Recommended Retail Price 24 | frontend_input: price 25 | used_in_product_listing: 1 26 | product_types: 27 | - bundle 28 | - simple -------------------------------------------------------------------------------- /samples/components/categories.yaml: -------------------------------------------------------------------------------- 1 | - categories: 2 | - 3 | name: 1st Level Category 4 | description: Category Description 5 | store_group: Main Website Store 6 | url_key: first-level-cat 7 | is_anchor: 1 8 | products: 9 | - t-shirt1 10 | - laptop 11 | categories: 12 | - 13 | name: 2nd Level Category 1 14 | description: 15 | url_key: second-level-cat-1 16 | products: 17 | - t-shirt1 18 | - 19 | name: 2nd Level Category 2 20 | description: 21 | url_key: second-level-cat-2 22 | is_anchor: 1 23 | products: 24 | - laptop -------------------------------------------------------------------------------- /samples/components/config.yaml: -------------------------------------------------------------------------------- 1 | - global: 2 | core_config: 3 | - 4 | path: design/package/name 5 | value: cti 6 | - 7 | path: design/theme/default 8 | value: theme 9 | - grouped: 10 | - paypal: 11 | core_config: 12 | - 13 | path: payment/pbridge/profilestatus 14 | value: 0 15 | - 16 | path: payment/paypal_express/active 17 | value: 0 18 | - 19 | path: payment/paypal_express_bml/active 20 | value: 0 21 | - 22 | path: paypal/wpp/sandbox_flag 23 | value: 1 24 | - 25 | path: paypal/general/business_account 26 | value: test@test 27 | - 28 | path: payment/paypal_standard/active 29 | value: 0 30 | - 31 | path: paypal/wpp/api_username 32 | value: test_api1.test.com 33 | encrypted: 1 34 | - 35 | path: paypal/wpp/api_password 36 | value: 111111111 37 | encrypted: 1 38 | - 39 | path: paypal/wpp/api_signature 40 | value: fjweofij3q0rjFASPOFDSOPFJDSPF0_dfFoijfFSFSD 41 | encrypted: 1 42 | - 43 | path: payment/paypal_express/payment_action 44 | value: Authorization 45 | - 46 | path: payment/paypal_express/visible_on_cart 47 | value: 0 48 | - 49 | path: payment/paypal_express/visible_on_product 50 | value: 0 51 | - websites: 52 | - base: 53 | inherit: 54 | - paypal 55 | core_config: 56 | - 57 | path: general/locale/timezone 58 | value: Europe/London 59 | - stores: 60 | - default: 61 | core_config: 62 | - 63 | path: general/locale/code 64 | value: en_GB -------------------------------------------------------------------------------- /samples/components/customer-groups.yaml: -------------------------------------------------------------------------------- 1 | - groups: 2 | - 3 | customer_group_code: NOT LOGGED IN 4 | tax_class: Retail Customer 5 | - 6 | customer_group_code: General 7 | tax_class: Retail Customer -------------------------------------------------------------------------------- /samples/components/html/footer_block_1.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /samples/components/media.yaml: -------------------------------------------------------------------------------- 1 | - media: 2 | - wysiwyg: 3 | - 4 | name: placeholder1.gif 5 | location: http://placehold.it/350x150 6 | - 7 | name: placeholder2.gif 8 | location: http://placehold.it/350x550 9 | - other_folder: 10 | - another_sub_folder: 11 | - 12 | name: placeholder1.gif 13 | location: http://placehold.it/350x150 14 | - 15 | name: placeholder2.gif 16 | location: http://placehold.it/350x550 -------------------------------------------------------------------------------- /samples/components/pages.yaml: -------------------------------------------------------------------------------- 1 | - pages: 2 | - home: 3 | title: Home page 4 | is_active: 1 5 | root_template: one_column 6 | under_version_control: 1 7 | contents: 8 | - all: 9 | content_heading: 10 | content_file: -------------------------------------------------------------------------------- /samples/components/products.yaml: -------------------------------------------------------------------------------- 1 | - products: 2 | - t-shirt1: 3 | name: That T-Shirt 4 | url_key: that_tshirt 5 | attribute_set: Shirts 6 | type_id: configurable 7 | weight: 1 8 | status: 1 9 | websites: 10 | - base 11 | - test 12 | - test1 13 | description: Standard T-Shirt 14 | short_description: Standard T-Shirt 15 | country_of_manufacture: in 16 | price: 10 17 | tax_class_id: 2 18 | qty: 100 19 | configurable_attributes: 20 | - colour 21 | simple_products: 22 | - red: 23 | label: Red 24 | attribute: colour 25 | value: Red 26 | is_percent: 0 27 | pricing_value: 0 28 | - green: 29 | label: Green 30 | attribute: colour 31 | value: Green 32 | is_percent: 0 33 | pricing_value: 0 34 | - yellow: 35 | label: Yellow 36 | attribute: colour 37 | value: Yellow 38 | is_percent: 0 39 | pricing_value: 0 40 | - blue: 41 | label: Blue 42 | attribute: colour 43 | value: Blue 44 | is_percent: 0 45 | pricing_value: 0 46 | - purple: 47 | label: Purple 48 | attribute: colour 49 | value: Purple 50 | is_percent: 0 51 | pricing_value: 0 52 | - pink: 53 | label: Pink 54 | attribute: colour 55 | value: Pink 56 | is_percent: 0 57 | pricing_value: 1 58 | - orange: 59 | label: Orange 60 | attribute: colour 61 | value: Orange 62 | is_percent: 0 63 | pricing_value: 0 64 | - brown: 65 | label: Brown 66 | attribute: colour 67 | value: Brown 68 | is_percent: 0 69 | pricing_value: 0 70 | - laptop: 71 | name: Laptop 72 | url_key: that_laptop 73 | attribute_set: Default 74 | type_id: simple 75 | weight: 1 76 | status: 1 77 | websites: 78 | - base 79 | - test 80 | - test1 81 | description: Standard Laptop 82 | short_description: Standard Laptop 83 | country_of_manufacture: cn 84 | price: 1000 85 | tax_class_id: 2 86 | qty: 10 -------------------------------------------------------------------------------- /samples/components/related-products.yaml: -------------------------------------------------------------------------------- 1 | - related: 2 | - t-shirt1: 3 | - laptop -------------------------------------------------------------------------------- /samples/components/sql.yaml: -------------------------------------------------------------------------------- 1 | sql: 2 | - /app/etc/components/sql/sitemap.sql -------------------------------------------------------------------------------- /samples/components/sql/sitemap.sql: -------------------------------------------------------------------------------- 1 | LOCK TABLES `sitemap` WRITE; 2 | TRUNCATE TABLE `sitemap`; 3 | INSERT INTO `sitemap` (`sitemap_id`, `sitemap_type`, `sitemap_filename`, `sitemap_path`, `sitemap_time`, `store_id`) 4 | VALUES 5 | (1, NULL, 'sitemap.xml', '/', '2015-08-21 15:13:24', 1); 6 | UNLOCK TABLES; -------------------------------------------------------------------------------- /samples/components/static-blocks.yaml: -------------------------------------------------------------------------------- 1 | - blocks: 2 | - footer_block_1: 3 | title: Footer Block 4 | is_active: 1 5 | contents: 6 | - all: 7 | content_file: footer_block_1.html -------------------------------------------------------------------------------- /samples/components/tax.yaml: -------------------------------------------------------------------------------- 1 | - customer_classes: 2 | - Retail Customer 3 | - product_classes: 4 | - Shipping 5 | - Taxable Goods 6 | - rates: 7 | - GB: 8 | tax_country_id: GB 9 | rate: 20 10 | - AL: 11 | tax_country_id: AL 12 | rate: 20 13 | - AD: 14 | tax_country_id: AD 15 | rate: 20 16 | - AT: 17 | tax_country_id: AT 18 | rate: 20 19 | - BY: 20 | tax_country_id: BY 21 | rate: 20 22 | - BE: 23 | tax_country_id: BE 24 | rate: 20 25 | - BA: 26 | tax_country_id: BA 27 | rate: 20 28 | - BG: 29 | tax_country_id: BG 30 | rate: 20 31 | - HR: 32 | tax_country_id: HR 33 | rate: 20 34 | - CY: 35 | tax_country_id: CY 36 | rate: 20 37 | - CZ: 38 | tax_country_id: CZ 39 | rate: 20 40 | - DK: 41 | tax_country_id: DK 42 | rate: 20 43 | - EE: 44 | tax_country_id: EE 45 | rate: 20 46 | - FO: 47 | tax_country_id: FO 48 | rate: 20 49 | - FI: 50 | tax_country_id: FI 51 | rate: 20 52 | - FR: 53 | tax_country_id: FR 54 | rate: 20 55 | - DE: 56 | tax_country_id: DE 57 | rate: 20 58 | - GI: 59 | tax_country_id: GI 60 | rate: 20 61 | - GR: 62 | tax_country_id: GR 63 | rate: 20 64 | - HU: 65 | tax_country_id: HU 66 | rate: 20 67 | - IS: 68 | tax_country_id: IS 69 | rate: 20 70 | - IE: 71 | tax_country_id: IE 72 | rate: 20 73 | - IT: 74 | tax_country_id: IT 75 | rate: 20 76 | - LV: 77 | tax_country_id: LV 78 | rate: 20 79 | - LB: 80 | tax_country_id: LB 81 | rate: 20 82 | - LI: 83 | tax_country_id: LI 84 | rate: 20 85 | - LT: 86 | tax_country_id: LT 87 | rate: 20 88 | - LU: 89 | tax_country_id: LU 90 | rate: 20 91 | - MT: 92 | tax_country_id: MT 93 | rate: 20 94 | - MD: 95 | tax_country_id: MD 96 | rate: 20 97 | - MC: 98 | tax_country_id: CD 99 | rate: 20 100 | - ME: 101 | tax_country_id: ME 102 | rate: 20 103 | - NL: 104 | tax_country_id: NL 105 | rate: 20 106 | - Norway: 107 | tax_country_id: Norway 108 | rate: 20 109 | - PL: 110 | tax_country_id: PL 111 | rate: 20 112 | - PT: 113 | tax_country_id: PT 114 | rate: 20 115 | - RO: 116 | tax_country_id: RO 117 | rate: 20 118 | - RS: 119 | tax_country_id: RS 120 | rate: 20 121 | - SK: 122 | tax_country_id: SK 123 | rate: 20 124 | - SI: 125 | tax_country_id: SI 126 | rate: 20 127 | - ES: 128 | tax_country_id: ES 129 | rate: 20 130 | - SJ: 131 | tax_country_id: SJ 132 | rate: 20 133 | - SE: 134 | tax_country_id: SE 135 | rate: 20 136 | - CH: 137 | tax_country_id: CH 138 | rate: 20 139 | - TR: 140 | tax_country_id: TR 141 | rate: 20 142 | - UA: 143 | tax_country_id: UA 144 | rate: 20 145 | - VA: 146 | tax_country_id: VA 147 | rate: 20 148 | - rules: 149 | - 150 | code: VAT 151 | customer_tax_class: 152 | - Retail Customer 153 | product_tax_class: 154 | - Shipping 155 | - Taxable Goods 156 | tax_rate: 157 | - GB 158 | - AL 159 | - AD 160 | - AT 161 | - BY 162 | - BE 163 | - BA 164 | - BG 165 | - HR 166 | - CY 167 | - CZ 168 | - DK 169 | - EE 170 | - FO 171 | - FI 172 | - FR 173 | - DE 174 | - GI 175 | - GR 176 | - HU 177 | - IS 178 | - IE 179 | - IT 180 | - LV 181 | - LB 182 | - LI 183 | - LT 184 | - LU 185 | - MT 186 | - MD 187 | - MC 188 | - ME 189 | - NL 190 | - Norway 191 | - PL 192 | - PT 193 | - RO 194 | - RS 195 | - SK 196 | - SI 197 | - ES 198 | - SJ 199 | - SE 200 | - CH 201 | - TR 202 | - UA 203 | - VA 204 | - priority: 0 -------------------------------------------------------------------------------- /samples/components/users.yaml: -------------------------------------------------------------------------------- 1 | - soap: 2 | - users: 3 | - soapstar: 4 | firstname: Soap 5 | lastname: Star 6 | email: soap@example.com 7 | api_key: s3cr3t4p1k3y 8 | is_active: 1 9 | role: soapgroup 10 | - roles: 11 | - soapgroup: 12 | parent_id: 0 13 | tree_level: 1 14 | sort_order: 0 15 | role_type: G 16 | rules: 17 | - 18 | resource_id: core 19 | role_type: G 20 | api_permission: allow 21 | - 22 | resource_id: core/store 23 | role_type: G 24 | api_permission: allow 25 | - 26 | resource_id: core/store/info 27 | role_type: G 28 | api_permission: allow 29 | - 30 | resource_id: core/store/list 31 | role_type: G 32 | api_permission: allow 33 | - 34 | resource_id: core/magento 35 | role_type: G 36 | api_permission: deny 37 | - 38 | resource_id: core/magento/info 39 | role_type: G 40 | api_permission: deny 41 | - 42 | resource_id: directory 43 | role_type: G 44 | api_permission: deny 45 | - 46 | resource_id: directory/country 47 | role_type: G 48 | api_permission: deny 49 | - 50 | resource_id: directory/region 51 | role_type: G 52 | api_permission: deny 53 | - 54 | resource_id: customer 55 | role_type: G 56 | api_permission: deny 57 | - 58 | resource_id: customer/create 59 | role_type: G 60 | api_permission: deny 61 | - 62 | resource_id: customer/update 63 | role_type: G 64 | api_permission: deny 65 | - 66 | resource_id: customer/delete 67 | role_type: G 68 | api_permission: deny 69 | - 70 | resource_id: customer/info 71 | role_type: G 72 | api_permission: deny 73 | - 74 | resource_id: customer/address 75 | role_type: G 76 | api_permission: deny 77 | - 78 | resource_id: customer/address/create 79 | role_type: G 80 | api_permission: deny 81 | - 82 | resource_id: customer/address/update 83 | role_type: G 84 | api_permission: deny 85 | - 86 | resource_id: customer/address/delete 87 | role_type: G 88 | api_permission: deny 89 | - 90 | resource_id: customer/address/info 91 | role_type: G 92 | api_permission: deny 93 | - 94 | resource_id: catalog 95 | role_type: G 96 | api_permission: allow 97 | - 98 | resource_id: catalog/category 99 | role_type: G 100 | api_permission: allow 101 | - 102 | resource_id: catalog/category/create 103 | role_type: G 104 | api_permission: allow 105 | - 106 | resource_id: catalog/category/update 107 | role_type: G 108 | api_permission: allow 109 | - 110 | resource_id: catalog/category/move 111 | role_type: G 112 | api_permission: allow 113 | - 114 | resource_id: catalog/category/delete 115 | role_type: G 116 | api_permission: allow 117 | - 118 | resource_id: catalog/category/tree 119 | role_type: G 120 | api_permission: allow 121 | - 122 | resource_id: catalog/category/info 123 | role_type: G 124 | api_permission: allow 125 | - 126 | resource_id: catalog/category/attributes 127 | role_type: G 128 | api_permission: allow 129 | - 130 | resource_id: catalog/category/product 131 | role_type: G 132 | api_permission: allow 133 | - 134 | resource_id: catalog/category/product/assign 135 | role_type: G 136 | api_permission: allow 137 | - 138 | resource_id: catalog/category/product/update 139 | role_type: G 140 | api_permission: allow 141 | - 142 | resource_id: catalog/category/product/remove 143 | role_type: G 144 | api_permission: allow 145 | - 146 | resource_id: catalog/product 147 | role_type: G 148 | api_permission: allow 149 | - 150 | resource_id: catalog/product/create 151 | role_type: G 152 | api_permission: allow 153 | - 154 | resource_id: catalog/product/update 155 | role_type: G 156 | api_permission: allow 157 | - 158 | resource_id: catalog/product/delete 159 | role_type: G 160 | api_permission: allow 161 | - 162 | resource_id: catalog/product/update_tier_price 163 | role_type: G 164 | api_permission: allow 165 | - 166 | resource_id: catalog/product/group_price 167 | role_type: G 168 | api_permission: allow 169 | - 170 | resource_id: catalog/product/group_price/update 171 | role_type: G 172 | api_permission: allow 173 | - 174 | resource_id: catalog/product/info 175 | role_type: G 176 | api_permission: allow 177 | - 178 | resource_id: catalog/product/listOfAdditionalAttributes 179 | role_type: G 180 | api_permission: deny 181 | - 182 | resource_id: catalog/product/attributes 183 | role_type: G 184 | api_permission: allow 185 | - 186 | resource_id: catalog/product/attribute 187 | role_type: G 188 | api_permission: allow 189 | - 190 | resource_id: catalog/product/attribute/read 191 | role_type: G 192 | api_permission: allow 193 | - 194 | resource_id: catalog/product/attribute/write 195 | role_type: G 196 | api_permission: allow 197 | - 198 | resource_id: catalog/product/attribute/types 199 | role_type: G 200 | api_permission: allow 201 | - 202 | resource_id: catalog/product/attribute/create 203 | role_type: G 204 | api_permission: deny 205 | - 206 | resource_id: catalog/product/attribute/update 207 | role_type: G 208 | api_permission: deny 209 | - 210 | resource_id: catalog/product/attribute/remove 211 | role_type: G 212 | api_permission: deny 213 | - 214 | resource_id: catalog/product/attribute/info 215 | role_type: G 216 | api_permission: allow 217 | - 218 | resource_id: catalog/product/attribute/option 219 | role_type: G 220 | api_permission: allow 221 | - 222 | resource_id: catalog/product/attribute/option/add 223 | role_type: G 224 | api_permission: allow 225 | - 226 | resource_id: catalog/product/attribute/option/remove 227 | role_type: G 228 | api_permission: allow 229 | - 230 | resource_id: catalog/product/attribute/set 231 | role_type: G 232 | api_permission: allow 233 | - 234 | resource_id: catalog/product/attribute/set/list 235 | role_type: G 236 | api_permission: allow 237 | - 238 | resource_id: catalog/product/attribute/set/create 239 | role_type: G 240 | api_permission: deny 241 | - 242 | resource_id: catalog/product/attribute/set/remove 243 | role_type: G 244 | api_permission: deny 245 | - 246 | resource_id: catalog/product/attribute/set/attribute_add 247 | role_type: G 248 | api_permission: deny 249 | - 250 | resource_id: catalog/product/attribute/set/attribute_remove 251 | role_type: G 252 | api_permission: deny 253 | - 254 | resource_id: catalog/product/attribute/set/group_add 255 | role_type: G 256 | api_permission: deny 257 | - 258 | resource_id: catalog/product/attribute/set/group_rename 259 | role_type: G 260 | api_permission: deny 261 | - 262 | resource_id: catalog/product/attribute/set/group_remove 263 | role_type: G 264 | api_permission: deny 265 | - 266 | resource_id: catalog/product/link 267 | role_type: G 268 | api_permission: allow 269 | - 270 | resource_id: catalog/product/link/assign 271 | role_type: G 272 | api_permission: allow 273 | - 274 | resource_id: catalog/product/link/update 275 | role_type: G 276 | api_permission: allow 277 | - 278 | resource_id: catalog/product/link/remove 279 | role_type: G 280 | api_permission: allow 281 | - 282 | resource_id: catalog/product/media 283 | role_type: G 284 | api_permission: allow 285 | - 286 | resource_id: catalog/product/media/create 287 | role_type: G 288 | api_permission: allow 289 | - 290 | resource_id: catalog/product/media/update 291 | role_type: G 292 | api_permission: allow 293 | - 294 | resource_id: catalog/product/media/remove 295 | role_type: G 296 | api_permission: allow 297 | - 298 | resource_id: catalog/product/option 299 | role_type: G 300 | api_permission: allow 301 | - 302 | resource_id: catalog/product/option/add 303 | role_type: G 304 | api_permission: allow 305 | - 306 | resource_id: catalog/product/option/update 307 | role_type: G 308 | api_permission: allow 309 | - 310 | resource_id: catalog/product/option/types 311 | role_type: G 312 | api_permission: allow 313 | - 314 | resource_id: catalog/product/option/info 315 | role_type: G 316 | api_permission: allow 317 | - 318 | resource_id: catalog/product/option/list 319 | role_type: G 320 | api_permission: allow 321 | - 322 | resource_id: catalog/product/option/remove 323 | role_type: G 324 | api_permission: allow 325 | - 326 | resource_id: catalog/product/option/value 327 | role_type: G 328 | api_permission: allow 329 | - 330 | resource_id: catalog/product/option/value/list 331 | role_type: G 332 | api_permission: allow 333 | - 334 | resource_id: catalog/product/option/value/info 335 | role_type: G 336 | api_permission: allow 337 | - 338 | resource_id: catalog/product/option/value/add 339 | role_type: G 340 | api_permission: allow 341 | - 342 | resource_id: catalog/product/option/value/update 343 | role_type: G 344 | api_permission: allow 345 | - 346 | resource_id: catalog/product/option/value/remove 347 | role_type: G 348 | api_permission: allow 349 | - 350 | resource_id: catalog/product/tag 351 | role_type: G 352 | api_permission: allow 353 | - 354 | resource_id: catalog/product/tag/list 355 | role_type: G 356 | api_permission: allow 357 | - 358 | resource_id: catalog/product/tag/info 359 | role_type: G 360 | api_permission: allow 361 | - 362 | resource_id: catalog/product/tag/add 363 | role_type: G 364 | api_permission: allow 365 | - 366 | resource_id: catalog/product/tag/update 367 | role_type: G 368 | api_permission: allow 369 | - 370 | resource_id: catalog/product/tag/remove 371 | role_type: G 372 | api_permission: allow 373 | - 374 | resource_id: catalog/product/downloadable_link 375 | role_type: G 376 | api_permission: allow 377 | - 378 | resource_id: catalog/product/downloadable_link/add 379 | role_type: G 380 | api_permission: allow 381 | - 382 | resource_id: catalog/product/downloadable_link/list 383 | role_type: G 384 | api_permission: allow 385 | - 386 | resource_id: catalog/product/downloadable_link/remove 387 | role_type: G 388 | api_permission: allow 389 | - 390 | resource_id: sales 391 | role_type: G 392 | api_permission: allow 393 | - 394 | resource_id: sales/order 395 | role_type: G 396 | api_permission: allow 397 | - 398 | resource_id: sales/order/change 399 | role_type: G 400 | api_permission: allow 401 | - 402 | resource_id: sales/order/info 403 | role_type: G 404 | api_permission: allow 405 | - 406 | resource_id: sales/order/shipment 407 | role_type: G 408 | api_permission: allow 409 | - 410 | resource_id: sales/order/shipment/create 411 | role_type: G 412 | api_permission: allow 413 | - 414 | resource_id: sales/order/shipment/comment 415 | role_type: G 416 | api_permission: allow 417 | - 418 | resource_id: sales/order/shipment/track 419 | role_type: G 420 | api_permission: allow 421 | - 422 | resource_id: sales/order/shipment/info 423 | role_type: G 424 | api_permission: allow 425 | - 426 | resource_id: sales/order/shipment/send 427 | role_type: G 428 | api_permission: allow 429 | - 430 | resource_id: sales/order/invoice 431 | role_type: G 432 | api_permission: allow 433 | - 434 | resource_id: sales/order/invoice/create 435 | role_type: G 436 | api_permission: allow 437 | - 438 | resource_id: sales/order/invoice/comment 439 | role_type: G 440 | api_permission: allow 441 | - 442 | resource_id: sales/order/invoice/capture 443 | role_type: G 444 | api_permission: allow 445 | - 446 | resource_id: sales/order/invoice/void 447 | role_type: G 448 | api_permission: allow 449 | - 450 | resource_id: sales/order/invoice/cancel 451 | role_type: G 452 | api_permission: allow 453 | - 454 | resource_id: sales/order/invoice/info 455 | role_type: G 456 | api_permission: allow 457 | - 458 | resource_id: sales/order/creditmemo 459 | role_type: G 460 | api_permission: allow 461 | - 462 | resource_id: sales/order/creditmemo/create 463 | role_type: G 464 | api_permission: allow 465 | - 466 | resource_id: sales/order/creditmemo/comment 467 | role_type: G 468 | api_permission: allow 469 | - 470 | resource_id: sales/order/creditmemo/cancel 471 | role_type: G 472 | api_permission: allow 473 | - 474 | resource_id: sales/order/creditmemo/info 475 | role_type: G 476 | api_permission: allow 477 | - 478 | resource_id: sales/order/creditmemo/list 479 | role_type: G 480 | api_permission: allow 481 | - 482 | resource_id: cataloginventory 483 | role_type: G 484 | api_permission: allow 485 | - 486 | resource_id: cataloginventory/update 487 | role_type: G 488 | api_permission: allow 489 | - 490 | resource_id: cataloginventory/info 491 | role_type: G 492 | api_permission: allow 493 | - 494 | resource_id: cart 495 | role_type: G 496 | api_permission: deny 497 | - 498 | resource_id: cart/create 499 | role_type: G 500 | api_permission: deny 501 | - 502 | resource_id: cart/order 503 | role_type: G 504 | api_permission: deny 505 | - 506 | resource_id: cart/info 507 | role_type: G 508 | api_permission: deny 509 | - 510 | resource_id: cart/totals 511 | role_type: G 512 | api_permission: deny 513 | - 514 | resource_id: cart/license 515 | role_type: G 516 | api_permission: deny 517 | - 518 | resource_id: cart/product 519 | role_type: G 520 | api_permission: deny 521 | - 522 | resource_id: cart/product/add 523 | role_type: G 524 | api_permission: deny 525 | - 526 | resource_id: cart/product/update 527 | role_type: G 528 | api_permission: deny 529 | - 530 | resource_id: cart/product/remove 531 | role_type: G 532 | api_permission: deny 533 | - 534 | resource_id: cart/product/list 535 | role_type: G 536 | api_permission: deny 537 | - 538 | resource_id: cart/product/moveToCustomerQuote 539 | role_type: G 540 | api_permission: deny 541 | - 542 | resource_id: cart/customer 543 | role_type: G 544 | api_permission: deny 545 | - 546 | resource_id: cart/customer/set 547 | role_type: G 548 | api_permission: deny 549 | - 550 | resource_id: cart/customer/addresses 551 | role_type: G 552 | api_permission: deny 553 | - 554 | resource_id: cart/shipping 555 | role_type: G 556 | api_permission: deny 557 | - 558 | resource_id: cart/shipping/method 559 | role_type: G 560 | api_permission: deny 561 | - 562 | resource_id: cart/shipping/list 563 | role_type: G 564 | api_permission: deny 565 | - 566 | resource_id: cart/payment 567 | role_type: G 568 | api_permission: deny 569 | - 570 | resource_id: cart/payment/method 571 | role_type: G 572 | api_permission: deny 573 | - 574 | resource_id: cart/payment/list 575 | role_type: G 576 | api_permission: deny 577 | - 578 | resource_id: cart/coupon 579 | role_type: G 580 | api_permission: deny 581 | - 582 | resource_id: cart/coupon/add 583 | role_type: G 584 | api_permission: deny 585 | - 586 | resource_id: cart/coupon/remove 587 | role_type: G 588 | api_permission: deny 589 | - 590 | resource_id: giftmessage 591 | role_type: G 592 | api_permission: deny 593 | - 594 | resource_id: giftmessage/set 595 | role_type: G 596 | api_permission: deny 597 | - 598 | resource_id: all 599 | role_type: G 600 | api_permission: deny -------------------------------------------------------------------------------- /samples/components/websites.yaml: -------------------------------------------------------------------------------- 1 | - websites: 2 | - base: 3 | name: Default Website 4 | - store_groups: 5 | - 6 | name: Main Website Store 7 | root_category: Default Category 8 | stores: 9 | - default: 10 | name: Default Store View 11 | 12 | - test: 13 | name: Test Website 14 | - store_groups: 15 | - 16 | name: Test Website Store 17 | root_category: Default Category 18 | stores: 19 | - test: 20 | name: Test Store View 21 | - test1: 22 | name: Second Test Website 23 | - store_groups: 24 | - 25 | name: Test 1 Website Store 26 | root_category: Default Category 27 | stores: 28 | - test1: 29 | name: Test 2 Store View -------------------------------------------------------------------------------- /src/app/code/community/Cti/Configurator/Helper/Components/Abstract.php: -------------------------------------------------------------------------------- 1 | _cliLog = false; 12 | } 13 | 14 | public function process() { 15 | 16 | try { 17 | 18 | if (is_null($this->_componentName)) { 19 | throw new Exception("Component name is not defined"); 20 | } 21 | 22 | Mage::dispatchEvent('configurator_process_before',array('object'=>$this)); 23 | Mage::dispatchEvent($this->_componentName.'_configurator_process_before',array('object'=>$this)); 24 | 25 | $this->_data = $this->_processFile($this->_filePath1,$this->_filePath2); 26 | 27 | $this->_processComponent($this->_data); 28 | 29 | Mage::dispatchEvent('configurator_process_after',array('object'=>$this)); 30 | Mage::dispatchEvent($this->_componentName.'_configurator_process_after',array('object'=>$this)); 31 | 32 | } catch (Exception $e) { 33 | 34 | Mage::logException($e); 35 | } 36 | 37 | } 38 | 39 | public function enableCliLog() { 40 | $this->_cliLog = true; 41 | } 42 | 43 | protected function log($msg,$nest = 0,$logLevel = 0) { 44 | if ($this->_cliLog) { 45 | for($i = 0; $i < $nest; $i++) { 46 | echo " | "; 47 | } 48 | 49 | echo $msg .PHP_EOL; 50 | } 51 | } 52 | 53 | abstract protected function _processFile($file1,$file2 = null); 54 | 55 | abstract protected function _processComponent($data); 56 | 57 | 58 | } -------------------------------------------------------------------------------- /src/app/code/community/Cti/Configurator/Helper/Components/AttributeSets.php: -------------------------------------------------------------------------------- 1 | _componentName = 'attribute_sets'; 6 | $this->_filePath1 = Mage::getBaseDir().DS.'app'.DS.'etc'.DS.'components'.DS.'attribute-sets.yaml'; 7 | } 8 | 9 | protected function _processFile($globalFile,$localFile = null) { 10 | 11 | if (!file_exists($globalFile)) { 12 | throw new Mage_Core_Exception("Cannot find global configuration YAML file."); 13 | } 14 | 15 | // Decode the YAML File 16 | $globalClass = new Zend_Config_Yaml($globalFile, 17 | NULL, 18 | array('ignore_constants' => true)); 19 | $globalArray = $globalClass->toArray(); 20 | 21 | return $globalArray; 22 | 23 | } 24 | 25 | protected function _processComponent($data) { 26 | 27 | if (isset($data['attribute_sets'])) { 28 | 29 | foreach ($data['attribute_sets'] as $set) { 30 | 31 | $attributeSet = $this->_getAttributeSet($set); 32 | 33 | if (!$attributeSet) { 34 | $attributeSet = $this->_createAttributeSet($set); 35 | 36 | $this->log($this->__('Created new attribute set "%s"',$attributeSet->getAttributeSetName())); 37 | 38 | // Set the skeleton attribute set to Default if none is specified 39 | $inheritAttributeSetName = 'Default'; 40 | 41 | if (isset($set['inherit'])) { 42 | $inheritAttributeSetName = $set['inherit']; 43 | } 44 | 45 | $this->_inheritAttributeSet($attributeSet,$inheritAttributeSetName); 46 | 47 | $this->log($this->__('Inherited new attributes from "%s"',$inheritAttributeSetName)); 48 | } 49 | 50 | foreach ($set['groups'] as $i=>$group) { 51 | 52 | if (!isset($group['name'])) { 53 | throw new Exception($this->__('No group name set for attribute "%s"',$set['name'])); 54 | } 55 | 56 | // Get the attribute Group ID 57 | $attributeGroupId = $this->_getAttributeGroupId($attributeSet,$group['name']); 58 | 59 | if (!$attributeGroupId) { 60 | $attributeGroupId = $this->_createAttributeGroup($attributeSet,$group['name'],$i); 61 | $this->log($this->__('Created attribute group found named "%s"',$group['name'])); 62 | } 63 | 64 | foreach ($group['attributes'] as $attributeCode) { 65 | 66 | $attribute = $this->_getAttribute($attributeCode); 67 | 68 | if (!$attribute) { 69 | $this->log($this->__('Attribute "%s" does not exist',$attributeCode)); 70 | continue; 71 | } 72 | 73 | // Add the attribute to the attribute set 74 | $this->_assignAttributeToAttributeSet($attribute,$attributeSet,$attributeGroupId); 75 | $this->log($this->__('Added "%s" attribute to "%s" attribute within "%s" group', 76 | $attribute->getName(), 77 | $attributeSet->getAttributeSetName(), 78 | $group['name'] 79 | )); 80 | } 81 | } 82 | 83 | } 84 | } 85 | } 86 | 87 | /** 88 | * Gets a particular attribute set otherwise 89 | * returns false if it doesn't exist. 90 | * 91 | * @param $attributeConfig 92 | * @return Mage_Eav_Model_Entity_Attribute_Set 93 | */ 94 | private function _getAttributeSet($attributeConfig) { 95 | $entityTypeId = Mage::getModel('catalog/product') 96 | ->getResource() 97 | ->getEntityType() 98 | ->getId(); 99 | 100 | $attributeSet = Mage::getResourceModel('eav/entity_attribute_set_collection') 101 | ->addFieldToFilter('entity_type_id',$entityTypeId) 102 | ->addFieldToFilter('attribute_set_name',$attributeConfig['name']) 103 | ->getFirstItem(); 104 | 105 | if ($attributeSet->getId()) { 106 | return $attributeSet; 107 | } else { 108 | return false; 109 | } 110 | } 111 | 112 | /** 113 | * Creates an attribute set 114 | * 115 | * @param array $attributeConfig 116 | * @return Mage_Eav_Model_Entity_Attribute_Set 117 | * @see http://magento.stackexchange.com/questions/4905/programmatically-create-new-attribute-set-while-inheriting-from-another 118 | */ 119 | private function _createAttributeSet($attributeConfig) { 120 | 121 | $entityTypeId = $this->_getEntityTypeId(); 122 | 123 | $attributeSet = Mage::getModel('eav/entity_attribute_set') 124 | ->setEntityTypeId($entityTypeId) 125 | ->setAttributeSetName($attributeConfig['name']); 126 | 127 | $attributeSet->validate(); 128 | $attributeSet->save(); 129 | return $attributeSet; 130 | } 131 | 132 | /** 133 | * Inherits all the attributes from the particular attribute set. 134 | * 135 | * @param Mage_Eav_Model_Entity_Attribute_Set $attributeSet 136 | * @param $inheritFromSetName 137 | */ 138 | private function _inheritAttributeSet(Mage_Eav_Model_Entity_Attribute_Set $attributeSet,$inheritFromSetName) { 139 | 140 | $entityTypeId = $this->_getEntityTypeId(); 141 | 142 | $inheritFromSetId = Mage::getResourceModel('eav/entity_attribute_set_collection') 143 | ->addFieldToFilter('entity_type_id',$entityTypeId) 144 | ->addFieldToFilter('attribute_set_name',$inheritFromSetName) 145 | ->getFirstItem() 146 | ->getId(); 147 | 148 | // Include some kind of failure check here 149 | 150 | $attributeSet->initFromSkeleton($inheritFromSetId)->save(); 151 | } 152 | 153 | /** 154 | * Gets a particular group ID within the attribute set 155 | * To be used with setting an attribute to a particular group 156 | * 157 | * @param Mage_Eav_Model_Entity_Attribute_Set $attributeSet 158 | * @param $attributeGroupName 159 | * @return mixed 160 | */ 161 | private function _getAttributeGroupId(Mage_Eav_Model_Entity_Attribute_Set $attributeSet,$attributeGroupName) { 162 | return Mage::getResourceModel('eav/entity_attribute_group_collection') 163 | ->addFieldToFilter('attribute_set_id',$attributeSet->getId()) 164 | ->addFieldToFilter('attribute_group_name',$attributeGroupName) 165 | ->getFirstItem() 166 | ->getId(); 167 | } 168 | 169 | private function _createAttributeGroup(Mage_Eav_Model_Entity_Attribute_Set $attributeSet,$attributeGroupName,$index) { 170 | $modelGroup = Mage::getModel('eav/entity_attribute_group'); 171 | $modelGroup->setAttributeGroupName($attributeGroupName) 172 | ->setAttributeSetId($attributeSet->getId()) 173 | ->setSortOrder($index*10); 174 | $modelGroup->save(); 175 | return $modelGroup->getId(); 176 | } 177 | 178 | /** 179 | * Gets a particular attribute otherwise 180 | * returns false if it doesn't exist 181 | * 182 | * @param $code 183 | * @return bool|Varien_Object 184 | */ 185 | private function _getAttribute($code) { 186 | 187 | $entityTypeId = $this->_getEntityTypeId(); 188 | 189 | $attribute = Mage::getResourceModel('catalog/eav_mysql4_product_attribute_collection') 190 | ->addFieldToFilter('attribute_code',$code) 191 | ->addFieldToFilter('entity_type_id',$entityTypeId) 192 | ->getFirstItem(); 193 | 194 | if ($attribute->getId()) { 195 | return $attribute; 196 | } else { 197 | return false; 198 | } 199 | } 200 | 201 | /** 202 | * Assigns the attribute to the attribute set 203 | * 204 | * @param Mage_Eav_Model_Entity_Attribute $attribute 205 | * @param Mage_Eav_Model_Entity_Attribute_Set $attributeSet 206 | * @param int $attributeGroupId 207 | */ 208 | protected function _assignAttributeToAttributeSet($attribute,$attributeSet,$attributeGroupId) { 209 | 210 | $entityTypeId = $this->_getEntityTypeId(); 211 | 212 | $setup = Mage::getModel('eav/entity_setup','core_setup'); 213 | $setup->addAttributeToSet($entityTypeId,$attributeSet->getId(),$attributeGroupId,$attribute->getId()); 214 | } 215 | 216 | private function _getEntityTypeId() { 217 | return Mage::getModel('catalog/product') 218 | ->getResource() 219 | ->getEntityType() 220 | ->getId(); 221 | } 222 | } -------------------------------------------------------------------------------- /src/app/code/community/Cti/Configurator/Helper/Components/Attributes.php: -------------------------------------------------------------------------------- 1 | _componentName = 'attributes'; 6 | $this->_filePath1 = Mage::getBaseDir().DS.'app'.DS.'etc'.DS.'components'.DS.'attributes.yaml'; 7 | } 8 | 9 | protected function _processFile($globalFile,$localFile = null) { 10 | if (!file_exists($globalFile)) { 11 | throw new Mage_Core_Exception("Cannot find global configuration YAML file."); 12 | } 13 | 14 | // Decode the YAML File 15 | $globalClass = new Zend_Config_Yaml($globalFile, 16 | NULL, 17 | array('ignore_constants' => true)); 18 | $globalArray = $globalClass->toArray(); 19 | 20 | return $globalArray; 21 | } 22 | 23 | protected function _processComponent($data) { 24 | 25 | if (isset($data['attributes'])) { 26 | 27 | foreach ($data['attributes'] as $code=>$attributeData) { 28 | 29 | $this->_createOrUpdateAttribute($code,$attributeData); 30 | } 31 | } 32 | } 33 | 34 | private function _createOrUpdateAttribute($code,$data) { 35 | $attribute = $this->_getAttribute($code); 36 | $canSave = false; 37 | if (!$attribute) { 38 | $this->log($this->__('Creating Attribute %s',$code)); 39 | $attribute = Mage::getModel('catalog/resource_eav_attribute'); 40 | $attribute->setData('attribute_code',$code); 41 | $canSave = true; 42 | $data = array_replace_recursive($this->_getAttributeDefaultSettings(),$data); 43 | $data['backend_type'] = $attribute->getBackendTypeByInput($data['frontend_input']); 44 | $data['source_model'] = Mage::helper('catalog/product')->getAttributeSourceModelByInputType($data['frontend_input']); 45 | $data['backend_model'] = Mage::helper('catalog/product')->getAttributeBackendModelByInputType($data['frontend_input']); 46 | } 47 | 48 | foreach ($data as $key=>$value) { 49 | // Skip store labels to be processed after 50 | if ($key == 'store_labels') { 51 | continue; 52 | } 53 | 54 | // YAML will pass product types as an array which needs to be imploded 55 | if ($key == "product_types") { 56 | $key = "apply_to"; 57 | $value = implode(",",$value); 58 | } 59 | 60 | // YAML will pass options as an array which will require to be added differently 61 | if ($key == "options") { 62 | continue; 63 | } 64 | 65 | // Skip setting search_weight if not enterprise 66 | if ($key == "search_weight" && Mage::getEdition() != Mage::EDITION_ENTERPRISE) { 67 | continue; 68 | } 69 | 70 | if ($attribute->getId() && $attribute->getData($key) == $value) { 71 | continue; 72 | } 73 | 74 | $attribute->setData($key,$value); 75 | $this->log($this->__('Setting attribute "%s" %s with %s',$code,$key,$value)); 76 | $canSave = true; 77 | }; 78 | unset($key); 79 | unset($value); 80 | if (!$attribute->getEntityTypeId()) { 81 | $attribute->setEntityTypeId(Mage::getModel('eav/entity')->setType('catalog_product')->getTypeId()); 82 | $attribute->setIsUserDefined(1); 83 | } 84 | try { 85 | if ($canSave) { 86 | $attribute->save(); 87 | $this->log($this->__('Saved Attribute %s',$code)); 88 | } 89 | if ($data['options']) { 90 | $this->_maintainAttributeOptions($attribute,$data['options']); 91 | } 92 | if ($data['store_labels']) { 93 | $this->_maintainAttributeStoreLabels($attribute, $data['store_labels']); 94 | } 95 | } catch (Exception $e) { 96 | throw $e; 97 | } 98 | } 99 | 100 | 101 | /** 102 | * Gets a particular attribute otherwise 103 | * returns false if it doesn't exist 104 | * 105 | * @param $code 106 | * @return bool|Varien_Object 107 | */ 108 | private function _getAttribute($code) { 109 | $entityTypeId = Mage::getModel('catalog/product') 110 | ->getResource() 111 | ->getEntityType() 112 | ->getId(); 113 | 114 | $attribute = Mage::getResourceModel('catalog/eav_mysql4_product_attribute_collection') 115 | ->addFieldToFilter('attribute_code',$code) 116 | ->addFieldToFilter('entity_type_id',$entityTypeId) 117 | ->getFirstItem(); 118 | 119 | if ($attribute->getId()) { 120 | return $attribute; 121 | } else { 122 | return false; 123 | } 124 | } 125 | 126 | 127 | /** 128 | * Assigns options to an attribute 129 | * 130 | * The attribute should be a select/multiselect 131 | * 132 | * @param $attribute 133 | * @param $options 134 | */ 135 | private function _maintainAttributeOptions($attribute,$options) { 136 | 137 | $currentOptions = $attribute->getSource()->getAllOptions(); 138 | 139 | $currentOptionFormat = array(); 140 | foreach ($currentOptions as $option) { 141 | if ($option['label'] != '') { 142 | $currentOptionFormat[] = $option['label']; 143 | } 144 | } 145 | 146 | $attributeId = $attribute->getId(); 147 | $optionsToAdd = array_diff($options,$currentOptionFormat); 148 | $optionsToRemove = array_diff($currentOptionFormat,$options); 149 | $eav_entity_setup = new Mage_Eav_Model_Entity_Setup('core_setup'); 150 | 151 | // Create new attributes 152 | foreach ($optionsToAdd as $option) { 153 | 154 | unset($new_option); 155 | 156 | // Check if the option already exists 157 | if ($attribute->getSource()->getOptionId($option)) { 158 | $this->log($this->__("Exsting attribute option %s for %s",$option,$attribute->getAttributeCode())); 159 | } 160 | $new_option['attribute_id'] = $attributeId; 161 | $new_option['value']['_custom_'.$option][0] = $option; 162 | $eav_entity_setup->addAttributeOption($new_option); 163 | 164 | /* 165 | $attribute->setData( 166 | 'option', 167 | array( 168 | 'value'=>array( 169 | 'option'=>array( 170 | $option 171 | ) 172 | ) 173 | ) 174 | ); 175 | $attribute->save(); 176 | */ 177 | 178 | $this->log($this->__("Created attribute option %s for %s",$option,$attribute->getAttributeCode())); 179 | } 180 | 181 | // Remove old attributes 182 | foreach ($optionsToRemove as $option) { 183 | $optionId = $attribute->getSource()->getOptionId($option); 184 | $toDelete['delete'][$optionId] = true; 185 | $toDelete['value'][$optionId] = true; 186 | $setup = new Mage_Eav_Model_Entity_Setup('core_setup'); 187 | $setup->addAttributeOption($toDelete); 188 | $this->log($this->__("Deleted attribute option %s for %s",$option,$attribute->getAttributeCode())); 189 | } 190 | } 191 | 192 | 193 | /** 194 | * Assign store labels to an attribute 195 | * 196 | * @param $attribute 197 | * @param $labels 198 | */ 199 | private function _maintainAttributeStoreLabels($attribute, $labels) 200 | { 201 | //get existing labels 202 | $storeLabels = Mage::getModel('eav/entity_attribute')->getResource() 203 | ->getStoreLabelsByAttributeId($attribute->getId()); 204 | 205 | //build up array of storeId - Label 206 | foreach ($labels as $storeCode => $label) { 207 | try{ 208 | $store = Mage::app()->getStore($storeCode); 209 | $storeId = $store->getId(); 210 | $storeLabels[$storeId] = $label; 211 | } catch (Exception $e){ 212 | $this->log($this->__('Skipping label for store "' . $storeCode . '" - Check the store is setup ')); 213 | } 214 | } 215 | 216 | //save the new store labels 217 | $attribute->setStoreLabels($storeLabels)->save(); 218 | 219 | } 220 | 221 | /** 222 | * @return array 223 | */ 224 | private function _getAttributeDefaultSettings() { 225 | return array( 226 | 'is_global' => 0, 227 | 'is_visible' => 1, 228 | 'is_searchable' => 0, 229 | 'is_filterable' => 0, 230 | 'is_comparable' => 0, 231 | 'is_visible_on_front' => 0, 232 | 'is_html_allowed_on_front' => 0, 233 | 'is_used_for_price_rules' => 0, 234 | 'is_filterable_in_search' => 0, 235 | 'used_in_product_listing' => 0, 236 | 'used_for_sort_by' => 0, 237 | 'is_configurable' => 0, 238 | 'product_types' => NULL, 239 | 'is_visible_in_advanced_search' => 0, 240 | 'position' => 0, 241 | 'is_wysiwyg_enabled' => 0, 242 | 'is_used_for_promo_rules' => 0, 243 | 'default_value_text' => '', 244 | 'default_value_yesno' => 0, 245 | 'default_value_date' => '', 246 | 'default_value_textarea' => '', 247 | 'is_unique' => 0, 248 | 'is_required' => 0, 249 | 'frontend_input' => 'boolean', 250 | 'backend_type' => 'static', 251 | 'search_weight' => 1 // EE only 252 | ); 253 | } 254 | } -------------------------------------------------------------------------------- /src/app/code/community/Cti/Configurator/Helper/Components/Categories.php: -------------------------------------------------------------------------------- 1 | _filePath1 = Mage::getBaseDir() . DS . 'app' . DS . 'etc' . DS . 'components' . DS . 'categories.yaml'; 11 | 12 | } 13 | 14 | protected function _processFile($globalFile,$localFile = null) { 15 | if (!file_exists($globalFile)) { 16 | throw new Mage_Core_Exception("Cannot find global configuration YAML file."); 17 | } 18 | 19 | // Decode the YAML File 20 | $globalClass = new Zend_Config_Yaml($globalFile, 21 | NULL, 22 | array('ignore_constants' => true)); 23 | $globalArray = $globalClass->toArray(); 24 | 25 | return $globalArray; 26 | } 27 | 28 | protected function _processComponent($data) { 29 | 30 | if (isset($data['categories'])) { 31 | 32 | foreach ($data['categories'] as $i=>$catData) { 33 | 34 | $this->_addCategory($catData); 35 | } 36 | } 37 | } 38 | 39 | /** 40 | * Function to add category 41 | * 42 | * @param $data 43 | * @param Mage_Catalog_Model_Category $parent 44 | * @throws Mage_Core_Exception 45 | */ 46 | protected function _addCategory($data,Mage_Catalog_Model_Category $parent = null) { 47 | 48 | // If parent category is null then just set it as the store groups root category 49 | if ($parent == null && isset($data['store_group'])) { 50 | $storeGroup = Mage::getResourceModel('core/store_group_collection') 51 | ->addFieldToFilter('name',$data['store_group']) 52 | ->getFirstItem(); 53 | if ($storeGroup->getId()) { 54 | $parentId = $storeGroup->getRootCategoryId(); 55 | } else { 56 | throw new Mage_Core_Exception('No store group exists'); 57 | } 58 | } elseif ($parent != null) { 59 | $parentId = $parent->getId(); 60 | } else { 61 | throw new Mage_Core_Exception('No root category id assignable.'); 62 | } 63 | 64 | /* @var $category Mage_Catalog_Model_Category */ 65 | 66 | // Check if the category with that name exists and has the same parent 67 | $category = Mage::getResourceModel('catalog/category_collection') 68 | ->addAttributeToFilter('name',$data['name']) 69 | ->addFieldToFilter('parent_id',$parentId) 70 | ->addAttributeToSelect('*') 71 | ->getFirstItem(); 72 | 73 | $canSave = false; 74 | 75 | // If it does exist, update the description 76 | if (!$category->getId()) { 77 | 78 | $category = Mage::getModel('catalog/category') 79 | ->setName($data['name']) 80 | ->setParentId($parentId) 81 | ->setIsActive(1) 82 | ->setDisplayMode("PRODUCTS") 83 | ->setPath(Mage::getModel('catalog/category')->load($parentId)->getPath()); 84 | 85 | $canSave = true; 86 | } 87 | 88 | foreach ($data as $key=>$value) { 89 | if ($key == "categories") { 90 | continue; 91 | } 92 | if ($key == "products") { 93 | continue; 94 | } 95 | if ($key == "store_group") { 96 | continue; 97 | } 98 | if ($category->getData($key) == $value) { 99 | continue; 100 | } 101 | $category->setData($key,$value); 102 | $canSave = true; 103 | } 104 | 105 | // Add products 106 | if (isset($data['products'])) { 107 | $products = array(); 108 | $i = 10; 109 | foreach ($data['products'] as $sku) { 110 | $id = Mage::getModel('catalog/product')->getIdBySku($sku); 111 | $products[$id] = $i; 112 | $i = $i + 10; 113 | unset($id); 114 | } 115 | unset($i); 116 | $category->setPostedProducts($products); 117 | } 118 | 119 | if ($canSave) { 120 | $category->save(); 121 | $this->log($this->__('Category %s saved', $category->getName()),($category->getLevel()-2)); 122 | } 123 | 124 | // Recursive category creation 125 | if (isset($data['categories'])) { 126 | foreach ($data['categories'] as $categoryConfig) { 127 | $this->_addCategory($categoryConfig,$category); 128 | } 129 | } 130 | 131 | } 132 | } -------------------------------------------------------------------------------- /src/app/code/community/Cti/Configurator/Helper/Components/Config.php: -------------------------------------------------------------------------------- 1 | _filePath1 = Mage::getBaseDir().DS.'app'.DS.'etc'.DS.'components'.DS.'config.yaml'; 10 | $this->_filePath2 = Mage::getBaseDir().DS.'app'.DS.'etc'.DS.'local_components'.DS.'config.yaml'; // Could be some symlinked file environment specific 11 | 12 | $this->_coreConfigModel = Mage::getModel('core/config'); 13 | 14 | } 15 | 16 | protected function _processFile($globalFile,$localFile = null) { 17 | 18 | if (!file_exists($globalFile)) { 19 | $this->log("No configuration component found in: " . $globalFile); 20 | $this->log("Skipping"); 21 | throw new Mage_Core_Exception("Cannot find global configuration YAML file."); 22 | } 23 | 24 | // Decode the YAML File 25 | $globalClass = new Zend_Config_Yaml($globalFile, 26 | NULL, 27 | array('ignore_constants' => true)); 28 | $globalArray = $globalClass->toArray(); 29 | 30 | $localArray = array(); 31 | if (file_exists($localFile)) { 32 | // Decode the YAML File 33 | $localClass = new Zend_Config_Yaml($localFile, 34 | NULL, 35 | array('ignore_constants' => true)); 36 | $localArray = $localClass->toArray(); 37 | } 38 | 39 | $data = array_merge_recursive($globalArray,$localArray); 40 | 41 | return $data; 42 | } 43 | 44 | protected function _processComponent($data) { 45 | 46 | // Loop through global configuration settings first 47 | if (isset($data['global'])) { 48 | $this->_saveDefaultConfigItems($data['global']); 49 | } 50 | 51 | // Initialise inheritable config for website and store level config 52 | $inheritables = null; 53 | if (isset($data['grouped'])) { 54 | $inheritables = $data['grouped']; 55 | } 56 | 57 | if (isset($data['websites'])) { 58 | foreach ($data['websites'] as $websiteCode=>$configData) { 59 | $websiteConfig = $this->_mergeInheritables($configData,$inheritables); 60 | $website = Mage::getModel('core/website')->load($websiteCode,'code'); 61 | $this->_saveWebsiteConfigItems($websiteConfig,$website); 62 | } 63 | } 64 | 65 | if (isset($data['stores'])) { 66 | foreach ($data['stores'] as $storeCode=>$configData) { 67 | $storeConfig = $this->_mergeInheritables($configData,$inheritables); 68 | $store = Mage::getModel('core/store')->load($storeCode,'code'); 69 | $this->_saveStoreConfigItems($storeConfig,$store); 70 | } 71 | } 72 | 73 | } 74 | 75 | private function _saveDefaultConfigItems($config) { 76 | if (isset($config['core_config'])) { 77 | foreach ($config['core_config'] as $config) { 78 | 79 | // See if the value should be encrypted 80 | if (isset($config['encrypted']) && $config['encrypted'] == 1) { 81 | $config['value'] = Mage::helper('core')->encrypt($config['value']); 82 | } 83 | 84 | // Save config 85 | $this->_checkAndSaveConfig( 86 | $config['path'], 87 | $config['value'] 88 | ); 89 | 90 | } 91 | } 92 | } 93 | 94 | private function _saveWebsiteConfigItems(array $configs,Mage_Core_Model_Website $website) { 95 | try { 96 | if (!$website->getId()) { 97 | throw new Exception($this->__('Website does not exist')); 98 | } 99 | if (!empty($configs)) { 100 | foreach ($configs as $config) { 101 | if (isset($config['encrypted']) && $config['encrypted'] == 1) { 102 | $config['value'] = Mage::helper('core')->encrypt($config['value']); 103 | } 104 | 105 | // Save config 106 | $this->_checkAndSaveConfig( 107 | $config['path'], 108 | $config['value'], 109 | 'websites', 110 | $website->getId(), 111 | $website->getCode() 112 | ); 113 | 114 | } 115 | } 116 | } catch (Exception $e) { 117 | $this->log($e->getMessage()); 118 | } 119 | } 120 | 121 | private function _saveStoreConfigItems(array $configs,Mage_Core_Model_Store $store) { 122 | try { 123 | if (!$store->getId()) { 124 | throw new Exception($this->__('Store does not exist')); 125 | } 126 | if (!empty($configs)) { 127 | foreach ($configs as $config) { 128 | if (isset($config['encrypted']) && $config['encrypted'] == 1) { 129 | $config['value'] = Mage::helper('core')->encrypt($config['value']); 130 | } 131 | 132 | // Save config 133 | $this->_checkAndSaveConfig( 134 | $config['path'], 135 | $config['value'], 136 | 'stores', 137 | $store->getId(), 138 | $store->getCode() 139 | ); 140 | 141 | } 142 | } 143 | } catch (Exception $e) { 144 | $this->log($e->getMessage()); 145 | } 146 | } 147 | 148 | private function _mergeInheritables($config,$inheritables) { 149 | $data = array(); 150 | if (isset($config['core_config'])) { 151 | $data = $config['core_config']; 152 | } 153 | if (isset($config['inherit'])){ 154 | foreach ($config['inherit'] as $key) { 155 | $data = array_merge_recursive($data,$inheritables[$key]['core_config']); 156 | } 157 | } 158 | return $data; 159 | } 160 | 161 | private function _checkAndSaveConfig($path,$value,$scope = 'default',$scopeId = 0,$code = null) { 162 | 163 | 164 | switch ($scope) { 165 | case 'websites': 166 | $valueCheck = (string) Mage::app()->getWebsite($scopeId)->getConfig($path); 167 | break; 168 | case 'stores': 169 | $valueCheck = (string) Mage::getStoreConfig($path,$scopeId); 170 | break; 171 | default: 172 | $valueCheck = (string) Mage::app()->getConfig()->getNode($path,$scope); 173 | break; 174 | } 175 | 176 | 177 | if ($value != $valueCheck) { 178 | $this->_coreConfigModel->saveConfig($path,$value,$scope,$scopeId); 179 | 180 | switch ($scope) { 181 | case 'websites': 182 | $this->log($this->__('Saved path for website: %s - %s to %s',$code,$path,$value)); 183 | break; 184 | case 'stores': 185 | $this->log($this->__('Saved path for store: %s - %s to %s',$code,$path,$value)); 186 | break; 187 | default: 188 | $this->log($this->__('Saved default path for %s to %s',$path,$value)); 189 | break; 190 | } 191 | 192 | } 193 | 194 | 195 | } 196 | } -------------------------------------------------------------------------------- /src/app/code/community/Cti/Configurator/Helper/Components/CustomerGroups.php: -------------------------------------------------------------------------------- 1 | _componentName = 'customer_groups'; 6 | $this->_filePath1 = Mage::getBaseDir().DS.'app'.DS.'etc'.DS.'components'.DS.'customer-groups.yaml'; 7 | } 8 | 9 | protected function _processFile($globalFile,$localFile = null) { 10 | 11 | if (!file_exists($globalFile)) { 12 | throw new Mage_Core_Exception("Cannot find global configuration YAML file."); 13 | } 14 | 15 | // Decode the YAML File 16 | $globalClass = new Zend_Config_Yaml($globalFile, 17 | NULL, 18 | array('ignore_constants' => true)); 19 | $globalArray = $globalClass->toArray(); 20 | 21 | return $globalArray; 22 | 23 | } 24 | 25 | protected function _processComponent($data) { 26 | 27 | if (isset($data['groups'])) { 28 | foreach ($data['groups'] as $i=>$_group) { 29 | $group = Mage::getModel('customer/group')->load($_group['customer_group_code'],'customer_group_code'); 30 | 31 | if (!$group->getId() && $group->getId() != "0") { 32 | $group = Mage::getModel('customer/group')->setCustomerGroupCode($_group['customer_group_code']); 33 | } 34 | 35 | try { 36 | 37 | $taxClass = $this->_getTaxClass($_group['tax_class'],Mage_Tax_Model_Class::TAX_CLASS_TYPE_CUSTOMER); 38 | if (!$taxClass) { 39 | throw new Exception($this->__('Customer tax class with name %s does not exist',$_group['tax_class'])); 40 | } 41 | 42 | if ($group->getTaxClassId() != $taxClass->getId()) { 43 | $group 44 | ->setTaxClassId($taxClass->getId()) 45 | ->save(); 46 | $this->log($this->__('Saved Customer Group %s',$_group['customer_group_code'])); 47 | } 48 | 49 | } catch (Exception $e) { 50 | $this->log($e->getMessage()); 51 | } 52 | } 53 | } 54 | } 55 | 56 | /** 57 | * @param $name 58 | * @param $type 59 | * 60 | * @return Mage_Tax_Model_Class 61 | */ 62 | private function _getTaxClass($name,$type) { 63 | $taxClasses = Mage::getResourceModel('tax/class_collection') 64 | ->addFieldToFilter('class_type',$type) 65 | ->addFieldToFilter('class_name',$name); 66 | if ($taxClasses->count()) { 67 | return $taxClasses->getFirstItem(); 68 | } 69 | return false; 70 | } 71 | } -------------------------------------------------------------------------------- /src/app/code/community/Cti/Configurator/Helper/Components/Media.php: -------------------------------------------------------------------------------- 1 | _filePath1 = Mage::getBaseDir() . DS . 'app' . DS . 'etc' . DS . 'components' . DS . 'media.yaml'; 11 | $this->_filePath2 = Mage::getBaseDir() . DS . 'app' . DS . 'etc' . DS . 'components' . DS . 'local_components' . DS . 'media.yaml'; 12 | 13 | $this->_coreConfigModel = Mage::getModel('core/config'); 14 | 15 | } 16 | 17 | protected function _processFile($globalFile, $localFile = null) 18 | { 19 | 20 | if (!file_exists($globalFile)) { 21 | $this->log("No configuration component found in: " . $globalFile); 22 | $this->log("Skipping"); 23 | throw new Mage_Core_Exception("Cannot find global configuration YAML file."); 24 | } 25 | 26 | // Decode the YAML File 27 | $globalClass = new Zend_Config_Yaml($globalFile, 28 | NULL, 29 | array('ignore_constants' => true)); 30 | $globalArray = $globalClass->toArray(); 31 | 32 | $localArray = array(); 33 | if (file_exists($localFile)) { 34 | // Decode the YAML File 35 | $localClass = new Zend_Config_Yaml($localFile, 36 | NULL, 37 | array('ignore_constants' => true)); 38 | $localArray = $localClass->toArray(); 39 | } 40 | 41 | $data = array_merge_recursive($globalArray, $localArray); 42 | 43 | return $data; 44 | } 45 | 46 | 47 | protected function _processComponent($data) { 48 | 49 | try { 50 | // no media set 51 | if(!isset($data['media'])) { 52 | throw new Exception('Could not find a media node'); 53 | } 54 | 55 | $currentPath = Mage::getBaseDir('media'); 56 | 57 | foreach ($data['media'] as $name=>$childNode) { 58 | $this->_createChildFolderFileItem($currentPath,$name,$childNode); 59 | } 60 | 61 | } catch (Exception $e) { 62 | 63 | } 64 | } 65 | 66 | private function _createChildFolderFileItem($currentPath,$name,$node,$nest = 0) { 67 | try { 68 | 69 | // Update the current path to new path 70 | $newPath = $currentPath.DIRECTORY_SEPARATOR.$name; 71 | 72 | // If doesn't file/folder exists 73 | if (!file_exists($newPath)) { 74 | 75 | // If the node does not have a name 76 | if (!is_numeric($name)) { 77 | 78 | // Then it is a directory so create it 79 | mkdir($newPath, 0777, true); 80 | $this->log("Created new media directory $name",$nest); 81 | } 82 | } else { 83 | 84 | // If the node does not have a name 85 | if (!is_numeric($name)) { 86 | 87 | $this->log("Directory exists: $name",$nest); 88 | } 89 | } 90 | 91 | // If the node does not have a name 92 | if (!is_numeric($name)) { 93 | 94 | $nest++; 95 | 96 | // Loop through the children nodes 97 | foreach ($node as $childName=>$childNode) { 98 | 99 | // Create a child folder 100 | $this->_createChildFolderFileItem($newPath,$childName,$childNode,$nest); 101 | } 102 | } else { 103 | 104 | if (!isset($node['name'])) { 105 | throw new Exception("No name set for child item in $currentPath"); 106 | } 107 | 108 | if (!isset($node['location'])) { 109 | throw new Exception("No location set for child item in $currentPath"); 110 | } 111 | 112 | $newPath = $currentPath.DIRECTORY_SEPARATOR.$node['name']; 113 | 114 | if (file_exists($newPath)) { 115 | throw new Exception("File already exists $newPath"); 116 | } 117 | 118 | // Get the contents of the file 119 | $this->log("Downloading contents of file from ".$node['location'],$nest); 120 | $fileContents = file_get_contents($node['location']); 121 | 122 | // Save it in the new path 123 | file_put_contents($newPath,$fileContents); 124 | $this->log("Created new file $newPath",$nest); 125 | 126 | } 127 | 128 | 129 | } catch (Exception $e) { 130 | $this->log($e->getMessage(),$nest); 131 | } 132 | 133 | } 134 | } -------------------------------------------------------------------------------- /src/app/code/community/Cti/Configurator/Helper/Components/Pages.php: -------------------------------------------------------------------------------- 1 | _componentName = 'pages'; 8 | $this->_filePath1 = Mage::getBaseDir() . DS . 'app' . DS . 'etc' . DS . 'components' . DS . 'pages.yaml'; 9 | } 10 | 11 | protected function _processFile($globalFile, $localFile = null) 12 | { 13 | 14 | if (!file_exists($globalFile)) { 15 | throw new Mage_Core_Exception("Cannot find pages configuration YAML file."); 16 | } 17 | 18 | 19 | // Decode the YAML File 20 | $globalClass = new Zend_Config_Yaml($globalFile, 21 | NULL, 22 | array('ignore_constants' => true)); 23 | 24 | $globalArray = $globalClass->toArray(); 25 | 26 | 27 | return $globalArray; 28 | } 29 | 30 | protected function _processComponent($data) 31 | { 32 | // Check if there is a pages node in the yaml 33 | if (isset($data['pages'])) { 34 | 35 | // Loop through its children 36 | foreach ($data['pages'] as $identifier => $pageData) { 37 | 38 | try { 39 | 40 | // Ensure identifier is set 41 | if (is_numeric($identifier)) { 42 | throw new Exception("Please refer to sample content for see how the page identifier is set."); 43 | } 44 | 45 | // Try load existing page 46 | if (!isset($pageData['contents'])) { 47 | throw new Exception("Could not find the page contents"); 48 | } 49 | 50 | // If the all attribute is set then this will be a global page. 51 | if (isset($pageData['contents']['all'])) { 52 | $page = Mage::getResourceModel('cms/page_collection') 53 | ->addStoreFilter(0) 54 | ->addFieldToFilter('identifier',$identifier) 55 | ->getFirstItem(); 56 | 57 | $storePageData = array_merge_recursive($pageData,$pageData['contents']['all']); 58 | 59 | $this->_createUpdatePage($identifier,$page,$storePageData); 60 | 61 | } elseif (is_array($pageData['contents'])) { 62 | 63 | // Loop through the different versions of the content 64 | foreach ($pageData['contents'] as $i=>$content) { 65 | 66 | // Check if we have an index 67 | if (!is_numeric($i)) { 68 | throw new Exception("A textual index for the content should not be defined. Use 'all' or none"); 69 | } 70 | 71 | // Check if we have store view(s) set 72 | if (!isset($content['stores']) || !is_array($content['stores'])) { 73 | throw new Exception("Store views are not correctly set on $identifier"); 74 | } 75 | 76 | $pages = Mage::getResourceModel('cms/page_collection') 77 | ->addFieldToFilter('identifier',$identifier); 78 | 79 | if ($pages->count()) { 80 | $pagesArray = array_values($pages->getItems()); 81 | if (isset($pagesArray[$i])) { 82 | $page = $pagesArray[$i]; 83 | } else { 84 | $page = Mage::getModel('cms/page'); 85 | } 86 | } else { 87 | $page = Mage::getModel('cms/page'); 88 | } 89 | 90 | $storePageData = array_merge_recursive($pageData,$content); 91 | 92 | $this->_createUpdatePage($identifier,$page,$storePageData); 93 | 94 | unset($storeIds); 95 | } 96 | } 97 | 98 | } catch (Exception $e) { 99 | 100 | $this->log($e->getMessage()); 101 | } 102 | } 103 | } 104 | } 105 | 106 | /** 107 | * @param Mage_Cms_Model_Page $page 108 | * @param $data 109 | * @throws Exception 110 | */ 111 | private function _createUpdatePage($identifier,Mage_Cms_Model_Page $page,$data) { 112 | 113 | $canSave = false; 114 | 115 | // Load page model 116 | if (!$page->getId()) { 117 | $page = Mage::getModel('cms/page'); 118 | $page->setIdentifier($identifier); 119 | } 120 | 121 | unset($data['contents']); 122 | 123 | if (isset($data['stores'])) { 124 | 125 | // Loop through the store view names to get its corresponding ID 126 | $storeIds = array(); 127 | foreach ($data['stores'] as $storeViewName) { 128 | $store = Mage::getModel('core/store')->load($storeViewName,'code'); 129 | if (!$store->getId()) { 130 | throw new Exception("Store View Name: $storeViewName does not exist for $identifier"); 131 | } 132 | $storeIds[] = $store->getId(); 133 | unset($store); 134 | } 135 | unset($storeViewName); 136 | 137 | // @todo check what stores it is associated to already 138 | $oldStoreIds = Mage::getModel('cms/page')->load($page->getId())->getStoreId(); 139 | 140 | sort($storeIds); 141 | if ($oldStoreIds != $storeIds) { 142 | $canSave = true; 143 | $page->setStores($storeIds); 144 | } 145 | 146 | unset($oldStoreIds); 147 | unset($storeIds); 148 | unset($data['stores']); 149 | } else { 150 | 151 | $page->setStores(array(0)); 152 | } 153 | 154 | // Loop through page attributes 155 | foreach ($data as $key=>$value) { 156 | 157 | // content file attribute would require to read it from a file 158 | if ($key == "content_file") { 159 | 160 | // If a value/path is set then get its contents 161 | if ($value != "") { 162 | 163 | // locate file path 164 | $filePath = Mage::getBaseDir() . DS . 'app' . DS . 'etc' . DS . 'components' . DS . 'html' . DS . $value; 165 | 166 | // Check if the file exists 167 | if (file_exists($filePath)) { 168 | 169 | // Get the contents of the file and save it as the value 170 | $value = file_get_contents($filePath); 171 | 172 | unset($filePath); 173 | 174 | $key = 'content'; 175 | } else { 176 | throw new Exception("No file found in $filePath"); 177 | } 178 | 179 | } else { 180 | continue; 181 | } 182 | } 183 | 184 | // If the value is already equal to the value in the database, skip it 185 | if ($page->getData($key) == $value) { 186 | continue; 187 | } 188 | 189 | $canSave = true; 190 | $page->setData($key,$value); 191 | $this->log("Setting page attribute $key to $value for $identifier"); 192 | 193 | } 194 | 195 | if ($canSave) { 196 | $page->save(); 197 | $this->log("Saved page $identifier"); 198 | } 199 | } 200 | 201 | } -------------------------------------------------------------------------------- /src/app/code/community/Cti/Configurator/Helper/Components/Products.php: -------------------------------------------------------------------------------- 1 | _filePath1 = Mage::getBaseDir() . DS . 'app' . DS . 'etc' . DS . 'components' . DS . 'products.yaml'; 28 | } 29 | 30 | protected function _processFile($globalFile,$localFile = null) { 31 | if (!file_exists($globalFile)) { 32 | throw new Mage_Core_Exception("Cannot find global configuration YAML file."); 33 | } 34 | 35 | // Decode the YAML File 36 | $globalClass = new Zend_Config_Yaml($globalFile, 37 | NULL, 38 | array('ignore_constants' => true)); 39 | $globalArray = $globalClass->toArray(); 40 | 41 | return $globalArray; 42 | } 43 | 44 | protected function _processComponent($data) { 45 | if (isset($data['products'])) { 46 | 47 | foreach ($data['products'] as $i=>$data) { 48 | 49 | $this->_addUpdateProduct($i,$data); 50 | } 51 | } 52 | } 53 | 54 | private function _addUpdateProduct($sku,$data,$child = false) { 55 | 56 | try { 57 | $productId = Mage::getModel('catalog/product')->getIdBySku($sku); 58 | 59 | $product = Mage::getModel('catalog/product'); 60 | if ($productId) { 61 | $product->load($productId); 62 | } else { 63 | $product->setSku($sku); 64 | } 65 | 66 | $data = array_replace_recursive($this->_getProductDefaultSettings(),$data); 67 | $product->setMediaGallery(array('images'=>array (), 'values'=>array ())); 68 | 69 | foreach ($data as $key=>$value) { 70 | 71 | $attributeLog = true; 72 | 73 | // Setting the ID of the attribute set correctly 74 | if ($key == "attribute_set") { 75 | $attribute = $this->_getAttributeSet($value); 76 | 77 | if (!$attribute) { 78 | throw new Exception($this->__('Attribute Set %s for %s does not exists',$value,$sku)); 79 | } 80 | $key = "attribute_set_id"; 81 | $value = $attribute->getId(); 82 | } 83 | 84 | // Setting for website 85 | if ($key == "websites") { 86 | $key = 'website_ids'; 87 | $value = $this->_getWebsiteIds($value); 88 | } 89 | 90 | // QTY 91 | if ($key == "qty") { 92 | $key = 'stock_data'; 93 | $value = array( 94 | 'use_config_manage_stock' => 1, 95 | 'is_in_stock' => 1, 96 | 'qty' => $data['qty'] 97 | ); 98 | 99 | 100 | $stockItem = Mage::getModel('cataloginventory/stock_item'); 101 | $stockItem->assignProduct($product); 102 | $stockItem->setData('is_in_stock', 1); 103 | $stockItem->setData('qty', $data['qty']); 104 | $product->setStockItem($stockItem); 105 | } 106 | 107 | if ($key == "configurable_attributes") { 108 | continue; 109 | } 110 | 111 | if ($key == "simple_products") { 112 | continue; 113 | } 114 | 115 | if ($key == "weight" && $product->getTypeId() == "configurable") { 116 | continue; 117 | } 118 | 119 | if ($key == "images") { 120 | $this->_downloadAndPrepareImages($sku,$value); 121 | continue; 122 | } 123 | 124 | // Get the attribute 125 | $attribute = $this->_getAttribute($key); 126 | 127 | 128 | // Check if the attribute exists 129 | if (!$attribute && !$this->_isStandardAttributeOption($key)) { 130 | $this->log($this->__('Attribute %s does not exist',$key,$child)); 131 | continue; 132 | //throw new Exception($this->__('Attribute %s does not exist',$key)); 133 | } 134 | 135 | // If the value has to be obtained from a file - fetch it 136 | if (!is_array($value) && (strpos($value,'file:') !== false)) { 137 | $filepath = substr($value,strlen('file: ')); 138 | $filepath = Mage::getBaseDir('etc') . '/components/'.$filepath; 139 | if (file_exists($filepath)) { 140 | $value = file_get_contents($filepath); 141 | $attributeLog = false; 142 | } 143 | } 144 | 145 | // If it is a multiselect value, get the relevant IDs to save as the value 146 | if (!$this->_isStandardAttributeOption($key) && $attribute->getFrontendInput() == "multiselect") { 147 | $values = array(); 148 | foreach ($value as $optionValue) { 149 | $optionId = $this->_getAttributeOptionIdByValue($attribute,$optionValue); 150 | if (!$optionId) { 151 | throw new Exception($this->__('Cannot find option value % for attribute %s',$optionValue,$attribute)); 152 | } 153 | $values[] = $optionId; 154 | } 155 | unset($optionValue); 156 | unset($optionId); 157 | $value = $values; 158 | unset($values); 159 | } 160 | 161 | // if it is a standard select value, get the option ID to save as the value 162 | if (!$this->_isStandardAttributeOption($key) && $attribute->getFrontendInput() == "select") { 163 | $optionId = $this->_getAttributeOptionIdByValue($attribute,$value); 164 | if (!$optionId) { 165 | throw new Exception($this->__('Cannot find option value % for attribute %s',$value,$attribute)); 166 | } 167 | $value = $optionId; 168 | unset($optionId); 169 | } 170 | 171 | 172 | // If the attribute is a media image attribute 173 | if (!$this->_isStandardAttributeOption($key) && $attribute->getFrontendInput() == "media_image") { 174 | if (isset($this->_images[$value]) && file_exists($this->_images[$value])) { 175 | $product->addImageToMediaGallery($this->_images[$value], array($key), false, false); 176 | } else { 177 | $this->log($this->__('No image set in cache')); 178 | } 179 | continue; 180 | 181 | } 182 | 183 | // Save the value if not equal to the existing value 184 | if ($product->getData($key) != $value) { 185 | $product->setData($key, $value); 186 | if (is_array($value)) { 187 | $value = implode(',',$value); 188 | } 189 | if ($attributeLog) { 190 | $this->log($this->__('Product (%s) - Attribute %s -> %s', $sku, $key, $value), $child); 191 | } 192 | } 193 | unset($attribute); 194 | } 195 | unset($key); 196 | unset($value); 197 | unset($attributeLog); 198 | 199 | // Add product image if specified and the file exists 200 | // $imageLocation = Mage::getBaseDir('etc') . '/components/images/'; 201 | // 202 | // if ((isset($data['imagefile'])) && (file_exists($imageLocation . $data['imagefile']))) { 203 | // $product->setMediaGallery(array('images'=>array (), 'values'=>array ())); 204 | // $product->addImageToMediaGallery($imageLocation . $data['imagefile'], array('image', 'small_image', 'thumbnail'), false, false); 205 | // $this->log($this->__('Product (%s) - Attribute %s -> %s', $sku, 'image', $data['imagefile']),$child); 206 | // } 207 | 208 | unset($imageLocation); 209 | 210 | // Configurable product specific configuration 211 | if ($data['type_id'] == Mage_Catalog_Model_Product_Type::TYPE_CONFIGURABLE) { 212 | 213 | // Ensure we have configurable attributes 214 | if (!isset($data['configurable_attributes'])) { 215 | throw new Exception($this->__('There are no configurable attributes for %s',$sku)); 216 | } 217 | 218 | // Loop through the attributes 219 | $configurableAttributes = array(); 220 | foreach ($data['configurable_attributes'] as $configurableAttr) { 221 | $configurableAttributes[] =$this->_getAttribute($configurableAttr)->getId(); 222 | } 223 | 224 | // Associate configurable attributes to the product 225 | if ($product->getTypeInstance()->getUsedProductAttributeIds() != $configurableAttributes) { 226 | $product->getTypeInstance()->setUsedProductAttributeIds($configurableAttributes); 227 | $configurableAttributesData = $product->getTypeInstance()->getConfigurableAttributesAsArray(); 228 | 229 | 230 | $product->setCanSaveConfigurableAttributes(true); 231 | $product->setConfigurableAttributesData($configurableAttributesData); 232 | } 233 | 234 | 235 | // Associate products 236 | $configurableProductsData = array(); 237 | foreach ($data['simple_products'] as $key=>$sProductConfig) { 238 | 239 | // Need to create/update the simple product first 240 | $sData = $data; 241 | $sData['type_id'] = 'simple'; 242 | $sData['name'] = $data['name'].' - '.$sProductConfig['label']; 243 | $sData['visibility'] = Mage_Catalog_Model_Product_Visibility::VISIBILITY_NOT_VISIBLE; 244 | foreach ($sProductConfig['attributes'] as $attributeKey=>$attributeValue) { 245 | $sData[$attributeKey] = $attributeValue; 246 | } 247 | $sProduct = $this->_addUpdateProduct($sku.'-'.$key,$sData,true); 248 | 249 | 250 | // Associate the product 251 | foreach ($sProductConfig['attributes'] as $attributeKey=>$attributeValue) { 252 | $attribute = $this->_getAttribute($attributeKey); 253 | $configurableProductsData[$sProduct->getId()][] = array( 254 | 'label' => $sProductConfig['label'], 255 | 'attribute' => $attribute->getId(), 256 | 'value' => $this->_getAttributeOptionIdByValue($attribute, $attributeValue), 257 | 'is_percent' => $sProductConfig['is_percent'], 258 | 'pricing_value' => $sProductConfig['pricing_value'] 259 | ); 260 | } 261 | unset($sProductConfig['attributes']); 262 | } 263 | 264 | $product->setConfigurableProductsData($configurableProductsData); 265 | } 266 | 267 | $this->log($this->__('Preparing to save %s',$sku),$child); 268 | 269 | $product->setCreatedAt(strtotime('now')); 270 | $product->save(); 271 | $this->_images = array(); 272 | return $product; 273 | } catch (Exception $e) { 274 | $this->log($e->getMessage()); 275 | } 276 | 277 | } 278 | 279 | 280 | /** 281 | * @param array $websites 282 | * @return array 283 | */ 284 | private function _getWebsiteIds($websites) { 285 | $ids = array(); 286 | foreach ($websites as $website) { 287 | $ids[] = Mage::getResourceModel('core/website_collection') 288 | ->addFieldToFilter('code',$website) 289 | ->getFirstItem() 290 | ->getId(); 291 | } 292 | return $ids; 293 | } 294 | 295 | /** 296 | * Gets a particular attribute set 297 | * returns false if it doesn't exist 298 | * 299 | * @param $code 300 | * @return bool|Varien_Object 301 | */ 302 | private function _getAttributeSet($code) { 303 | 304 | $entityTypeId = $this->_getEntityTypeId(); 305 | 306 | $attributeSet = Mage::getResourceModel('eav/entity_attribute_set_collection') 307 | ->addFieldToFilter('entity_type_id',$entityTypeId) 308 | ->addFieldToFilter('attribute_set_name',$code) 309 | ->getFirstItem(); 310 | 311 | 312 | if ($attributeSet->getId()) { 313 | return $attributeSet; 314 | } else { 315 | return false; 316 | } 317 | } 318 | 319 | /** 320 | * Gets a particular attribute otherwise 321 | * returns false if it doesn't exist 322 | * 323 | * @param $code 324 | * @return bool|Varien_Object 325 | */ 326 | private function _getAttribute($code) { 327 | 328 | $entityTypeId = $this->_getEntityTypeId(); 329 | 330 | $attribute = Mage::getResourceModel('catalog/eav_mysql4_product_attribute_collection') 331 | ->addFieldToFilter('attribute_code',$code) 332 | ->addFieldToFilter('entity_type_id',$entityTypeId) 333 | ->getFirstItem(); 334 | 335 | if ($attribute->getId()) { 336 | return $attribute; 337 | } else { 338 | return false; 339 | } 340 | } 341 | 342 | private function _getEntityTypeId() { 343 | return Mage::getModel('catalog/product') 344 | ->getResource() 345 | ->getEntityType() 346 | ->getId(); 347 | } 348 | 349 | private function _isStandardAttributeOption($key) { 350 | return in_array($key,$this->_standardAttributes); 351 | } 352 | 353 | private function _getAttributeOptionIdByValue(Mage_Catalog_Model_Resource_Eav_Attribute $attribute,$value) { 354 | $options = $attribute->getSource()->getAllOptions(false); 355 | foreach ($options as $option) { 356 | if ($option['label'] == $value) { 357 | return $option['value']; 358 | } 359 | } 360 | return false; 361 | } 362 | 363 | private function _downloadAndPrepareImages($sku,$images) { 364 | 365 | $tmpProductsFolder = Mage::getBaseDir('media').DIRECTORY_SEPARATOR.'product-images'.DIRECTORY_SEPARATOR; 366 | 367 | if (!is_array($images)) { 368 | throw new Exception($this->__("An array of images should be supplied")); 369 | } 370 | 371 | if (!file_exists($tmpProductsFolder)) { 372 | 373 | // If the node does not have a name 374 | if (!is_numeric($tmpProductsFolder)) { 375 | 376 | // Then it is a directory so create it 377 | mkdir($tmpProductsFolder, 0755, true); 378 | $this->log("Created new media directory $tmpProductsFolder"); 379 | } 380 | } 381 | 382 | foreach ($images as $i=>$imagePath) { 383 | 384 | $pathinfo = pathinfo($imagePath); 385 | $extension = $pathinfo['extension']; 386 | $newPath = $tmpProductsFolder.$sku.'_'.$i.'.'.$extension; 387 | 388 | if (!file_exists($newPath)) { 389 | 390 | // Get the contents of the file 391 | $this->log("Downloading image file from ".$imagePath); 392 | 393 | $fileContents = file_get_contents($imagePath); 394 | 395 | // Save it in the new path 396 | file_put_contents($newPath, $fileContents); 397 | unset($fileContents); 398 | $this->log("Created new file $newPath"); 399 | } 400 | $this->_images[$i] = $newPath; 401 | } 402 | } 403 | 404 | private function _getProductDefaultSettings() { 405 | return array( 406 | 'type_id' => 'simple', 407 | 'has_options' => 0, 408 | 'required_options' => 0, 409 | 'meta_title' => '', 410 | 'meta_description' => '', 411 | 'custom_design' => null, 412 | 'page_layout' => null, 413 | 'msrp_enabled' => 2, 414 | 'msrp_display_actual_price_type' => 2, 415 | 'gift_message_available' => null, 416 | 'is_recurring' => 0, 417 | 'visibility' => 4, 418 | 'tax_class_id' => 0 419 | ); 420 | } 421 | 422 | } -------------------------------------------------------------------------------- /src/app/code/community/Cti/Configurator/Helper/Components/RelatedProducts.php: -------------------------------------------------------------------------------- 1 | _filePath1 = Mage::getBaseDir() . DS . 'app' . DS . 'etc' . DS . 'components' . DS . 'related-products.yaml'; 8 | } 9 | 10 | protected function _processFile($globalFile,$localFile = null) { 11 | if (!file_exists($globalFile)) { 12 | throw new Mage_Core_Exception("Cannot find global configuration YAML file."); 13 | } 14 | 15 | // Decode the YAML File 16 | $globalClass = new Zend_Config_Yaml($globalFile, 17 | NULL, 18 | array('ignore_constants' => true)); 19 | $globalArray = $globalClass->toArray(); 20 | 21 | return $globalArray; 22 | } 23 | 24 | protected function _processComponent($data) { 25 | if (isset($data['related'])) { 26 | 27 | foreach ($data['related'] as $mainSku=>$data) { 28 | 29 | $_productId = Mage::getModel('catalog/product')->getIdBySku($mainSku); 30 | 31 | try { 32 | 33 | if (!$_productId) { 34 | throw new Exception("Product $mainSku does not exist"); 35 | } 36 | 37 | $this->_relateProducts(Mage::getModel('catalog/product')->load($_productId),$data); 38 | } catch (Exception $e) { 39 | $this->log($e->getMessage()); 40 | } 41 | 42 | } 43 | } 44 | } 45 | 46 | private function _relateProducts(Mage_Catalog_Model_Product $_product,$data) { 47 | 48 | $this->log($this->__('Relating products for %s',$_product->getSku())); 49 | 50 | $relatableData = array(); 51 | 52 | foreach ($data as $i=>$relatedSku) { 53 | $relatedProductId = Mage::getModel('catalog/product')->getIdBySku($relatedSku); 54 | 55 | if (!$relatedProductId) { 56 | throw new Exception($this->__('No product with sku: %s'.$relatedSku)); 57 | } 58 | 59 | $relatableData[$relatedProductId] = array( 60 | 'position' => $i 61 | ); 62 | 63 | $this->log($this->__('Related %s',$relatedSku),1); 64 | 65 | } 66 | 67 | 68 | $_product->setRelatedLinkData($relatableData); 69 | $_product->save(); 70 | $this->log($this->__('Finished relating products for %s',$_product->getSku())); 71 | } 72 | 73 | } -------------------------------------------------------------------------------- /src/app/code/community/Cti/Configurator/Helper/Components/Sql.php: -------------------------------------------------------------------------------- 1 | _filePath1 = Mage::getBaseDir() . DS . 'app' . DS . 'etc' . DS . 'components' . DS . 'sql.yaml'; 10 | $this->_filePath2 = Mage::getBaseDir() . DS . 'app' . DS . 'etc' . DS . 'local_components' . DS . 'sql.yaml'; // Could be some symlinked file environment specific 11 | 12 | } 13 | 14 | protected function _processFile($globalFile, $localFile = null) 15 | { 16 | 17 | if (!file_exists($globalFile)) { 18 | $this->log("No sql component found in: " . $globalFile); 19 | $this->log("Skipping"); 20 | throw new Mage_Core_Exception("Cannot find global sql YAML file."); 21 | } 22 | 23 | // Decode the YAML File 24 | $globalClass = new Zend_Config_Yaml($globalFile, 25 | NULL, 26 | array('ignore_constants' => true)); 27 | $globalArray = $globalClass->toArray(); 28 | 29 | $localArray = array(); 30 | if (file_exists($localFile)) { 31 | // Decode the YAML File 32 | $localClass = new Zend_Config_Yaml($localFile, 33 | NULL, 34 | array('ignore_constants' => true)); 35 | $localArray = $localClass->toArray(); 36 | } 37 | 38 | $data = array_merge_recursive($globalArray, $localArray); 39 | 40 | return $data; 41 | } 42 | 43 | protected function _processComponent($data) { 44 | if (!isset($data['sql'])) { 45 | return; 46 | } 47 | 48 | foreach ($data['sql'] as $file) { 49 | try { 50 | $path = Mage::getBaseDir().$file; 51 | if (!file_exists($path)) { 52 | throw new Exception($file.' does not exist for SQL execution'); 53 | } 54 | 55 | $resource = Mage::getSingleton('core/resource'); 56 | $writeConnection = $resource->getConnection('core_write'); 57 | $query = file_get_contents($path); 58 | $writeConnection->query($query); 59 | 60 | $this->log($this->__("Executed sql script %s",$file)); 61 | 62 | } catch (Exception $e) { 63 | $this->log($this->__("Error executing script %s: %s",$file,$e->getMessage())); 64 | throw new Exception($e->getMessage()); 65 | } 66 | } 67 | } 68 | } -------------------------------------------------------------------------------- /src/app/code/community/Cti/Configurator/Helper/Components/StaticBlocks.php: -------------------------------------------------------------------------------- 1 | _componentName = 'staticblocks'; 7 | $this->_filePath1 = Mage::getBaseDir() . DS . 'app' . DS . 'etc' . DS . 'components' . DS . 'static-blocks.yaml'; 8 | } 9 | 10 | protected function _processFile($globalFile, $localFile = null) 11 | { 12 | 13 | if (!file_exists($globalFile)) { 14 | throw new Mage_Core_Exception("Cannot find static blocks configuration YAML file."); 15 | } 16 | 17 | // Decode the YAML File 18 | $globalClass = new Zend_Config_Yaml($globalFile, 19 | NULL, 20 | array('ignore_constants' => true)); 21 | 22 | $globalArray = $globalClass->toArray(); 23 | 24 | 25 | return $globalArray; 26 | } 27 | 28 | protected function _processComponent($data) { 29 | 30 | // Check if there is a block node in the yaml 31 | if (isset($data['blocks'])) { 32 | 33 | // Loop through its children 34 | foreach ($data['blocks'] as $identifier => $blockData) { 35 | 36 | try { 37 | 38 | // Ensure identifier is set 39 | if (is_numeric($identifier)) { 40 | throw new Exception("Please refer to sample content for see how the block identifier is set."); 41 | } 42 | 43 | // Try load existing block 44 | if (!isset($blockData['contents'])) { 45 | throw new Exception("Could not find the block contents"); 46 | } 47 | 48 | // If the all attribute is set then this will be a global block. 49 | if (isset($blockData['contents']['all'])) { 50 | $block = Mage::getResourceModel('cms/block_collection') 51 | ->addStoreFilter(0) 52 | ->addFieldToFilter('identifier',$identifier) 53 | ->getFirstItem(); 54 | 55 | $storeBlockData = array_merge_recursive($blockData,$blockData['contents']['all']); 56 | 57 | $this->_processBlock($identifier,$block,$storeBlockData); 58 | 59 | } elseif (is_array($blockData['contents'])) { 60 | 61 | // Loop through the different versions of the content 62 | foreach ($blockData['contents'] as $i=>$content) { 63 | 64 | // Check if we have an index 65 | if (!is_numeric($i)) { 66 | throw new Exception("A textual index for the content should not be defined. Use 'all' or none"); 67 | } 68 | 69 | // Check if we have store view(s) set 70 | if (!isset($content['stores']) || !is_array($content['stores'])) { 71 | throw new Exception("Store views are not correctly set on $identifier"); 72 | } 73 | 74 | $blocks = Mage::getResourceModel('cms/block_collection') 75 | ->addFieldToFilter('identifier',$identifier); 76 | 77 | if ($blocks->count()) { 78 | $blocksArray = array_values($blocks->getItems()); 79 | if (isset($blocksArray[$i])) { 80 | $block = $blocksArray[$i]; 81 | } else { 82 | $block = Mage::getModel('cms/block'); 83 | } 84 | } else { 85 | $block = Mage::getModel('cms/block'); 86 | } 87 | 88 | $storeBlockData = array_merge_recursive($blockData,$content); 89 | 90 | $this->_processBlock($identifier,$block,$storeBlockData); 91 | 92 | unset($storeIds); 93 | } 94 | } 95 | 96 | } catch (Exception $e) { 97 | 98 | $this->log($e->getMessage()); 99 | } 100 | } 101 | } 102 | } 103 | 104 | private function _processBlock($identifier,Mage_Cms_Model_Block $block,$data) { 105 | $canSave = false; 106 | 107 | // Load block model 108 | if (!$block->getId()) { 109 | $block = Mage::getModel('cms/block'); 110 | $block->setIdentifier($identifier); 111 | } 112 | 113 | unset($data['contents']); 114 | 115 | if (isset($data['stores'])) { 116 | 117 | // Loop through the store view names to get its corresponding ID 118 | $storeIds = array(); 119 | foreach ($data['stores'] as $storeViewName) { 120 | $store = Mage::getModel('core/store')->load($storeViewName,'code'); 121 | if (!$store->getId()) { 122 | throw new Exception("Store View Name: $storeViewName does not exist for $identifier"); 123 | } 124 | $storeIds[] = $store->getId(); 125 | unset($store); 126 | } 127 | unset($storeViewName); 128 | 129 | // @todo check what stores it is associated to already 130 | $oldStoreIds = Mage::getModel('cms/block')->load($block->getId())->getStoreId(); 131 | 132 | sort($storeIds); 133 | if ($oldStoreIds != $storeIds) { 134 | $canSave = true; 135 | $block->setStores($storeIds); 136 | } 137 | 138 | unset($oldStoreIds); 139 | unset($storeIds); 140 | unset($data['stores']); 141 | } else { 142 | 143 | $block->setStores(array(0)); 144 | } 145 | 146 | // Loop through block attributes 147 | foreach ($data as $key=>$value) { 148 | 149 | // content file attribute would require to read it from a file 150 | if ($key == "content_file") { 151 | 152 | // If a value/path is set then get its contents 153 | if ($value != "") { 154 | 155 | // locate file path 156 | $filePath = Mage::getBaseDir() . DS . 'app' . DS . 'etc' . DS . 'components' . DS . 'html' . DS . $value; 157 | 158 | // Check if the file exists 159 | if (file_exists($filePath)) { 160 | 161 | // Get the contents of the file and save it as the value 162 | $value = file_get_contents($filePath); 163 | 164 | unset($filePath); 165 | 166 | $key = 'content'; 167 | } else { 168 | throw new Exception("No file found in $filePath"); 169 | } 170 | 171 | } else { 172 | continue; 173 | } 174 | } 175 | 176 | // If the value is already equal to the value in the database, skip it 177 | if ($block->getData($key) == $value) { 178 | continue; 179 | } 180 | 181 | $canSave = true; 182 | $block->setData($key,$value); 183 | $this->log("Setting block attribute $key to $value for $identifier"); 184 | 185 | } 186 | 187 | if ($canSave) { 188 | $block->save(); 189 | $this->log("Saved block $identifier"); 190 | } 191 | } 192 | } -------------------------------------------------------------------------------- /src/app/code/community/Cti/Configurator/Helper/Components/Tax.php: -------------------------------------------------------------------------------- 1 | 0, 8 | 'tax_postcode' => '*', 9 | 'zip_is_range' => null, 10 | 'zip_from' => null, 11 | 'zip_to' => null 12 | ); 13 | 14 | public function __construct() 15 | { 16 | 17 | $this->_filePath1 = Mage::getBaseDir() . DS . 'app' . DS . 'etc' . DS . 'components' . DS . 'tax.yaml'; 18 | 19 | } 20 | 21 | protected function _processFile($globalFile, $localFile = null) 22 | { 23 | if (!file_exists($globalFile)) { 24 | throw new Mage_Core_Exception("Cannot find global configuration YAML file."); 25 | } 26 | 27 | // Decode the YAML File 28 | $globalClass = new Zend_Config_Yaml($globalFile, 29 | NULL, 30 | array('ignore_constants' => true)); 31 | $globalArray = $globalClass->toArray(); 32 | 33 | return $globalArray; 34 | } 35 | 36 | protected function _processComponent($data) 37 | { 38 | 39 | // Loop through the customer classes 40 | if (isset($data['customer_classes'])) { 41 | foreach ($data['customer_classes'] as $customerClass) { 42 | $this->_addTaxClass($customerClass,Mage_Tax_Model_Class::TAX_CLASS_TYPE_CUSTOMER); 43 | } 44 | } 45 | 46 | // Loop through the product classes 47 | if (isset($data['product_classes'])) { 48 | foreach ($data['product_classes'] as $productClass) { 49 | $this->_addTaxClass($productClass,Mage_Tax_Model_Class::TAX_CLASS_TYPE_PRODUCT); 50 | } 51 | } 52 | 53 | // Loop through the tax rates 54 | if (isset($data['rates'])) { 55 | foreach ($data['rates'] as $code => $rate) { 56 | $this->_addRate($code,$rate); 57 | } 58 | } 59 | 60 | // Loop through the tax rules 61 | if (isset($data['rules'])) { 62 | foreach ($data['rules'] as $rule) { 63 | $this->_addRule($rule); 64 | } 65 | } 66 | } 67 | 68 | private function _addTaxClass($name, $type) { 69 | $taxClasses = Mage::getResourceModel('tax/class_collection') 70 | ->addFieldToFilter('class_type',$type) 71 | ->addFieldToFilter('class_name',$name); 72 | 73 | if ($taxClasses->count() == 0) { 74 | try { 75 | Mage::getModel('tax/class') 76 | ->setClassType($type) 77 | ->setClassName($name) 78 | ->save(); 79 | 80 | $this->log($this->__('Added new %s tax class %s',strtolower($type),$name)); 81 | } catch (Exception $e) { 82 | $this->log($e->getMessage()); 83 | } 84 | } 85 | } 86 | 87 | private function _addRate($code,$data) { 88 | $taxRate = Mage::getModel('tax/calculation_rate')->load($code,'code'); 89 | if (!$taxRate->getId()) { 90 | $taxRate = Mage::getModel('tax/calculation_rate')->setCode($code); 91 | } 92 | $toSave = false; 93 | $data = array_merge_recursive($data,$this->_defaultRate); 94 | foreach ($data as $key=>$value) { 95 | if ($taxRate->getData($key) == $value) { 96 | continue; 97 | } 98 | if ($key == "tax_country_id" && $value == "Norway") { 99 | $value = "NO"; 100 | } 101 | $taxRate->setData($key,$value); 102 | $this->log($this->__('Setting tax rate %s attribute %s to %s',$code,$key,$value)); 103 | $toSave = true; 104 | } 105 | if ($toSave) { 106 | try { 107 | $taxRate->save(); 108 | } catch (Exception $e) { 109 | $this->log($e->getMessage()); 110 | } 111 | } 112 | } 113 | 114 | private function _addRule($data) { 115 | 116 | $taxRules = Mage::getResourceModel('tax/calculation_rule_collection') 117 | ->addFieldToFilter('code',$data['code']); 118 | if ($taxRules->count()) { 119 | $taxRule = $taxRules->getFirstItem(); 120 | } else { 121 | $taxRule = Mage::getModel('tax/calculation_rule'); 122 | } 123 | 124 | unset($taxRules); 125 | 126 | $data = array_merge_recursive($data,array('priority'=> 1,'position' => 1)); 127 | $toSave = false; 128 | foreach ($data as $key=>$value) { 129 | if ($key == "tax_rate" || $key == "customer_tax_class" || $key == "product_tax_class") { 130 | continue; 131 | } 132 | if ($taxRule->getData($key) == $value) { 133 | continue; 134 | } 135 | $taxRule->setData($key,$value); 136 | $this->log($this->__('Setting tax rule attribute %s to %s',$key,$value)); 137 | $toSave = true; 138 | } 139 | if ($toSave) { 140 | try { 141 | $taxRule->save(); 142 | } catch (Exception $e) { 143 | $this->log($e->getMessage()); 144 | } 145 | } 146 | 147 | 148 | // Link up the tax rules and classes 149 | try { 150 | foreach ($data['tax_rate'] as $code) { 151 | $rateId = Mage::getModel('tax/calculation_rate')->load($code,'code')->getId(); 152 | if (!$rateId) { 153 | throw new Exception($this->__('There is no rate for country code %s',$code)); 154 | } 155 | foreach ($data['customer_tax_class'] as $_customerClass) { 156 | $customerClass = $this->_getTaxClass($_customerClass,Mage_Tax_Model_Class::TAX_CLASS_TYPE_CUSTOMER); 157 | if (!$customerClass) { 158 | throw new Exception($this->__('There is no customer class found for %s',$_customerClass)); 159 | } 160 | foreach ($data['product_tax_class'] as $_productClass) { 161 | $productClass = $this->_getTaxClass($_productClass,Mage_Tax_Model_Class::TAX_CLASS_TYPE_PRODUCT); 162 | if (!$productClass) { 163 | throw new Exception($this->__('There is no product class found for %s',$_productClass)); 164 | } 165 | 166 | // Create new Tax Rule 167 | try { 168 | $taxCalculationCollection = Mage::getResourceModel('tax/calculation_collection') 169 | ->addFieldToFilter('tax_calculation_rate_id',$rateId) 170 | ->addFieldToFilter('tax_calculation_rule_id',$taxRule->getId()) 171 | ->addFieldToFilter('customer_tax_class_id',$customerClass->getId()) 172 | ->addFieldToFilter('product_tax_class_id',$productClass->getId()); 173 | 174 | if (!$taxCalculationCollection->count()) { 175 | $taxCalculation = Mage::getModel('tax/calculation') 176 | ->setTaxCalculationRateId($rateId) 177 | ->setTaxCalculationRuleId($taxRule->getId()) 178 | ->setCustomerTaxClassId($customerClass->getId()) 179 | ->setProductTaxClassId($productClass->getId()) 180 | ->save(); 181 | 182 | $this->log($this->__('Created tax rule %s', $taxCalculation->getId())); 183 | } 184 | } catch (Exception $e) { 185 | $this->__($e->getMessage()); 186 | } 187 | 188 | } 189 | } 190 | } 191 | } catch (Exception $e) { 192 | $this->log($e->getMessage()); 193 | } 194 | 195 | 196 | 197 | } 198 | 199 | /** 200 | * @param $name 201 | * @param $type 202 | * 203 | * @return Mage_Tax_Model_Class 204 | */ 205 | private function _getTaxClass($name,$type) { 206 | $taxClasses = Mage::getResourceModel('tax/class_collection') 207 | ->addFieldToFilter('class_type',$type) 208 | ->addFieldToFilter('class_name',$name); 209 | if ($taxClasses->count()) { 210 | return $taxClasses->getFirstItem(); 211 | } 212 | return false; 213 | } 214 | } -------------------------------------------------------------------------------- /src/app/code/community/Cti/Configurator/Helper/Components/Users.php: -------------------------------------------------------------------------------- 1 | _filePath1 = Mage::getBaseDir() . DS . 'app' . DS . 'etc' . DS . 'components' . DS . 'users.yaml'; 10 | 11 | } 12 | 13 | protected function _processFile($globalFile, $localFile = null) 14 | { 15 | if (!file_exists($globalFile)) { 16 | throw new Mage_Core_Exception("Cannot find global configuration YAML file."); 17 | } 18 | 19 | // Decode the YAML File 20 | $globalClass = new Zend_Config_Yaml($globalFile, 21 | NULL, 22 | array('ignore_constants' => true)); 23 | $globalArray = $globalClass->toArray(); 24 | 25 | return $globalArray; 26 | } 27 | 28 | protected function _processComponent($data) 29 | { 30 | 31 | // Loop through the soap users and roles 32 | if (isset($data['soap'])) { 33 | if (isset($data['soap']['roles'])) { 34 | $this->_addSoapRoles($data['soap']['roles']); 35 | } 36 | if (isset($data['soap']['users'])) { 37 | $this->_addSoapUsers($data['soap']['users']); 38 | } 39 | } 40 | 41 | // @todo Loop through the rest users and roles 42 | if (isset($data['rest'])) { 43 | $this->log('Todo - support for rests api users'); 44 | } 45 | 46 | // @todo Loop through the admin users and roles 47 | if (isset($data['admin'])) { 48 | $this->log('Todo - support for admin users'); 49 | } 50 | } 51 | 52 | private function _addSoapUsers($users) { 53 | foreach ($users as $username=>$data) { 54 | try { 55 | 56 | $canSave = false; 57 | 58 | $user = Mage::getModel('api/user')->load($username,'username'); 59 | 60 | if (!$user->getId()) { 61 | $user = Mage::getModel('api/user'); 62 | $user->setUsername($username); 63 | $canSave = true; 64 | } 65 | 66 | foreach ($data as $key => $value) { 67 | 68 | if ($key == "role") { 69 | continue; 70 | } 71 | 72 | if ($user->getData($key) == $value) { 73 | continue; 74 | } 75 | 76 | $user->setData($key,$value); 77 | $canSave = true; 78 | $this->log($this->__('Set soap user record for %s key %s to value %s',$username,$key,$value)); 79 | } 80 | 81 | if ($canSave) { 82 | $user->save(); 83 | $this->log('Saved soap user '.$username); 84 | } 85 | 86 | if (isset($data['role'])) { 87 | try { 88 | 89 | $parentRole = Mage::getResourceModel('api/role_collection') 90 | ->addFieldToFilter('role_name',$data['role']) 91 | ->getFirstItem(); 92 | 93 | if (!$parentRole->getId()) { 94 | throw new Exception('No role name for '.$data['role']); 95 | } 96 | 97 | $userRole = Mage::getResourceModel('api/role_collection') 98 | ->addFieldToFilter('role_name',$username) 99 | ->getFirstItem(); 100 | 101 | 102 | if (!$userRole->getId()) { 103 | $userRole = Mage::getModel('api/role') 104 | ->setRoleName($username); 105 | 106 | $this->log($this->__('New user role for %s',$username)); 107 | } 108 | 109 | $userRole 110 | ->setParentId($parentRole->getId()) 111 | ->setRoleType('U') 112 | ->setTreeLevel(1) 113 | ->setUserId($user->getId()) 114 | ->save(); 115 | 116 | } catch (Exception $e) { 117 | $this->log($e->getMessage()); 118 | } 119 | } 120 | 121 | } catch (Exception $e) { 122 | $this->log($e->getMessage()); 123 | } 124 | } 125 | } 126 | 127 | private function _addSoapRoles($roles) { 128 | foreach ($roles as $roleName=>$data) { 129 | try { 130 | 131 | $canSave = false; 132 | 133 | $role = Mage::getResourceModel('api/role_collection') 134 | ->addFieldToFilter('role_name',$roleName) 135 | ->getFirstItem(); 136 | 137 | if (!$role->getId()){ 138 | $role = Mage::getModel('api/role'); 139 | $role->setRoleName($roleName); 140 | $canSave = true; 141 | } 142 | 143 | foreach ($data as $key=>$value) { 144 | if ($key == "rules") { 145 | continue; 146 | } 147 | 148 | if ($role->getData($key) == $value) { 149 | continue; 150 | } 151 | 152 | $role->setData($key,$value); 153 | $canSave = true; 154 | $this->log($this->__('Set soap role record for %s key %s to value $s',$roleName,$key,$value)); 155 | } 156 | 157 | if ($canSave) { 158 | $role->save(); 159 | $this->log('Saved role '.$roleName); 160 | } 161 | 162 | $this->_addSoapRules($role,$data['rules']); 163 | } catch (Exception $e) { 164 | $this->log($e->getMessage()); 165 | } 166 | } 167 | } 168 | 169 | private function _addSoapRules(Mage_Api_Model_Role $role,$rules) { 170 | foreach ($rules as $data) { 171 | try { 172 | $canSave = false; 173 | 174 | $rule = Mage::getResourceModel('api/rules_collection') 175 | ->addFieldToFilter('role_id',$role->getId()) 176 | ->addFieldToFilter('resource_id',$data['resource_id']) 177 | ->getFirstItem(); 178 | 179 | if (!$rule->getId()) { 180 | $rule = Mage::getModel('api/rules'); 181 | $rule->setRoleId($role->getId()); 182 | $canSave = true; 183 | } 184 | 185 | foreach ($data as $key=>$value) { 186 | if ($rule->getData($key) == $value) { 187 | continue; 188 | } 189 | $rule->setData($key,$value); 190 | $canSave = true; 191 | $this->log($this->__('Set soap rule record for role %s key %s to value %s',$role->getRoleName(),$key,$value),1); 192 | } 193 | 194 | if ($canSave) { 195 | $rule->save(); 196 | $this->log('Saved rule for '.$role->getRoleName().' - '.$data['resource_id'],1); 197 | } 198 | 199 | } catch (Exception $e) { 200 | $this->log($e->getMessage()); 201 | } 202 | } 203 | } 204 | } -------------------------------------------------------------------------------- /src/app/code/community/Cti/Configurator/Helper/Components/Website.php: -------------------------------------------------------------------------------- 1 | _filePath1 = Mage::getBaseDir().DS.'app'.DS.'etc'.DS.'components'.DS.'websites.yaml'; 9 | 10 | } 11 | 12 | protected function _processFile($globalFile,$localFile = null) { 13 | 14 | if (!file_exists($globalFile)) { 15 | $this->log("No website configuration found in: " . $globalFile); 16 | $this->log("Skipping"); 17 | throw new Mage_Core_Exception("Cannot find website configuration YAML file."); 18 | } 19 | 20 | // Decode the YAML File 21 | $globalClass = new Zend_Config_Yaml($globalFile, 22 | NULL, 23 | array('ignore_constants' => true)); 24 | $globalArray = $globalClass->toArray(); 25 | 26 | $localArray = array(); 27 | if (file_exists($localFile)) { 28 | // Decode the YAML File 29 | $localClass = new Zend_Config_Yaml($localFile, 30 | NULL, 31 | array('ignore_constants' => true)); 32 | $localArray = $localClass->toArray(); 33 | } 34 | 35 | $data = array_merge_recursive($globalArray,$localArray); 36 | 37 | return $data; 38 | } 39 | 40 | protected function _processComponent($data) { 41 | 42 | if (isset($data['websites'])) { 43 | 44 | $websiteCount = 1; 45 | 46 | // Process websites 47 | foreach ($data['websites'] as $code=>$config) { 48 | $website = $this->__addUpdateWebsite($config,$code,$websiteCount); 49 | 50 | foreach($config['store_groups'] as $sgConfig) { 51 | 52 | if (isset($sgConfig['root_category'])) { 53 | $sgConfig['root_category_id'] = $this->_getOrCreateCategoryByName($sgConfig['root_category'])->getId(); 54 | } 55 | 56 | $storeGroup = $this->__addUpdateStoreGroup($sgConfig,$website); 57 | 58 | $storeCount = 1; 59 | foreach ($sgConfig['stores'] as $code=>$sConfig) { 60 | 61 | // Increment Sort Order 62 | $sConfig['sort_order'] = $storeCount; 63 | $sConfig['code'] = $code; 64 | $this->__addUpdateStore($sConfig,$storeGroup); 65 | $storeCount++; 66 | } 67 | } 68 | 69 | $websiteCount++; 70 | } 71 | } 72 | 73 | } 74 | 75 | protected function _getOrCreateCategoryByName($name) { 76 | $categories = Mage::getResourceModel('catalog/category_collection') 77 | ->addAttributeToFilter('name',$name) 78 | ->addFieldToFilter('level',1); 79 | 80 | if (!$categories->count()) { 81 | 82 | $category = Mage::getModel('catalog/category') 83 | ->setStoreId(0) 84 | ->setName($name) 85 | ->setPath(1) 86 | ->setDisplayMode("PRODUCTS") 87 | ->setIsActive(1) 88 | ->save(); 89 | } else { 90 | 91 | $category = $categories->getFirstItem(); 92 | } 93 | 94 | return $category; 95 | } 96 | 97 | 98 | /** 99 | * @param array $config 100 | * @param string $code 101 | * @param int $sortOrder 102 | * @return Mage_Core_Model_Website 103 | */ 104 | private function __addUpdateWebsite($config,$code,$sortOrder){ 105 | 106 | // See if the website exists otherwise create the website 107 | $website = Mage::getModel('core/website')->load($code,'code'); 108 | if ($website->getId()) { 109 | if ($website->getName() != $config['name'] || $website->getSortOrder() != $sortOrder) { 110 | $website->setName($config['name']) 111 | ->setSortOrder($sortOrder) 112 | ->save(); 113 | $this->log("Updated website ".$website->getCode()); 114 | } 115 | } else { 116 | $website = Mage::getModel('core/website'); 117 | $website->setCode($code) 118 | ->setName($config['name']) 119 | ->setSortOrder($sortOrder) 120 | ->save(); 121 | 122 | $this->log("Created website ".$website->getCode()." with name ".$website->getName()); 123 | } 124 | return $website; 125 | } 126 | 127 | /** 128 | * @param array $sgConfig 129 | * @param Mage_Core_Model_Website $website 130 | * @return Mage_Core_Model_Store_Group 131 | */ 132 | private function __addUpdateStoreGroup($sgConfig,$website) { 133 | 134 | // See if the store group exists otherwise create a store group 135 | $storeGroup = Mage::getModel('core/store_group')->load($sgConfig['name'],'name'); 136 | if ($storeGroup->getId()) { 137 | 138 | if ($storeGroup->getWebsiteId() != $website->getId() 139 | || $storeGroup->getRootCategoryId() != $sgConfig['root_category_id']) { 140 | 141 | $storeGroup->setWebsiteId($website->getId()) 142 | ->setRootCategoryId($sgConfig['root_category_id']) 143 | ->save(); 144 | $this->log("Updated store group " . $storeGroup->getName()); 145 | } 146 | } else { 147 | $storeGroup = Mage::getModel('core/store_group'); 148 | $storeGroup->setWebsiteId($website->getId()) 149 | ->setName($sgConfig['name']) 150 | ->setRootCategoryId($sgConfig['root_category_id']) 151 | ->save(); 152 | 153 | $this->log("Created store group ".$storeGroup->getName()); 154 | } 155 | return $storeGroup; 156 | } 157 | 158 | /** 159 | * @param array $sConfig 160 | * @param Mage_Core_Model_Store_Group $storeGroup 161 | * @return Mage_Core_Model_Store 162 | */ 163 | private function __addUpdateStore($sConfig,$storeGroup) { 164 | 165 | // See if the store exists otherwise create a store 166 | $store = Mage::getModel('core/store')->load($sConfig['code'],'code'); 167 | if ($store->getId()) { 168 | 169 | if ($store->getWebsiteId() != $storeGroup->getWebsiteId() 170 | || $store->getGroupId() != $storeGroup->getId() 171 | || $store->getName() != $sConfig['name'] 172 | || $store->getIsActive() != (isset($sConfig['active'])? $sConfig['active']:1) 173 | || $store->getSortOrder() != $sConfig['sort_order']) { 174 | 175 | $store->setWebsiteId($storeGroup->getWebsiteId()) 176 | ->setGroupId($storeGroup->getId()) 177 | ->setName($sConfig['name']) 178 | ->setIsActive(isset($sConfig['active']) ? $sConfig['active'] : 1) 179 | ->setSortOrder($sConfig['sort_order']) 180 | ->save(); 181 | 182 | $this->log("Updated store " . $store->getCode()); 183 | } 184 | } else { 185 | $store = Mage::getModel('core/store'); 186 | $store->setCode($sConfig['code']) 187 | ->setWebsiteId($storeGroup->getWebsiteId()) 188 | ->setGroupId($storeGroup->getId()) 189 | ->setName($sConfig['name']) 190 | ->setIsActive(isset($sConfig['active'])? $sConfig['active']:1) 191 | ->setSortOrder($sConfig['sort_order']) 192 | ->save(); 193 | 194 | $this->log("Created store ".$store->getCode()." with name ".$store->getName()); 195 | } 196 | return $store; 197 | } 198 | } -------------------------------------------------------------------------------- /src/app/code/community/Cti/Configurator/Helper/Data.php: -------------------------------------------------------------------------------- 1 | getNode('global/configurator_processors'); 6 | if ($config->hasChildren()) { 7 | foreach ($config->asArray() as $class) { 8 | foreach ($class as $alias) { 9 | /* @var $helper Cti_Configurator_Helper_Components_Abstract */ 10 | $helper = Mage::helper($alias); 11 | if ($cliLogging) $helper->enableCliLog(); 12 | $helper->process(); 13 | } 14 | } 15 | } 16 | } 17 | 18 | public function processComponent($component, $cliLogging = false) { 19 | 20 | $node = 'global/configurator_processors/components/'.$component; 21 | $config = Mage::getConfig()->getNode($node); 22 | 23 | /* @var $helper Cti_Configurator_Helper_Components_Abstract */ 24 | $helper = Mage::helper($config); 25 | if ($cliLogging) $helper->enableCliLog(); 26 | $helper->process(); 27 | } 28 | 29 | public function getComponents() { 30 | $components = array(); 31 | $config = Mage::getConfig()->getNode('global/configurator_processors'); 32 | if ($config->hasChildren()) { 33 | foreach ($config->asArray() as $class) { 34 | foreach($class as $alias=>$name) { 35 | $components[] = $alias; 36 | } 37 | } 38 | } 39 | return $components; 40 | } 41 | } -------------------------------------------------------------------------------- /src/app/code/community/Cti/Configurator/etc/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 0.9.0 6 | 7 | 8 | 9 | 10 | 11 | Cti_Configurator_Helper 12 | 13 | 14 | 15 | 16 | cti_configurator/components_website 17 | cti_configurator/components_config 18 | cti_configurator/components_attributes 19 | cti_configurator/components_attributeSets 20 | cti_configurator/components_products 21 | cti_configurator/components_categories 22 | cti_configurator/components_relatedProducts 23 | cti_configurator/components_tax 24 | cti_configurator/components_customerGroups 25 | cti_configurator/components_media 26 | cti_configurator/components_pages 27 | cti_configurator/components_staticBlocks 28 | cti_configurator/components_users 29 | cti_configurator/components_sql 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /src/app/etc/modules/Cti_Configurator.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | true 6 | community 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/shell/configurator.php: -------------------------------------------------------------------------------- 1 | getArg('run-components')) { 12 | $this->_components = array_merge( 13 | $this->_components, 14 | array_map( 15 | 'trim', 16 | explode(',', $this->getArg('run-components')) 17 | ) 18 | ); 19 | } 20 | } 21 | 22 | public function run() { 23 | 24 | $helper = Mage::helper('cti_configurator'); 25 | 26 | if ($this->getArg('list-components')) { 27 | 28 | foreach ($helper->getComponents() as $i=>$component) { 29 | echo $i.') '.$component.PHP_EOL; 30 | } 31 | 32 | } else if ($this->getArg('run-components')) { 33 | 34 | // Loop through components 35 | foreach ($this->_components as $component) { 36 | $helper->processComponent($component,true); 37 | } 38 | 39 | } else { 40 | 41 | // Process the rest of the components 42 | $helper->processComponents(true); 43 | } 44 | 45 | } 46 | 47 | // Usage instructions 48 | public function usageHelp() { 49 | return << Run specific components, comma separated 55 | 56 | help This help 57 | 58 | USAGE; 59 | } 60 | } 61 | $shell = new Cti_Configurator_Shell(); 62 | $shell->run(); --------------------------------------------------------------------------------