magento-full-catalog-translate - Version 0.2.0

Version Notes

First public release

Download this release

Release Info

Developer Fabrizio Balliano
Extension magento-full-catalog-translate
Version 0.2.0
Comparing to
See all releases


Version 0.2.0

Files changed (81) hide show
  1. app/code/community/Fballiano/FullCatalogTranslate/Helper/Data.php +45 -0
  2. app/code/community/Fballiano/FullCatalogTranslate/etc/adminhtml.xml +22 -0
  3. app/code/community/Fballiano/FullCatalogTranslate/etc/config.xml +30 -0
  4. app/code/community/Fballiano/FullCatalogTranslate/etc/system.xml +45 -0
  5. app/code/community/Fballiano/FullCatalogTranslate/sql/fballiano_fullcatalogtranslate_setup/install-0.1.0.php +52 -0
  6. app/etc/modules/Fballiano_FullCatalogTranslate.xml +12 -0
  7. lib/Magmi/ReleaseNotes.txt +67 -0
  8. lib/Magmi/conf/magmi.ini +2 -0
  9. lib/Magmi/conf/plugins.conf +0 -0
  10. lib/Magmi/engines/magmi_productimportengine.php +1678 -0
  11. lib/Magmi/engines/magmi_utilityengine.php +84 -0
  12. lib/Magmi/inc/dbhelper.class.php +593 -0
  13. lib/Magmi/inc/dbhelper.class.php~ +589 -0
  14. lib/Magmi/inc/fshelper.php +370 -0
  15. lib/Magmi/inc/license.txt +19 -0
  16. lib/Magmi/inc/magmi_config.php +278 -0
  17. lib/Magmi/inc/magmi_csvreader.php +243 -0
  18. lib/Magmi/inc/magmi_defs.php +10 -0
  19. lib/Magmi/inc/magmi_engine.php +453 -0
  20. lib/Magmi/inc/magmi_loggers.php +53 -0
  21. lib/Magmi/inc/magmi_mixin.php +44 -0
  22. lib/Magmi/inc/magmi_pluginhelper.php +202 -0
  23. lib/Magmi/inc/magmi_postinstall.php +41 -0
  24. lib/Magmi/inc/magmi_statemanager.php +74 -0
  25. lib/Magmi/inc/magmi_utils.php +149 -0
  26. lib/Magmi/inc/magmi_version.php +5 -0
  27. lib/Magmi/inc/properties.php +202 -0
  28. lib/Magmi/integration/inc/magmi_datapump.php +37 -0
  29. lib/Magmi/integration/inc/magmi_datapumpdatasource.php +18 -0
  30. lib/Magmi/integration/inc/productimport_datapump.php +84 -0
  31. lib/Magmi/integration/inc/pumpfactory.ini +2 -0
  32. lib/Magmi/integration/samples/sample.php +117 -0
  33. lib/Magmi/integration/samples/sample2_configurables.php +79 -0
  34. lib/Magmi/plugins/base/datasources/__magento/magmi_magentodatasource.php +90 -0
  35. lib/Magmi/plugins/base/datasources/__magento/options_panel.php +6 -0
  36. lib/Magmi/plugins/base/datasources/csv/csvds_filelist.php +17 -0
  37. lib/Magmi/plugins/base/datasources/csv/magmi_csvdatasource.php +274 -0
  38. lib/Magmi/plugins/base/datasources/csv/options_panel.php +142 -0
  39. lib/Magmi/plugins/base/datasources/genericsql/mysql_options.php +28 -0
  40. lib/Magmi/plugins/base/datasources/genericsql/options_panel.php +45 -0
  41. lib/Magmi/plugins/base/datasources/genericsql/other_options.php +15 -0
  42. lib/Magmi/plugins/base/datasources/genericsql/sql_datasource.php +138 -0
  43. lib/Magmi/plugins/base/general/emailreport/emailreport.php +133 -0
  44. lib/Magmi/plugins/base/general/emailreport/options_panel.php +29 -0
  45. lib/Magmi/plugins/base/general/importurl/importurl_plugin.php +15 -0
  46. lib/Magmi/plugins/base/general/importurl/options_panel.php +63 -0
  47. lib/Magmi/plugins/base/general/optimizer/magmi_optimizer_plugin.php +42 -0
  48. lib/Magmi/plugins/base/general/reindex/magmi_reindexing_plugin.php +117 -0
  49. lib/Magmi/plugins/base/general/reindex/options_panel.php +49 -0
  50. lib/Magmi/plugins/base/itemprocessors/columnmapper/000_columnmapper.php +115 -0
  51. lib/Magmi/plugins/base/itemprocessors/columnmapper/options_panel.php +22 -0
  52. lib/Magmi/plugins/base/itemprocessors/configurables/magmi_configurableprocessor.php +368 -0
  53. lib/Magmi/plugins/base/itemprocessors/configurables/options_panel.php +34 -0
  54. lib/Magmi/plugins/base/itemprocessors/defaultvalues/00_default_values.php +100 -0
  55. lib/Magmi/plugins/base/itemprocessors/defaultvalues/options_panel.php +22 -0
  56. lib/Magmi/plugins/base/itemprocessors/genericmapper/02_genericmapper.php +123 -0
  57. lib/Magmi/plugins/base/itemprocessors/genericmapper/mappings/default/__common__.csv +2 -0
  58. lib/Magmi/plugins/base/itemprocessors/genericmapper/mappings/default/options_container.csv +2 -0
  59. lib/Magmi/plugins/base/itemprocessors/genericmapper/mappings/default/page_layout.csv +6 -0
  60. lib/Magmi/plugins/base/itemprocessors/genericmapper/mappings/default/status.csv +2 -0
  61. lib/Magmi/plugins/base/itemprocessors/genericmapper/mappings/default/visibility.csv +4 -0
  62. lib/Magmi/plugins/base/itemprocessors/genericmapper/options_panel.php +7 -0
  63. lib/Magmi/plugins/base/itemprocessors/grouped/alpine_groupedprocessor.php +227 -0
  64. lib/Magmi/plugins/base/itemprocessors/grouped/options_panel.php +60 -0
  65. lib/Magmi/plugins/base/itemprocessors/importlimiter/01_importlimiter.php +172 -0
  66. lib/Magmi/plugins/base/itemprocessors/importlimiter/options_panel.php +48 -0
  67. lib/Magmi/plugins/base/itemprocessors/productdeleter/options_panel.php +9 -0
  68. lib/Magmi/plugins/base/itemprocessors/productdeleter/productdeleter.php +60 -0
  69. lib/Magmi/plugins/base/itemprocessors/related/related_products.php +301 -0
  70. lib/Magmi/plugins/base/itemprocessors/skufinder/001_skufinder.php +95 -0
  71. lib/Magmi/plugins/base/itemprocessors/skufinder/options_panel.php +13 -0
  72. lib/Magmi/plugins/base/itemprocessors/upcross_sell/crossupsell_products.php +279 -0
  73. lib/Magmi/plugins/inc/magmi_datasource.php +30 -0
  74. lib/Magmi/plugins/inc/magmi_default_options_panel.php +1 -0
  75. lib/Magmi/plugins/inc/magmi_defaultattributehandler.php +218 -0
  76. lib/Magmi/plugins/inc/magmi_generalimport_plugin.php +15 -0
  77. lib/Magmi/plugins/inc/magmi_item_processor.php +102 -0
  78. lib/Magmi/plugins/inc/magmi_plugin.php +346 -0
  79. lib/Magmi/plugins/inc/magmi_utility_plugin.php +13 -0
  80. package.xml +36 -0
  81. shell/fballiano_full_catalog_translate.php +143 -0
app/code/community/Fballiano/FullCatalogTranslate/Helper/Data.php ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * FBalliano
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ *
12
+ * DISCLAIMER
13
+ *
14
+ * Do not edit or add to this file if you wish to upgrade this Module to
15
+ * newer versions in the future.
16
+ *
17
+ * @category FBalliano
18
+ * @package FBalliano_FullCatalogTranslate
19
+ * @copyright Copyright (c) 2014 Fabrizio Balliano (http://fabrizioballiano.it)
20
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
21
+ */
22
+ class Fballiano_FullCatalogTranslate_Helper_Data extends Mage_Core_Helper_Abstract
23
+ {
24
+ /**
25
+ * @return array
26
+ */
27
+ public function getAttributesToTranslate()
28
+ {
29
+ $attributes = Mage::getStoreConfig("fballiano_full_catalog_translate/general/attributes_to_translate");
30
+ $attributes = explode(",", $attributes);
31
+ foreach ($attributes as $k=>$v) {
32
+ $attributes[$k] = trim($v);
33
+ }
34
+
35
+ return $attributes;
36
+ }
37
+
38
+ /**
39
+ * @return string
40
+ */
41
+ public function getApiKey()
42
+ {
43
+ return Mage::getStoreConfig("fballiano_full_catalog_translate/google_translate/api_key");
44
+ }
45
+ }
app/code/community/Fballiano/FullCatalogTranslate/etc/adminhtml.xml ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <acl>
4
+ <resources>
5
+ <admin>
6
+ <children>
7
+ <system>
8
+ <children>
9
+ <config>
10
+ <children>
11
+ <fballiano_full_catalog_translate>
12
+ <title>FBalliano Full Catalog Translate</title>
13
+ </fballiano_full_catalog_translate>
14
+ </children>
15
+ </config>
16
+ </children>
17
+ </system>
18
+ </children>
19
+ </admin>
20
+ </resources>
21
+ </acl>
22
+ </config>
app/code/community/Fballiano/FullCatalogTranslate/etc/config.xml ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <modules>
4
+ <Fballiano_FullCatalogTranslate>
5
+ <version>0.2.0</version>
6
+ </Fballiano_FullCatalogTranslate>
7
+ </modules>
8
+ <global>
9
+ <helpers>
10
+ <fballiano_fullcatalogtranslate>
11
+ <class>Fballiano_FullCatalogTranslate_Helper</class>
12
+ </fballiano_fullcatalogtranslate>
13
+ </helpers>
14
+ <resources>
15
+ <fballiano_fullcatalogtranslate_setup>
16
+ <setup>
17
+ <module>Fballiano_FullCatalogTranslate</module>
18
+ <class>Mage_Catalog_Model_Resource_Setup</class>
19
+ </setup>
20
+ </fballiano_fullcatalogtranslate_setup>
21
+ </resources>
22
+ </global>
23
+ <default>
24
+ <fballiano_full_catalog_translate>
25
+ <general>
26
+ <attributes_to_translate>name, short_description, description, meta_title, meta_keyword, meta_description</attributes_to_translate>
27
+ </general>
28
+ </fballiano_full_catalog_translate>
29
+ </default>
30
+ </config>
app/code/community/Fballiano/FullCatalogTranslate/etc/system.xml ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <sections>
4
+ <fballiano_full_catalog_translate>
5
+ <tab>service</tab>
6
+ <label>Fballiano Full Catalog Translate</label>
7
+ <show_in_default>1</show_in_default>
8
+ <show_in_website>0</show_in_website>
9
+ <show_in_store>0</show_in_store>
10
+ <groups>
11
+ <general>
12
+ <label>General</label>
13
+ <show_in_default>1</show_in_default>
14
+ <show_in_website>0</show_in_website>
15
+ <show_in_store>0</show_in_store>
16
+ <sort_order>10</sort_order>
17
+ <fields>
18
+ <attributes_to_translate>
19
+ <label>Attributes to translate</label>
20
+ <show_in_default>1</show_in_default>
21
+ <show_in_website>0</show_in_website>
22
+ <show_in_store>0</show_in_store>
23
+ <comment>Comma separated list of attribute codes, only these attributes will be translated.</comment>
24
+ </attributes_to_translate>
25
+ </fields>
26
+ </general>
27
+ <google_translate>
28
+ <label>Google Translate</label>
29
+ <show_in_default>1</show_in_default>
30
+ <show_in_website>0</show_in_website>
31
+ <show_in_store>0</show_in_store>
32
+ <sort_order>20</sort_order>
33
+ <fields>
34
+ <api_key>
35
+ <label>API key</label>
36
+ <show_in_default>1</show_in_default>
37
+ <show_in_website>0</show_in_website>
38
+ <show_in_store>0</show_in_store>
39
+ </api_key>
40
+ </fields>
41
+ </google_translate>
42
+ </groups>
43
+ </fballiano_full_catalog_translate>
44
+ </sections>
45
+ </config>
app/code/community/Fballiano/FullCatalogTranslate/sql/fballiano_fullcatalogtranslate_setup/install-0.1.0.php ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * FBalliano
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ *
12
+ * DISCLAIMER
13
+ *
14
+ * Do not edit or add to this file if you wish to upgrade this Module to
15
+ * newer versions in the future.
16
+ *
17
+ * @category FBalliano
18
+ * @package FBalliano_FullCatalogTranslate
19
+ * @copyright Copyright (c) 2014 Fabrizio Balliano (http://fabrizioballiano.it)
20
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
21
+ */
22
+
23
+ /* @var $installer Mage_Catalog_Model_Resource_Setup */
24
+ $installer = $this;
25
+ $installer->startSetup();
26
+
27
+ //$installer->removeAttribute(Mage_Catalog_Model_Product::ENTITY, "fb_translate");
28
+ $installer->addAttribute(Mage_Catalog_Model_Product::ENTITY, "fb_translate", array(
29
+ "group" => "General",
30
+ "type" => "int",
31
+ "default" => "0",
32
+ "label" => "Translate automatically?",
33
+ "note"=> "Should this product be translated automatically when the store admin decides so?",
34
+ "input" => "select",
35
+ 'source' => 'eav/entity_attribute_source_boolean',
36
+ "global" => Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_STORE,
37
+ "backend" => "",
38
+ "frontend" => "",
39
+ "is_configurable" => false,
40
+ "required" => false,
41
+ 'searchable' => false,
42
+ 'filterable' => false,
43
+ 'comparable' => false,
44
+ 'visible_on_front' => false,
45
+ 'visible_in_advanced_search' => false,
46
+ 'used_in_product_listing' => false,
47
+ 'unique' => false,
48
+ 'apply_to' => ''
49
+ )
50
+ );
51
+
52
+ $installer->endSetup();
app/etc/modules/Fballiano_FullCatalogTranslate.xml ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <modules>
4
+ <Fballiano_FullCatalogTranslate>
5
+ <active>true</active>
6
+ <codePool>community</codePool>
7
+ <depends>
8
+ <Mage_Catalog/>
9
+ </depends>
10
+ </Fballiano_FullCatalogTranslate>
11
+ </modules>
12
+ </config>
lib/Magmi/ReleaseNotes.txt ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ -------------------------------------------------
2
+ - RELEASE NOTES FOR MAGMI 0.7.18beta1 -
3
+ -------------------------------------------------
4
+
5
+
6
+ ##########
7
+ #Bugfix
8
+ #########
9
+ - fixed case insensitive matching for options
10
+
11
+
12
+ ##########
13
+ #Core
14
+ ##########
15
+
16
+
17
+ * ProductImportEngine
18
+ - added support for category item positioning
19
+ - better behaviour on unmatched category id in category_ids (if not existing, warning instead of exception)
20
+ - autodefaulting of store column to "admin" if omitted
21
+
22
+ * Magmi_config
23
+ - support for alternate global configuration files
24
+
25
+ * Magmi_cli
26
+ - support for profile chaining in magmi.cli.php
27
+ - magmi.cli.php could be now more easily integrated as include in other scripts.
28
+
29
+ * Magmi_utils
30
+ - added utility functions to detect remote urls
31
+
32
+ ############
33
+ # UI
34
+ ############
35
+
36
+ - fixed cache sensivity of magmi run from UI
37
+ - use of google CDN url for prototype.js lib
38
+
39
+ #########
40
+ #Plugins
41
+ #########
42
+
43
+ Base:
44
+ ------
45
+
46
+ * Remote Agent:
47
+ Enable connecting to remote magento installs (put ftp://user:pass@host/magento_base_dir) as magento base directory
48
+ Enable to perform remote filesystem operations
49
+ need DB connectivity between magento host & magmi host.
50
+
51
+ *Grouped Products:
52
+ - added support for any type of subproducts
53
+
54
+ * CSV Datasource
55
+
56
+ Extra
57
+ -----
58
+
59
+ * Categories
60
+ - added support for multiple root assignment in a single line
61
+ - added support for tree separator escaping
62
+ - added support for item position in each branch of the tree
63
+
64
+ Utilities
65
+ ---------
66
+
67
+ Mass Option Remapper : enable to remap select attribute values using input csv..
lib/Magmi/conf/magmi.ini ADDED
@@ -0,0 +1,2 @@
 
 
1
+ [GLOBAL]
2
+ step = "0.5"
lib/Magmi/conf/plugins.conf ADDED
File without changes
lib/Magmi/engines/magmi_productimportengine.php ADDED
@@ -0,0 +1,1678 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * MAGENTO MASS IMPORTER CLASS
5
+ *
6
+ * version : 0.6
7
+ * author : S.BRACQUEMONT aka dweeves
8
+ * updated : 2010-10-09
9
+ *
10
+ */
11
+
12
+ /* use external file for db helper */
13
+ require_once("magmi_engine.php");
14
+
15
+ /**
16
+ *
17
+ * Magmi Product Import engine class
18
+ * This class handle product import
19
+ * @author dweeves
20
+ *
21
+ */
22
+ class Magmi_ProductImportEngine extends Magmi_Engine
23
+ {
24
+
25
+ public $attrinfo=array();
26
+ public $attrbytype=array();
27
+ public $store_ids=array();
28
+ public $status_id=array();
29
+ public $attribute_sets=array();
30
+ public $prod_etype;
31
+ public $default_asid;
32
+ public $sidcache=array();
33
+ public $mode="update";
34
+ private $_attributehandlers;
35
+ private $_current_row;
36
+ private $_optidcache=null;
37
+ private $_curitemids=array("sku"=>null);
38
+ private $_dstore=array();
39
+ private $_same;
40
+ private $_currentpid;
41
+ private $_extra_attrs;
42
+ private $_profile;
43
+ private $_sid_wsscope=array();
44
+ private $_sid_sscope=array();
45
+ private $_prodcols=array();
46
+ private $_stockcols=array();
47
+ private $_skustats=array();
48
+
49
+ public function addExtraAttribute($attr)
50
+ {
51
+ $attinfo=$this->attrinfo[$attr];
52
+ $this->_extra_attrs[$attinfo["backend_type"]]["data"][]=$attinfo;
53
+
54
+ }
55
+ /**
56
+ * constructor
57
+ * @param string $conffile : configuration .ini filename
58
+ */
59
+ public function __construct()
60
+ {
61
+
62
+ $this->setBuiltinPluginClasses("itemprocessors",dirname(dirname(__FILE__))."/plugins/inc/magmi_defaultattributehandler.php::Magmi_DefaultAttributeItemProcessor");
63
+ }
64
+
65
+
66
+ public function getSkuStats()
67
+ {
68
+ return $this->_skustats;
69
+ }
70
+
71
+ public function getImportMode()
72
+ {
73
+ return $this->mode;
74
+ }
75
+ /**
76
+ * (non-PHPdoc)
77
+ * @see Magmi_Engine::getEngineInfo()
78
+ */
79
+ public function getEngineInfo()
80
+ {
81
+ return array("name"=>"Magmi Product Import Engine","version"=>"1.7.1","author"=>"dweeves");
82
+ }
83
+
84
+ /**
85
+ * load properties
86
+ * @param string $conf : configuration .ini filename
87
+ */
88
+
89
+
90
+
91
+
92
+ public function initProdType()
93
+ {
94
+ $tname=$this->tablename("eav_entity_type");
95
+ $this->prod_etype=$this->selectone("SELECT entity_type_id FROM $tname WHERE entity_type_code=?","catalog_product","entity_type_id");
96
+ $this->default_asid=$this->getAttributeSetId('Default');
97
+ }
98
+
99
+
100
+
101
+ public function getPluginFamilies()
102
+ {
103
+ return array("datasources","general","itemprocessors");
104
+ }
105
+
106
+ public function registerAttributeHandler($ahinst,$attdeflist)
107
+ {
108
+ foreach($attdeflist as $attdef)
109
+ {
110
+ $ad=explode(":",$attdef);
111
+ if(count($ad)!=2)
112
+ {
113
+ $this->log("Invalid registration string ($attdef) :".get_class($ahinst),"warning");
114
+ }
115
+ else
116
+ {
117
+ $this->_attributehandlers[$attdef]=$ahinst;
118
+ }
119
+ }
120
+ }
121
+
122
+
123
+
124
+
125
+ /**
126
+ *
127
+ * Return list of store codes that share the same website than the stores passed as parameter
128
+ * @param string $scodes comma separated list of store view codes
129
+ */
130
+ public function getStoreIdsForWebsiteScope($scodes)
131
+ {
132
+ if(!isset($this->_sid_wsscope[$scodes]))
133
+ {
134
+ $this->_sid_wsscope[$scodes]=array();
135
+ $wscarr=csl2arr($scodes);
136
+ $qcolstr=$this->arr2values($wscarr);
137
+ $cs=$this->tablename("core_store");
138
+ $sql="SELECT csdep.store_id FROM $cs as csmain
139
+ JOIN $cs as csdep ON csdep.website_id=csmain.website_id
140
+ WHERE csmain.code IN ($qcolstr) ";
141
+ $sidrows=$this->selectAll($sql,$wscarr);
142
+ foreach($sidrows as $sidrow)
143
+ {
144
+ $this->_sid_wsscope[$scodes][]=$sidrow["store_id"];
145
+ }
146
+ }
147
+ return $this->_sid_wsscope[$scodes];
148
+ }
149
+
150
+ public function getStoreIdsForStoreScope($scodes)
151
+ {
152
+ if(!isset($this->_sid_sscope[$scodes]))
153
+ {
154
+ $this->_sid_sscope[$scodes]=array();
155
+ $scarr=csl2arr($scodes);
156
+ $qcolstr=$this->arr2values($scarr);
157
+ $cs=$this->tablename("core_store");
158
+ $sql="SELECT csmain.store_id from $cs as csmain WHERE csmain.code IN ($qcolstr)";
159
+ $sidrows=$this->selectAll($sql,$scarr);
160
+ foreach($sidrows as $sidrow)
161
+ {
162
+ $this->_sid_sscope[$scodes][]=$sidrow["store_id"];
163
+ }
164
+
165
+ }
166
+ return $this->_sid_sscope[$scodes];
167
+ }
168
+
169
+
170
+ /**
171
+ * returns mode
172
+ */
173
+ public function getMode()
174
+ {
175
+ return $this->mode;
176
+ }
177
+
178
+ public function getProdCols()
179
+ {
180
+ if(count($this->_prodcols)==0)
181
+ {
182
+ $sql='DESCRIBE '.$this->tablename('catalog_product_entity');
183
+ $rows=$this->selectAll($sql);
184
+ foreach($rows as $row)
185
+ {
186
+ $this->_prodcols[]=$row['Field'];
187
+ }
188
+ }
189
+ return $this->_prodcols;
190
+ }
191
+
192
+ public function getStockCols()
193
+ {
194
+ if(count($this->_stockcols)==0)
195
+ {
196
+ $sql='DESCRIBE '.$this->tablename('cataloginventory_stock_item');
197
+ $rows=$this->selectAll($sql);
198
+ foreach($rows as $row)
199
+ {
200
+ $this->_stockcols[]=$row['Field'];
201
+ }
202
+ }
203
+ return $this->_stockcols;
204
+ }
205
+ /**
206
+ * Initialize attribute infos to be used during import
207
+ * @param array $cols : array of attribute names
208
+ */
209
+ public function checkRequired($cols)
210
+ {
211
+ $eav_attr=$this->tablename("eav_attribute");
212
+ $sql="SELECT attribute_code FROM $eav_attr WHERE is_required=1
213
+ AND frontend_input!='' AND frontend_label!='' AND entity_type_id=?";
214
+ $required=$this->selectAll($sql,$this->prod_etype);
215
+ $reqcols=array();
216
+ foreach($required as $line)
217
+ {
218
+ $reqcols[]=$line["attribute_code"];
219
+ }
220
+ $required=array_diff($reqcols,$cols);
221
+ return $required;
222
+ }
223
+
224
+ /**
225
+ *
226
+ * gets attribute metadata from DB and put it in attribute metadata caches
227
+ * @param array $cols list of attribute codes to get metadata from
228
+ * if in this list, some values are not attribute code, no metadata will be cached.
229
+ */
230
+ public function initAttrInfos($cols)
231
+ {
232
+ if($this->prod_etype==null)
233
+ {
234
+ //Find product entity type
235
+ $tname=$this->tablename("eav_entity_type");
236
+ $this->prod_etype=$this->selectone("SELECT entity_type_id FROM $tname WHERE entity_type_code=?","catalog_product","entity_type_id");
237
+ }
238
+
239
+ $toscan=array_values(array_diff($cols,array_keys($this->attrinfo)));
240
+ if(count($toscan)>0)
241
+ {
242
+ //create statement parameter string ?,?,?.....
243
+ $qcolstr=$this->arr2values($toscan);
244
+
245
+ $tname=$this->tablename("eav_attribute");
246
+ if($this->getMagentoVersion()!="1.3.x")
247
+ {
248
+ $extra=$this->tablename("catalog_eav_attribute");
249
+ //SQL for selecting attribute properties for all wanted attributes
250
+ $sql="SELECT `$tname`.*,$extra.is_global FROM `$tname`
251
+ LEFT JOIN $extra ON $tname.attribute_id=$extra.attribute_id
252
+ WHERE ($tname.attribute_code IN ($qcolstr)) AND (entity_type_id=?)";
253
+ }
254
+ else
255
+ {
256
+ $sql="SELECT `$tname`.* FROM `$tname` WHERE ($tname.attribute_code IN ($qcolstr)) AND (entity_type_id=?)";
257
+ }
258
+ $toscan[]=$this->prod_etype;
259
+ $result=$this->selectAll($sql,$toscan);
260
+
261
+ $attrinfs=array();
262
+ //create an attribute code based array for the wanted columns
263
+ foreach($result as $r)
264
+ {
265
+ $attrinfs[$r["attribute_code"]]=$r;
266
+ }
267
+ unset($result);
268
+
269
+ //create a backend_type based array for the wanted columns
270
+ //this will greatly help for optimizing inserts when creating attributes
271
+ //since eav_ model for attributes has one table per backend type
272
+ foreach($attrinfs as $k=>$a)
273
+ {
274
+ //do not index attributes that are not in header (media_gallery may have been inserted for other purposes)
275
+ if(!in_array($k,$cols))
276
+ {
277
+ continue;
278
+ }
279
+ $bt=$a["backend_type"];
280
+ if(!isset($this->attrbytype[$bt]))
281
+ {
282
+ $this->attrbytype[$bt]=array("data"=>array());
283
+ }
284
+ $this->attrbytype[$bt]["data"][]=$a;
285
+ }
286
+ //now add a fast index in the attrbytype array to store id list in a comma separated form
287
+ foreach($this->attrbytype as $bt=>$test)
288
+ {
289
+ $idlist;
290
+ foreach($test["data"] as $it)
291
+ {
292
+ $idlist[]=$it["attribute_id"];
293
+ }
294
+ $this->attrbytype[$bt]["ids"]=implode(",",$idlist);
295
+ }
296
+ $this->attrinfo=array_merge($this->attrinfo,$attrinfs);
297
+ }
298
+ $notattribs=array_diff($cols,array_keys($this->attrinfo));
299
+ foreach($notattribs as $k)
300
+ {
301
+ $this->attrinfo[$k]=null;
302
+ }
303
+ /*now we have 2 index arrays
304
+ 1. $this->attrinfo which has the following structure:
305
+ key : attribute_code
306
+ value : attribute_properties
307
+ 2. $this->attrbytype which has the following structure:
308
+ key : attribute backend type
309
+ value : array of :
310
+ data => array of attribute_properties ,one for each attribute that match
311
+ the backend type
312
+ ids => list of attribute ids of the backend type */
313
+ }
314
+
315
+ /**
316
+ *
317
+ * retrieves attribute metadata
318
+ * @param string $attcode attribute code
319
+ * @param boolean $lookup if set, this will try to get info from DB otherwise will get from cache and may return null if not cached
320
+ * @return array attribute metadata info
321
+ */
322
+ public function getAttrInfo($attcode,$lookup=true)
323
+ {
324
+ $attrinf=isset($this->attrinfo[$attcode])?$this->attrinfo[$attcode]:null;
325
+ if($attrinf==null && $lookup)
326
+ {
327
+ $this->initAttrInfos(array($attcode));
328
+
329
+ }
330
+ if(count($this->attrinfo[$attcode])==0)
331
+ {
332
+
333
+ $attrinf=null;
334
+ unset($this->attrinfo[$attcode]);
335
+ }
336
+ else
337
+ {
338
+ $attrinf=$this->attrinfo[$attcode];
339
+ }
340
+ return $attrinf;
341
+ }
342
+
343
+ /**
344
+ * retrieves attribute set id for a given attribute set name
345
+ * @param string $asname : attribute set name
346
+ */
347
+ public function getAttributeSetId($asname)
348
+ {
349
+
350
+ if(!isset($this->attribute_sets[$asname]))
351
+ {
352
+ $tname=$this->tablename("eav_attribute_set");
353
+ $asid=$this->selectone(
354
+ "SELECT attribute_set_id FROM $tname WHERE attribute_set_name=? AND entity_type_id=?",
355
+ array($asname,$this->prod_etype),
356
+ 'attribute_set_id');
357
+ $this->attribute_sets[$asname]=$asid;
358
+ }
359
+ return $this->attribute_sets[$asname];
360
+ }
361
+
362
+ /**
363
+ * Retrieves product id for a given sku
364
+ * @param string $sku : sku of product to get id for
365
+ */
366
+ public function getProductIds($sku)
367
+ {
368
+ $tname=$this->tablename("catalog_product_entity");
369
+ $result=$this->selectAll(
370
+ "SELECT sku,entity_id as pid,attribute_set_id as asid FROM $tname WHERE sku=?",
371
+ $sku);
372
+ if(count($result)>0)
373
+ {
374
+ return $result[0];
375
+ }
376
+ else
377
+ {
378
+ return false;
379
+ }
380
+ }
381
+
382
+ /**
383
+ * creates a product in magento database
384
+ * @param array $item: product attributes as array with key:attribute name,value:attribute value
385
+ * @param int $asid : attribute set id for values
386
+ * @return : product id for newly created product
387
+ */
388
+ public function createProduct($item,$asid)
389
+ {
390
+ //force item type if not exists
391
+ if(!isset($item["type"]))
392
+ {
393
+ $item["type"]="simple";
394
+ }
395
+ $tname=$this->tablename('catalog_product_entity');
396
+ $item['type_id']=$item['type'];
397
+ $item['attribute_set_id']=$asid;
398
+ $item['entity_type_id']=$this->prod_etype;
399
+ $item['created_at']=strftime("%Y-%m-%d %H:%M:%S");
400
+ $item['updated_at']=strftime("%Y-%m-%d %H:%M:%S");
401
+ $columns=array_intersect(array_keys($item), $this->getProdCols());
402
+ $values=$this->filterkvarr($item, $columns);
403
+ $sql="INSERT INTO `$tname` (".implode(",",$columns).") VALUES (".$this->arr2values($columns).")";
404
+ $lastid=$this->insert($sql,array_values($values));
405
+ return $lastid;
406
+ }
407
+
408
+ /**
409
+ * Updateds product update time
410
+ * @param unknown_type $pid : entity_id of product
411
+ */
412
+ public function touchProduct($pid)
413
+ {
414
+ $tname=$this->tablename('catalog_product_entity');
415
+ $this->update("UPDATE $tname SET updated_at=? WHERE entity_id=?",array(strftime("%Y-%m-%d %H:%M:%S"),$pid));
416
+ }
417
+
418
+ /**
419
+ * Get Option id for select attributes based on value
420
+ * @param int $attid : attribute id to find option id from value
421
+ * @param mixed $optval : value to get option id for
422
+ * @return : array of lines (should be as much as values found),"opvd"=>option_id for value on store 0,"opvs" option id for value on current store
423
+ */
424
+ public function getOptionsFromValues($attid,$store_id,$optvals)
425
+ {
426
+ $ovstr=substr(str_repeat("?,",count($optvals)),0,-1);
427
+ $t1=$this->tablename('eav_attribute_option');
428
+ $t2=$this->tablename('eav_attribute_option_value');
429
+ $sql="SELECT optvals.option_id as opvs,optvals.value FROM $t2 as optvals";
430
+ $sql.=" JOIN $t1 as opt ON opt.option_id=optvals.option_id AND opt.attribute_id=?";
431
+ $sql.=" WHERE optvals.store_id=? AND BINARY optvals.value IN ($ovstr)";
432
+ return $this->selectAll($sql,array_merge(array($attid,$store_id),$optvals));
433
+ }
434
+
435
+
436
+ /* create a new option entry for an attribute */
437
+ public function createOption($attid)
438
+ {
439
+ $t=$this->tablename('eav_attribute_option');
440
+ $optid=$this->insert("INSERT INTO $t (attribute_id) VALUES (?)",$attid);
441
+ return $optid;
442
+ }
443
+ /**
444
+ * Creates a new option value for an option entry for a store
445
+ * @param int $optid : option entry id
446
+ * @param int $store_id : store id to add value for
447
+ * @param mixed $optval : new option value to add
448
+ * @return : option id for new created value
449
+ */
450
+ public function createOptionValue($optid,$store_id,$optval)
451
+ {
452
+ $t=$this->tablename('eav_attribute_option_value');
453
+ $optval_id=$this->insert("INSERT INTO $t (option_id,store_id,value) VALUES (?,?,?)",array($optid,$store_id,$optval));
454
+ return $optval_id;
455
+ }
456
+
457
+
458
+ public function getOptionIds($attid,$storeid,$values)
459
+ {
460
+ $optids=array();
461
+ $svalues=array();
462
+ $avalues=array();
463
+ //Matching refstore value
464
+ foreach($values as $val)
465
+ {
466
+ if(preg_match("|^(.*)::\[(.*)\]$|",$val,$matches))
467
+ {
468
+ $svalues[]=$matches[2];
469
+ $avalues[]=$matches[1];
470
+ }
471
+ else
472
+ {
473
+ $svalues[]=$val;
474
+ $avalues[]=$val;
475
+ }
476
+ }
477
+ $existing=$this->getOptionsFromValues($attid,0,$avalues);
478
+ $exvals=array();
479
+ foreach($existing as $optdesc)
480
+ {
481
+ $exvals[]=$optdesc["value"];
482
+ }
483
+ $new=array_merge(array_diff($avalues,$exvals));
484
+ if($storeid==0)
485
+ {
486
+ foreach($new as $nval)
487
+ {
488
+ $row=array("opvs"=>$this->createOption($attid),"value"=>$nval);
489
+ $this->createOptionValue($row["opvs"],$storeid,$nval);
490
+ $existing[]=$row;
491
+ }
492
+ $this->cacheOptIds($attid,$existing);
493
+
494
+ }
495
+ else
496
+ {
497
+
498
+ $brows=$this->getCachedOptIds($attid);
499
+ if(count($brows)==0)
500
+ {
501
+ $existing=$this->getOptionsFromValues($attid,0,$avalues);
502
+ $new=array_merge(array_diff($avalues,$exvals));
503
+ foreach($new as $nval)
504
+ {
505
+ $row=array("opvs"=>$this->createOption($attid),"value"=>$nval);
506
+ $this->createOptionValue($row["opvs"],$storeid,$nval);
507
+ $existing[]=$row;
508
+ }
509
+ $this->cacheOptIds($attid,$existing);
510
+ $brows=$this->getCachedOptIds($attid);
511
+ }
512
+ foreach($existing as $ex)
513
+ {
514
+ array_shift($brows);
515
+ }
516
+ for($i=0;$i<count($new);$i++)
517
+ {
518
+ $row=$brows[$i];
519
+ if(!isset($row["opvs"]))
520
+ {
521
+ $row["opvs"]=$this->createOption($attid);
522
+ $this->createOptionValue($row["opvs"],0,$new[$i]);
523
+ }
524
+ $this->createOptionValue($row["opvs"],$storeid,$new[$i]);
525
+ $existing[]=$row;
526
+ }
527
+ }
528
+ $optids=array();
529
+ foreach($existing as $row)
530
+ {
531
+ $optids[]=$row["opvs"];
532
+ }
533
+ unset($existing);
534
+ unset($exvals);
535
+ return $optids;
536
+
537
+ }
538
+
539
+ public function cacheOptIds($attid,$row)
540
+ {
541
+ $this->_optidcache[$attid]=$row;
542
+ }
543
+
544
+ public function getCachedOptIds($attid)
545
+ {
546
+ if(isset($this->_optidcache[$attid]))
547
+ {
548
+ return $this->_optidcache[$attid];
549
+ }
550
+ else
551
+ {
552
+ return null;
553
+ }
554
+ }
555
+
556
+
557
+ /**
558
+ * returns tax class id for a given tax class value
559
+ * @param $tcvalue : tax class value
560
+ */
561
+ public function getTaxClassId($tcvalue)
562
+ {
563
+ $t=$this->tablename('tax_class');
564
+ $txid=$this->selectone("SELECT class_id FROM $t WHERE class_name=?",array($tcvalue),"class_id");
565
+ //bugfix for tax class id, if not found set it to none
566
+ if(!isset($txid))
567
+ {
568
+ $txid=0;
569
+ }
570
+ return $txid;
571
+ }
572
+
573
+ public function parseCalculatedValue($pvalue,$item,$params)
574
+ {
575
+ $matches=array();
576
+ $ik=array_keys($item);
577
+ $rep="";
578
+
579
+ //replace base item values
580
+ while(preg_match("|\{item\.(.*?)\}|",$pvalue,$matches))
581
+ {
582
+ foreach($matches as $match)
583
+ {
584
+ if($match!=$matches[0])
585
+ {
586
+ if(in_array($match,$ik))
587
+ {
588
+ $rep='$item["'.$match.'"]';
589
+ }
590
+ else
591
+ {
592
+ $rep="";
593
+ }
594
+ $pvalue=str_replace($matches[0],$rep,$pvalue);
595
+ }
596
+ }
597
+ }
598
+ unset($matches);
599
+ //replac meta
600
+ $meta=$params;
601
+
602
+
603
+ while(preg_match("|\{meta\.(.*?)\}|",$pvalue,$matches))
604
+ {
605
+ foreach($matches as $match)
606
+ {
607
+ if($match!=$matches[0])
608
+ {
609
+ if(in_array($match,$ik))
610
+ {
611
+ $rep='$meta["'.$match.'"]';
612
+ }
613
+ else
614
+ {
615
+ $rep="";
616
+ }
617
+ $pvalue=str_replace($matches[0],$rep,$pvalue);
618
+ }
619
+ }
620
+ }
621
+ unset($matches);
622
+
623
+
624
+ //replacing expr values
625
+ while(preg_match("|\{\{\s*(.*?)\s*\}\}|",$pvalue,$matches))
626
+ {
627
+ foreach($matches as $match)
628
+ {
629
+ if($match!=$matches[0])
630
+ {
631
+ $code=trim($match);
632
+ //settiing meta values
633
+ $meta=$params;
634
+ $rep=eval("return ($code);");
635
+ //escape potential "{{xxx}}" values in interpreted target
636
+ //so that they won't be reparsed in next round
637
+ $rep=preg_replace("|\{\{\s*(.*?)\s*\}\}|", "____$1____", $rep);
638
+ $pvalue=str_replace($matches[0],$rep,$pvalue);
639
+ }
640
+ }
641
+ }
642
+
643
+ //unescape matches
644
+ $pvalue=preg_replace("|____(.*?)____|",'{{$1}}',$pvalue);
645
+ //replacing single values not in complex values
646
+ while(preg_match('|\$item\["(.*?)"\]|',$pvalue,$matches))
647
+ {
648
+ foreach($matches as $match)
649
+ {
650
+ if($match!=$matches[0])
651
+ {
652
+ if(in_array($match,$ik))
653
+ {
654
+ $rep=$item[$match];
655
+ }
656
+ else
657
+ {
658
+ $rep="";
659
+ }
660
+ $pvalue=str_replace($matches[0],$rep,$pvalue);
661
+ }
662
+ }
663
+ }
664
+
665
+ unset($matches);
666
+ return $pvalue;
667
+ }
668
+
669
+ /**
670
+ *
671
+ * Return affected store ids for a given item given an attribute scope
672
+ * @param array $item : item to get store for scope
673
+ * @param string $scope : scope to get stores from.
674
+ */
675
+ public function getItemStoreIds($item,$scope=0)
676
+ {
677
+ if(!isset($item['store']))
678
+ {
679
+ $item['store']="admin";
680
+ }
681
+ switch($scope){
682
+ //global scope
683
+ case 1:
684
+ $bstore_ids=$this->getStoreIdsForStoreScope("admin");
685
+ break;
686
+ //store scope
687
+ case 0:
688
+ $bstore_ids=$this->getStoreIdsForStoreScope($item["store"]);
689
+ break;
690
+ //website scope
691
+ case 2:
692
+ $bstore_ids=$this->getStoreIdsForWebsiteScope($item["store"]);
693
+ break;
694
+ }
695
+
696
+ $itemstores=array_unique(array_merge($this->_dstore,$bstore_ids));
697
+ sort($itemstores);
698
+ return $itemstores;
699
+ }
700
+
701
+ /**
702
+ * Create product attribute from values for a given product id
703
+ * @param $pid : product id to create attribute values for
704
+ * @param $item : attribute values in an array indexed by attribute_code
705
+ */
706
+ public function createAttributes($pid,&$item,$attmap,$isnew)
707
+ {
708
+ /**
709
+ * get all store ids
710
+ */
711
+ $this->_extra_attrs=array();
712
+ /* now is the interesring part */
713
+ /* iterate on attribute backend type index */
714
+ foreach($attmap as $tp=>$a)
715
+ {
716
+ /* for static types, do not insert into attribute tables */
717
+ if($tp=="static")
718
+ {
719
+ continue;
720
+ }
721
+
722
+ //table name for backend type data
723
+ $cpet=$this->tablename("catalog_product_entity_$tp");
724
+ //data table for inserts
725
+ $data=array();
726
+ //inserts to perform on backend type eav
727
+ $inserts=array();
728
+ //deletes to perform on backend type eav
729
+ $deletes=array();
730
+
731
+ //use reflection to find special handlers
732
+ $typehandler="handle".ucfirst($tp)."Attribute";
733
+ //iterate on all attribute descriptions for the given backend type
734
+ foreach($a["data"] as $attrdesc)
735
+ {
736
+ //get attribute id
737
+ $attid=$attrdesc["attribute_id"];
738
+ //get attribute value in the item to insert based on code
739
+ $atthandler="handle".ucfirst($attrdesc["attribute_code"])."Attribute";
740
+ $attrcode=$attrdesc["attribute_code"];
741
+ //if the attribute code is no more in item (plugins may have come into the way), continue
742
+ if(!in_array($attrcode,array_keys($item)))
743
+ {
744
+ continue;
745
+ }
746
+ //get the item value
747
+ $ivalue=$item[$attrcode];
748
+ //get item store id for the current attribute
749
+ $store_ids=$this->getItemStoreIds($item,$attrdesc["is_global"]);
750
+
751
+
752
+ //do not handle empty generic int values in create mode
753
+ if($ivalue=="" && $this->mode!="update" && $tp=="int")
754
+ {
755
+ continue;
756
+ }
757
+ //for all store ids
758
+ foreach($store_ids as $store_id)
759
+ {
760
+
761
+ //base output value to be inserted = base source value
762
+ $ovalue=$ivalue;
763
+ //check for attribute handlers for current attribute
764
+ foreach($this->_attributehandlers as $match=>$ah)
765
+ {
766
+ $matchinfo=explode(":",$match);
767
+ $mtype=$matchinfo[0];
768
+ $mtest=$matchinfo[1];
769
+ unset($matchinfo);
770
+ unset($hvalue);
771
+ if(preg_match("/$mtest/",$attrdesc[$mtype]))
772
+ {
773
+ //if there is a specific handler for attribute, use it
774
+ if(method_exists($ah,$atthandler))
775
+ {
776
+ $hvalue=$ah->$atthandler($pid,$item,$store_id,$attrcode,$attrdesc,$ivalue);
777
+ }
778
+ else
779
+ //use generic type attribute
780
+ if(method_exists($ah,$typehandler))
781
+ {
782
+ $hvalue=$ah->$typehandler($pid,$item,$store_id,$attrcode,$attrdesc,$ivalue);
783
+ }
784
+ //if handlers returned a value that is not "__MAGMI_UNHANDLED__" , we have our output value
785
+ if(isset($hvalue) && $hvalue!="__MAGMI_UNHANDLED__")
786
+ {
787
+ $ovalue=$hvalue;
788
+ break;
789
+ }
790
+ }
791
+ }
792
+ //if __MAGMI_UNHANDLED__ ,don't insert anything
793
+ if($ovalue=="__MAGMI_UNHANDLED__")
794
+ {
795
+ $ovalue=false;
796
+ }
797
+ //if handled value is a "DELETE"
798
+ if($ovalue=="__MAGMI_DELETE__")
799
+ {
800
+ $deletes[]=$attid;
801
+ }
802
+ else
803
+ //if we have something to do with this value
804
+ if($ovalue!==false)
805
+ {
806
+
807
+ $data[]=$this->prod_etype;
808
+ $data[]=$attid;
809
+ $data[]=$store_id;
810
+ $data[]=$pid;
811
+ $data[]=$ovalue;
812
+ $insstr="(?,?,?,?,?)";
813
+ $inserts[]=$insstr;
814
+ }
815
+
816
+ //if one of the store in the list is admin
817
+ if($store_id==0)
818
+ {
819
+ $sids=$store_ids;
820
+ //remove all values bound to the other stores for this attribute,so that they default to "use admin value"
821
+ array_shift($sids);
822
+ if(count($sids)>0)
823
+ {
824
+ $sidlist=implode(",",$sids);
825
+ $ddata=array($this->prod_etype,$attid,$pid);
826
+ $sql="DELETE FROM $cpet WHERE entity_type_id=? AND attribute_id=? AND store_id IN ($sidlist) AND entity_id=?";
827
+ $this->delete($sql,$ddata);
828
+ unset($ddata);
829
+ }
830
+ unset($sids);
831
+ break;
832
+ }
833
+ }
834
+ }
835
+
836
+
837
+
838
+ if(!empty($inserts))
839
+ {
840
+ //now perform insert for all values of the the current backend type in one
841
+ //single insert
842
+ $sql="INSERT INTO $cpet
843
+ (`entity_type_id`, `attribute_id`, `store_id`, `entity_id`, `value`)
844
+ VALUES ";
845
+ $sql.=implode(",",$inserts);
846
+ //this one taken from mysql log analysis of magento import
847
+ //smart one :)
848
+ $sql.=" ON DUPLICATE KEY UPDATE `value`=VALUES(`value`)";
849
+ $this->insert($sql,$data);
850
+ }
851
+
852
+ if(!empty($deletes))
853
+ {
854
+ $sidlist=implode(",",$store_ids);
855
+ $attidlist=implode(",",$deletes);
856
+ $sql="DELETE FROM $cpet WHERE entity_type_id=? AND attribute_id IN ($attidlist) AND store_id IN ($sidlist) AND entity_id=?";
857
+ $this->delete($sql,array($this->prod_etype,$pid));
858
+ }
859
+
860
+ if(empty($deletes) && empty($inserts) && $isnew)
861
+ {
862
+ if(!$this->_same)
863
+ {
864
+ $this->log("No $tp Attributes created for sku ".$item["sku"],"warning");
865
+ }
866
+ }
867
+ unset($store_ids);
868
+ unset($data);
869
+ unset($inserts);
870
+ unset($deletes);
871
+ }
872
+ return $this->_extra_attrs;
873
+ }
874
+
875
+
876
+
877
+ /**
878
+ * update product stock
879
+ * @param int $pid : product id
880
+ * @param array $item : attribute values for product indexed by attribute_code
881
+ */
882
+ public function updateStock($pid,$item,$isnew)
883
+ {
884
+
885
+ $scols=$this->getStockCols();
886
+ #take only stock columns that are in item
887
+ $itstockcols=array_intersect(array_keys($item),$scols);
888
+ #no stock columns set, item exists, no stock update needed.
889
+ if(count($itstockcols)==0 && !$isnew)
890
+ {
891
+ return;
892
+ }
893
+ $csit=$this->tablename("cataloginventory_stock_item");
894
+ $css=$this->tablename("cataloginventory_stock_status");
895
+ #calculate is_in_stock flag
896
+ if(isset($item["qty"]))
897
+ {
898
+ if(!isset($item["manage_stock"]))
899
+ {
900
+ $item["manage_stock"]=1;
901
+ $item["use_config_manage_stock"]=0;
902
+ }
903
+
904
+ $mqty=(isset($item["min_qty"])?$item["min_qty"]:0);
905
+ $is_in_stock=isset($item["is_in_stock"])?$item["is_in_stock"]:($item["qty"]>$mqty?1:0);
906
+ if(!$is_in_stock && $item["qty"]>$mqty)
907
+ {
908
+ $is_in_stock=1;
909
+ }
910
+ $item["is_in_stock"]=$is_in_stock;
911
+ }
912
+ #take only stock columns that are in item after item update
913
+ $common=array_intersect(array_keys($item),$scols);
914
+
915
+ #create stock item line if needed
916
+ $stock_id=(isset($item["stock_id"])?$item["stock_id"]:1);
917
+ $sql="INSERT IGNORE INTO `$csit` (product_id,stock_id) VALUES (?,?)";
918
+ $this->insert($sql,array($pid,$stock_id));
919
+
920
+ if(count($common)>0)
921
+ {
922
+ $cols=$this->arr2columns($common);
923
+ $stockvals=$this->filterkvarr($item,$common);
924
+
925
+ #fill with values
926
+ $svstr=$this->arr2update($stockvals);
927
+ if(isset($item["qty"]))
928
+ {
929
+ $relqty=NULL;
930
+ //test for relative qty
931
+ if($item["qty"][0]=="+" || $item["qty"][0]=="-")
932
+ {
933
+ $relqty=getRelative($item["qty"]);
934
+ }
935
+ //if relative qty
936
+ if($relqty!=NULL)
937
+ {
938
+ //update UPDATE statement value affectation
939
+ $svstr=preg_replace("/(^|,)qty=\?/","$1qty=qty$relqty?",$svstr);
940
+ $stockvals["qty"]=$item["qty"];
941
+ $svstr=str_replace("is_in_stock=?","is_in_stock=(qty>min_qty)",$svstr);
942
+ unset($stockvals["is_in_stock"]);
943
+ }
944
+ }
945
+ $sql="UPDATE `$csit` SET $svstr WHERE product_id=? AND stock_id=?";
946
+ $this->update($sql,array_merge(array_values($stockvals),array($pid,$stock_id)));
947
+ }
948
+
949
+ $data=array();
950
+ $wsids=$this->getItemWebsites($item);
951
+ $csscols=array("website_id","product_id","stock_id","qty","stock_status");
952
+ $cssvals=$this->filterkvarr($item,$csscols);
953
+ $stock_id=(isset($cssvals["stock_id"])?$cssvals["stock_id"]:1);
954
+ $stock_status=(isset($cssvals["stock_status"])?$cssvals["stock_status"]:1);
955
+ //new auto synchro on lat inserted stock item values for stock status.
956
+ //also works for multiple stock ids.
957
+ $sql="INSERT INTO `$css` SELECT csit.product_id,ws.website_id,cis.stock_id,csit.qty,? as stock_status
958
+ FROM `$csit` as csit
959
+ JOIN ".$this->tablename("core_website")." as ws ON ws.website_id IN (".$this->arr2values($wsids).")
960
+ JOIN ".$this->tablename("cataloginventory_stock")." as cis ON cis.stock_id=?
961
+ WHERE product_id=?
962
+ ON DUPLICATE KEY UPDATE stock_status=VALUES(`stock_status`),qty=VALUES(`qty`)";
963
+ $data[]=$stock_status;
964
+ $data=array_merge($data,$wsids);
965
+ $data[]=$stock_id;
966
+ $data[]=$pid;
967
+ $this->insert($sql,$data);
968
+ unset($data);
969
+ }
970
+ /**
971
+ * assign categories for a given product id from values
972
+ * categories should already be created & csv values should be as the ones
973
+ * given in the magento export (ie: comma separated ids, minus 1,2)
974
+ * @param int $pid : product id
975
+ * @param array $item : attribute values for product indexed by attribute_code
976
+ */
977
+ public function assignCategories($pid,$item)
978
+ {
979
+ $cce=$this->tablename("catalog_category_entity");
980
+ $ccpt=$this->tablename("catalog_category_product");
981
+ #handle assignment reset
982
+ if(!isset($item["category_reset"]) || $item["category_reset"]==1)
983
+ {
984
+ $sql="DELETE $ccpt.*
985
+ FROM $ccpt
986
+ JOIN $cce ON $cce.entity_id=$ccpt.category_id
987
+ WHERE product_id=?";
988
+ $this->delete($sql,$pid);
989
+ }
990
+
991
+
992
+ $inserts=array();
993
+ $data=array();
994
+ $cdata=array();
995
+ $ddata=array();
996
+ $cpos=array();
997
+ $catids=csl2arr($item["category_ids"]);
998
+
999
+ //find positive category assignments
1000
+
1001
+ foreach($catids as $catdef)
1002
+ {
1003
+ $a=explode("::",$catdef);
1004
+ $catid=$a[0];
1005
+ $catpos=(count($a)>1?$a[1]:"0");
1006
+ $rel=getRelative($catid);
1007
+ if($rel=="-")
1008
+ {
1009
+ $ddata[]=$catid;
1010
+ }
1011
+ else
1012
+ {
1013
+ $cdata[]=$catid;
1014
+ $cpos[]=$catpos;
1015
+ }
1016
+ }
1017
+
1018
+ //get all "real ids"
1019
+ $rcatids=$this->selectAll("SELECT cce.entity_id as id FROM $cce as cce WHERE cce.entity_id IN (".$this->arr2values($cdata).")",$cdata);
1020
+ $vcatids=array();
1021
+ foreach($rcatids as $rcatrow)
1022
+ {
1023
+ $vcatids[]=$rcatrow['id'];
1024
+ }
1025
+ //now get the diff
1026
+ $diff=array_diff($cdata,$vcatids);
1027
+ //if there are some, warning
1028
+ if(count($diff)>0)
1029
+ {
1030
+ $this->log('Invalid category ids found for sku '.$item['sku'].":".implode(",",$diff),"warning");
1031
+ }
1032
+
1033
+ $cdata=$vcatids;
1034
+ if(count($cdata)==0)
1035
+ {
1036
+ $this->log('No valid categories found, skip category assingment for sku '.$item['sku'],"warning");
1037
+ }
1038
+
1039
+ #now we have verified ids
1040
+ for($i=0;$i<count($cdata);$i++)
1041
+ {
1042
+ $inserts[]="(?,?,?)";
1043
+ $data[]=$cdata[$i];
1044
+ $data[]=$pid;
1045
+ $data[]=$cpos[$i];
1046
+ }
1047
+
1048
+ #peform deletion of removed category affectation
1049
+ if(count($ddata)>0)
1050
+ {
1051
+ $sql="DELETE FROM $ccpt WHERE category_id IN (".$this->arr2values($ddata).") AND product_id=?";
1052
+ $ddata[]=$pid;
1053
+ $this->delete($sql,$ddata);
1054
+ unset($ddata);
1055
+ }
1056
+
1057
+
1058
+
1059
+ #create new category assignment for products, if multi store with repeated ids
1060
+ #ignore duplicates
1061
+ if(count($inserts)>0)
1062
+ {
1063
+ $sql="INSERT INTO $ccpt (`category_id`,`product_id`,`position`)
1064
+ VALUES ";
1065
+ $sql.=implode(",",$inserts);
1066
+ $sql.="ON DUPLICATE KEY UPDATE position=VALUES(`position`)";
1067
+ $this->insert($sql,$data);
1068
+ unset($data);
1069
+ }
1070
+ unset($deletes);
1071
+ unset($inserts);
1072
+ }
1073
+
1074
+
1075
+ public function getItemWebsites($item,$default=false)
1076
+ {
1077
+ if(!isset($item['store']))
1078
+ {
1079
+ $item['store']="admin";
1080
+ }
1081
+ $k=$item["store"];
1082
+
1083
+ if(!isset($this->_wsids[$k]))
1084
+ {
1085
+ $this->_wsids[$k]=array();
1086
+ $cs=$this->tablename("core_store");
1087
+ if(trim($k)!="admin")
1088
+ {
1089
+ $scodes=csl2arr($k);
1090
+ $qcolstr=$this->arr2values($scodes);
1091
+ $rows=$this->selectAll("SELECT website_id FROM $cs WHERE code IN ($qcolstr) AND store_id!=0 GROUP BY website_id",$scodes);
1092
+ }
1093
+ else
1094
+ {
1095
+ $rows=$this->selectAll("SELECT website_id FROM $cs WHERE store_id!=0 GROUP BY website_id ");
1096
+ }
1097
+ foreach($rows as $row)
1098
+ {
1099
+ $this->_wsids[$k][]=$row['website_id'];
1100
+ }
1101
+ }
1102
+ return $this->_wsids[$k];
1103
+
1104
+ }
1105
+
1106
+ /**
1107
+ * set website of product if not exists
1108
+ * @param int $pid : product id
1109
+ * @param array $item : attribute values for product indexed by attribute_code
1110
+ */
1111
+ public function updateWebSites($pid,$item)
1112
+ {
1113
+ $wsids=$this->getItemWebsites($item);
1114
+ $qcolstr=$this->arr2values($wsids);
1115
+ $cpst=$this->tablename("catalog_product_website");
1116
+ $cws=$this->tablename("core_website");
1117
+ //associate product with all websites in a single multi insert (use ignore to avoid duplicates)
1118
+ $sql="INSERT IGNORE INTO `$cpst` (`product_id`, `website_id`) SELECT ?,website_id FROM $cws WHERE website_id IN ($qcolstr)";
1119
+ $this->insert($sql,array_merge(array($pid),$wsids));
1120
+ }
1121
+
1122
+
1123
+
1124
+ public function clearOptCache()
1125
+ {
1126
+ unset($this->_optidcache);
1127
+ $this->_optidcache=array();
1128
+ }
1129
+
1130
+ public function onNewSku($sku,$existing)
1131
+ {
1132
+ $this->clearOptCache();
1133
+ //only assign values to store 0 by default in create mode for new sku
1134
+ //for store related options
1135
+ if(!$existing)
1136
+ {
1137
+ $this->_dstore=array(0);
1138
+ }
1139
+ else
1140
+ {
1141
+ $this->_dstore=array();
1142
+ }
1143
+ $this->_same=false;
1144
+ }
1145
+
1146
+ public function onSameSku($sku)
1147
+ {
1148
+ unset($this->_dstore);
1149
+ $this->_dstore=array();
1150
+ $this->_same=true;
1151
+ }
1152
+
1153
+
1154
+ public function getItemIds($item)
1155
+ {
1156
+ $sku=$item["sku"];
1157
+ if($sku!=$this->_curitemids["sku"])
1158
+ {
1159
+ //try to find item ids in db
1160
+ $cids=$this->getProductIds($sku);
1161
+ if($cids!==false)
1162
+ {
1163
+ //if found use it
1164
+ $this->_curitemids=$cids;
1165
+ }
1166
+ else
1167
+ {
1168
+ //only sku & attribute set id from datasource otherwise.
1169
+ $this->_curitemids=array("pid"=>null,"sku"=>$sku,"asid"=>isset($item["attribute_set"])?$this->getAttributeSetId($item["attribute_set"]):$this->default_asid);
1170
+ }
1171
+ //do not reset values for existing if non admin
1172
+ $this->onNewSku($sku,($cids!==false));
1173
+ unset($cids);
1174
+ }
1175
+ else
1176
+ {
1177
+ $this->onSameSku($sku);
1178
+ }
1179
+ return $this->_curitemids;
1180
+ }
1181
+
1182
+ public function handleIgnore(&$item)
1183
+ {
1184
+ //filter __MAGMI_IGNORE__ COLUMNS
1185
+ foreach($item as $k=>$v)
1186
+ {
1187
+ if($v=="__MAGMI_IGNORE__")
1188
+ {
1189
+ unset($item[$k]);
1190
+ }
1191
+ }
1192
+ }
1193
+ public function findItemStores($pid)
1194
+ {
1195
+ $sql="SELECT cs.code FROM ".$this->tablename("catalog_product_website")." AS cpw".
1196
+ " JOIN ".$this->tablename("core_store")." as cs ON cs.website_id=cpw.website_id".
1197
+ " WHERE cpw.product_id=?";
1198
+ $result=$this->selectAll($sql,array($pid));
1199
+ $scodes=array();
1200
+ foreach($result as $row)
1201
+ {
1202
+ $scodes[]=$row["code"];
1203
+ }
1204
+ return implode(",",$scodes);
1205
+ }
1206
+
1207
+ public function checkItemStores($scodes)
1208
+ {
1209
+ if($scodes=="admin")
1210
+ {
1211
+ return $scodes;
1212
+ }
1213
+
1214
+ $scarr=explode(",",$scodes);
1215
+ trimarray($scarr);
1216
+ $rscode=array();
1217
+ $sql="SELECT code FROM ".$this->tablename("core_store")." WHERE code IN (".$this->arr2values($scarr).")";
1218
+ $result=$this->selectAll($sql,$scarr);
1219
+ $rscodes=array();
1220
+ foreach($result as $row)
1221
+ {
1222
+ $rscodes[]=$row["code"];
1223
+ }
1224
+ $diff=array_diff($scarr, $rscodes);
1225
+ $out="";
1226
+ if(count($diff)>0)
1227
+ {
1228
+ $out="Invalid store code(s) found:".implode(",",$diff);
1229
+ }
1230
+ if($out!="")
1231
+ {
1232
+ if(count($rscodes)==0)
1233
+ {
1234
+ $out.=", NO VALID STORE FOUND";
1235
+ }
1236
+ $this->log($out,"warning");
1237
+ }
1238
+
1239
+ return implode(",",$rscodes);
1240
+ }
1241
+
1242
+ public function checkstore(&$item,$pid,$isnew)
1243
+ {
1244
+ //we have store column set , just check
1245
+ if(isset($item["store"]) && trim($item["store"])!="")
1246
+ {
1247
+ $scodes=$this->checkItemStores($item["store"]);
1248
+ }
1249
+ else
1250
+ {
1251
+ $scodes="admin";
1252
+ }
1253
+ if($scodes=="")
1254
+ {
1255
+ return false;
1256
+ }
1257
+ $item["store"]=$scodes;
1258
+ return true;
1259
+ }
1260
+ /**
1261
+ * full import workflow for item
1262
+ * @param array $item : attribute values for product indexed by attribute_code
1263
+ */
1264
+ public function importItem($item)
1265
+ {
1266
+
1267
+ $this->handleIgnore($item);
1268
+ if(Magmi_StateManager::getState()=="canceled")
1269
+ {
1270
+ exit();
1271
+ }
1272
+ //first step
1273
+
1274
+ if(!$this->callPlugins("itemprocessors","processItemBeforeId",$item))
1275
+ {
1276
+ return false;
1277
+ }
1278
+
1279
+ //check if sku has been reset
1280
+ if(!isset($item["sku"]) || trim($item["sku"])=='')
1281
+ {
1282
+ $this->log('No sku info found for record #'.$this->_current_row,"error");
1283
+ return false;
1284
+ }
1285
+ //handle "computed" ignored columns
1286
+ $this->handleIgnore($item);
1287
+ //get Item identifiers in magento
1288
+ $itemids=$this->getItemIds($item);
1289
+
1290
+ //extract product id & attribute set id
1291
+ $pid=$itemids["pid"];
1292
+ $asid=$itemids["asid"];
1293
+
1294
+ $isnew=false;
1295
+ if(isset($pid) && $this->mode=="xcreate")
1296
+ {
1297
+ $this->log("skipping existing sku:{$item["sku"]} - xcreate mode set","skip");
1298
+ return false;
1299
+ }
1300
+
1301
+ if(!isset($pid))
1302
+ {
1303
+
1304
+ if($this->mode!=='update')
1305
+ {
1306
+ if(!isset($asid))
1307
+ {
1308
+ $this->log("cannot create product sku:{$item["sku"]}, no attribute_set defined","error");
1309
+ return false;
1310
+ }
1311
+ $pid=$this->createProduct($item,$asid);
1312
+ $this->_curitemids["pid"]=$pid;
1313
+ $isnew=true;
1314
+ }
1315
+ else
1316
+ {
1317
+ //mode is update, do nothing
1318
+ $this->log("skipping unknown sku:{$item["sku"]} - update mode set","skip");
1319
+ return false;
1320
+ }
1321
+ }
1322
+ else
1323
+ {
1324
+ $this->updateProduct($item,$pid);
1325
+ }
1326
+
1327
+ try
1328
+ {
1329
+ if(!$this->callPlugins("itemprocessors","processItemAfterId",$item,array("product_id"=>$pid,"new"=>$isnew,"same"=>$this->_same,"asid"=>$asid)))
1330
+ {
1331
+ return false;
1332
+ }
1333
+
1334
+
1335
+
1336
+ if(count($item)==0)
1337
+ {
1338
+ return true;
1339
+ }
1340
+ //handle "computed" ignored columns from afterImport
1341
+ $this->handleIgnore($item);
1342
+
1343
+ if(!$this->checkstore($item,$pid,$isnew))
1344
+ {
1345
+ $this->log("invalid store value, skipping item sku:".$item["sku"]);
1346
+ return false;
1347
+ }
1348
+ //create new ones
1349
+ $attrmap=$this->attrbytype;
1350
+ do
1351
+ {
1352
+ $attrmap=$this->createAttributes($pid,$item,$attrmap,$isnew);
1353
+ }
1354
+ while(count($attrmap)>0);
1355
+
1356
+ if(!testempty($item,"category_ids"))
1357
+ {
1358
+ //assign categories
1359
+ $this->assignCategories($pid,$item);
1360
+ }
1361
+
1362
+ //update websites
1363
+ if($this->mode!="update")
1364
+ {
1365
+ $this->updateWebSites($pid,$item);
1366
+ }
1367
+
1368
+ if(!$this->_same)
1369
+ {
1370
+ //update stock
1371
+ $this->updateStock($pid,$item,$isnew);
1372
+ }
1373
+
1374
+ $this->touchProduct($pid);
1375
+ //ok,we're done
1376
+ if(!$this->callPlugins("itemprocessors","processItemAfterImport",$item,array("product_id"=>$pid,"new"=>$isnew,"same"=>$this->_same)))
1377
+ {
1378
+ return false;
1379
+ }
1380
+ }
1381
+ catch(Exception $e)
1382
+ {
1383
+ $this->callPlugins(array("itemprocessors"),"processItemException",$item,array("exception"=>$e));
1384
+ $this->logException($e,$this->_laststmt->queryString);
1385
+ throw $e;
1386
+ }
1387
+ return true;
1388
+ }
1389
+
1390
+ public function getProperties()
1391
+ {
1392
+ return $this->_props;
1393
+ }
1394
+
1395
+ /**
1396
+ * count lines of csv file
1397
+ * @param string $csvfile filename
1398
+ */
1399
+ public function lookup()
1400
+ {
1401
+ $t0=microtime(true);
1402
+ $this->log("Performing Datasouce Lookup...","startup");
1403
+
1404
+ $count=$this->datasource->getRecordsCount();
1405
+ $t1=microtime(true);
1406
+ $time=$t1-$t0;
1407
+ $this->log("$count:$time","lookup");
1408
+ $this->log("Found $count records, took $time sec","startup");
1409
+
1410
+ return $count;
1411
+ }
1412
+
1413
+
1414
+
1415
+ public function updateProduct($item,$pid)
1416
+ {
1417
+ $tname=$this->tablename('catalog_product_entity');
1418
+ if(isset($item['type']))
1419
+ {
1420
+ $item['type_id']=$item['type'];
1421
+ }
1422
+ $item['entity_type_id']=$this->prod_etype;
1423
+ $item['updated_at']=strftime("%Y-%m-%d %H:%M:%S");
1424
+ $columns=array_intersect(array_keys($item), $this->getProdCols());
1425
+ $values=$this->filterkvarr($item, $columns);
1426
+
1427
+ $sql="UPDATE `$tname` SET ".$this->arr2update($values). " WHERE entity_id=?";
1428
+
1429
+ $this->update($sql,array_merge(array_values($values),array($pid)));
1430
+
1431
+ }
1432
+
1433
+ public function getProductEntityType()
1434
+ {
1435
+ return $this->prod_etype;
1436
+ }
1437
+
1438
+ public function getCurrentRow()
1439
+ {
1440
+ return $this->_current_row;
1441
+ }
1442
+
1443
+ public function setCurrentRow($cnum)
1444
+ {
1445
+ $this->_current_row=$cnum;
1446
+ }
1447
+
1448
+ public function isLastItem($item)
1449
+ {
1450
+ return isset($item["__MAGMI_LAST__"]);
1451
+ }
1452
+
1453
+ public function setLastItem(&$item)
1454
+ {
1455
+ $item["__MAGMI_LAST__"]=1;
1456
+ }
1457
+
1458
+ public function engineInit($params)
1459
+ {
1460
+ $this->_profile=$this->getParam($params,"profile","default");
1461
+ //create an instance of local magento directory handler
1462
+ //this instance will autoregister in factory
1463
+ $mdh=new LocalMagentoDirHandler(Magmi_Config::getInstance()->getMagentoDir());
1464
+
1465
+ $this->initPlugins($this->_profile);
1466
+ $this->mode=$this->getParam($params,"mode","update");
1467
+
1468
+ }
1469
+
1470
+
1471
+ public function reportStats($nrow,&$tstart,&$tdiff,&$lastdbtime,&$lastrec)
1472
+ {
1473
+ $tend=microtime(true);
1474
+ $this->log($nrow." - ".($tend-$tstart)." - ".($tend-$tdiff),"itime");
1475
+ $this->log($this->_nreq." - ".($this->_indbtime)." - ".($this->_indbtime-$lastdbtime)." - ".($this->_nreq-$lastrec),"dbtime");
1476
+ $lastrec=$this->_nreq;
1477
+ $lastdbtime=$this->_indbtime;
1478
+ $tdiff=microtime(true);
1479
+ }
1480
+
1481
+
1482
+
1483
+ public function initImport($params)
1484
+ {
1485
+ $this->log("MAGMI by dweeves - version:".Magmi_Version::$version,"title");
1486
+ $this->log("Import Profile:$this->_profile","startup");
1487
+ $this->log("Import Mode:$this->mode","startup");
1488
+ $this->log("step:".$this->getProp("GLOBAL","step",0.5)."%","step");
1489
+ //intialize store id cache
1490
+ $this->connectToMagento();
1491
+ try
1492
+ {
1493
+ $this->initProdType();
1494
+ $this->createPlugins($this->_profile,$params);
1495
+ $this->_registerPluginLoopCallback("processItemAfterId", "onPluginProcessedItemAfterId");
1496
+ $this->callPlugins("datasources,itemprocessors","startImport");
1497
+ $this->resetSkuStats();
1498
+ }
1499
+ catch(Exception $e)
1500
+ {
1501
+ $this->disconnectFromMagento();
1502
+ }
1503
+ }
1504
+
1505
+ public function onPluginProcessedItemAfterId($plinst,&$item,$plresult)
1506
+ {
1507
+ $this->handleIgnore($item);
1508
+ }
1509
+
1510
+ public function exitImport()
1511
+ {
1512
+ $this->callPlugins("datasources,general,itemprocessors","endImport");
1513
+ $this->callPlugins("datasources,general,itemprocessors","afterImport");
1514
+ $this->disconnectFromMagento();
1515
+ }
1516
+
1517
+ public function updateSkuStats($res)
1518
+ {
1519
+ if(!$this->_same)
1520
+ {
1521
+ $this->_skustats["nsku"]++;
1522
+ if($res["ok"])
1523
+ {
1524
+ $this->_skustats["ok"]++;
1525
+ }
1526
+ else
1527
+ {
1528
+ $this->_skustats["ko"]++;
1529
+ }
1530
+ }
1531
+ }
1532
+ public function getDataSource()
1533
+ {
1534
+ return $this->getPluginInstance("datasources");
1535
+
1536
+ }
1537
+
1538
+ public function processDataSourceLine($item,$rstep,&$tstart,&$tdiff,&$lastdbtime,&$lastrec)
1539
+ {
1540
+ //counter
1541
+ $res=array("ok"=>0,"last"=>0);
1542
+ $this->_current_row++;
1543
+ if($this->_current_row%$rstep==0)
1544
+ {
1545
+ $this->reportStats($this->_current_row,$tstart,$tdiff,$lastdbtime,$lastrec);
1546
+ }
1547
+ try
1548
+ {
1549
+ if(is_array($item) && count($item)>0)
1550
+ {
1551
+ //import item
1552
+ $this->beginTransaction();
1553
+ $importedok=$this->importItem($item);
1554
+ if($importedok)
1555
+ {
1556
+ $res["ok"]=true;
1557
+ $this->commitTransaction();
1558
+ }
1559
+ else
1560
+ {
1561
+ $res["ok"]=false;
1562
+ $this->rollbackTransaction();
1563
+
1564
+ }
1565
+ }
1566
+ else
1567
+ {
1568
+ $this->log("ERROR - RECORD #$this->_current_row - INVALID RECORD","error");
1569
+ }
1570
+ //intermediary measurement
1571
+
1572
+ }
1573
+ catch(Exception $e)
1574
+ {
1575
+ $this->rollbackTransaction();
1576
+ $res["ok"]=false;
1577
+ $this->logException($e,"ERROR ON RECORD #$this->_current_row");
1578
+ }
1579
+ if($this->isLastItem($item))
1580
+ {
1581
+ unset($item);
1582
+ $res["last"]=1;
1583
+ }
1584
+
1585
+ unset($item);
1586
+ $this->updateSkuStats($res);
1587
+
1588
+ return $res;
1589
+
1590
+ }
1591
+
1592
+ public function resetSkuStats()
1593
+ {
1594
+ $this->_skustats=array("nsku"=>0,"ok"=>0,"ko"=>0);
1595
+ }
1596
+
1597
+
1598
+ public function engineRun($params,$forcebuiltin=array())
1599
+ {
1600
+
1601
+ $this->log("Import Profile:$this->_profile","startup");
1602
+ $this->log("Import Mode:$this->mode","startup");
1603
+ $this->log("step:".$this->getProp("GLOBAL","step",0.5)."%","step");
1604
+ $this->createPlugins($this->_profile,$params);
1605
+ $this->datasource=$this->getDataSource();
1606
+ $this->callPlugins("datasources,general","beforeImport");
1607
+ $nitems=$this->lookup();
1608
+ Magmi_StateManager::setState("running");
1609
+ //if some rows found
1610
+ if($nitems>0)
1611
+ {
1612
+ $this->resetSkuStats();
1613
+ //intialize store id cache
1614
+ $this->callPlugins("datasources,itemprocessors","startImport");
1615
+ //initializing item processors
1616
+ $cols=$this->datasource->getColumnNames();
1617
+ $this->log(count($cols),"columns");
1618
+ $this->callPlugins("itemprocessors","processColumnList",$cols);
1619
+ $this->log("Ajusted processed columns:".count($cols),"startup");
1620
+ $this->initProdType();
1621
+ //initialize attribute infos & indexes from column names
1622
+ if($this->mode!="update")
1623
+ {
1624
+ $this->checkRequired($cols);
1625
+ }
1626
+ $this->initAttrInfos(array_values($cols));
1627
+ //counter
1628
+ $this->_current_row=0;
1629
+ //start time
1630
+ $tstart=microtime(true);
1631
+ //differential
1632
+ $tdiff=$tstart;
1633
+ //intermediary report step
1634
+ $this->initDbqStats();
1635
+ $pstep=$this->getProp("GLOBAL","step",0.5);
1636
+ $rstep=ceil(($nitems*$pstep)/100);
1637
+ //read each line
1638
+ $lastrec=0;
1639
+ $lastdbtime=0;
1640
+ while(($item=$this->datasource->getNextRecord())!==false)
1641
+ {
1642
+ $res=$this->processDataSourceLine($item, $rstep,$tstart,$tdiff,$lastdbtime,$lastrec);
1643
+ //break on "forced" last
1644
+ if($res["last"])
1645
+ {
1646
+ break;
1647
+ }
1648
+ }
1649
+ $this->callPlugins("datasources,general,itemprocessors","endImport");
1650
+ $this->reportStats($this->_current_row,$tstart,$tdiff,$lastdbtime,$lastrec);
1651
+ $this->log("Skus imported OK:".$this->_skustats["ok"]."/".$this->_skustats["nsku"],"info");
1652
+ if($this->_skustats["ko"]>0)
1653
+ {
1654
+ $this->log("Skus imported KO:".$this->_skustats["ko"]."/".$this->_skustats["nsku"],"warning");
1655
+ }
1656
+ }
1657
+ else
1658
+ {
1659
+ $this->log("No Records returned by datasource","warning");
1660
+ }
1661
+ $this->callPlugins("datasources,general,itemprocessors","afterImport");
1662
+
1663
+ $this->log("Import Ended","end");
1664
+ Magmi_StateManager::setState("idle");
1665
+ }
1666
+
1667
+ public function onEngineException($e)
1668
+ {
1669
+ if(isset($this->datasource))
1670
+ {
1671
+ $this->datasource->onException($e);
1672
+ }
1673
+ $this->log("Import Ended","end");
1674
+
1675
+ Magmi_StateManager::setState("idle");
1676
+ }
1677
+
1678
+ }
lib/Magmi/engines/magmi_utilityengine.php ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * MAGENTO MASS IMPORTER CLASS
5
+ *
6
+ * version : 0.6
7
+ * author : S.BRACQUEMONT aka dweeves
8
+ * updated : 2010-10-09
9
+ *
10
+ */
11
+
12
+ /* use external file for db helper */
13
+ require_once("magmi_engine.php");
14
+ require_once("magmi_pluginhelper.php");
15
+
16
+
17
+ /* Magmi ProductImporter is now a Magmi_Engine instance */
18
+ class Magmi_UtilityEngine extends Magmi_Engine
19
+ {
20
+
21
+ /**
22
+ * constructor
23
+ * @param string $conffile : configuration .ini filename
24
+ */
25
+ public function __construct()
26
+ {
27
+ }
28
+
29
+ public function getEnabledPluginClasses($profile)
30
+ {
31
+ $clist=Magmi_PluginHelper::getInstance("main")->getPluginsInfo("utilities","class");
32
+ return $clist;
33
+ }
34
+
35
+ public function getEngineInfo()
36
+ {
37
+ return array("name"=>"Magmi Utilities Engine","version"=>"1.0.1","author"=>"dweeves");
38
+ }
39
+
40
+ /**
41
+ * load properties
42
+ * @param string $conf : configuration .ini filename
43
+ */
44
+
45
+ public function getPluginFamilies()
46
+ {
47
+ return array("utilities");
48
+ }
49
+
50
+ public function engineInit($params)
51
+ {
52
+ $this->initPlugins(null);
53
+ }
54
+
55
+ public function engineRun($params)
56
+ {
57
+ $this->log("Magento Mass Importer by dweeves - version:".Magmi_Version::$version,"title");
58
+ //initialize db connectivity
59
+ Magmi_StateManager::setState("running");
60
+ //force only one class to run
61
+ $this->_pluginclasses=array("utilities"=>array($params["pluginclass"]));
62
+
63
+ $this->createPlugins("__utilities__",$params);
64
+ foreach($this->_activeplugins["utilities"] as $pinst)
65
+ {
66
+ try
67
+ {
68
+ $pinst->runUtility();
69
+ }
70
+ catch(Exception $e)
71
+ {
72
+ $this->logException($e);
73
+ }
74
+ }
75
+
76
+ Magmi_StateManager::setState("idle");
77
+ }
78
+
79
+ public function onEngineException($e)
80
+ {
81
+ Magmi_StateManager::setState("idle");
82
+ }
83
+
84
+ }
lib/Magmi/inc/dbhelper.class.php ADDED
@@ -0,0 +1,593 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ *
4
+ * This class is a Database Operation Helper based on PDO library
5
+ * It provides shortcuts for common DB CRUD operations and some advanced templated requests operations
6
+ * @author dweeves
7
+ *
8
+ */
9
+ class DBHelper
10
+ {
11
+ protected $_db;
12
+ protected $_debug;
13
+ protected $_laststmt;
14
+ protected $_use_stmt_cache=true;
15
+ protected $_nreq;
16
+ protected $_indbtime;
17
+ protected $_intrans=false;
18
+ protected $prepared=array();
19
+ /**
20
+ * Intializes database connection
21
+ * @param string $host : hostname
22
+ * @param string $dbname : database name
23
+ * @param string $user : username
24
+ * @param string $pass : password
25
+ * @param bool $debug : debug mode
26
+ */
27
+ public function initDb($host,$dbname,$user,$pass,$port=3306,$socket="/tmp/mysql.sock",$conntype="net",$debug=false)
28
+ {
29
+ //intialize connection with PDO
30
+ //fix by Mr Lei for UTF8 special chars
31
+ if($conntype=="net")
32
+ {
33
+ $pdostr="mysql:host=$host;port=$port;dbname=$dbname;charset=utf8";
34
+ }
35
+ else
36
+ {
37
+ $pdostr="mysql:unix_socket=$socket;dbname=$dbname;charset=utf8";
38
+ }
39
+
40
+ //FB: patch for magento
41
+ $this->_db = Mage::getSingleton('core/resource')->getConnection('core_write')->getConnection();
42
+ /*
43
+ $this->_db=new PDO($pdostr, $user, $pass,array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));
44
+ //use exception error mode
45
+ $this->_db->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
46
+ $this->_db->setAttribute(PDO::ATTR_ORACLE_NULLS ,PDO::NULL_NATURAL);
47
+ $this->_db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE,PDO::FETCH_ASSOC);
48
+ */
49
+
50
+ //set database debug mode to trace if necessary
51
+ $this->_debug=$debug;
52
+ $this->prepared=array();
53
+
54
+ }
55
+ /**
56
+ *
57
+ * store output in some debug file
58
+ * @param unknown_type $data
59
+ */
60
+ public function logdebug($data)
61
+ {
62
+ if($this->_debug)
63
+ {
64
+ $f=fopen($this->_debugfile,"a");
65
+ fwrite($f,microtime());
66
+ fwrite($f,$data);
67
+ fwrite($f,"\n");
68
+ fclose($f);
69
+ }
70
+ }
71
+ /**
72
+ *
73
+ * Sets or unsets the usage of internal prepared statement cache for reuse
74
+ * @param boolean $uc true:use cache,false:do not use cache
75
+ */
76
+ public function usestmtcache($uc)
77
+ {
78
+ $this->_use_stmt_cache=$uc;
79
+ }
80
+
81
+ /**
82
+ * releases database connection
83
+ */
84
+ public function exitDb()
85
+ {
86
+ //clear PDO resource
87
+ $this->_db=NULL;
88
+
89
+ }
90
+
91
+ /**
92
+ *
93
+ * Helper method to try to guess mysql socket based on some tricky phpinfo analysis
94
+ * @throws Exception if something got wrong during detection
95
+ */
96
+ public static function getMysqlSocket()
97
+ {
98
+ $mysqlsock="";
99
+ $old_track = ini_set('track_errors', '1');
100
+ try
101
+ {
102
+ $mysqlsock=ini_get("mysql.default_socket");
103
+
104
+ if(isset($mysqlsock) && !@file_exists($mysqlsock))
105
+ {
106
+ if(error_get_last()!==null)
107
+ {
108
+ throw new Exception();
109
+ }
110
+ ob_start();
111
+ phpinfo();
112
+ $data=ob_get_contents();
113
+ ob_end_clean();
114
+ $cap=preg_match("/MYSQL_SOCKET.*?<td .*?>(.*?)<\/td>/msi",$data,$matches);
115
+ if($cap)
116
+ {
117
+ $mysqlsock=$matches[1];
118
+ }
119
+ }
120
+ if(isset($mysqlsock) && !@file_exists($mysqlsock))
121
+ {
122
+ $mysqlsock="";
123
+ }
124
+
125
+ }
126
+ catch(Exception $e)
127
+ {
128
+ }
129
+ if(error_get_last()!==null)
130
+ {
131
+ $mysqlsock=false;
132
+ }
133
+ ini_set('track_errors',$old_track);
134
+ return $mysqlsock;
135
+ }
136
+
137
+ /**
138
+ *
139
+ * Initializes database requests stats counters
140
+ */
141
+ public function initDbqStats()
142
+ {
143
+ $this->_nreq=0;
144
+ $this->_indbtime=0;
145
+ }
146
+
147
+ /**
148
+ *
149
+ * Enter description here ...
150
+ * @param unknown_type $nbreq
151
+ */
152
+ public function collectDbqStats(&$nbreq)
153
+ {
154
+ return $this->_nreq;
155
+ }
156
+
157
+ /**
158
+ * cache sorting comparison method
159
+ *
160
+ * @param unknown_type $a
161
+ * @param unknown_type $b
162
+ */
163
+ public function cachesort($a,$b)
164
+ {
165
+ return $b[1]-$a[1];
166
+ }
167
+
168
+ /**
169
+ * Garbages statement cache if above 500 , removes less used statements
170
+ * Enter description here ...
171
+ */
172
+ public function garbageStmtCache()
173
+ {
174
+ if(count($this->prepared)>=500)
175
+ {
176
+ uasort($this->prepared,array($this,"cachesort"));
177
+ array_splice($this->prepared,350,count($this->prepared));
178
+ }
179
+ }
180
+ /**
181
+ * executes an sql statement
182
+ * @param string $sql : sql statement (may include ? placeholders or named variables)
183
+ * @param array $params : parameters to replace placeholders (can be null)
184
+ * @param boolean $close : auto close cursor after statement execution (defaults to true)
185
+ * @return PDOStatement : statement for further processing if needed
186
+ */
187
+ public function exec_stmt($sql,$params=null,$close=true)
188
+ {
189
+ $this->_nreq++;
190
+ $t0=microtime(true);
191
+
192
+ if($this->_use_stmt_cache && strpos($sql,"'")==false)
193
+ {
194
+ //if sql not in statement cache
195
+ if(!isset($this->prepared[$sql]))
196
+ {
197
+ $this->garbageStmtCache();
198
+ //create new prepared statement
199
+ $stmt=$this->_db->prepare($sql);
200
+ //cache prepare statement
201
+ $this->prepared[$sql]=array($stmt,1);
202
+ }
203
+ else
204
+ {
205
+ //get from statement cache
206
+ $this->prepared[$sql][1]++;
207
+ $stmt=$this->prepared[$sql][0];
208
+ }
209
+ }
210
+ else
211
+ {
212
+ //create new prepared statement
213
+ $stmt=$this->_db->prepare($sql);
214
+ }
215
+ $this->_laststmt=$stmt;
216
+ if($params!=null)
217
+ {
218
+ if(!$this->is_assoc($params))
219
+ {
220
+ $params=is_array($params)?$params:array($params);
221
+ $stmt->execute($params);
222
+ }
223
+ else
224
+ {
225
+ foreach($params as $pname=>$pval)
226
+ {
227
+ if(count(explode(":",$pname))==1)
228
+ {
229
+ $val=strval($pval);
230
+ $stmt->bindValue(":$pname",$val);
231
+ }
232
+ }
233
+ $stmt->execute();
234
+ }
235
+ }
236
+ else
237
+ {
238
+
239
+ $stmt->execute();
240
+ }
241
+ if($close)
242
+ {
243
+ $stmt->closeCursor();
244
+ }
245
+ $t1=microtime(true);
246
+ $this->_indbtime+=$t1-$t0;
247
+ $this->logdebug("$sql\n".print_r($params,true));
248
+ unset($params);
249
+ return $stmt;
250
+ }
251
+
252
+ /**
253
+ * Perform a delete statement, sql should be "DELETE"
254
+ * @param string $sql : DELETE statement sql (placeholders allowed)
255
+ * @param array $params : placeholder replacements (can be null)
256
+ */
257
+ public function delete($sql,$params=null)
258
+ {
259
+ $this->exec_stmt($sql,$params);
260
+ }
261
+
262
+ /**
263
+ * Performs an update statement
264
+ * Enter description here ...
265
+ * @param string $sql UPDATE statement sql (placeholder allowed)
266
+ * @param array $params parameter values if placeholders in SQL
267
+ */
268
+ public function update($sql,$params=null)
269
+ {
270
+ $this->exec_stmt($sql,$params);
271
+ }
272
+ /**
273
+ * Perform an insert , sql should be "INSERT"
274
+ * @param string $sql :INSERT statement SQL (placeholders allowed)
275
+ * @param array $params : placeholder replacements (can be null)
276
+ * @return mixed : last inserted id
277
+ */
278
+ public function insert($sql,$params=null)
279
+ {
280
+ $this->exec_stmt($sql,$params);
281
+ $liid=$this->_db->lastInsertId();
282
+ return $liid;
283
+ }
284
+
285
+ /**
286
+ * Perform a select ,sql should be "SELECT"
287
+ * @param string $sql :SELECT statement SQL (placeholders allowed)
288
+ * @param array $params : placeholder replacements (can be null)
289
+ * @return PDOStatement : statement instance for further processing
290
+ */
291
+ public function select($sql,$params=null)
292
+ {
293
+ return $this->exec_stmt($sql,$params,false);
294
+ }
295
+
296
+ /**
297
+ * Selects one unique value from one single row
298
+ * @param $sql : SELECT statement SQL (placeholders allowed)
299
+ * @param $params :placeholder replacements (can be null)
300
+ * @param $col : column value to retrieve
301
+ * @return mixed : null if not result , wanted column value if match
302
+ */
303
+ public function selectone($sql,$params,$col)
304
+ {
305
+ $stmt=$this->select($sql,$params);
306
+ $t0=microtime(true);
307
+
308
+ $r=$stmt->fetch(PDO::FETCH_ASSOC);
309
+ $stmt->closeCursor();
310
+ $t1=microtime(true);
311
+ $this->_indbtime+=$t1-$t0;
312
+ $v=(is_array($r)?$r[$col]:null);
313
+ unset($r);
314
+ return $v;
315
+ }
316
+
317
+ /**
318
+ * Selects all values from a statement into a php array
319
+ * @param unknown_type $sql sql select to execute
320
+ * @param unknown_type $params placeholder replacements (can be null)
321
+ */
322
+ public function selectAll($sql,$params=null)
323
+ {
324
+ $stmt=$this->select($sql,$params);
325
+ $t0=microtime(true);
326
+
327
+ $r=$stmt->fetchAll(PDO::FETCH_ASSOC);
328
+ $stmt->closeCursor();
329
+ $t1=microtime(true);
330
+ $this->_indbtime+=$t1-$t0;
331
+ return $r;
332
+ }
333
+
334
+ /**
335
+ * test if value exists (test should be compatible with unique select)
336
+ * @param $sql : SELECT statement SQL (placeholders allowed)
337
+ * @param $params :placeholder replacements (can be null)
338
+ * @param $col : column value to retrieve
339
+ * @return boolean : true if value found, false otherwise
340
+ */
341
+ public function testexists($sql,$params,$col)
342
+ {
343
+ return $this->selectone($sql,$params,$col)!=null;
344
+ }
345
+
346
+ /**
347
+ * Quote array values in order to be used as parameters (handy if array used directly in explode in a IN condition)
348
+ * Enter description here ...
349
+ * @param array $arr array of values to be quoted
350
+ */
351
+ public function quotearr($arr)
352
+ {
353
+ $arrout=array();
354
+ foreach($arr as $v)
355
+ {
356
+ $arrout[]=$this->_db->quote($v);
357
+ }
358
+ return $arrout;
359
+ }
360
+
361
+ /**
362
+ *
363
+ * transforms an array in a comma separated list of enclosed column names for request
364
+ * @param array $arr list of names to enclose
365
+ */
366
+ public function arr2columns($arr)
367
+ {
368
+ $arrout=array();
369
+ foreach($arr as $cname)
370
+ {
371
+ $arrout[]="`".$cname."`";
372
+ }
373
+ $colstr=implode(",",$arrout);
374
+ unset($arrout);
375
+ return $colstr;
376
+ }
377
+
378
+ /**
379
+ *
380
+ * transform an array of values into equivalent comma separated list of unnamed placeholders.
381
+ * @param array $arr
382
+ */
383
+ public function arr2values($arr)
384
+ {
385
+ $str=substr(str_repeat("?,",count($arr)),0,-1);
386
+ return $str;
387
+ }
388
+
389
+ /**
390
+ *
391
+ * transform a list of values into static select to use it as SQL static resultset
392
+ * @param array $arr list of values to use as SQL dataset
393
+ * @param string $cname sql column name to use to represent dataset
394
+ */
395
+ public function arr2select($arr,$cname="id")
396
+ {
397
+ $rpt=str_repeat("? AS $cname UNION SELECT ",count($arr));
398
+ $subsel=substr($rpt,0,-1*strlen(" UNION SELECT "));
399
+ return "(SELECT $subsel)";
400
+ }
401
+
402
+ /**
403
+ *
404
+ * transform a associative array into a list of update prepared placeholders
405
+ * @param array $arr associative array to prepare for update , array keys used as column to update
406
+ */
407
+ public function arr2update($arr)
408
+ {
409
+ $arrout=array();
410
+ foreach($arr as $k=>$v)
411
+ {
412
+ $arrout[]="$k=?";
413
+ }
414
+ $updstr=implode(",",$arrout);
415
+ unset($arrout);
416
+ return $updstr;
417
+ }
418
+
419
+ /**
420
+ *
421
+ * Enter description here ...
422
+ * @param unknown_type $kvarr
423
+ * @param unknown_type $keys
424
+ */
425
+ public function filterkvarr($kvarr,$keys)
426
+ {
427
+ $out=array();
428
+ foreach($keys as $k)
429
+ {
430
+ $out[$k]=isset($kvarr[$k])?$kvarr[$k]:null;
431
+ }
432
+ return $out;
433
+ }
434
+
435
+ /**
436
+ * begins a transaction
437
+ */
438
+ public function beginTransaction()
439
+ {
440
+ $this->_db->beginTransaction();
441
+ $this->_intrans=true;
442
+ $this->logdebug("-- TRANSACTION BEGIN --");
443
+
444
+ }
445
+
446
+ /**
447
+ * commits the current transaction
448
+ */
449
+ public function commitTransaction()
450
+ {
451
+ $this->_db->commit();
452
+ $this->_intrans=false;
453
+ $this->logdebug("-- TRANSACTION COMMIT --");
454
+
455
+ }
456
+
457
+ /**
458
+ * rollback the current transaction
459
+ */
460
+ public function rollbackTransaction()
461
+ {
462
+ if($this->_intrans)
463
+ {
464
+ $this->_db->rollBack();
465
+ $this->_intrans=false;
466
+ $this->logdebug("-- TRANSACTION ROLLBACK --");
467
+
468
+ }
469
+
470
+ }
471
+
472
+ /**
473
+ *
474
+ * Sets debug management
475
+ * @param bool $debug debug flag
476
+ * @param string $debugfname debug file name to use
477
+ */
478
+ public function setDebug($debug,$debugfname)
479
+ {
480
+ $this->_debug=$debug;
481
+ $this->_debugfile=$debugfname;
482
+ }
483
+
484
+ /**
485
+ *
486
+ * Replaces named params in a descriptive parameterized request
487
+ * Descriptive parameterized request have parameters defined as
488
+ * [namespace:name/label/default value] , this parameters may represent table names or any request parameter
489
+ * namespace is optional, as label & default value
490
+ * - NameSpaces:
491
+ * tn : tablename, this namespace ensures replacement of given name with defined DB prefix so, parameterized request can use generic names to define their ops
492
+ *
493
+ * @param unknown_type $stmt
494
+ * @param unknown_type $rparams
495
+ */
496
+ public function replaceParams(&$stmt,&$rparams)
497
+ {
498
+ $params=array();
499
+ $hasp=preg_match_all('|\[\[(.*?)\]\]|msi',$stmt,$matches);
500
+ if($hasp)
501
+ {
502
+ $pdefs=$matches[0];
503
+ $params=$matches[1];
504
+
505
+ }
506
+ for($i=0;$i<count($params);$i++)
507
+ {
508
+ $param=$params[$i];
509
+ $pdef=$pdefs[$i];
510
+ $pinfo=explode("/",$param);
511
+ $pname=$pinfo[0];
512
+ $epar=explode(":",$pname);
513
+ if(count($epar)>1)
514
+ {
515
+ $stmt=str_replace($pdef,$rparams[$pname],$stmt);
516
+ }
517
+ else
518
+ {
519
+ $stmt=str_replace($pdef,":$pname",$stmt);
520
+ }
521
+ }
522
+ for($i=0;$i<count($params);$i++)
523
+ {
524
+ $param=$params[$i];
525
+ $pinfo=explode("/",$param);
526
+ $pname=$pinfo[0];
527
+ $epar=explode(":",$pname);
528
+ if(count($epar)>1)
529
+ {
530
+ unset($rparams[$pname]);
531
+ }
532
+ }
533
+ }
534
+
535
+ /**
536
+ *
537
+ * Checks wether an array is associative
538
+ * @param mixed $var array or variable to test
539
+ */
540
+ public function is_assoc($var) {
541
+ return is_array($var) && array_keys($var)!==range(0,sizeof($var)-1);
542
+ }
543
+
544
+ /**
545
+ *
546
+ * This method handled mutiple statements in a single SQL (PDO cannot do it by itself)
547
+ * Statements have to be separed by ; & line return.
548
+ * @param string $sql multiple statements
549
+ * @param array $params values to use for parameter placeholder, in case of named parameters,array has to have array keys aligned with parameter names
550
+ */
551
+ public function multipleParamRequests($sql,$params,$return=false)
552
+ {
553
+ //ensure windows/mac compatibility for user made requests
554
+ $sql=str_replace("\r\n","\n",$sql);
555
+ $sqllines=explode("--",$sql);
556
+ foreach($sqllines as $sqlline)
557
+ {
558
+ if($sqlline!="")
559
+ {
560
+ $subs=explode(";\n","--".$sqlline);
561
+ foreach($subs as $sub)
562
+ {
563
+
564
+ if(trim($sub)!="" && substr($sub,0,2)!="--")
565
+ {
566
+ $stmts[]=$sub;
567
+ }
568
+ }
569
+ }
570
+ }
571
+ $results=array();
572
+ foreach($stmts as $stmt)
573
+ {
574
+ $zparams=$params;
575
+ $this->replaceParams($stmt,$zparams);
576
+ if($return)
577
+ {
578
+ if(substr(trim($stmt),0,6)=="SELECT")
579
+ {
580
+ $results[$stmt]=$this->selectAll($stmt,$zparams);
581
+ continue;
582
+ }
583
+ }
584
+ $this->exec_stmt($stmt,$zparams);
585
+ }
586
+ if($return)
587
+ {
588
+ return $results;
589
+ }
590
+ }
591
+
592
+
593
+ }
lib/Magmi/inc/dbhelper.class.php~ ADDED
@@ -0,0 +1,589 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ *
4
+ * This class is a Database Operation Helper based on PDO library
5
+ * It provides shortcuts for common DB CRUD operations and some advanced templated requests operations
6
+ * @author dweeves
7
+ *
8
+ */
9
+ class DBHelper
10
+ {
11
+ protected $_db;
12
+ protected $_debug;
13
+ protected $_laststmt;
14
+ protected $_use_stmt_cache=true;
15
+ protected $_nreq;
16
+ protected $_indbtime;
17
+ protected $_intrans=false;
18
+ protected $prepared=array();
19
+ /**
20
+ * Intializes database connection
21
+ * @param string $host : hostname
22
+ * @param string $dbname : database name
23
+ * @param string $user : username
24
+ * @param string $pass : password
25
+ * @param bool $debug : debug mode
26
+ */
27
+ public function initDb($host,$dbname,$user,$pass,$port=3306,$socket="/tmp/mysql.sock",$conntype="net",$debug=false)
28
+ {
29
+ //intialize connection with PDO
30
+ //fix by Mr Lei for UTF8 special chars
31
+ if($conntype=="net")
32
+ {
33
+ $pdostr="mysql:host=$host;port=$port;dbname=$dbname;charset=utf8";
34
+ }
35
+ else
36
+ {
37
+ $pdostr="mysql:unix_socket=$socket;dbname=$dbname;charset=utf8";
38
+ }
39
+
40
+ $this->_db=new PDO($pdostr, $user, $pass,array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));
41
+ //use exception error mode
42
+ $this->_db->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
43
+ $this->_db->setAttribute(PDO::ATTR_ORACLE_NULLS ,PDO::NULL_NATURAL);
44
+ $this->_db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE,PDO::FETCH_ASSOC);
45
+
46
+ //set database debug mode to trace if necessary
47
+ $this->_debug=$debug;
48
+ $this->prepared=array();
49
+
50
+ }
51
+ /**
52
+ *
53
+ * store output in some debug file
54
+ * @param unknown_type $data
55
+ */
56
+ public function logdebug($data)
57
+ {
58
+ if($this->_debug)
59
+ {
60
+ $f=fopen($this->_debugfile,"a");
61
+ fwrite($f,microtime());
62
+ fwrite($f,$data);
63
+ fwrite($f,"\n");
64
+ fclose($f);
65
+ }
66
+ }
67
+ /**
68
+ *
69
+ * Sets or unsets the usage of internal prepared statement cache for reuse
70
+ * @param boolean $uc true:use cache,false:do not use cache
71
+ */
72
+ public function usestmtcache($uc)
73
+ {
74
+ $this->_use_stmt_cache=$uc;
75
+ }
76
+
77
+ /**
78
+ * releases database connection
79
+ */
80
+ public function exitDb()
81
+ {
82
+ //clear PDO resource
83
+ $this->_db=NULL;
84
+
85
+ }
86
+
87
+ /**
88
+ *
89
+ * Helper method to try to guess mysql socket based on some tricky phpinfo analysis
90
+ * @throws Exception if something got wrong during detection
91
+ */
92
+ public static function getMysqlSocket()
93
+ {
94
+ $mysqlsock="";
95
+ $old_track = ini_set('track_errors', '1');
96
+ try
97
+ {
98
+ $mysqlsock=ini_get("mysql.default_socket");
99
+
100
+ if(isset($mysqlsock) && !@file_exists($mysqlsock))
101
+ {
102
+ if(error_get_last()!==null)
103
+ {
104
+ throw new Exception();
105
+ }
106
+ ob_start();
107
+ phpinfo();
108
+ $data=ob_get_contents();
109
+ ob_end_clean();
110
+ $cap=preg_match("/MYSQL_SOCKET.*?<td .*?>(.*?)<\/td>/msi",$data,$matches);
111
+ if($cap)
112
+ {
113
+ $mysqlsock=$matches[1];
114
+ }
115
+ }
116
+ if(isset($mysqlsock) && !@file_exists($mysqlsock))
117
+ {
118
+ $mysqlsock="";
119
+ }
120
+
121
+ }
122
+ catch(Exception $e)
123
+ {
124
+ }
125
+ if(error_get_last()!==null)
126
+ {
127
+ $mysqlsock=false;
128
+ }
129
+ ini_set('track_errors',$old_track);
130
+ return $mysqlsock;
131
+ }
132
+
133
+ /**
134
+ *
135
+ * Initializes database requests stats counters
136
+ */
137
+ public function initDbqStats()
138
+ {
139
+ $this->_nreq=0;
140
+ $this->_indbtime=0;
141
+ }
142
+
143
+ /**
144
+ *
145
+ * Enter description here ...
146
+ * @param unknown_type $nbreq
147
+ */
148
+ public function collectDbqStats(&$nbreq)
149
+ {
150
+ return $this->_nreq;
151
+ }
152
+
153
+ /**
154
+ * cache sorting comparison method
155
+ *
156
+ * @param unknown_type $a
157
+ * @param unknown_type $b
158
+ */
159
+ public function cachesort($a,$b)
160
+ {
161
+ return $b[1]-$a[1];
162
+ }
163
+
164
+ /**
165
+ * Garbages statement cache if above 500 , removes less used statements
166
+ * Enter description here ...
167
+ */
168
+ public function garbageStmtCache()
169
+ {
170
+ if(count($this->prepared)>=500)
171
+ {
172
+ uasort($this->prepared,array($this,"cachesort"));
173
+ array_splice($this->prepared,350,count($this->prepared));
174
+ }
175
+ }
176
+ /**
177
+ * executes an sql statement
178
+ * @param string $sql : sql statement (may include ? placeholders or named variables)
179
+ * @param array $params : parameters to replace placeholders (can be null)
180
+ * @param boolean $close : auto close cursor after statement execution (defaults to true)
181
+ * @return PDOStatement : statement for further processing if needed
182
+ */
183
+ public function exec_stmt($sql,$params=null,$close=true)
184
+ {
185
+ $this->_nreq++;
186
+ $t0=microtime(true);
187
+
188
+ if($this->_use_stmt_cache && strpos($sql,"'")==false)
189
+ {
190
+ //if sql not in statement cache
191
+ if(!isset($this->prepared[$sql]))
192
+ {
193
+ $this->garbageStmtCache();
194
+ //create new prepared statement
195
+ $stmt=$this->_db->prepare($sql);
196
+ //cache prepare statement
197
+ $this->prepared[$sql]=array($stmt,1);
198
+ }
199
+ else
200
+ {
201
+ //get from statement cache
202
+ $this->prepared[$sql][1]++;
203
+ $stmt=$this->prepared[$sql][0];
204
+ }
205
+ }
206
+ else
207
+ {
208
+ //create new prepared statement
209
+ $stmt=$this->_db->prepare($sql);
210
+ }
211
+ $this->_laststmt=$stmt;
212
+ if($params!=null)
213
+ {
214
+ if(!$this->is_assoc($params))
215
+ {
216
+ $params=is_array($params)?$params:array($params);
217
+ $stmt->execute($params);
218
+ }
219
+ else
220
+ {
221
+ foreach($params as $pname=>$pval)
222
+ {
223
+ if(count(explode(":",$pname))==1)
224
+ {
225
+ $val=strval($pval);
226
+ $stmt->bindValue(":$pname",$val);
227
+ }
228
+ }
229
+ $stmt->execute();
230
+ }
231
+ }
232
+ else
233
+ {
234
+
235
+ $stmt->execute();
236
+ }
237
+ if($close)
238
+ {
239
+ $stmt->closeCursor();
240
+ }
241
+ $t1=microtime(true);
242
+ $this->_indbtime+=$t1-$t0;
243
+ $this->logdebug("$sql\n".print_r($params,true));
244
+ unset($params);
245
+ return $stmt;
246
+ }
247
+
248
+ /**
249
+ * Perform a delete statement, sql should be "DELETE"
250
+ * @param string $sql : DELETE statement sql (placeholders allowed)
251
+ * @param array $params : placeholder replacements (can be null)
252
+ */
253
+ public function delete($sql,$params=null)
254
+ {
255
+ $this->exec_stmt($sql,$params);
256
+ }
257
+
258
+ /**
259
+ * Performs an update statement
260
+ * Enter description here ...
261
+ * @param string $sql UPDATE statement sql (placeholder allowed)
262
+ * @param array $params parameter values if placeholders in SQL
263
+ */
264
+ public function update($sql,$params=null)
265
+ {
266
+ $this->exec_stmt($sql,$params);
267
+ }
268
+ /**
269
+ * Perform an insert , sql should be "INSERT"
270
+ * @param string $sql :INSERT statement SQL (placeholders allowed)
271
+ * @param array $params : placeholder replacements (can be null)
272
+ * @return mixed : last inserted id
273
+ */
274
+ public function insert($sql,$params=null)
275
+ {
276
+ $this->exec_stmt($sql,$params);
277
+ $liid=$this->_db->lastInsertId();
278
+ return $liid;
279
+ }
280
+
281
+ /**
282
+ * Perform a select ,sql should be "SELECT"
283
+ * @param string $sql :SELECT statement SQL (placeholders allowed)
284
+ * @param array $params : placeholder replacements (can be null)
285
+ * @return PDOStatement : statement instance for further processing
286
+ */
287
+ public function select($sql,$params=null)
288
+ {
289
+ return $this->exec_stmt($sql,$params,false);
290
+ }
291
+
292
+ /**
293
+ * Selects one unique value from one single row
294
+ * @param $sql : SELECT statement SQL (placeholders allowed)
295
+ * @param $params :placeholder replacements (can be null)
296
+ * @param $col : column value to retrieve
297
+ * @return mixed : null if not result , wanted column value if match
298
+ */
299
+ public function selectone($sql,$params,$col)
300
+ {
301
+ $stmt=$this->select($sql,$params);
302
+ $t0=microtime(true);
303
+
304
+ $r=$stmt->fetch(PDO::FETCH_ASSOC);
305
+ $stmt->closeCursor();
306
+ $t1=microtime(true);
307
+ $this->_indbtime+=$t1-$t0;
308
+ $v=(is_array($r)?$r[$col]:null);
309
+ unset($r);
310
+ return $v;
311
+ }
312
+
313
+ /**
314
+ * Selects all values from a statement into a php array
315
+ * @param unknown_type $sql sql select to execute
316
+ * @param unknown_type $params placeholder replacements (can be null)
317
+ */
318
+ public function selectAll($sql,$params=null)
319
+ {
320
+ $stmt=$this->select($sql,$params);
321
+ $t0=microtime(true);
322
+
323
+ $r=$stmt->fetchAll(PDO::FETCH_ASSOC);
324
+ $stmt->closeCursor();
325
+ $t1=microtime(true);
326
+ $this->_indbtime+=$t1-$t0;
327
+ return $r;
328
+ }
329
+
330
+ /**
331
+ * test if value exists (test should be compatible with unique select)
332
+ * @param $sql : SELECT statement SQL (placeholders allowed)
333
+ * @param $params :placeholder replacements (can be null)
334
+ * @param $col : column value to retrieve
335
+ * @return boolean : true if value found, false otherwise
336
+ */
337
+ public function testexists($sql,$params,$col)
338
+ {
339
+ return $this->selectone($sql,$params,$col)!=null;
340
+ }
341
+
342
+ /**
343
+ * Quote array values in order to be used as parameters (handy if array used directly in explode in a IN condition)
344
+ * Enter description here ...
345
+ * @param array $arr array of values to be quoted
346
+ */
347
+ public function quotearr($arr)
348
+ {
349
+ $arrout=array();
350
+ foreach($arr as $v)
351
+ {
352
+ $arrout[]=$this->_db->quote($v);
353
+ }
354
+ return $arrout;
355
+ }
356
+
357
+ /**
358
+ *
359
+ * transforms an array in a comma separated list of enclosed column names for request
360
+ * @param array $arr list of names to enclose
361
+ */
362
+ public function arr2columns($arr)
363
+ {
364
+ $arrout=array();
365
+ foreach($arr as $cname)
366
+ {
367
+ $arrout[]="`".$cname."`";
368
+ }
369
+ $colstr=implode(",",$arrout);
370
+ unset($arrout);
371
+ return $colstr;
372
+ }
373
+
374
+ /**
375
+ *
376
+ * transform an array of values into equivalent comma separated list of unnamed placeholders.
377
+ * @param array $arr
378
+ */
379
+ public function arr2values($arr)
380
+ {
381
+ $str=substr(str_repeat("?,",count($arr)),0,-1);
382
+ return $str;
383
+ }
384
+
385
+ /**
386
+ *
387
+ * transform a list of values into static select to use it as SQL static resultset
388
+ * @param array $arr list of values to use as SQL dataset
389
+ * @param string $cname sql column name to use to represent dataset
390
+ */
391
+ public function arr2select($arr,$cname="id")
392
+ {
393
+ $rpt=str_repeat("? AS $cname UNION SELECT ",count($arr));
394
+ $subsel=substr($rpt,0,-1*strlen(" UNION SELECT "));
395
+ return "(SELECT $subsel)";
396
+ }
397
+
398
+ /**
399
+ *
400
+ * transform a associative array into a list of update prepared placeholders
401
+ * @param array $arr associative array to prepare for update , array keys used as column to update
402
+ */
403
+ public function arr2update($arr)
404
+ {
405
+ $arrout=array();
406
+ foreach($arr as $k=>$v)
407
+ {
408
+ $arrout[]="$k=?";
409
+ }
410
+ $updstr=implode(",",$arrout);
411
+ unset($arrout);
412
+ return $updstr;
413
+ }
414
+
415
+ /**
416
+ *
417
+ * Enter description here ...
418
+ * @param unknown_type $kvarr
419
+ * @param unknown_type $keys
420
+ */
421
+ public function filterkvarr($kvarr,$keys)
422
+ {
423
+ $out=array();
424
+ foreach($keys as $k)
425
+ {
426
+ $out[$k]=isset($kvarr[$k])?$kvarr[$k]:null;
427
+ }
428
+ return $out;
429
+ }
430
+
431
+ /**
432
+ * begins a transaction
433
+ */
434
+ public function beginTransaction()
435
+ {
436
+ $this->_db->beginTransaction();
437
+ $this->_intrans=true;
438
+ $this->logdebug("-- TRANSACTION BEGIN --");
439
+
440
+ }
441
+
442
+ /**
443
+ * commits the current transaction
444
+ */
445
+ public function commitTransaction()
446
+ {
447
+ $this->_db->commit();
448
+ $this->_intrans=false;
449
+ $this->logdebug("-- TRANSACTION COMMIT --");
450
+
451
+ }
452
+
453
+ /**
454
+ * rollback the current transaction
455
+ */
456
+ public function rollbackTransaction()
457
+ {
458
+ if($this->_intrans)
459
+ {
460
+ $this->_db->rollBack();
461
+ $this->_intrans=false;
462
+ $this->logdebug("-- TRANSACTION ROLLBACK --");
463
+
464
+ }
465
+
466
+ }
467
+
468
+ /**
469
+ *
470
+ * Sets debug management
471
+ * @param bool $debug debug flag
472
+ * @param string $debugfname debug file name to use
473
+ */
474
+ public function setDebug($debug,$debugfname)
475
+ {
476
+ $this->_debug=$debug;
477
+ $this->_debugfile=$debugfname;
478
+ }
479
+
480
+ /**
481
+ *
482
+ * Replaces named params in a descriptive parameterized request
483
+ * Descriptive parameterized request have parameters defined as
484
+ * [namespace:name/label/default value] , this parameters may represent table names or any request parameter
485
+ * namespace is optional, as label & default value
486
+ * - NameSpaces:
487
+ * tn : tablename, this namespace ensures replacement of given name with defined DB prefix so, parameterized request can use generic names to define their ops
488
+ *
489
+ * @param unknown_type $stmt
490
+ * @param unknown_type $rparams
491
+ */
492
+ public function replaceParams(&$stmt,&$rparams)
493
+ {
494
+ $params=array();
495
+ $hasp=preg_match_all('|\[\[(.*?)\]\]|msi',$stmt,$matches);
496
+ if($hasp)
497
+ {
498
+ $pdefs=$matches[0];
499
+ $params=$matches[1];
500
+
501
+ }
502
+ for($i=0;$i<count($params);$i++)
503
+ {
504
+ $param=$params[$i];
505
+ $pdef=$pdefs[$i];
506
+ $pinfo=explode("/",$param);
507
+ $pname=$pinfo[0];
508
+ $epar=explode(":",$pname);
509
+ if(count($epar)>1)
510
+ {
511
+ $stmt=str_replace($pdef,$rparams[$pname],$stmt);
512
+ }
513
+ else
514
+ {
515
+ $stmt=str_replace($pdef,":$pname",$stmt);
516
+ }
517
+ }
518
+ for($i=0;$i<count($params);$i++)
519
+ {
520
+ $param=$params[$i];
521
+ $pinfo=explode("/",$param);
522
+ $pname=$pinfo[0];
523
+ $epar=explode(":",$pname);
524
+ if(count($epar)>1)
525
+ {
526
+ unset($rparams[$pname]);
527
+ }
528
+ }
529
+ }
530
+
531
+ /**
532
+ *
533
+ * Checks wether an array is associative
534
+ * @param mixed $var array or variable to test
535
+ */
536
+ public function is_assoc($var) {
537
+ return is_array($var) && array_keys($var)!==range(0,sizeof($var)-1);
538
+ }
539
+
540
+ /**
541
+ *
542
+ * This method handled mutiple statements in a single SQL (PDO cannot do it by itself)
543
+ * Statements have to be separed by ; & line return.
544
+ * @param string $sql multiple statements
545
+ * @param array $params values to use for parameter placeholder, in case of named parameters,array has to have array keys aligned with parameter names
546
+ */
547
+ public function multipleParamRequests($sql,$params,$return=false)
548
+ {
549
+ //ensure windows/mac compatibility for user made requests
550
+ $sql=str_replace("\r\n","\n",$sql);
551
+ $sqllines=explode("--",$sql);
552
+ foreach($sqllines as $sqlline)
553
+ {
554
+ if($sqlline!="")
555
+ {
556
+ $subs=explode(";\n","--".$sqlline);
557
+ foreach($subs as $sub)
558
+ {
559
+
560
+ if(trim($sub)!="" && substr($sub,0,2)!="--")
561
+ {
562
+ $stmts[]=$sub;
563
+ }
564
+ }
565
+ }
566
+ }
567
+ $results=array();
568
+ foreach($stmts as $stmt)
569
+ {
570
+ $zparams=$params;
571
+ $this->replaceParams($stmt,$zparams);
572
+ if($return)
573
+ {
574
+ if(substr(trim($stmt),0,6)=="SELECT")
575
+ {
576
+ $results[$stmt]=$this->selectAll($stmt,$zparams);
577
+ continue;
578
+ }
579
+ }
580
+ $this->exec_stmt($stmt,$zparams);
581
+ }
582
+ if($return)
583
+ {
584
+ return $results;
585
+ }
586
+ }
587
+
588
+
589
+ }
lib/Magmi/inc/fshelper.php ADDED
@@ -0,0 +1,370 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class FSHelper
3
+ {
4
+ public static function isDirWritable($dir)
5
+ {
6
+ $test=@fopen("$dir/__testwr__","w");
7
+ if($test==false)
8
+ {
9
+ return false;
10
+ }
11
+ else
12
+ {
13
+ fclose($test);
14
+ unlink("$dir/__testwr__");
15
+ }
16
+ return true;
17
+ }
18
+
19
+ }
20
+
21
+
22
+
23
+ class MagentoDirHandlerFactory
24
+ {
25
+ protected $_handlers=array();
26
+ protected static $_instance;
27
+
28
+ public function __construct()
29
+ {
30
+ }
31
+
32
+ public static function getInstance()
33
+ {
34
+ if(!isset(self::$_instance))
35
+ {
36
+ self::$_instance=new MagentoDirHandlerFactory();
37
+ }
38
+ return self::$_instance;
39
+ }
40
+
41
+ public function registerHandler($obj)
42
+ {
43
+ $cls=get_class($obj);
44
+ if(!isset($this->_handlers[$cls]))
45
+ {
46
+ $this->_handlers[$cls]=$obj;
47
+ }
48
+ }
49
+
50
+ public function getHandler($url)
51
+ {
52
+ foreach($this->_handlers as $cls=>$handler)
53
+ {
54
+ if ($handler->canHandle($url))
55
+ {
56
+ return $handler;
57
+ }
58
+ }
59
+
60
+ }
61
+
62
+ }
63
+
64
+ abstract class RemoteFileGetter
65
+ {
66
+ protected $_errors;
67
+ public abstract function urlExists($url);
68
+ public abstract function copyRemoteFile($url,$dest);
69
+ public function getErrors()
70
+ {
71
+ return $this->_errors;
72
+ }
73
+ }
74
+
75
+ class CURL_RemoteFileGetter extends RemoteFileGetter
76
+ {
77
+ protected $_curlh;
78
+
79
+ public function createContext($url)
80
+ {
81
+ if($this->_curlh==NULL)
82
+ {
83
+ $curl_url=str_replace(" ","%20",$url);
84
+ $context = curl_init($curl_url);
85
+ $this->_curlh=$context;
86
+ }
87
+ return $this->_curlh;
88
+ }
89
+
90
+ public function destroyContext($url)
91
+ {
92
+ if($this->_curlh!=NULL)
93
+ {
94
+ curl_close($this->_curlh);
95
+ $this->_curlh=NULL;
96
+ }
97
+ }
98
+
99
+
100
+ public function urlExists($remoteurl)
101
+ {
102
+ $context=$this->createContext($remoteurl);
103
+ //optimized lookup through curl
104
+ /* head */
105
+ curl_setopt($context, CURLOPT_HEADER, TRUE);
106
+ curl_setopt( $context, CURLOPT_RETURNTRANSFER, true );
107
+ curl_setopt( $context, CURLOPT_CUSTOMREQUEST, 'HEAD' );
108
+ curl_setopt( $context, CURLOPT_NOBODY, true );
109
+
110
+ /* Get the HTML or whatever is linked in $url. */
111
+ $response = curl_exec($context);
112
+
113
+ /* Check for 404 (file not found). */
114
+ $httpCode = curl_getinfo($context, CURLINFO_HTTP_CODE);
115
+ $exists = ($httpCode==200);
116
+ /* retry on error */
117
+
118
+ if($httpCode==503 or $httpCode==403)
119
+ {
120
+ /* wait for a half second */
121
+ usleep(500000);
122
+ $response = curl_exec($context);
123
+ $httpCode = curl_getinfo($context, CURLINFO_HTTP_CODE);
124
+ $exists = ($httpCode==200);
125
+ }
126
+ return $exists;
127
+ }
128
+
129
+ public function copyRemoteFile($url,$dest)
130
+ {
131
+ $this->_errors=array();
132
+ $ret=true;
133
+ $context=$this->createContext($url);
134
+ if(!$this->urlExists($url))
135
+ {
136
+ $this->_errors=array("type"=>"download error","message"=>"URL $url is unreachable");
137
+ return false;
138
+ }
139
+ $fp=fopen($dest,"w");
140
+ //add support for https urls
141
+ curl_setopt($context, CURLOPT_SSL_VERIFYPEER ,false);
142
+ curl_setopt($context, CURLOPT_RETURNTRANSFER, false);
143
+ curl_setopt( $context, CURLOPT_CUSTOMREQUEST, 'GET' );
144
+ curl_setopt( $context, CURLOPT_NOBODY, false);
145
+ curl_setopt($context, CURLOPT_FILE, $fp);
146
+ curl_setopt($context, CURLOPT_HEADER, 0);
147
+ curl_setopt($context,CURLOPT_FAILONERROR,true);
148
+ if(!ini_get('safe_mode'))
149
+ {
150
+ curl_setopt($context, CURLOPT_FOLLOWLOCATION, 1);
151
+ }
152
+ curl_exec($context);
153
+ if(curl_getinfo($context,CURLINFO_HTTP_CODE)>=400)
154
+ {
155
+ $this->_errors=array("type"=>"download error","message"=>curl_error($context));
156
+ $ret=false;
157
+ }
158
+ fclose($fp);
159
+ return $ret;
160
+ }
161
+ }
162
+
163
+ class URLFopen_RemoteFileGetter extends RemoteFileGetter
164
+ {
165
+ public function urlExists($url)
166
+ {
167
+ $fname=$url;
168
+ $h=@fopen($fname,"r");
169
+ if($h!==false)
170
+ {
171
+ $exists=true;
172
+ fclose($h);
173
+ }
174
+ unset($h);
175
+ }
176
+
177
+ public function copyRemoteFile($url,$dest)
178
+ {
179
+ if(!$this->urlExists($url))
180
+ {
181
+ $this->_errors=array("type"=>"target error","message"=>"URL $remoteurl is unreachable");
182
+ return false;
183
+ }
184
+
185
+ $ok=@copy($url,$dest);
186
+ if(!$ok)
187
+ {
188
+ $this->_errors= error_get_last();
189
+ }
190
+ return $ok;
191
+ }
192
+ }
193
+
194
+ class RemoteFileGetterFactory
195
+ {
196
+
197
+ public static function getFGInstance()
198
+ {
199
+ $fginst=NULL;
200
+ if(function_exists("curl_init"))
201
+ {
202
+ $fginst=new CURL_RemoteFileGetter();
203
+ }
204
+ else
205
+ {
206
+ $fginst=new URLFopen_RemoteFileGetter();
207
+ }
208
+ return $fginst;
209
+ }
210
+
211
+ }
212
+
213
+ abstract class MagentoDirHandler
214
+ {
215
+ protected $_magdir;
216
+ protected $_lasterror;
217
+ public function __construct($magurl)
218
+ {
219
+ $this->_magdir=$magurl;
220
+ $this->_lasterror=array();
221
+ }
222
+ public function getMagentoDir()
223
+ {
224
+ return $this->_magdir;
225
+ }
226
+ public abstract function canhandle($url);
227
+ public abstract function file_exists($filepath);
228
+ public abstract function mkdir($path,$mask=null,$rec=false);
229
+ public abstract function copy($srcpath,$destpath);
230
+ public abstract function unlink($path);
231
+ public abstract function chmod($path,$mask);
232
+ public abstract function exec_cmd($cmd,$params,$workingdir = null);
233
+ }
234
+
235
+ class LocalMagentoDirHandler extends MagentoDirHandler
236
+ {
237
+ public function __construct($magdir)
238
+ {
239
+ parent::__construct($magdir);
240
+ MagentoDirHandlerFactory::getInstance()->registerHandler($this);
241
+ }
242
+
243
+ public function canHandle($url)
244
+ {
245
+ return (preg_match("|^.*?://.*$|",$url)==false);
246
+ }
247
+
248
+ public function file_exists($filename)
249
+ {
250
+ $mp=str_replace("//","/",$this->_magdir."/".str_replace($this->_magdir, '', $filename));
251
+
252
+ return file_exists($mp);
253
+ }
254
+
255
+ public function mkdir($path,$mask=null,$rec=false)
256
+ {
257
+ $mp=str_replace("//","/",$this->_magdir."/".str_replace($this->_magdir, '', $path));
258
+
259
+ if($mask==null)
260
+ {
261
+ $mask=octdec('755');
262
+ }
263
+ $ok=@mkdir($mp,$mask,$rec);
264
+ if(!$ok)
265
+ {
266
+ $this->_lasterror=error_get_last();
267
+ }
268
+ return $ok;
269
+ }
270
+
271
+ public function chmod($path,$mask)
272
+ {
273
+ $mp=str_replace("//","/",$this->_magdir."/".str_replace($this->_magdir, '', $path));
274
+
275
+ if($mask==null)
276
+ {
277
+ $mask=octdec('755');
278
+ }
279
+ $ok=@chmod($mp,$mask);
280
+ if(!$ok)
281
+ {
282
+ $this->_lasterror=error_get_last();
283
+ }
284
+ return $ok;
285
+ }
286
+
287
+ public function getLastError()
288
+ {
289
+ return $this->_lasterror;
290
+ }
291
+
292
+ public function unlink($path)
293
+ {
294
+ $mp=str_replace("//","/",$this->_magdir."/".str_replace($this->_magdir, '', $path));
295
+ return @unlink($mp);
296
+ }
297
+
298
+ public function copyFromRemote($remoteurl,$destpath)
299
+ {
300
+ $rfg=RemoteFileGetterFactory::getFGInstance();
301
+ $mp=str_replace("//","/",$this->_magdir."/".str_replace($this->_magdir, '', $destpath));
302
+ $ok=$rfg->copyRemoteFile($remoteurl,$mp);
303
+ if(!$ok)
304
+ {
305
+ $this->_lasterror=$rfg->getErrors();
306
+ }
307
+ unset($rfg);
308
+ return $ok;
309
+ }
310
+
311
+ public function copy($srcpath,$destpath)
312
+ {
313
+ $result=false;
314
+ $destpath=str_replace("//","/",$this->_magdir."/".str_replace($this->_magdir, '', $destpath));
315
+ if(preg_match('|^.*?://.*$|', $srcpath))
316
+ {
317
+ $result=$this->copyFromRemote($srcpath,$destpath);
318
+ }
319
+ else
320
+ {
321
+
322
+ $result=@copy($srcpath,$destpath);
323
+ if(!$result)
324
+ {
325
+ $this->_lasterror=error_get_last();
326
+ }
327
+ }
328
+ return $result;
329
+ }
330
+
331
+ public function exec_cmd($cmd,$params, $working_dir = null)
332
+ {
333
+ $full_cmd = $cmd." ".$params;
334
+ $curdir=false;
335
+ $precmd="";
336
+ // If a working directory has been specified, switch to it
337
+ // before running the requested command
338
+ if(!empty($working_dir))
339
+ {
340
+ $curdir=getcwd();
341
+ $wdir=realpath($working_dir);
342
+ //get current directory
343
+ if($curdir!=$wdir && $wdir!==false)
344
+ {
345
+ //trying to change using chdir
346
+ if(!@chdir($wdir))
347
+ {
348
+ //if no success, use cd from shell
349
+ $precmd="cd $wdir && ";
350
+ }
351
+ }
352
+ }
353
+ $full_cmd = $precmd. $full_cmd;
354
+
355
+ $out=@shell_exec($full_cmd);
356
+
357
+ //restore old directory if changed
358
+ if($curdir)
359
+ {
360
+ @chdir($curdir);
361
+ }
362
+
363
+ if($out==null)
364
+ {
365
+ $this->_lasterror=array("type"=>" execution error","message"=>error_get_last());
366
+ return false;
367
+ }
368
+ return $out;
369
+ }
370
+ }
lib/Magmi/inc/license.txt ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Copyright (C) 2012 by Dweeves (S.BRACQUEMONT)
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
lib/Magmi/inc/magmi_config.php ADDED
@@ -0,0 +1,278 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once("properties.php");
3
+
4
+
5
+ class DirbasedConfig extends Properties
6
+ {
7
+ protected $_basedir=null;
8
+ protected $_confname=null;
9
+
10
+ public function __construct($basedir,$confname)
11
+ {
12
+ $this->_basedir=$basedir;
13
+ $this->_confname=$basedir.DS.$confname;
14
+ }
15
+
16
+ public function get($secname,$pname,$default=null)
17
+ {
18
+ if(!isset($this->_props))
19
+ {
20
+ $this->load();
21
+ }
22
+ return parent::get($secname, $pname,$default);
23
+ }
24
+
25
+ public function getConfFile()
26
+ {
27
+ return $this->_confname;
28
+ }
29
+
30
+ public function getLastSaved($fmt)
31
+ {
32
+
33
+ return strftime($fmt,filemtime($this->_confname));
34
+ }
35
+
36
+ public function load($name=null)
37
+ {
38
+ if($name==null)
39
+ {
40
+ $name=$this->_confname;
41
+ }
42
+
43
+ if(!file_exists($name))
44
+ {
45
+ $this->save();
46
+ }
47
+ parent::load($name);
48
+ }
49
+
50
+ public function save($arr=null)
51
+ {
52
+ if($arr!=null)
53
+ {
54
+ $this->setPropsFromFlatArray($arr);
55
+ }
56
+ return parent::save($this->_confname);
57
+ }
58
+
59
+ public function saveTo($arr,$newdir)
60
+ {
61
+ if(!file_exists($newdir))
62
+ {
63
+ mkdir($newdir,Magmi_Config::getInstance()->getDirMask());
64
+ }
65
+ $val=parent::save($newdir.DS.basename($this->_confname));
66
+ $this->_basedir=$newdir;
67
+ $this->_confname=$newdir.DS.basename($this->_confname);
68
+ return $val;
69
+ }
70
+
71
+ public function getConfDir()
72
+ {
73
+ return $this->_basedir;
74
+ }
75
+ }
76
+
77
+ class ProfileBasedConfig extends DirbasedConfig
78
+ {
79
+ private static $_script=__FILE__;
80
+ protected $_profile=null;
81
+
82
+ public function getProfileDir()
83
+ {
84
+ $subdir=($this->_profile=="default"?"":DS.$this->_profile);
85
+ $confdir=dirname(dirname(self::$_script)).DS."conf$subdir";
86
+ if(!file_exists($confdir))
87
+ {
88
+ @mkdir($confdir,Magmi_Config::getInstance()->getDirMask());
89
+ }
90
+ return realpath($confdir);
91
+ }
92
+
93
+ public function __construct($fname,$profile=null)
94
+ {
95
+ $this->_profile=$profile;
96
+ parent::__construct($this->getProfileDir(),$fname);
97
+ }
98
+
99
+ public function getProfile()
100
+ {
101
+ return $this->_profile;
102
+ }
103
+
104
+ }
105
+
106
+
107
+ class Magmi_Config extends DirbasedConfig
108
+ {
109
+ private static $_instance=null;
110
+ private $_defaultconfigname=null;
111
+ public static $conffile=null;
112
+ private static $_script=__FILE__;
113
+
114
+
115
+ public function getConfDir()
116
+ {
117
+ $confdir=realpath(dirname(dirname(self::$_script)).DS."conf");
118
+ return $confdir;
119
+ }
120
+
121
+ public function __construct()
122
+ {
123
+ parent::__construct($this->getConfDir(),"magmi.ini");
124
+
125
+ }
126
+
127
+ public function getDirMask()
128
+ {
129
+ return octdec($this->get("GLOBAL","dirmask","755"));
130
+ }
131
+
132
+ public function getFileMask()
133
+ {
134
+ return octdec($this->get("GLOBAL","filemask","644"));
135
+
136
+ }
137
+
138
+ public function getMagentoDir()
139
+ {
140
+ $bd=$this->get("MAGENTO","basedir");
141
+ $dp=$bd[0]=="."?dirname(__FILE__)."/".$bd:$bd;
142
+ return $dp;
143
+ }
144
+
145
+ public static function getInstance()
146
+ {
147
+ if(self::$_instance==null)
148
+ {
149
+ self::$_instance=new Magmi_Config();
150
+ }
151
+ return self::$_instance;
152
+ }
153
+
154
+ public function isDefault()
155
+ {
156
+ return !file_exists($this->_confname);
157
+ }
158
+
159
+ public function load($name=null)
160
+ {
161
+ $conf=(!$this->isDefault())?$this->_confname:$this->_confname.".default";
162
+ parent::load($conf);
163
+ $alt=false;
164
+ if($this->hasSection('USE_ALTERNATE'))
165
+ {
166
+ $this->_confname=$this->get("USE_ALTERNATE","file");
167
+ $alt=true;
168
+ }
169
+ parent::load($this->_confname);
170
+ if($alt)
171
+ {
172
+ $this->set("USE_ALTERNATE","file",$this->_confname);
173
+ }
174
+ //Migration from 0.6.17
175
+ if($this->hasSection("PLUGINS_DATASOURCES"))
176
+ {
177
+ $pluginsconf=new DirbasedConfig($this->getConfDir(),"plugins.conf");
178
+ $arr=array("PLUGINS_DATASOURCES"=>$this->getSection("PLUGINS_DATASOURCES"),
179
+ "PLUGINS_GENERAL"=>$this->getSection("PLUGINS_GENERAL"),
180
+ "PLUGINS_ITEMPROCESSORS"=>$this->getSection("PLUGINS_ITEMPROCESSORS"));
181
+ $pluginsconf->setProps($arr);
182
+ $pluginsconf->save();
183
+ $this->removeSection("PLUGINS_DATASOURCES");
184
+ $this->removeSection("PLUGINS_GENERAL");
185
+ $this->removeSection("PLUGINS_ITEMPROCESSORS");
186
+ $this->save();
187
+
188
+ }
189
+ //Migration step (to percent) , 0.7beta4
190
+ if($this->get("GLOBAL","step",0)==0 || floatval($this->get("GLOBAL","step",0.5))>20)
191
+ {
192
+ $this->set("GLOBAL","step",0.5);
193
+ $this->save();
194
+ }
195
+ return $this;
196
+ }
197
+
198
+
199
+ public function save($arr=null)
200
+ {
201
+ if(isset($arr["USE_ALTERNATE:file"]))
202
+ {
203
+ $this->_confname=$arr["USE_ALTERNATE:file"];
204
+ unset($arr["USE_ALTERNATE:file"]);
205
+ }
206
+ if($arr!==null)
207
+ {
208
+ foreach($arr as $k=>$v)
209
+ {
210
+ if(!preg_match("/\w+:\w+/",$k))
211
+ {
212
+ unset($arr[$k]);
213
+ }
214
+ }
215
+ }
216
+ return parent::save($arr);
217
+ }
218
+
219
+ public function getProfileList()
220
+ {
221
+ $proflist=array();
222
+ $candidates=scandir($this->getConfDir());
223
+ foreach($candidates as $candidate)
224
+ {
225
+ if(is_dir($this->getConfDir().DS.$candidate) && $candidate[0]!="." && substr($candidate,0,2)!="__")
226
+ {
227
+ $proflist[]=$candidate;
228
+ }
229
+ }
230
+ return $proflist;
231
+ }
232
+
233
+ }
234
+
235
+ class EnabledPlugins_Config extends ProfileBasedConfig
236
+ {
237
+
238
+ public function __construct($profile="default")
239
+ {
240
+ parent::__construct("plugins.conf",$profile);
241
+ }
242
+
243
+ public function getEnabledPluginFamilies($typelist)
244
+ {
245
+ $btlist=array();
246
+ if(!is_array($typelist))
247
+ {
248
+ $typelist=explode(",",$typelist);
249
+ }
250
+ foreach($typelist as $pfamily)
251
+ {
252
+ $btlist[$pfamily]=$this->getEnabledPluginClasses($pfamily);
253
+ }
254
+ return $btlist;
255
+ }
256
+
257
+ public function getEnabledPluginClasses($type)
258
+ {
259
+ $type=strtoupper($type);
260
+ $cslist=$this->get("PLUGINS_$type","classes");
261
+ if($cslist==null)
262
+ {
263
+ $cslist=$this->get("PLUGINS_$type","class");
264
+ $epc=($cslist==null?array():array($cslist));
265
+ }
266
+ else
267
+ {
268
+ $epc=($cslist==""?array():explode(",",$cslist));
269
+ }
270
+ return $epc;
271
+ }
272
+
273
+ public function isPluginEnabled($type,$pclass)
274
+ {
275
+ return in_array($pclass,$this->getEnabledPluginClasses($type));
276
+ }
277
+
278
+ }
lib/Magmi/inc/magmi_csvreader.php ADDED
@@ -0,0 +1,243 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once("magmi_mixin.php");
3
+ require_once("magmi_utils.php");
4
+
5
+ class Magmi_CSVException extends Exception
6
+ {
7
+
8
+ }
9
+
10
+ class Magmi_CSVReader extends Magmi_Mixin
11
+ {
12
+ protected $_filename;
13
+ protected $_fh;
14
+ protected $_cols;
15
+ protected $_csep;
16
+ protected $_dcsep;
17
+ protected $_params;
18
+ protected $_buffersize;
19
+ protected $_curline;
20
+ protected $_nhcols;
21
+ protected $_ignored=array();
22
+
23
+
24
+
25
+
26
+ public function initialize()
27
+ {
28
+ $this->_filename=$this->getParam("CSV:filename");
29
+ $this->_csep=$this->getParam("CSV:separator",",");
30
+ $this->_dcsep=$this->_csep;
31
+
32
+ if($this->_csep=="\\t")
33
+ {
34
+ $this->_csep="\t";
35
+ }
36
+
37
+ $this->_cenc=$this->getParam("CSV:enclosure",'"');
38
+ $this->_buffersize=$this->getParam("CSV:buffer",0);
39
+ $this->_ignored=explode(",",$this->getParam("CSV:ignore"));
40
+
41
+ }
42
+
43
+
44
+
45
+
46
+
47
+ public function getLinesCount()
48
+ {
49
+ //open csv file
50
+ $f=fopen($this->_filename,"rb");
51
+ if($this->getParam("CSV:noheader",false)==true)
52
+ {
53
+ $count=0;
54
+ }
55
+ else
56
+ {
57
+ $count=-1;
58
+ }
59
+ $linenum=0;
60
+ if($f!=false)
61
+ {
62
+ $line=1;
63
+ while($line<$this->getParam("CSV:headerline",1))
64
+ {
65
+ $line++;
66
+ $dummy=fgetcsv($f,$this->_buffersize,$this->_csep,$this->_cenc);
67
+ }
68
+ //get records count
69
+ while(fgetcsv($f,$this->_buffersize,$this->_csep,$this->_cenc))
70
+ {
71
+ if(!in_array($line,$this->_ignored))
72
+ {
73
+ $count++;
74
+ }
75
+ }
76
+ fclose($f);
77
+ }
78
+ else
79
+ {
80
+ $this->log("Could not read $this->_filename , check permissions","error");
81
+ }
82
+ return $count;
83
+ }
84
+
85
+
86
+ public function checkCSV()
87
+ {
88
+ $this->_curline=0;
89
+ ini_set("auto_detect_line_endings",true);
90
+ if(!isset($this->_filename))
91
+ {
92
+ throw new Magmi_CSVException("No csv file set");
93
+ }
94
+ if(!file_exists($this->_filename))
95
+ {
96
+ throw new Magmi_CSVException("{$this->_filename} not found");
97
+ }
98
+ $this->log("Importing CSV : $this->_filename using separator [ $this->_dcsep ] enclosing [ $this->_cenc ]","startup");
99
+ }
100
+
101
+
102
+ public function openCSV()
103
+ {
104
+ $utf8bom=chr(0xEF).chr(0xBB).chr(0xBF);
105
+ //open csv file
106
+ $this->_fh=fopen($this->_filename,"rb");
107
+ //check for UTF8 BOM
108
+ $bomtest=fread($this->_fh,3);
109
+ //if 3 first bytes of file are not utf8 bom
110
+ if($bomtest!=$utf8bom)
111
+ {
112
+ //rewind to first byte;
113
+ $this->log("No BOM detected, assuming File is UTF8 without BOM...","startup");
114
+ fseek($this->_fh,0,SEEK_SET);
115
+ }
116
+ else
117
+ {
118
+ $this->log("File is UTF8 (BOM Detected)","startup");
119
+ }
120
+ }
121
+
122
+ public function getColumnNames($prescan=false)
123
+ {
124
+ if($prescan==true)
125
+ {
126
+ $this->openCSV();
127
+ $this->_csep=$this->getParam("CSV:separator",",");
128
+ $this->_dcsep=$this->_csep;
129
+
130
+ if($this->_csep=="\\t")
131
+ {
132
+ $this->_csep="\t";
133
+ }
134
+
135
+ $this->_cenc=$this->getParam("CSV:enclosure",'"');
136
+ $this->_buffersize=$this->getParam("CSV:buffer",0);
137
+ }
138
+
139
+ $line=1;
140
+
141
+ while($line<$this->getParam("CSV:headerline",1))
142
+ {
143
+ $line++;
144
+ $dummy=fgetcsv($this->_fh,$this->_buffersize,$this->_csep,$this->_cenc);
145
+ $this->log("skip line $line:".implode($this->_csep,$dummy),"info");
146
+ }
147
+ $cols=fgetcsv($this->_fh,$this->_buffersize,$this->_csep,$this->_cenc);
148
+ //if csv has no headers,use column number as column name
149
+ if($this->getParam("CSV:noheader",false)==true)
150
+ {
151
+ $kl=array_merge(array("dummy"),$cols);
152
+ unset($kl[0]);
153
+ $cols=array();
154
+ foreach(array_keys($kl) as $c)
155
+ {
156
+ $cols[]="col".$c;
157
+ }
158
+ //reset file pointer
159
+ fseek($this->_fh,0);
160
+ }
161
+ $this->_cols=$cols;
162
+ $this->_nhcols=count($this->_cols);
163
+ //trim column names
164
+ for($i=0;$i<$this->_nhcols;$i++)
165
+ {
166
+ $this->_cols[$i]=trim($this->_cols[$i]);
167
+ }
168
+
169
+ if($prescan==true)
170
+ {
171
+ fclose($this->_fh);
172
+ }
173
+ else
174
+ {
175
+ $this->log("$this->_nhcols CSV headers columns found","startup");
176
+ }
177
+ return $this->_cols;
178
+ }
179
+
180
+ public function closeCSV()
181
+ {
182
+ fclose($this->_fh);
183
+ }
184
+
185
+ public function isemptyline($row) {
186
+ return ( !isset($row[1]) && empty($row[0]) );
187
+ }
188
+
189
+ public function getNextRecord()
190
+ {
191
+ $row=null;
192
+ $allowtrunc=$this->getParam("CSV:allowtrunc",false);
193
+ while($row!==false)
194
+ {
195
+ $row=fgetcsv($this->_fh,$this->_buffersize,$this->_csep,$this->_cenc);
196
+ if($row !==false)
197
+ {
198
+ $this->_curline++;
199
+ //skip empty lines
200
+ if($this->isemptyline($row))
201
+ {
202
+ continue;
203
+ }
204
+ $rcols=count($row);
205
+ if(!$allowtrunc && $rcols!=$this->_nhcols)
206
+ {
207
+ //if strict matching, warning & continue
208
+ $this->log("warning: line $this->_curline , wrong column number : $rcols found over $this->_nhcols, line skipped","warning");
209
+ continue;
210
+ }
211
+ break;
212
+ }
213
+ }
214
+ //if we read something
215
+ if(is_array($row))
216
+ {
217
+ //strict mode
218
+ if(!$allowtrunc)
219
+ {
220
+ //create product attributes values array indexed by attribute code
221
+ $record=array_combine($this->_cols,$row);
222
+ }
223
+ else
224
+ {
225
+
226
+ //relax mode, recompose keys from read columns , others will be left unset
227
+ $ncols=count($row);
228
+ $cols=array_slice($this->_cols,0,$ncols);
229
+ $record=array_combine($cols,$row);
230
+ }
231
+
232
+
233
+ }
234
+ else
235
+ {
236
+ $record=false;
237
+ }
238
+ unset($row);
239
+ return $record;
240
+ }
241
+
242
+
243
+ }
lib/Magmi/inc/magmi_defs.php ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ define("MAGMI_BASEDIR",dirname(dirname(__FILE__)));
3
+ define("MAGMI_INCDIR",MAGMI_BASEDIR."/inc");
4
+ define("MAGMI_INTEGRATION_INCDIR",MAGMI_BASEDIR."/integration/inc");
5
+ define("MAGMI_ENGINE_DIR",MAGMI_BASEDIR."/engines");
6
+ set_include_path(ini_get("include_path").
7
+ PATH_SEPARATOR.MAGMI_INCDIR.
8
+ PATH_SEPARATOR.MAGMI_INTEGRATION_INCDIR.
9
+ PATH_SEPARATOR.MAGMI_ENGINE_DIR);
10
+ require_once('magmi_loggers.php');
lib/Magmi/inc/magmi_engine.php ADDED
@@ -0,0 +1,453 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once("dbhelper.class.php");
3
+ require_once("magmi_config.php");
4
+ require_once("magmi_version.php");
5
+ require_once("magmi_utils.php");
6
+ require_once("magmi_statemanager.php");
7
+ require_once("magmi_pluginhelper.php");
8
+
9
+ /**
10
+ *
11
+ * This class is the mother class for magmi engines
12
+ * A magmi engine is a class that performs operations on DB
13
+ * @author dweeves
14
+ *
15
+ */
16
+ abstract class Magmi_Engine extends DbHelper
17
+ {
18
+ protected $_conf;
19
+ protected $_initialized=false;
20
+ protected $_exceptions=array();
21
+ public $tprefix;
22
+ protected $_connected;
23
+ protected $_activeplugins;
24
+ protected $_pluginclasses;
25
+ protected $_builtinplugins=array();
26
+ protected $_ploop_callbacks=array();
27
+ private $_excid=0;
28
+ public $logger=null;
29
+
30
+ public function getEngineInfo()
31
+ {
32
+ return array("name"=>"Generic Magmi Engine","version"=>"1.1","author"=>"dweeves");
33
+ }
34
+
35
+ public function __construct()
36
+ {
37
+ //force PHP internal encoding as UTF 8
38
+ mb_internal_encoding("UTF-8");
39
+ }
40
+
41
+
42
+ public final function initialize($params=array())
43
+ {
44
+ try
45
+ {
46
+ $this->_conf=Magmi_Config::getInstance();
47
+ $this->_conf->load();
48
+
49
+ $this->tprefix=$this->_conf->get("DATABASE","table_prefix");
50
+ $this->_excid=0;
51
+ $this->_initialized=true;
52
+ $this->_exceptions=array();
53
+ }
54
+ catch(Exception $e)
55
+ {
56
+ die("Error initializing Engine:{$this->_conf->getConfigFilename()} \n".$e->getMessage());
57
+ }
58
+
59
+ }
60
+
61
+ /**
62
+ * Returns magento directory
63
+ */
64
+ public function getMagentoDir()
65
+ {
66
+ return $this->_conf->getMagentoDir();
67
+ }
68
+ public function getMagentoVersion()
69
+ {
70
+ return $this->_conf->get("MAGENTO","version");
71
+ }
72
+
73
+ protected function _registerPluginLoopCallback($cbtype,$cb)
74
+ {
75
+ $this->_ploop_callbacks[$cbtype]=$cb;
76
+ }
77
+
78
+ protected function _unregisterPluginLoopCallback($cbtype)
79
+ {
80
+ unset($this->_ploop_callbacks[$cbtype]);
81
+ }
82
+
83
+ public function getPluginFamilies()
84
+ {
85
+ return array();
86
+ }
87
+
88
+
89
+ public function getEnabledPluginClasses($profile)
90
+ {
91
+ $enabledplugins=new EnabledPlugins_Config($profile);
92
+ $enabledplugins->load();
93
+ return $enabledplugins->getEnabledPluginFamilies($this->getPluginFamilies());
94
+ }
95
+
96
+ public function initPlugins($profile=null)
97
+ {
98
+
99
+ $this->_pluginclasses=$this->getEnabledPluginClasses($profile);
100
+ }
101
+
102
+ public function getBuiltinPluginClasses()
103
+ {
104
+ $bplarr=array();
105
+
106
+ foreach($this->_builtinplugins as $pfamily=>$pdef)
107
+ {
108
+ $plinfo=explode("::",$pdef);
109
+ $pfile=$plinfo[0];
110
+ $pclass=$plinfo[1];
111
+ require_once($pfile);
112
+ if(!isset($bplarr[$pfamily]))
113
+ {
114
+ $bplarr[$pfamily]=array();
115
+ }
116
+ $bplarr[$pfamily][]=$pclass;
117
+ }
118
+ return $bplarr;
119
+ }
120
+
121
+ public function getPluginClasses()
122
+ {
123
+ return $this->_pluginclasses;
124
+ }
125
+
126
+ public function getPluginInstances($family=null)
127
+ {
128
+ $pil=null;
129
+ if($family==null)
130
+ {
131
+ $pil=$this->_activeplugins();
132
+ }
133
+ else
134
+ {
135
+ $pil=(isset($this->_activeplugins[$family])?$this->_activeplugins[$family]:array());
136
+ }
137
+ return $pil;
138
+ }
139
+
140
+ public function setBuiltinPluginClasses($pfamily,$pclasses)
141
+ {
142
+ $this->_builtinplugins[$pfamily]=$pclasses;
143
+ }
144
+
145
+ public function sortPlugins($p1,$p2)
146
+ {
147
+
148
+ $m1=$p1->getPluginMeta();
149
+ if($m1==null)
150
+ {
151
+ return 1;
152
+ }
153
+ $m2=$p2->getPluginMeta();
154
+ if($m2==null)
155
+ {
156
+ return -1;
157
+ }
158
+ return strcmp($m1["file"],$m2["file"]);
159
+ }
160
+ public function createPlugins($profile,$params)
161
+ {
162
+ $plhelper=Magmi_PluginHelper::getInstance($profile);
163
+ $this->_pluginclasses = array_merge_recursive($this->_pluginclasses,$this->getBuiltinPluginClasses());
164
+ foreach($this->_pluginclasses as $pfamily=>$pclasses)
165
+ {
166
+ if($pfamily[0]=="*")
167
+ {
168
+ $this->_pluginclasses[substr($pfamily,1)]=$pclasses;
169
+ unset($this->_pluginclasses[$pfamily]);
170
+ }
171
+ }
172
+ foreach($this->_pluginclasses as $pfamily=>$pclasses)
173
+ {
174
+ if(!isset($this->_activeplugins[$pfamily]))
175
+ {
176
+ $this->_activeplugins[$pfamily]=array();
177
+ }
178
+ foreach($pclasses as $pclass)
179
+ {
180
+ $this->_activeplugins[$pfamily][]=$plhelper->createInstance($pfamily,$pclass,$params,$this);
181
+
182
+ }
183
+ usort($this->_activeplugins[$pfamily],array(&$this,"sortPlugins"));
184
+ }
185
+
186
+ }
187
+
188
+ public function getPluginInstanceByClassName($pfamily,$pclassname)
189
+ {
190
+ $inst=null;
191
+ if(isset($this->_activeplugins[$pfamily]))
192
+ {
193
+ foreach($this->_activeplugins[$pfamily] as $pinstance)
194
+ {
195
+ if(get_class($pinstance)==$pclassname)
196
+ {
197
+ $inst=$pinstance;
198
+ break;
199
+ }
200
+ }
201
+ }
202
+ return $inst;
203
+ }
204
+
205
+ public function getPluginInstance($family,$order=-1)
206
+ {
207
+ if($order<0)
208
+ {
209
+ $order+=count($this->_activeplugins[$family]);
210
+ }
211
+ return $this->_activeplugins[$family][$order];
212
+ }
213
+
214
+ public function callPlugins($types,$callback,&$data=null,$params=null,$break=true)
215
+ {
216
+ $result=true;
217
+ if(!is_array($types))
218
+ {
219
+ if($types!="*")
220
+ {
221
+ $types=explode(",",$types);
222
+ }
223
+ else
224
+ {
225
+ $types=array_keys($this->_activeplugins);
226
+ }
227
+ }
228
+ foreach($types as $ptype)
229
+ {
230
+ if(isset($this->_activeplugins[$ptype]))
231
+ {
232
+ foreach($this->_activeplugins[$ptype] as $pinst)
233
+ {
234
+ if(method_exists($pinst,$callback))
235
+ {
236
+ $callres=($data==null?($params==null?$pinst->$callback():$pinst->$callback($params)):$pinst->$callback($data,$params));
237
+ if($callres===false && $data!=null)
238
+ {
239
+
240
+ $result=false;
241
+
242
+ }
243
+ if(isset($this->_ploop_callbacks[$callback]))
244
+ {
245
+ $cb=$this->_ploop_callbacks[$callback];
246
+ $this->$cb($pinst,$data,$result);
247
+ }
248
+ if($result===false && $break)
249
+ {
250
+ return $result;
251
+ }
252
+ }
253
+ }
254
+ }
255
+ }
256
+ return $result;
257
+ }
258
+
259
+ public function getParam($params,$pname,$default=null)
260
+ {
261
+ return isset($params[$pname])?$params[$pname]:$default;
262
+ }
263
+
264
+ public function setLogger($logger)
265
+ {
266
+ $this->logger=$logger;
267
+ }
268
+ /**
269
+ * logging function
270
+ * @param string $data : string to log
271
+ * @param string $type : log type
272
+ */
273
+ public function microDateTime()
274
+ {
275
+ list($microSec, $timeStamp) = explode(" ", microtime());
276
+ return date('Y-m-d h:i:', $timeStamp) . (date('s', $timeStamp) + $microSec);
277
+ }
278
+
279
+ public function log($data,$type="default",$logger=null)
280
+ {
281
+ $usedlogger=($logger==null?$this->logger:$logger);
282
+ if(isset($usedlogger))
283
+ {
284
+ $usedlogger->log($data,$type);
285
+ }
286
+ }
287
+
288
+ public function logException($e,$data="",$logger=null)
289
+ {
290
+ $this->trace($e,$data);
291
+ $this->log($this->_excid.":".$e->getMessage()." - ".$data,"error",$logger);
292
+ }
293
+
294
+ public function getExceptionTrace($tk,&$traces)
295
+ {
296
+ $this->_excid++;
297
+ $trstr="";
298
+ foreach($traces as $trace)
299
+ {
300
+ if(isset($trace["file"]))
301
+ {
302
+ $fname=str_replace(dirname(dirname(__FILE__)),"",$trace["file"]);
303
+ $trstr.= $fname.":".(isset($trace["line"])?$trace["line"]:"?")." - ";
304
+ if(isset($trace["class"]))
305
+ {
306
+ $trstr.=$trace["class"]."->";
307
+ if(isset($trace["function"]))
308
+ {
309
+ $trstr.=$trace["function"];
310
+ }
311
+ $trstr.="\n----------------------------------------\n";
312
+ if(isset($trace["args"]))
313
+ {
314
+ $trstr.=print_r($trace["args"],true);
315
+ }
316
+ $trstr.="\n";
317
+ }
318
+ }
319
+ }
320
+ if(!isset($this->_exceptions[$tk]))
321
+ {
322
+ $this->_exceptions[$tk]=array(0,$this->_excid);
323
+ }
324
+ $this->_exceptions[$tk][0]++;
325
+ $trstr="************************************\n$trstr";
326
+ return array($trstr,$this->_exceptions[$tk][0]==1,$this->_exceptions[$tk][1]);
327
+ }
328
+
329
+ public function trace($e,$data="")
330
+ {
331
+ $traces=$e->getTrace();
332
+ $tk=$e->getMessage();
333
+ $traceinfo=$this->getExceptionTrace($tk,$traces);
334
+ $f=fopen(Magmi_StateManager::getTraceFile(),"a");
335
+ fwrite($f,"---- TRACE : $this->_excid -----\n");
336
+ try
337
+ {
338
+ if($traceinfo[1]==true)
339
+ {
340
+ fwrite($f,$traceinfo[0]);
341
+ fwrite($f,"+++++++++++++++++++++++++++++\nCONTEXT DUMP\n+++++++++++++++++++++++++++++\n");
342
+ fwrite($f,print_r($this,true));
343
+ fwrite($f,"\n+++++++++++++++++++++++++++++\nEND CONTEXT DUMP\n+++++++++++++++++++++++++++++\n");
344
+ }
345
+ else
346
+ {
347
+ $tnum=$traceinfo[2];
348
+ fwrite($f,"Duplicated exception - same trace as TRACE : $tnum\n");
349
+ }
350
+ }
351
+ catch(Exception $te)
352
+ {
353
+ fwrite($f,"Exception occured during trace:".$te->getMessage());
354
+ }
355
+ fwrite($f,"---- ENDTRACE : $this->_excid -----\n");
356
+ fclose($f);
357
+ }
358
+
359
+
360
+ /**
361
+ * Engine run method
362
+ * @param array $params - run parameters
363
+ */
364
+ public final function run($params=array())
365
+ {
366
+ try
367
+ {
368
+ $f=fopen(Magmi_StateManager::getTraceFile(),"w");
369
+ fclose($f);
370
+ $enginf=$this->getEngineInfo();
371
+ $this->log("MAGMI by dweeves - version:".Magmi_Version::$version,"title");
372
+ $this->log("Running {$enginf["name"]} v${enginf["version"]} by ${enginf["author"]}","startup");
373
+ if(!$this->_initialized)
374
+ {
375
+ $this->initialize($params);
376
+ }
377
+ $this->connectToMagento();
378
+ $this->engineInit($params);
379
+ $this->engineRun($params);
380
+ $this->disconnectFromMagento();
381
+ }
382
+ catch(Exception $e)
383
+ {
384
+ $this->disconnectFromMagento();
385
+
386
+ $this->handleException($e);
387
+ }
388
+
389
+ }
390
+
391
+ public function handleException($e)
392
+ {
393
+ $this->logException($e);
394
+ if(method_exists($this, "onEngineException"))
395
+ {
396
+ $this->onEngineException($e);
397
+ }
398
+ }
399
+
400
+ /**
401
+ shortcut method for configuration properties get
402
+ */
403
+ public function getProp($sec,$val,$default=null)
404
+ {
405
+ return $this->_conf->get($sec,$val,$default);
406
+ }
407
+
408
+ /**
409
+ * Initialize Connection with Magento Database
410
+ */
411
+ public function connectToMagento()
412
+ {
413
+ #get database infos from properties
414
+ if(!$this->_connected)
415
+ {
416
+ $host=$this->getProp("DATABASE","host","localhost");
417
+ $dbname=$this->getProp("DATABASE","dbname","magento");
418
+ $user=$this->getProp("DATABASE","user");
419
+ $pass=$this->getProp("DATABASE","password");
420
+ $debug=$this->getProp("DATABASE","debug");
421
+ $conn=$this->getProp("DATABASE","connectivity","net");
422
+ $port=$this->getProp("DATABASE","port","3306");
423
+ $socket=$this->getProp("DATABASE","unix_socket");
424
+ $this->initDb($host,$dbname,$user,$pass,$port,$socket,$conn,$debug);
425
+ //suggested by pastanislas
426
+ $this->_db->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY,true);
427
+ }
428
+ }
429
+ /*
430
+ * Disconnect Magento db
431
+ */
432
+ public function disconnectFromMagento()
433
+ {
434
+ if($this->_connected)
435
+ {
436
+ $this->exitDb();
437
+ }
438
+ }
439
+
440
+ /**
441
+ * returns prefixed table name
442
+ * @param string $magname : magento base table name
443
+ */
444
+ public function tablename($magname)
445
+ {
446
+ return $this->tprefix!=""?$this->tprefix."$magname":$magname;
447
+ }
448
+
449
+
450
+ public abstract function engineInit($params);
451
+ public abstract function engineRun($params);
452
+
453
+ }
lib/Magmi/inc/magmi_loggers.php ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class FileLogger
3
+ {
4
+ protected $_fname;
5
+
6
+ public function __construct($fname=null)
7
+ {
8
+ if($fname==null)
9
+ {
10
+ $fname=Magmi_StateManager::getProgressFile(true);
11
+ }
12
+ $this->_fname=$fname;
13
+ $f=fopen($this->_fname,"w");
14
+ if($f==false)
15
+ {
16
+ throw new Exception("CANNOT WRITE PROGRESS FILE ");
17
+ }
18
+ fclose($f);
19
+ }
20
+
21
+ public function log($data,$type)
22
+ {
23
+
24
+ $f=fopen($this->_fname,"a");
25
+ if($f==false)
26
+ {
27
+ throw new Exception("CANNOT WRITE PROGRESS FILE ");
28
+ }
29
+ $data=preg_replace ("/(\r|\n|\r\n)/", "<br>", $data);
30
+ fwrite($f,"$type:$data\n");
31
+ fclose($f);
32
+ }
33
+
34
+ }
35
+
36
+ class EchoLogger
37
+ {
38
+ public function log($data,$type)
39
+ {
40
+ $info=explode(";",$type);
41
+ $type=$info[0];
42
+ echo('<p class="logentry log_'.$type.'">'.$data."</p>");
43
+ }
44
+
45
+ }
46
+ class CLILogger
47
+ {
48
+ public function log($data,$type)
49
+ {
50
+ echo("$type:$data\n");
51
+ }
52
+ }
53
+ ?>
lib/Magmi/inc/magmi_mixin.php ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Magmi_Mixin
3
+ {
4
+ protected $_callers;
5
+
6
+ public function bind($caller)
7
+ {
8
+ $this->_callers[]=$caller;
9
+ $this->_callers=array_unique($this->_callers);
10
+ }
11
+
12
+ public function unbind($caller)
13
+ {
14
+
15
+ $ks=array_keys($this->_callers,$caller);
16
+ if(count($ks)>0)
17
+ {
18
+ foreach($ks as $k)
19
+ {
20
+ unset($this->_callers[$k]);
21
+ }
22
+ }
23
+
24
+ }
25
+
26
+ public function __call($data,$arg)
27
+ {
28
+ if(substr($data,0,8)=="_caller_")
29
+ {
30
+ $data=substr($data,8);
31
+ }
32
+ for($i=0;$i<count($this->_callers);$i++)
33
+ {
34
+ if(method_exists($this->_callers[$i],$data))
35
+ {
36
+ return call_user_func_array(array($this->_callers[$i],$data), $arg);
37
+ }
38
+ else
39
+ {
40
+ die("Invalid Method Call: $data - Not found in Caller");
41
+ }
42
+ }
43
+ }
44
+ }
lib/Magmi/inc/magmi_pluginhelper.php ADDED
@@ -0,0 +1,202 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once("magmi_config.php");
3
+ require_once("fshelper.php");
4
+ class Magmi_PluginHelper
5
+ {
6
+
7
+
8
+ static $_plugins_cache=array();
9
+ static $_instances=array();
10
+ public $base_dir;
11
+ public $plugin_dir;
12
+ protected $_profile;
13
+ protected $_plmeta=array("datasources"=>array("Magmi_Datasource","*/*"),
14
+ "itemprocessors"=>array("Magmi_ItemProcessor","*/*"),
15
+ "general"=>array("Magmi_GeneralImportPlugin","*/*"),
16
+ "utilities"=>array("Magmi_UtilityPlugin","utilities"));
17
+
18
+ public function __construct($profile=null)
19
+ {
20
+ $this->_profile=$profile;
21
+ $this->base_dir=dirname(__FILE__);
22
+ $this->plugin_dir=realpath(dirname(dirname(__FILE__)).DS."plugins");
23
+ //set include path to inclue plugins inc & base dir
24
+ set_include_path(ini_get("include_path").PATH_SEPARATOR."$this->plugin_dir/inc".PATH_SEPARATOR."$this->base_dir");
25
+ //add base classes in context
26
+ require_once("magmi_item_processor.php");
27
+ require_once("magmi_datasource.php");
28
+ require_once("magmi_generalimport_plugin.php");
29
+ require_once("magmi_utility_plugin.php");
30
+
31
+ }
32
+ public static function getInstance($profile=null)
33
+ {
34
+ $key=($profile==null?"default":$profile);
35
+ if(!isset(self::$_instances[$key]))
36
+ {
37
+ self::$_instances[$key]=new Magmi_PluginHelper($profile);
38
+ }
39
+ return self::$_instances[$key];
40
+ }
41
+
42
+ public static function fnsort($f1,$f2)
43
+ {
44
+ return strcmp(basename($f1),basename($f2));
45
+ }
46
+
47
+
48
+ public function initPluginInfos($baseclass,$basedir="*/*")
49
+ {
50
+ $candidates=glob("$this->plugin_dir/$basedir/*/*.php");
51
+ usort($candidates,array("Magmi_PluginHelper","fnsort"));
52
+ $pluginclasses=array();
53
+ foreach($candidates as $pcfile)
54
+ {
55
+ $dirname=dirname(substr($pcfile,strlen($this->plugin_dir)));
56
+ if(substr(basename($dirname),0,2)!='__')
57
+ {
58
+ $content=file_get_contents($pcfile);
59
+ if(preg_match_all("/class\s+(.*?)\s+extends\s+$baseclass/mi",$content,$matches,PREG_SET_ORDER))
60
+ {
61
+ require_once($pcfile);
62
+ foreach($matches as $match)
63
+ {
64
+ $pluginclasses[]=array("class"=>$match[1],"dir"=>$dirname,"file"=>basename($pcfile));
65
+ }
66
+ }
67
+ }
68
+ }
69
+ return $pluginclasses;
70
+ }
71
+
72
+ public function getPluginClasses($pltypes)
73
+ {
74
+ return self::getPluginsInfo($pltypes,"class");
75
+ }
76
+
77
+ public function getPluginsInfo($pltypes,$filter=null)
78
+ {
79
+ if(self::$_plugins_cache==null)
80
+ {
81
+ self::scanPlugins($pltypes);
82
+ }
83
+
84
+ if(isset($filter))
85
+ {
86
+ $out=array();
87
+ foreach(self::$_plugins_cache as $k=>$arr)
88
+ {
89
+ if(!isset($out[$k]))
90
+ {
91
+ $out[$k]=array();
92
+ }
93
+ foreach($arr as $desc)
94
+ {
95
+ $out[$k][]=$desc[$filter];
96
+ }
97
+ }
98
+ $plugins=$out;
99
+ }
100
+ else
101
+ {
102
+ $plugins=self::$_plugins_cache;
103
+ }
104
+ return $plugins;
105
+
106
+ }
107
+
108
+ public function scanPlugins($pltypes)
109
+ {
110
+ if(!is_array($pltypes))
111
+ {
112
+ $pltypes=array($pltypes);
113
+ }
114
+ foreach($pltypes as $pltype)
115
+ {
116
+ if(!isset(self::$_plugins_cache[$pltype]))
117
+ {
118
+ self::$_plugins_cache[$pltype]=self::initPluginInfos($this->_plmeta[$pltype][0],$this->_plmeta[$pltype][1]);
119
+ }
120
+ }
121
+ }
122
+
123
+
124
+ public function createInstance($ptype,$pclass,$params=null,$mmi=null)
125
+ {
126
+
127
+ if(!isset(self::$_plugins_cache[$ptype]))
128
+ {
129
+ self::scanPlugins($ptype);
130
+ }
131
+ $plinst=new $pclass();
132
+
133
+ $plinst->pluginInit($mmi,$this->getPluginMeta($plinst),$params,($mmi!=null),$this->_profile);
134
+ return $plinst;
135
+ }
136
+
137
+ public function getPluginDir($pinst)
138
+ {
139
+ $mt=$this->getPluginMeta($pinst);
140
+ return $mt["dir"];
141
+ }
142
+
143
+ public function getPluginMeta($pinst)
144
+ {
145
+ if(self::$_plugins_cache==null)
146
+ {
147
+ self::scanPlugins();
148
+ }
149
+
150
+ foreach(self::$_plugins_cache as $t=>$l)
151
+ {
152
+ foreach($l as $pdesc)
153
+ {
154
+ if($pdesc["class"]==get_class($pinst))
155
+ {
156
+ $out=$pdesc;
157
+ $out["dir"]=$this->plugin_dir.$pdesc["dir"];
158
+ return $out;
159
+ }
160
+ }
161
+ }
162
+ }
163
+
164
+ public function installPluginPackage($pkgname)
165
+ {
166
+ $zip = new ZipArchive();
167
+ $res = $zip->open($pkgname);
168
+ if ($res === TRUE)
169
+ {
170
+ $zip->extractTo($this->plugin_dir);
171
+ $zip->close();
172
+ return array("plugin_install"=>"OK");
173
+ }
174
+ else
175
+ {
176
+ return array("plugin_install"=>"ERROR",
177
+ "ERROR"=>"Invalid Plugin Package Archive");
178
+ }
179
+ $packages=glob("$this->plugin_dir/*");
180
+ foreach($packages as $pdir)
181
+ {
182
+ if(file_exists($pdir.DS."obsolete.txt"))
183
+ {
184
+ $content=file_get_contents($pdir.DS."obsolete.txt");
185
+ $obsolete=explode("\n",$content);
186
+ foreach($obsolete as $todelete)
187
+ {
188
+ if($todelete!="")
189
+ {
190
+ @unlink($pdir.DS.$todelete);
191
+ }
192
+ }
193
+ unlink($pdir.DS."obsolete.txt");
194
+ }
195
+ }
196
+ }
197
+
198
+ public function removePlugin($pgpath)
199
+ {
200
+ unlink($pgpath);
201
+ }
202
+ }
lib/Magmi/inc/magmi_postinstall.php ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once("magmi_version.php");
3
+
4
+ function magmi_post_install()
5
+ {
6
+ $out="";
7
+ if(version_compare(Magmi_Version::$version,"0.7.17")<=0)
8
+ {
9
+ $delcds=array_merge(glob("../integration/inc/*.*"),glob("../integration/samples/*.*"));
10
+ $todelete=array();
11
+ foreach($delcds as $fname)
12
+ {
13
+ $todelete[]=basename($fname);
14
+ }
15
+ $allfiles=glob("../integration/*.*");
16
+ if($allfiles!==false)
17
+ {
18
+ foreach($allfiles as $fname)
19
+ {
20
+ if(in_array(basename($fname),$todelete))
21
+ {
22
+ $out.="deleting $fname (new dir struct)<br>";
23
+ unlink($fname);
24
+ }
25
+ else
26
+ {
27
+ $out.="moving $fname to migrated (custom script)<br>";
28
+ @mkdir("../integration/scripts/migrated/");
29
+ copy($fname,"../integration/scripts/migrated/".basename($fname));
30
+ unlink($fname);
31
+ }
32
+ }
33
+ }
34
+ else
35
+ {
36
+ $out="nothing to do";
37
+ }
38
+
39
+ }
40
+ return array("OK"=>$out);
41
+ }
lib/Magmi/inc/magmi_statemanager.php ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if(!defined("DS"))
3
+ {
4
+ define("DS",DIRECTORY_SEPARATOR);
5
+ }
6
+ class Magmi_StateManager
7
+ {
8
+ private static $_statefile=null;
9
+ private static $_script=__FILE__;
10
+ private static $_state="idle";
11
+
12
+
13
+ public static function getStateFile()
14
+ {
15
+ return self::getStateDir().DS."magmistate";
16
+ }
17
+
18
+ public static function getTraceFile()
19
+ {
20
+ return self::getStateDir().DS."trace.txt";
21
+
22
+ }
23
+
24
+ public static function getStateDir()
25
+ {
26
+ return dirname(dirname(self::$_script)).DS."state";
27
+ }
28
+
29
+ public static function getProgressFile($full=false)
30
+ {
31
+ $fullname=self::getStateDir().DS."progress.txt";
32
+ $pfname=($full?$fullname:"progress.txt");
33
+ return $pfname;
34
+ }
35
+
36
+ public static function setState($state,$force=false)
37
+ {
38
+
39
+ if(self::$_state==$state && !$force)
40
+ {
41
+ return;
42
+ }
43
+
44
+ self::$_state=$state;
45
+ $f=fopen(self::getStateFile(),"w");
46
+ fwrite($f,self::$_state);
47
+ fclose($f);
48
+ @chmod(self::getStateFile(),0664);
49
+ if($state=="running")
50
+ {
51
+ $f=fopen(self::getTraceFile(),"w");
52
+ fclose($f);
53
+ @chmod(self::getTraceFile(),0664);
54
+ }
55
+ }
56
+
57
+ public static function getState($cached=false)
58
+ {
59
+ if(!$cached)
60
+ {
61
+ if(!file_exists(self::getStateFile()))
62
+ {
63
+ self::setState("idle",true);
64
+ }
65
+ $state=file_get_contents(self::getStateFile());
66
+ }
67
+ else
68
+ {
69
+ $state=self::$_state;
70
+ }
71
+ return $state;
72
+ }
73
+
74
+ }
lib/Magmi/inc/magmi_utils.php ADDED
@@ -0,0 +1,149 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ //utilities function
3
+ // return null for empty string
4
+ function nullifempty($val)
5
+ {
6
+ return (isset($val)?(trim($val)==""?null:$val):null);
7
+ }
8
+ // return false for empty string
9
+ function falseifempty($val)
10
+ {
11
+ return (isset($val)?(strlen($val)==0?false:$val):false);
12
+ }
13
+ //test for empty string
14
+ function testempty($arr,$val)
15
+ {
16
+
17
+ return !isset($arr[$val]) || strlen(trim($arr[$val]))==0;
18
+ }
19
+
20
+ function deleteifempty($val)
21
+ {
22
+ return (isset($val)?(trim($val)==""?"__MAGMI_DELETE__":$val):"__MAGMI_DELETE__");
23
+ }
24
+
25
+ function csl2arr($cslarr,$sep=",")
26
+ {
27
+ $arr=explode($sep,$cslarr);
28
+ for($i=0;$i<count($arr);$i++)
29
+ {
30
+ $arr[$i]=trim($arr[$i]);
31
+ }
32
+ return $arr;
33
+ }
34
+
35
+ function trimarray(&$arr)
36
+ {
37
+ for($i=0;$i<count($arr);$i++)
38
+ {
39
+ $arr[$i]=trim($arr[$i]);
40
+ }
41
+
42
+ }
43
+
44
+ function getRelative(&$val)
45
+ {
46
+ $dir="+";
47
+ if($val[0]=="-")
48
+ {
49
+ $val=substr($val,1);
50
+ $dir="-";
51
+ }
52
+ else
53
+ if($val[0]=="+")
54
+ {
55
+ $val=substr($val,1);
56
+ }
57
+ return $dir;
58
+ }
59
+
60
+ function is_remote_path($path)
61
+ {
62
+ $parsed=parse_url($path);
63
+ return isset($parsed['host']);
64
+ }
65
+
66
+ function abspath($path,$basepath="",$resolve=true)
67
+ {
68
+ if($basepath=="")
69
+ {
70
+ $basepath=dirname(dirname(__FILE__));
71
+ }
72
+ $cpath=str_replace('//','/',$basepath."/".$path);
73
+ if($resolve && !is_remote_path($cpath))
74
+ {
75
+ $abs=realpath($cpath);
76
+ }
77
+ else
78
+ {
79
+ $abs=preg_replace('|\w+/\.\.\/|', '',$cpath );
80
+ $abs=preg_replace('|\./|','',$abs);
81
+
82
+ }
83
+ return $abs;
84
+ }
85
+
86
+ function truepath($path){
87
+ $opath=$path;
88
+ // whether $path is unix or not
89
+ $unipath=strlen($path)==0 || $path{0}!='/';
90
+ // attempts to detect if path is relative in which case, add cwd
91
+ if(strpos($path,':')===false && $unipath)
92
+ $path=getcwd().DIRECTORY_SEPARATOR.$path;
93
+ // resolve path parts (single dot, double dot and double delimiters)
94
+ $path = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $path);
95
+ $parts = array_filter(explode(DIRECTORY_SEPARATOR, $path), 'strlen');
96
+ $absolutes = array();
97
+ foreach ($parts as $part) {
98
+ if ('.' == $part) continue;
99
+ if ('..' == $part) {
100
+ array_pop($absolutes);
101
+ } else {
102
+ $absolutes[] = $part;
103
+ }
104
+ }
105
+ $path=implode(DIRECTORY_SEPARATOR, $absolutes);
106
+ // resolve any symlinks
107
+ if(file_exists($path) && linkinfo($path)>0)
108
+ {
109
+ $path=readlink($path);
110
+ }
111
+ // put initial separator that could have been lost
112
+ $path=!$unipath ? '/'.$path : $path;
113
+ return $path;
114
+ }
115
+
116
+
117
+ function isabspath($path)
118
+ {
119
+ return ($path[0]=="." || (substr(PHP_OS,3)=="WIN" && strlen($path)>1)?$path[1]==":":$path[0]=="/");
120
+ }
121
+
122
+
123
+ class Slugger
124
+ {
125
+ static protected $_translit=array(
126
+ 'Š'=>'S', 'š'=>'s', 'Ð'=>'Dj','Ž'=>'Z', 'ž'=>'z', 'À'=>'A', 'Á'=>'A', 'Â'=>'A', 'Ã'=>'A', 'Ä'=>'A',
127
+ 'Å'=>'A', 'Æ'=>'A', 'Ç'=>'C', 'È'=>'E', 'É'=>'E', 'Ê'=>'E', 'Ë'=>'E', 'Ì'=>'I', 'Í'=>'I', 'Î'=>'I',
128
+ 'Ï'=>'I', 'Ñ'=>'N', 'Ò'=>'O', 'Ó'=>'O', 'Ô'=>'O', 'Õ'=>'O', 'Ö'=>'O', 'Ø'=>'O', 'Ù'=>'U', 'Ú'=>'U',
129
+ 'Û'=>'U', 'Ü'=>'U', 'Ý'=>'Y', 'Þ'=>'B', 'ß'=>'Ss','à'=>'a', 'á'=>'a', 'â'=>'a', 'ã'=>'a', 'ä'=>'a',
130
+ 'å'=>'a', 'æ'=>'a', 'ç'=>'c', 'è'=>'e', 'é'=>'e', 'ê'=>'e', 'ë'=>'e', 'ì'=>'i', 'í'=>'i', 'î'=>'i',
131
+ 'ï'=>'i', 'ð'=>'o', 'ñ'=>'n', 'ò'=>'o', 'ó'=>'o', 'ô'=>'o', 'õ'=>'o', 'ö'=>'o', 'ø'=>'o', 'ù'=>'u',
132
+ 'ú'=>'u', 'û'=>'u', 'ý'=>'y', 'ý'=>'y', 'þ'=>'b', 'ÿ'=>'y', 'ƒ'=>'f'
133
+ );
134
+
135
+ public static function stripAccents($text){
136
+
137
+ return strtr($text,self::$_translit);
138
+ }
139
+
140
+ public static function slug($str,$allowslash=false)
141
+ {
142
+ $str = strtolower(self::stripAccents(trim($str)));
143
+ $rerep=$allowslash?'[^a-z0-9-/]':'[^a-z0-9-]';
144
+ $str = preg_replace("|$rerep|", '-', $str);
145
+ $str = preg_replace('|-+|', "-", $str);
146
+ $str = preg_replace('|-$|', "", $str);
147
+ return $str;
148
+ }
149
+ }
lib/Magmi/inc/magmi_version.php ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
1
+ <?php
2
+ class Magmi_Version
3
+ {
4
+ public static $version="0.7.18";
5
+ }
lib/Magmi/inc/properties.php ADDED
@@ -0,0 +1,202 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if(!defined("DS"))
3
+ {
4
+ define("DS",DIRECTORY_SEPARATOR);
5
+ }
6
+ class FileNotFoundException extends Exception
7
+ {
8
+
9
+ }
10
+ class InvalidPropertiesException extends Exception
11
+ {
12
+
13
+ }
14
+ class Properties
15
+ {
16
+ protected $_props;
17
+ public $inifile;
18
+ protected $_specialchars=array('"'=>":DQUOTE:",
19
+ "'"=>":SQUOTE:",
20
+ '\\t'=>"TAB");
21
+ public function __construct()
22
+ {
23
+ $this->inifile=null;
24
+ $this->_props=array();
25
+ }
26
+
27
+ public function setPropsFromFlatArray($flatarr)
28
+ {
29
+
30
+ $this->_props=$this->getIniStruct($flatarr);
31
+ }
32
+
33
+ public function setProps($proparr)
34
+ {
35
+ $this->_props=$proparr;
36
+ }
37
+
38
+ public function load($file)
39
+ {
40
+ if(!file_exists($file))
41
+ {
42
+ return;
43
+ //throw new FileNotFoundException();
44
+
45
+ }
46
+ try
47
+ {
48
+ $this->inifile=$file;
49
+ $this->_props=parse_ini_file($this->inifile,true);
50
+ foreach($this->_props as $sec=>$data)
51
+ {
52
+ foreach($data as $k=>$v)
53
+ {
54
+ foreach($this->_specialchars as $spch=>$alias)
55
+ {
56
+ $newv=str_replace($alias,$spch,$v);
57
+ if($newv!=$v)
58
+ {
59
+ break;
60
+ }
61
+ }
62
+ $this->_props[$sec][$k]=$newv;
63
+ }
64
+ }
65
+ }
66
+ catch(Exception $e)
67
+ {
68
+ throw new InvalidPropertiesException();
69
+ }
70
+ }
71
+
72
+ public function getIniStruct($arr)
73
+ {
74
+ $conf=array();
75
+ foreach($arr as $k=>$v)
76
+ {
77
+ list($section,$value)=explode(":",$k,2);
78
+ if(!isset($conf[$section]))
79
+ {
80
+ $conf[$section]=array();
81
+ }
82
+ $conf[$section][$value]=$v;
83
+ }
84
+ return $conf;
85
+ }
86
+
87
+ public function save($fname=null)
88
+ {
89
+ if($fname==null)
90
+ {
91
+ $fname==$this->inifile;
92
+ }
93
+ return $this->write_ini_file($this->_props,$fname,true);
94
+ }
95
+
96
+ public function esc($str)
97
+ {
98
+ foreach($this->_specialchars as $spch=>$alias)
99
+ {
100
+ $str=str_replace($spch,$alias,$str);
101
+ }
102
+ return $str;
103
+ }
104
+
105
+ public function write_ini_file($assoc_arr, $path, $has_sections=FALSE) {
106
+ $content = "";
107
+ if(count($assoc_arr)>0)
108
+ {
109
+ if ($has_sections) {
110
+ foreach ($assoc_arr as $key=>$elem) {
111
+ $content .= "[".$key."]\n";
112
+ foreach ($elem as $key2=>$elem2) {
113
+ if(is_array($elem2))
114
+ {
115
+ for($i=0;$i<count($elem2);$i++)
116
+ {
117
+ $content .= $key2."[] = \"".$this->esc($elem2[$i])."\"\n";
118
+ }
119
+ }
120
+ else if($elem2=="") $content .= $key2." = \n";
121
+ else $content .= $key2." = \"".$this->esc($elem2)."\"\n";
122
+ }
123
+ }
124
+ }
125
+ else {
126
+ foreach ($assoc_arr as $key=>$elem) {
127
+ if(is_array($elem))
128
+ {
129
+ for($i=0;$i<count($elem);$i++)
130
+ {
131
+ $content .= $key2."[] = \"".$this->esc($elem[$i])."\"\n";
132
+ }
133
+ }
134
+ else if($elem=="") $content .= $key2." = \n";
135
+ else $content .= $key2." = \"".$this->esc($elem)."\"\n";
136
+ }
137
+ }
138
+ }
139
+
140
+ if (!$handle = fopen($path, 'w')) {
141
+ return false;
142
+ }
143
+ if (!fwrite($handle, $content)) {
144
+ return false;
145
+ }
146
+ @chmod($path,0664);
147
+ fclose($handle);
148
+ return true;
149
+ }
150
+
151
+ public function set($secname,$pname,$val)
152
+ {
153
+ $this->_props[$secname][$pname]=$val;
154
+ }
155
+
156
+ /**
157
+ * retrieve property value with default if not found
158
+ * @param string $secname section name
159
+ * @param string $pname property name
160
+ * @param string $default default value if not found (null if not set)
161
+ * @return string value if found or default if not found
162
+ */
163
+ public function get($secname,$pname,$default=null)
164
+ {
165
+ if(isset($this->_props[$secname]) && isset($this->_props[$secname][$pname]))
166
+ {
167
+ $v=$this->_props[$secname][$pname];
168
+ return $v;
169
+ }
170
+ else
171
+ {
172
+ return $default;
173
+ }
174
+ }
175
+
176
+ public function getsection($secname)
177
+ {
178
+ if(isset($this->_props[$secname]))
179
+ {
180
+ return $this->_props[$secname];
181
+ }
182
+ else
183
+ {
184
+ return array();
185
+ }
186
+ }
187
+
188
+ public function hasSection($secname)
189
+ {
190
+ return isset($this->_props[$secname]);
191
+ }
192
+
193
+ public function removeSection($secname)
194
+ {
195
+ if($this->hasSection($secname))
196
+ {
197
+ unset($this->_props[$secname]);
198
+ }
199
+ }
200
+
201
+
202
+ }
lib/Magmi/integration/inc/magmi_datapump.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once("properties.php");
3
+
4
+ class Magmi_DataPumpFactory
5
+ {
6
+ static protected $_factoryprops=null;
7
+ static function getDataPumpInstance($pumptype)
8
+ {
9
+ if(self::$_factoryprops==null)
10
+ {
11
+ self::$_factoryprops=new Properties();
12
+ self::$_factoryprops->load(dirname(__FILE__).DS."pumpfactory.ini");
13
+ }
14
+ $pumpinfo=self::$_factoryprops->get("DATAPUMPS",$pumptype,"");
15
+ $arr=explode("::",$pumpinfo);
16
+ if(count($arr)==2)
17
+ {
18
+ $pumpfile=$arr[0];
19
+ $pumpclass=$arr[1];
20
+
21
+ try
22
+ {
23
+ require_once(dirname(__FILE__).DS."$pumpfile.php");
24
+ $pumpinst=new $pumpclass();
25
+ }
26
+ catch(Exception $e)
27
+ {
28
+ $pumpinst=null;
29
+ }
30
+ }
31
+ else
32
+ {
33
+ echo "Invalid Pump Type";
34
+ }
35
+ return $pumpinst;
36
+ }
37
+ }
lib/Magmi/integration/inc/magmi_datapumpdatasource.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * This is a fake datasource for datapump, it just does nothing ;)
4
+ * @author dweeves
5
+ *
6
+ */
7
+ class Magmi_DatapumpDS extends Magmi_Datasource
8
+ {
9
+
10
+ public function getPluginInfo()
11
+ {
12
+ return array("name"=>"DataPump Datasource",
13
+ "author"=>"Dweeves",
14
+ "version"=>"1.0.0");
15
+ }
16
+
17
+
18
+ }
lib/Magmi/integration/inc/productimport_datapump.php ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ require_once("magmi_productimportengine.php");
4
+
5
+ class Magmi_ProductImport_DataPump
6
+ {
7
+ protected $_engine=null;
8
+ protected $_params=array();
9
+ protected $_logger=null;
10
+ protected $_importcolumns=array();
11
+ protected $_defaultvalues=array();
12
+ protected $_stats;
13
+ protected $_crow;
14
+ protected $_rstep=100;
15
+ protected $_mdpatched=false;
16
+
17
+
18
+ public function __construct()
19
+ {
20
+ $this->_engine=new Magmi_ProductImportEngine();
21
+ $this->_engine->setBuiltinPluginClasses("*datasources",dirname(__FILE__).DS."magmi_datapumpdatasource.php::Magmi_DatapumpDS");
22
+
23
+ $this->_stats["tstart"]=microtime(true);
24
+ //differential
25
+ $this->_stats["tdiff"]=$this->_stats["tstart"];
26
+ }
27
+
28
+ public function setReportingStep($rstep)
29
+ {
30
+ $this->_rstep=$rstep;
31
+ }
32
+ public function beginImportSession($profile,$mode,$logger=null)
33
+ {
34
+ $this->_engine->setLogger($logger);
35
+ $this->_engine->initialize();
36
+ $this->_params=array("profile"=>$profile,"mode"=>$mode);
37
+ $this->_engine->engineInit($this->_params);
38
+ $this->_engine->initImport($this->_params);
39
+ //intermediary report step
40
+ $this->_engine->initDbqStats();
41
+ $pstep=$this->_engine->getProp("GLOBAL","step",0.5);
42
+ //read each line
43
+ $this->_stats["lastrec"]=0;
44
+ $this->_stats["lastdbtime"]=0;
45
+ $this->crow=0;
46
+
47
+ }
48
+
49
+
50
+ public function setDefaultValues($dv=array())
51
+ {
52
+ $this->_defaultvalues=$dv;
53
+ }
54
+
55
+
56
+ public function ingest($item=array())
57
+ {
58
+ $item=array_merge($this->_defaultvalues,$item);
59
+ $diff=array_diff(array_keys($item),$this->_importcolumns);
60
+ if(count($diff)>0)
61
+ {
62
+ $this->_importcolumns=array_keys($item);
63
+ //process columns
64
+ $this->_engine->callPlugins("itemprocessors","processColumnList",$this->_importcolumns);
65
+ $this->_engine->initAttrInfos($this->_importcolumns);
66
+ }
67
+ $res=$this->_engine->processDataSourceLine($item, $this->_rstep,$this->_stats["tstart"],$this->_stats["tdiff"],$this->_stats["lastdbtime"],$_this->stats["lastrec"]);
68
+
69
+ }
70
+
71
+ public function endImportSession()
72
+ {
73
+ $this->_engine->reportStats($this->_engine->getCurrentRow(),$this->_stats["tstart"],$this->_stats["tdiff"],$this->_stats["lastdbtime"],$_this->stats["lastrec"]);
74
+ $skustats=$this->_engine->getSkuStats();
75
+ $this->_engine->log("Skus imported OK:".$skustats["ok"]."/".$skustats["nsku"],"info");
76
+ if($skustats["ko"]>0)
77
+ {
78
+ $this->_engine->log("Skus imported KO:".$skustats["ko"]."/".$skustats["nsku"],"warning");
79
+ }
80
+
81
+ $this->_engine->exitImport();
82
+ }
83
+
84
+ }
lib/Magmi/integration/inc/pumpfactory.ini ADDED
@@ -0,0 +1,2 @@
 
 
1
+ [DATAPUMPS]
2
+ productimport=productimport_datapump::Magmi_ProductImport_Datapump
lib/Magmi/integration/samples/sample.php ADDED
@@ -0,0 +1,117 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once("../../inc/magmi_defs.php");
3
+ require_once("../inc/magmi_datapump.php");
4
+
5
+
6
+ /** Define a logger class that will receive all magmi logs **/
7
+ class TestLogger
8
+ {
9
+ /**
10
+ * logging methos
11
+ * @param string $data : log content
12
+ * @param string $type : log type
13
+ */
14
+ public function log($data,$type)
15
+ {
16
+ echo "$type:$data\n";
17
+ }
18
+ }
19
+ /**
20
+ * create a Product import Datapump using Magmi_DatapumpFactory
21
+ */
22
+ $dp=Magmi_DataPumpFactory::getDataPumpInstance("productimport");
23
+ /**
24
+ * Start import session
25
+ * with :
26
+ * - profile : test_ptj
27
+ * - mode : create
28
+ * - logger : an instance of the class defined above
29
+ */
30
+
31
+ /**
32
+ * FOR THE SAMPLE TO WORK CORRECTLY , YOU HAVE TO DEFINE A test_ptj profile with :
33
+ * UPSELL/CROSS SELL, ITEM RELATER, CATEGORIES IMPORTER/CREATOR selected
34
+ * ON THE FLY INDEXER IS RECOMMENDED (better endimport performance)
35
+ * Reindexer needed also to have products show up on front : select all but "catalog_category_product" & "url_rewrite" (both are handled by on the fly indexer)
36
+ */
37
+ $dp->beginImportSession("test_ptj","create",new TestLogger());
38
+
39
+ /* Create 5000 items , with every 100 :
40
+ *
41
+ * upsell on last 100 even
42
+ * cross sell on last 100 odd
43
+ * related on last 100 every 5
44
+ * cross sell on last 100 every 10
45
+ * categories named catX/even or catX/odd with X is thousand of item (using categories plugin) */
46
+ for($sku=0;$sku<5000;$sku++)
47
+ {
48
+ //create item category path array
49
+ //catX/even or catX/odd, X being the 1000's of the item
50
+ $cats=array("cat".strval(intval($sku/1000)));
51
+ if($sku%2==0)
52
+ {
53
+ $cats[]="even";
54
+ }
55
+ else
56
+ {
57
+ $cats[]="odd";
58
+ }
59
+ //create item to import
60
+ // sku : XXXXX , 5 numbers , padded left with current loop counter as sku
61
+ // name : itemXXXXX
62
+ // description : testXXXXX
63
+ // price : random between $1 & $500
64
+ // categories : the ones built above
65
+ $item=array("sku"=>str_pad($sku,5,"0",STR_PAD_LEFT),"name"=>"item".$sku,"description"=>"test".$sku,"price"=>rand(1,500),"categories"=>implode("/",$cats));
66
+ //now some fun, every 100 items, create some relations
67
+ if($sku>99 && $sku%100==0)
68
+ {
69
+ //first, we'll remove all existing relations (upsell/cross sell / related)
70
+ $upsell=array("-re::.*");
71
+ $csell=array("-re::.*");
72
+ $re=array("-re::.*");
73
+ $xre=array();
74
+ for($i=$sku-99;$i<$sku;$i++)
75
+ {
76
+ //related item sku
77
+ $rsku=str_pad($i,5,"0",STR_PAD_LEFT);
78
+ //add upselling on each odd item in the 100 before the current
79
+ if($i%2==1)
80
+ {
81
+ $upsell[]=$rsku;
82
+ }
83
+ else
84
+ //add cross sell on each even item in the 100 before the current
85
+ {
86
+ $csell[]=$rsku;
87
+ }
88
+
89
+ //on each 10 before, cross relate
90
+ if($i%10==0)
91
+ {
92
+ $xre[]="-$rsku";
93
+ }
94
+ else
95
+ {
96
+ //on each 5 before , single relate
97
+ if($i%5==0)
98
+ {
99
+ $re[]=$rsku;
100
+ }
101
+ }
102
+ }
103
+ //fill upsell with the computed skus from rules above
104
+ $item["us_skus"]=implode(",",$upsell);
105
+ //fill cross sell with the computed skus from rules above
106
+ $item["cs_skus"]=implode(",",$csell);
107
+ //fill single related with the computed skus from rules above
108
+ $item["re_skus"]=implode(",",$re);
109
+ //fill cross related with the computed skus from rules above
110
+ $item["xre_skus"]=implode(",",$xre);
111
+ }
112
+ /* import current item */
113
+ $dp->ingest($item);
114
+ }
115
+ /* end import session, will run post import plugins */
116
+ $dp->endImportSession();
117
+
lib/Magmi/integration/samples/sample2_configurables.php ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once("../../inc/magmi_defs.php");
3
+ require_once("../inc/magmi_datapump.php");
4
+
5
+
6
+ /** Define a logger class that will receive all magmi logs **/
7
+ class TestLogger
8
+ {
9
+ /**
10
+ * logging methos
11
+ * @param string $data : log content
12
+ * @param string $type : log type
13
+ */
14
+ public function log($data,$type)
15
+ {
16
+ echo "$type:$data\n";
17
+ }
18
+ }
19
+ /**
20
+ * create a Product import Datapump using Magmi_DatapumpFactory
21
+ */
22
+ $dp=Magmi_DataPumpFactory::getDataPumpInstance("productimport");
23
+ /**
24
+ * Start import session
25
+ * with :
26
+ * - profile : test_ptj
27
+ * - mode : create
28
+ * - logger : an instance of the class defined above
29
+ */
30
+
31
+ /**
32
+ * FOR THE SAMPLE TO WORK CORRECTLY , YOU HAVE TO DEFINE A test_ptj profile with :
33
+ * UPSELL/CROSS SELL, ITEM RELATER, CATEGORIES IMPORTER/CREATOR selected
34
+ * ON THE FLY INDEXER IS RECOMMENDED (better endimport performance)
35
+ * Reindexer needed also to have products show up on front : select all but "catalog_category_product" & "url_rewrite" (both are handled by on the fly indexer)
36
+ */
37
+ $dp->beginImportSession("default","create",new TestLogger());
38
+
39
+ /* Create 5000 items , with every 100 :
40
+ *
41
+ * upsell on last 100 even
42
+ * cross sell on last 100 odd
43
+ * related on last 100 every 5
44
+ * cross sell on last 100 every 10
45
+ * categories named catX/even or catX/odd with X is thousand of item (using categories plugin) */
46
+ for($sku=0;$sku<=200;$sku++)
47
+ {
48
+ // price : random between $1 & $500
49
+ $item=array("store"=>"admin","type"=>"simple","sku"=>str_pad($sku,5,"0",STR_PAD_LEFT),"name"=>"item".$sku,"description"=>"test".$sku,"price"=>rand(1,500),"min_qty"=>3,"qty"=>"+7");
50
+ //color : radom c0/c10
51
+ $item["color"]="c".strval(rand(0, 10));
52
+
53
+ //now some fun, every 100 items, create some relations
54
+ if($sku>99 && $sku%100==0)
55
+ {
56
+ //first, we'll remove all existing relations (upsell/cross sell / related)
57
+ $subskus=array();
58
+ for($i=$sku-99;$i<$sku;$i++)
59
+ {
60
+ //related item sku
61
+ $subskus[]=str_pad($i,5,"0",STR_PAD_LEFT);
62
+ }
63
+ $item["simples_skus"]=implode(",",$subskus);
64
+ $item["type"]="configurable";
65
+ $item["configurable_attributes"]="color";
66
+ //cross relate with all skus ending by 2
67
+ $item["xre_skus"]="re::.*2$";
68
+ //star relate all skus ending with 1
69
+ $item["*re_skus"]="re::.*1$";
70
+
71
+
72
+ }
73
+
74
+ /* import current item */
75
+ $dp->ingest($item);
76
+ }
77
+ /* end import session, will run post import plugins */
78
+ $dp->endImportSession();
79
+
lib/Magmi/plugins/base/datasources/__magento/magmi_magentodatasource.php ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once("magmi_engine.php");
3
+
4
+ class Magmi_DSEngine extends Magmi_Engine
5
+ {
6
+ public function engineInit($params)
7
+ {
8
+
9
+ }
10
+
11
+ public function engineRun($params)
12
+ {
13
+
14
+ }
15
+ }
16
+
17
+ class Magmi_MagentoDatasource extends Magmi_Datasource
18
+ {
19
+ public function initialize($params)
20
+ {
21
+ $this->engine=new Magmi_DSEngine();
22
+ $this->extractSQL=$this->buildSQL();
23
+ }
24
+
25
+ public function buildSQL()
26
+ {
27
+
28
+ }
29
+
30
+ public function getPluginInfo()
31
+ {
32
+ return array("name"=>"Magento Products Datasource",
33
+ "author"=>"Dweeves",
34
+ "version"=>"1.0.0");
35
+ }
36
+
37
+ public function getPluginParamNames()
38
+ {
39
+ return array("MAGDS:fields");
40
+ }
41
+
42
+ public function startImport()
43
+ {
44
+ }
45
+
46
+
47
+
48
+ public function getRecordsCount()
49
+ {
50
+ $sql=null;
51
+ //optimized count query
52
+ $sql="SELECT COUNT(*) as cnt FROM (".str_replace("\n"," ",$this->extractsql).") as t1";
53
+ }
54
+
55
+ public function getColumnNames($prescan=false)
56
+ {
57
+ $s=$this->dbh->select($this->extractsql);
58
+ $test=$s->fetch();
59
+ $s->closeCursor();
60
+ unset($s);
61
+ $cl=array_keys($test);
62
+ return $cl;
63
+ }
64
+
65
+
66
+
67
+ public function getNextRecord()
68
+ {
69
+ if(!isset($this->stmt))
70
+ {
71
+ $this->stmt=$this->dbh->select($this->extractsql);
72
+ }
73
+ $data=$this->stmt->fetch();
74
+ if(!$data)
75
+ {
76
+ return false;
77
+ }
78
+ return $data;
79
+ }
80
+
81
+ public function endImport()
82
+ {
83
+
84
+ }
85
+ public function afterImport()
86
+ {
87
+
88
+ }
89
+
90
+ }
lib/Magmi/plugins/base/datasources/__magento/options_panel.php ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+
2
+ <div class="plugin_description">
3
+ This plugin enables magmi <b>mass updates</b> by selecting
4
+ existing products from magento database
5
+ </div>
6
+
lib/Magmi/plugins/base/datasources/csv/csvds_filelist.php ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ $files=$this->getCSVList();
3
+ if($files!==false && count($files)>0){?>
4
+ <select name="CSV:filename" id="csvfile">
5
+ <?php foreach($files as $fname){ ?>
6
+ <option <?php if($fname==$this->getParam("CSV:filename")){?>selected=selected<?php }?> value="<?php echo $fname?>"><?php echo basename($fname)?></option>
7
+ <?php }?>
8
+ </select>
9
+ <a id='csvdl' href="./download_file.php?file=<?php $this->getParam("CSV:filename")?>">Download CSV</a>
10
+ <script type="text/javascript">
11
+ $('csvdl').observe('click',function(el){
12
+ var fval=$('csvfile').value;
13
+ $('csvdl').href="./download_file.php?file="+fval;}
14
+ );
15
+ </script><?php } else {?>
16
+ <span> No csv files found in <?php echo $this->getScanDir(false)?></span>
17
+ <?php }?>
lib/Magmi/plugins/base/datasources/csv/magmi_csvdatasource.php ADDED
@@ -0,0 +1,274 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once("magmi_csvreader.php");
3
+
4
+
5
+ class Magmi_CSVDataSource extends Magmi_Datasource
6
+ {
7
+ protected $_csvreader;
8
+
9
+ public function initialize($params)
10
+ {
11
+ $this->_csvreader=new Magmi_CSVReader();
12
+ $this->_csvreader->bind($this);
13
+ $this->_csvreader->initialize();
14
+
15
+ }
16
+
17
+ public function getAbsPath($path)
18
+ {
19
+
20
+ return abspath($path,$this->getScanDir());
21
+
22
+ }
23
+
24
+ public function getScanDir($resolve=true)
25
+ {
26
+ $scandir=$this->getParam("CSV:basedir","var/import");
27
+ if(!isabspath($scandir))
28
+ {
29
+ $scandir=abspath($scandir,Magmi_Config::getInstance()->getMagentoDir(),$resolve);
30
+ }
31
+ return $scandir;
32
+ }
33
+
34
+ public function getCSVList()
35
+ {
36
+ $scandir=$this->getScanDir();
37
+ $files=glob("$scandir/*.csv");
38
+ return $files;
39
+ }
40
+
41
+ public function getPluginParams($params)
42
+ {
43
+ $pp=array();
44
+ foreach($params as $k=>$v)
45
+ {
46
+ if(preg_match("/^CSV:.*$/",$k))
47
+ {
48
+ $pp[$k]=$v;
49
+ }
50
+ }
51
+ return $pp;
52
+ }
53
+
54
+ public function getPluginInfo()
55
+ {
56
+ return array("name"=>"CSV Datasource",
57
+ "author"=>"Dweeves",
58
+ "version"=>"1.3");
59
+ }
60
+
61
+ public function getRecordsCount()
62
+ {
63
+ return $this->_csvreader->getLinesCount();
64
+ }
65
+
66
+ public function getAttributeList()
67
+ {
68
+
69
+ }
70
+
71
+ public function getRemoteFile($url,$creds=null,$authmode=null,$cookies=null)
72
+ {
73
+ $ch = curl_init($url);
74
+ $this->log("Fetching CSV: $url","startup");
75
+ //output filename (current dir+remote filename)
76
+ $csvdldir=dirname(__FILE__)."/downloads";
77
+ if(!file_exists($csvdldir))
78
+ {
79
+ @mkdir($csvdldir);
80
+ @chmod($csvdldir, Magmi_Config::getInstance()->getDirMask());
81
+ }
82
+
83
+ $outname=$csvdldir."/".basename($url);
84
+ $ext = substr(strrchr($outname, '.'), 1);
85
+ if($ext!=".txt" && $ext!=".csv")
86
+ {
87
+ $outname=$outname.".csv";
88
+ }
89
+ //open file for writing
90
+ if(file_exists($outname))
91
+ {
92
+ unlink($outname);
93
+ }
94
+ $fp = fopen($outname, "w");
95
+ if($fp==false)
96
+ {
97
+ throw new Exception("Cannot write file:$outname");
98
+ }
99
+ if(substr($url,0,4)=="http")
100
+ {
101
+ $lookup=1;
102
+
103
+ $lookup_opts= array(CURLOPT_RETURNTRANSFER=>true,
104
+ CURLOPT_HEADER=>true,
105
+ CURLOPT_NOBODY=>true,
106
+ CURLOPT_FOLLOWLOCATION=>true,
107
+ CURLOPT_FILETIME=>true,
108
+ CURLOPT_CUSTOMREQUEST=>"HEAD");
109
+
110
+ $dl_opts=array(CURLOPT_FILE=>$fp,
111
+ CURLOPT_CUSTOMREQUEST=>"GET",
112
+ CURLOPT_HEADER=>false,
113
+ CURLOPT_NOBODY=>false,
114
+ CURLOPT_FOLLOWLOCATION=>true,
115
+ CURLOPT_UNRESTRICTED_AUTH=>true,
116
+ CURLOPT_HTTPHEADER=> array('Expect:'));
117
+
118
+ }
119
+ else
120
+ {
121
+ if(substr($url,0,3)=="ftp")
122
+ {
123
+ $lookup=0;
124
+ $dl_opts=array(CURLOPT_FILE=>$fp);
125
+ }
126
+ }
127
+
128
+
129
+ if($creds!="")
130
+ {
131
+ if($lookup!=0)
132
+ {
133
+ if(substr($url,0,4)=="http")
134
+ {
135
+ $lookup_opts[CURLOPT_HTTPAUTH]=CURLAUTH_ANY;
136
+ $lookup_opts[CURLOPT_UNRESTRICTED_AUTH]=true;
137
+ }
138
+ $lookup_opts[CURLOPT_USERPWD]="$creds";
139
+ }
140
+
141
+
142
+ if(substr($url,0,4)=="http")
143
+ {
144
+ $dl_opts[CURLOPT_HTTPAUTH]=CURLAUTH_ANY;
145
+ $dl_opts[CURLOPT_UNRESTRICTED_AUTH]=true;
146
+ }
147
+ $dl_opts[CURLOPT_USERPWD]="$creds";
148
+ }
149
+
150
+ if($cookies)
151
+ {
152
+ if($lookup!=0)
153
+ {
154
+ if(substr($url,0,4)=="http")
155
+ {
156
+ $lookup_opts[CURLOPT_COOKIE]=$cookies;
157
+ }
158
+ }
159
+
160
+ if(substr($url,0,4)=="http")
161
+ {
162
+ $dl_opts[CURLOPT_COOKIE]=$cookies;
163
+ }
164
+ }
165
+
166
+ if($lookup)
167
+ {
168
+ //lookup , using HEAD request
169
+ $ok=curl_setopt_array($ch,$lookup_opts);
170
+ $res=curl_exec($ch);
171
+ if($res!==false)
172
+ {
173
+ $lm=curl_getinfo($ch);
174
+ if(curl_getinfo($ch,CURLINFO_HTTP_CODE)!=200)
175
+ {
176
+ $resp = explode("\n\r\n", $res);
177
+ $this->log("http header:<pre>".$resp[0]."</pre>","error");
178
+ throw new Exception("Cannot fetch $url");
179
+
180
+ }
181
+ }
182
+ else
183
+ {
184
+ $lm=curl_getinfo($ch);
185
+ throw new Exception("Cannot fetch $url");
186
+ }
187
+
188
+ }
189
+
190
+ $res=array("should_dl"=>true,"reason"=>"");
191
+
192
+ if($res["should_dl"])
193
+ {
194
+ //clear url options
195
+ $ok=curl_setopt_array($ch, array());
196
+
197
+ //Download the file , force expect to nothing to avoid buffer save problem
198
+ curl_setopt_array($ch,$dl_opts);
199
+ curl_exec($ch);
200
+ if(curl_error($ch)!="")
201
+ {
202
+ $this->log(curl_error($ch),"error");
203
+ throw new Exception("Cannot fetch $url");
204
+ }
205
+ else
206
+ {
207
+ $lm=curl_getinfo($ch);
208
+
209
+ $this->log("CSV Fetched in ".$lm['total_time']. "secs","startup");
210
+ }
211
+ curl_close($ch);
212
+ fclose($fp);
213
+
214
+ }
215
+ else
216
+ {
217
+ curl_close($ch);
218
+ //bad file or bad hour, no download this time
219
+ $this->log("No dowload , ".$res["reason"],"info");
220
+ }
221
+ //return the csv filename
222
+ return $outname;
223
+ }
224
+ public function beforeImport()
225
+ {
226
+ if($this->getParam("CSV:importmode","local")=="remote")
227
+ {
228
+ $url=$this->getParam("CSV:remoteurl","");
229
+ $creds="";
230
+ $authmode="";
231
+ if($this->getParam("CSV:remoteauth",false)==true)
232
+ {
233
+ $user=$this->getParam("CSV:remoteuser");
234
+ $pass=$this->getParam("CSV:remotepass");
235
+
236
+ $authmode=$this->getParam("CSV:authmode");
237
+ $creds="$user:$pass";
238
+ }
239
+ $cookies=$this->getParam("CSV:remotecookie");
240
+ $outname=$this->getRemoteFile($url,$creds,$authmode,$cookies);
241
+ $this->setParam("CSV:filename", $outname);
242
+ $this->_csvreader->initialize();
243
+ }
244
+ return $this->_csvreader->checkCSV();
245
+ }
246
+
247
+ public function afterImport()
248
+ {
249
+
250
+ }
251
+
252
+ public function startImport()
253
+ {
254
+ $this->_csvreader->openCSV();
255
+ }
256
+
257
+ public function getColumnNames($prescan=false)
258
+ {
259
+ return $this->_csvreader->getColumnNames($prescan);
260
+ }
261
+
262
+ public function endImport()
263
+ {
264
+ $this->_csvreader->closeCSV();
265
+ }
266
+
267
+
268
+ public function getNextRecord()
269
+ {
270
+ return $this->_csvreader->getNextRecord();
271
+ }
272
+
273
+
274
+ }
lib/Magmi/plugins/base/datasources/csv/options_panel.php ADDED
@@ -0,0 +1,142 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ <div class="plugin_description">
3
+ This plugin enables magmi import from csv files (using Dataflow format + magmi extended columns)<br/> <b>NOT Magento 1.5 new importexport format!!</b>
4
+ </div>
5
+ <div>
6
+
7
+ <div class="csvmode">
8
+ </div>
9
+
10
+ <ul class="formline">
11
+ <li class="label">CSV import mode</li>
12
+ <li class="value">
13
+ <select name="CSV:importmode" id="CSV:importmode">
14
+ <option value="local" <?php if($this->getParam("CSV:importmode","local")=="local"){?>selected="selected"<?php }?>>Local</option>
15
+ <option value="remote" <?php if($this->getParam("CSV:importmode","local")=="remote"){?>selected="selected"<?php }?>>Remote</option>
16
+ </select>
17
+ </ul>
18
+
19
+ <div id="localcsv" <?php if($this->getParam("CSV:importmode","local")=="remote"){?> style="display:none"<?php }?>>
20
+ <ul class="formline">
21
+ <li class="label">CSVs base directory</li>
22
+ <li class="value">
23
+ <input type="text" name="CSV:basedir" id="CSV:basedir" value="<?php echo $this->getParam("CSV:basedir","var/import")?>"></input>
24
+ <div class="fieldinfo">Relative paths are relative to magento base directory , absolute paths will be used as is</div></li>
25
+ </ul>
26
+ <ul class="formline">
27
+ <li class="label" >File to import:</li>
28
+ <li class="value" id="csvds_filelist">
29
+ <?php echo $this->getOptionsPanel("csvds_filelist.php")->getHtml(); ?>
30
+ </li>
31
+ </ul>
32
+ </div>
33
+
34
+ <div id="remotecsv" <?php if($this->getParam("CSV:importmode","local")=="local"){?> style="display:none"<?php }?>>
35
+ <ul class="formline">
36
+ <li class="label">Remote CSV url</li>
37
+ <li class="value">
38
+ <input type="text" name="CSV:remoteurl" id="CSV:remoteurl" value="<?php echo $this->getParam("CSV:remoteurl","")?>" style="width:400px"></input>
39
+ </li>
40
+ </ul>
41
+ <div id="remotecookie" >
42
+ <ul class="formline">
43
+ <li class="label">HTTP Cookie</li>
44
+ <li class="value"><input type="text" name="CSV:remotecookie" id="CSV:remotecookie" value="<?php echo $this->getParam("CSV:remotecookie","")?>" style="width:400px"></li>
45
+ </ul>
46
+ </div>
47
+ <input type="checkbox" id="CSV:remoteauth" name="CSV:remoteauth" <?php if($this->getParam("CSV:remoteauth",false)==true){?>checked="checked"<?php }?>>authentication needed
48
+ <div id="remoteauth" <?php if($this->getParam("CSV:remoteauth",false)==false){?>style="display:none"<?php }?>>
49
+
50
+ <div class="remoteuserpass">
51
+ <ul class="formline">
52
+ <li class="label">User</li>
53
+ <li class="value"><input type="text" name="CSV:remoteuser" id="CSV:remoteuser" value="<?php echo $this->getParam("CSV:remoteuser","")?>"></li>
54
+
55
+ </ul>
56
+ <ul class="formline">
57
+ <li class="label">Password</li>
58
+ <li class="value"><input type="text" name="CSV:remotepass" id="CSV:remotepass" value="<?php echo $this->getParam("CSV:remotepass","")?>"></li>
59
+ </ul>
60
+ </div>
61
+
62
+ </div>
63
+
64
+ </div>
65
+
66
+
67
+ </div>
68
+ <div>
69
+ <h3>CSV options</h3>
70
+ <span class="">CSV separator:</span><input type="text" maxlength="3" size="3" name="CSV:separator" value="<?php echo $this->getParam("CSV:separator")?>"></input>
71
+ <span class="">CSV Enclosure:</span><input type="text" maxlength="3" size="3" name="CSV:enclosure" value='<?php echo $this->getParam("CSV:enclosure")?>'></input>
72
+ </div>
73
+
74
+ <div class=""><input type="checkbox" name="CSV:noheader" <?php if($this->getParam("CSV:noheader",false)==true){?>checked="checked"<?php }?>>
75
+ Headerless CSV (Use Column Mapper Plugin to set processable column names)</div>
76
+ <div class=""><input type="checkbox" name="CSV:allowtrunc" <?php if($this->getParam("CSV:allowtrunc",false)==true){?>checked="checked"<?php }?>>
77
+ Allow truncated lines (bypasses data line structure correlation with headers)</div>
78
+
79
+ <?php $hdline=$this->getParam("CSV:headerline","");
80
+ $malformed=($hdline!="" && $hdline!=1)?>
81
+ <input type="checkbox" id="malformedcb" <?php if($malformed){?>checked="checked"<?php }?>/>Malformed CSV (column list line not at top of file)
82
+ <div id="malformed" <?php if(!$malformed){?>style="display:none"<?php }?>>
83
+ <span class="">CSV Header at line:</span><input type="text" id="CSV:headerline" name="CSV:headerline" maxlength="7" size="7" value="<?php echo $hdline?>"></input>
84
+ </div>
85
+ <script type="text/javascript">
86
+ handle_auth=function()
87
+ {
88
+ if($('CSV:remoteauth').checked)
89
+ {
90
+ $('remoteauth').show();
91
+ }
92
+ else
93
+ {
94
+ $('remoteauth').hide();
95
+ }
96
+ }
97
+
98
+ $('CSV:basedir').observe('blur',function()
99
+ {
100
+ new Ajax.Updater('csvds_filelist','ajax_pluginconf.php',{
101
+ parameters:{file:'csvds_filelist.php',
102
+ plugintype:'datasources',
103
+ pluginclass:'<?php echo get_class($this->_plugin)?>',
104
+ profile:'<?php echo $this->getConfig()->getProfile()?>',
105
+ 'CSV:basedir':$F('CSV:basedir')}});
106
+ });
107
+ $('malformedcb').observe('click',function(ev){
108
+ if($('malformedcb').checked)
109
+ {
110
+ $('malformed').show();
111
+ }
112
+ else
113
+ {
114
+ $('malformed').hide();
115
+ }
116
+ });
117
+ $('CSV:headerline').observe('blur',function()
118
+ {
119
+ var wellformed=($F('CSV:headerline')=="1" || $F('CSV:headerline')=="");
120
+ if(wellformed)
121
+ {
122
+ $('malformedcb').checked=false;
123
+ $('malformed').hide();
124
+ $('CSV:headerline').value="";
125
+ }
126
+ });
127
+ $('CSV:importmode').observe('change',function()
128
+ {
129
+ if($F('CSV:importmode')=='local')
130
+ {
131
+ $('localcsv').show();
132
+ $('remotecsv').hide();
133
+ }
134
+ else
135
+ {
136
+ $('localcsv').hide();
137
+ $('remotecsv').show();
138
+ }
139
+ });
140
+ $('CSV:remoteauth').observe('click',handle_auth);
141
+ $('CSV:remoteurl').observe('blur',handle_auth);
142
+ </script>
lib/Magmi/plugins/base/datasources/genericsql/mysql_options.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div id="mysql_config">
2
+ <ul class="formline">
3
+ <li class="label">Input DB Host</li>
4
+ <li class="value"><input type="text" name="SQL:dbhost" value="<?php echo $this->getParam("SQL:dbhost","localhost")?>"/></li>
5
+ </ul>
6
+ <ul class="formline">
7
+ <li class="label">Input DB Name</li>
8
+ <li class="value"><input type="text" name="SQL:dbname" value="<?php echo $this->getParam("SQL:dbname","")?>"/></li>
9
+ </ul>
10
+ <ul class="formline">
11
+ <li class="label">Input DB User</li>
12
+ <li class="value"><input type="text" name="SQL:dbuser" value="<?php echo $this->getParam("SQL:dbuser","")?>"/></li>
13
+ </ul>
14
+ <ul class="formline">
15
+ <li class="label">Input DB Password</li>
16
+ <li class="value"><input type="password" name="SQL:dbpass" value="<?php echo $this->getParam("SQL:dbpass","")?>"/></li>
17
+ </ul>
18
+ <ul class="formline">
19
+ <li class="label">Input DB Initial Statements (optional)</li>
20
+ <li class="value"><textarea name="SQL:dbextra" cols="80" rows="5">
21
+ <?php echo $this->getParam("SQL:dbextra","")?>
22
+ </textarea>
23
+ <div class="fieldinfo">
24
+ Put DB requests like SET NAMES if necessary separated by ;
25
+ </div>
26
+ </li>
27
+ </ul>
28
+ </div>
lib/Magmi/plugins/base/datasources/genericsql/options_panel.php ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div class="plugin_description">
2
+ This plugin imports data from Generic SQL Backend<br/>
3
+ You should put sql files in the <b><?php echo $this->getPluginDir()."/requests"?></b> directory
4
+ </div>
5
+ <ul class="formline">
6
+ <?php $dbtype=$this->getParam("SQL:dbtype");?>
7
+ <li class="label">Input DB Type</li>
8
+ <li><select name="SQL:dbtype" id="SQL:dbtype">
9
+ <option value="mysql" <?php if ($dbtype=="mysql"){?>selected="selected"<?php }?>>MySQL</option>
10
+ <option value="other" <?php if ($dbtype=="other"){?>selected="selected"<?php }?>>Other</option>
11
+ </select></li>
12
+ </ul>
13
+ <div id="options_container">
14
+ <?php echo $this->getOptionsPanel("$dbtype"."_options.php")->getHtml();?>
15
+ </div>
16
+ <ul class="formline">
17
+ <li class="label">SQL file</li>
18
+ <li class="value">
19
+ <?php $dr=$this->getParam("SQL:queryfile");?>
20
+ <?php $sqlfiles=$this->getSQLFileList();?>
21
+ <?php if(count($sqlfiles)>0){?>
22
+
23
+ <select name="SQL:queryfile">
24
+ <?php foreach($sqlfiles as $curfile):?>
25
+ <option <?php if($curfile==$dr){?>selected=selected<?php }?> value="<?php echo $curfile?>" ><?php echo basename($curfile)?></option>
26
+ <?php endforeach?>
27
+ </select>
28
+ <?php }else{?>
29
+ <span class="error">No SQL files detected in <?php echo $this->getPluginDir()."/requests"?></span>
30
+ <?php }?>
31
+ </li>
32
+ </ul>
33
+ <script type="text/javascript">
34
+ var dbt=$('SQL:dbtype');
35
+ dbt.observe('change',function(ev)
36
+ {
37
+ new Ajax.Updater('options_container','ajax_pluginconf.php',{
38
+ parameters:{file:$('SQL:dbtype').value+'_options.php',
39
+ plugintype:'datasources',
40
+ pluginclass:'<?php echo get_class($this->_plugin)?>',
41
+ profile:'<?php echo $this->getConfig()->getProfile()?>',
42
+ }});
43
+ }
44
+ );
45
+ </script>
lib/Magmi/plugins/base/datasources/genericsql/other_options.php ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div id="other_config">
2
+ <ul class="formline">
3
+ <li class="label">Input DB User</li>
4
+ <li class="value"><input type="text" name="SQL:dbuser" value="<?echo $this->getParam("SQL:dbuser","")?>"/></li>
5
+ </ul>
6
+ <ul class="formline">
7
+ <li class="label">Input DB Password</li>
8
+ <li class="value"><input type="password" name="SQL:dbpass" value="<?echo $this->getParam("SQL:dbpass","")?>"/></li>
9
+ </ul>
10
+ <ul class="formline">
11
+ <li class="label">PDO Connection String</li>
12
+ <li class="value"><input type="text" size="80" name="SQL:pdostr" value="<?echo $this->getParam("SQL:pdostr","")?>"/>
13
+ <div class="fieldinfo">you must have correct PDO driver installed &amp; also know PDO connection string syntax</div></li>
14
+ </ul>
15
+ </div>
lib/Magmi/plugins/base/datasources/genericsql/sql_datasource.php ADDED
@@ -0,0 +1,138 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once("dbhelper.class.php");
3
+
4
+ class ExtDBHelper extends DBHelper
5
+ {
6
+ public function initDBMysql($dbname,$host,$user,$pass)
7
+ {
8
+
9
+ $this->_db=new PDO("mysql:host=$host;dbname=$dbname;charset=utf8", $user, $pass);
10
+ }
11
+
12
+ public function initDBPDOStr($user,$pass,$pdostr)
13
+ {
14
+ //fix by Mr Lei for UTF8 special chars
15
+ $this->_db=new PDO("$pdostr", $user, $pass);
16
+ }
17
+
18
+ }
19
+ class SQL_Datasource extends Magmi_Datasource
20
+ {
21
+ public $dbh;
22
+ public $stmt;
23
+ public $extractsql;
24
+ public $sqlfile;
25
+
26
+ public function initialize($params)
27
+ {
28
+ $this->dbh=new ExtDBHelper();
29
+ $cdbtype=$this->getParam("SQL:dbtype");
30
+ $cdbusr=$this->getParam("SQL:dbuser");
31
+ $cdbpass=$this->getParam("SQL:dbpass");
32
+ if($cdbtype=="other")
33
+ {
34
+ $cdbpdostr=$this->getParam("SQL:pdostr","");
35
+
36
+ $this->dbh->initDBPDOStr($cdbuser,$cdbpass,$cdbpdostr);
37
+ }
38
+ else
39
+ {
40
+ $cdbname=$this->getParam("SQL:dbname");
41
+ $cdbhost=$this->getParam("SQL:dbhost");
42
+ $extra=$this->getParam("SQL:dbextra");
43
+ $this->dbh->initDbMysql($cdbname,$cdbhost,$cdbusr, $cdbpass);
44
+
45
+ }
46
+ //handle extra initial commands
47
+ if(isset($extra) && $extra!="")
48
+ {
49
+ foreach(explode(";\n",$extra) as $st)
50
+ {
51
+ if($st!="")
52
+ {
53
+ $this->dbh->exec_stmt($st);
54
+ }
55
+ }
56
+ }
57
+ $this->stmt=null;
58
+ $this->sqlfile=$this->getParam("SQL:queryfile");
59
+ $this->extractsql=file_get_contents($this->sqlfile);
60
+ }
61
+
62
+ public function getPluginInfo()
63
+ {
64
+ return array("name"=>"Generic SQL Datasource",
65
+ "author"=>"Dweeves",
66
+ "version"=>"1.0.2");
67
+ }
68
+
69
+ public function getPluginParamNames()
70
+ {
71
+ return array("SQL:dbtype","SQL:dbname","SQL:dbhost","SQL:dbuser","SQL:dbpass","SQL:dbextra","SQL:queryfile","SQL:pdostr");
72
+ }
73
+
74
+ public function startImport()
75
+ {
76
+ }
77
+
78
+
79
+
80
+ public function getSQLFileList()
81
+ {
82
+ $files=glob(dirname(__file__)."/requests/*.sql");
83
+ return $files;
84
+ }
85
+
86
+
87
+ public function getRecordsCount()
88
+ {
89
+ $sql=null;
90
+ //optimized count query
91
+ if(file_exists($this->sqlfile.".count"))
92
+ {
93
+ $sql=file_get_contents($this->sqlfile.".count");
94
+ }
95
+ if(!isset($sql))
96
+ {
97
+ $sql="SELECT COUNT(*) as cnt FROM (".str_replace("\n"," ",$this->extractsql).") as t1";
98
+ }
99
+ $cnt=$this->dbh->selectone($sql,null,"cnt");
100
+
101
+ return $cnt;
102
+ }
103
+
104
+ public function getColumnNames($prescan=false)
105
+ {
106
+ $s=$this->dbh->select($this->extractsql);
107
+ $test=$s->fetch();
108
+ $s->closeCursor();
109
+ unset($s);
110
+ $cl=array_keys($test);
111
+ return $cl;
112
+ }
113
+
114
+
115
+
116
+ public function getNextRecord()
117
+ {
118
+ if(!isset($this->stmt))
119
+ {
120
+ $this->stmt=$this->dbh->select($this->extractsql);
121
+ }
122
+ $data=$this->stmt->fetch();
123
+ if(!$data)
124
+ {
125
+ return false;
126
+ }
127
+ return $data;
128
+ }
129
+
130
+ public function endImport()
131
+ {
132
+
133
+ }
134
+ public function afterImport()
135
+ {
136
+
137
+ }
138
+ }
lib/Magmi/plugins/base/general/emailreport/emailreport.php ADDED
@@ -0,0 +1,133 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class EmailReportPlugin extends Magmi_GeneralImportPlugin
3
+ {
4
+ protected $_attach;
5
+
6
+ public function initialize($params)
7
+ {
8
+ $this->_attach=array();
9
+ }
10
+
11
+ public function getPluginInfo()
12
+ {
13
+ return array(
14
+ "name" => "Import Report Mail Notifier",
15
+ "author" => "Dweeves",
16
+ "version" => "1.0.0",
17
+ "url"=>$this->pluginDocUrl("Import_report_mail_notifier")
18
+ );
19
+ }
20
+ public function send_email($to, $from, $from_name, $subject, $message, $attachments=false)
21
+ {
22
+ $headers = "From: ".$from_name."<".$from.">\n";
23
+ $headers .= "Reply-To: ".$from_name."<".$from.">\n";
24
+ $headers .= "Return-Path: ".$from_name."<".$from.">\n";
25
+ $headers .= "Message-ID: <".time()."-".$from.">\n";
26
+ $headers .= "X-Mailer: PHP v".phpversion();
27
+
28
+ $msg_txt="";
29
+ $email_txt = $message;
30
+
31
+ $semi_rand = md5(time());
32
+ $mime_boundary = "==Multipart_Boundary_x{$semi_rand}x";
33
+
34
+ $headers .= "\nMIME-Version: 1.0\n" .
35
+ "Content-Type: multipart/mixed;\n" .
36
+ " boundary=\"{$mime_boundary}\"";
37
+
38
+ $email_txt .= $msg_txt;
39
+ $email_message = $email_txt;
40
+ $email_message .= "This is a multi-part message in MIME format.\n\n" .
41
+ "--{$mime_boundary}\n" .
42
+ "Content-Type:text/html; charset=\"iso-8859-1\"\n" .
43
+ "Content-Transfer-Encoding: 7bit\n\n" .
44
+ $email_txt . "\n\n";
45
+
46
+ $attachments=$this->_attach;
47
+ if ($attachments !== false)
48
+ {
49
+ for($i=0; $i < count($attachments); $i++)
50
+ {
51
+ if (is_file($attachments[$i]))
52
+ {
53
+ $fileatt = $attachments[$i];
54
+ $fileatt_type = "application/octet-stream";
55
+ $start= strrpos($attachments[$i], '/') == -1 ? strrpos($attachments[$i], '//') : strrpos($attachments[$i], '/')+1;
56
+ $fileatt_name = substr($attachments[$i], $start, strlen($attachments[$i]));
57
+
58
+ $file = fopen($fileatt,'rb');
59
+ $data = fread($file,filesize($fileatt));
60
+ fclose($file);
61
+
62
+ $data = chunk_split(base64_encode($data));
63
+
64
+ $email_message .= "--{$mime_boundary}\n" .
65
+ "Content-Type: {$fileatt_type};\n" .
66
+ " name=\"{$fileatt_name}\"\n" .
67
+ "Content-Transfer-Encoding: base64\n\n" .
68
+ $data . "\n\n";
69
+
70
+ }
71
+ }
72
+ }
73
+
74
+ $email_message .= "--{$mime_boundary}--\n";
75
+ $this->log("Sending report to : $to","info");
76
+ $ok= mail($to, $subject, $email_message, $headers);
77
+ return $ok;
78
+ }
79
+
80
+ public function addAttachment($fname)
81
+ {
82
+ $this->_attach[]=$fname;
83
+ $this->_attach=array_unique($this->_attach);
84
+ }
85
+
86
+ public function getPluginParams($params)
87
+ {
88
+ $pp=array();
89
+ foreach($params as $k=>$v)
90
+ {
91
+ if(preg_match("/^EMAILREP:.*$/",$k))
92
+ {
93
+ $pp[$k]=$v;
94
+ }
95
+ }
96
+ return $pp;
97
+ }
98
+
99
+ public function afterImport()
100
+ {
101
+ $eng=$this->_callers[0];
102
+ if($this->getParam("EMAILREP:to","")!="" && $this->getParam("EMAILREP:from","")!="")
103
+ {
104
+ if($this->getParam("EMAILREP:attachcsv",false)==true)
105
+ {
106
+ $ds=$eng->getPluginInstanceByClassName("datasources","Magmi_CSVDataSource");
107
+ if($ds!=null)
108
+ {
109
+ $csvfile=$ds->getParam("CSV:filename");
110
+ $this->addAttachment($csvfile);
111
+ }
112
+ }
113
+
114
+ if($this->getParam("EMAILREP:attachlog",false)==true)
115
+ {
116
+ //copy magmi report
117
+ $pfile=Magmi_StateManager::getProgressFile(true);
118
+ $this->addAttachment($pfile);
119
+ }
120
+
121
+ $ok=$this->send_email($this->getParam("EMAILREP:to"),
122
+ $this->getParam("EMAILREP:from"),
123
+ $this->getParam("EMAILREP:from_alias",""),
124
+ $this->getParam("EMAILREP:subject","Magmi import report"),
125
+ $this->getParam("EMAILREP:body","report attached"),$this->_attach);
126
+ if(!$ok)
127
+ {
128
+ $this->log("Cannot send email","error");
129
+ }
130
+ }
131
+ }
132
+
133
+ }
lib/Magmi/plugins/base/general/emailreport/options_panel.php ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div class="plugin_description">
2
+ <p>This plugin can be used to send a email report for the import</p>
3
+ <p>it uses PHP <b>mail</b> feature, <b>please ensure your setup is compatible with this</b></p>
4
+ </div>
5
+ <ul class="formline">
6
+ <li class="label">Email report to:</li>
7
+ <li class="value"><input type="text" style="width:400px" name="EMAILREP:to" value="<?php echo $this->getParam("EMAILREP:to","")?>"><div class="fieldinfo">You can set several receiver emails separated by a comma (,)</div></li>
8
+ </ul>
9
+ <ul class="formline">
10
+ <li class="label">Report sender:</li>
11
+ <li class="value"><input type="text" name="EMAILREP:from" value="<?php echo $this->getParam("EMAILREP:from","magmi@sourceforge.net")?>"></li>
12
+ </ul>
13
+ <ul class="formline">
14
+ <li class="label">Report sender alias:</li>
15
+ <li class="value"><input type="text" name="EMAILREP:from_alias" value="<?php echo $this->getParam("EMAILREP:from_alias","Magmi Importer")?>"></li>
16
+ </ul>
17
+ <ul class="formline">
18
+ <li class="label">Subject:</li>
19
+ <li class="value"><input type="text" name="EMAILREP:subject" value="<?php echo $this->getParam("EMAILREP:subject","Magmi import report")?>"></li>
20
+ </ul>
21
+ <ul class="formline">
22
+ <li class="label">Body:</li>
23
+ <li class="value"><textarea name="EMAILREP:body"><?php echo $this->getParam("EMAILREP:body","report attached");?></textarea></li>
24
+ </ul>
25
+ <ul class="formline">
26
+ <li class="label">Attachments</li>
27
+ <li class="value"><input type="checkbox" name="EMAILREP:attachlog" <?php if($this->getParam("EMAILREP:attachlog")==true){?>checked="checked"<?php }?>>Attach import log</li>
28
+ <li class="value"><input type="checkbox" name="EMAILREP:attachcsv" <?php if($this->getParam("EMAILREP:attachcsv")==true){?>checked="checked"<?php }?>>Attach source CSV</li>
29
+ </ul>
lib/Magmi/plugins/base/general/importurl/importurl_plugin.php ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Magmi_ImportUrlPlugin extends Magmi_GeneralImportPlugin
3
+ {
4
+ public function getPluginInfo()
5
+ {
6
+ return array("name"=>"Magmi Import Url UI",
7
+ "author"=>"Dweeves",
8
+ "version"=>"1.0.3",
9
+ "url"=>$this->pluginDocUrl("Magmi_Import_Url_UI"));
10
+ }
11
+ public function initialize($params)
12
+ {
13
+
14
+ }
15
+ }
lib/Magmi/plugins/base/general/importurl/options_panel.php ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div class="plugin_description">
2
+ This plugin provides a textarea that gives the wget or curl command line (or just url if you want) that will run magmi with
3
+ current settings.
4
+ <p>this area is refreshed each time you leave any field of this import config page.</p>
5
+ </div>
6
+ <select id="GETURL:mode">
7
+ <option value="wget">wget</option>
8
+ <option value="wget_auth">wget (authentified)</option>
9
+ <option value="curl">curl</option>
10
+ <option value="curl_auth">curl (authentified)</option>
11
+ <option value="rawurl">just url</option>
12
+ <option value="cli">magmi cli</option>
13
+ </select>
14
+
15
+ <div id="GETURL:urlcontainer">
16
+ <textarea id="GETURL:url" cols="100" rows="5"></textarea>
17
+ </div>
18
+ <div class="fieldinfo">
19
+ </div>
20
+ <script type="text/javascript">
21
+
22
+ magmi_getimporturl=function()
23
+ {
24
+ var mode=$('GETURL:mode').value;
25
+ var old_action=$('runmagmi').action;
26
+ $('runmagmi').action="./magmi_run.php";
27
+ var url=$('runmagmi').action+'?'+Form.serializeElements([$('mode'),$('runprofile')])+'&engine=magmi_productimportengine:Magmi_ProductImportEngine';
28
+ $('runmagmi').action=old_action;
29
+ var content="";
30
+ switch(mode)
31
+ {
32
+ case "wget_auth":
33
+ url=url.replace("://","://your_username:your_pass@");
34
+ case "wget":
35
+ content='wget "'+url+'" -O /dev/null';
36
+ break;
37
+ case "curl_auth":
38
+ url=url.replace("://","://your_username:your_pass@");
39
+ case "curl":
40
+ content='curl -o /dev/null "'+url+'"';
41
+ break;
42
+ case "rawurl":
43
+ content=url;
44
+ break;
45
+ case "cli":
46
+ content='magmi.cli.php -mode='+$F('mode')+' -profile='+$F('runprofile');
47
+ break;
48
+ default:
49
+ content=url;
50
+ }
51
+ $('GETURL:url').update(content);
52
+ }
53
+
54
+
55
+ $('runmagmi').getElements().each(function(it){
56
+ it.observe('blur',magmi_getimporturl);
57
+ });
58
+ $('GETURL:mode').observe('change',magmi_getimporturl);
59
+ magmi_getimporturl();
60
+
61
+
62
+
63
+ </script>
lib/Magmi/plugins/base/general/optimizer/magmi_optimizer_plugin.php ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Magmi_OptimizerPlugin extends Magmi_GeneralImportPlugin
3
+ {
4
+ public function getPluginInfo()
5
+ {
6
+ return array("name"=>"Magmi Optimizer",
7
+ "author"=>"Dweeves",
8
+ "version"=>"1.0.5",
9
+ "url"=>$this->pluginDocUrl("Magmi_Optimizer"));
10
+ }
11
+
12
+ public function beforeImport()
13
+ {
14
+ $tbls=array("eav_attribute_option_value"=>array("value","MAGMI_EAOV_OPTIMIZATION_IDX"),
15
+ "catalog_product_entity_media_gallery"=>array("value","MAGMI_CPEM_OPTIMIZATION_IDX"),
16
+ "catalog_category_entity_varchar"=>array("value","MAGMI_CCEV_OPTIMIZATION_IDX"),
17
+ "eav_attribute"=>array("attribute_code","MAGMI_EA_CODE_OPTIMIZATION_IDX"));
18
+ $this->log("Optimizing magmi","info");
19
+ foreach($tbls as $tblname=>$idxinfo)
20
+ {
21
+ try
22
+ {
23
+ $t=$this->tablename($tblname);
24
+ $this->log("Adding index {$idxinfo[1]} on $t","info");
25
+ $sql="ALTER TABLE $t ADD INDEX {$idxinfo[1]} (`{$idxinfo[0]}`)";
26
+ $this->exec_stmt($sql);
27
+ }
28
+ catch(Exception $e)
29
+ {
30
+ //ignore exception
31
+ $this->log("Already optmized!","info");
32
+ }
33
+ }
34
+ return true;
35
+ }
36
+
37
+
38
+ public function initialize($params)
39
+ {
40
+
41
+ }
42
+ }
lib/Magmi/plugins/base/general/reindex/magmi_reindexing_plugin.php ADDED
@@ -0,0 +1,117 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Magmi_ReindexingPlugin extends Magmi_GeneralImportPlugin
3
+ {
4
+ protected $_reindex;
5
+ protected $_indexlist="catalog_product_attribute,catalog_product_price,catalog_product_flat,catalog_category_flat,catalog_category_product,cataloginventory_stock,catalog_url,catalogsearch_fulltext";
6
+ protected $_mdh;
7
+
8
+ public function getPluginInfo()
9
+ {
10
+ return array("name"=>"Magmi Magento Reindexer",
11
+ "author"=>"Dweeves",
12
+ "version"=>"1.0.2",
13
+ "url"=>$this->pluginDocUrl("Magmi_Magento_Reindexer"));
14
+ }
15
+
16
+ public function afterImport()
17
+ {
18
+ $this->fixFlat();
19
+ $this->log("running indexer","info");
20
+ $this->updateIndexes();
21
+ return true;
22
+ }
23
+
24
+ public function OptimEav()
25
+ {
26
+ $tables=array("catalog_product_entity_varchar",
27
+ "catalog_product_entity_int",
28
+ "catalog_product_entity_text",
29
+ "catalog_product_entity_decimal",
30
+ "catalog_product_entity_datetime",
31
+ "catalog_product_entity_media_gallery",
32
+ "catalog_product_entity_tier_price");
33
+
34
+ $cpe=$this->tablename('catalog_product_entity');
35
+ $this->log("Optmizing EAV Tables...","info");
36
+ foreach($tables as $t)
37
+ {
38
+ $this->log("Optmizing $t....","info");
39
+ $sql="DELETE ta.* FROM ".$this->tablename($t)." as ta
40
+ LEFT JOIN $cpe as cpe on cpe.entity_id=ta.entity_id
41
+ WHERE ta.store_id=0 AND cpe.entity_id IS NULL";
42
+ $this->delete($sql);
43
+ $this->log("$t optimized","info");
44
+ }
45
+ }
46
+
47
+ public function fixFlat()
48
+ {
49
+ $this->log("Cleaning flat tables before reindex...","info");
50
+ $stmt=$this->exec_stmt("SHOW TABLES LIKE '".$this->tablename('catalog_product_flat')."%'",NULL,false);
51
+ while($row=$stmt->fetch(PDO::FETCH_NUM))
52
+ {
53
+ $tname=$row[0];
54
+ //removing records in flat tables that are no more linked to entries in catalog_product_entity table
55
+ //for some reasons, this seem to happen
56
+ $sql="DELETE cpf.* FROM $tname as cpf
57
+ LEFT JOIN ".$this->tablename('catalog_product_entity')." as cpe ON cpe.entity_id=cpf.entity_id
58
+ WHERE cpe.entity_id IS NULL";
59
+ $this->delete($sql);
60
+ }
61
+ }
62
+ public function getPluginParamNames()
63
+ {
64
+ return array("REINDEX:indexes","REINDEX:phpcli");
65
+ }
66
+
67
+ public function getIndexList()
68
+ {
69
+ return $this->_indexlist;
70
+ }
71
+
72
+ public function updateIndexes()
73
+ {
74
+ //make sure we are not in session
75
+ if(session_id()!=="")
76
+ {
77
+ session_write_close();
78
+ }
79
+ $cl=$this->getParam("REINDEX:phpcli")." shell/indexer.php";
80
+ $idxlstr=$this->getParam("REINDEX:indexes","");
81
+ $idxlist=explode(",",$idxlstr);
82
+ if(count($idxlist)==0)
83
+ {
84
+ $this->log("No indexes selected , skipping reindexing...","warning");
85
+ return true;
86
+ }
87
+ foreach($idxlist as $idx)
88
+ {
89
+ $tstart=microtime(true);
90
+ $this->log("Reindexing $idx....","info");
91
+
92
+ // Execute Reindex command, and specify that it should be ran from Magento directory
93
+ $out = $this->_mdh->exec_cmd($cl,"--reindex $idx", $this->_mdh->getMagentoDir());
94
+ $this->log($out,"info");
95
+ $tend=microtime(true);
96
+ $this->log("done in ".round($tend-$tstart,2). " secs","info");
97
+ if(Magmi_StateManager::getState()=="canceled")
98
+ {
99
+ exit();
100
+ }
101
+ flush();
102
+ }
103
+ }
104
+
105
+
106
+ public function isRunnable()
107
+ {
108
+ return array(true,"");
109
+ }
110
+
111
+ public function initialize($params)
112
+ {
113
+ $magdir=Magmi_Config::getInstance()->getMagentoDir();
114
+ $this->_mdh=MagentoDirHandlerFactory::getInstance()->getHandler($magdir);
115
+
116
+ }
117
+ }
lib/Magmi/plugins/base/general/reindex/options_panel.php ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ <div class="plugin_description">
3
+ This plugin calls magento reindex script via calling php cli. please ensure security configuration enable "shell_exec()" calls from php
4
+ </div>
5
+
6
+ <div class="formline">
7
+ <span class="label">PHP CLI command</span>
8
+ <span class="value"><input type="text" name="REINDEX:phpcli" value="<?php echo $this->getParam("REINDEX:phpcli","php")?>"></input></span>
9
+ </div>
10
+ <hr/>
11
+ <input type="hidden" name="REINDEX:indexes" id="indexes" value="<?php echo $this->getParam("REINDEX:indexes")?>"></input>
12
+ <div>
13
+ <a name="REINDEX:config"></a>
14
+ <span>Indexing:</span><a href="#REINDEX:config" onclick="fcheck(1);">All</a>&nbsp;<a href="#REINDEX:config" onclick="fcheck(0)">None</a>
15
+ <ul>
16
+ <?php
17
+ $idxarr=explode(",",$this->_plugin->getIndexList());
18
+ $indexes=explode(",",$this->getParam("REINDEX:indexes"));
19
+ foreach($idxarr as $indexname)
20
+ {
21
+ ?>
22
+ <li><input type="checkbox" name="<?php echo $indexname?>" class="_magindex" <?php if(in_array($indexname,$indexes)){?>checked=checked<?php }?>><?php echo $indexname?></li>
23
+ <?php }?>
24
+ </ul>
25
+ </div>
26
+ <script type="text/javascript">
27
+ getIndexes=function()
28
+ {
29
+ var outs=[];
30
+ $$('._magindex').each(function(it){if(it.checked){outs.push(it.name)}});
31
+ return outs.join(",");
32
+ };
33
+
34
+
35
+
36
+ fcheck=function(t)
37
+ {
38
+ $$('._magindex').each(function(it){it.checked=t});
39
+ updateIndexes();
40
+
41
+ }
42
+
43
+ updateIndexes=function()
44
+ {
45
+ $('indexes').value=getIndexes();
46
+ }
47
+
48
+ $$('._magindex').each(function(it){it.observe('click',updateIndexes)});
49
+ </script>
lib/Magmi/plugins/base/itemprocessors/columnmapper/000_columnmapper.php ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Class SampleItemProcessor
4
+ * @author dweeves
5
+ *
6
+ * This class is a sample for item processing
7
+ */
8
+ class ColumnMappingItemProcessor extends Magmi_ItemProcessor
9
+ {
10
+
11
+ protected $_dcols=array();
12
+
13
+ public function getPluginInfo()
14
+ {
15
+ return array(
16
+ "name" => "Column mapper",
17
+ "author" => "Dweeves",
18
+ "version" => "0.0.3",
19
+ "url"=>$this->pluginDocUrl("Column_mapper")
20
+ );
21
+ }
22
+
23
+ /**
24
+ * you can add/remove columns for the item passed since it is passed by reference
25
+ * @param Magmi_Engine $mmi : reference to magmi engine(convenient to perform database operations)
26
+ * @param unknown_type $item : modifiable reference to item before import
27
+ * the $item is a key/value array with column names as keys and values as read from csv file.
28
+ * @return bool :
29
+ * true if you want the item to be imported after your custom processing
30
+ * false if you want to skip item import after your processing
31
+ */
32
+
33
+ public function processColumnList(&$cols,$params=null)
34
+ {
35
+ $icols=$cols;
36
+ $ocols=array();
37
+ $scols=array();
38
+ foreach($icols as $cname)
39
+ {
40
+
41
+ if(isset($this->_dcols[$cname]))
42
+ {
43
+ $mlist=array_unique(explode(",",$this->_dcols[$cname]));
44
+ $ncol=array_shift($mlist);
45
+ $ocols[]=$ncol;
46
+ if($ncol!=$cname)
47
+ {
48
+ $this->log("Replacing Column $cname by $ncol","startup");
49
+ }
50
+ if(count($mlist)>0)
51
+ {
52
+ $scols=array_merge($scols,$mlist);
53
+ $this->log("Replicating Column $cname to ".implode(",",$mlist),"startup");
54
+ }
55
+ }
56
+ else
57
+ {
58
+ $ocols[]=$cname;
59
+ }
60
+ }
61
+ $ocols=array_unique(array_merge($ocols,$scols));
62
+ $cols=$ocols;
63
+ return true;
64
+ }
65
+
66
+ public function processItemBeforeId(&$item,$params=null)
67
+ {
68
+ foreach($this->_dcols as $oname=>$mnames)
69
+ {
70
+ if(isset($item[$oname]))
71
+ {
72
+ $mapped=explode(",",$mnames);
73
+ foreach($mapped as $mname)
74
+ {
75
+ $item[$mname]=$item[$oname];
76
+ }
77
+ if(!in_array($oname,$mapped))
78
+ {
79
+ unset($item[$oname]);
80
+ }
81
+ }
82
+ }
83
+ return true;
84
+ }
85
+
86
+ public function initialize($params)
87
+ {
88
+ foreach($params as $k=>$v)
89
+ {
90
+ if(preg_match_all("/^CMAP:(.*)$/",$k,$m) && $k!="CMAP:columnlist")
91
+ {
92
+ $colname=rawurldecode($m[1][0]);
93
+ $this->_dcols[$colname]=$params[$k];
94
+ }
95
+ }
96
+ }
97
+
98
+ public function getPluginParams($params)
99
+ {
100
+ $pp=array();
101
+ foreach($params as $k=>$v)
102
+ {
103
+ if(preg_match("/^CMAP:.*$/",$k))
104
+ {
105
+ $pp[$k]=$v;
106
+ }
107
+ }
108
+ return $pp;
109
+ }
110
+
111
+ static public function getCategory()
112
+ {
113
+ return "Input Data Preprocessing";
114
+ }
115
+ }
lib/Magmi/plugins/base/itemprocessors/columnmapper/options_panel.php ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div class="plugin_description">
2
+ This plugin enables to change column names from datasource before they are handled by magmi.
3
+ enter columns to set new name for in mapped column list field, separated by commas (,)
4
+ when leaving the field, new fields will be inserted for filling new column names.
5
+ <b>You can put several values (comma separated) in the mapped column names,doing so , the column mapper will replicate
6
+ values of column to map to all mapped columns !!!</b>
7
+ </div>
8
+ <?php $clist=$this->fixListParam($this->getParam("CMAP:columnlist"))?>
9
+ <div>
10
+ <ul class="formline">
11
+ <li class="label">Mapped columns list</li>
12
+ <li class="value"><input type="text" id="CMAP:columnlist" name="CMAP:columnlist" size="80" value="<?php echo $clist?>" onblur="cmap_mf.buildparamlist()"></input></li>
13
+ </ul>
14
+ <div id="CMAP:columnsetup">
15
+ </div>
16
+ </div>
17
+ <script type="text/javascript">
18
+ var cm_vals=<?php echo tdarray_to_js($this,'CMAP:columnlist','CMAP')?>;
19
+ var cm_linetpl='<ul class="formline"><li class="label">New name for col {fieldname}</li><li class="value"><input type="text" name="CMAP:{fieldname.enc}" value="{value}"></input></li></ul>';
20
+ cmap_mf=new magmi_multifield('CMAP:columnlist','CMAP:columnsetup',cm_linetpl,cm_vals);
21
+ cmap_mf.buildparamlist();
22
+ </script>
lib/Magmi/plugins/base/itemprocessors/configurables/magmi_configurableprocessor.php ADDED
@@ -0,0 +1,368 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Magmi_ConfigurableItemProcessor extends Magmi_ItemProcessor
3
+ {
4
+
5
+
6
+ private $_configurable_attrs=array();
7
+ private $_use_defaultopc=false;
8
+ private $_optpriceinfo=array();
9
+ private $_currentsimples=array();
10
+
11
+ public function initialize($params)
12
+ {
13
+
14
+ }
15
+
16
+ public function getPluginInfo()
17
+ {
18
+ return array(
19
+ "name" => "Configurable Item processor",
20
+ "author" => "Dweeves",
21
+ "version" => "1.3.7",
22
+ "url"=> $this->pluginDocUrl("Configurable_Item_processor")
23
+ );
24
+ }
25
+
26
+ public function getConfigurableOptsFromAsId($asid)
27
+ {
28
+ if(!isset($this->_configurable_attrs[$asid]))
29
+ {
30
+ $ea=$this->tablename("eav_attribute");
31
+ $eea=$this->tablename("eav_entity_attribute");
32
+ $eas=$this->tablename("eav_attribute_set");
33
+ $eet=$this->tablename("eav_entity_type");
34
+
35
+ $sql="SELECT ea.attribute_code FROM `$ea` as ea
36
+ JOIN $eet as eet ON eet.entity_type_id=ea.entity_type_id AND eet.entity_type_id=?
37
+ JOIN $eas as eas ON eas.entity_type_id=eet.entity_type_id AND eas.attribute_set_id=?
38
+ JOIN $eea as eea ON eea.attribute_id=ea.attribute_id";
39
+ $cond="ea.is_user_defined=1";
40
+ if($this->getMagentoVersion()!="1.3.x")
41
+ {
42
+ $cea=$this->tablename("catalog_eav_attribute");
43
+ $sql.=" JOIN $cea as cea ON cea.attribute_id=ea.attribute_id AND cea.is_global=1 AND cea.is_configurable=1";
44
+ }
45
+ else
46
+ {
47
+ $cond.=" AND ea.is_global=1 AND ea.is_configurable=1";
48
+ }
49
+ $sql.=" WHERE $cond
50
+ GROUP by ea.attribute_id";
51
+
52
+ $result=$this->selectAll($sql,array($this->getProductEntityType(),$asid));
53
+ foreach($result as $r)
54
+ {
55
+ $this->_configurable_attrs[$asid][]=$r["attribute_code"];
56
+ }
57
+ }
58
+ return $this->_configurable_attrs[$asid];
59
+ }
60
+
61
+
62
+ public function dolink($pid,$cond,$conddata=array())
63
+ {
64
+ $cpsl=$this->tablename("catalog_product_super_link");
65
+ $cpr=$this->tablename("catalog_product_relation");
66
+ $cpe=$this->tablename("catalog_product_entity");
67
+ $sql="DELETE cpsl.*,cpsr.* FROM $cpsl as cpsl
68
+ JOIN $cpr as cpsr ON cpsr.parent_id=cpsl.parent_id
69
+ WHERE cpsl.parent_id=?";
70
+ $this->delete($sql,array($pid));
71
+ //recreate associations
72
+ $sql="INSERT INTO $cpsl (`parent_id`,`product_id`) SELECT cpec.entity_id as parent_id,cpes.entity_id as product_id
73
+ FROM $cpe as cpec
74
+ JOIN $cpe as cpes ON cpes.type_id IN ('simple','virtual') AND cpes.sku $cond
75
+ WHERE cpec.entity_id=?";
76
+ $this->insert($sql,array_merge($conddata,array($pid)));
77
+ $sql="INSERT INTO $cpr (`parent_id`,`child_id`) SELECT cpec.entity_id as parent_id,cpes.entity_id as child_id
78
+ FROM $cpe as cpec
79
+ JOIN $cpe as cpes ON cpes.type_id IN ('simple','virtual') AND cpes.sku $cond
80
+ WHERE cpec.entity_id=?";
81
+ $this->insert($sql,array_merge($conddata,array($pid)));
82
+ unset($conddata);
83
+ }
84
+
85
+
86
+ public function autoLink($pid)
87
+ {
88
+ $this->dolink($pid,"LIKE CONCAT(cpec.sku,'%')");
89
+ }
90
+
91
+ public function updSimpleVisibility($pid)
92
+ {
93
+ $vis=$this->getParam("CFGR:updsimplevis",0);
94
+ if($vis!=0)
95
+ {
96
+ $attinfo=$this->getAttrInfo("visibility");
97
+ $sql="UPDATE ".$this->tablename("catalog_product_entity_int")." as cpei
98
+ JOIN ".$this->tablename("catalog_product_super_link"). " as cpsl ON cpsl.parent_id=?
99
+ JOIN ".$this->tablename("catalog_product_entity")." as cpe ON cpe.entity_id=cpsl.product_id
100
+ SET cpei.value=?
101
+ WHERE cpei.entity_id=cpe.entity_id AND attribute_id=?";
102
+ $this->update($sql,array($pid,$vis,$attinfo["attribute_id"]));
103
+ }
104
+ }
105
+
106
+ public function fixedLink($pid,$skulist)
107
+ {
108
+ $this->dolink($pid,"IN (".$this->arr2values($skulist).")",$skulist);
109
+ }
110
+
111
+ public function buildSAPTable($sapdesc)
112
+ {
113
+ $saptable=array();
114
+ $sapentries=explode(",",$sapdesc);
115
+ foreach($sapentries as $sapentry)
116
+ {
117
+ $sapinf=explode("::",$sapentry);
118
+ $sapname=$sapinf[0];
119
+ $sapdata=$sapinf[1];
120
+ $sapdarr=explode(";",$sapdata);
121
+ $saptable[$sapname]=$sapdarr;
122
+ unset($sapdarr);
123
+ }
124
+ unset($sapentries);
125
+ return $saptable;
126
+ }
127
+ public function processItemBeforeId(&$item,$params=null)
128
+ {
129
+ //if item is not configurable, nothing to do
130
+ if($item["type"]!=="configurable")
131
+ {
132
+ return true;
133
+ }
134
+ if($this->_use_defaultopc || ($item["options_container"]!="container1" && $item["options_container"]!="container2"))
135
+ {
136
+ $item["options_container"]="container2";
137
+ }
138
+ //reset option price info
139
+ $this->_optpriceinfo=array();
140
+ if(isset($item["super_attribute_pricing"]))
141
+ {
142
+ $this->_optpriceinfo=$this->buildSAPTable($item["super_attribute_pricing"]);
143
+ unset($item["super_attribute_pricing"]);
144
+ }
145
+ return true;
146
+ }
147
+
148
+ public function getMatchMode($item)
149
+ {
150
+ $matchmode="auto";
151
+ if($this->getParam('CFGR:nolink',0))
152
+ {
153
+ $matchmode="none";
154
+
155
+ }
156
+ else
157
+ {
158
+ if($this->getParam("CFGR:simplesbeforeconf")==1)
159
+ {
160
+ $matchmode="cursimples";
161
+ }
162
+ if(isset($item["simples_skus"]) && trim($item["simples_skus"])!="")
163
+ {
164
+ $matchmode="fixed";
165
+ }
166
+ }
167
+ return $matchmode;
168
+ }
169
+
170
+ public function processItemAfterId(&$item,$params=null)
171
+ {
172
+ //if item is not configurable, nothing to do
173
+ if($item["type"]!=="configurable")
174
+ {
175
+ if($this->getParam("CFGR:simplesbeforeconf")==1)
176
+ {
177
+ $this->_currentsimples[]=$item["sku"];
178
+ }
179
+ return true;
180
+ }
181
+
182
+ //check for explicit configurable attributes
183
+ if(isset($item["configurable_attributes"]))
184
+ {
185
+ $confopts=explode(",",$item["configurable_attributes"]);
186
+ for($i=0;$i<count($confopts);$i++)
187
+ {
188
+ $confopts[$i]=trim($confopts[$i]);
189
+ }
190
+ }
191
+ //if not found, try to deduce them
192
+ else
193
+ {
194
+ $asconfopts=$this->getConfigurableOptsFromAsId($params["asid"]);
195
+ //limit configurable options to ones presents & defined in item
196
+ $confopts=array();
197
+ foreach($asconfopts as $confopt)
198
+ {
199
+ if(in_array($confopt,array_keys($item)) && trim($item[$confopt])!="")
200
+ {
201
+ $confopts[]=$confopt;
202
+ }
203
+ }
204
+ unset($asconfotps);
205
+ }
206
+ //if no configurable attributes, nothing to do
207
+ if(count($confopts)==0)
208
+ {
209
+ $this->log("No configurable attributes found for configurable sku: ".$item["sku"]." cannot link simples.","warning");
210
+ return true;
211
+ }
212
+ //set product to have options & required
213
+ $tname=$this->tablename('catalog_product_entity');
214
+ $sql="UPDATE $tname SET has_options=1,required_options=1 WHERE entity_id=?";
215
+ $this->update($sql,$params["product_id"]);
216
+ //matching mode
217
+ //if associated skus
218
+
219
+ $matchmode=$this->getMatchMode($item);
220
+
221
+ //check if item has exising options
222
+ $pid=$params["product_id"];
223
+ $cpsa=$this->tablename("catalog_product_super_attribute");
224
+ $cpsal=$this->tablename("catalog_product_super_attribute_label");
225
+
226
+ //process configurable options
227
+ $ins_sa=array();
228
+ $data_sa=array();
229
+ $ins_sal=array();
230
+ $data_sal=array();
231
+ $idx=0;
232
+ foreach($confopts as $confopt)
233
+ {
234
+
235
+ $attrinfo=$this->getAttrInfo($confopt);
236
+ $attrid=$attrinfo["attribute_id"];
237
+ $psaid=NULL;
238
+
239
+ //try to get psaid for attribute
240
+ $sql="SELECT product_super_attribute_id as psaid FROM `$cpsa` WHERE product_id=? AND attribute_id=?";
241
+ $psaid=$this->selectOne($sql,array($pid,$attrid),"psaid");
242
+ //if no entry found, create one
243
+ if($psaid==NULL)
244
+ {
245
+ $sql="INSERT INTO `$cpsa` (`product_id`,`attribute_id`,`position`) VALUES (?,?,?)";
246
+ //inserting new options
247
+ $psaid=$this->insert($sql,array($pid,$attrid,$idx));
248
+ }
249
+
250
+
251
+ //for all stores defined for the item
252
+ $sids=$this->getItemStoreIds($item,0);
253
+ $data=array();
254
+ $ins=array();
255
+ foreach($sids as $sid)
256
+ {
257
+ $data[]=$psaid;
258
+ $data[]=$sid;
259
+ $data[] = $attrinfo['frontend_label'];
260
+ $ins[]="(?,?,1,?)";
261
+ }
262
+ if(count($ins)>0)
263
+ {
264
+ //insert/update attribute value for association
265
+ $sql="INSERT INTO `$cpsal` (`product_super_attribute_id`,`store_id`,`use_default`,`value`) VALUES ".implode(",",$ins).
266
+ "ON DUPLICATE KEY UPDATE value=VALUES(`value`)";
267
+ $this->insert($sql,$data);
268
+ }
269
+ //if we have price info for this attribute
270
+ if(isset($this->_optpriceinfo[$confopt]))
271
+ {
272
+ $cpsap=$this->tablename("catalog_product_super_attribute_pricing");
273
+ $wsids=$this->getItemWebsites($item);
274
+ //if admin set as store, website force to 0
275
+ if(in_array(0,$sids))
276
+ {
277
+ $wsids=array(0);
278
+ }
279
+ $data=array();
280
+ $ins=array();
281
+
282
+ foreach($this->_optpriceinfo[$confopt] as $opdef)
283
+ {
284
+ //if optpriceinfo has no is_percent, force to 0
285
+ $opinf=explode(":",$opdef);
286
+ $optids=$this->getOptionIds($attrid,0,explode("//",$opinf[0]));
287
+ foreach($optids as $optid)
288
+ {
289
+ //generate price info for each given website
290
+ foreach($wsids as $wsid)
291
+ {
292
+ if(count($opinf)<3)
293
+ {
294
+ $opinf[]=0;
295
+ }
296
+
297
+ $data[]=$psaid;
298
+ $data[]=$optid;
299
+ $data[]=$opinf[1];
300
+ $data[]=$opinf[2];
301
+ $data[]=$wsid;
302
+ $ins[]="(?,?,?,?,?)";
303
+ }
304
+ }
305
+ }
306
+
307
+ $sql="INSERT INTO $cpsap (`product_super_attribute_id`,`value_index`,`pricing_value`,`is_percent`,`website_id`) VALUES ".implode(",",$ins).
308
+ " ON DUPLICATE KEY UPDATE pricing_value=VALUES(pricing_value),is_percent=VALUES(is_percent)";
309
+ $this->insert($sql,$data);
310
+ unset($data);
311
+ }
312
+ $idx++;
313
+ }
314
+ unset($confopts);
315
+ switch($matchmode)
316
+ {
317
+ case "none":
318
+ break;
319
+ case "auto":
320
+ //destroy old associations
321
+ $this->autoLink($pid);
322
+ $this->updSimpleVisibility($pid);
323
+ break;
324
+ case "cursimples":
325
+ $this->fixedLink($pid,$this->_currentsimples);
326
+ $this->updSimpleVisibility($pid);
327
+
328
+ break;
329
+ case "fixed":
330
+ $sskus=explode(",",$item["simples_skus"]);
331
+ trimarray($sskus);
332
+ $this->fixedLink($pid,$sskus);
333
+ $this->updSimpleVisibility($pid);
334
+ unset($item["simples_skus"]);
335
+ break;
336
+ default:
337
+ break;
338
+ }
339
+ //always clear current simples
340
+ if(count($this->_currentsimples)>0)
341
+ {
342
+ unset($this->_currentsimples);
343
+ $this->_currentsimples=array();
344
+ }
345
+ return true;
346
+ }
347
+
348
+
349
+ public function processColumnList(&$cols,$params=null)
350
+ {
351
+ if(!in_array("options_container",$cols))
352
+ {
353
+ $cols=array_unique(array_merge($cols,array("options_container")));
354
+ $this->_use_defaultopc=true;
355
+ $this->log("no options_container set, defaulting to :Block after product info","startup");
356
+ }
357
+ }
358
+
359
+ public function getPluginParamNames()
360
+ {
361
+ return array("CFGR:simplesbeforeconf","CFGR:updsimplevis","CFGR:nolink");
362
+ }
363
+
364
+ static public function getCategory()
365
+ {
366
+ return "Product Type Import";
367
+ }
368
+ }
lib/Magmi/plugins/base/itemprocessors/configurables/options_panel.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div class="plugin_description">
2
+ This plugins handles configurable import
3
+ </div>
4
+
5
+ <ul class="formline">
6
+ <li class="label" style="width:360px">Perform simples/configurable link</li>
7
+ <li class="value">
8
+ <select name="CFGR:nolink">
9
+ <option value="0" <?php if ($this->getParam("CFGR:nolink",0)==0){?>selected="selected"<?php }?>>Yes</option>
10
+ <option value="1" <?php if ($this->getParam("CFGR:nolink",0)==1){?>selected="selected"<?php }?>>No</option>
11
+ </select>
12
+ </li>
13
+ </ul>
14
+ <ul class="formline">
15
+ <li class="label" style="width:360px">auto match simples skus before configurable</li>
16
+ <li class="value"><select name="CFGR:simplesbeforeconf">
17
+ <option value="0" <?php if ($this->getParam("CFGR:simplesbeforeconf")==0){?>selected="selected"<?php }?>>No</option>
18
+ <option value="1" <?php if ($this->getParam("CFGR:simplesbeforeconf")==1){?>selected="selected"<?php }?>>Yes</option></select></li>
19
+ </ul>
20
+ <ul class="formline">
21
+ <li class="label">
22
+ Force simples visibility
23
+ </li>
24
+ <li class="value">
25
+ <?php $v=$this->getParam("CFGR:updsimplevis",0)?>
26
+ <select name="CFGR:updsimplevis">
27
+ <option value="0" <?php if($v==0){?>selected="selected"<?php }?>>No</option>
28
+ <option value="1" <?php if($v==1){?>selected="selected"<?php }?>>Not Visible Individually</option>
29
+ <option value="2" <?php if($v==2){?>selected="selected"<?php }?>>Catalog</option>
30
+ <option value="3" <?php if($v==3){?>selected="selected"<?php }?>>Search</option>
31
+ <option value="4" <?php if($v==4){?>selected="selected"<?php }?>>Catalog, Search</option>
32
+ </select>
33
+ </li>
34
+ </ul>
lib/Magmi/plugins/base/itemprocessors/defaultvalues/00_default_values.php ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Class SampleItemProcessor
4
+ * @author dweeves
5
+ *
6
+ * This class is a sample for item processing
7
+ */
8
+ class DefaultValuesItemProcessor extends Magmi_ItemProcessor
9
+ {
10
+
11
+ protected $_dset=array();
12
+ protected $_dcols=array();
13
+
14
+ public function getPluginInfo()
15
+ {
16
+ return array(
17
+ "name" => "Default Values setter",
18
+ "author" => "Dweeves",
19
+ "version" => "0.0.5",
20
+ "url" => $this->pluginDocUrl("Default_Values_setter")
21
+ );
22
+ }
23
+
24
+ /**
25
+ * you can add/remove columns for the item passed since it is passed by reference
26
+ * @param Magmi_Engine $mmi : reference to magmi engine instance (convenient to perform database operations)
27
+ * @param unknown_type $item : modifiable reference to item before import
28
+ * the $item is a key/value array with column names as keys and values as read from csv file.
29
+ * @return bool :
30
+ * true if you want the item to be imported after your custom processing
31
+ * false if you want to skip item import after your processing
32
+ */
33
+
34
+
35
+ public function processItemBeforeId(&$item,$params=null)
36
+ {
37
+ foreach($this->_dcols as $col)
38
+ {
39
+ $item[$col]=$this->_dset[$col];
40
+ }
41
+ return true;
42
+ }
43
+
44
+ public function processItemAfterId(&$item,$params=null)
45
+ {
46
+ return true;
47
+ }
48
+
49
+ /*
50
+ public function processItemException(&$item,$params=null)
51
+ {
52
+
53
+ }*/
54
+
55
+ public function initialize($params)
56
+ {
57
+ foreach($params as $k=>$v)
58
+ {
59
+ if(preg_match_all("/^DEFAULT:(.*)$/",$k,$m) && $k!="DEFAULT:columnlist")
60
+ {
61
+ $this->_dset[$m[1][0]]=$params[$k];
62
+ }
63
+ }
64
+ }
65
+
66
+ public function getPluginParams($params)
67
+ {
68
+ $pp=array();
69
+ foreach($params as $k=>$v)
70
+ {
71
+ if(preg_match("/^DEFAULT:.*$/",$k))
72
+ {
73
+ $pp[$k]=$v;
74
+ }
75
+ }
76
+ return $pp;
77
+ }
78
+
79
+
80
+ public function processColumnList(&$cols,$params=null)
81
+ {
82
+ $dcols=array_diff(array_keys($this->_dset),array_intersect($cols,array_keys($this->_dset)));
83
+ foreach($dcols as $col)
84
+ {
85
+ if(!empty($this->_dset[$col]))
86
+ {
87
+ $cols[]=$col;
88
+ $this->_dcols[]=$col;
89
+ }
90
+ }
91
+ $this->log("Adding Columns ".implode(",",$dcols),"startup");
92
+
93
+ return true;
94
+ }
95
+
96
+ static public function getCategory()
97
+ {
98
+ return "Input Data Preprocessing";
99
+ }
100
+ }
lib/Magmi/plugins/base/itemprocessors/defaultvalues/options_panel.php ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php $clist=$this->fixListParam($this->getParam("DEFAULT:columnlist"))?>
2
+ <div class="plugin_description">
3
+ This plugin enables to set some default item values if not found in input source.
4
+ enter columns to set default value for in default attribute list field, separated by commas (,)
5
+ when leaving the field, new fields will be inserted for filling default values.
6
+ </div>
7
+ <div>
8
+ <ul class="formline">
9
+ <li class="label">Default attribute list</li>
10
+ <li class="value"><input type="text" id="DEFAULT:columnlist" name="DEFAULT:columnlist" size="80" value="<?php echo $clist?>" onblur="default_mf.buildparamlist()"></input></li>
11
+ </ul>
12
+ <div style="position:relative">
13
+ <div id="DEFAULT:columnsetup">
14
+ </div>
15
+ </div>
16
+ </div>
17
+ <script type="text/javascript">
18
+ var df_vals=<?php echo tdarray_to_js($this,'DEFAULT:columnlist','DEFAULT')?>;
19
+ var df_linetpl='<ul class="formline"><li class="label">Default {fieldname}</li><li class="value"><input type="text" name="DEFAULT:{fieldname.enc}" value="{value}"></input></li></ul>';
20
+ default_mf=new magmi_multifield('DEFAULT:columnlist','DEFAULT:columnsetup',df_linetpl,df_vals);
21
+ default_mf.buildparamlist();
22
+ </script>
lib/Magmi/plugins/base/itemprocessors/genericmapper/02_genericmapper.php ADDED
@@ -0,0 +1,123 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Class SampleItemProcessor
4
+ * @author dweeves
5
+ *
6
+ * This class is a sample for item processing
7
+ */
8
+ class GenericMapperProcessor extends Magmi_ItemProcessor
9
+ {
10
+ protected $_mapping;
11
+
12
+ public function getPluginInfo()
13
+ {
14
+ return array(
15
+ "name" => "Generic mapper",
16
+ "author" => "Dweeves",
17
+ "version" => "0.0.6a",
18
+ "url" => $this->pluginDocUrl("Generic_mapper")
19
+ );
20
+ }
21
+
22
+ /**
23
+ * you can add/remove columns for the item passed since it is passed by reference
24
+ * @param Magmi_Engine $mmi : reference to magmi engine instance (convenient to perform database operations)
25
+ * @param unknown_type $item : modifiable reference to item before import
26
+ * the $item is a key/value array with column names as keys and values as read from csv file.
27
+ * @return bool :
28
+ * true if you want the item to be imported after your custom processing
29
+ * false if you want to skip item import after your processing
30
+ */
31
+
32
+
33
+ public function processItemBeforeId(&$item,$params=null)
34
+ {
35
+ foreach(array_keys($item) as $k)
36
+ {
37
+ $mapped=false;
38
+ if(isset($this->_mapping["$k.csv"]))
39
+ {
40
+ $mpd=$this->_mapping["$k.csv"]["DIRECT"];
41
+ if(isset($mpd[$item[$k]]))
42
+ {
43
+ $item[$k]=$mpd[$item[$k]];
44
+ $mapped=true;
45
+ }
46
+ else
47
+ {
48
+ $mpr=$this->_mapping["$k.csv"]["RE"];
49
+ foreach($mpr as $re=>$value)
50
+ {
51
+ if(preg_match("|$re|msi",$item[$k]))
52
+ {
53
+ $item[$k]=preg_replace("|$re|",$value,$item[$k]);
54
+ $mapped=true;
55
+ break;
56
+ }
57
+ }
58
+
59
+ }
60
+ }
61
+ #if not found,try common mappings
62
+ if(!$mapped)
63
+ {
64
+ $mpd=$this->_mapping["__common__.csv"]["DIRECT"];
65
+ if(isset($mpd[$item[$k]]))
66
+ {
67
+ $item[$k]=$mpd[$item[$k]];
68
+ }
69
+ }
70
+ }
71
+ return true;
72
+ }
73
+
74
+
75
+
76
+ public function initialize($params)
77
+ {
78
+ $this->_mapping=array();
79
+
80
+ $dlist=glob(dirname(__file__)."/mappings/default/*.csv");
81
+ if($dlist==false)
82
+ {
83
+ $dlist=array();
84
+ $this->log("No default mapping found","warning");
85
+ }
86
+ $slist=glob(dirname(__file__)."/mappings/*.csv");
87
+ if($slist==false)
88
+ {
89
+ $slist=array();
90
+ $this->log("No custom mapping found","startup");
91
+ }
92
+ $flist=array_merge($dlist,$slist);
93
+ foreach($flist as $fname)
94
+ {
95
+ $idx=basename($fname);
96
+ if(!isset($this->_mapping[$idx]))
97
+ {
98
+ $this->_mapping[$idx]=array("DIRECT"=>array(),"RE"=>array());
99
+ }
100
+ $mf=fopen("$fname","r");
101
+ while (($data = fgetcsv($mf, 1000, ",")) !== FALSE)
102
+ {
103
+ if(substr($data[0],0,4)=="_RE:")
104
+ {
105
+ $target="RE";
106
+ $key=substr($data[0],4);
107
+ }
108
+ else
109
+ {
110
+ $target="DIRECT";
111
+ $key=$data[0];
112
+ }
113
+ $this->_mapping[$idx][$target][$key]=$data[1];
114
+ }
115
+ }
116
+ }
117
+
118
+ static public function getCategory()
119
+ {
120
+ return "Input Data Preprocessing";
121
+ }
122
+ }
123
+
lib/Magmi/plugins/base/itemprocessors/genericmapper/mappings/default/__common__.csv ADDED
@@ -0,0 +1,2 @@
 
 
1
+ "Yes",1
2
+ "No",0
lib/Magmi/plugins/base/itemprocessors/genericmapper/mappings/default/options_container.csv ADDED
@@ -0,0 +1,2 @@
 
 
1
+ "Product Info Column","container1"
2
+ "Block after Info Column","container2"
lib/Magmi/plugins/base/itemprocessors/genericmapper/mappings/default/page_layout.csv ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ "No layout updates",""
2
+ "CMS Page","cms_one_column"
3
+ "Product Description Page","two_columns_left"
4
+ "1 column","one_column"
5
+ "2 columns with right bar","two_columns_right"
6
+ "3 columns","three_columns"
lib/Magmi/plugins/base/itemprocessors/genericmapper/mappings/default/status.csv ADDED
@@ -0,0 +1,2 @@
 
 
1
+ "Enabled",1
2
+ "Disabled",2
lib/Magmi/plugins/base/itemprocessors/genericmapper/mappings/default/visibility.csv ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ "Not Visible Individually",1
2
+ "Catalog",2
3
+ "Search",3
4
+ "Catalog, Search",4
lib/Magmi/plugins/base/itemprocessors/genericmapper/options_panel.php ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ <div class="plugin_description">
2
+ This plugin provides value mapping for csv values before they are handled by magmi
3
+ typically visibility &amp; page_layout need mapping for magmi to process them correctly.
4
+ to change the mappings accordingly to your config,please edit the csv files located at :
5
+ <pre>[magmi_dir]/plugins/itemprocessors/genericmapper/mappings</pre>
6
+ the csv files have the following names [column_to_map].csv
7
+ </div>
lib/Magmi/plugins/base/itemprocessors/grouped/alpine_groupedprocessor.php ADDED
@@ -0,0 +1,227 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The MIT License (MIT)
4
+ * Copyright (c) 2012 Alpine Consulting, Inc
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining
7
+ * a copy of this software and associated documentation files (the
8
+ * "Software"), to deal in the Software without restriction, including
9
+ * without limitation the rights to use, copy, modify, merge, publish,
10
+ * distribute, sublicense, and/or sell copies of the Software, and to
11
+ * permit persons to whom the Software is furnished to do so, subject to
12
+ * the following conditions:
13
+ *
14
+ * The above copyright notice and this permission notice shall be included
15
+ * in all copies or substantial portions of the Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
21
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
22
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24
+ * SOFTWARE.
25
+ *
26
+ * Grouped Item processor
27
+ * Based on magmi_configurableprocessor by dweeves
28
+ *
29
+ * @author Alpine Consulting, Inc
30
+ *
31
+ * This imports grouped products and associates the simple products to
32
+ * the group
33
+ */
34
+ class Magmi_GroupedItemProcessor extends Magmi_ItemProcessor
35
+ {
36
+
37
+ public static $_VERSION = '1.1';
38
+ private $_use_defaultopc = false;
39
+ private $_optpriceinfo = array();
40
+ private $_currentgrouped = array();
41
+ private $_linktype=null;
42
+
43
+ public function getPluginUrl()
44
+ {
45
+ return $this->pluginDocUrl('Grouped_Item_processor');
46
+ }
47
+
48
+ public function getPluginVersion()
49
+ {
50
+ return self::$_VERSION;
51
+ }
52
+
53
+ public function getPluginName()
54
+ {
55
+ return 'Grouped Item processor';
56
+ }
57
+
58
+ public function getPluginAuthor()
59
+ {
60
+ return 'Alpine Consulting, Inc & Dweeves';
61
+ }
62
+
63
+ /**
64
+ * Links the simple products to the group
65
+ *
66
+ * @param type $pid
67
+ * @param type $cond
68
+ * @param type $conddata
69
+ */
70
+ public function dolink($pid, $cond, $conddata = array())
71
+ {
72
+ $cpl = $this->tablename("catalog_product_link");
73
+ $cpsl = $this->tablename("catalog_product_super_link");
74
+ $cpr = $this->tablename("catalog_product_relation");
75
+ $cpe = $this->tablename("catalog_product_entity");
76
+ $cplt = $this->tablename("catalog_product_link_type");
77
+
78
+ $sql = "DELETE cpsl.*,cpsr.* FROM $cpsl as cpsl
79
+ JOIN $cpr as cpsr ON cpsr.parent_id=cpsl.parent_id
80
+ WHERE cpsl.parent_id=?";
81
+ $this->delete($sql, array($pid));
82
+ $sql = "DELETE FROM $cpl
83
+ WHERE product_id=?";
84
+ $this->delete($sql, array($pid));
85
+ //recreate associations
86
+ $sql = "INSERT INTO $cpsl (`parent_id`,`product_id`)
87
+ SELECT cpec.entity_id as parent_id,cpes.entity_id as product_id
88
+ FROM $cpe as cpec
89
+ JOIN $cpe as cpes ON cpes.sku $cond
90
+ WHERE cpec.entity_id=?";
91
+ $this->insert($sql, array_merge($conddata, array($pid)));
92
+ if($this->_linktype==NULL)
93
+ {
94
+ $sql = "select link_type_id from $cplt where code=?";
95
+ $this->_linktype = $this->selectone($sql, 'super', 'link_type_id');
96
+ }
97
+ $sql = "INSERT INTO $cpl (`product_id`,`linked_product_id`, `link_type_id`)
98
+ SELECT cpec.entity_id as parent_id,cpes.entity_id as product_id, ?
99
+ FROM $cpe as cpec
100
+ JOIN $cpe as cpes ON cpes.sku $cond
101
+ WHERE cpec.entity_id=?";
102
+ $this->insert($sql, array_merge(array($this->_linktype),$conddata, array($pid)));
103
+ $sql = "INSERT INTO $cpr (`parent_id`,`child_id`)
104
+ SELECT cpec.entity_id as parent_id,cpes.entity_id as child_id
105
+ FROM $cpe as cpec
106
+ JOIN $cpe as cpes ON cpes.sku $cond
107
+ WHERE cpec.entity_id=?";
108
+ $this->insert($sql, array_merge($conddata, array($pid)));
109
+ unset($conddata);
110
+ }
111
+
112
+ /**
113
+ * Wrapper for dolink
114
+ *
115
+ * @see dolink($pid, $cond, $conddata = array())
116
+ * @param type $pid
117
+ */
118
+ public function autoLink($pid)
119
+ {
120
+ $this->dolink($pid, "LIKE CONCAT(cpec.sku,'%')");
121
+ }
122
+
123
+ public function updSimpleVisibility($pid)
124
+ {
125
+ $vis = $this->getParam("APIGRP:updgroupedvis", 0);
126
+ if ($vis != 0) {
127
+ $attinfo = $this->getAttrInfo("visibility");
128
+ $sql = "UPDATE " . $this->tablename("catalog_product_entity_int") . " as cpei
129
+ JOIN " . $this->tablename("catalog_product_super_link") . " as cpsl ON cpsl.parent_id=?
130
+ JOIN " . $this->tablename("catalog_product_entity") . " as cpe ON cpe.entity_id=cpsl.product_id
131
+ SET cpei.value=?
132
+ WHERE cpei.entity_id=cpe.entity_id AND attribute_id=?";
133
+ $this->update($sql, array($pid, $vis, $attinfo["attribute_id"]));
134
+ }
135
+ }
136
+
137
+ /**
138
+ * Wrapper for dolink
139
+ *
140
+ * @see dolink($pid, $cond, $conddata = array())
141
+ * @param type $pid
142
+ * @param type $skulist
143
+ */
144
+ public function fixedLink($pid, $skulist)
145
+ {
146
+ $this->dolink($pid, "IN (" . $this->arr2values($skulist) . ")", $skulist);
147
+ }
148
+
149
+ /**
150
+ * Determines which method is being used for linking the simple products
151
+ * to the group
152
+ *
153
+ * @param type $item
154
+ * @return string
155
+ */
156
+ public function getMatchMode($item)
157
+ {
158
+ $matchmode = "auto";
159
+ if ($this->getParam('APIGRP:nolink', 0)) {
160
+ $matchmode = "none";
161
+ } else {
162
+ if ($this->getParam("APIGRP:groupedbeforegrp") == 1) {
163
+ $matchmode = "cursimples";
164
+ }
165
+ if (isset($item["grouped_skus"]) && trim($item["grouped_skus"]) != "") {
166
+ $matchmode = "fixed";
167
+ }
168
+ }
169
+ return $matchmode;
170
+ }
171
+
172
+ public function processItemAfterId(&$item, $params = null) {
173
+ //if item is not grouped, nothing to do
174
+ if ($item["type"] !== "grouped") {
175
+ if ($this->getParam("APIGRP:groupedbeforegrp") == 1) {
176
+ $this->_currentgrouped[] = $item["sku"];
177
+ }
178
+ return true;
179
+ }
180
+
181
+ $pid = $params["product_id"];
182
+ $matchmode = $this->getMatchMode($item);
183
+ switch ($matchmode)
184
+ {
185
+ case "none":
186
+ break;
187
+ case "auto":
188
+ //destroy old associations
189
+ $this->autoLink($pid);
190
+ $this->updSimpleVisibility($pid);
191
+ break;
192
+ case "cursimples":
193
+ $this->fixedLink($pid, $this->_currentgrouped);
194
+ $this->updSimpleVisibility($pid);
195
+ break;
196
+ case "fixed":
197
+ $sskus = explode(",", $item["grouped_skus"]);
198
+ $this->trimarray($sskus);
199
+ $this->fixedLink($pid, $sskus);
200
+ $this->updSimpleVisibility($pid);
201
+ unset($item["simples_skus"]);
202
+ break;
203
+ default:
204
+ break;
205
+ }
206
+ //always clear current simples
207
+ if (count($this->_currentgrouped) > 0) {
208
+ unset($this->_currentgrouped);
209
+ $this->_currentgrouped = array();
210
+ }
211
+ return true;
212
+ }
213
+
214
+ public function getPluginParamNames() {
215
+ return array("APIGRP:groupedbeforegrp", "APIGRP:updgroupedvis", "APIGRP:nolink");
216
+ }
217
+
218
+ static public function getCategory() {
219
+ return "Product Type Import";
220
+ }
221
+
222
+ private function trimarray(&$arr) {
223
+ for ($i=0;$i<count($arr);$i++) {
224
+ $arr[$i]=trim($arr[$i]);
225
+ }
226
+ }
227
+ }
lib/Magmi/plugins/base/itemprocessors/grouped/options_panel.php ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The MIT License (MIT)
4
+ * Copyright (c) 2012 Alpine Consulting, Inc
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining
7
+ * a copy of this software and associated documentation files (the
8
+ * "Software"), to deal in the Software without restriction, including
9
+ * without limitation the rights to use, copy, modify, merge, publish,
10
+ * distribute, sublicense, and/or sell copies of the Software, and to
11
+ * permit persons to whom the Software is furnished to do so, subject to
12
+ * the following conditions:
13
+ *
14
+ * The above copyright notice and this permission notice shall be included
15
+ * in all copies or substantial portions of the Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
21
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
22
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24
+ * SOFTWARE.
25
+ *
26
+ */?>
27
+ <div class="plugin_description">
28
+ This plugins handles grouped item import
29
+ </div>
30
+
31
+ <ul class="formline">
32
+ <li class="label" style="width:360px">Perform simples/group link</li>
33
+ <li class="value">
34
+ <select name="APIGRP:nolink">
35
+ <option value="0" <?php if ($this->getParam("APIGRP:nolink",0)==0){?>selected="selected"<?php }?>>Yes</option>
36
+ <option value="1" <?php if ($this->getParam("APIGRP:nolink",0)==1){?>selected="selected"<?php }?>>No</option>
37
+ </select>
38
+ </li>
39
+ </ul>
40
+ <ul class="formline">
41
+ <li class="label" style="width:360px">auto match simples skus before grouped</li>
42
+ <li class="value"><select name="APIGRP:groupedbeforegrp">
43
+ <option value="0" <?php if ($this->getParam("APIGRP:groupedbeforegrp")==0){?>selected="selected"<?php }?>>No</option>
44
+ <option value="1" <?php if ($this->getParam("APIGRP:groupedbeforegrp")==1){?>selected="selected"<?php }?>>Yes</option></select></li>
45
+ </ul>
46
+ <ul class="formline">
47
+ <li class="label">
48
+ Force simples visibility
49
+ </li>
50
+ <li class="value">
51
+ <?php $v=$this->getParam("APIGRP:updgroupedvis",0)?>
52
+ <select name="APIGRP:updgroupedvis">
53
+ <option value="0" <?php if($v==0){?>selected="selected"<?php }?>>No</option>
54
+ <option value="1" <?php if($v==1){?>selected="selected"<?php }?>>Not Visible Individually</option>
55
+ <option value="2" <?php if($v==2){?>selected="selected"<?php }?>>Catalog</option>
56
+ <option value="3" <?php if($v==3){?>selected="selected"<?php }?>>Search</option>
57
+ <option value="4" <?php if($v==4){?>selected="selected"<?php }?>>Catalog, Search</option>
58
+ </select>
59
+ </li>
60
+ </ul>
lib/Magmi/plugins/base/itemprocessors/importlimiter/01_importlimiter.php ADDED
@@ -0,0 +1,172 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class ImportLimiter extends Magmi_ItemProcessor
3
+ {
4
+ protected $_recranges;
5
+ protected $_rmax=-1;
6
+ protected $_filters;
7
+ protected $_col_filter=NULL;
8
+
9
+ public function getPluginInfo()
10
+ {
11
+ return array("name"=>"Magmi Import Limiter",
12
+ "author"=>"Dweeves",
13
+ "version"=>"0.0.6",
14
+ "url"=>$this->pluginDocUrl("Magmi_Import_Limiter"));
15
+ }
16
+
17
+
18
+ public function filtermatch($item,$fltdef)
19
+ {
20
+ $negate=0;
21
+ $field=$fltdef[0];
22
+ $match=false;
23
+ if($field[0]=="!")
24
+ {
25
+ $field=substr($field,1);
26
+ $negate=1;
27
+ }
28
+ $re=$fltdef[1];
29
+ if(in_array($field,array_keys($item)))
30
+ {
31
+ $v=$item[$field];
32
+ $match=preg_match("|$re|",$v);
33
+ if($negate)
34
+ {
35
+ $match=!$match;
36
+ }
37
+ if($match)
38
+ {
39
+ $this->log("skipping sku {$item['sku']} => Filter '$field::$re'","info");
40
+ }
41
+ }
42
+ return $match;
43
+ }
44
+ public function processItemBeforeId(&$item,$params=null)
45
+ {
46
+ $crow=$this->getCurrentRow();
47
+ $ok=(count($this->_recranges)==0);
48
+
49
+ if(!$ok)
50
+ {
51
+ if($this->_rmax>-1 && $crow==$this->_rmax)
52
+ {
53
+ $this->setLastItem($item);
54
+ }
55
+ foreach($this->_recranges as $rr)
56
+ {
57
+ $ok=($crow>=$rr[0] && ($crow<=$rr[1] || $rr[1]==-1));
58
+ if($ok)
59
+ {
60
+ break;
61
+ }
62
+ }
63
+ }
64
+
65
+
66
+ if($ok)
67
+ {
68
+ foreach($this->_filters as $fltdef)
69
+ {
70
+ //negative filters
71
+ $ok=$ok && (!$this->filtermatch($item,$fltdef));
72
+ if(!$ok)
73
+ {
74
+ break;
75
+ }
76
+ }
77
+ }
78
+ else
79
+ {
80
+ $this->log("Filtered row $crow not in range ".$this->getParam("LIMITER:ranges",""));
81
+ }
82
+
83
+ return $ok;
84
+ }
85
+
86
+ public function parseFilters($fltstr)
87
+ {
88
+ $this->_filters=array();
89
+ if($fltstr=="")
90
+ {
91
+ return;
92
+ }
93
+ $fltlist=explode(";;",$fltstr);
94
+ foreach($fltlist as $fltdef)
95
+ {
96
+ $fltinf=explode("::",$fltdef);
97
+ $this->_filters[]=$fltinf;
98
+ }
99
+
100
+ }
101
+
102
+ public function parseRanges($rangestr)
103
+ {
104
+ $this->_recranges=array();
105
+ if($rangestr=="")
106
+ {
107
+ return;
108
+ }
109
+ $rangelist=explode(",",$rangestr);
110
+ foreach($rangelist as $rdef)
111
+ {
112
+ $rlist=explode("-",$rdef);
113
+ if($rlist[0]=="")
114
+ {
115
+ $rlist[0]=-1;
116
+ }
117
+ else
118
+ {
119
+ $rmin=$rlist[0];
120
+ }
121
+ if(count($rlist)>1)
122
+ {
123
+ if($rlist[1]=="")
124
+ {
125
+ $rlist[1]=-1;
126
+ }
127
+ else
128
+ {
129
+ $rmax=$rlist[1];
130
+ if($rmax>$this->_rmax && $this->_rmax!=-1)
131
+ {
132
+ $this->_rmax=$rmax;
133
+ }
134
+ }
135
+ }
136
+ else
137
+ {
138
+ $rmax=$rmin;
139
+ }
140
+ $this->_recranges[]=array($rmin,$rmax);
141
+ }
142
+ }
143
+
144
+ public function processColumnList(&$cols,$params=null)
145
+ {
146
+ if(count($this->_col_filter)>0)
147
+ {
148
+ $this->log("limiting columns to :".implode(",",$this->_col_filter),"startup");
149
+ $cols=$this->_col_filter;
150
+ }
151
+
152
+ }
153
+
154
+ public function initialize($params)
155
+ {
156
+ $this->parseRanges($this->getParam("LIMITER:ranges",""));
157
+ $this->parseFilters($this->getParam("LIMITER:filters",""));
158
+ $this->_col_filter=explode(",",$this->getParam("LIMITER:col_filter"));
159
+ return true;
160
+
161
+ }
162
+
163
+ public function getPluginParamNames()
164
+ {
165
+ return array('LIMITER:ranges','LIMITER:filters','LIMITER:col_filter');
166
+ }
167
+
168
+ static public function getCategory()
169
+ {
170
+ return "Input Data Preprocessing";
171
+ }
172
+ }
lib/Magmi/plugins/base/itemprocessors/importlimiter/options_panel.php ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div class="plugin_description">
2
+ This plugin is made to limit magmi import to selected record ranges or matching values.
3
+ ranges are ranges of rows to be imported
4
+ filters are regexps or strings that if matched will exclude record from import
5
+ </div>
6
+
7
+ <div class="ifield">
8
+ <span class="">Column filter:</span><input type="text" name="LIMITER:col_filter" size="80" value="<?php echo $this->getParam("LIMITER:col_filter")?>"></input>
9
+ <div class="fieldhelp"></div>
10
+ <div class="fieldinfo">
11
+ This field defines what columns should be imported
12
+ <div class="fieldsyntax" style="display:none">
13
+ <pre>
14
+ You should put column names, comma separated ie : sku,qty
15
+ </pre>
16
+ </div>
17
+ </div>
18
+ </div>
19
+
20
+ <div class="ifield">
21
+ <span class="">Limiter ranges:</span><input type="text" name="LIMITER:ranges" size="80" value="<?php echo $this->getParam("LIMITER:ranges")?>"></input>
22
+ <div class="fieldhelp"></div>
23
+ <div class="fieldinfo">
24
+ This field defines what lines should be imported
25
+ <div class="fieldsyntax" style="display:none">
26
+ <pre>
27
+ 1-100 : for the first 100 records of csv
28
+ 100- : for all records after 100 (including 100th)
29
+ 1-10,40-50,67,78,89 : for records 1 to 10,40 to 50 , 67 , 78 &amp; 89
30
+ </pre>
31
+ </div>
32
+ </div>
33
+ </div>
34
+ <div class="ifield">
35
+
36
+ <span class="">Limiter filters:</span><input type="text" name="LIMITER:filters" size="80" value="<?php echo $this->getParam("LIMITER:filters")?>"></input>
37
+ <div class="fieldhelp"></div>
38
+ <div class="fieldinfo">
39
+ This field defines what content should not be imported with a regexp like syntax.
40
+ <div class="fieldsyntax" style="display:none">
41
+ <pre>
42
+ sku::00.* : exclude all skus that begin with 00
43
+ !name::.*blue.* : exclude all items with name not blue (see the ! before the "name" field to negate the filter)
44
+ sku:00.*;;!name::.*blue.* : exclude all items with skus that begin with 00 which name does not contain blue
45
+ </pre>
46
+ </div>
47
+ </div>
48
+ </div>
lib/Magmi/plugins/base/itemprocessors/productdeleter/options_panel.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <div class="plugin_description">
2
+ This plugins should be used to delete existing products
3
+ </div>
4
+ <ul class="formline">
5
+ <li>
6
+ <input type="checkbox" name="PDEL:delsimples" <?php if($this->getParam("PDEL:delsimples",false)==true){?> checked="checked" <?php }?>>Delete children products
7
+ </li>
8
+
9
+ </ul>
lib/Magmi/plugins/base/itemprocessors/productdeleter/productdeleter.php ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class ProductDeleter extends Magmi_ItemProcessor
3
+ {
4
+ public function getPluginInfo()
5
+ {
6
+ return array(
7
+ "name" => "Product Deleter",
8
+ "author" => "Dweeves",
9
+ "version" => "0.0.2",
10
+ "url" => $this->pluginDocUrl("Product_Deleter")
11
+ );
12
+ }
13
+
14
+ public function getPluginParamNames()
15
+ {
16
+ return array("PDEL:delsimples");
17
+ }
18
+
19
+ public function removeFromFlat($pid)
20
+ {
21
+ $this->log("Cleaning flat tables before reindex...","info");
22
+ $stmt=$this->exec_stmt("SHOW TABLES LIKE '".$this->tablename('catalog_product_flat')."%'",NULL,false);
23
+ while($row=$stmt->fetch(PDO::FETCH_NUM))
24
+ {
25
+ $tname=$row[0];
26
+ //removing records in flat tables that are no more linked to entries in catalog_product_entity table
27
+ //for some reasons, this seem to happen
28
+ $sql="DELETE cpf.* FROM $tname as cpf
29
+ WHERE cpf.entity_id=?";
30
+ $this->delete($sql,$pid);
31
+ }
32
+ }
33
+ public function processItemAfterId(&$item,$params=null)
34
+ {
35
+
36
+ //get item ids, since we are before id
37
+ $pid=$params["product_id"];
38
+ if(isset($item["magmi:delete"]) && $item["magmi:delete"]==1)
39
+ {
40
+ $this->log("DELETING SKU '".$item["sku"]."' =>".$pid,"info");
41
+ //delete simple products if flag set
42
+ if($this->getParam("PDEL:delsimples",false)==true)
43
+ {
44
+ $childrensel="SELECT entity_id FROM ".$this->tablename("catalog_product_entity")." as cpe
45
+ JOIN ".$this->tablename("catalog_product_super_link")." as cpl ON cpl.parent_id=? AND cpe.entity_id=cpl.product_id";
46
+ $sql="DELETE cpe.* FROM ".$this->tablename("catalog_product_entity")." cpe WHERE cpe.entity_id IN (SELECT s1.entity_id FROM ($childrensel) as s1)";
47
+
48
+ $this->delete($sql,$pid);
49
+ }
50
+ //delete from indexes table if store is set
51
+ $this->removeFromFlat($pid);
52
+
53
+ //delete product (this cascades for all eav & relations)
54
+ $sql="DELETE FROM ".$this->tablename("catalog_product_entity")." WHERE entity_id=?";
55
+ $this->delete($sql,$pid);
56
+ $this->log($sql,"info");
57
+ $item=array();
58
+ }
59
+ }
60
+ }
lib/Magmi/plugins/base/itemprocessors/related/related_products.php ADDED
@@ -0,0 +1,301 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class RelatedProducts extends Magmi_ItemProcessor
3
+ {
4
+
5
+ public function getPluginInfo()
6
+ {
7
+ return array(
8
+ "name" => "Product relater",
9
+ "author" => "Dweeves,jwtechniek",
10
+ "version" => "1.0.3",
11
+ "url"=>$this->pluginDocUrl("Product_relater")
12
+ );
13
+ }
14
+
15
+
16
+ public function checkRelated(&$rinfo)
17
+ {
18
+ if(count($rinfo["direct"])>0)
19
+ {
20
+ $sql="SELECT testid.sku,cpe.sku as esku FROM ".$this->arr2select($rinfo["direct"],"sku")." AS testid
21
+ LEFT JOIN ".$this->tablename("catalog_product_entity")." as cpe ON cpe.sku=testid.sku
22
+ WHERE testid.sku NOT LIKE '%re::%'
23
+ HAVING esku IS NULL";
24
+ $result=$this->selectAll($sql,$rinfo["direct"]);
25
+
26
+ $to_delete=array();
27
+ foreach($result as $row)
28
+ {
29
+ $this->log("Unknown related sku ".$row["sku"],"warning");
30
+ $to_delete[]=$row["sku"];
31
+ }
32
+ $rinfo["direct"]=array_diff($rinfo["direct"],$to_delete);
33
+ }
34
+ return count($rinfo["direct"])+count($rinfo["re"]);
35
+
36
+ }
37
+
38
+ public function processItemAfterId(&$item,$params=null)
39
+ {
40
+ $related=isset($item["re_skus"])?$item["re_skus"]:null;
41
+ $xrelated=isset($item["xre_skus"])?$item["xre_skus"]:null;
42
+ $srelated=isset($item["*re_skus"])?$item["*re_skus"]:null;
43
+ $pid=$params["product_id"];
44
+ $new=$params["new"];
45
+
46
+ if(isset($related) && trim($related)!="")
47
+ {
48
+ $rinf=$this->getRelInfos($related);
49
+ if($new==false)
50
+ {
51
+ $this->deleteRelatedItems($item,$rinf["del"]);
52
+ }
53
+ $this->setRelatedItems($item,$rinf["add"]);
54
+ }
55
+ if(isset($xrelated) && trim($xrelated)!="")
56
+ {
57
+ $rinf=$this->getRelInfos($xrelated);
58
+ if($new==false)
59
+ {
60
+ $this->deleteXRelatedItems($item,$rinf["del"]);
61
+ }
62
+ $this->setXRelatedItems($item,$rinf["add"]);
63
+ }
64
+
65
+ if(isset($srelated) && trim($srelated)!="")
66
+ {
67
+ $rinf=$this->getRelInfos($srelated);
68
+ if($new==false)
69
+ {
70
+ $this->deleteXRelatedItems($item,$rinf["del"],true);
71
+ }
72
+ $this->setXRelatedItems($item,$rinf["add"],true);
73
+ }
74
+ }
75
+
76
+ public function deleteRelatedItems($item,$inf)
77
+ {
78
+ $joininfo=$this->buildJoinCond($item,$inf,"cpe2.sku");
79
+ $j2=$joininfo["join"]["cpe2.sku"];
80
+ if($j2!="")
81
+ {
82
+ $sql="DELETE cplai.*,cpl.*
83
+ FROM ".$this->tablename("catalog_product_entity")." as cpe
84
+ JOIN ".$this->tablename("catalog_product_link_type")." as cplt ON cplt.code='relation'
85
+ JOIN ".$this->tablename("catalog_product_link")." as cpl ON cpl.product_id=cpe.entity_id AND cpl.link_type_id=cplt.link_type_id
86
+ JOIN ".$this->tablename("catalog_product_link_attribute_int")." as cplai ON cplai.link_id=cpl.link_id
87
+ JOIN ".$this->tablename("catalog_product_entity")." as cpe2 ON cpe2.sku!=cpe.sku AND $j2
88
+
89
+ WHERE cpe.sku=?";
90
+ $this->delete($sql,array_merge($joininfo["data"]["cpe2.sku"],array($item["sku"])));
91
+ }
92
+ }
93
+
94
+ public function deleteXRelatedItems($item,$inf,$fullcross=false)
95
+ {
96
+ $joininfo=$this->buildJoinCond($item,$inf,"cpe2.sku,cpe.sku");
97
+ $j2=$joininfo["join"]["cpe2.sku"];
98
+ $j=$joininfo["join"]["cpe.sku"];
99
+ if($j2!="")
100
+ {
101
+
102
+ $sql="DELETE cplai.*,cpl.*
103
+ FROM ".$this->tablename("catalog_product_entity")." as cpe
104
+ JOIN ".$this->tablename("catalog_product_link")." as cpl ON cpl.product_id=cpe.entity_id
105
+ JOIN ".$this->tablename("catalog_product_link_attribute_int")." as cplai ON cplai.link_id=cpl.link_id
106
+ JOIN ".$this->tablename("catalog_product_entity")." as cpe2 ON cpe2.sku!=cpe.sku AND (cpe2.sku=? OR $j2)
107
+ JOIN ".$this->tablename("catalog_product_link_type")." as cplt ON cplt.code='relation'
108
+ WHERE cpe.sku=? OR $j";
109
+ $this->delete($sql,array_merge(array($item["sku"]),$joininfo["data"]["cpe2.sku"],array($item["sku"]),$joininfo["data"]["cpe.sku"]));
110
+ }
111
+ }
112
+
113
+ public function getDirection(&$inf)
114
+ {
115
+ $dir="+";
116
+ if($inf[0]=="-" || $inf[0]=="+")
117
+ {
118
+ $dir=$inf[0];
119
+ $inf=substr($inf,1);
120
+ }
121
+ return $dir;
122
+
123
+ }
124
+ public function getRelInfos($relationdef)
125
+ {
126
+ $relinfos=explode(",",$relationdef);
127
+ $relskusadd=array("direct"=>array(),"re"=>array());
128
+ $relskusdel=array("direct"=>array(),"re"=>array());
129
+ foreach($relinfos as $relinfo)
130
+ {
131
+ $rinf=explode("::",$relinfo);
132
+ if(count($rinf)==1)
133
+ {
134
+ if($this->getDirection($rinf[0])=="+")
135
+ {
136
+ $relskusadd["direct"][]=$rinf[0];
137
+ }
138
+ else
139
+ {
140
+ $relskusdel["direct"][]=$rinf[0];
141
+ }
142
+ }
143
+
144
+ if(count($rinf)==2)
145
+ {
146
+ $dir=$this->getDirection($rinf[0]);
147
+ if($dir=="+")
148
+ {
149
+ switch($rinf[0])
150
+ {
151
+ case "re":
152
+ $relskusadd["re"][]=$rinf[1];
153
+ break;
154
+ }
155
+ }
156
+ else
157
+ {
158
+ switch($rinf[0])
159
+ {
160
+ case "re":
161
+ $relskusdel["re"][]=$rinf[1];
162
+ break;
163
+ }
164
+ }
165
+ }
166
+ }
167
+
168
+ return array("add"=>$relskusadd,"del"=>$relskusdel);
169
+ }
170
+
171
+ public function buildJoinCond($item,$rinfo,$keys)
172
+ {
173
+ $joinconds=array();
174
+ $joins=array();
175
+ $klist=explode(",",$keys);
176
+ foreach($klist as $key)
177
+ {
178
+ $data[$key]=array();
179
+ $joinconds[$key]=array();
180
+ if(count($rinfo["direct"])>0)
181
+ {
182
+ $joinconds[$key][]="$key IN (".$this->arr2values($rinfo["direct"]).")";
183
+ $data[$key]=array_merge($data[$key],$rinfo["direct"]);
184
+ }
185
+ if(count($rinfo["re"])>0)
186
+ {
187
+ foreach($rinfo["re"] as $rinf)
188
+ {
189
+ $joinconds[$key][]="$key REGEXP ?";
190
+ $data[$key][]=$rinf;
191
+ }
192
+ }
193
+ $joins[$key] = implode(" OR ",$joinconds[$key]);
194
+ if($joins[$key]!="")
195
+ {
196
+ $joins[$key]="({$joins[$key]})";
197
+ }
198
+
199
+ }
200
+ return array("join"=>$joins,"data"=>$data);
201
+ }
202
+
203
+
204
+ public function setRelatedItems($item,$rinfo)
205
+ {
206
+ if($this->checkRelated($rinfo)>0)
207
+
208
+ {
209
+ $joininfo=$this->buildJoinCond($item,$rinfo,"cpe2.sku");
210
+ $jinf=$joininfo["join"]["cpe2.sku"];
211
+ if($jinf!="")
212
+ {
213
+ //insert into link table
214
+ $bsql="SELECT cplt.link_type_id,cpe.entity_id as product_id,cpe2.entity_id as linked_product_id
215
+ FROM ".$this->tablename("catalog_product_entity")." as cpe
216
+ JOIN ".$this->tablename("catalog_product_entity")." as cpe2 ON cpe2.sku!=cpe.sku AND $jinf
217
+ JOIN ".$this->tablename("catalog_product_link_type")." as cplt ON cplt.code='relation'
218
+ WHERE cpe.sku=?";
219
+ $sql="INSERT IGNORE INTO ".$this->tablename("catalog_product_link")." (link_type_id,product_id,linked_product_id) $bsql";
220
+ $data=array_merge($joininfo["data"]["cpe2.sku"],array($item["sku"]));
221
+ $this->insert($sql,$data);
222
+ $this->updateLinkAttributeTable($item["sku"],$joininfo);
223
+ }
224
+ }
225
+ }
226
+
227
+ public function setXRelatedItems($item,$rinfo,$fullrel=false)
228
+ {
229
+ if($this->checkRelated($rinfo)>0)
230
+ {
231
+ $joininfo=$this->buildJoinCond($item,$rinfo,"cpe.sku,cpe2.sku");
232
+ $j2=$joininfo["join"]["cpe2.sku"];
233
+ $j=$joininfo["join"]["cpe.sku"];
234
+ if($j2!="")
235
+ {
236
+ //insert into link table
237
+ $bsql="SELECT cplt.link_type_id,cpe.entity_id as product_id,cpe2.entity_id as linked_product_id
238
+ FROM ".$this->tablename("catalog_product_entity")." as cpe
239
+ JOIN ".$this->tablename("catalog_product_entity")." as cpe2 ON cpe2.entity_id!=cpe.entity_id AND (cpe2.sku=? OR $j2)
240
+ JOIN ".$this->tablename("catalog_product_link_type")." as cplt ON cplt.code='relation'
241
+ WHERE cpe.sku=? OR $j ";
242
+ if(!$fullrel)
243
+ {
244
+ $bsql.=" AND NOT($j AND $j2)";
245
+ }
246
+ $sql="INSERT IGNORE INTO ".$this->tablename("catalog_product_link")." (link_type_id,product_id,linked_product_id) $bsql";
247
+ $data=array_merge(array($item["sku"]),$joininfo["data"]["cpe2.sku"],array($item["sku"]),$joininfo["data"]["cpe.sku"]);
248
+ if(!$fullrel)
249
+ {
250
+ $data=array_merge($data,$joininfo["data"]["cpe.sku"],$joininfo["data"]["cpe.sku"]);
251
+ }
252
+ $this->insert($sql,$data);
253
+ $this->updateLinkAttributeTable($item["sku"],$joininfo);
254
+ }
255
+ }
256
+ }
257
+
258
+ public function updateLinkAttributeTable($sku,$joininfo)
259
+ {
260
+ //insert into attribute link attribute int table,reusing the same relations
261
+ $ji=$joininfo["join"];
262
+ $data=array($sku);
263
+ $addcond="";
264
+ if(isset($ji["cpe.sku"]))
265
+ {
266
+ $addcond="OR ".$joininfo["join"]["cpe.sku"];
267
+ $data=array_merge($data,$joininfo["data"]["cpe.sku"]);
268
+ }
269
+ //this enable to mass add
270
+ $bsql="SELECT cpl.link_id,cpla.product_link_attribute_id,0 as value
271
+ FROM ".$this->tablename("catalog_product_entity")." AS cpe
272
+ JOIN ".$this->tablename("catalog_product_entity")." AS cpe2 ON cpe2.entity_id!=cpe.entity_id
273
+ JOIN ".$this->tablename("catalog_product_link_type")." AS cplt ON cplt.code='relation'
274
+ JOIN ".$this->tablename("catalog_product_link_attribute")." AS cpla ON cpla.product_link_attribute_code='position' AND cpla.link_type_id=cplt.link_type_id
275
+ JOIN ".$this->tablename("catalog_product_link") ." AS cpl ON cpl.link_type_id=cplt.link_type_id AND cpl.product_id=cpe.entity_id AND cpl.linked_product_id=cpe2.entity_id
276
+ WHERE cpe.sku=? $addcond";
277
+
278
+ $sql="INSERT IGNORE INTO ".$this->tablename("catalog_product_link_attribute_int")." (link_id,product_link_attribute_id,value) $bsql";
279
+ $this->insert($sql,$data);
280
+ }
281
+
282
+ public function afterImport()
283
+ {
284
+ //remove maybe inserted doubles
285
+ $cplai=$this->tablename("catalog_product_link_attribute_int");
286
+ $sql="DELETE cplaix FROM $cplai as cplaix
287
+ WHERE cplaix.value_id IN
288
+ (SELECT s1.value_id FROM
289
+ (SELECT cplai.link_id,cplai.value_id,MAX(cplai.value_id) as latest
290
+ FROM $cplai as cplai
291
+ GROUP BY cplai.link_id
292
+ HAVING cplai.value_id!=latest)
293
+ as s1)";
294
+ $this->delete($sql);
295
+ }
296
+
297
+ static public function getCategory()
298
+ {
299
+ return "Related Products";
300
+ }
301
+ }
lib/Magmi/plugins/base/itemprocessors/skufinder/001_skufinder.php ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class SkuFinderItemProcessor extends Magmi_ItemProcessor
3
+ {
4
+ private $_compchecked=FALSE;
5
+
6
+ public function getPluginInfo()
7
+ {
8
+ return array(
9
+ "name" => "SKU Finder",
10
+ "author" => "Dweeves",
11
+ "version" => "0.0.1",
12
+ "url"=>$this->pluginDocUrl("SKU_Finder")
13
+ );
14
+ }
15
+
16
+ public function processItemBeforeId(&$item,$params=null)
17
+ {
18
+
19
+ $matchfield=trim($this->getParam("SKUF:matchfield"));
20
+ //protection from tricky testers ;)
21
+ if($matchfield=="sku")
22
+ {
23
+ return true;
24
+ }
25
+ $attinfo=$this->getAttrInfo($matchfield);
26
+ if($this->_compchecked==FALSE)
27
+ {
28
+ //Checking attribute compatibility with sku matching
29
+ if($attinfo==NULL)
30
+ {
31
+ $this->log("$matchfield is not a valid attribute","error");
32
+ $item["__MAGMI_LAST__"]=1;
33
+ return false;
34
+ }
35
+ if($attinfo["is_unique"]==0 || $attinfo["is_global"]==0)
36
+ {
37
+ $this->log("sku matching attribute $matchfield must be unique & global scope");
38
+ $item["__MAGMI_LAST__"]=1;
39
+ return false;
40
+ }
41
+ if($attinfo["backend_type"]=="static")
42
+ {
43
+ $this->log("$matchfield is ".$attinfo["backend_type"].", it cannot be used as sku matching field.","error");
44
+ $item["__MAGMI_LAST__"]=1;
45
+ return false;
46
+ }
47
+ if($attinfo["frontend_input"]=="select" || $attinfo["frontend_input"]=="multiselect" )
48
+ {
49
+ $this->log("$matchfield is ".$attinfo["frontend_input"].", it cannot be used as sku matching field.","error");
50
+ $item["__MAGMI_LAST__"]=1;
51
+ return false;
52
+ }
53
+ $this->_compchecked=true;
54
+ }
55
+
56
+ //no item data for selected matching field, skipping
57
+ if(!isset($item[$matchfield]) && trim($item["matchfield"])!=='')
58
+ {
59
+ $this->log("No value for $matchfield in datasource","error");
60
+ return false;
61
+ }
62
+ //now find sku
63
+ $sql="SELECT sku FROM ".$this->tablename("catalog_product_entity")." as cpe JOIN
64
+ catalog_product_entity_".$attinfo["backend_type"]. "ON value=? AND attribute_id=?";
65
+ $stmt=$this->select($sql,array($item[$matchfield],$attinfo["attribute_id"]));
66
+ $n=0;
67
+ while($result=$stmt->fetch())
68
+ {
69
+ //if more than one result, cannot match single sku
70
+ if($n>1)
71
+ {
72
+ $this->log("Several skus match $matchfield value : ".$item["matchfield"],"error");
73
+ return false;
74
+ }
75
+ else
76
+ {
77
+ $item["sku"]=$result["sku"];
78
+ }
79
+ $n++;
80
+ }
81
+ //if no item found, warning & skip
82
+ if($n==0)
83
+ {
84
+ $this->log("No sku found matching $matchfield value : ".$item["matchfield"],"warning");
85
+ return false;
86
+ }
87
+ //found a single sku ! item sku is in place, continue with processor chain
88
+ return true;
89
+ }
90
+
91
+ static public function getCategory()
92
+ {
93
+ return "Input Data Preprocessing";
94
+ }
95
+ }
lib/Magmi/plugins/base/itemprocessors/skufinder/options_panel.php ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div class="plugin_description">
2
+ This plugins can be used in <b>update</b> mode to find sku from custom column in datasource.
3
+ this column <b>MUST</b> be an attribute code
4
+ </div>
5
+ <ul class="formline">
6
+ <li class="label">
7
+ <span>sku find attribute code</span>
8
+ </li>
9
+ <li class="value">
10
+ <input type="text" name="SKUF:matchfield" value="<?php $this->getParam("SKUF:matchfield","")?>">
11
+ </li>
12
+
13
+ </ul>
lib/Magmi/plugins/base/itemprocessors/upcross_sell/crossupsell_products.php ADDED
@@ -0,0 +1,279 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class CrossUpsellProducts extends Magmi_ItemProcessor
3
+ {
4
+
5
+ public function getPluginInfo()
6
+ {
7
+ return array(
8
+ "name" => "Cross/Upsell Importer",
9
+ "author" => "Dweeves",
10
+ "version" => "1.0.3",
11
+ "url"=>$this->pluginDocUrl("Cross/Upsell_Importer")
12
+ );
13
+ }
14
+
15
+ public function checkRelated(&$rinfo)
16
+ {
17
+ if(count($rinfo["direct"])>0)
18
+ {
19
+ $sql="SELECT testid.sku,cpe.sku as esku FROM ".$this->arr2select($rinfo["direct"],"sku")." AS testid
20
+ LEFT JOIN ".$this->tablename("catalog_product_entity")." as cpe ON cpe.sku=testid.sku
21
+ WHERE testid.sku NOT LIKE '%re::%'
22
+ HAVING esku IS NULL";
23
+ $result=$this->selectAll($sql,$rinfo["direct"]);
24
+
25
+ $to_delete=array();
26
+ foreach($result as $row)
27
+ {
28
+ $this->log("Unknown related sku ".$row["sku"],"warning");
29
+ $to_delete[]=$row["sku"];
30
+ }
31
+ $rinfo["direct"]=array_diff($rinfo["direct"],$to_delete);
32
+ }
33
+ return count($rinfo["direct"])+count($rinfo["re"]);
34
+ }
35
+
36
+ public function processItemAfterId(&$item,$params=null)
37
+ {
38
+ $usell=isset($item["us_skus"])?$item["us_skus"]:null;
39
+ $csell=isset($item["cs_skus"])?$item["cs_skus"]:null;
40
+ $pid=$params["product_id"];
41
+ $new=$params["new"];
42
+
43
+ if(isset($usell) && trim($usell)!="")
44
+ {
45
+ $rinf=$this->getRelInfos($usell);
46
+ if($new==false)
47
+ {
48
+ $this->deleteUsellItems($item,$rinf["del"]);
49
+ }
50
+ $this->setUsellItems($item,$rinf["add"]);
51
+ }
52
+ if(isset($csell) && trim($csell)!="")
53
+ {
54
+ $rinf=$this->getRelInfos($csell);
55
+ if($new==false)
56
+ {
57
+ $this->deleteCSellItems($item,$rinf["del"]);
58
+ }
59
+ $this->setCSellItems($item,$rinf["add"]);
60
+ }
61
+ }
62
+
63
+ public function deleteUSellItems($item,$inf)
64
+ {
65
+ $joininfo=$this->buildJoinCond($item,$inf,"cpe2.sku");
66
+ $j2=$joininfo["join"]["cpe2.sku"];
67
+ if($j2!="")
68
+ {
69
+ $sql="DELETE cplai.*,cpl.*
70
+ FROM ".$this->tablename("catalog_product_entity")." as cpe
71
+ JOIN ".$this->tablename("catalog_product_link_type")." as cplt ON cplt.code='up_sell'
72
+ JOIN ".$this->tablename("catalog_product_link")." as cpl ON cpl.product_id=cpe.entity_id AND cpl.link_type_id=cplt.link_type_id
73
+ JOIN ".$this->tablename("catalog_product_link_attribute_int")." as cplai ON cplai.link_id=cpl.link_id
74
+ JOIN ".$this->tablename("catalog_product_entity")." as cpe2 ON cpe2.entity_id!=cpe.entity_id AND $j2
75
+ WHERE cpe.sku=?";
76
+ $this->delete($sql,array_merge($joininfo["data"]["cpe2.sku"],array($item["sku"])));
77
+ }
78
+ }
79
+
80
+ public function deleteCSellItems($item,$inf)
81
+ {
82
+ $joininfo=$this->buildJoinCond($item,$inf,"cpe2.sku");
83
+ $j2=$joininfo["join"]["cpe2.sku"];
84
+ if($j2!="")
85
+ {
86
+
87
+ $sql="DELETE cplai.*,cpl.*
88
+ FROM ".$this->tablename("catalog_product_entity")." as cpe
89
+ JOIN ".$this->tablename("catalog_product_link_type")." as cplt ON cplt.code='cross_sell'
90
+ JOIN ".$this->tablename("catalog_product_link")." as cpl ON cpl.product_id=cpe.entity_id AND cpl.link_type_id=cplt.link_type_id
91
+ JOIN ".$this->tablename("catalog_product_link_attribute_int")." as cplai ON cplai.link_id=cpl.link_id
92
+ JOIN ".$this->tablename("catalog_product_entity")." as cpe2 ON cpe2.entity_id!=cpe.entity_id AND $j2
93
+ WHERE cpe.sku=?";
94
+ $this->delete($sql,array_merge($joininfo["data"]["cpe2.sku"],array($item["sku"])));
95
+ }
96
+ }
97
+
98
+ public function getDirection(&$inf)
99
+ {
100
+ $dir="+";
101
+ if($inf[0]=="-" || $inf[0]=="+")
102
+ {
103
+ $dir=$inf[0];
104
+ $inf=substr($inf,1);
105
+ }
106
+ return $dir;
107
+
108
+ }
109
+ public function getRelInfos($relationdef)
110
+ {
111
+ $relinfos=explode(",",$relationdef);
112
+ $relskusadd=array("direct"=>array(),"re"=>array());
113
+ $relskusdel=array("direct"=>array(),"re"=>array());
114
+ foreach($relinfos as $relinfo)
115
+ {
116
+ $rinf=explode("::",$relinfo);
117
+ if(count($rinf)==1)
118
+ {
119
+ if($this->getDirection($rinf[0])=="+")
120
+ {
121
+ $relskusadd["direct"][]=$rinf[0];
122
+ }
123
+ else
124
+ {
125
+ $relskusdel["direct"][]=$rinf[0];
126
+ }
127
+ }
128
+
129
+ if(count($rinf)==2)
130
+ {
131
+ $dir=$this->getDirection($rinf[0]);
132
+ if($dir=="+")
133
+ {
134
+ switch($rinf[0])
135
+ {
136
+ case "re":
137
+ $relskusadd["re"][]=$rinf[1];
138
+ break;
139
+ }
140
+ }
141
+ else
142
+ {
143
+ switch($rinf[0])
144
+ {
145
+ case "re":
146
+ $relskusdel["re"][]=$rinf[1];
147
+ break;
148
+ }
149
+ }
150
+ }
151
+ }
152
+
153
+ return array("add"=>$relskusadd,"del"=>$relskusdel);
154
+ }
155
+
156
+ public function buildJoinCond($item,$rinfo,$keys)
157
+ {
158
+ $joinconds=array();
159
+ $joins=array();
160
+ $klist=explode(",",$keys);
161
+ foreach($klist as $key)
162
+ {
163
+ $data[$key]=array();
164
+ $joinconds[$key]=array();
165
+ if(count($rinfo["direct"])>0)
166
+ {
167
+ $joinconds[$key][]="$key IN (".$this->arr2values($rinfo["direct"]).")";
168
+ $data[$key]=array_merge($data[$key],$rinfo["direct"]);
169
+ }
170
+ if(count($rinfo["re"])>0)
171
+ {
172
+ foreach($rinfo["re"] as $rinf)
173
+ {
174
+ if($rinf!=".*")
175
+ {
176
+ $joinconds[$key][]="$key REGEXP ?";
177
+ $data[$key][]=$rinf;
178
+ }
179
+ else
180
+ {
181
+ $joinconds[$key][]="?";
182
+ $data[$key][]=1;
183
+
184
+ }
185
+ }
186
+ }
187
+ $joins[$key] = implode(" OR ",$joinconds[$key]);
188
+ if($joins[$key]!="")
189
+ {
190
+ $joins[$key]="({$joins[$key]})";
191
+ }
192
+
193
+ }
194
+ return array("join"=>$joins,"data"=>$data);
195
+ }
196
+
197
+
198
+ public function setUSellItems($item,$rinfo)
199
+ {
200
+ if($this->checkRelated($rinfo)>0)
201
+
202
+ {
203
+ $joininfo=$this->buildJoinCond($item,$rinfo,"cpe2.sku");
204
+ $jinf=$joininfo["join"]["cpe2.sku"];
205
+ if($jinf!="")
206
+ {
207
+ //insert into link table
208
+ $bsql="SELECT cplt.link_type_id,cpe.entity_id as product_id,cpe2.entity_id as linked_product_id
209
+ FROM ".$this->tablename("catalog_product_entity")." as cpe
210
+ JOIN ".$this->tablename("catalog_product_entity")." as cpe2 ON cpe2.entity_id!=cpe.entity_id AND $jinf
211
+ JOIN ".$this->tablename("catalog_product_link_type")." as cplt ON cplt.code='up_sell'
212
+ WHERE cpe.sku=?";
213
+ $sql="INSERT IGNORE INTO ".$this->tablename("catalog_product_link")." (link_type_id,product_id,linked_product_id) $bsql";
214
+ $data=array_merge($joininfo["data"]["cpe2.sku"],array($item["sku"]));
215
+ $this->insert($sql,$data);
216
+ $this->updateLinkAttributeTable($item["sku"],$joininfo,'up_sell');
217
+ }
218
+ }
219
+ }
220
+
221
+ public function setCSellItems($item,$rinfo)
222
+ {
223
+ if($this->checkRelated($rinfo)>0)
224
+
225
+ {
226
+ $joininfo=$this->buildJoinCond($item,$rinfo,"cpe2.sku");
227
+ $j2=$joininfo["join"]["cpe2.sku"];
228
+ if($j2!="")
229
+ {
230
+ //insert into link table
231
+ $bsql="SELECT cplt.link_type_id,cpe.entity_id as product_id,cpe2.entity_id as linked_product_id
232
+ FROM ".$this->tablename("catalog_product_entity")." as cpe
233
+ JOIN ".$this->tablename("catalog_product_entity")." as cpe2 ON cpe2.entity_id!=cpe.entity_id AND $j2
234
+ JOIN ".$this->tablename("catalog_product_link_type")." as cplt ON cplt.code='cross_sell'
235
+ WHERE cpe.sku=?";
236
+ $sql="INSERT IGNORE INTO ".$this->tablename("catalog_product_link")." (link_type_id,product_id,linked_product_id) $bsql";
237
+ $data=array_merge($joininfo["data"]["cpe2.sku"],array($item["sku"]));
238
+ $this->insert($sql,$data);
239
+ $this->updateLinkAttributeTable($item["sku"],$joininfo,'cross_sell');
240
+ }
241
+ }
242
+ }
243
+
244
+ public function updateLinkAttributeTable($sku,$joininfo,$reltype)
245
+ {
246
+ //insert into attribute link attribute int table,reusing the same relations
247
+ //this enable to mass add
248
+ $bsql="SELECT cpl.link_id,cpla.product_link_attribute_id,0 as value
249
+ FROM ".$this->tablename("catalog_product_entity")." AS cpe
250
+ JOIN ".$this->tablename("catalog_product_entity")." AS cpe2 ON cpe2.entity_id!=cpe.entity_id
251
+ JOIN ".$this->tablename("catalog_product_link_type")." AS cplt ON cplt.code=?
252
+ JOIN ".$this->tablename("catalog_product_link_attribute")." AS cpla ON cpla.product_link_attribute_code='position' AND cpla.link_type_id=cplt.link_type_id
253
+ JOIN ".$this->tablename("catalog_product_link") ." AS cpl ON cpl.link_type_id=cplt.link_type_id AND cpl.product_id=cpe.entity_id AND cpl.linked_product_id=cpe2.entity_id
254
+ WHERE cpe.sku=?";
255
+ $sql="INSERT IGNORE INTO ".$this->tablename("catalog_product_link_attribute_int")." (link_id,product_link_attribute_id,value) $bsql";
256
+ $this->insert($sql,array($reltype,$sku));
257
+
258
+ }
259
+
260
+ public function afterImport()
261
+ {
262
+ //remove maybe inserted doubles
263
+ $cplai=$this->tablename("catalog_product_link_attribute_int");
264
+ $sql="DELETE cplaix FROM $cplai as cplaix
265
+ WHERE cplaix.value_id IN
266
+ (SELECT s1.value_id FROM
267
+ (SELECT cplai.link_id,cplai.value_id,MAX(cplai.value_id) as latest
268
+ FROM $cplai as cplai
269
+ GROUP BY cplai.link_id
270
+ HAVING cplai.value_id!=latest)
271
+ as s1)";
272
+ $this->delete($sql);
273
+ }
274
+
275
+ static public function getCategory()
276
+ {
277
+ return "Related Products";
278
+ }
279
+ }
lib/Magmi/plugins/inc/magmi_datasource.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Class Magmi_Datasource
4
+ * @author dweeves
5
+ *
6
+ * This class enables to perform input format support for ingested data
7
+ */
8
+ require_once("magmi_generalimport_plugin.php");
9
+ abstract class Magmi_DataSource extends Magmi_GeneralImportPlugin
10
+ {
11
+
12
+ public function getColumnNames($prescan=false)
13
+ {
14
+
15
+ }
16
+ public function getRecordsCount()
17
+ {
18
+
19
+ }
20
+
21
+ public function getNextRecord()
22
+ {
23
+
24
+ }
25
+
26
+ public function onException($e)
27
+ {
28
+
29
+ }
30
+ }
lib/Magmi/plugins/inc/magmi_default_options_panel.php ADDED
@@ -0,0 +1 @@
 
1
+ <span>Plugin has no configurable parameters</span>
lib/Magmi/plugins/inc/magmi_defaultattributehandler.php ADDED
@@ -0,0 +1,218 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Magmi_DefaultAttributeItemProcessor extends Magmi_ItemProcessor
3
+ {
4
+ protected $_basecols=array("store"=>"admin","type"=>"simple");
5
+ protected $_baseattrs=array("status"=>1,"visibility"=>4,"page_layout"=>"");
6
+ protected $_forcedefault=array("store"=>"admin");
7
+ protected $_missingcols=array();
8
+ protected $_missingattrs=array();
9
+
10
+ public function initialize($params)
11
+ {
12
+ $this->registerAttributeHandler($this,array("attribute_code:.*"));
13
+ }
14
+
15
+ public function getPluginInfo()
16
+ {
17
+ return array(
18
+ "name" => "Standard Attribute Import",
19
+ "author" => "Dweeves",
20
+ "version" => "1.0.5"
21
+ );
22
+ }
23
+
24
+ public function processColumnList(&$cols)
25
+ {
26
+ $this->_missingcols=array_diff(array_keys($this->_basecols),$cols);
27
+ $this->_missingattrs=array_diff(array_keys($this->_baseattrs),$cols);
28
+ $m=$this->getMode();
29
+ if($m=="create" || $m=="xcreate")
30
+ {
31
+ $cols=array_merge($cols,$this->_missingcols,$this->_missingattrs);
32
+ $this->log("Newly created items will have default values for columns:".implode(",",array_merge($this->_missingcols,$this->_missingattrs)),"startup");
33
+ }
34
+ }
35
+
36
+
37
+ public function initializeBaseCols(&$item)
38
+ {
39
+ foreach($this->_missingcols as $missing)
40
+ {
41
+ $item[$missing]=$this->_basecols[$missing];
42
+ }
43
+ }
44
+
45
+ public function initializeBaseAttrs(&$item)
46
+ {
47
+ foreach($this->_missingattrs as $missing)
48
+ {
49
+ $item[$missing]=$this->_baseattrs[$missing];
50
+ }
51
+ }
52
+
53
+
54
+
55
+ public function processItemAfterId(&$item,$params=null)
56
+ {
57
+ if($params["new"]==true)
58
+ {
59
+ $this->initializeBaseCols($item);
60
+ $this->initializeBaseAttrs($item);
61
+ }
62
+ //forcing default values for mandatory processing columns
63
+ foreach($this->_forcedefault as $k=>$v)
64
+ {
65
+ if(isset($item[$k]) && trim($item[$k])=="")
66
+ {
67
+ $item[$k]=$v;
68
+ }
69
+ }
70
+ return true;
71
+ }
72
+
73
+ /**
74
+ * attribute handler for decimal attributes
75
+ * @param int $pid : product id
76
+ * @param int $ivalue : initial value of attribute
77
+ * @param array $attrdesc : attribute description
78
+ * @return mixed : false if no further processing is needed,
79
+ * string (magento value) for the decimal attribute otherwise
80
+ */
81
+ public function handleDecimalAttribute($pid,&$item,$storeid,$attrcode,$attrdesc,$ivalue)
82
+ {
83
+ //force convert decimal separator to dot
84
+ $ivalue=str_replace(",",".",$ivalue);
85
+ $ovalue=deleteifempty($ivalue);
86
+ return $ovalue;
87
+ }
88
+
89
+ /**
90
+ * attribute handler for datetime attributes
91
+ * @param int $pid : product id
92
+ * @param int $ivalue : initial value of attribute
93
+ * @param array $attrdesc : attribute description
94
+ * @return mixed : false if no further processing is needed,
95
+ * string (magento value) for the datetime attribute otherwise
96
+ */
97
+ public function handleDatetimeAttribute($pid,&$item,$storeid,$attrcode,$attrdesc,$ivalue)
98
+ {
99
+ $ovalue=deleteifempty(trim($ivalue));
100
+ //Handle european date format or other common separators
101
+ if(preg_match("|([0-9]){1,2}\D([0-9]){1,2}\D([0-9]){4}|",$ovalue,$matches))
102
+ {
103
+ $ovalue=sprintf("%4d-%2d-%2d",$matches[3],$matches[2],$matches[1]);
104
+ }
105
+ return $ovalue;
106
+ }
107
+
108
+ public function handleTextAttribute($pid,&$item,$storeid,$attrcode,$attrdesc,$ivalue)
109
+ {
110
+ $ovalue=(empty($ivalue)?'':$ivalue);
111
+ return $ovalue;
112
+ }
113
+
114
+ public function checkInt($value)
115
+ {
116
+ return is_int($value) || (is_string($value) && is_numeric($value) && (int)$value==$value);
117
+ }
118
+ /**
119
+ * attribute handler for int typed attributes
120
+ * @param int $pid : product id
121
+ * @param int $ivalue : initial value of attribute
122
+ * @param array $attrdesc : attribute description
123
+ * @return mixed : false if no further processing is needed,
124
+ * int (magento value) for the int attribute otherwise
125
+ */
126
+ public function handleIntAttribute($pid,&$item,$storeid,$attrcode,$attrdesc,$ivalue)
127
+ {
128
+ $ovalue=$ivalue;
129
+ $attid=$attrdesc["attribute_id"];
130
+ //if we've got a select type value
131
+ if($attrdesc["frontend_input"]=="select")
132
+ {
133
+ //we need to identify its type since some have no options
134
+ switch($attrdesc["source_model"])
135
+ {
136
+ //if its status, default to 1 (Enabled) if not correcly mapped
137
+ case "catalog/product_status":
138
+ if(!$this->checkInt($ivalue) ){
139
+ $ovalue=1;
140
+ }
141
+ break;
142
+ //do not create options for boolean values tagged as select ,default to 0 if not correcly mapped
143
+ case "eav/entity_attribute_source_boolean":
144
+ if(!$this->checkInt($ivalue)){
145
+ $ovalue=0;
146
+ }
147
+ break;
148
+ //if visibility no options either,default to 4 if not correctly mapped
149
+ case "catalog/product_visibility":
150
+ if(!$this->checkInt($ivalue)){
151
+ $ovalue=4;
152
+ }
153
+
154
+ break;
155
+ //if it's tax_class, get tax class id from item value
156
+ case "tax/class_source_product":
157
+ $ovalue=$this->getTaxClassId($ivalue);
158
+ break;
159
+ //otherwise, standard option behavior
160
+ //get option id for value, create it if does not already exist
161
+ //do not insert if empty
162
+ default:
163
+ if($ivalue=="" && $this->getMode()=="update")
164
+ {
165
+ return "__MAGMI_DELETE__";
166
+ }
167
+ $oids=$this->getOptionIds($attid,$storeid,array($ivalue));
168
+ $ovalue=$oids[0];
169
+ unset($oids);
170
+ break;
171
+ }
172
+ }
173
+ return $ovalue;
174
+ }
175
+
176
+
177
+ /**
178
+ * attribute handler for varchar based attributes
179
+ * @param int $pid : product id
180
+ * @param string $ivalue : attribute value
181
+ * @param array $attrdesc : attribute description
182
+ */
183
+ public function handleVarcharAttribute($pid,&$item,$storeid,$attrcode,$attrdesc,$ivalue)
184
+ {
185
+
186
+ if($storeid!==0 && empty($ivalue) && $this->getImportMode()=="create")
187
+ {
188
+ return false;
189
+ }
190
+ if($ivalue=="" && $this->getImportMode()=="update")
191
+ {
192
+ return "__MAGMI_DELETE__";
193
+ }
194
+
195
+ $ovalue=$ivalue;
196
+ $attid=$attrdesc["attribute_id"];
197
+ //--- Contribution From mennos , optimized by dweeves ----
198
+ //Added to support multiple select attributes
199
+ //(as far as i could figure out) always stored as varchars
200
+ //if it's a multiselect value
201
+ if($attrdesc["frontend_input"]=="multiselect")
202
+ {
203
+ //if empty delete entry
204
+ if($ivalue=="")
205
+ {
206
+ return "__MAGMI_DELETE__";
207
+ }
208
+ //magento uses "," as separator for different multiselect values
209
+ $sep=Magmi_Config::getInstance()->get("GLOBAL","multiselect_sep",",");
210
+ $multiselectvalues=explode($sep,$ivalue);
211
+ $oids=$this->getOptionIds($attid,$storeid,$multiselectvalues);
212
+ $ovalue=implode(",",$oids);
213
+ unset($oids);
214
+ }
215
+ return $ovalue;
216
+ }
217
+
218
+ }
lib/Magmi/plugins/inc/magmi_generalimport_plugin.php ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once("magmi_plugin.php");
3
+ abstract class Magmi_GeneralImportPlugin extends Magmi_Plugin
4
+ {
5
+ public function beforeImport()
6
+ {
7
+ return true;
8
+ }
9
+
10
+ public function afterImport()
11
+ {
12
+ return true;
13
+ }
14
+
15
+ }
lib/Magmi/plugins/inc/magmi_item_processor.php ADDED
@@ -0,0 +1,102 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Class CustomItemProcessor
4
+ * @author dweeves
5
+ *
6
+ * This class enables to perform custom modifications on item
7
+ *
8
+ * class principle:
9
+ * methods should be called processItemXxx where Xxx is an import step of the Magmi_ProductImportEngine
10
+ *
11
+ * all processItemXxx methods are optional, you need only to define methods you need to implement
12
+ *
13
+ * processItemXxx signature are always the same
14
+ *
15
+ *
16
+ * processItemXxx($mmi,&$item,$params=null) where
17
+ *
18
+ * $mmi : reference to Magmi_Engine instance
19
+ * &$item : array reference to item
20
+ * $params : step dependent array, may be null
21
+ *
22
+ * processItemXxx method always return a boolean value , return false if you want to break mmi processing for item
23
+ *
24
+ * current available import steps:
25
+ * beforeId => method processItemBeforeId , called before item is identified, just after loading csv values for item
26
+ * $params : null
27
+ *
28
+ *
29
+ * afterId => method processItemAfterId , called after item is identified or created in magento
30
+ * $params : array("product_id"=><magento product id>)
31
+ *
32
+ * exception => method processItemException , called when mmi processing caused an exception (even customItemProcessor thrown exception)
33
+ *$params : array("exception"=><exception instance thrown>)
34
+ *
35
+ *
36
+ */
37
+ require_once("magmi_generalimport_plugin.php");
38
+ abstract class Magmi_ItemProcessor extends Magmi_GeneralImportPlugin
39
+ {
40
+ /**
41
+ * you can add/remove columns for the item passed since it is passed by reference
42
+ * @param MagentoMassImporter $mmi : reference to mass importer (convenient to perform database operations)
43
+ * @param unknown_type $item : modifiable reference to item before import
44
+ * the $item is a key/value array with column names as keys and values as read from csv file.
45
+ * @return bool :
46
+ * true if you want the item to be imported after your custom processing
47
+ * false if you want to skip item import after your processing
48
+ */
49
+
50
+
51
+ public function processItemBeforeId(&$item,$params=null)
52
+ {
53
+ /* example code 1 */
54
+ /* i've added some non item attribute values in my csv (cp_id,cp_price) but
55
+ * these values are meant to be inserted into a custom module table
56
+ * so , i get the following code (commented)
57
+ */
58
+
59
+ /*
60
+ //if my special column cp_id exists
61
+ if(isset($item['cp_id']))
62
+ {
63
+ //if its value is not empty
64
+ if($item['cp_id']!="")
65
+ {
66
+ //ask mmi for custom module table name (takes into account table prefix
67
+ $tname=$mmi->tablename("book_categoryprice");
68
+ //parameterized sql for insert (ignore doubles)
69
+ $sql="INSERT IGNORE INTO $tname (cp_id,price) VALUES (?,?)";
70
+ $data=array($item["cp_id"],$item["cp_price"]);
71
+ //ask mmi to perform insert
72
+ $mmi->insert($sql,$data);
73
+ }
74
+ //remove my special columns from item
75
+ unset($item["cp_id"]);
76
+ unset($item["cp_price"]);
77
+ }*/
78
+
79
+ /** example code 2 **/
80
+ /*
81
+ * //if we have qty column & are in create mode & reset, do not import items with 0 qty
82
+ if(isset($item['qty']) && $item['qty']==0 && $mmi->mode=="create" && $mmi->reset)
83
+ {
84
+ return false;
85
+ }
86
+ * /
87
+ */
88
+ //return true , enable item processing
89
+ return true;
90
+ }
91
+
92
+ public function processItemAfterId(&$item,$params=null)
93
+ {
94
+ return true;
95
+ }
96
+
97
+ /*
98
+ public function processItemException($mmi,&$item,$params=null)
99
+ {
100
+
101
+ }*/
102
+ }
lib/Magmi/plugins/inc/magmi_plugin.php ADDED
@@ -0,0 +1,346 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once("magmi_config.php");
3
+ require_once("magmi_mixin.php");
4
+ class Magmi_PluginConfig extends ProfileBasedConfig
5
+ {
6
+ protected $_prefix;
7
+ protected $_conffile;
8
+ public function __construct($pname,$profile=null)
9
+ {
10
+ $this->_prefix=$pname;
11
+ parent::__construct("$this->_prefix.conf",$profile);
12
+ }
13
+
14
+ public function getConfDir()
15
+ {
16
+ return dirname($this->_confname);
17
+ }
18
+
19
+ public function load($name=null)
20
+ {
21
+ $cname=($name==null?$this->_confname:$name);
22
+ if(file_exists($cname))
23
+ {
24
+ parent::load($cname);
25
+ }
26
+ }
27
+
28
+ public function getIniStruct($arr)
29
+ {
30
+ $conf=array();
31
+ foreach($arr as $k=>$v)
32
+ {
33
+ $k=$this->_prefix.":".$k;
34
+ list($section,$value)=explode(":",$k,2);
35
+ if(!isset($conf[$section]))
36
+ {
37
+ $conf[$section]=array();
38
+ }
39
+ $conf[$section][$value]=$v;
40
+ }
41
+ return $conf;
42
+ }
43
+
44
+
45
+ public function getConfig()
46
+ {
47
+ return parent::getsection($this->_prefix);
48
+ }
49
+ }
50
+
51
+ class Magmi_PluginOptionsPanel
52
+ {
53
+ private $_plugin;
54
+ private $_defaulthtml="";
55
+ private $_file=null;
56
+ public function __construct($pinst,$file=null)
57
+ {
58
+ $this->_plugin=$pinst;
59
+ $this->_file=($file==null?"options_panel.php":$file);
60
+ $this->initDefaultHtml();
61
+
62
+ }
63
+
64
+ public function getFile()
65
+ {
66
+ return $this->_file;
67
+ }
68
+
69
+ public final function initDefaultHtml()
70
+ {
71
+ $panelfile=dirname(__FILE__)."/magmi_default_options_panel.php";
72
+ ob_start();
73
+ require($panelfile);
74
+ $this->_defaulthtml = ob_get_contents();
75
+ ob_end_clean();
76
+
77
+ }
78
+
79
+ public function getHtml()
80
+ {
81
+ $plugin=$this->_plugin;
82
+ $pdir=Magmi_PluginHelper::getInstance()->getPluginDir($this->_plugin);
83
+ $panelfile="$pdir/".$this->getFile();
84
+ $content="";
85
+ if(!file_exists($panelfile))
86
+ {
87
+ $content=$this->_defaulthtml;
88
+ }
89
+ else
90
+ {
91
+ ob_start();
92
+ require($panelfile);
93
+ $content = ob_get_contents();
94
+ ob_end_clean();
95
+ }
96
+ return $content;
97
+ }
98
+
99
+ public function __call($data,$arg)
100
+ {
101
+ return call_user_func_array(array($this->_plugin,$data), $arg);
102
+ }
103
+ }
104
+
105
+ abstract class Magmi_Plugin extends Magmi_Mixin
106
+ {
107
+ protected $_class;
108
+ protected $_plugintype;
109
+ protected $_plugindir;
110
+ protected $_config;
111
+ protected $_magmiconfig;
112
+ protected $_pluginmeta;
113
+ public function __construct()
114
+ {
115
+ }
116
+
117
+ public function pluginDocUrl($urlk)
118
+ {
119
+ return "http://sourceforge.net/apps/mediawiki/magmi/index.php?title=".$urlk;
120
+ }
121
+
122
+ public function getParam($pname,$default=null)
123
+ {
124
+ return (isset($this->_params[$pname]) && $this->_params[$pname]!="")?$this->_params[$pname]:$default;
125
+
126
+ }
127
+
128
+ public function setParam($pname,$value)
129
+ {
130
+ $this->_params[$pname]=$value;
131
+ }
132
+
133
+ public function fixListParam($pvalue)
134
+ {
135
+ $iarr=explode(",",$pvalue);
136
+ $oarr=array();
137
+ foreach($iarr as $v)
138
+ {
139
+ if($v!="")
140
+ {
141
+ $oarr[]=$v;
142
+ }
143
+ }
144
+ $val=implode(",",$oarr);
145
+ unset($iarr);
146
+ unset($oarr);
147
+ return $val;
148
+ }
149
+ public function getPluginParamNames()
150
+ {
151
+ return array();
152
+ }
153
+
154
+ public function getPluginInfo()
155
+ {
156
+ return array("name"=>$this->getPluginName(),
157
+ "version"=>$this->getPluginVersion(),
158
+ "author"=>$this->getPluginAuthor(),
159
+ "url"=>$this->getPluginUrl());
160
+ }
161
+
162
+ public function getPluginUrl()
163
+ {
164
+ return null;
165
+ }
166
+
167
+ public function getPluginVersion()
168
+ {
169
+ return null;
170
+ }
171
+
172
+ public function getPluginName()
173
+ {
174
+ return null;
175
+ }
176
+
177
+
178
+ public function getPluginAuthor()
179
+ {
180
+ return null;
181
+ }
182
+
183
+ public function log($data,$type='std',$useprefix=true)
184
+ {
185
+ $pinf=$this->getPluginInfo();
186
+ if($useprefix)
187
+ {
188
+ $data="{$pinf["name"]} v{$pinf["version"]} - ".$data;
189
+ }
190
+ $this->_caller_log($data,"plugin;$this->_class;$type");
191
+ }
192
+
193
+ public function pluginHello()
194
+ {
195
+ $info=$this->getPluginInfo();
196
+ $hello=array(!isset($info["name"])?"":$info["name"]);
197
+ $hello[]=!isset($info["version"])?"":$info["version"];
198
+ $hello[]=!isset($info["author"])?"":$info["author"];
199
+ $hello[]=!isset($info["url"])?"":$info["url"];
200
+ $hellostr=implode("-",$hello);
201
+ $base=get_parent_class($this);
202
+ $this->log("$hellostr ","pluginhello",false);
203
+
204
+ }
205
+
206
+ public function initialize($params)
207
+ {
208
+
209
+ }
210
+
211
+ public function getConfig()
212
+ {
213
+ return $this->_config;
214
+ }
215
+
216
+ public function getMagmiConfig()
217
+ {
218
+ return $this->_magmiconfig;
219
+ }
220
+
221
+ public final function pluginInit($mmi,$meta,$params=null,$doinit=true,$profile=null)
222
+ {
223
+ $this->bind($mmi);
224
+ $this->_pluginmeta=$meta;
225
+ $this->_class=get_class($this);
226
+ $this->_config=new Magmi_PluginConfig(get_class($this),$profile);
227
+ $this->_config->load();
228
+ $this->_magmiconfig=Magmi_Config::getInstance();
229
+
230
+ $this->_params=($params!=null?array_merge($this->_config->getConfig(),$params):$this->_config->getConfig());
231
+
232
+ if(isset($mmi))
233
+ {
234
+ $this->pluginHello();
235
+ }
236
+
237
+ if($doinit)
238
+ {
239
+ $this->initialize($this->_params);
240
+ }
241
+ }
242
+
243
+
244
+ public function getPluginParamsNoCurrent($params)
245
+ {
246
+ $arr=array();
247
+ $paramkeys=$this->getPluginParamNames();
248
+ foreach($paramkeys as $pk)
249
+ {
250
+ if(isset($params[$pk]))
251
+ {
252
+ $arr[$pk]=$params[$pk];
253
+ }
254
+ else
255
+ {
256
+ $arr[$pk]=0;
257
+ }
258
+ }
259
+ return $arr;
260
+ }
261
+ public function getPluginParams($params)
262
+ {
263
+ $arr=array();
264
+ $paramkeys=$this->getPluginParamNames();
265
+ foreach($paramkeys as $pk)
266
+ {
267
+ if(isset($params[$pk]))
268
+ {
269
+ $arr[$pk]=$params[$pk];
270
+ }
271
+ else
272
+ {
273
+ if(isset($this->_params[$pk]))
274
+ {
275
+ $arr[$pk]=$this->_params[$pk];
276
+ }
277
+ }
278
+ }
279
+ return $arr;
280
+ }
281
+
282
+ public function persistParams($plist)
283
+ {
284
+ if(count($plist)>0)
285
+ {
286
+ $this->_config->setPropsFromFlatArray($plist);
287
+ return $this->_config->save();
288
+ }
289
+ return true;
290
+ }
291
+
292
+ public function getOptionsPanel($file=null)
293
+ {
294
+ return new Magmi_PluginOptionsPanel($this,$file);
295
+ }
296
+
297
+ public function getShortDescription()
298
+ {
299
+ $panel=$this->getOptionsPanel()->getHtml();
300
+ $info=null;
301
+ if(preg_match('|<div class="plugin_description">(.*?)</div>|smi',$panel,$match))
302
+ {
303
+
304
+ $info=$match[1];
305
+ $delims=array(".",":");
306
+ foreach($delims as $delim)
307
+ {
308
+ $p=strpos($info,$delim);
309
+ if($p!==false)
310
+ {
311
+ $info=substr($info,0,$p);
312
+ break;
313
+ }
314
+ }
315
+
316
+ }
317
+ return $info;
318
+ }
319
+
320
+ static public function getCategory()
321
+ {
322
+ return "common";
323
+ }
324
+
325
+ public function getPluginDir()
326
+ {
327
+ return $this->_pluginmeta["dir"];
328
+ }
329
+
330
+ public function getPluginMeta()
331
+ {
332
+ return $this->_pluginmeta;
333
+ }
334
+
335
+ public function getPluginClass()
336
+ {
337
+ return $this->_class;
338
+ }
339
+
340
+ public function isRunnable()
341
+ {
342
+ return array(true,"");
343
+ }
344
+
345
+
346
+ }
lib/Magmi/plugins/inc/magmi_utility_plugin.php ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class Magmi_UtilityPlugin extends Magmi_Plugin
3
+ {
4
+ public function runUtility()
5
+ {
6
+ //Put Running code
7
+ }
8
+
9
+ public function getWarning()
10
+ {
11
+ return null;
12
+ }
13
+ }
package.xml ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <package>
3
+ <name>magento-full-catalog-translate</name>
4
+ <version>0.2.0</version>
5
+ <stability>stable</stability>
6
+ <license uri="http://opensource.org/licenses/osl-3.0.php">OSL v3.0</license>
7
+ <channel>community</channel>
8
+ <extends/>
9
+ <summary>A module to translate all your products automatically using Google Translate API.</summary>
10
+ <description>When you install the module it will create a new product attribute called "Translate automatically?" (you'll find it in the "General" tab for all of your products).&#xD;
11
+ &lt;br /&gt;&lt;br /&gt;&#xD;
12
+ Let's say you have your main store in English, then you create a storeview in Italian, now all of your products in the Italian store view have the English texts. What you want is to quickly have them in Italian. Be sure the locales are correctly configured for all the stores/storeviews you're going to use in the process (this module will automatically read the language settings from the storeviews).&#xD;
13
+ &lt;br /&gt;&lt;br /&gt;&#xD;
14
+ So go in your "Catalog -&gt; Manage products" mask in the Magento backend, select the Italian store view (or anyway the one you want to translate), then with the mass action tools selects all the products and "update attributes", now set the "Translate automatically?" attribute to yes. This means that these products for this store view neeed to be translated (we'll see later how and from what language to what language).&#xD;
15
+ &lt;br /&gt;&lt;br /&gt;&#xD;
16
+ Now we have products in English and products marked as "to be translated" in our Italian storeview.&#xD;
17
+ &lt;br /&gt;&lt;br /&gt;&#xD;
18
+ Let's step back a little bit: configuration. Before actually translating our contents you need to review come configurations of the module, go to the Magento backend mask "System -&gt; Configuration -&gt; Services -&gt; Fballiano Full Catalog Translate". Here can decide which product attributes have to be translated (defaults: name, short_description, description, meta_title, meta_keyword, meta_description) but most importantly you'll have to fill your Google Translate API key (without it nothing will actually work).&#xD;
19
+ &lt;br /&gt;&lt;br /&gt;&#xD;
20
+ Open the console and navigate to the "shell" directory. Now we'll start the actual translate process.&#xD;
21
+ &lt;br /&gt;&lt;br /&gt;&#xD;
22
+ php fballiano_full_catalog_translate.php sourcestorecode targetstorecode&#xD;
23
+ &lt;br /&gt;&lt;br /&gt;&#xD;
24
+ in out case it could be:&#xD;
25
+ &lt;br /&gt;&lt;br /&gt;&#xD;
26
+ php fballiano_full_catalog_translate.php default storeviewita&#xD;
27
+ &lt;br /&gt;&lt;br /&gt;&#xD;
28
+ The process will gather all the products that need to be translated (from the target storeview), gather the untranslated text (from the source storeview), call Google Translate API for every attribute, import the translated text into the target store view, set the record to "not to be translated" (again, into the target storeview).</description>
29
+ <notes>First public release</notes>
30
+ <authors><author><name>Fabrizio Balliano</name><user>fballiano</user><email>fabrizio@fabrizioballiano.it</email></author></authors>
31
+ <date>2014-06-13</date>
32
+ <time>07:06:58</time>
33
+ <contents><target name="mage"><dir name="app"><dir name="code"><dir name="community"><dir name="Fballiano"><dir name="FullCatalogTranslate"><dir name="Helper"><file name="Data.php" hash="fed4f9d970da860ee349d8de2bb752ac"/></dir><dir name="etc"><file name="adminhtml.xml" hash="db29c60a26c76fc43d89a6aad45b8c0d"/><file name="config.xml" hash="9aaed4e0d405c4c93747359babf4db5a"/><file name="system.xml" hash="a525da02ee6ea44ccde8ee29d5942ee2"/></dir><dir name="sql"><dir name="fballiano_fullcatalogtranslate_setup"><file name="install-0.1.0.php" hash="39142871be423777adec9c76372a9731"/></dir></dir></dir></dir></dir></dir><dir name="etc"><dir name="modules"><file name="Fballiano_FullCatalogTranslate.xml" hash="7763d2974b52ca32136a0260a426f090"/></dir></dir></dir><dir name="lib"><dir name="Magmi"><file name="ReleaseNotes.txt" hash="0ac67ff0b1bd147e09aacc854113309d"/><dir name="conf"><file name="magmi.ini" hash="17ad89d67997e66c499c673e3e8af291"/><file name="plugins.conf" hash="d41d8cd98f00b204e9800998ecf8427e"/></dir><dir name="engines"><file name="magmi_productimportengine.php" hash="8897589287f42e89a4c13dae04c5c152"/><file name="magmi_utilityengine.php" hash="d0ca093690e95caea5864d2fd4321104"/></dir><dir name="inc"><file name="dbhelper.class.php" hash="9d08f9e386e482048335c35069175e1c"/><file name="dbhelper.class.php~" hash="59098f2580e780f55bd99f0602e78b2d"/><file name="fshelper.php" hash="b191c2c916cf3dca5055bd96c93b8945"/><file name="license.txt" hash="d69f02f4db9d64af32ac1a390d2a9574"/><file name="magmi_config.php" hash="aea8a1efdeca49f2405f473c1f0b9a23"/><file name="magmi_csvreader.php" hash="895070e4753f1e77d1702f9de5652d03"/><file name="magmi_defs.php" hash="50a8feecdfb43dde843bd7e36fddc413"/><file name="magmi_engine.php" hash="f0b097072ec83b7b50b4e243a6bfb9be"/><file name="magmi_loggers.php" hash="27e74b06ce160c6e07f9da614503bfba"/><file name="magmi_mixin.php" hash="95ac60575fcda43174fa545f2e4c0217"/><file name="magmi_pluginhelper.php" hash="75d5ba334c43f545cdc38d274341b423"/><file name="magmi_postinstall.php" hash="3bef1b9a85d364d0858502e0d5b3cd87"/><file name="magmi_statemanager.php" hash="a56c33fe73c871338853c25933c2a280"/><file name="magmi_utils.php" hash="9694d4ffdb23c1ca2b350dad99d08e96"/><file name="magmi_version.php" hash="1a18210c3c8b7884c596a2d350ebc7ae"/><file name="properties.php" hash="1a57150735e51255fff575b8f1df5e91"/></dir><dir name="integration"><dir name="inc"><file name="magmi_datapump.php" hash="5446ff3f4dd82086d10d81c8f32bba05"/><file name="magmi_datapumpdatasource.php" hash="98113a6bc3d3617da7655c850596c36b"/><file name="productimport_datapump.php" hash="b5bfa0ce6aa4e7b56f70bd3da623e428"/><file name="pumpfactory.ini" hash="b4beac3e561fcf91a416eb52c76ce4e3"/></dir><dir name="samples"><file name="sample.php" hash="89df4a819a4396ab981092cae130eaa9"/><file name="sample2_configurables.php" hash="4ab28a07812ae27c9ad26bf3edbb68fd"/></dir></dir><dir name="plugins"><dir name="base"><dir name="datasources"><dir name="__magento"><file name="magmi_magentodatasource.php" hash="7994fe4f0ffdbe6d2d5881d31597319a"/><file name="options_panel.php" hash="1c1cf71c5ca55933b1c39e4040d1865e"/></dir><dir name="csv"><file name="csvds_filelist.php" hash="737e882668364fd8fe517f6fb94d3deb"/><file name="magmi_csvdatasource.php" hash="d6d78948b50669161fd8bb615dab8de1"/><file name="options_panel.php" hash="0addabcc9d0469cfd6a86b0cbda63418"/></dir><dir name="genericsql"><file name="mysql_options.php" hash="ca0c24ee9397fcdfba2b75063ef28901"/><file name="options_panel.php" hash="fe738f8d7f861eba725a4cd7a6798809"/><file name="other_options.php" hash="f47deb1e13a7e5bfaade5b878f9f1065"/><file name="sql_datasource.php" hash="f1e6b42056630739bcb38df8e74f121e"/></dir></dir><dir name="general"><dir name="emailreport"><file name="emailreport.php" hash="6bda450b7141cdcdb7b0e7b184cca8bd"/><file name="options_panel.php" hash="72c1ac4891219fa1a87f8b03a15dc0c6"/></dir><dir name="importurl"><file name="importurl_plugin.php" hash="3b3226fb553a03a2bfff8d45babf4f02"/><file name="options_panel.php" hash="3f4131f0c50b22af8d5762eae25a8561"/></dir><dir name="optimizer"><file name="magmi_optimizer_plugin.php" hash="2c0a9f084c93ac6052a115eaac5cb398"/></dir><dir name="reindex"><file name="magmi_reindexing_plugin.php" hash="2552a823150c881b877035d79824565f"/><file name="options_panel.php" hash="eb077f772e34bdbf75c79ce882cd0f07"/></dir></dir><dir name="itemprocessors"><dir name="columnmapper"><file name="000_columnmapper.php" hash="7a0ae78ee3ab4f38431c07f8ed46bd6d"/><file name="options_panel.php" hash="44b2ab98da57a5354cd22c1d7f5a8e0f"/></dir><dir name="configurables"><file name="magmi_configurableprocessor.php" hash="93f7f7da42a017e77a3293e825bb2048"/><file name="options_panel.php" hash="4ffc870e5ff6bc33a02e972a2f614707"/></dir><dir name="defaultvalues"><file name="00_default_values.php" hash="d8e94a904b9b4a03304785ec2d5a9d9d"/><file name="options_panel.php" hash="b951c2d3487d694597c416a1ff3dafa1"/></dir><dir name="genericmapper"><file name="02_genericmapper.php" hash="5890de9499085267cde209a07aabb9d0"/><dir name="mappings"><dir name="default"><file name="__common__.csv" hash="51f076b2137b08cbcec63bcfa046ad7a"/><file name="options_container.csv" hash="bb84f94e68900c1aafc66ce2c2461d06"/><file name="page_layout.csv" hash="0f6ac4af46d4090cb22497d172bad2f8"/><file name="status.csv" hash="dc5569042656c4163fea1cd74e8ed6d8"/><file name="visibility.csv" hash="462fe1effcdb1ab3942677a011019f15"/></dir></dir><file name="options_panel.php" hash="06477d262c34d194da52d533af8d270f"/></dir><dir name="grouped"><file name="alpine_groupedprocessor.php" hash="570fd184740e822b6b4489cd3a30324a"/><file name="options_panel.php" hash="746c1d9e4e3248ab768f2da7002d0ac4"/></dir><dir name="importlimiter"><file name="01_importlimiter.php" hash="770310a86b9bd7b8a03889c60d4b82d2"/><file name="options_panel.php" hash="cb52e5ac4bc489c50b2b5768608bcf0b"/></dir><dir name="productdeleter"><file name="options_panel.php" hash="4252b3a975efc6bc42ec3903a1f9158f"/><file name="productdeleter.php" hash="d9390afd593ed793a5ce13f3877d2f70"/></dir><dir name="related"><file name="related_products.php" hash="c9623952da7d17e76d8e6483b7327f80"/></dir><dir name="skufinder"><file name="001_skufinder.php" hash="a5dbdaed122087f6c0a68e024556fae4"/><file name="options_panel.php" hash="fe48ad7baac974583c41eb762dbe4e1c"/></dir><dir name="upcross_sell"><file name="crossupsell_products.php" hash="23eec787b46fcb0463367090e47e97e4"/></dir></dir></dir><dir name="inc"><file name="magmi_datasource.php" hash="255921bd1b5879e77a3a16f762781ac0"/><file name="magmi_default_options_panel.php" hash="b35c690a790c77b97124c3bd395b176d"/><file name="magmi_defaultattributehandler.php" hash="4f6ce8c7286aca015bef34366c11899d"/><file name="magmi_generalimport_plugin.php" hash="e5a337ee90873ee82c6ecb7ed38af647"/><file name="magmi_item_processor.php" hash="1bd368a6970940206724284a299f028b"/><file name="magmi_plugin.php" hash="c3a09fef3804f0b56b3123494e47239c"/><file name="magmi_utility_plugin.php" hash="8b0aaa8700a9337a206d72ded13bfa9b"/></dir></dir></dir></dir><dir name="shell"><file name="fballiano_full_catalog_translate.php" hash="e87ba031e963a459a5f22edf30902900"/></dir></target></contents>
34
+ <compatible/>
35
+ <dependencies><required><php><min>5.3.0</min><max>6.0.0</max></php></required></dependencies>
36
+ </package>
shell/fballiano_full_catalog_translate.php ADDED
@@ -0,0 +1,143 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * FBalliano
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ *
12
+ * DISCLAIMER
13
+ *
14
+ * Do not edit or add to this file if you wish to upgrade this Module to
15
+ * newer versions in the future.
16
+ *
17
+ * @category FBalliano
18
+ * @package FBalliano_FullCatalogTranslate
19
+ * @copyright Copyright (c) 2014 Fabrizio Balliano (http://fabrizioballiano.it)
20
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
21
+ */
22
+
23
+ require_once 'abstract.php';
24
+
25
+ class Fballiano_FullCatalogTranslate_Shell extends Mage_Shell_Abstract
26
+ {
27
+ protected $helper = null;
28
+ protected $api_key = null;
29
+ protected $store_source = null;
30
+ protected $store_dest = null;
31
+ protected $language_source = null;
32
+ protected $language_dest = null;
33
+ protected $ws_url = "https://www.googleapis.com/language/translate/v2";
34
+ protected $attributes_to_translate = null;
35
+ protected $datapump = null;
36
+
37
+ public function run()
38
+ {
39
+ $this->helper = Mage::helper("fballiano_fullcatalogtranslate");
40
+ $this->attributes_to_translate = $this->helper->getAttributesToTranslate();
41
+ $this->api_key = $this->helper->getApiKey();
42
+ if (!$this->api_key) die("Please set your API key in the Magento admin configuration.\n");
43
+ $this->ws_url .= "?key={$this->api_key}";
44
+
45
+ $args = array_keys($this->_args);
46
+ $this->store_source = @$args[0];
47
+ $this->store_dest = @$args[1];
48
+ if (!$this->store_source or !$this->store_dest) die($this->usageHelp());
49
+
50
+ require_once "Magmi/inc/magmi_defs.php";
51
+ require_once "Magmi/integration/inc/magmi_datapump.php";
52
+ require_once "Magmi/integration/inc/productimport_datapump.php";
53
+ require_once "Magmi/integration/inc/productimport_datapump.php";
54
+ $this->datapump = new Magmi_ProductImport_Datapump();
55
+ $this->datapump->beginImportSession("default", "create");
56
+
57
+ $appEmulation = Mage::getSingleton("core/app_emulation");
58
+
59
+ try {
60
+ $initialEnvironmentInfo = $appEmulation->startEnvironmentEmulation($this->store_dest);
61
+ } catch (Mage_Core_Model_Store_Exception $e) {
62
+ die("Target store view \"{$this->store_dest}\" doesn't seem to exist\n" . $this->usageHelp());
63
+ }
64
+
65
+ $store_id_dest = Mage::app()->getStore()->getId();
66
+ $this->language_dest = substr(Mage::app()->getLocale()->getLocaleCode(), 0, 2);
67
+ $this->ws_url .= "&target={$this->language_dest}";
68
+
69
+ $appEmulation->stopEnvironmentEmulation($initialEnvironmentInfo);
70
+
71
+ $attribute_id = Mage::getModel("catalog/entity_attribute")->loadByCode(Mage_Catalog_Model_Product::ENTITY, "fb_translate")->getId();
72
+ $table_name = Mage::getSingleton("core/resource")->getTableName("catalog_product_entity_int");
73
+ $products = Mage::getSingleton("core/resource")->getConnection("core_read")->fetchCol("SELECT entity_id FROM {$table_name} WHERE attribute_id={$attribute_id} AND store_id={$store_id_dest} AND value=1");
74
+
75
+ try {
76
+ $initialEnvironmentInfo = $appEmulation->startEnvironmentEmulation($this->store_source);
77
+ } catch (Mage_Core_Model_Store_Exception $e) {
78
+ die("Source store \"{$this->store_source}\" view doesn't seem to exist\n" . $this->usageHelp());
79
+ }
80
+
81
+ $this->language_source = substr(Mage::app()->getLocale()->getLocaleCode(), 0, 2);
82
+ $this->ws_url .= "&source={$this->language_source}";
83
+
84
+ $product = Mage::getModel("catalog/product");
85
+ foreach ($products as $product_id) {
86
+ $product->load($product_id);
87
+ $row = $product->getData();
88
+
89
+ echo "Translating {$row["sku"]} from {$this->language_source} to {$this->language_dest}... ";
90
+ $translated_row = array();
91
+ $translated_row["store"] = (string)$this->store_dest;
92
+ $translated_row["sku"] = (string)$row["sku"];
93
+ $translated_row["fb_translate"] = "0"; //leave it as string otherwise magmi won't save it
94
+ foreach ($this->attributes_to_translate as $attribute) {
95
+ if (strlen($row[$attribute])) {
96
+ $ws_url = "{$this->ws_url}&q=" . urlencode($row[$attribute]);
97
+ $translated = json_decode(file_get_contents($ws_url), true);
98
+ $translated = $translated["data"]["translations"][0]["translatedText"];
99
+ $translated_row[$attribute] = (string)$translated;
100
+ }
101
+ }
102
+ $this->datapump->ingest($translated_row);
103
+ echo "OK\n";
104
+ }
105
+
106
+ $appEmulation->stopEnvironmentEmulation($initialEnvironmentInfo);
107
+ $this->datapump->endImportSession();
108
+ echo "Terminated\n";
109
+ }
110
+
111
+ public function productCollectionWalkCallback($args)
112
+ {
113
+ $row = $args["row"];
114
+ echo "Translating {$row["sku"]} from {$this->language_source} to {$this->language_dest}... ";
115
+ $translated_row = array();
116
+ $translated_row["store"] = $this->store_dest;
117
+ $translated_row["sku"] = $row["sku"];
118
+ $translated_row["fb_translate"] = 0;
119
+ foreach ($this->attributes_to_translate as $attribute) {
120
+ if (strlen($row[$attribute])) {
121
+ $ws_url = "{$this->ws_url}&q=" . urlencode($row[$attribute]);
122
+ $translated = json_decode(file_get_contents($ws_url), true);
123
+ $translated = $translated["data"]["translations"][0]["translatedText"];
124
+ $translated_row[$attribute] = $translated;
125
+ }
126
+ }
127
+
128
+ $this->datapump->ingest($translated_row);
129
+ echo "OK\n";
130
+ }
131
+
132
+ public function usageHelp()
133
+ {
134
+ return <<<USAGE
135
+
136
+ Usage: php -f fballiano_full_catalog_translate.php source_store_view_code target_store_view_code
137
+
138
+ USAGE;
139
+ }
140
+ }
141
+
142
+ $shell = new Fballiano_FullCatalogTranslate_Shell();
143
+ $shell->run();