Ecocode_Profiler - Version 1.1.0

Version Notes

Download this release

Release Info

Developer Justus Krapp
Extension Ecocode_Profiler
Version 1.1.0
Comparing to
See all releases


Version 1.1.0

Files changed (171) hide show
  1. app/MageDev.php +42 -0
  2. app/code/community/Ecocode/Profiler/Block/Bag.php +23 -0
  3. app/code/community/Ecocode/Profiler/Block/Collector/Base.php +45 -0
  4. app/code/community/Ecocode/Profiler/Block/Collector/Layout/Panel.php +137 -0
  5. app/code/community/Ecocode/Profiler/Block/Collector/Log/Panel.php +98 -0
  6. app/code/community/Ecocode/Profiler/Block/Collector/Menu.php +14 -0
  7. app/code/community/Ecocode/Profiler/Block/Collector/Mysql/Panel.php +183 -0
  8. app/code/community/Ecocode/Profiler/Block/Collector/Translation/Panel.php +33 -0
  9. app/code/community/Ecocode/Profiler/Block/Profiler/Sidebar.php +33 -0
  10. app/code/community/Ecocode/Profiler/Block/Profiler/Sidebar/Menu.php +45 -0
  11. app/code/community/Ecocode/Profiler/Block/Renderer/AbstractRenderer.php +31 -0
  12. app/code/community/Ecocode/Profiler/Block/Renderer/BackTrace.php +36 -0
  13. app/code/community/Ecocode/Profiler/Block/Renderer/Context.php +16 -0
  14. app/code/community/Ecocode/Profiler/Block/Renderer/Log/LogTable.php +41 -0
  15. app/code/community/Ecocode/Profiler/Block/Renderer/Mysql/QueryTable.php +43 -0
  16. app/code/community/Ecocode/Profiler/Block/Renderer/RendererInterface.php +9 -0
  17. app/code/community/Ecocode/Profiler/Block/Toolbar.php +65 -0
  18. app/code/community/Ecocode/Profiler/Controller/AbstractController.php +52 -0
  19. app/code/community/Ecocode/Profiler/Db/Statement/Pdo/Mysql.php +94 -0
  20. app/code/community/Ecocode/Profiler/Helper/AbstractHelper.php +17 -0
  21. app/code/community/Ecocode/Profiler/Helper/Code.php +200 -0
  22. app/code/community/Ecocode/Profiler/Helper/Context.php +104 -0
  23. app/code/community/Ecocode/Profiler/Helper/Data.php +191 -0
  24. app/code/community/Ecocode/Profiler/Helper/Renderer.php +34 -0
  25. app/code/community/Ecocode/Profiler/Helper/Rewrite.php +163 -0
  26. app/code/community/Ecocode/Profiler/Helper/Sql.php +99 -0
  27. app/code/community/Ecocode/Profiler/Helper/ValueExporter.php +95 -0
  28. app/code/community/Ecocode/Profiler/Model/AppDev.php +149 -0
  29. app/code/community/Ecocode/Profiler/Model/Collector/AbstractDataCollector.php +82 -0
  30. app/code/community/Ecocode/Profiler/Model/Collector/AjaxDataCollector.php +27 -0
  31. app/code/community/Ecocode/Profiler/Model/Collector/CacheDataCollector.php +146 -0
  32. app/code/community/Ecocode/Profiler/Model/Collector/ConfigDataCollector.php +237 -0
  33. app/code/community/Ecocode/Profiler/Model/Collector/ContextDataCollector.php +45 -0
  34. app/code/community/Ecocode/Profiler/Model/Collector/CustomerDataCollector.php +91 -0
  35. app/code/community/Ecocode/Profiler/Model/Collector/DataCollectorInterface.php +24 -0
  36. app/code/community/Ecocode/Profiler/Model/Collector/EventDataCollector.php +97 -0
  37. app/code/community/Ecocode/Profiler/Model/Collector/LateDataCollectorInterface.php +12 -0
  38. app/code/community/Ecocode/Profiler/Model/Collector/LayoutDataCollector.php +175 -0
  39. app/code/community/Ecocode/Profiler/Model/Collector/LogDataCollector.php +217 -0
  40. app/code/community/Ecocode/Profiler/Model/Collector/MemoryDataCollector.php +113 -0
  41. app/code/community/Ecocode/Profiler/Model/Collector/ModelDataCollector.php +228 -0
  42. app/code/community/Ecocode/Profiler/Model/Collector/MysqlDataCollector.php +139 -0
  43. app/code/community/Ecocode/Profiler/Model/Collector/RequestDataCollector.php +488 -0
  44. app/code/community/Ecocode/Profiler/Model/Collector/RewriteDataCollector.php +62 -0
  45. app/code/community/Ecocode/Profiler/Model/Collector/TimeDataCollector.php +44 -0
  46. app/code/community/Ecocode/Profiler/Model/Collector/TranslationDataCollector.php +91 -0
  47. app/code/community/Ecocode/Profiler/Model/Context.php +56 -0
  48. app/code/community/Ecocode/Profiler/Model/ContextInterface.php +21 -0
  49. app/code/community/Ecocode/Profiler/Model/Core/Cache.php +46 -0
  50. app/code/community/Ecocode/Profiler/Model/Core/Config.php +56 -0
  51. app/code/community/Ecocode/Profiler/Model/DebugLoggerInterface.php +28 -0
  52. app/code/community/Ecocode/Profiler/Model/Http/HeaderBag.php +322 -0
  53. app/code/community/Ecocode/Profiler/Model/Http/ParameterBag.php +235 -0
  54. app/code/community/Ecocode/Profiler/Model/Http/ResponseHeaderBag.php +240 -0
  55. app/code/community/Ecocode/Profiler/Model/Logger.php +79 -0
  56. app/code/community/Ecocode/Profiler/Model/Logger/DebugHandler.php +60 -0
  57. app/code/community/Ecocode/Profiler/Model/Observer.php +116 -0
  58. app/code/community/Ecocode/Profiler/Model/Observer/Context.php +55 -0
  59. app/code/community/Ecocode/Profiler/Model/Profile.php +289 -0
  60. app/code/community/Ecocode/Profiler/Model/Profiler.php +172 -0
  61. app/code/community/Ecocode/Profiler/Model/Profiler/FileStorage.php +295 -0
  62. app/code/community/Ecocode/Profiler/Model/Profiler/StorageInterface.php +58 -0
  63. app/code/community/Ecocode/Profiler/Tests/Dev/Controller/AbstractControllerTest.php +70 -0
  64. app/code/community/Ecocode/Profiler/Tests/Dev/DevModeTest.php +33 -0
  65. app/code/community/Ecocode/Profiler/Tests/Dev/Fixtures/DummyCacheBackend.php +7 -0
  66. app/code/community/Ecocode/Profiler/Tests/Dev/Fixtures/ResponseHttp.php +10 -0
  67. app/code/community/Ecocode/Profiler/Tests/Dev/Helper/CodeTest.php +55 -0
  68. app/code/community/Ecocode/Profiler/Tests/Dev/Helper/ContextTest.php +136 -0
  69. app/code/community/Ecocode/Profiler/Tests/Dev/Helper/DataTest.php +94 -0
  70. app/code/community/Ecocode/Profiler/Tests/Dev/Helper/RewriteTest.php +124 -0
  71. app/code/community/Ecocode/Profiler/Tests/Dev/Helper/SqlTest.php +56 -0
  72. app/code/community/Ecocode/Profiler/Tests/Dev/Helper/ValueExporterTest.php +60 -0
  73. app/code/community/Ecocode/Profiler/Tests/Dev/Model/Collector/CacheDataCollectorTest.php +89 -0
  74. app/code/community/Ecocode/Profiler/Tests/Dev/Model/Collector/ConfigCollectorTest.php +51 -0
  75. app/code/community/Ecocode/Profiler/Tests/Dev/Model/Collector/ContextDataCollectorTest.php +54 -0
  76. app/code/community/Ecocode/Profiler/Tests/Dev/Model/Collector/CustomerDataCollectorTest.php +54 -0
  77. app/code/community/Ecocode/Profiler/Tests/Dev/Model/Collector/EventDataCollectorTest.php +68 -0
  78. app/code/community/Ecocode/Profiler/Tests/Dev/Model/Collector/LayoutDataCollectorTest.php +221 -0
  79. app/code/community/Ecocode/Profiler/Tests/Dev/Model/Collector/LogDataCollectorTest.php +84 -0
  80. app/code/community/Ecocode/Profiler/Tests/Dev/Model/Collector/MemoryDataCollectorTest.php +71 -0
  81. app/code/community/Ecocode/Profiler/Tests/Dev/Model/Collector/ModelDataCollectorTest.php +177 -0
  82. app/code/community/Ecocode/Profiler/Tests/Dev/Model/Collector/MysqlDataCollectorTest.php +23 -0
  83. app/code/community/Ecocode/Profiler/Tests/Dev/Model/Collector/RequestDataCollectorTest.php +158 -0
  84. app/code/community/Ecocode/Profiler/Tests/Dev/Model/Collector/RewriteDataCollectorTest.php +39 -0
  85. app/code/community/Ecocode/Profiler/Tests/Dev/Model/Collector/TimeDataCollectorTest.php +30 -0
  86. app/code/community/Ecocode/Profiler/Tests/Dev/Model/Collector/TranslationDataCollectorTest.php +79 -0
  87. app/code/community/Ecocode/Profiler/Tests/Dev/Model/Http/HeaderBagTest.php +192 -0
  88. app/code/community/Ecocode/Profiler/Tests/Dev/Model/Http/ParameterBagTest.php +181 -0
  89. app/code/community/Ecocode/Profiler/Tests/Dev/Model/Http/ResponseHeaderBagTest.php +160 -0
  90. app/code/community/Ecocode/Profiler/Tests/Dev/Model/LoggerTest.php +87 -0
  91. app/code/community/Ecocode/Profiler/Tests/Dev/Model/Observer/ContextTest.php +66 -0
  92. app/code/community/Ecocode/Profiler/Tests/Dev/Model/ObserverTest.php +163 -0
  93. app/code/community/Ecocode/Profiler/Tests/Dev/Model/Overwrite/MageCoreModelResourceDbAbstractTest.php +118 -0
  94. app/code/community/Ecocode/Profiler/Tests/Dev/Model/Overwrite/MageCoreModelResourceTest.php +29 -0
  95. app/code/community/Ecocode/Profiler/Tests/Dev/Model/Overwrite/MageCoreModelTranslateTest.php +66 -0
  96. app/code/community/Ecocode/Profiler/Tests/Dev/Model/Overwrite/MageEavModelEntityAbstractTest.php +111 -0
  97. app/code/community/Ecocode/Profiler/Tests/Dev/Model/Overwrite/MageTest.php +43 -0
  98. app/code/community/Ecocode/Profiler/Tests/Dev/Model/Profiler/FileStorageTest.php +346 -0
  99. app/code/community/Ecocode/Profiler/Tests/Dev/Model/ProfilerTest.php +58 -0
  100. app/code/community/Ecocode/Profiler/Tests/Dev/bootstrap.php +54 -0
  101. app/code/community/Ecocode/Profiler/Tests/Dev/controllers/CacheControllerTest.php +168 -0
  102. app/code/community/Ecocode/Profiler/Tests/Prod/DevModeTest.php +33 -0
  103. app/code/community/Ecocode/Profiler/Tests/Prod/bootstrap.php +51 -0
  104. app/code/community/Ecocode/Profiler/Tests/TestHelper.php +91 -0
  105. app/code/community/Ecocode/Profiler/autoloader.php +68 -0
  106. app/code/community/Ecocode/Profiler/controllers/CacheController.php +71 -0
  107. app/code/community/Ecocode/Profiler/controllers/IndexController.php +155 -0
  108. app/code/community/Ecocode/Profiler/debug.php +24 -0
  109. app/code/community/Ecocode/Profiler/etc/config.xml +8 -0
  110. app/code/community/Ecocode/Profiler/etc/development.xml +139 -0
  111. app/code/community/Ecocode/Profiler/overwrite/Mage.php +124 -0
  112. app/code/community/Ecocode/Profiler/overwrite/MageCoreModelResource.php +33 -0
  113. app/code/community/Ecocode/Profiler/overwrite/MageCoreModelResourceDbAbstract.php +83 -0
  114. app/code/community/Ecocode/Profiler/overwrite/MageCoreModelStore.php +35 -0
  115. app/code/community/Ecocode/Profiler/overwrite/MageCoreModelTranslate.php +154 -0
  116. app/code/community/Ecocode/Profiler/overwrite/MageEavModelEntityAbstract.php +70 -0
  117. app/design/frontend/base/default/layout/ecocode_profiler.xml +120 -0
  118. app/design/frontend/base/default/template/ecocode_profiler/back-trace.phtml +24 -0
  119. app/design/frontend/base/default/template/ecocode_profiler/bag.phtml +33 -0
  120. app/design/frontend/base/default/template/ecocode_profiler/collector/ajax/toolbar.phtml +38 -0
  121. app/design/frontend/base/default/template/ecocode_profiler/collector/base/menu.phtml +8 -0
  122. app/design/frontend/base/default/template/ecocode_profiler/collector/cache/menu.phtml +8 -0
  123. app/design/frontend/base/default/template/ecocode_profiler/collector/cache/panel.phtml +164 -0
  124. app/design/frontend/base/default/template/ecocode_profiler/collector/cache/toolbar.phtml +62 -0
  125. app/design/frontend/base/default/template/ecocode_profiler/collector/config/menu.phtml +10 -0
  126. app/design/frontend/base/default/template/ecocode_profiler/collector/config/panel.phtml +151 -0
  127. app/design/frontend/base/default/template/ecocode_profiler/collector/config/toolbar.phtml +79 -0
  128. app/design/frontend/base/default/template/ecocode_profiler/collector/customer/toolbar.phtml +45 -0
  129. app/design/frontend/base/default/template/ecocode_profiler/collector/event/menu.phtml +17 -0
  130. app/design/frontend/base/default/template/ecocode_profiler/collector/event/panel.phtml +116 -0
  131. app/design/frontend/base/default/template/ecocode_profiler/collector/layout/menu.phtml +15 -0
  132. app/design/frontend/base/default/template/ecocode_profiler/collector/layout/panel.phtml +69 -0
  133. app/design/frontend/base/default/template/ecocode_profiler/collector/layout/toolbar.phtml +48 -0
  134. app/design/frontend/base/default/template/ecocode_profiler/collector/log/menu.phtml +25 -0
  135. app/design/frontend/base/default/template/ecocode_profiler/collector/log/panel.phtml +118 -0
  136. app/design/frontend/base/default/template/ecocode_profiler/collector/log/panel/log-table.phtml +130 -0
  137. app/design/frontend/base/default/template/ecocode_profiler/collector/log/toolbar.phtml +52 -0
  138. app/design/frontend/base/default/template/ecocode_profiler/collector/memory/toolbar.phtml +31 -0
  139. app/design/frontend/base/default/template/ecocode_profiler/collector/model/menu.phtml +20 -0
  140. app/design/frontend/base/default/template/ecocode_profiler/collector/model/panel.phtml +177 -0
  141. app/design/frontend/base/default/template/ecocode_profiler/collector/model/toolbar.phtml +48 -0
  142. app/design/frontend/base/default/template/ecocode_profiler/collector/mysql/menu.phtml +19 -0
  143. app/design/frontend/base/default/template/ecocode_profiler/collector/mysql/panel.phtml +343 -0
  144. app/design/frontend/base/default/template/ecocode_profiler/collector/mysql/panel/query-table.phtml +63 -0
  145. app/design/frontend/base/default/template/ecocode_profiler/collector/mysql/toolbar.phtml +36 -0
  146. app/design/frontend/base/default/template/ecocode_profiler/collector/request/menu.phtml +22 -0
  147. app/design/frontend/base/default/template/ecocode_profiler/collector/request/panel.phtml +163 -0
  148. app/design/frontend/base/default/template/ecocode_profiler/collector/request/toolbar.phtml +51 -0
  149. app/design/frontend/base/default/template/ecocode_profiler/collector/rewrite/menu.phtml +22 -0
  150. app/design/frontend/base/default/template/ecocode_profiler/collector/rewrite/panel.phtml +77 -0
  151. app/design/frontend/base/default/template/ecocode_profiler/collector/rewrite/toolbar.phtml +40 -0
  152. app/design/frontend/base/default/template/ecocode_profiler/collector/time/toolbar.phtml +23 -0
  153. app/design/frontend/base/default/template/ecocode_profiler/collector/translation/menu.phtml +31 -0
  154. app/design/frontend/base/default/template/ecocode_profiler/collector/translation/panel.phtml +121 -0
  155. app/design/frontend/base/default/template/ecocode_profiler/collector/translation/panel/table.phtml +82 -0
  156. app/design/frontend/base/default/template/ecocode_profiler/collector/translation/toolbar.phtml +56 -0
  157. app/design/frontend/base/default/template/ecocode_profiler/layout.phtml +87 -0
  158. app/design/frontend/base/default/template/ecocode_profiler/layout/sidebar.phtml +103 -0
  159. app/design/frontend/base/default/template/ecocode_profiler/layout/sidebar/menu.phtml +22 -0
  160. app/design/frontend/base/default/template/ecocode_profiler/profiler/base.css.phtml +935 -0
  161. app/design/frontend/base/default/template/ecocode_profiler/profiler/base.js.phtml +464 -0
  162. app/design/frontend/base/default/template/ecocode_profiler/profiler/search/results.phtml +71 -0
  163. app/design/frontend/base/default/template/ecocode_profiler/profiler/search/summery.phtml +5 -0
  164. app/design/frontend/base/default/template/ecocode_profiler/profiler/summery.phtml +90 -0
  165. app/design/frontend/base/default/template/ecocode_profiler/renderer/context.phtml +30 -0
  166. app/design/frontend/base/default/template/ecocode_profiler/toolbar.css.phtml +479 -0
  167. app/design/frontend/base/default/template/ecocode_profiler/toolbar.phtml +75 -0
  168. app/design/frontend/base/default/template/ecocode_profiler/toolbar_js.phtml +81 -0
  169. app/etc/modules/Ecocode_Profiler.xml +9 -0
  170. dev.php +59 -0
  171. package.xml +448 -0
app/MageDev.php ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+
4
+ define('BP', MAGENTO_ROOT);
5
+ $ds = DIRECTORY_SEPARATOR;
6
+
7
+ /** AUTOLOADER PATCH **/
8
+ if (file_exists($autoloaderPath = BP . $ds . '../vendor/autoload.php') ||
9
+ file_exists($autoloaderPath = BP . $ds . 'vendor/autoload.php')
10
+ ) {
11
+ require $autoloaderPath;
12
+ }
13
+ /** AUTOLOADER PATCH **/
14
+
15
+
16
+
17
+
18
+ $profilerDir = implode(DIRECTORY_SEPARATOR, [MAGENTO_ROOT, 'app', 'code', 'community', 'Ecocode', 'Profiler']);
19
+ $profilerDir .= DIRECTORY_SEPARATOR;
20
+ define('PROFILER_DIR', $profilerDir);
21
+
22
+ $overwriteBasePath = $profilerDir . 'overwrite' . DIRECTORY_SEPARATOR;
23
+
24
+ require_once PROFILER_DIR . 'autoloader.php';
25
+ $autoloader = Ecocode_Profiler_Autoloader::getAutoloader();
26
+ $autoloader->register(true);
27
+
28
+
29
+ $autoloader
30
+ ->addOverwrite('Mage_Core_Model_Resource', 'MageCoreModelResource.php')
31
+ ->addOverwrite('Mage_Core_Model_Resource_Db_Abstract', 'MageCoreModelResourceDbAbstract.php')
32
+ ->addOverwrite('Mage_Core_Model_Store', 'MageCoreModelStore.php')
33
+ ->addOverwrite('Mage_Core_Model_Translate', 'MageCoreModelTranslate.php')
34
+ ->addOverwrite('Mage_Eav_Model_Entity_Abstract', 'MageEavModelEntityAbstract.php');
35
+
36
+ require_once $profilerDir . 'Helper' . DIRECTORY_SEPARATOR . 'Data.php';
37
+
38
+ require_once $overwriteBasePath . 'Mage.php';
39
+
40
+ //load overwrites so we can get around the autoloader
41
+ Mage::setRoot(MAGENTO_ROOT . DIRECTORY_SEPARATOR . 'app');
42
+
app/code/community/Ecocode/Profiler/Block/Bag.php ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Ecocode_Profiler_Block_Bag
5
+ *
6
+ * @method getBag
7
+ */
8
+ class Ecocode_Profiler_Block_Bag
9
+ extends Mage_Core_Block_Template
10
+ {
11
+ public function _construct()
12
+ {
13
+ $this->setTemplate('ecocode_profiler/bag.phtml');
14
+ parent::_construct();
15
+ }
16
+
17
+ public function getLabels()
18
+ {
19
+ $labels = $this->getData('labels');
20
+
21
+ return $labels ? $labels : [];
22
+ }
23
+ }
app/code/community/Ecocode/Profiler/Block/Collector/Base.php ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Ecocode_Profiler_Block_Collector_Base
5
+ */
6
+ class Ecocode_Profiler_Block_Collector_Base
7
+ extends Mage_Core_Block_Template
8
+ {
9
+ /** @var Ecocode_Profiler_Model_Collector_DataCollectorInterface */
10
+ protected $collector;
11
+
12
+ /** @var Ecocode_Profiler_Model_Profile */
13
+ protected $profile;
14
+
15
+ public function setCollector(Ecocode_Profiler_Model_Collector_DataCollectorInterface $collector)
16
+ {
17
+ $this->collector = $collector;
18
+ }
19
+
20
+ public function getCollector()
21
+ {
22
+ return $this->collector;
23
+ }
24
+
25
+ /**
26
+ * @return Ecocode_Profiler_Model_Profile
27
+ */
28
+ public function getProfile()
29
+ {
30
+ if ($this->profile === null) {
31
+ $this->profile = Mage::registry('current_profile');
32
+ }
33
+ return $this->profile;
34
+ }
35
+
36
+ public function renderBag($bag, array $data = [])
37
+ {
38
+ /** @var Ecocode_Profiler_Block_Bag $bagBlock */
39
+ $bagBlock = $this->getLayout()->createBlock('ecocode_profiler/bag');
40
+ $data['bag'] = $bag;
41
+ $bagBlock->setData($data);
42
+
43
+ return $bagBlock->toHtml();
44
+ }
45
+ }
app/code/community/Ecocode/Profiler/Block/Collector/Layout/Panel.php ADDED
@@ -0,0 +1,137 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Ecocode_Profiler_Block_Collector_Layout_Panel
5
+ */
6
+ class Ecocode_Profiler_Block_Collector_Layout_Panel
7
+ extends Ecocode_Profiler_Block_Collector_Base
8
+ {
9
+ protected $tree;
10
+
11
+ private static $colors = [
12
+ 'block' => '#dfd',
13
+ 'macro' => '#ddf',
14
+ 'template' => '#ffd',
15
+ 'big' => '#d44',
16
+ ];
17
+
18
+ public function renderTree()
19
+ {
20
+ $html = '';
21
+ foreach ($this->getCallTree() as $node) {
22
+ $html .= $this->renderNode($node);
23
+ }
24
+
25
+ return '<pre>' . $html . '</pre>';
26
+ }
27
+
28
+ protected function renderNode($node, $prefix = '', $sibling = false)
29
+ {
30
+ if (!$node['parent_id']) {
31
+ $start = $node['name'];
32
+ } else {
33
+ if (isset($node['template'])) {
34
+ $start = $this->_formatTemplate($node, $prefix);
35
+ } else {
36
+ $start = $this->_formatBlock($node, $prefix);
37
+ }
38
+ if ($node['cacheable']) {
39
+ $start .= '<span class="label">cacheable</span>';
40
+ }
41
+ $prefix .= $sibling ? '│ ' : ' ';
42
+ }
43
+ $percent = $node['render_time_percent'] *= 100;
44
+
45
+ if (false && $node['render_time'] * 1000 < 1) {
46
+ $str = $start . "\n";
47
+ } else {
48
+ $str = sprintf("%s %s\n", $start, $this->_formatTime($node, $percent));
49
+ }
50
+
51
+ if ($node['children']) {
52
+ $nCount = count($node['children']);
53
+ $index = 0;
54
+ foreach ($node['children'] as $childNode) {
55
+ $index++;
56
+ $str .= $this->renderNode($childNode, $prefix, $index !== $nCount);
57
+ }
58
+ }
59
+ return $str;
60
+ }
61
+
62
+
63
+ public function getCallTree()
64
+ {
65
+ if (!$this->tree) {
66
+ $this->tree = $this->createCallTree();
67
+ }
68
+
69
+ return $this->tree;
70
+ }
71
+
72
+ protected function createCallTree()
73
+ {
74
+ $tree = [];
75
+ /** @var Ecocode_Profiler_Model_Collector_LayoutDataCollector $collector */
76
+ $collector = $this->getCollector();
77
+ $totalRenderTime = $collector->getTotalRenderTime();
78
+ $nodeList = $collector->getRenderLog();
79
+ foreach ($nodeList as $id => &$node) {
80
+ $node['render_time_percent'] = $node['render_time_incl'] / $totalRenderTime;
81
+ }
82
+ foreach ($nodeList as $id => &$node) {
83
+ $nodeList[$id] = $node;
84
+ if ($node['parent_id'] === false) {
85
+ $this->resolveChildren($node, $nodeList);
86
+ $tree[$id] = $node;
87
+ }
88
+ }
89
+
90
+ return $tree;
91
+ }
92
+
93
+ protected function resolveChildren(&$node, array $nodeList)
94
+ {
95
+ $children = [];
96
+ if (isset($node['children'])) {
97
+ foreach ($node['children'] as $childId) {
98
+ $child = $nodeList[$childId];
99
+
100
+ $this->resolveChildren($child, $nodeList);
101
+ $children[$childId] = $child;
102
+ }
103
+ }
104
+ $node['children'] = $children;
105
+ }
106
+
107
+
108
+ protected function _formatTemplate($blockData, $prefix)
109
+ {
110
+ return sprintf(
111
+ '%sâ”” <span style="background-color: %s">%s (%s) <small>%s::%s</small></span>',
112
+ $prefix,
113
+ self::$colors['template'],
114
+ $blockData['name'],
115
+ $blockData['type'],
116
+ $blockData['class'],
117
+ $blockData['template']
118
+ );
119
+ }
120
+
121
+ protected function _formatBlock($blockData, $prefix)
122
+ {
123
+ return sprintf(
124
+ '%sâ”” <span style="background-color: %s">%s (%s) <small>%s</small></span>',
125
+ $prefix, self::$colors['block'],
126
+ $blockData['name'],
127
+ $blockData['type'],
128
+ $blockData['class']
129
+ );
130
+ }
131
+
132
+ protected function _formatTime($node, $percent)
133
+ {
134
+ return sprintf('<span style="color: %s">%.2fms/%.0f%% (excl. %.2fms)</span>', $percent > 20 ? self::$colors['big'] : 'auto', $node['render_time_incl'] * 1000, $percent, $node['render_time'] * 1000);
135
+ }
136
+
137
+ }
app/code/community/Ecocode/Profiler/Block/Collector/Log/Panel.php ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Ecocode_Profiler_Block_Collector_Log_Panel
5
+ */
6
+ class Ecocode_Profiler_Block_Collector_Log_Panel
7
+ extends Ecocode_Profiler_Block_Collector_Base
8
+ {
9
+ protected $logTableRenderer;
10
+ protected $logGroups;
11
+
12
+ protected $priorityNames = [
13
+ Zend_Log::EMERG => 'emergency',
14
+ Zend_Log::ALERT => 'emergency',
15
+ Zend_Log::CRIT => 'critical',
16
+ Zend_Log::ERR => 'error',
17
+ Zend_Log::WARN => 'warning',
18
+ Zend_Log::NOTICE => 'notice',
19
+ Zend_Log::INFO => 'info',
20
+ Zend_Log::DEBUG => 'debug',
21
+ ];
22
+
23
+
24
+ public function getLogGroups()
25
+ {
26
+ if ($this->logGroups === null) {
27
+ $logGroups = [
28
+ 'deprecation' => [],
29
+ 'debug' => [],
30
+ 'info_and_error' => [],
31
+ 'silenced' => []
32
+ ];
33
+
34
+ /** @var Ecocode_Profiler_Model_Collector_LogDataCollector $collector */
35
+ $collector = $this->getCollector();
36
+ foreach ($collector->getLogs() as $log) {
37
+ if (isset($log['context']['level'], $log['context']['type']) && in_array($log['context']['type'], [E_DEPRECATED, E_USER_DEPRECATED])) {
38
+ $logGroups['deprecation'][] = $log;
39
+ } elseif (isset($log['context']['scream']) && $log['context']['scream'] === true) {
40
+ $logGroups['silenced'][] = $log;
41
+ } elseif ($log['priorityName'] === 'DEBUG') {
42
+ $logGroups['debug'][] = $log;
43
+ } else {
44
+ $logGroups['info_and_error'][] = $log;
45
+ }
46
+ }
47
+ $this->logGroups = $logGroups;
48
+ }
49
+
50
+ return $this->logGroups;
51
+ }
52
+
53
+ public function getPriorityName($level)
54
+ {
55
+ $names = $this->priorityNames;
56
+ if (isset($names[$level])) {
57
+ return $names[$level];
58
+ }
59
+
60
+ return 'unknown';
61
+ }
62
+
63
+ public function getEntryCssClass($level)
64
+ {
65
+ if ($level <= 3) {
66
+ return 'status-error';
67
+ }
68
+ if ($level <= 5) {
69
+ return 'status-warning';
70
+ }
71
+
72
+ return '';
73
+ }
74
+
75
+
76
+ public function renderLogTable($logs, $category = '', $showLevel = false, $isDeprecation = false)
77
+ {
78
+ $block = $this->getLogTableRenderer();
79
+ $block->setData([
80
+ 'logs' => $logs,
81
+ 'category' => $category,
82
+ 'show_level' => $showLevel,
83
+ 'is_deprecation' => $isDeprecation
84
+ ]);
85
+ return $block->toHtml();
86
+ }
87
+
88
+ /**
89
+ * @return $this
90
+ */
91
+ public function getLogTableRenderer()
92
+ {
93
+ if ($this->logTableRenderer === null) {
94
+ $this->logTableRenderer = Mage::app()->getLayout()->createBlock('ecocode_profiler/renderer_log_logTable');
95
+ }
96
+ return $this->logTableRenderer;
97
+ }
98
+ }
app/code/community/Ecocode/Profiler/Block/Collector/Menu.php ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Ecocode_Profiler_Block_Collector_Menu
5
+ */
6
+ class Ecocode_Profiler_Block_Collector_Menu extends
7
+ Ecocode_Profiler_Block_Collector_Base
8
+ {
9
+ public function _construct()
10
+ {
11
+ parent::_construct();
12
+ $this->setTemplate('ecocode_profiler/collector/base/menu.phtml');
13
+ }
14
+ }
app/code/community/Ecocode/Profiler/Block/Collector/Mysql/Panel.php ADDED
@@ -0,0 +1,183 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Ecocode_Profiler_Block_Collector_Mysql_Panel
5
+ */
6
+ class Ecocode_Profiler_Block_Collector_Mysql_Panel
7
+ extends Ecocode_Profiler_Block_Collector_Base
8
+ {
9
+
10
+
11
+ protected $sqlHelper;
12
+ protected $queryTableRenderer;
13
+
14
+ protected $queries;
15
+ protected $identicalQueries;
16
+ protected $queriesByContext;
17
+ protected $queryCountByType;
18
+
19
+ public function _construct()
20
+ {
21
+ //ban cache usage as we dont need the cache and it causes some overhead
22
+ Mage::app()->getCacheInstance()->banUse(Mage_Core_Block_Abstract::CACHE_GROUP);
23
+
24
+ $this->setTemplate('ecocode_profiler/collector/mysql/panel.phtml');
25
+ parent::_construct();
26
+ }
27
+
28
+ public function prepareQueryData()
29
+ {
30
+ $this->queries = [];
31
+ $this->identicalQueries = [];
32
+ $this->queriesByContext = [];
33
+ $this->queryCountByType = [
34
+ 'select' => 0,
35
+ 'insert' => 0,
36
+ 'update' => 0,
37
+ 'delete' => 0
38
+ ];
39
+
40
+ /** @var Ecocode_Profiler_Model_Collector_MysqlDataCollector $collector */
41
+ $collector = $this->getCollector();
42
+
43
+ foreach ($collector->getQueries() as &$queryData) {
44
+ $this->processType($queryData);
45
+ $this->preRenderQuery($queryData);
46
+ $this->processIdentical($queryData);
47
+ $this->processContext($queryData);
48
+ $this->queries[] = $queryData;
49
+ }
50
+
51
+ usort($this->queriesByContext, function ($a, $b) {
52
+ return $b['count'] - $a['count'];
53
+ });
54
+
55
+ usort($this->identicalQueries, function ($a, $b) {
56
+ return $b['count'] - $a['count'];
57
+ });
58
+
59
+ $this->identicalQueries = array_filter($this->identicalQueries, function ($item) {
60
+ return $item['count'] > 1;
61
+ });
62
+
63
+
64
+ return $this;
65
+ }
66
+
67
+ protected function processType(array &$queryData)
68
+ {
69
+ $sql = $queryData['sql'];
70
+ $type = explode(' ', $sql, 2);
71
+ $type = reset($type);
72
+ $type = strtolower($type);
73
+
74
+ if (isset($this->queryCountByType[$type])) {
75
+ $this->queryCountByType[$type]++;
76
+ }
77
+
78
+ $queryData['type'] = $type;
79
+ }
80
+
81
+ protected function processIdentical(array $queryData)
82
+ {
83
+ $queryId = md5($queryData['sql'] . implode(',', $queryData['params']));
84
+
85
+ if (!isset($this->identicalQueries[$queryId])) {
86
+ $this->identicalQueries[$queryId] = [
87
+ 'id' => $queryId,
88
+ 'count' => 0,
89
+ 'total_time' => 0,
90
+ 'query' => $queryData,
91
+ 'traces' => []
92
+ ];
93
+ }
94
+ $this->identicalQueries[$queryId]['count']++;
95
+ $this->identicalQueries[$queryId]['total_time'] += $queryData['time'];
96
+ $this->identicalQueries[$queryId]['traces'][] = $queryData['trace'];
97
+ }
98
+
99
+ protected function processContext(array $queryData)
100
+ {
101
+ $contextKey = $queryData['context'];
102
+ if (!isset($this->queriesByContext[$contextKey])) {
103
+ $this->queriesByContext[$contextKey] = [
104
+ 'name' => $contextKey,
105
+ 'count' => 0,
106
+ 'total_time' => 0,
107
+ 'queries' => []
108
+ ];
109
+ }
110
+
111
+ $this->queriesByContext[$contextKey]['count']++;
112
+ $this->queriesByContext[$contextKey]['total_time'] += $queryData['time'];
113
+ $this->queriesByContext[$contextKey]['queries'][] = $queryData;
114
+ }
115
+
116
+ public function getIdenticalQueries()
117
+ {
118
+ if ($this->identicalQueries === null) {
119
+ $this->prepareQueryData();
120
+ }
121
+ return $this->identicalQueries;
122
+ }
123
+
124
+ public function preRenderQuery(array &$queryData)
125
+ {
126
+ $queryTableRenderer = $this->getQueryTableRenderer();
127
+
128
+ $queryData['sql_highlighted'] = $queryTableRenderer->formatQuery($queryData['sql'], true);
129
+ $queryData['sql_formatted'] = $queryTableRenderer->formatQuery($queryData['sql']);
130
+ $queryData['sql_runnable'] = $queryTableRenderer->formatQuery(
131
+ $queryTableRenderer->replaceQueryParameters($queryData['sql'], $queryData['params']),
132
+ true
133
+ );
134
+ }
135
+
136
+ public function getQueries()
137
+ {
138
+ if ($this->queries === null) {
139
+ $this->prepareQueryData();
140
+ }
141
+ return $this->queries;
142
+ }
143
+
144
+ public function getQueryCountByType()
145
+ {
146
+ if ($this->queryCountByType === null) {
147
+ $this->prepareQueryData();
148
+ $this->queryCountByType = array_filter($this->queryCountByType);
149
+ }
150
+ return $this->queryCountByType;
151
+ }
152
+
153
+ public function getByContext()
154
+ {
155
+ if ($this->queriesByContext === null) {
156
+ $this->prepareQueryData();
157
+ }
158
+ return $this->queriesByContext;
159
+ }
160
+
161
+
162
+ public function renderQueryTable($prefix, array $queries)
163
+ {
164
+ $prefix .= '-';
165
+ $block = $this->getQueryTableRenderer();
166
+ $block->setData([
167
+ 'queries' => $queries,
168
+ 'prefix' => $prefix
169
+ ]);
170
+ return $block->toHtml();
171
+ }
172
+
173
+ /**
174
+ * @return $this
175
+ */
176
+ public function getQueryTableRenderer()
177
+ {
178
+ if ($this->queryTableRenderer === null) {
179
+ $this->queryTableRenderer = Mage::app()->getLayout()->createBlock('ecocode_profiler/renderer_mysql_queryTable');
180
+ }
181
+ return $this->queryTableRenderer;
182
+ }
183
+ }
app/code/community/Ecocode/Profiler/Block/Collector/Translation/Panel.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Ecocode_Profiler_Block_Collector_Translation_Panel
5
+ */
6
+ class Ecocode_Profiler_Block_Collector_Translation_Panel
7
+ extends Ecocode_Profiler_Block_Collector_Base
8
+ {
9
+
10
+
11
+ public function getMessageGroups()
12
+ {
13
+ /** @var Ecocode_Profiler_Model_Collector_TranslationDataCollector $collector */
14
+ $collector = $this->getCollector();
15
+ $statusCounts = $collector->getStateCount();
16
+
17
+ $groups = array_fill_keys(array_keys($statusCounts), []);
18
+
19
+ foreach ($collector->getTranslations() as $message) {
20
+ $groups[$message['state']][] = $message;
21
+ }
22
+
23
+ return $groups;
24
+ }
25
+
26
+ public function renderTable(array $messages)
27
+ {
28
+ $tableBlock = $this->getLayout()->createBlock('core/template');
29
+ $tableBlock->setTemplate('ecocode_profiler/collector/translation/panel/table.phtml');
30
+ $tableBlock->setData('messages', $messages);
31
+ return $tableBlock->toHtml();
32
+ }
33
+ }
app/code/community/Ecocode/Profiler/Block/Profiler/Sidebar.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Ecocode_Profiler_Block_Profiler_Sidebar
5
+ */
6
+ class Ecocode_Profiler_Block_Profiler_Sidebar
7
+ extends Mage_Core_Block_Template
8
+ {
9
+ protected $profile = null;
10
+
11
+ public function _construct()
12
+ {
13
+ $this->setTemplate('ecocode_profiler/layout/sidebar.phtml');
14
+ parent::_construct();
15
+ }
16
+
17
+ public function getCollector()
18
+ {
19
+ return $this->getProfile()->getCollector(Mage::registry('current_panel'));
20
+ }
21
+
22
+ /**
23
+ * @return Ecocode_Profiler_Model_Profile
24
+ */
25
+ public function getProfile()
26
+ {
27
+ if ($this->profile === null) {
28
+ $this->profile = Mage::registry('current_profile');
29
+ }
30
+
31
+ return $this->profile;
32
+ }
33
+ }
app/code/community/Ecocode/Profiler/Block/Profiler/Sidebar/Menu.php ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Ecocode_Profiler_Block_Profiler_Sidebar_Menu
5
+ */
6
+ class Ecocode_Profiler_Block_Profiler_Sidebar_Menu extends Mage_Core_Block_Template
7
+ {
8
+ protected $profile = null;
9
+
10
+ public function getMenuBlocks()
11
+ {
12
+ if (!$this->getProfile()) {
13
+ return [];
14
+ }
15
+
16
+ $blocks = [];
17
+
18
+ $collectors = $this->getProfile()->getCollectors();
19
+ foreach ($this->getSortedChildBlocks() as $name => $block) {
20
+ if (!$block instanceof Ecocode_Profiler_Block_Collector_Base) {
21
+ continue;
22
+ }
23
+
24
+ if(!isset($collectors[$name])) {
25
+ continue;
26
+ }
27
+ $block->setCollector($collectors[$name]);
28
+ $blocks[$collectors[$name]->getName()] = $block;
29
+ }
30
+
31
+ return $blocks;
32
+ }
33
+
34
+ /**
35
+ * @return Ecocode_Profiler_Model_Profile
36
+ */
37
+ public function getProfile()
38
+ {
39
+ if ($this->profile === null) {
40
+ $this->profile = Mage::registry('current_profile');
41
+ }
42
+
43
+ return $this->profile;
44
+ }
45
+ }
app/code/community/Ecocode/Profiler/Block/Renderer/AbstractRenderer.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Ecocode_Profiler_Block_Renderer_AbstractRenderer
5
+ *
6
+ * @method getBag
7
+ */
8
+ class Ecocode_Profiler_Block_Renderer_AbstractRenderer
9
+ extends Mage_Core_Block_Template
10
+ implements Ecocode_Profiler_Block_Renderer_RendererInterface
11
+ {
12
+ protected $_templateFileCache = [];
13
+
14
+ public function render(array $data = [])
15
+ {
16
+ $this->setData($data);
17
+ return $this->toHtml();
18
+ }
19
+
20
+ public function getTemplateFile()
21
+ {
22
+ $template = $this->getTemplate();
23
+ $key = $this->getArea() . '_' . $template;
24
+
25
+ if (!isset($this->_templateFileCache[$key])) {
26
+ $this->_templateFileCache[$key] = parent::getTemplateFile();
27
+ }
28
+
29
+ return $this->_templateFileCache[$key];
30
+ }
31
+ }
app/code/community/Ecocode/Profiler/Block/Renderer/BackTrace.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Ecocode_Profiler_Block_Bag
5
+ *
6
+ * @method getBag
7
+ */
8
+ class Ecocode_Profiler_Block_Renderer_BackTrace
9
+ extends Ecocode_Profiler_Block_Renderer_AbstractRenderer
10
+ {
11
+ public function _construct()
12
+ {
13
+ $this->setTemplate('ecocode_profiler/back-trace.phtml');
14
+ parent::_construct();
15
+ }
16
+
17
+ public function getTraceId()
18
+ {
19
+ $id = $this->getData('id');
20
+ if (!$id) {
21
+ $this->setData('id', uniqid());
22
+ }
23
+
24
+ return $id;
25
+ }
26
+
27
+ public function getTrace()
28
+ {
29
+ $trace = $this->getData('trace');
30
+ if (!$trace) {
31
+ return [];
32
+ }
33
+
34
+ return $trace;
35
+ }
36
+ }
app/code/community/Ecocode/Profiler/Block/Renderer/Context.php ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Ecocode_Profiler_Block_Renderer_Context
5
+ *
6
+ * @method getBag
7
+ */
8
+ class Ecocode_Profiler_Block_Renderer_Context
9
+ extends Ecocode_Profiler_Block_Renderer_AbstractRenderer
10
+ {
11
+ public function _construct()
12
+ {
13
+ $this->setTemplate('ecocode_profiler/renderer/context.phtml');
14
+ parent::_construct();
15
+ }
16
+ }
app/code/community/Ecocode/Profiler/Block/Renderer/Log/LogTable.php ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Ecocode_Profiler_Block_Renderer_Log_LogTable
5
+ */
6
+ class Ecocode_Profiler_Block_Renderer_Log_LogTable
7
+ extends Ecocode_Profiler_Block_Renderer_AbstractRenderer
8
+ {
9
+ public function _construct()
10
+ {
11
+ $this->setTemplate('ecocode_profiler/collector/log/panel/log-table.phtml');
12
+ parent::_construct();
13
+ }
14
+
15
+ public function getCategory()
16
+ {
17
+ return isset($this->_data['category']) ? $this->_data['category'] : [];
18
+ }
19
+
20
+ public function getLogs()
21
+ {
22
+ return isset($this->_data['logs']) ? $this->_data['logs'] : [];
23
+ }
24
+
25
+ public function getShowLevel()
26
+ {
27
+ return isset($this->_data['show_level']) ? $this->_data['show_level'] : true;
28
+ }
29
+
30
+ public function isDeprecation()
31
+ {
32
+ return isset($this->_data['is_deprecation']) ? $this->_data['is_deprecation'] : false;
33
+ }
34
+
35
+ public function isChannelDefined()
36
+ {
37
+ $logs = $this->getLogs();
38
+ $log = reset($logs);
39
+ return isset($log['channel']);
40
+ }
41
+ }
app/code/community/Ecocode/Profiler/Block/Renderer/Mysql/QueryTable.php ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Ecocode_Profiler_Block_Renderer_Context
5
+ */
6
+ class Ecocode_Profiler_Block_Renderer_Mysql_QueryTable
7
+ extends Ecocode_Profiler_Block_Renderer_AbstractRenderer
8
+ {
9
+ protected $sqlHelper;
10
+
11
+ public function _construct()
12
+ {
13
+ $this->setTemplate('ecocode_profiler/collector/mysql/panel/query-table.phtml');
14
+ parent::_construct();
15
+ }
16
+
17
+
18
+ public function replaceQueryParameters($query, array $parameters)
19
+ {
20
+ return $this->getSqlHelper()->replaceQueryParameters($query, $parameters);
21
+ }
22
+
23
+ public function dumpParameters(array $parameters)
24
+ {
25
+ return $this->getSqlHelper()->dumpParameters($parameters);
26
+ }
27
+
28
+ public function formatQuery($sql, $highlightOnly = false)
29
+ {
30
+ return $this->getSqlHelper()->formatQuery($sql, $highlightOnly);
31
+ }
32
+
33
+ /**
34
+ * @return Ecocode_Profiler_Helper_Sql
35
+ */
36
+ public function getSqlHelper()
37
+ {
38
+ if ($this->sqlHelper === null) {
39
+ $this->sqlHelper = Mage::helper('ecocode_profiler/sql');
40
+ }
41
+ return $this->sqlHelper;
42
+ }
43
+ }
app/code/community/Ecocode/Profiler/Block/Renderer/RendererInterface.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Interface Ecocode_Profiler_Block_Renderer_RendererInterface
5
+ */
6
+ interface Ecocode_Profiler_Block_Renderer_RendererInterface
7
+ {
8
+ public function render(array $data = []);
9
+ }
app/code/community/Ecocode/Profiler/Block/Toolbar.php ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Ecocode_Profiler_Block_Toolbar
4
+ extends Mage_Core_Block_Template
5
+ {
6
+ protected $profile = null;
7
+ protected $collectors = null;
8
+
9
+ public function _construct()
10
+ {
11
+ $this->setTemplate('ecocode_profiler/toolbar_js.phtml');
12
+ parent::_construct();
13
+ }
14
+
15
+ public function getToken()
16
+ {
17
+ if ($this->getData('token')) {
18
+ return $this->getData('token');
19
+ }
20
+
21
+ if ($this->getProfile()) {
22
+ return $this->getProfile()->getToken();
23
+ }
24
+ return false;
25
+ }
26
+
27
+ public function getCollectors()
28
+ {
29
+ if ($this->collectors === null) {
30
+ $this->collectors = $this->getProfile()->getCollectors();
31
+
32
+ }
33
+ return $this->collectors;
34
+ }
35
+
36
+ public function getToolbarItems()
37
+ {
38
+ $blocks = [];
39
+
40
+ $layout = $this->getLayout();
41
+ foreach ($this->getCollectors() as $collector) {
42
+ /** @var Ecocode_Profiler_Model_Collector_DataCollectorInterface $collector */
43
+ if (!$block = $layout->getBlock($collector->getBlockToolbarName())) {
44
+ continue;
45
+ }
46
+ $block->setCollector($collector);
47
+ $block->setData('token', $this->getToken());
48
+ $blocks[$collector->getName()] = $block;
49
+ }
50
+
51
+ return $blocks;
52
+ }
53
+
54
+ /**
55
+ * @return Ecocode_Profiler_Model_Profile
56
+ */
57
+ public function getProfile()
58
+ {
59
+ if ($this->profile === null) {
60
+ $this->profile = Mage::registry('current_profile');
61
+ }
62
+
63
+ return $this->profile;
64
+ }
65
+ }
app/code/community/Ecocode/Profiler/Controller/AbstractController.php ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Ecocode_Profiler_AbstractController
5
+ */
6
+ class Ecocode_Profiler_Controller_AbstractController
7
+ extends Mage_Core_Controller_Front_Action
8
+ {
9
+ /** @var Ecocode_Profiler_Model_Profiler */
10
+ protected $profiler;
11
+
12
+ public function preDispatch()
13
+ {
14
+ $app = $this->getApp();
15
+ //should not be needed as we do not include development.xml
16
+ //in production anyway
17
+ if (!$app instanceof Ecocode_Profiler_Model_AppDev) {
18
+ throw new \RuntimeException('You are not allowed to access this file. Check ' . basename(__FILE__) . ' for more information.');
19
+ }
20
+
21
+ /** @var Mage_Core_Model_Config $config */
22
+ $config = $app->getConfig();
23
+
24
+ //disable before/after to html observer as its quiet costly
25
+ $config->setNode('frontend/events/core_block_abstract_to_html_before/observers/ecocode_profiler_context/type', 'disabled');
26
+ $config->setNode('frontend/events/core_block_abstract_to_html_after/observers/ecocode_profiler_context/type', 'disabled');
27
+
28
+ parent::preDispatch();
29
+ return $this;
30
+ }
31
+
32
+ /**
33
+ * @codeCoverageIgnore
34
+ * @return Mage_Core_Model_App
35
+ */
36
+ protected function getApp()
37
+ {
38
+ return Mage::app();
39
+ }
40
+
41
+ /**
42
+ * @codeCoverageIgnore
43
+ * @return Ecocode_Profiler_Model_Profiler
44
+ */
45
+ protected function getProfiler()
46
+ {
47
+ if (!$this->profiler) {
48
+ $this->profiler = Mage::getSingleton('ecocode_profiler/profiler');
49
+ }
50
+ return $this->profiler;
51
+ }
52
+ }
app/code/community/Ecocode/Profiler/Db/Statement/Pdo/Mysql.php ADDED
@@ -0,0 +1,94 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Ecocode_Profiler_Db_Statement_Pdo_Mysql
5
+ *
6
+ */
7
+ class Ecocode_Profiler_Db_Statement_Pdo_Mysql extends Varien_Db_Statement_Pdo_Mysql
8
+ {
9
+ protected $elapsedTime;
10
+ protected $params;
11
+ protected $result;
12
+
13
+ /**
14
+ * Executes statement with binding values to it.
15
+ * Allows transferring specific options to DB driver.
16
+ *
17
+ * @param array $params Array of values to bind to parameter placeholders.
18
+ * @return bool
19
+ * @throws Zend_Db_Statement_Exception
20
+ */
21
+ public function _executeWithBinding(array $params)
22
+ {
23
+ $this->params = $params;
24
+ $start = microtime(true);
25
+
26
+ $this->result = parent::_executeWithBinding($params);
27
+
28
+ $this->elapsedTime = microtime(true) - $start;
29
+ $this->log();
30
+ return $this->result;
31
+ }
32
+
33
+ /**
34
+ * Executes a prepared statement.
35
+ *
36
+ * @param array $params OPTIONAL Values to bind to parameter placeholders.
37
+ * @return bool
38
+ * @throws Zend_Db_Statement_Exception
39
+ */
40
+ public function _execute(array $params = null)
41
+ {
42
+ $this->params = $params;
43
+ $start = microtime(true);
44
+
45
+ $this->result = parent::_execute($params);
46
+
47
+ $this->elapsedTime = microtime(true) - $start;
48
+ $this->log();
49
+
50
+ return $this->result;
51
+ }
52
+
53
+ protected function log()
54
+ {
55
+ $this->getCollector()->logQuery($this);
56
+ }
57
+
58
+ /**
59
+ * @return Ecocode_Profiler_Model_Collector_MysqlDataCollector
60
+ */
61
+ public function getCollector()
62
+ {
63
+ return Mage::getSingleton('ecocode_profiler/collector_mysqlDataCollector');
64
+ }
65
+
66
+ public function getQueryString()
67
+ {
68
+ return $this->_stmt->queryString;
69
+ }
70
+
71
+ /**
72
+ * @return mixed
73
+ */
74
+ public function getElapsedTime()
75
+ {
76
+ return $this->elapsedTime;
77
+ }
78
+
79
+ /**
80
+ * @return mixed
81
+ */
82
+ public function getParams()
83
+ {
84
+ return $this->params;
85
+ }
86
+
87
+ /**
88
+ * @return mixed
89
+ */
90
+ public function getResult()
91
+ {
92
+ return $this->result;
93
+ }
94
+ }
app/code/community/Ecocode/Profiler/Helper/AbstractHelper.php ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Ecocode_Profiler_Helper_AbstractHelper
5
+ */
6
+ abstract class Ecocode_Profiler_Helper_AbstractHelper
7
+ {
8
+
9
+ /**
10
+ * @return null|Ecocode_Profiler_Model_Profile
11
+ * @codeCoverageIgnore
12
+ */
13
+ public function getCurrentProfile()
14
+ {
15
+ return Mage::registry('current_profile');
16
+ }
17
+ }
app/code/community/Ecocode/Profiler/Helper/Code.php ADDED
@@ -0,0 +1,200 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+
4
+ /**
5
+ * Twig extension relate to PHP code and used by the profiler and the default exception templates.
6
+ *
7
+ * @author Fabien Potencier <fabien@symfony.com>
8
+ */
9
+ class Ecocode_Profiler_Helper_Code
10
+ {
11
+ private $fileLinkFormat;
12
+ private $rootDir;
13
+ private $charset;
14
+
15
+ /**
16
+ * Constructor.
17
+ * @param null $format
18
+ * @param null $rootDir
19
+ * @param null|string $charset
20
+ */
21
+ public function __construct($format = null, $rootDir = null, $charset = 'UTF-8')
22
+ {
23
+ $this->fileLinkFormat = $format ? $format : ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format');
24
+ $this->rootDir = $rootDir ? $rootDir : str_replace('/', DIRECTORY_SEPARATOR, dirname(Mage::getRoot())) . DIRECTORY_SEPARATOR;
25
+ $this->charset = $charset;
26
+ }
27
+
28
+ public function abbrClass($class)
29
+ {
30
+ $parts = explode('\\', $class);
31
+ $short = array_pop($parts);
32
+
33
+ return sprintf('<abbr title="%s">%s</abbr>', $class, $short);
34
+ }
35
+
36
+ public function abbrMethod($method)
37
+ {
38
+ if (false !== strpos($method, '::')) {
39
+ list($class, $method) = explode('::', $method, 2);
40
+ $result = sprintf('%s::%s()', $this->abbrClass($class), $method);
41
+ } elseif ('Closure' === $method) {
42
+ $result = sprintf('<abbr title="%s">%s</abbr>', $method, $method);
43
+ } else {
44
+ $result = sprintf('<abbr title="%s">%s</abbr>()', $method, $method);
45
+ }
46
+
47
+ return $result;
48
+ }
49
+
50
+ /**
51
+ * Formats an array as a string.
52
+ *
53
+ * @param array $args The argument array
54
+ *
55
+ * @return string
56
+ */
57
+ public function formatArgs($args)
58
+ {
59
+ $result = [];
60
+ foreach ($args as $key => $item) {
61
+ if ('object' === $item[0]) {
62
+ $parts = explode('\\', $item[1]);
63
+ $short = array_pop($parts);
64
+ $formattedValue = sprintf('<em>object</em>(<abbr title="%s">%s</abbr>)', $item[1], $short);
65
+ } elseif ('array' === $item[0]) {
66
+ $formattedValue = sprintf('<em>array</em>(%s)', is_array($item[1]) ? $this->formatArgs($item[1]) : $item[1]);
67
+ } elseif ('string' === $item[0]) {
68
+ $formattedValue = sprintf("'%s'", htmlspecialchars($item[1], ENT_QUOTES, $this->charset));
69
+ } elseif ('null' === $item[0]) {
70
+ $formattedValue = '<em>null</em>';
71
+ } elseif ('boolean' === $item[0]) {
72
+ $formattedValue = '<em>' . strtolower(var_export($item[1], true)) . '</em>';
73
+ } elseif ('resource' === $item[0]) {
74
+ $formattedValue = '<em>resource</em>';
75
+ } else {
76
+ $formattedValue = str_replace("\n", '', var_export(htmlspecialchars((string)$item[1], ENT_QUOTES, $this->charset), true));
77
+ }
78
+
79
+ $result[] = is_int($key) ? $formattedValue : sprintf("'%s' => %s", $key, $formattedValue);
80
+ }
81
+
82
+ return implode(', ', $result);
83
+ }
84
+
85
+ /**
86
+ * Formats an array as a string.
87
+ *
88
+ * @param array $args The argument array
89
+ *
90
+ * @return string
91
+ */
92
+ public function formatArgsAsText($args)
93
+ {
94
+ return strip_tags($this->formatArgs($args));
95
+ }
96
+
97
+ /**
98
+ * Returns an excerpt of a code file around the given line number.
99
+ *
100
+ * @param string $file A file path
101
+ * @param int $line The selected line number
102
+ *
103
+ * @return string An HTML string
104
+ */
105
+ public function fileExcerpt($file, $line)
106
+ {
107
+ if (is_readable($file)) {
108
+ // highlight_file could throw warnings
109
+ // see https://bugs.php.net/bug.php?id=25725
110
+ $code = @highlight_file($file, true);
111
+ // remove main code/span tags
112
+ $code = preg_replace('#^<code.*?>\s*<span.*?>(.*)</span>\s*</code>#s', '\\1', $code);
113
+ $content = preg_split('#<br />#', $code);
114
+
115
+ $lines = [];
116
+ for ($i = max($line - 3, 1), $max = min($line + 3, count($content)); $i <= $max; ++$i) {
117
+ $lines[] = '<li' . ($i == $line ? ' class="selected"' : '') . '><code>' . self::fixCodeMarkup($content[$i - 1]) . '</code></li>';
118
+ }
119
+
120
+ return '<ol start="' . max($line - 3, 1) . '">' . implode("\n", $lines) . '</ol>';
121
+ }
122
+ }
123
+
124
+ /**
125
+ * Formats a file path.
126
+ *
127
+ * @param string $file An absolute file path
128
+ * @param int $line The line number
129
+ * @param string $text Use this text for the link rather than the file path
130
+ *
131
+ * @return string
132
+ */
133
+ public function formatFile($file, $line, $text = null)
134
+ {
135
+ $file = trim($file);
136
+
137
+ if (null === $text) {
138
+ $text = str_replace('/', DIRECTORY_SEPARATOR, $file);
139
+ if (0 === strpos($text, $this->rootDir)) {
140
+ $text = substr($text, strlen($this->rootDir));
141
+ $text = explode(DIRECTORY_SEPARATOR, $text, 2);
142
+ $text = sprintf('<abbr title="%s%2$s">%s</abbr>%s', $this->rootDir, $text[0], isset($text[1]) ? DIRECTORY_SEPARATOR . $text[1] : '');
143
+ }
144
+ }
145
+
146
+ $text = "$text at line $line";
147
+
148
+ if (false !== $link = $this->getFileLink($file, $line)) {
149
+ $flags = ENT_QUOTES | ENT_SUBSTITUTE;
150
+
151
+ return sprintf('<a href="%s" title="Click to open this file" class="file_link">%s</a>', htmlspecialchars($link, $flags, $this->charset), $text);
152
+ }
153
+
154
+ return $text;
155
+ }
156
+
157
+ /**
158
+ * Returns the link for a given file/line pair.
159
+ *
160
+ * @param string $file An absolute file path
161
+ * @param int $line The line number
162
+ *
163
+ * @return string A link of false
164
+ */
165
+ public function getFileLink($file, $line)
166
+ {
167
+ if ($this->fileLinkFormat && is_file($file)) {
168
+ return strtr($this->fileLinkFormat, ['%f' => $file, '%l' => $line]);
169
+ }
170
+
171
+ return false;
172
+ }
173
+
174
+ public function formatFileFromText($text)
175
+ {
176
+ return preg_replace_callback('/in ("|&quot;)?(.+?)\1(?: +(?:on|at))? +line (\d+)/s', function ($match) {
177
+ return 'in ' . $this->formatFile($match[2], $match[3]);
178
+ }, $text);
179
+ }
180
+
181
+ protected static function fixCodeMarkup($line)
182
+ {
183
+ // </span> ending tag from previous line
184
+ $opening = strpos($line, '<span');
185
+ $closing = strpos($line, '</span>');
186
+ if (false !== $closing && (false === $opening || $closing < $opening)) {
187
+ $line = substr_replace($line, '', $closing, 7);
188
+ }
189
+
190
+ // missing </span> tag at the end of line
191
+ $opening = strpos($line, '<span');
192
+ $closing = strpos($line, '</span>');
193
+ if (false !== $opening && (false === $closing || $closing > $opening)) {
194
+ $line .= '</span>';
195
+ }
196
+
197
+ return $line;
198
+ }
199
+ }
200
+
app/code/community/Ecocode/Profiler/Helper/Context.php ADDED
@@ -0,0 +1,104 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Ecocode_Profiler_Helper_Context
5
+ */
6
+ class Ecocode_Profiler_Helper_Context
7
+ extends Ecocode_Profiler_Helper_AbstractHelper
8
+ {
9
+ protected $stack = [];
10
+
11
+ protected $list = [];
12
+
13
+ protected $contextRenderer;
14
+
15
+ public function __construct()
16
+ {
17
+ $this->open(new Ecocode_Profiler_Model_Context('unknown'));
18
+ }
19
+
20
+ /**
21
+ * open a new context
22
+ *
23
+ * @param Ecocode_Profiler_Model_ContextInterface $context
24
+ */
25
+ public function open(Ecocode_Profiler_Model_ContextInterface $context)
26
+ {
27
+ $id = $context->getId();
28
+ if ($current = $this->getCurrent()) {
29
+ $context->setParentId($current->getId());
30
+ }
31
+
32
+ $this->list[$id] = $context;
33
+ $this->stack[$id] = $context;
34
+ }
35
+
36
+ /**
37
+ * close a previously opened context
38
+ *
39
+ * @param Ecocode_Profiler_Model_ContextInterface $context
40
+ * @return $this
41
+ * @throws Exception
42
+ */
43
+ public function close(Ecocode_Profiler_Model_ContextInterface $context)
44
+ {
45
+ $id = $context->getId();
46
+ if (!isset($this->stack[$id])) {
47
+ throw new \RuntimeException('unable to close unknown context');
48
+ }
49
+ unset($this->stack[$id]);
50
+
51
+ return $this;
52
+ }
53
+
54
+ public function getList()
55
+ {
56
+ return $this->list;
57
+ }
58
+
59
+ public function getCurrent()
60
+ {
61
+ return end($this->stack);
62
+ }
63
+
64
+ public function getCurrentId()
65
+ {
66
+ $current = $this->getCurrent();
67
+ if (!$current) {
68
+ return null;
69
+ }
70
+ return $current->getId();
71
+ }
72
+
73
+ public function getStack()
74
+ {
75
+ return $this->stack;
76
+ }
77
+
78
+
79
+ public function render($prefix, $contextId)
80
+ {
81
+ $context = $this->getContextById($contextId);
82
+ return $this->getContextRenderer()
83
+ ->render(['prefix' => $prefix, 'context' => $context]);
84
+ }
85
+
86
+ public function getContextById($id)
87
+ {
88
+ $profile = $this->getCurrentProfile();
89
+ return $profile->getCollector('context')->getById($id);
90
+ }
91
+
92
+
93
+ /**
94
+ * @return Ecocode_Profiler_Block_Renderer_Context
95
+ * @codeCoverageIgnore
96
+ */
97
+ public function getContextRenderer()
98
+ {
99
+ if ($this->contextRenderer === null) {
100
+ $this->contextRenderer = Mage::app()->getLayout()->createBlock('ecocode_profiler/renderer_context');
101
+ }
102
+ return $this->contextRenderer;
103
+ }
104
+ }
app/code/community/Ecocode/Profiler/Helper/Data.php ADDED
@@ -0,0 +1,191 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Ecocode_Profiler_Helper_Data
5
+ */
6
+ class Ecocode_Profiler_Helper_Data
7
+ {
8
+ protected static $version;
9
+ protected static $overwriteDirectory;
10
+
11
+ protected $configClassNameReflection;
12
+ protected $classNameCache;
13
+
14
+ public static function getOverwriteDir()
15
+ {
16
+ if (self::$overwriteDirectory === null) {
17
+ self::$overwriteDirectory = MAGENTO_ROOT . DIRECTORY_SEPARATOR . 'var' . DIRECTORY_SEPARATOR . 'cache' . DIRECTORY_SEPARATOR;
18
+ }
19
+
20
+ if (!file_exists(self::$overwriteDirectory)) {
21
+ mkdir(self::$overwriteDirectory, 0775, true);
22
+ }
23
+
24
+ return self::$overwriteDirectory;
25
+ }
26
+
27
+ /**
28
+ * @return string
29
+ */
30
+ public static function getVersion()
31
+ {
32
+ if (self::$version === null && class_exists('Mage') && $config = Mage::getConfig()) {
33
+ //try to load from magento
34
+ $config = $config->getModuleConfig('Ecocode_Profiler');
35
+ if ($config && $config->version) {
36
+ self::$version = (string)$config->version;
37
+ }
38
+ }
39
+
40
+ if (self::$version === null) {
41
+ //try to load it from the config directly
42
+ $configFile = __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'etc' . DIRECTORY_SEPARATOR . 'config.xml';
43
+ $xml = file_get_contents($configFile);
44
+ preg_match('/<version>([0-9\.]+)<\/version>/', $xml, $matches);
45
+ if (!$matches) {
46
+ throw new RuntimeException('unable to determinate profiler version');
47
+ }
48
+ self::$version = $matches[1];
49
+ }
50
+
51
+ return self::$version;
52
+ }
53
+
54
+ /**
55
+ * @param string $fileName
56
+ * @param string $className
57
+ */
58
+ public static function loadRenamedClass($fileName, $className)
59
+ {
60
+
61
+ $ds = DIRECTORY_SEPARATOR;
62
+ $sourceFile = MAGENTO_ROOT . $ds . 'app' . $ds . 'code' . $ds . $fileName;
63
+ $sourceMd5 = md5_file($sourceFile);
64
+
65
+ $fileName = sprintf('%s-%s-%s.php', $className, self::getVersion(), $sourceMd5);
66
+ $cacheFile = self::getOverwriteDir() . $fileName;
67
+
68
+ if (!file_exists($cacheFile)) {
69
+ $code = file_get_contents($sourceFile);
70
+ $code = preg_replace('/class ([^\s]+)/', 'class ' . $className, $code);
71
+
72
+ file_put_contents($cacheFile, $code);
73
+ }
74
+
75
+ require_once $cacheFile;
76
+ }
77
+
78
+ /**
79
+ * use the config class cache to retrieve the initial class group
80
+ *
81
+ * @param string|object $className
82
+ * @return string
83
+ */
84
+ public function getClassGroup($className)
85
+ {
86
+ if (is_object($className)) {
87
+ $className = get_class($className);
88
+ }
89
+
90
+ $classNames = $this->getClassNames();
91
+ if (!isset($classNames[$className])) {
92
+ $classNames = $this->getClassNames(true);
93
+ if (!isset($classNames[$className])) {
94
+ return 'unknown';
95
+ }
96
+ }
97
+
98
+ return $classNames[$className];
99
+ }
100
+
101
+ protected function getClassNames($reload = false)
102
+ {
103
+ if ($this->classNameCache !== null && $reload === false) {
104
+ return $this->classNameCache;
105
+ }
106
+ if ($this->configClassNameReflection === null) {
107
+ $this->configClassNameReflection = new ReflectionProperty('Mage_Core_Model_Config', '_classNameCache');
108
+ $this->configClassNameReflection->setAccessible(true);
109
+ }
110
+
111
+ $classNameCache = $this->configClassNameReflection->getValue(Mage::getConfig());
112
+ foreach ($classNameCache as $groupRoot) {
113
+ foreach ($groupRoot as $module => $classNames) {
114
+ foreach ($classNames as $class => $className) {
115
+ $this->classNameCache[$className] = $module . '/' . $class;
116
+ }
117
+ }
118
+ }
119
+
120
+ return $this->classNameCache;
121
+ }
122
+
123
+ /**
124
+ * @param string $token $token
125
+ * @param Ecocode_Profiler_Model_Collector_DataCollectorInterface $collector
126
+ * @return string
127
+ */
128
+ public function getCollectorUrl($token, Ecocode_Profiler_Model_Collector_DataCollectorInterface $collector)
129
+ {
130
+ return $this->getUrl($token, $collector->getName());
131
+ }
132
+
133
+ public function getUrl($token = null, $panel = null)
134
+ {
135
+ $params = [];
136
+ if ($token) {
137
+ $params[Ecocode_Profiler_Model_Profiler::URL_TOKEN_PARAMETER] = $token;
138
+ }
139
+ if ($panel) {
140
+ $params['panel'] = $panel;
141
+ }
142
+
143
+ return Mage::getUrl('_profiler/index/panel', $params);
144
+ }
145
+
146
+ /**
147
+ * removes all backtrace items until
148
+ * one does not match the rules defined
149
+ *
150
+ * @param array $backtrace
151
+ * @param array $ignoreCalls
152
+ * @param array $ignoreInstanceOf
153
+ * @return array
154
+ */
155
+ public function cleanBacktrace(array $backtrace, array $ignoreCalls = [], array $ignoreInstanceOf = [])
156
+ {
157
+ $item = reset($backtrace);
158
+ while ($item && $this->_cleanBacktrace($item, $ignoreCalls, $ignoreInstanceOf)) {
159
+ array_shift($backtrace);
160
+ $item = reset($backtrace);
161
+ }
162
+
163
+ return $backtrace;
164
+ }
165
+
166
+ public function _cleanBacktrace(array $data, array $ignoreCalls = [], array $ignoreInstanceOf = [])
167
+ {
168
+ //remove if not called from a class
169
+ if (!isset($data['class'], $data['function'])) {
170
+ return true;
171
+ }
172
+
173
+ $functionIdent = $data['class'] . '::' . $data['function'];
174
+ if (in_array($functionIdent, $ignoreCalls)) {
175
+ return true;
176
+ }
177
+
178
+ if (!isset($data['object'])) {
179
+ return false;
180
+ }
181
+
182
+ foreach ($ignoreInstanceOf as $instance) {
183
+ if ($data['object'] instanceof $instance) {
184
+ return true;
185
+ }
186
+ }
187
+
188
+ return false;
189
+ }
190
+
191
+ }
app/code/community/Ecocode/Profiler/Helper/Renderer.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Ecocode_Profiler_Helper_Renderer
5
+ */
6
+ class Ecocode_Profiler_Helper_Renderer
7
+ extends Mage_Core_Helper_Abstract
8
+ {
9
+ protected $backTraceRenderer;
10
+
11
+ public function get($name)
12
+ {
13
+
14
+ }
15
+
16
+
17
+ public function renderBackTrace($id, $trace)
18
+ {
19
+ return $this->getBackTraceRenderer()
20
+ ->setData(['id' => $id, 'trace' => $trace])
21
+ ->toHtml();
22
+ }
23
+
24
+ /**
25
+ * @return Ecocode_Profiler_Block_Renderer_BackTrace
26
+ */
27
+ public function getBackTraceRenderer()
28
+ {
29
+ if ($this->backTraceRenderer === null) {
30
+ $this->backTraceRenderer = Mage::app()->getLayout()->createBlock('ecocode_profiler/renderer_backTrace');
31
+ }
32
+ return $this->backTraceRenderer;
33
+ }
34
+ }
app/code/community/Ecocode/Profiler/Helper/Rewrite.php ADDED
@@ -0,0 +1,163 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Ecocode_Profiler_Helper_Rewrite
5
+ *
6
+ * taken from the awesome b98-magerun:
7
+ * https://github.com/netz98/n98-magerun/blob/master/src/N98/Magento/Command/Developer/Module/Rewrite/ConflictsCommand.php#L49-L55
8
+ */
9
+ class Ecocode_Profiler_Helper_Rewrite
10
+ {
11
+ protected $_rewrites = null;
12
+ protected $_rewriteTypes = [
13
+ 'blocks',
14
+ 'helpers',
15
+ 'models',
16
+ ];
17
+
18
+ /**
19
+ * @codeCoverageIgnore
20
+ * @return SimpleXMLElement
21
+ */
22
+ public function getModules()
23
+ {
24
+ return Mage::getConfig()->getNode('modules')->children();
25
+ }
26
+
27
+ /**
28
+ * @codeCoverageIgnore
29
+ * @param $moduleName
30
+ * @param $file
31
+ * @return bool|SimpleXMLElement
32
+ */
33
+ public function getModuleConfigXml($moduleName, $file)
34
+ {
35
+ $file = Mage::getConfig()->getModuleDir('etc', $moduleName) . DIRECTORY_SEPARATOR . $file;
36
+ if (!is_readable($file)) {
37
+ return false;
38
+ }
39
+
40
+ $xml = \simplexml_load_file($file);
41
+ if (!$xml) {
42
+ return false;
43
+ }
44
+
45
+ return $xml;
46
+ }
47
+
48
+ /**
49
+ * Return all rewrites
50
+ *
51
+ * @return array
52
+ */
53
+ public function loadRewrites()
54
+ {
55
+ if ($this->_rewrites === null) {
56
+ $files = ['config.xml', 'development.xml'];
57
+ $prototype = $this->_rewriteTypes;
58
+ $return = array_combine($prototype, array_fill(0, count($prototype), []));
59
+ // Load config of each module because modules can overwrite config each other. Global config is already merged
60
+ $modules = $this->getModules();
61
+ foreach ($modules as $moduleName => $moduleData) {
62
+ // Check only active modules
63
+ if (!$moduleData->is('active')) {
64
+ continue;
65
+ }
66
+ // Load config of module
67
+ foreach ($files as $file) {
68
+ $xml = $this->getModuleConfigXml($moduleName, $file);
69
+ if (!$xml) {
70
+ continue;
71
+ }
72
+ $rewriteElements = $xml->xpath('//*/*/rewrite');
73
+ foreach ($rewriteElements as $element) {
74
+ $type = \simplexml_import_dom(dom_import_simplexml($element)->parentNode->parentNode)->getName();
75
+ if (!isset($return[$type])) {
76
+ continue;
77
+ }
78
+ foreach ($element->children() as $child) {
79
+ $groupClassName = \simplexml_import_dom(dom_import_simplexml($element)->parentNode)->getName();
80
+ if (!isset($return[$type][$groupClassName . '/' . $child->getName()])) {
81
+ $return[$type][$groupClassName . '/' . $child->getName()] = [];
82
+ }
83
+ $return[$type][$groupClassName . '/' . $child->getName()][] = (string)$child;
84
+ }
85
+ }
86
+ }
87
+ }
88
+ $this->_rewrites = $return;
89
+ }
90
+
91
+ return $this->_rewrites;
92
+ }
93
+
94
+ public function getRewriteConflicts()
95
+ {
96
+ $conflicts = [];
97
+ $rewrites = $this->loadRewrites();
98
+ foreach ($rewrites as $type => $data) {
99
+ if (!is_array($data)) {
100
+ continue;
101
+ }
102
+ foreach ($data as $class => $rewriteClasses) {
103
+ if (!$this->_isInheritanceConflict($rewriteClasses)) {
104
+ continue;
105
+ }
106
+ $conflicts[] = [
107
+ 'type' => $type,
108
+ 'class' => $class,
109
+ 'rewrites' => $rewriteClasses,
110
+ 'loaded_class' => $this->_getLoadedClass($type, $class),
111
+ ];
112
+ }
113
+ }
114
+ return $conflicts;
115
+ }
116
+
117
+
118
+ /**
119
+ * Check if rewritten class has inherited the parent class.
120
+ * If yes we have no conflict. The top class can extend every core class.
121
+ * So we cannot check this.
122
+ *
123
+ * @var array $classes
124
+ * @return bool
125
+ */
126
+ protected function _isInheritanceConflict($classes)
127
+ {
128
+ $count = count($classes);
129
+ $classes = array_reverse($classes);
130
+ for ($i = 1; $i < $count; $i++) {
131
+ try {
132
+ if (class_exists($classes[$i - 1])
133
+ && class_exists($classes[$i])
134
+ ) {
135
+ if (!is_a($classes[$i - 1], $classes[$i], true)) {
136
+ return true;
137
+ }
138
+ }
139
+ } catch (Exception $e) {
140
+ return true;
141
+ }
142
+ }
143
+ return false;
144
+ }
145
+
146
+ /**
147
+ * Returns loaded class by type like models or blocks
148
+ *
149
+ * @param string $type
150
+ * @param string $class
151
+ * @return string
152
+ */
153
+ protected function _getLoadedClass($type, $class)
154
+ {
155
+ switch ($type) {
156
+ case 'blocks':
157
+ return Mage::getConfig()->getBlockClassName($class);
158
+ case 'helpers':
159
+ return Mage::getConfig()->getHelperClassName($class);
160
+ }
161
+ return Mage::getConfig()->getModelClassName($class);
162
+ }
163
+ }
app/code/community/Ecocode/Profiler/Helper/Sql.php ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Ecocode_Profiler_Helper_Sql
5
+ */
6
+ class Ecocode_Profiler_Helper_Sql extends Mage_Core_Helper_Abstract
7
+ {
8
+ protected $formattedQueriesCache = [];
9
+
10
+ public function replaceQueryParameters($query, array $parameters)
11
+ {
12
+ $i = 0;
13
+ if (!array_key_exists(0, $parameters) && array_key_exists(1, $parameters)) {
14
+ $i = 1;
15
+ }
16
+
17
+ $result = preg_replace_callback(
18
+ '/\?|((?<!:):[a-z0-9_]+)/i',
19
+ function ($matches) use ($parameters, &$i) {
20
+ $key = substr($matches[0], 1);
21
+ if (!array_key_exists($i, $parameters) && (false === $key || !array_key_exists($key, $parameters))) {
22
+ return $matches[0];
23
+ }
24
+ $value = array_key_exists($i, $parameters) ? $parameters[$i] : $parameters[$key];
25
+ $result = Mage::getSingleton('core/resource')->getConnection('default_write')->quote($value);
26
+ $i++;
27
+ return $result;
28
+ },
29
+ $query
30
+ );
31
+ return $result;
32
+ }
33
+
34
+ /**
35
+ * @param array $parameters
36
+ * @return string
37
+ *
38
+ * @codeCoverageIgnore covered by Yaml\Dumper itself
39
+ */
40
+ public function dumpParameters(array $parameters)
41
+ {
42
+ if (!$parameters) {
43
+ return '{}';
44
+ }
45
+
46
+ if (@!class_exists('\Symfony\Component\Yaml\Dumper')) {
47
+ return '"\Symfony\Component\Yaml\Dumper" is not installed';
48
+ }
49
+
50
+ static $dumper;
51
+
52
+ if (null === $dumper) {
53
+ $dumper = new \Symfony\Component\Yaml\Dumper();
54
+ }
55
+
56
+ return $dumper->dump($parameters);
57
+ }
58
+
59
+
60
+ /**
61
+ * @param $sql
62
+ * @param bool $highlightOnly
63
+ * @return string
64
+ * @codeCoverageIgnore covered by SqlFormatter itself
65
+ */
66
+ public function formatQuery($sql, $highlightOnly = false)
67
+ {
68
+ if (@!class_exists('SqlFormatter')) {
69
+ return 'SqlFormatter is not installed';
70
+ }
71
+
72
+ $cacheKey = md5($sql . ($highlightOnly ? '1' : 0));
73
+ if (isset($this->formattedQueriesCache[$cacheKey])) {
74
+ return $this->formattedQueriesCache[$cacheKey];
75
+ }
76
+
77
+ \SqlFormatter::$cli = false;
78
+ \SqlFormatter::$pre_attributes = 'class="highlight highlight-sql"';
79
+ \SqlFormatter::$quote_attributes = 'class="string"';
80
+ \SqlFormatter::$backtick_quote_attributes = 'class="string"';
81
+ \SqlFormatter::$reserved_attributes = 'class="keyword"';
82
+ \SqlFormatter::$boundary_attributes = 'class="symbol"';
83
+ \SqlFormatter::$number_attributes = 'class="number"';
84
+ \SqlFormatter::$word_attributes = 'class="word"';
85
+ \SqlFormatter::$error_attributes = 'class="error"';
86
+ \SqlFormatter::$comment_attributes = 'class="comment"';
87
+ \SqlFormatter::$variable_attributes = 'class="variable"';
88
+
89
+ if ($highlightOnly) {
90
+ $html = \SqlFormatter::highlight($sql);
91
+ $html = preg_replace('/<pre class=".*">([^"]*+)<\/pre>/Us', '\1', $html);
92
+ } else {
93
+ $html = \SqlFormatter::format($sql);
94
+ $html = preg_replace('/<pre class="(.*)">([^"]*+)<\/pre>/Us', '<div class="\1"><pre>\2</pre></div>', $html);
95
+ }
96
+
97
+ return $this->formattedQueriesCache[$cacheKey] = $html;
98
+ }
99
+ }
app/code/community/Ecocode/Profiler/Helper/ValueExporter.php ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+
13
+ /**
14
+ * @author Bernhard Schussek <bschussek@gmail.com>
15
+ */
16
+ class Ecocode_Profiler_Helper_ValueExporter
17
+ extends Mage_Core_Helper_Abstract
18
+ {
19
+ /**
20
+ * Converts a PHP value to a string.
21
+ *
22
+ * @param mixed $value The PHP value
23
+ * @param int $depth only for internal usage
24
+ * @param bool $deep only for internal usage
25
+ *
26
+ * @return string The string representation of the given value
27
+ */
28
+ public function exportValue($value, $depth = 1, $deep = false)
29
+ {
30
+ if (is_object($value)) {
31
+ if ($value instanceof \DateTimeInterface) {
32
+ return sprintf('Object(%s) - %s', get_class($value), $value->format(\DateTime::ISO8601));
33
+ }
34
+
35
+ return sprintf('Object(%s)', get_class($value));
36
+ }
37
+
38
+ if ($value instanceof \__PHP_Incomplete_Class) {
39
+ return sprintf('__PHP_Incomplete_Class(%s)', $this->getClassNameFromIncomplete($value));
40
+ }
41
+
42
+ if (is_array($value)) {
43
+ if (empty($value)) {
44
+ return '[]';
45
+ }
46
+
47
+ $indent = str_repeat(' ', $depth);
48
+
49
+ $a = [];
50
+ foreach ($value as $k => $v) {
51
+ if (is_array($v)) {
52
+ $deep = true;
53
+ }
54
+ $a[] = sprintf('%s => %s', $k, $this->exportValue($v, $depth + 1, $deep));
55
+ }
56
+
57
+ if ($deep) {
58
+ return sprintf("[\n%s%s\n%s]", $indent, implode(sprintf(", \n%s", $indent), $a), str_repeat(' ', $depth - 1));
59
+ }
60
+
61
+ $s = sprintf('[%s]', implode(', ', $a));
62
+
63
+ if (80 > strlen($s)) {
64
+ return $s;
65
+ }
66
+
67
+ return sprintf("[\n%s%s\n]", $indent, implode(sprintf(",\n%s", $indent), $a));
68
+ }
69
+
70
+ if (is_resource($value)) {
71
+ return sprintf('Resource(%s#%d)', get_resource_type($value), $value);
72
+ }
73
+
74
+ if (null === $value) {
75
+ return 'null';
76
+ }
77
+
78
+ if (false === $value) {
79
+ return 'false';
80
+ }
81
+
82
+ if (true === $value) {
83
+ return 'true';
84
+ }
85
+
86
+ return (string)$value;
87
+ }
88
+
89
+ private function getClassNameFromIncomplete(\__PHP_Incomplete_Class $value)
90
+ {
91
+ $array = new \ArrayObject($value);
92
+
93
+ return $array['__PHP_Incomplete_Class_Name'];
94
+ }
95
+ }
app/code/community/Ecocode/Profiler/Model/AppDev.php ADDED
@@ -0,0 +1,149 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Ecocode_Profiler_Model_AppDev
5
+ */
6
+ class Ecocode_Profiler_Model_AppDev extends Mage_Core_Model_App
7
+ {
8
+ protected $eventsFiredCount = 0;
9
+ protected $eventFiredCount = [];
10
+ protected $calledListeners = [];
11
+
12
+ protected $startTime;
13
+
14
+ /**
15
+ * Constructor
16
+ */
17
+ public function __construct()
18
+ {
19
+ $this->startTime = microtime(true);
20
+ }
21
+
22
+ public function getStartTime()
23
+ {
24
+ return $this->startTime;
25
+ }
26
+
27
+ public function _initRequest()
28
+ {
29
+ $result = parent::_initRequest();
30
+
31
+ $this->startProfiler();
32
+
33
+ return $result;
34
+ }
35
+
36
+ public function setErrorHandler($handler)
37
+ {
38
+ //DONT SET WE ARE USING THE SYMFONY DEBUG ONE
39
+ }
40
+
41
+
42
+ /**
43
+ * Initialize application cache instance
44
+ *
45
+ * @param array $cacheInitOptions
46
+ * @return Mage_Core_Model_App
47
+ */
48
+ protected function _initCache(array $cacheInitOptions = array())
49
+ {
50
+ //its to early to make use of normal rewrites as they are not yet loaded
51
+ //so just set it our self
52
+ $this->_config->setNode('global/models/core/rewrite/cache', 'Ecocode_Profiler_Model_Core_Cache');
53
+ return parent::_initCache($cacheInitOptions);
54
+ }
55
+
56
+ /**
57
+ * start the profiler
58
+ *
59
+ * @return $this
60
+ */
61
+ protected function startProfiler()
62
+ {
63
+ //to early to detect if this is the admin store
64
+ $path = $this->getRequest()->getPathInfo();
65
+ if (substr($path, 0, 10) === '/_profiler') {
66
+ return $this;
67
+ }
68
+ //this wont work if you use a custom url and we cant tell by now
69
+ //which one is configured. even if we read the local.xml manually
70
+ // it can still be set in the database, so for now 80/20 solution :)
71
+ if (substr($path, 0, 6) === '/admin') {
72
+ return $this;
73
+ }
74
+
75
+ Mage::getSingleton('ecocode_profiler/profiler')->init();
76
+
77
+ return $this;
78
+ }
79
+
80
+ /**
81
+ * @param $eventName
82
+ * @param $args
83
+ * @return $this
84
+ */
85
+ public function dispatchEvent($eventName, $args)
86
+ {
87
+ if (!isset($args['debug'])) {
88
+ if (!isset($this->eventFiredCount[$eventName])) {
89
+ $this->eventFiredCount[$eventName] = 0;
90
+ }
91
+ $this->eventFiredCount[$eventName]++;
92
+ }
93
+
94
+ return parent::dispatchEvent($eventName, $args);
95
+ }
96
+
97
+ /**
98
+ * overwrite to log all listener calls
99
+ *
100
+ * @param object $object
101
+ * @param string $method
102
+ * @param Varien_Event_Observer $observer
103
+ * @return $this
104
+ */
105
+ protected function _callObserverMethod($object, $method, $observer)
106
+ {
107
+ $eventName = $observer->getEvent()->getName();
108
+ if (!$observer->getEvent()->getData('debug')) {
109
+ $this->calledListeners[] = [
110
+ 'event_name' => $eventName,
111
+ 'class' => get_class($object),
112
+ 'method' => $method
113
+ ];
114
+
115
+ if (!method_exists($object, $method)) {
116
+ Mage::log(
117
+ sprintf(
118
+ 'event "%s" tried to call a non existing method "%s" in "%s"',
119
+ $eventName,
120
+ $method,
121
+ get_class($object)
122
+ )
123
+ );
124
+ }
125
+ }
126
+
127
+ return parent::_callObserverMethod($object, $method, $observer);
128
+ }
129
+
130
+ public function getEvents()
131
+ {
132
+ return $this->_events;
133
+ }
134
+
135
+ public function getFiredEventCount()
136
+ {
137
+ return $this->eventsFiredCount;
138
+ }
139
+
140
+ public function getFiredEvents()
141
+ {
142
+ return $this->eventFiredCount;
143
+ }
144
+
145
+ public function getCalledListeners()
146
+ {
147
+ return $this->calledListeners;
148
+ }
149
+ }
app/code/community/Ecocode/Profiler/Model/Collector/AbstractDataCollector.php ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Ecocode_Profiler_Model_Collector_AbstractDataCollector
5
+ */
6
+ abstract class Ecocode_Profiler_Model_Collector_AbstractDataCollector
7
+ implements Ecocode_Profiler_Model_Collector_DataCollectorInterface,
8
+ Serializable
9
+ {
10
+ protected $data = [];
11
+
12
+ protected $contextHelper;
13
+
14
+
15
+ public function init()
16
+ {
17
+ //fill if needed
18
+ }
19
+
20
+ public function serialize()
21
+ {
22
+ return serialize($this->data);
23
+ }
24
+
25
+ public function unserialize($data)
26
+ {
27
+ $this->data = unserialize($data);
28
+ }
29
+
30
+ public function getBlockPanelName()
31
+ {
32
+ return $this->getName() . '_panel';
33
+ }
34
+
35
+ public function getBlockMenuName()
36
+ {
37
+ return $this->getName() . '_menu';
38
+ }
39
+
40
+ public function getBlockToolbarName()
41
+ {
42
+ return 'profiler.' . $this->getName() . '.toolbar';
43
+ }
44
+
45
+ /**
46
+ * @param $key
47
+ * @param null $default
48
+ * @return mixed
49
+ */
50
+ protected function getData($key, $default = null)
51
+ {
52
+ return isset($this->data[$key]) ? $this->data[$key] : $default;
53
+ }
54
+ /**
55
+ * @return integer
56
+ */
57
+ public function getContextId()
58
+ {
59
+ return $this->getContextHelper()->getCurrentId();
60
+ }
61
+
62
+ /**
63
+ * @return Ecocode_Profiler_Helper_Context
64
+ */
65
+ public function getContextHelper()
66
+ {
67
+ if ($this->contextHelper === null) {
68
+ $this->contextHelper = Mage::helper('ecocode_profiler/context');
69
+ }
70
+
71
+ return $this->contextHelper;
72
+ }
73
+
74
+ protected function getBacktrace($options = DEBUG_BACKTRACE_PROVIDE_OBJECT)
75
+ {
76
+ if (!function_exists('debug_backtrace')) {
77
+ return false;
78
+ }
79
+
80
+ return debug_backtrace($options);
81
+ }
82
+ }
app/code/community/Ecocode/Profiler/Model/Collector/AjaxDataCollector.php ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Ecocode_Profiler_Model_Collector_AjaxDataCollector
5
+ */
6
+ class Ecocode_Profiler_Model_Collector_AjaxDataCollector
7
+ extends Ecocode_Profiler_Model_Collector_AbstractDataCollector
8
+ {
9
+ /**
10
+ * {@inheritdoc}
11
+ *
12
+ * @codeCoverageIgnore
13
+ */
14
+ public function collect(Mage_Core_Controller_Request_Http $request, Mage_Core_Controller_Response_Http $response, \Exception $exception = null)
15
+ {
16
+ // all collecting is done client side
17
+ }
18
+
19
+ /**
20
+ * @codeCoverageIgnore
21
+ * @return string
22
+ */
23
+ public function getName()
24
+ {
25
+ return 'ajax';
26
+ }
27
+ }
app/code/community/Ecocode/Profiler/Model/Collector/CacheDataCollector.php ADDED
@@ -0,0 +1,146 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Ecocode_Profiler_Model_Collector_CacheDataCollector
5
+ */
6
+ class Ecocode_Profiler_Model_Collector_CacheDataCollector
7
+ extends Ecocode_Profiler_Model_Collector_AbstractDataCollector
8
+ implements Ecocode_Profiler_Model_Collector_LateDataCollectorInterface
9
+ {
10
+ /**
11
+ * @return Mage_Core_Model_Cache
12
+ *
13
+ * @codeCoverageIgnore
14
+ */
15
+ protected function getCacheInstance()
16
+ {
17
+ return Mage::app()->getCacheInstance();
18
+ }
19
+
20
+ /**
21
+ * @return Zend_Cache_Core
22
+ *
23
+ * @codeCoverageIgnore
24
+ */
25
+ protected function getCache()
26
+ {
27
+ return Mage::app()->getCache();
28
+ }
29
+
30
+ /**
31
+ * {@inheritdoc}
32
+ */
33
+ public function collect(Mage_Core_Controller_Request_Http $request, Mage_Core_Controller_Response_Http $response, \Exception $exception = null)
34
+ {
35
+ $caches = [];
36
+ $cacheInstance = $this->getCacheInstance();
37
+
38
+ foreach ($cacheInstance->getTypes() as $cache) {
39
+ $caches[] = $cache->getData();
40
+ }
41
+
42
+ /** @var Zend_Cache_Core $cache */
43
+ $cache = $this->getCache();
44
+ $backend = $cache->getBackend();
45
+
46
+ $backendOptionsProperty = new ReflectionProperty('Zend_Cache_Backend', '_options');
47
+ $backendOptionsProperty->setAccessible(true);
48
+
49
+ $this->data = [
50
+ 'backend_name' => get_class($backend),
51
+ 'backend_options' => $backendOptionsProperty->getValue($backend),
52
+ 'cache_list' => $caches,
53
+ 'cache_calls' => [],
54
+ 'stats' => [
55
+ 'total' => 0,
56
+ 'hit' => 0,
57
+ 'miss' => 0,
58
+ 'save' => 0,
59
+ ]
60
+ ];
61
+ }
62
+
63
+ public function lateCollect()
64
+ {
65
+ $this->collectCacheCallData();
66
+ }
67
+
68
+ protected function collectCacheCallData()
69
+ {
70
+ $cache = $this->getCacheInstance();
71
+ if (!$cache instanceof Ecocode_Profiler_Model_Core_Cache) {
72
+ return;
73
+ }
74
+ $cacheCalls = $cache->getLog();
75
+ $totalTime = 0;
76
+ $stats = [
77
+ 'total' => count($cacheCalls),
78
+ 'hit' => 0,
79
+ 'miss' => 0,
80
+ 'save' => 0,
81
+ ];
82
+
83
+ foreach ($cacheCalls as $log) {
84
+ $totalTime += $log['time'];
85
+ switch ($log['action']) {
86
+ case 'load':
87
+ $stats[$log['hit'] ? 'hit' : 'miss']++;
88
+ break;
89
+ case 'save':
90
+ $stats['save']++;
91
+ break;
92
+ default:
93
+ break;
94
+ }
95
+ }
96
+
97
+ $this->data['stats'] = $stats;
98
+ $this->data['total_time'] = $totalTime;
99
+ $this->data['cache_calls'] = $cache->getLog();
100
+ }
101
+
102
+ public function getBackendName()
103
+ {
104
+ return $this->getData('backend_name', 'Unknown');
105
+ }
106
+
107
+ public function getBackendOptions()
108
+ {
109
+ return $this->getData('backend_options', []);
110
+ }
111
+
112
+ public function getStats($key = null)
113
+ {
114
+ if ($key) {
115
+ return $this->data['stats'][$key];
116
+ }
117
+
118
+ return $this->data['stats'];
119
+ }
120
+
121
+ public function getTotalTime()
122
+ {
123
+ return $this->getData('total_time', 0);
124
+ }
125
+
126
+
127
+ public function getCacheList()
128
+ {
129
+ return $this->getData('cache_list', []);
130
+ }
131
+
132
+
133
+ public function getCacheCalls()
134
+ {
135
+ return $this->getData('cache_calls', []);
136
+ }
137
+
138
+ /**
139
+ * @codeCoverageIgnore
140
+ * @return string
141
+ */
142
+ public function getName()
143
+ {
144
+ return 'cache';
145
+ }
146
+ }
app/code/community/Ecocode/Profiler/Model/Collector/ConfigDataCollector.php ADDED
@@ -0,0 +1,237 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Ecocode_Profiler_Model_Collector_ConfigDataCollector
5
+ */
6
+ class Ecocode_Profiler_Model_Collector_ConfigDataCollector
7
+ extends Ecocode_Profiler_Model_Collector_AbstractDataCollector
8
+ {
9
+
10
+ /**
11
+ * {@inheritdoc}
12
+ */
13
+ public function collect(Mage_Core_Controller_Request_Http $request, Mage_Core_Controller_Response_Http $response, \Exception $exception = null)
14
+ {
15
+ $store = Mage::app()->getStore();
16
+ $website = Mage::app()->getWebsite();
17
+
18
+ $this->data = [
19
+ 'store_id' => $store->getId(),
20
+ 'store_name' => $store->getName(),
21
+ 'store_code' => $store->getCode(),
22
+ 'website_id' => $website->getId(),
23
+ 'website_name' => $website->getName(),
24
+ 'website_code' => $website->getCode(),
25
+ 'developer_mode' => Mage::getIsDeveloperMode(),
26
+ 'token' => $this->retrieveToken($response),
27
+ 'magento_version' => Mage::getVersion(),
28
+ 'magento_modules' => $this->collectMagentoModules(),
29
+ 'php_version' => PHP_VERSION,
30
+ 'xdebug_enabled' => extension_loaded('xdebug'),
31
+ 'eaccel_enabled' => extension_loaded('eaccelerator') && ini_get('eaccelerator.enable'),
32
+ 'apc_enabled' => extension_loaded('apc') && ini_get('apc.enabled'),
33
+ 'xcache_enabled' => extension_loaded('xcache') && ini_get('xcache.cacher'),
34
+ 'wincache_enabled' => extension_loaded('wincache') && ini_get('wincache.ocenabled'),
35
+ 'zend_opcache_enabled' => extension_loaded('Zend OPcache') && ini_get('opcache.enable'),
36
+ 'sapi_name' => PHP_SAPI,
37
+ ];
38
+
39
+ }
40
+
41
+ protected function collectMagentoModules()
42
+ {
43
+ /** @var Mage_Core_Model_Config_Element $modules */
44
+ $moduleList = Mage::getConfig()->getNode('modules')->children();
45
+ $modules = [];
46
+ foreach ($moduleList as $key => $node) {
47
+ $data = $node->asArray();
48
+ $data['active'] = isset($data['active']) && $data['active'] === 'true';
49
+ $modules[$key] = $data;
50
+ }
51
+
52
+ return $modules;
53
+ }
54
+
55
+ public function getMagentoVersion()
56
+ {
57
+ return $this->getData('magento_version');
58
+ }
59
+
60
+ public function getStoreId()
61
+ {
62
+ return $this->getData('store_id');
63
+ }
64
+
65
+ public function getStoreName()
66
+ {
67
+ return $this->getData('store_name');
68
+ }
69
+
70
+ public function getStoreCode()
71
+ {
72
+ return $this->getData('store_code');
73
+ }
74
+
75
+ public function getWebsiteId()
76
+ {
77
+ return $this->getData('website_id');
78
+ }
79
+
80
+ public function getWebsiteName()
81
+ {
82
+ return $this->getData('website_name');
83
+ }
84
+
85
+ public function getWebsiteCode()
86
+ {
87
+ return $this->getData('website_code');
88
+ }
89
+
90
+ /**
91
+ * Gets the token.
92
+ *
93
+ * @return string The token
94
+ */
95
+ public function getToken()
96
+ {
97
+ return $this->getData('token');
98
+ }
99
+
100
+ /**
101
+ * Gets the PHP version.
102
+ *
103
+ * @return string The PHP version
104
+ */
105
+ public function getPhpVersion()
106
+ {
107
+ return $this->getData('php_version');
108
+ }
109
+
110
+ /**
111
+ * Returns true if the developer mode is enabled.
112
+ *
113
+ * @return bool true if debug is enabled, false otherwise
114
+ */
115
+ public function isDeveloperMode()
116
+ {
117
+ return $this->getData('developer_mode');
118
+ }
119
+
120
+ public function getMagentoModules()
121
+ {
122
+ return $this->getData('magento_modules', []);
123
+ }
124
+
125
+ /**
126
+ * @param $state
127
+ * @return array
128
+ */
129
+ public function geModulesByState($state)
130
+ {
131
+ return array_filter($this->getMagentoModules(), function ($module) use ($state) {
132
+ return $module['active'] === $state;
133
+ });
134
+ }
135
+
136
+ /**
137
+ * Returns true if the XDebug is enabled.
138
+ *
139
+ * @return bool true if XDebug is enabled, false otherwise
140
+ */
141
+ public function hasXDebug()
142
+ {
143
+ return $this->getData('xdebug_enabled');
144
+ }
145
+
146
+ /**
147
+ * Returns true if EAccelerator is enabled.
148
+ *
149
+ * @return bool true if EAccelerator is enabled, false otherwise
150
+ */
151
+ public function hasEAccelerator()
152
+ {
153
+ return $this->getData('eaccel_enabled');
154
+ }
155
+
156
+ /**
157
+ * Returns true if APC is enabled.
158
+ *
159
+ * @return bool true if APC is enabled, false otherwise
160
+ */
161
+ public function hasApc()
162
+ {
163
+ return $this->getData('apc_enabled');
164
+ }
165
+
166
+ /**
167
+ * Returns true if Zend OPcache is enabled.
168
+ *
169
+ * @return bool true if Zend OPcache is enabled, false otherwise
170
+ */
171
+ public function hasZendOpcache()
172
+ {
173
+ return $this->getData('zend_opcache_enabled');
174
+ }
175
+
176
+ /**
177
+ * Returns true if XCache is enabled.
178
+ *
179
+ * @return bool true if XCache is enabled, false otherwise
180
+ */
181
+ public function hasXCache()
182
+ {
183
+ return $this->getData('xcache_enabled');
184
+ }
185
+
186
+ /**
187
+ * Returns true if WinCache is enabled.
188
+ *
189
+ * @return bool true if WinCache is enabled, false otherwise
190
+ */
191
+ public function hasWinCache()
192
+ {
193
+ return $this->getData('wincache_enabled');
194
+ }
195
+
196
+ /**
197
+ * Returns true if any accelerator is enabled.
198
+ *
199
+ * @return bool true if any accelerator is enabled, false otherwise
200
+ */
201
+ public function hasAccelerator()
202
+ {
203
+ return $this->hasApc() || $this->hasZendOpcache() || $this->hasEAccelerator() || $this->hasXCache() || $this->hasWinCache();
204
+ }
205
+
206
+ /**
207
+ * Gets the PHP SAPI name.
208
+ *
209
+ * @return string The environment
210
+ */
211
+ public function getSapiName()
212
+ {
213
+ return $this->getData('sapi_name');
214
+ }
215
+
216
+ public function retrieveToken(Mage_Core_Controller_Response_Http $response)
217
+ {
218
+ $token = null;
219
+ foreach ($response->getHeaders() as $header) {
220
+ if ($header['name'] === 'X-Debug-Token') {
221
+ $token = $header['value'];
222
+ break;
223
+ }
224
+ }
225
+ return $token;
226
+ }
227
+
228
+ /**
229
+ * @codeCoverageIgnore
230
+ * @return string
231
+ */
232
+ public function getName()
233
+ {
234
+ return 'config';
235
+ }
236
+
237
+ }
app/code/community/Ecocode/Profiler/Model/Collector/ContextDataCollector.php ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Ecocode_Profiler_Model_Collector_ContextDataCollector
5
+ */
6
+ class Ecocode_Profiler_Model_Collector_ContextDataCollector
7
+ extends Ecocode_Profiler_Model_Collector_AbstractDataCollector
8
+ implements Ecocode_Profiler_Model_Collector_LateDataCollectorInterface
9
+ {
10
+
11
+ /**
12
+ * {@inheritdoc}
13
+ */
14
+ public function collect(Mage_Core_Controller_Request_Http $request, Mage_Core_Controller_Response_Http $response, \Exception $exception = null)
15
+ {
16
+ $this->data = ['list' => []];
17
+
18
+ return $this;
19
+ }
20
+
21
+ public function lateCollect()
22
+ {
23
+ $this->data = ['list' => $this->getContextHelper()->getList()];
24
+ }
25
+
26
+ public function getById($id)
27
+ {
28
+ if (isset($this->data['list'][$id])) {
29
+ return $this->data['list'][$id];
30
+ }
31
+
32
+ return null;
33
+ }
34
+
35
+ public function getList()
36
+ {
37
+ return $this->getData('list', []);
38
+ }
39
+
40
+ public function getName()
41
+ {
42
+ return 'context';
43
+ }
44
+
45
+ }
app/code/community/Ecocode/Profiler/Model/Collector/CustomerDataCollector.php ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Ecocode_Profiler_Model_Collector_CustomerDataCollector
5
+ */
6
+ class Ecocode_Profiler_Model_Collector_CustomerDataCollector
7
+ extends Ecocode_Profiler_Model_Collector_AbstractDataCollector
8
+ {
9
+ /**
10
+ * {@inheritdoc}
11
+ */
12
+ public function collect(Mage_Core_Controller_Request_Http $request, Mage_Core_Controller_Response_Http $response, \Exception $exception = null)
13
+ {
14
+ $customerHelper = $this->getCustomerHelper();
15
+
16
+ $customer = $customerHelper->getCustomer();
17
+
18
+ $group = Mage::getModel('customer/group')->load($customer->getGroupId());
19
+ $taxClass = Mage::getModel('tax/class')->load($group->getTaxClassId());
20
+
21
+ $this->data = [
22
+ 'logged_in' => $customerHelper->isLoggedIn(),
23
+ 'customer_email' => $customer->getEmail(),
24
+ 'customer_name' => $customer->getName(),
25
+ 'group_id' => $group->getId(),
26
+ 'group_code' => $group->getCustomerGroupCode(),
27
+ 'tax_class_id' => $taxClass->getId(),
28
+ 'tax_class_name' => $taxClass->getClassName(),
29
+ 'tax_class_type' => $taxClass->getClassType()
30
+ ];
31
+ }
32
+
33
+ public function isLoggedIn()
34
+ {
35
+ return $this->getData('logged_in');
36
+ }
37
+
38
+ public function getCustomerEmail()
39
+ {
40
+ return $this->getData('customer_email');
41
+ }
42
+
43
+ public function getCustomerName()
44
+ {
45
+ return $this->getData('customer_name');
46
+ }
47
+
48
+ public function getGroupId()
49
+ {
50
+ return $this->getData('group_id');
51
+ }
52
+
53
+ public function getGroupCode()
54
+ {
55
+ return $this->getData('group_code');
56
+ }
57
+
58
+
59
+ public function getTaxClassName()
60
+ {
61
+ return $this->getData('tax_class_name');
62
+ }
63
+
64
+ public function getTaxClassId()
65
+ {
66
+ return $this->getData('tax_class_id');
67
+ }
68
+
69
+ public function getTaxClassType()
70
+ {
71
+ return $this->getData('tax_class_type');
72
+ }
73
+
74
+ /**
75
+ * @codeCoverageIgnore
76
+ * @return Mage_Customer_Helper_Data
77
+ */
78
+ public function getCustomerHelper()
79
+ {
80
+ return Mage::helper('customer');
81
+ }
82
+
83
+ /**
84
+ * @codeCoverageIgnore
85
+ * @return string
86
+ */
87
+ public function getName()
88
+ {
89
+ return 'customer';
90
+ }
91
+ }
app/code/community/Ecocode/Profiler/Model/Collector/DataCollectorInterface.php ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Interface Ecocode_Profiler_Model_Collector_DataCollectorInterface
5
+ */
6
+ interface Ecocode_Profiler_Model_Collector_DataCollectorInterface
7
+ {
8
+ public function init();
9
+
10
+ /**
11
+ * @param Mage_Core_Controller_Request_Http $request
12
+ * @param Mage_Core_Controller_Response_Http $response
13
+ * @param Exception|null $exception
14
+ * @return mixed
15
+ */
16
+ public function collect(Mage_Core_Controller_Request_Http $request, Mage_Core_Controller_Response_Http $response, \Exception $exception = null);
17
+
18
+ /**
19
+ * Returns the name of the collector.
20
+ *
21
+ * @return string The collector name
22
+ */
23
+ public function getName();
24
+ }
app/code/community/Ecocode/Profiler/Model/Collector/EventDataCollector.php ADDED
@@ -0,0 +1,97 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Ecocode_Profiler_Model_Collector_EventDataCollector
5
+ */
6
+ class Ecocode_Profiler_Model_Collector_EventDataCollector
7
+ extends Ecocode_Profiler_Model_Collector_AbstractDataCollector
8
+ implements Ecocode_Profiler_Model_Collector_LateDataCollectorInterface
9
+ {
10
+ /**
11
+ * {@inheritdoc}
12
+ */
13
+ public function collect(Mage_Core_Controller_Request_Http $request, Mage_Core_Controller_Response_Http $response, \Exception $exception = null)
14
+ {
15
+ $this->data = [
16
+ 'called_listeners' => [],
17
+ 'fired_events' => []
18
+ ];
19
+ }
20
+
21
+ public function lateCollect()
22
+ {
23
+ $app = $this->getApp();
24
+
25
+ $this->data = [
26
+ 'called_listeners' => $this->collectedCalledListeners($app),
27
+ 'fired_events' => $this->collectEvents($app)
28
+ ];
29
+ }
30
+
31
+ protected function collectEvents(Ecocode_Profiler_Model_AppDev $app)
32
+ {
33
+ $eventList = $app->getFiredEvents();
34
+ $events = [];
35
+
36
+ $observerList = $app->getEvents();
37
+
38
+ foreach ($eventList as $eventName => $count) {
39
+ $observers = [];
40
+ $observerCount = 0;
41
+
42
+ foreach ($observerList as $area => $list) {
43
+ if (!isset($list[$eventName]) || $list[$eventName] === false) {
44
+ continue;
45
+ }
46
+
47
+ $observers[$area] = [];
48
+ foreach ($list[$eventName] as $areaObservers) {
49
+ $observers[$area] += $areaObservers;
50
+ $observerCount += count($areaObservers);
51
+ }
52
+ }
53
+
54
+ $events[$eventName] = [
55
+ 'name' => $eventName,
56
+ 'count' => $count,
57
+ 'observer' => $observers,
58
+ 'observer_count' => $observerCount
59
+ ];
60
+ }
61
+
62
+ return $events;
63
+ }
64
+
65
+ protected function collectedCalledListeners(Ecocode_Profiler_Model_AppDev $app)
66
+ {
67
+ return $app->getCalledListeners();
68
+ }
69
+
70
+ public function getCalledListeners()
71
+ {
72
+ return $this->getData('called_listeners', []);
73
+ }
74
+
75
+ public function getFiredEvents()
76
+ {
77
+ return $this->getData('fired_events', []);
78
+ }
79
+
80
+ /**
81
+ * @codeCoverageIgnore
82
+ * @return Mage_Core_Model_App
83
+ */
84
+ public function getApp()
85
+ {
86
+ return Mage::app();
87
+ }
88
+
89
+ /**
90
+ * @codeCoverageIgnore
91
+ * @return string
92
+ */
93
+ public function getName()
94
+ {
95
+ return 'event';
96
+ }
97
+ }
app/code/community/Ecocode/Profiler/Model/Collector/LateDataCollectorInterface.php ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Interface Ecocode_Profiler_Model_Collector_LateDataCollectorInterface
5
+ */
6
+ interface Ecocode_Profiler_Model_Collector_LateDataCollectorInterface
7
+ {
8
+ /**
9
+ * Collects data as late as possible.
10
+ */
11
+ public function lateCollect();
12
+ }
app/code/community/Ecocode/Profiler/Model/Collector/LayoutDataCollector.php ADDED
@@ -0,0 +1,175 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Ecocode_Profiler_Model_Collector_LayoutDataCollector
4
+ extends Ecocode_Profiler_Model_Collector_AbstractDataCollector
5
+ {
6
+ protected $renderLog = [];
7
+ protected $renderedBlocks = [];
8
+ protected $currentBlock;
9
+
10
+ public function beforeToHtml(Varien_Event_Observer $observer)
11
+ {
12
+ /** @var Mage_Core_Block_Abstract $block */
13
+ $block = $observer->getEvent()->getData('block');
14
+ $id = uniqid();
15
+ $block->setData('profiler_id', $id);
16
+
17
+ $data = [
18
+ 'id' => $id,
19
+ 'start_render' => microtime(true),
20
+ 'hash' => spl_object_hash($block),
21
+ 'children' => [],
22
+ 'parent_id' => false,
23
+ ];
24
+
25
+ if ($parentBlock = $block->getParentBlock()) {
26
+
27
+ } else if ($block instanceof Mage_Widget_Block_Interface) {
28
+ $parentBlock = $this->currentBlock;
29
+ }
30
+
31
+ if ($parentBlock && $parentId = $parentBlock->getData('profiler_id')) {
32
+ $this->renderLog[$parentId]['children'][] = $id;
33
+ $data['parent_id'] = $parentId;
34
+ }
35
+
36
+ if (!$block instanceof Mage_Widget_Block_Interface) {
37
+ $this->currentBlock = $block;
38
+ }
39
+ $this->renderLog[$id] = $data;
40
+ }
41
+
42
+ public function afterToHtml(Varien_Event_Observer $observer)
43
+ {
44
+ /** @var Mage_Core_Block_Abstract $block */
45
+ $block = $observer->getEvent()->getData('block');
46
+ $id = $block->getData('profiler_id');
47
+ $data = $this->renderLog[$id];
48
+
49
+ $data += $this->getBaseBlockData($block);
50
+ $data['stop_render'] = microtime(true);
51
+ $data['render_time_incl'] = $data['stop_render'] - $data['start_render'];
52
+
53
+ if ($block instanceof Mage_Core_Block_Template) {
54
+ $data['template'] = $block->getTemplate();
55
+ }
56
+
57
+ $this->renderedBlocks[$id] = $block;
58
+ $this->renderLog[$id] = $data;
59
+
60
+
61
+ }
62
+
63
+ /**
64
+ * {@inheritdoc}
65
+ */
66
+ public function collect(Mage_Core_Controller_Request_Http $request, Mage_Core_Controller_Response_Http $response, \Exception $exception = null)
67
+ {
68
+ $outputProperties = new ReflectionProperty('Mage_Core_Model_Layout', '_output');
69
+ $outputProperties->setAccessible(true);
70
+
71
+ $layout = $this->getLayout();
72
+ $outputBlocks = [];
73
+ foreach ($outputProperties->getValue($layout) as $name => $data) {
74
+ $block = $layout->getBlock($name);
75
+ $outputBlocks[] = $block->getData('profiler_id');
76
+ }
77
+
78
+ $totalTime = 0;
79
+ foreach ($this->renderLog as &$data) {
80
+ $renderTimeExcl = $data['render_time_incl'];
81
+ foreach ($data['children'] as $childId) {
82
+ $child = $this->renderLog[$childId];
83
+ $renderTimeExcl -= $child['render_time_incl'];
84
+ }
85
+ $data['render_time'] = $renderTimeExcl;
86
+
87
+ $totalTime += $data['render_time'];
88
+ }
89
+
90
+ $renderedCount = 0;
91
+ $notRenderedBlocks = [];
92
+ foreach ($layout->getAllBlocks() as $block) {
93
+ if ($block->getData('profiler_id')) {
94
+ $renderedCount++;
95
+ } else {
96
+ $notRenderedBlocks[] = $this->getBaseBlockData($block);
97
+ }
98
+ }
99
+ $this->data = [
100
+ 'handles' => $layout->getUpdate()->getHandles(),
101
+ 'blocks_created_count' => count($layout->getAllBlocks()),
102
+ 'blocks_rendered_count' => count($this->renderLog),
103
+ 'blocks_not_rendered_count' => count($notRenderedBlocks),
104
+ 'blocks_not_rendered' => $notRenderedBlocks,
105
+ 'output_blocks' => $outputBlocks,
106
+ 'render_log' => $this->renderLog,
107
+ 'render_time' => $totalTime
108
+
109
+ ];
110
+ return $this;
111
+ }
112
+
113
+ protected function getBaseBlockData(Mage_Core_Block_Abstract $block)
114
+ {
115
+ return [
116
+ 'name' => $block->getNameInLayout(),
117
+ 'class' => get_class($block),
118
+ 'module' => $block->getModuleName(),
119
+ 'type' => $block->getData('type'),
120
+ 'cacheable' => $block->getCacheLifetime() !== null,
121
+ 'cache_time' => $block->getCacheLifetime(),
122
+ ];
123
+ }
124
+
125
+ public function getTotalRenderTime()
126
+ {
127
+ return $this->getData('render_time', 0);
128
+ }
129
+
130
+ public function getRenderLog()
131
+ {
132
+ return $this->getData('render_log', []);
133
+ }
134
+
135
+ public function getBlocksNotRendered()
136
+ {
137
+ return $this->getData('blocks_not_rendered', []);
138
+ }
139
+
140
+ public function getLayoutHandles()
141
+ {
142
+ return $this->getData('handles', []);
143
+ }
144
+
145
+ public function getBlocksCreatedCount()
146
+ {
147
+ return $this->getData('blocks_created_count', []);
148
+ }
149
+
150
+ public function getBlocksRenderedCount()
151
+ {
152
+ return $this->getData('blocks_rendered_count', 0);
153
+ }
154
+
155
+
156
+
157
+ /**
158
+ * @codeCoverageIgnore
159
+ * @return Mage_Core_Model_Layout
160
+ */
161
+ public function getLayout()
162
+ {
163
+ return Mage::app()->getLayout();
164
+ }
165
+
166
+ /**
167
+ * @codeCoverageIgnore
168
+ * @return string
169
+ */
170
+ public function getName()
171
+ {
172
+ return 'layout';
173
+ }
174
+
175
+ }
app/code/community/Ecocode/Profiler/Model/Collector/LogDataCollector.php ADDED
@@ -0,0 +1,217 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Ecocode_Profiler_Model_Collector_LogDataCollector
5
+ */
6
+ class Ecocode_Profiler_Model_Collector_LogDataCollector
7
+ extends Ecocode_Profiler_Model_Collector_AbstractDataCollector
8
+ implements Ecocode_Profiler_Model_Collector_LateDataCollectorInterface
9
+ {
10
+ private $errorNames = [
11
+ E_DEPRECATED => 'E_DEPRECATED',
12
+ E_USER_DEPRECATED => 'E_USER_DEPRECATED',
13
+ E_NOTICE => 'E_NOTICE',
14
+ E_USER_NOTICE => 'E_USER_NOTICE',
15
+ E_STRICT => 'E_STRICT',
16
+ E_WARNING => 'E_WARNING',
17
+ E_USER_WARNING => 'E_USER_WARNING',
18
+ E_COMPILE_WARNING => 'E_COMPILE_WARNING',
19
+ E_CORE_WARNING => 'E_CORE_WARNING',
20
+ E_USER_ERROR => 'E_USER_ERROR',
21
+ E_RECOVERABLE_ERROR => 'E_RECOVERABLE_ERROR',
22
+ E_COMPILE_ERROR => 'E_COMPILE_ERROR',
23
+ E_PARSE => 'E_PARSE',
24
+ E_ERROR => 'E_ERROR',
25
+ E_CORE_ERROR => 'E_CORE_ERROR',
26
+ ];
27
+
28
+ protected $logger;
29
+
30
+ /**
31
+ * Ecocode_Profiler_Model_Collector_LogDataCollector constructor.
32
+ */
33
+ public function __construct()
34
+ {
35
+ $this->logger = Mage::getLogger();
36
+ }
37
+
38
+ /**
39
+ * {@inheritdoc}
40
+ */
41
+ public function collect(Mage_Core_Controller_Request_Http $request, Mage_Core_Controller_Response_Http $response, \Exception $exception = null)
42
+ {
43
+ $this->data = [
44
+ 'logs' => [],
45
+ 'total_count' => 0
46
+ ];
47
+ }
48
+
49
+
50
+ public function lateCollect()
51
+ {
52
+ $this->data = [];
53
+ if ($this->logger) {
54
+ $this->data = $this->computeErrorsCount();
55
+ $this->data['logs'] = $this->sanitizeLogs($this->getLogger()->getLogs());
56
+ }
57
+ }
58
+
59
+ public function countErrors()
60
+ {
61
+ return isset($this->data['error_count']) ? $this->data['error_count'] : 0;
62
+ }
63
+
64
+ /**
65
+ * Gets the logs.
66
+ *
67
+ * @return array An array of logs
68
+ */
69
+ public function getLogs()
70
+ {
71
+ return isset($this->data['logs']) ? $this->data['logs'] : [];
72
+ }
73
+
74
+ public function getPriorities()
75
+ {
76
+ return isset($this->data['priorities']) ? $this->data['priorities'] : [];
77
+ }
78
+
79
+ public function countDeprecations()
80
+ {
81
+ return isset($this->data['deprecation_count']) ? $this->data['deprecation_count'] : 0;
82
+ }
83
+
84
+ public function countScreams()
85
+ {
86
+ return isset($this->data['scream_count']) ? $this->data['scream_count'] : 0;
87
+ }
88
+
89
+ private function sanitizeLogs($logs)
90
+ {
91
+ $errorContextById = [];
92
+ $sanitizedLogs = [];
93
+
94
+ foreach ($logs as $log) {
95
+ $context = $this->sanitizeContext($log['context']);
96
+
97
+ if (isset($context['type'], $context['file'], $context['line'], $context['level'])) {
98
+ $errorId = md5("{$context['type']}/{$context['line']}/{$context['file']}\x00{$log['message']}", true);
99
+ $silenced = !($context['type'] & $context['level']);
100
+ if (isset($this->errorNames[$context['type']])) {
101
+ $context = array_merge(['name' => $this->errorNames[$context['type']]], $context);
102
+ }
103
+
104
+ if (isset($errorContextById[$errorId])) {
105
+ if (isset($errorContextById[$errorId]['errorCount'])) {
106
+ ++$errorContextById[$errorId]['errorCount'];
107
+ } else {
108
+ $errorContextById[$errorId]['errorCount'] = 2;
109
+ }
110
+
111
+ if (!$silenced && isset($errorContextById[$errorId]['scream'])) {
112
+ unset($errorContextById[$errorId]['scream']);
113
+ $errorContextById[$errorId]['level'] = $context['level'];
114
+ }
115
+
116
+ continue;
117
+ }
118
+
119
+ $errorContextById[$errorId] = &$context;
120
+ if ($silenced) {
121
+ $context['scream'] = true;
122
+ }
123
+
124
+ $log['context'] = &$context;
125
+ unset($context);
126
+ } else {
127
+ $log['context'] = $context;
128
+ }
129
+
130
+ $sanitizedLogs[] = $log;
131
+ }
132
+
133
+ return $sanitizedLogs;
134
+ }
135
+
136
+ private function sanitizeContext($context)
137
+ {
138
+ if (is_array($context)) {
139
+ foreach ($context as $key => $value) {
140
+ $context[$key] = $this->sanitizeContext($value);
141
+ }
142
+
143
+ return $context;
144
+ }
145
+
146
+ if (is_resource($context)) {
147
+ return sprintf('Resource(%s)', get_resource_type($context));
148
+ }
149
+
150
+ if (is_object($context)) {
151
+ return sprintf('Object(%s)', get_class($context));
152
+ }
153
+
154
+ return $context;
155
+ }
156
+
157
+ private function computeErrorsCount()
158
+ {
159
+ $logger = $this->getLogger();
160
+ $count = [
161
+ 'total_log_count' => count($logger->getLogs()),
162
+ 'error_count' => $logger->countErrors(),
163
+ 'deprecation_count' => 0,
164
+ 'scream_count' => 0,
165
+ 'priorities' => [],
166
+ ];
167
+
168
+ foreach ($logger->getLogs() as $log) {
169
+ if (isset($count['priorities'][$log['priority']])) {
170
+ ++$count['priorities'][$log['priority']]['count'];
171
+ } else {
172
+ $count['priorities'][$log['priority']] = [
173
+ 'count' => 1,
174
+ 'name' => $log['priorityName'],
175
+ ];
176
+ }
177
+
178
+ if (isset($log['context']['type'], $log['context']['level'])) {
179
+ if (E_DEPRECATED === $log['context']['type'] || E_USER_DEPRECATED === $log['context']['type']) {
180
+ ++$count['deprecation_count'];
181
+ } elseif (!($log['context']['type'] & $log['context']['level'])) {
182
+ ++$count['scream_count'];
183
+ }
184
+ }
185
+ }
186
+
187
+ ksort($count['priorities']);
188
+
189
+ return $count;
190
+ }
191
+
192
+ public function getLogCount()
193
+ {
194
+ return isset($this->data['total_log_count']) ? $this->data['total_log_count'] : 0;
195
+ }
196
+
197
+
198
+ /**
199
+ * @codeCoverageIgnore
200
+ * {@inheritdoc}
201
+ */
202
+ protected function getLogger()
203
+ {
204
+ return $this->logger;
205
+ }
206
+
207
+
208
+ /**
209
+ * @codeCoverageIgnore
210
+ * {@inheritdoc}
211
+ */
212
+ public function getName()
213
+ {
214
+ return 'log';
215
+ }
216
+
217
+ }
app/code/community/Ecocode/Profiler/Model/Collector/MemoryDataCollector.php ADDED
@@ -0,0 +1,113 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Ecocode_Profiler_Model_Collector_MemoryDataCollector
5
+ */
6
+ class Ecocode_Profiler_Model_Collector_MemoryDataCollector
7
+ extends Ecocode_Profiler_Model_Collector_AbstractDataCollector
8
+ implements Ecocode_Profiler_Model_Collector_LateDataCollectorInterface
9
+ {
10
+ /**
11
+ * @return string
12
+ */
13
+ protected function getCurrentMemoryLimit()
14
+ {
15
+ return ini_get('memory_limit');
16
+ }
17
+
18
+ /**
19
+ * @return int
20
+ */
21
+ protected function getCurrentPeakMemoryUsage()
22
+ {
23
+ return memory_get_peak_usage(true);
24
+ }
25
+
26
+ /**
27
+ * {@inheritdoc}
28
+ */
29
+ public function collect(Mage_Core_Controller_Request_Http $request, Mage_Core_Controller_Response_Http $response, \Exception $exception = null)
30
+ {
31
+ $this->data = [
32
+ 'memory' => 0,
33
+ 'memory_limit' => $this->convertToBytes($this->getCurrentMemoryLimit()),
34
+ ];
35
+
36
+ $this->updateMemoryUsage();
37
+ }
38
+
39
+ /**
40
+ * {@inheritdoc}
41
+ */
42
+ public function lateCollect()
43
+ {
44
+ $this->updateMemoryUsage();
45
+ }
46
+
47
+ /**
48
+ * Gets the memory.
49
+ *
50
+ * @return int The memory
51
+ */
52
+ public function getMemory()
53
+ {
54
+ return $this->data['memory'];
55
+ }
56
+
57
+ /**
58
+ * Gets the PHP memory limit.
59
+ *
60
+ * @return int The memory limit
61
+ */
62
+ public function getMemoryLimit()
63
+ {
64
+ return $this->data['memory_limit'];
65
+ }
66
+
67
+ /**
68
+ * Updates the memory usage data.
69
+ */
70
+ public function updateMemoryUsage()
71
+ {
72
+ $this->data['memory'] = $this->getCurrentPeakMemoryUsage();
73
+ }
74
+
75
+ /**
76
+ * @codeCoverageIgnore
77
+ * {@inheritdoc}
78
+ */
79
+ public function getName()
80
+ {
81
+ return 'memory';
82
+ }
83
+
84
+ private function convertToBytes($memoryLimit)
85
+ {
86
+ if ('-1' === $memoryLimit) {
87
+ return -1;
88
+ }
89
+
90
+ $memoryLimit = strtolower($memoryLimit);
91
+ $max = strtolower(ltrim($memoryLimit, '+'));
92
+ if (0 === strpos($max, '0x')) {
93
+ $max = intval($max, 16);
94
+ } elseif (0 === strpos($max, '0')) {
95
+ $max = intval($max, 8);
96
+ } else {
97
+ $max = (int)$max;
98
+ }
99
+
100
+ switch (substr($memoryLimit, -1)) {
101
+ case 't':
102
+ $max *= 1024;
103
+ case 'g':
104
+ $max *= 1024;
105
+ case 'm':
106
+ $max *= 1024;
107
+ case 'k':
108
+ $max *= 1024;
109
+ }
110
+
111
+ return $max;
112
+ }
113
+ }
app/code/community/Ecocode/Profiler/Model/Collector/ModelDataCollector.php ADDED
@@ -0,0 +1,228 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Ecocode_Profiler_Model_Collector_ModelDataCollector
5
+ */
6
+ class Ecocode_Profiler_Model_Collector_ModelDataCollector
7
+ extends Ecocode_Profiler_Model_Collector_AbstractDataCollector
8
+ {
9
+ CONST LOAD_CALL_THRESHOLD = 20;
10
+
11
+ protected $callLog = [];
12
+
13
+ /**
14
+ * @codeCoverageIgnore
15
+ * @return int
16
+ */
17
+ public function getLoadCallThreshold()
18
+ {
19
+ return static::LOAD_CALL_THRESHOLD;
20
+ }
21
+
22
+ /**
23
+ * {@inheritdoc}
24
+ */
25
+ public function collect(Mage_Core_Controller_Request_Http $request, Mage_Core_Controller_Response_Http $response, \Exception $exception = null)
26
+ {
27
+ $stats = [
28
+ 'load' => 0,
29
+ 'loop_load' => 0,
30
+ 'save' => 0,
31
+ 'delete' => 0,
32
+ ];
33
+
34
+ $totalTime = 0;
35
+ $traceHashList = [];
36
+
37
+ foreach ($this->callLog as &$item) {
38
+ switch ($item['action']) {
39
+ case 'load':
40
+ $stats[$item['action']]++;
41
+
42
+ //try to detect load calls in loops
43
+ $traceHash = $item['trace_hash'];
44
+ if (!isset($traceHashList[$traceHash])) {
45
+ $traceHashList[$traceHash] = 0;
46
+ }
47
+ $traceHashList[$traceHash]++;
48
+ break;
49
+ case 'save':
50
+ case 'delete':
51
+ $stats[$item['action']]++;
52
+ break;
53
+ }
54
+ if (!isset($item['time'])) {
55
+ $item['time'] = null;
56
+ }
57
+ $totalTime += $item['time'];
58
+ }
59
+
60
+ $traceHashList = array_filter($traceHashList, function ($v) {
61
+ return $v > 1;
62
+ });
63
+
64
+ $stats['loop_load'] = array_sum($traceHashList);
65
+
66
+ $this->data = [
67
+ 'total_time' => $totalTime,
68
+ 'metrics' => $stats,
69
+ 'calls' => $this->callLog
70
+ ];
71
+
72
+ }
73
+
74
+ public function getLoadLoopCalls()
75
+ {
76
+ $traceHashList = [];
77
+
78
+ foreach ($this->getCallLog() as $item) {
79
+ if ($item['action'] !== 'load') {
80
+ continue;
81
+ }
82
+ //try to detect load calls in loops
83
+ $traceHash = $item['trace_hash'];
84
+ if (!isset($traceHashList[$traceHash])) {
85
+ $item['count'] = 0;
86
+ $item['total_time'] = 0;
87
+ $traceHashList[$traceHash] = $item;
88
+ }
89
+ $traceHashList[$traceHash]['count']++;
90
+ $traceHashList[$traceHash]['total_time'] += $item['time'];
91
+ }
92
+
93
+ $traceHashList = array_filter($traceHashList, function ($v) {
94
+ return $v['count'] > 1;
95
+ });
96
+
97
+ usort($traceHashList, function ($a, $b) {
98
+ return $b['count'] - $a['count'];
99
+ });
100
+
101
+ return array_values($traceHashList);
102
+ }
103
+
104
+
105
+ public function getTotalTime()
106
+ {
107
+
108
+ return $this->getData('total_time', 0);
109
+ }
110
+
111
+ public function getCallLog()
112
+ {
113
+
114
+ return $this->getData('calls', []);
115
+ }
116
+
117
+
118
+ public function getMetric($key = null)
119
+ {
120
+ if ($key === null) {
121
+ return $this->data['metrics'];
122
+ }
123
+
124
+ return $this->data['metrics'][$key];
125
+ }
126
+
127
+
128
+ public function trackModelLoad(Varien_Event_Observer $observer)
129
+ {
130
+ $this->trackEvent('load', $observer->getEvent());
131
+ }
132
+
133
+ public function trackModelSave(Varien_Event_Observer $observer)
134
+ {
135
+ $this->trackEvent('save', $observer->getEvent());
136
+ }
137
+
138
+ public function trackModelDelete(Varien_Event_Observer $observer)
139
+ {
140
+ $this->trackEvent('delete', $observer->getEvent());
141
+ }
142
+
143
+ protected function trackEvent($action, Varien_Event $event)
144
+ {
145
+ $object = $event->getData('object');
146
+
147
+ $this->track($action, $object, $event->getData('time'));
148
+ }
149
+
150
+ protected function track($action, Varien_Object $object, $time = null)
151
+ {
152
+ $className = get_class($object);
153
+ $classGroup = $this->getHelper()->getClassGroup($className);
154
+ $trace = $this->cleanBacktrace($this->getBacktrace(DEBUG_BACKTRACE_IGNORE_ARGS));
155
+
156
+ $data = [
157
+ 'action' => $action,
158
+ 'class' => $className,
159
+ 'class_group' => $classGroup,
160
+ 'trace' => $trace,
161
+ 'trace_hash' => md5(serialize($trace))
162
+ ];
163
+
164
+ if ($time) {
165
+ $data['time'] = $time;
166
+ }
167
+
168
+ $this->callLog[] = $data;
169
+ }
170
+
171
+ protected function cleanBacktrace(array $backtrace)
172
+ {
173
+ $item = reset($backtrace);
174
+ while ($item && $this->shouldRemoveBacktrace($item)) {
175
+ array_shift($backtrace);
176
+ $item = reset($backtrace);
177
+ }
178
+
179
+ $backtrace = array_map(function ($item) {
180
+ unset($item['object'], $item['args'], $item['type']);
181
+ return $item;
182
+ }, $backtrace);
183
+
184
+ return $backtrace;
185
+ }
186
+
187
+
188
+ protected function shouldRemoveBacktrace($data)
189
+ {
190
+ if (!is_array($data)) {
191
+ return false;
192
+ }
193
+
194
+ if (!isset($data['class'], $data['function'])) {
195
+ return true;
196
+ }
197
+
198
+ if (!in_array($data['class'], ['Mage_Core_Model_Resource_Db_Abstract', 'Mage_Eav_Model_Entity_Abstract'])) {
199
+ return true;
200
+ }
201
+
202
+ if (!in_array($data['function'], ['load', 'delete', 'save'])) {
203
+ return true;
204
+ }
205
+
206
+ return false;
207
+ }
208
+
209
+ /**
210
+ * @codeCoverageIgnore
211
+ * @return Ecocode_Profiler_Helper_Data
212
+ */
213
+ protected function getHelper()
214
+ {
215
+ return Mage::helper('ecocode_profiler');
216
+ }
217
+
218
+
219
+ /**
220
+ * @codeCoverageIgnore
221
+ * {@inheritdoc}
222
+ */
223
+ public function getName()
224
+ {
225
+ return 'model';
226
+ }
227
+
228
+ }
app/code/community/Ecocode/Profiler/Model/Collector/MysqlDataCollector.php ADDED
@@ -0,0 +1,139 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Ecocode_Profiler_Model_Collector_MysqlDataCollector
5
+ */
6
+ class Ecocode_Profiler_Model_Collector_MysqlDataCollector
7
+ extends Ecocode_Profiler_Model_Collector_AbstractDataCollector
8
+ {
9
+ const BACKTRACE_LIMIT = 10;
10
+
11
+ protected $ignoredFunctionCalls = [
12
+ 'Mage_Core_Model_Resource_Db_Abstract::load',
13
+ 'Mage_Eav_Model_Entity_Abstract::load',
14
+ 'Mage_Catalog_Model_Resource_Abstract::load',
15
+ 'Mage_Core_Model_Abstract::load',
16
+ 'Varien_Data_Collection_Db::_fetchAll'
17
+ ];
18
+
19
+ protected $ignoreInstanceOf = [
20
+ 'Ecocode_Profiler_Model_Collector_MysqlDataCollector',
21
+ 'Zend_Db_Statement',
22
+ 'Zend_Db_Adapter_Abstract',
23
+ 'Varien_Db_Statement_Pdo_Mysql'
24
+ ];
25
+
26
+ protected $rawQueries = [];
27
+ protected $totalQueryTime = 0;
28
+
29
+ public function logQuery(Ecocode_Profiler_Db_Statement_Pdo_Mysql $statement)
30
+ {
31
+ $connectionName = 'unknown';
32
+ $connectionConfig = $statement->getAdapter()->getConfig();
33
+ if (isset($connectionConfig['connection_name'])) {
34
+ $connectionName = $connectionConfig['connection_name'];
35
+ }
36
+
37
+ $this->totalQueryTime += $statement->getElapsedTime();
38
+ $this->rawQueries[] = [
39
+ 'sql' => $statement->getQueryString(),
40
+ 'connection' => $connectionName,
41
+ 'statement' => $statement,
42
+ 'time' => $statement->getElapsedTime(),
43
+ 'params' => $statement->getParams(),
44
+ 'result' => $statement->getResult(),
45
+ 'context' => $this->getContextId(),
46
+ 'trace' => $this->getTrace()
47
+ ];
48
+ }
49
+
50
+
51
+ /**
52
+ * @param Mage_Core_Controller_Request_Http $request
53
+ * @param Mage_Core_Controller_Response_Http $response
54
+ * @param Exception|null $exception
55
+ *
56
+ * @return void
57
+ */
58
+ public function collect(Mage_Core_Controller_Request_Http $request, Mage_Core_Controller_Response_Http $response, \Exception $exception = null)
59
+ {
60
+ $this->data['nb_queries'] = count($this->rawQueries);
61
+ $this->data['total_time'] = $this->totalQueryTime;
62
+
63
+ $queries = [];
64
+ $connections = [];
65
+
66
+ foreach ($this->rawQueries as $query) {
67
+ unset($query['statement']);
68
+ $connection = $query['connection'];
69
+ if (!isset($connections[$connection])) {
70
+ $connections[$connection] = 0;
71
+
72
+ }
73
+ $connections[$connection]++;
74
+ $queries[] = $query;
75
+ }
76
+ $this->data['queries'] = $queries;
77
+ $this->data['used_connections'] = $connections;
78
+ $this->data;
79
+ }
80
+
81
+ public function getQueries()
82
+ {
83
+ return $this->data['queries'];
84
+ }
85
+
86
+ public function getConnectionData()
87
+ {
88
+ return $this->data['used_connections'];
89
+ }
90
+
91
+ public function getTotalTime()
92
+ {
93
+ return $this->data['total_time'];
94
+ }
95
+
96
+
97
+ public function getQueryCount()
98
+ {
99
+ return $this->data['nb_queries'];
100
+ }
101
+
102
+
103
+ protected function getTrace()
104
+ {
105
+ $backtrace = $this->getBacktrace();
106
+ if ($backtrace === false) {
107
+ return [];
108
+ }
109
+
110
+ $backtrace = $this->cleanBacktrace($backtrace);
111
+
112
+ $backtrace = array_slice($backtrace, 0, self::BACKTRACE_LIMIT);
113
+ $backtrace = array_map(function ($item) {
114
+ unset($item['object'], $item['args'], $item['type']);
115
+ return $item;
116
+ }, $backtrace);
117
+
118
+ return $backtrace;
119
+ }
120
+
121
+ public function cleanBacktrace(array $backtrace)
122
+ {
123
+ return Mage::helper('ecocode_profiler')
124
+ ->cleanBacktrace(
125
+ $backtrace,
126
+ $this->ignoredFunctionCalls,
127
+ $this->ignoreInstanceOf
128
+
129
+ );
130
+ }
131
+
132
+ /**
133
+ * {@inheritdoc}
134
+ */
135
+ public function getName()
136
+ {
137
+ return 'mysql';
138
+ }
139
+ }
app/code/community/Ecocode/Profiler/Model/Collector/RequestDataCollector.php ADDED
@@ -0,0 +1,488 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Ecocode_Profiler_Model_Collector_RequestDataCollector
5
+ */
6
+ class Ecocode_Profiler_Model_Collector_RequestDataCollector
7
+ extends Ecocode_Profiler_Model_Collector_AbstractDataCollector
8
+ {
9
+ public static $statusTexts = [
10
+ 100 => 'Continue',
11
+ 101 => 'Switching Protocols',
12
+ 102 => 'Processing', // RFC2518
13
+ 200 => 'OK',
14
+ 201 => 'Created',
15
+ 202 => 'Accepted',
16
+ 203 => 'Non-Authoritative Information',
17
+ 204 => 'No Content',
18
+ 205 => 'Reset Content',
19
+ 206 => 'Partial Content',
20
+ 207 => 'Multi-Status', // RFC4918
21
+ 208 => 'Already Reported', // RFC5842
22
+ 226 => 'IM Used', // RFC3229
23
+ 300 => 'Multiple Choices',
24
+ 301 => 'Moved Permanently',
25
+ 302 => 'Found',
26
+ 303 => 'See Other',
27
+ 304 => 'Not Modified',
28
+ 305 => 'Use Proxy',
29
+ 307 => 'Temporary Redirect',
30
+ 308 => 'Permanent Redirect', // RFC7238
31
+ 400 => 'Bad Request',
32
+ 401 => 'Unauthorized',
33
+ 402 => 'Payment Required',
34
+ 403 => 'Forbidden',
35
+ 404 => 'Not Found',
36
+ 405 => 'Method Not Allowed',
37
+ 406 => 'Not Acceptable',
38
+ 407 => 'Proxy Authentication Required',
39
+ 408 => 'Request Timeout',
40
+ 409 => 'Conflict',
41
+ 410 => 'Gone',
42
+ 411 => 'Length Required',
43
+ 412 => 'Precondition Failed',
44
+ 413 => 'Payload Too Large',
45
+ 414 => 'URI Too Long',
46
+ 415 => 'Unsupported Media Type',
47
+ 416 => 'Range Not Satisfiable',
48
+ 417 => 'Expectation Failed',
49
+ 418 => 'I\'m a teapot', // RFC2324
50
+ 421 => 'Misdirected Request', // RFC7540
51
+ 422 => 'Unprocessable Entity', // RFC4918
52
+ 423 => 'Locked', // RFC4918
53
+ 424 => 'Failed Dependency', // RFC4918
54
+ 425 => 'Reserved for WebDAV advanced collections expired proposal', // RFC2817
55
+ 426 => 'Upgrade Required', // RFC2817
56
+ 428 => 'Precondition Required', // RFC6585
57
+ 429 => 'Too Many Requests', // RFC6585
58
+ 431 => 'Request Header Fields Too Large', // RFC6585
59
+ 451 => 'Unavailable For Legal Reasons', // RFC7725
60
+ 500 => 'Internal Server Error',
61
+ 501 => 'Not Implemented',
62
+ 502 => 'Bad Gateway',
63
+ 503 => 'Service Unavailable',
64
+ 504 => 'Gateway Timeout',
65
+ 505 => 'HTTP Version Not Supported',
66
+ 506 => 'Variant Also Negotiates (Experimental)', // RFC2295
67
+ 507 => 'Insufficient Storage', // RFC4918
68
+ 508 => 'Loop Detected', // RFC5842
69
+ 510 => 'Not Extended', // RFC2774
70
+ 511 => 'Network Authentication Required', // RFC6585
71
+ ];
72
+
73
+ /**
74
+ * {@inheritdoc}
75
+ */
76
+ public function collect(Mage_Core_Controller_Request_Http $request, Mage_Core_Controller_Response_Http $response, \Exception $exception = null)
77
+ {
78
+ $responseHeaders = $this->collectResponseHeaders($response);
79
+ // attributes are serialized and as they can be anything, they need to be converted to strings.
80
+ $requestAttributes = $this->collectRequestAttributes($request);
81
+ $requestHeaders = $this->collectRequestHeaders($request);
82
+ $requestContent = $request->getRawBody();
83
+
84
+ $sessionMetadata = [];
85
+ $sessionAttributes = [];
86
+ //@TODO get all magento session singletons to split them by namespace
87
+ $flashes = [];
88
+
89
+ /*
90
+ $session = null
91
+ if (false && $request->hasSession()) {
92
+ $session = $request->getSession();
93
+ if ($session->isStarted()) {
94
+ $sessionMetadata['Created'] = date(DATE_RFC822, $session->getMetadataBag()->getCreated());
95
+ $sessionMetadata['Last used'] = date(DATE_RFC822, $session->getMetadataBag()->getLastUsed());
96
+ $sessionMetadata['Lifetime'] = $session->getMetadataBag()->getLifetime();
97
+ $sessionAttributes = $session->all();
98
+ $flashes = $session->getFlashBag()->peekAll();
99
+ }
100
+ }*/
101
+
102
+ $statusCode = $this->detectStatusCode($response);
103
+ $statusText = isset(self::$statusTexts[$statusCode]) ? self::$statusTexts[$statusCode] : '';
104
+
105
+
106
+ $contentType = isset($responseHeaders['Content-Type']) ? $responseHeaders['Content-Type'] : 'text/html';
107
+ $this->data = [
108
+ 'method' => $request->getMethod(),
109
+ 'content' => $requestContent,
110
+ 'content_type' => $contentType,
111
+ 'status_text' => $statusText,
112
+ 'status_code' => $statusCode,
113
+ 'request_query' => $this->collectRequestQuery($request),
114
+ 'request_request' => $this->collectRequestData($request),
115
+ 'request_headers' => $requestHeaders,
116
+ 'request_server' => $request->getServer(),
117
+ 'request_cookies' => $request->getCookie(),
118
+ 'request_attributes' => $requestAttributes,
119
+ 'response_headers' => $responseHeaders,
120
+ 'session_metadata' => $sessionMetadata,
121
+ 'session_attributes' => $sessionAttributes,
122
+ 'flashes' => $flashes,
123
+ 'path_info' => $request->getPathInfo(),
124
+ 'controller' => 'n/a',
125
+ //'locale' => $request->getLocale(),
126
+ ];
127
+
128
+ $this->hideAuthData();
129
+
130
+ $controllerData = $this->collectControllerData();
131
+ if ($controllerData) {
132
+ $this->data['controller'] = $controllerData;
133
+ }
134
+
135
+ /*if (null !== $session && $session->isStarted()) {
136
+ if ($request->attributes->has('_redirected')) {
137
+ $this->data['redirect'] = $session->remove('sf_redirect');
138
+ }
139
+
140
+ if ($response->isRedirect()) {
141
+ $session->set('sf_redirect', [
142
+ 'token' => $response->headers->get('x-debug-token'),
143
+ 'route' => $request->attributes->get('_route', 'n/a'),
144
+ 'method' => $request->getMethod(),
145
+ 'controller' => $this->parseController($request->attributes->get('_controller')),
146
+ 'status_code' => $statusCode,
147
+ 'status_text' => Response::$statusTexts[(int)$statusCode],
148
+ ]);
149
+ }
150
+ }*/
151
+ }
152
+
153
+ protected function hideAuthData()
154
+ {
155
+ if (isset($this->data['request_headers']['php-auth-pw'])) {
156
+ $this->data['request_headers']['php-auth-pw'] = '******';
157
+ }
158
+
159
+ if (isset($this->data['request_server']['PHP_AUTH_PW'])) {
160
+ $this->data['request_server']['PHP_AUTH_PW'] = '******';
161
+ }
162
+
163
+ if (isset($this->data['request_request']['_password'])) {
164
+ $this->data['request_request']['_password'] = '******';
165
+ }
166
+ }
167
+
168
+ public function getMethod()
169
+ {
170
+ return $this->data['method'];
171
+ }
172
+
173
+ public function getPathInfo()
174
+ {
175
+ return $this->data['path_info'];
176
+ }
177
+
178
+ public function getRequestRequest()
179
+ {
180
+ return new Ecocode_Profiler_Model_Http_ParameterBag($this->data['request_request']);
181
+ }
182
+
183
+ public function getRequestQuery()
184
+ {
185
+ return new Ecocode_Profiler_Model_Http_ParameterBag($this->data['request_query']);
186
+ }
187
+
188
+ public function getRequestHeaders()
189
+ {
190
+ return new Ecocode_Profiler_Model_Http_HeaderBag($this->data['request_headers']);
191
+ }
192
+
193
+ public function getRequestServer()
194
+ {
195
+ return new Ecocode_Profiler_Model_Http_ParameterBag($this->data['request_server']);
196
+ }
197
+
198
+ public function getRequestCookies()
199
+ {
200
+ return new Ecocode_Profiler_Model_Http_ParameterBag($this->data['request_cookies']);
201
+ }
202
+
203
+ public function getRequestAttributes()
204
+ {
205
+ return new Ecocode_Profiler_Model_Http_ParameterBag($this->data['request_attributes']);
206
+ }
207
+
208
+ public function getResponseHeaders()
209
+ {
210
+ return new Ecocode_Profiler_Model_Http_ResponseHeaderBag($this->data['response_headers']);
211
+ }
212
+
213
+ public function getSessionMetadata()
214
+ {
215
+ return $this->data['session_metadata'];
216
+ }
217
+
218
+ public function getSessionAttributes()
219
+ {
220
+ return $this->data['session_attributes'];
221
+ }
222
+
223
+ public function getFlashes()
224
+ {
225
+ return $this->data['flashes'];
226
+ }
227
+
228
+ public function getContent()
229
+ {
230
+ return $this->data['content'];
231
+ }
232
+
233
+ public function getContentType()
234
+ {
235
+ return $this->data['content_type'];
236
+ }
237
+
238
+ public function getStatusText()
239
+ {
240
+ return $this->data['status_text'];
241
+ }
242
+
243
+ public function getStatusCode()
244
+ {
245
+ return $this->data['status_code'];
246
+ }
247
+
248
+ public function getFormat()
249
+ {
250
+ return $this->data['format'];
251
+ }
252
+
253
+ public function getLocale()
254
+ {
255
+ return $this->data['locale'];
256
+ }
257
+
258
+ /**
259
+ * Gets the route name.
260
+ *
261
+ * @return string The route
262
+ */
263
+ public function getRoute()
264
+ {
265
+ return isset($this->data['request_attributes']['_route']) ? $this->data['request_attributes']['_route'] : '';
266
+ }
267
+
268
+ /**
269
+ * @return string
270
+ */
271
+ public function getRequestUri()
272
+ {
273
+ return isset($this->data['request_attributes']['request_uri']) ? $this->data['request_attributes']['request_uri'] : '';
274
+ }
275
+
276
+ /**
277
+ * @return string
278
+ */
279
+ public function getRequestString()
280
+ {
281
+ return isset($this->data['request_attributes']['request_string']) ? $this->data['request_attributes']['request_string'] : '';
282
+ }
283
+
284
+ /**
285
+ * @return string
286
+ */
287
+ public function getRouteName()
288
+ {
289
+ return isset($this->data['request_attributes']['_route_name']) ? $this->data['request_attributes']['_route_name'] : '';
290
+ }
291
+
292
+ /**
293
+ * @return string
294
+ */
295
+ public function getModuleName()
296
+ {
297
+ return isset($this->data['request_attributes']['_module']) ? $this->data['request_attributes']['_module'] : '';
298
+ }
299
+
300
+ /**
301
+ * @return string
302
+ */
303
+ public function getControllerName()
304
+ {
305
+ return isset($this->data['request_attributes']['_controller']) ? $this->data['request_attributes']['_controller'] : '';
306
+ }
307
+
308
+ /**
309
+ * @return string
310
+ */
311
+ public function getActionName()
312
+ {
313
+ return isset($this->data['request_attributes']['_action']) ? $this->data['request_attributes']['_action'] : '';
314
+ }
315
+
316
+ /**
317
+ * Gets the route parameters.
318
+ *
319
+ * @return array The parameters
320
+ */
321
+ public function getRouteParams()
322
+ {
323
+ return isset($this->data['request_attributes']['_route_params']) ? $this->data['request_attributes']['_route_params'] : [];
324
+ }
325
+
326
+ /**
327
+ * Gets the parsed controller.
328
+ *
329
+ * @return array|string The controller as a string or array of data
330
+ * with keys 'class', 'method', 'file' and 'line'
331
+ */
332
+ public function getController()
333
+ {
334
+ return $this->data['controller'];
335
+ }
336
+
337
+ /**
338
+ * Gets the previous request attributes.
339
+ *
340
+ * @return array|bool A legacy array of data from the previous redirection response
341
+ * or false otherwise
342
+ */
343
+ public function getRedirect()
344
+ {
345
+ return isset($this->data['redirect']) ? $this->data['redirect'] : false;
346
+ }
347
+
348
+
349
+ /**
350
+ * {@inheritdoc}
351
+ * @codeCoverageIgnore
352
+ */
353
+ public function getName()
354
+ {
355
+ return 'request';
356
+ }
357
+
358
+ /**
359
+ * Parse a controller.
360
+ *
361
+ * @param mixed $controller The controller to parse
362
+ *
363
+ * @return array|string An array of controller data or a simple string
364
+ */
365
+ protected function parseController($controller)
366
+ {
367
+ if (is_object($controller)) {
368
+ $r = new \ReflectionClass($controller);
369
+
370
+ return [
371
+ 'class' => $r->getName(),
372
+ 'method' => null,
373
+ 'file' => $r->getFileName(),
374
+ 'line' => $r->getStartLine(),
375
+ ];
376
+ }
377
+
378
+ return (string)$controller ?: 'n/a';
379
+ }
380
+
381
+ protected function detectStatusCode(Mage_Core_Controller_Response_Http $response)
382
+ {
383
+ $statusCode = $response->getHttpResponseCode();
384
+ foreach ($response->getHeaders() as $header) {
385
+ if (substr($header['name'], 0, 5) === 'Http/') {
386
+ preg_match('/^[0-9]{3}/', $header['value'], $matches);
387
+ if ($matches) {
388
+ $statusCode = (int)reset($matches);
389
+ }
390
+
391
+ break;
392
+ }
393
+ }
394
+ return $statusCode;
395
+ }
396
+
397
+ protected function collectRequestAttributes(Mage_Core_Controller_Request_Http $request)
398
+ {
399
+ //we need to use a reflection as Request->getParams() takes also get parameters into account
400
+ $class = new ReflectionClass('Mage_Core_Controller_Request_Http');
401
+ /** @var ReflectionProperty $property */
402
+ $property = $class->getProperty('_params');
403
+ $property->setAccessible(true);
404
+
405
+ $routeParams = $property->getValue($request);
406
+
407
+ $fullActionName = $request->getRequestedRouteName() . '_' .
408
+ $request->getRequestedControllerName() . '_' .
409
+ $request->getRequestedActionName();
410
+
411
+ $attributes = [
412
+ 'request_string' => $request->getRequestString(),
413
+ 'request_uri' => $request->getRequestUri(),
414
+ '_module' => $request->getModuleName(),
415
+ '_controller' => $request->getControllerName(),
416
+ '_action' => $request->getActionName(),
417
+ '_route' => $fullActionName,
418
+ '_route_name' => $request->getRouteName()
419
+ ];
420
+
421
+ if ($routeParams) {
422
+ $attributes['_route_params'] = $routeParams;
423
+ }
424
+
425
+
426
+ return $attributes;
427
+ }
428
+
429
+ public function collectRequestHeaders(Mage_Core_Controller_Request_Http $request)
430
+ {
431
+ $headers = [];
432
+ foreach ($request->getServer() as $key => $value) {
433
+ if (substr($key, 0, 5) !== 'HTTP_') {
434
+ continue;
435
+ }
436
+ $header = str_replace(' ', '-', (str_replace('_', ' ', strtolower(substr($key, 5)))));
437
+ $headers[$header] = $value;
438
+ }
439
+ return $headers;
440
+ }
441
+
442
+ public function collectRequestQuery(Mage_Core_Controller_Request_Http $request)
443
+ {
444
+ $getData = $request->getQuery();
445
+ if ($getData === null) {
446
+ $getData = [];
447
+ }
448
+ return $getData;
449
+ }
450
+
451
+
452
+ public function collectRequestData(Mage_Core_Controller_Request_Http $request)
453
+ {
454
+ $postData = $request->getPost();
455
+ if ($postData === null) {
456
+ $postData = [];
457
+ }
458
+ return $postData;
459
+ }
460
+
461
+ protected function collectControllerData()
462
+ {
463
+ //use reflection to make sure we not init a front controller
464
+ $class = new ReflectionClass('Mage_Core_Model_App');
465
+ /** @var ReflectionProperty $property */
466
+ $property = $class->getProperty('_frontController');
467
+ $property->setAccessible(true);
468
+
469
+ $app = Mage::app();
470
+ $controller = $property->getValue($app);
471
+ if ($controller) {
472
+ return $this->parseController($controller);
473
+ }
474
+
475
+ return false;
476
+ }
477
+
478
+ public function collectResponseHeaders(Mage_Core_Controller_Response_Http $response)
479
+ {
480
+ $headers = [];
481
+
482
+ foreach ($response->getHeaders() as $headerData) {
483
+ $headers[$headerData['name']] = $headerData['value'];
484
+ }
485
+
486
+ return $headers;
487
+ }
488
+ }
app/code/community/Ecocode/Profiler/Model/Collector/RewriteDataCollector.php ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Ecocode_Profiler_Model_Collector_RewriteDataCollector
5
+ */
6
+ class Ecocode_Profiler_Model_Collector_RewriteDataCollector
7
+ extends Ecocode_Profiler_Model_Collector_AbstractDataCollector
8
+ {
9
+ /**
10
+ * @codeCoverageIgnore
11
+ * @return Ecocode_Profiler_Helper_Rewrite
12
+ */
13
+ protected function getRewriteHelper()
14
+ {
15
+ return Mage::helper('ecocode_profiler/rewrite');
16
+ }
17
+
18
+ /**
19
+ * {@inheritdoc}
20
+ */
21
+ public function collect(Mage_Core_Controller_Request_Http $request, Mage_Core_Controller_Response_Http $response, \Exception $exception = null)
22
+ {
23
+ $rewriteHelper = $this->getRewriteHelper();
24
+ $this->data = [
25
+ 'module_rewrites' => $rewriteHelper->loadRewrites(),
26
+ 'module_rewrite_conflicts' => $rewriteHelper->getRewriteConflicts(),
27
+ ];
28
+
29
+ }
30
+
31
+ /**
32
+ * @return array
33
+ */
34
+ public function getModuleRewrites()
35
+ {
36
+ return $this->data['module_rewrites'];
37
+ }
38
+
39
+ /**
40
+ * @return array
41
+ */
42
+ public function getModuleRewriteConflicts()
43
+ {
44
+ return $this->data['module_rewrite_conflicts'];
45
+ }
46
+
47
+
48
+ public function getModuleRewriteConflictCount()
49
+ {
50
+ return count($this->data['module_rewrite_conflicts']);
51
+ }
52
+
53
+ /**
54
+ * @codeCoverageIgnore
55
+ * @return string
56
+ */
57
+ public function getName()
58
+ {
59
+ return 'rewrite';
60
+ }
61
+
62
+ }
app/code/community/Ecocode/Profiler/Model/Collector/TimeDataCollector.php ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Ecocode_Profiler_Model_Collector_TimeDataCollector
5
+ */
6
+ class Ecocode_Profiler_Model_Collector_TimeDataCollector
7
+ extends Ecocode_Profiler_Model_Collector_AbstractDataCollector
8
+ implements Ecocode_Profiler_Model_Collector_LateDataCollectorInterface
9
+ {
10
+ /**
11
+ * {@inheritdoc}
12
+ */
13
+ public function collect(Mage_Core_Controller_Request_Http $request, Mage_Core_Controller_Response_Http $response, \Exception $exception = null)
14
+ {
15
+ $this->data = [
16
+ 'total_time' => 0
17
+ ];
18
+ }
19
+
20
+ public function lateCollect()
21
+ {
22
+ $startTime = Mage::app()->getStartTime();
23
+
24
+ if ($startTime) {
25
+ $this->data['total_time'] = microtime(true) - $startTime;
26
+ }
27
+
28
+ return $this;
29
+ }
30
+
31
+ public function getTotalTime()
32
+ {
33
+ return $this->data['total_time'];
34
+ }
35
+
36
+ /**
37
+ * @codeCoverageIgnore
38
+ * @return string
39
+ */
40
+ public function getName()
41
+ {
42
+ return 'time';
43
+ }
44
+ }
app/code/community/Ecocode/Profiler/Model/Collector/TranslationDataCollector.php ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Ecocode_Profiler_Model_Collector_TranslationDataCollector
5
+ */
6
+ class Ecocode_Profiler_Model_Collector_TranslationDataCollector
7
+ extends Ecocode_Profiler_Model_Collector_AbstractDataCollector
8
+ {
9
+ protected $_currentBlock;
10
+
11
+ protected $stateCounts = [
12
+ 'translated' => 0,
13
+ 'missing' => 0,
14
+ 'invalid' => 0,
15
+ 'fallback' => 0
16
+ ];
17
+
18
+ /**
19
+ * @return Mage_Core_Model_Translate
20
+ */
21
+ protected function getTranslator()
22
+ {
23
+ return Mage::getSingleton('core/translate');
24
+ }
25
+
26
+ /**
27
+ * {@inheritdoc}
28
+ */
29
+ public function collect(Mage_Core_Controller_Request_Http $request, Mage_Core_Controller_Response_Http $response, \Exception $exception = null)
30
+ {
31
+
32
+ $this->data['state_counts'] = $this->stateCounts;
33
+ $translations = [];
34
+
35
+ foreach ($this->getTranslator()->getMessages() as $translation) {
36
+ $translationId = $translation['code'];
37
+ if (!isset($translations[$translationId])) {
38
+ $translation['count'] = 1;
39
+ $translation['parameters'] = !empty($translation['parameters']) ? [$translation['parameters']] : [];
40
+ $translation['traces'] = !empty($translation['trace']) ? [$translation['trace']] : [];
41
+ unset($translation['trace']);
42
+ $translations[$translationId] = $translation;
43
+ $this->data['state_counts'][$translation['state']]++;
44
+ } else {
45
+ if (!empty($translation['parameters'])) {
46
+ $translations[$translationId]['parameters'][] = $translation['parameters'];
47
+ }
48
+ if (!empty($translation['trace'])) {
49
+ $translations[$translationId]['traces'][] = $translation['trace'];
50
+ }
51
+ $translations[$translationId]['count']++;
52
+ }
53
+ }
54
+ $this->data['translations'] = $translations;
55
+ $this->data['translation_count'] = count($translations);
56
+ }
57
+
58
+ public function getTranslations()
59
+ {
60
+ return $this->getData('translations', []);
61
+ }
62
+
63
+ public function getTranslationCount()
64
+ {
65
+ return $this->getData('translation_count', 0);
66
+ }
67
+
68
+ public function getStateCount($status = null)
69
+ {
70
+ if ($status === null) {
71
+ return $this->data['state_counts'];
72
+ }
73
+ return $this->data['state_counts'][$status];
74
+ }
75
+
76
+ public function getNotOkCount()
77
+ {
78
+ return $this->getStateCount('invalid')
79
+ + $this->getStateCount('missing')
80
+ + $this->getStateCount('fallback');
81
+ }
82
+
83
+ /**
84
+ * {@inheritdoc}
85
+ * @codeCoverageIgnore
86
+ */
87
+ public function getName()
88
+ {
89
+ return 'translation';
90
+ }
91
+ }
app/code/community/Ecocode/Profiler/Model/Context.php ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Ecocode_Profiler_Model_Context
5
+ */
6
+ class Ecocode_Profiler_Model_Context
7
+ implements Ecocode_Profiler_Model_ContextInterface
8
+ {
9
+ protected $parentId = 0;
10
+
11
+ /** @var string */
12
+ protected $key;
13
+
14
+ /** @var string */
15
+ protected $data;
16
+
17
+ public function __construct($key, array $data = [])
18
+ {
19
+ $this->id = uniqid();
20
+ $this->key = $key;
21
+ $this->data = $data;
22
+ }
23
+
24
+ public function getId()
25
+ {
26
+ return $this->id;
27
+ }
28
+
29
+ public function getParentId()
30
+ {
31
+ return $this->parentId;
32
+ }
33
+
34
+ public function setParentId($id)
35
+ {
36
+ $this->parentId = 0;
37
+ }
38
+
39
+
40
+ public function getKey()
41
+ {
42
+ return $this->key;
43
+ }
44
+
45
+ public function addData($key, $value)
46
+ {
47
+ $this->data[$key] = $value;
48
+
49
+ return $this;
50
+ }
51
+
52
+ public function getData()
53
+ {
54
+ return $this->data;
55
+ }
56
+ }
app/code/community/Ecocode/Profiler/Model/ContextInterface.php ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Interface Ecocode_Profiler_Model_ContextInterface
5
+ */
6
+ interface Ecocode_Profiler_Model_ContextInterface
7
+ {
8
+
9
+ public function getId();
10
+
11
+ public function getParentId();
12
+
13
+ public function setParentId($id);
14
+
15
+ public function getKey();
16
+
17
+ public function getData();
18
+
19
+ public function addData($key, $value);
20
+
21
+ }
app/code/community/Ecocode/Profiler/Model/Core/Cache.php ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Ecocode_Profiler_Model_Core_Cache
5
+ */
6
+ class Ecocode_Profiler_Model_Core_Cache extends Mage_Core_Model_Cache
7
+ {
8
+ protected $log = [];
9
+
10
+ public function load($id)
11
+ {
12
+ $start = microtime(true);
13
+ $result = parent::load($id);
14
+ $execTime = microtime(true) - $start;
15
+
16
+ $this->log[] = ['action' => 'load', 'id' => $id, 'hit' => ($result !== false), 'time' => $execTime];
17
+
18
+ return $result;
19
+ }
20
+
21
+ public function save($data, $id, $tags = [], $lifeTime = null)
22
+ {
23
+ $start = microtime(true);
24
+ $result = parent::save($data, $id, $tags, $lifeTime);
25
+ $execTime = microtime(true) - $start;
26
+
27
+ $this->log[] = ['action' => 'save', 'id' => $id, 'tags' => $tags, 'life_time' => $lifeTime, 'time' => $execTime];
28
+ return $result;
29
+ }
30
+
31
+ public function clean($tags = [])
32
+ {
33
+
34
+ $loadTime = microtime(true);
35
+ $result = parent::clean($tags);
36
+ $execTime = microtime(true) - $loadTime;
37
+ $this->log[] = ['action' => 'clean', 'tags' => $tags, 'time' => $execTime];
38
+
39
+ return $result;
40
+ }
41
+
42
+ public function getLog()
43
+ {
44
+ return $this->log;
45
+ }
46
+ }
app/code/community/Ecocode/Profiler/Model/Core/Config.php ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Ecocode_Profiler_Model_Core_Config
5
+ */
6
+ class Ecocode_Profiler_Model_Core_Config extends Mage_Core_Model_Config
7
+ {
8
+
9
+ public function loadBase()
10
+ {
11
+ parent::loadBase();
12
+
13
+ //needed as the mysql collector needs to log queries before the config is loaded!!!
14
+ $this->setNode('global/models/ecocode_profiler/class', 'Ecocode_Profiler_Model');
15
+ $this->setNode('global/helpers/ecocode_profiler/class', 'Ecocode_Profiler_Helper');
16
+ }
17
+ /**
18
+ * Load modules configuration
19
+ *
20
+ * @return Mage_Core_Model_Config
21
+ */
22
+ public function loadModules()
23
+ {
24
+ parent::loadModules();
25
+
26
+ /* load development.xml for all modules if present */
27
+ $this->loadModulesConfiguration(['development.xml'], $this);
28
+ return $this;
29
+ }
30
+
31
+ public function loadDb()
32
+ {
33
+ parent::loadDb();
34
+
35
+ //overwrite symlinks if needed
36
+ $this->enableSymlinks();
37
+
38
+ return $this;
39
+ }
40
+
41
+ protected function enableSymlinks()
42
+ {
43
+ $dir = $this->getModuleDir('etc', 'Ecocode_Profiler');
44
+ if (is_link($dir)) {
45
+ //due to magentos awesome "config->loadDb()" call we need to overwrite each store
46
+ //as the config gets copied over into all stores, so setting only the "default" is not enough
47
+ $this->setNode('default/dev/template/allow_symlink', true);
48
+ foreach($this->getNode('websites')->children() as $website) {
49
+ $website->setNode(Mage_Core_Block_Template::XML_PATH_TEMPLATE_ALLOW_SYMLINK, true);
50
+ }
51
+ foreach($this->getNode('stores')->children() as $store) {
52
+ $store->setNode(Mage_Core_Block_Template::XML_PATH_TEMPLATE_ALLOW_SYMLINK, true);
53
+ }
54
+ }
55
+ }
56
+ }
app/code/community/Ecocode/Profiler/Model/DebugLoggerInterface.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+
4
+ /**
5
+ * DebugLoggerInterface.
6
+ *
7
+ * @author Fabien Potencier <fabien@symfony.com>
8
+ */
9
+ interface Ecocode_Profiler_Model_DebugLoggerInterface
10
+ {
11
+ /**
12
+ * Returns an array of logs.
13
+ *
14
+ * A log is an array with the following mandatory keys:
15
+ * timestamp, message, priority, and priorityName.
16
+ * It can also have an optional context key containing an array.
17
+ *
18
+ * @return array An array of logs
19
+ */
20
+ public function getLogs();
21
+
22
+ /**
23
+ * Returns the number of errors.
24
+ *
25
+ * @return int The number of errors
26
+ */
27
+ public function countErrors();
28
+ }
app/code/community/Ecocode/Profiler/Model/Http/HeaderBag.php ADDED
@@ -0,0 +1,322 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * HeaderBag is a container for HTTP headers.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ */
17
+ class Ecocode_Profiler_Model_Http_HeaderBag implements \IteratorAggregate, \Countable
18
+ {
19
+ protected $headers = [];
20
+ protected $cacheControl = [];
21
+
22
+ /**
23
+ * Constructor.
24
+ *
25
+ * @param array $headers An array of HTTP headers
26
+ */
27
+ public function __construct(array $headers = [])
28
+ {
29
+ foreach ($headers as $key => $values) {
30
+ $this->set($key, $values);
31
+ }
32
+ }
33
+
34
+ /**
35
+ * Returns the headers as a string.
36
+ *
37
+ * @return string The headers
38
+ */
39
+ public function __toString()
40
+ {
41
+ if (!$this->headers) {
42
+ return '';
43
+ }
44
+
45
+ $max = max(array_map('strlen', array_keys($this->headers))) + 1;
46
+ $content = '';
47
+ ksort($this->headers);
48
+ foreach ($this->headers as $name => $values) {
49
+ $name = implode('-', array_map('ucfirst', explode('-', $name)));
50
+ foreach ($values as $value) {
51
+ $content .= sprintf("%-{$max}s %s\r\n", $name . ':', $value);
52
+ }
53
+ }
54
+
55
+ return $content;
56
+ }
57
+
58
+ /**
59
+ * Returns the headers.
60
+ *
61
+ * @return array An array of headers
62
+ */
63
+ public function all()
64
+ {
65
+ return $this->headers;
66
+ }
67
+
68
+ /**
69
+ * Returns the parameter keys.
70
+ *
71
+ * @return array An array of parameter keys
72
+ */
73
+ public function keys()
74
+ {
75
+ return array_keys($this->headers);
76
+ }
77
+
78
+ /**
79
+ * Replaces the current HTTP headers by a new set.
80
+ *
81
+ * @param array $headers An array of HTTP headers
82
+ */
83
+ public function replace(array $headers = [])
84
+ {
85
+ $this->headers = [];
86
+ $this->add($headers);
87
+ }
88
+
89
+ /**
90
+ * Adds new headers the current HTTP headers set.
91
+ *
92
+ * @param array $headers An array of HTTP headers
93
+ */
94
+ public function add(array $headers)
95
+ {
96
+ foreach ($headers as $key => $values) {
97
+ $this->set($key, $values);
98
+ }
99
+ }
100
+
101
+ /**
102
+ * Returns a header value by name.
103
+ *
104
+ * @param string $key The header name
105
+ * @param mixed $default The default value
106
+ * @param bool $first Whether to return the first value or all header values
107
+ *
108
+ * @return string|array The first header value if $first is true, an array of values otherwise
109
+ */
110
+ public function get($key, $default = null, $first = true)
111
+ {
112
+ $key = str_replace('_', '-', strtolower($key));
113
+
114
+ if (!array_key_exists($key, $this->headers)) {
115
+ if (null === $default) {
116
+ return $first ? null : [];
117
+ }
118
+
119
+ return $first ? $default : [$default];
120
+ }
121
+
122
+ if ($first) {
123
+ return count($this->headers[$key]) ? $this->headers[$key][0] : $default;
124
+ }
125
+
126
+ return $this->headers[$key];
127
+ }
128
+
129
+ /**
130
+ * Sets a header by name.
131
+ *
132
+ * @param string $key The key
133
+ * @param string|array $values The value or an array of values
134
+ * @param bool $replace Whether to replace the actual value or not (true by default)
135
+ */
136
+ public function set($key, $values, $replace = true)
137
+ {
138
+ $key = str_replace('_', '-', strtolower($key));
139
+
140
+ $values = array_values((array)$values);
141
+
142
+ if (true === $replace || !isset($this->headers[$key])) {
143
+ $this->headers[$key] = $values;
144
+ } else {
145
+ $this->headers[$key] = array_merge($this->headers[$key], $values);
146
+ }
147
+
148
+ if ('cache-control' === $key) {
149
+ $this->cacheControl = $this->parseCacheControl($values[0]);
150
+ }
151
+ }
152
+
153
+ /**
154
+ * Returns true if the HTTP header is defined.
155
+ *
156
+ * @param string $key The HTTP header
157
+ *
158
+ * @return bool true if the parameter exists, false otherwise
159
+ */
160
+ public function has($key)
161
+ {
162
+ return array_key_exists(str_replace('_', '-', strtolower($key)), $this->headers);
163
+ }
164
+
165
+ /**
166
+ * Returns true if the given HTTP header contains the given value.
167
+ *
168
+ * @param string $key The HTTP header name
169
+ * @param string $value The HTTP value
170
+ *
171
+ * @return bool true if the value is contained in the header, false otherwise
172
+ */
173
+ public function contains($key, $value)
174
+ {
175
+ return in_array($value, $this->get($key, null, false));
176
+ }
177
+
178
+ /**
179
+ * Removes a header.
180
+ *
181
+ * @param string $key The HTTP header name
182
+ */
183
+ public function remove($key)
184
+ {
185
+ $key = str_replace('_', '-', strtolower($key));
186
+
187
+ unset($this->headers[$key]);
188
+
189
+ if ('cache-control' === $key) {
190
+ $this->cacheControl = [];
191
+ }
192
+ }
193
+
194
+ /**
195
+ * Returns the HTTP header value converted to a date.
196
+ *
197
+ * @param string $key The parameter key
198
+ * @param \DateTime $default The default value
199
+ *
200
+ * @return null|\DateTime The parsed DateTime or the default value if the header does not exist
201
+ *
202
+ * @throws \RuntimeException When the HTTP header is not parseable
203
+ */
204
+ public function getDate($key, \DateTime $default = null)
205
+ {
206
+ if (null === $value = $this->get($key)) {
207
+ return $default;
208
+ }
209
+
210
+ if (false === $date = \DateTime::createFromFormat(DATE_RFC2822, $value)) {
211
+ throw new \RuntimeException(sprintf('The %s HTTP header is not parseable (%s).', $key, $value));
212
+ }
213
+
214
+ return $date;
215
+ }
216
+
217
+ /**
218
+ * Adds a custom Cache-Control directive.
219
+ *
220
+ * @param string $key The Cache-Control directive name
221
+ * @param mixed $value The Cache-Control directive value
222
+ */
223
+ public function addCacheControlDirective($key, $value = true)
224
+ {
225
+ $this->cacheControl[$key] = $value;
226
+
227
+ $this->set('Cache-Control', $this->getCacheControlHeader());
228
+ }
229
+
230
+ /**
231
+ * Returns true if the Cache-Control directive is defined.
232
+ *
233
+ * @param string $key The Cache-Control directive
234
+ *
235
+ * @return bool true if the directive exists, false otherwise
236
+ */
237
+ public function hasCacheControlDirective($key)
238
+ {
239
+ return array_key_exists($key, $this->cacheControl);
240
+ }
241
+
242
+ /**
243
+ * Returns a Cache-Control directive value by name.
244
+ *
245
+ * @param string $key The directive name
246
+ *
247
+ * @return mixed|null The directive value if defined, null otherwise
248
+ */
249
+ public function getCacheControlDirective($key)
250
+ {
251
+ return array_key_exists($key, $this->cacheControl) ? $this->cacheControl[$key] : null;
252
+ }
253
+
254
+ /**
255
+ * Removes a Cache-Control directive.
256
+ *
257
+ * @param string $key The Cache-Control directive
258
+ */
259
+ public function removeCacheControlDirective($key)
260
+ {
261
+ unset($this->cacheControl[$key]);
262
+
263
+ $this->set('Cache-Control', $this->getCacheControlHeader());
264
+ }
265
+
266
+ /**
267
+ * Returns an iterator for headers.
268
+ *
269
+ * @return \ArrayIterator An \ArrayIterator instance
270
+ */
271
+ public function getIterator()
272
+ {
273
+ return new \ArrayIterator($this->headers);
274
+ }
275
+
276
+ /**
277
+ * Returns the number of headers.
278
+ *
279
+ * @return int The number of headers
280
+ */
281
+ public function count()
282
+ {
283
+ return count($this->headers);
284
+ }
285
+
286
+ protected function getCacheControlHeader()
287
+ {
288
+ $parts = [];
289
+ ksort($this->cacheControl);
290
+ foreach ($this->cacheControl as $key => $value) {
291
+ if (true === $value) {
292
+ $parts[] = $key;
293
+ } else {
294
+ if (preg_match('#[^a-zA-Z0-9._-]#', $value)) {
295
+ $value = '"' . $value . '"';
296
+ }
297
+
298
+ $parts[] = "$key=$value";
299
+ }
300
+ }
301
+
302
+ return implode(', ', $parts);
303
+ }
304
+
305
+ /**
306
+ * Parses a Cache-Control HTTP header.
307
+ *
308
+ * @param string $header The value of the Cache-Control HTTP header
309
+ *
310
+ * @return array An array representing the attribute values
311
+ */
312
+ protected function parseCacheControl($header)
313
+ {
314
+ $cacheControl = [];
315
+ preg_match_all('#([a-zA-Z][a-zA-Z_-]*)\s*(?:=(?:"([^"]*)"|([^ \t",;]*)))?#', $header, $matches, PREG_SET_ORDER);
316
+ foreach ($matches as $match) {
317
+ $cacheControl[strtolower($match[1])] = isset($match[3]) ? $match[3] : (isset($match[2]) ? $match[2] : true);
318
+ }
319
+
320
+ return $cacheControl;
321
+ }
322
+ }
app/code/community/Ecocode/Profiler/Model/Http/ParameterBag.php ADDED
@@ -0,0 +1,235 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * This file is part of the Symfony package.
4
+ *
5
+ * (c) Fabien Potencier <fabien@symfony.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+
11
+ /**
12
+ * ParameterBag is a container for key/value pairs.
13
+ *
14
+ * @author Fabien Potencier <fabien@symfony.com>
15
+ */
16
+ class Ecocode_Profiler_Model_Http_ParameterBag implements \IteratorAggregate, \Countable
17
+ {
18
+ /**
19
+ * Parameter storage.
20
+ *
21
+ * @var array
22
+ */
23
+ protected $parameters;
24
+
25
+ /**
26
+ * Constructor.
27
+ *
28
+ * @param array $parameters An array of parameters
29
+ */
30
+ public function __construct(array $parameters = [])
31
+ {
32
+ $this->parameters = $parameters;
33
+ }
34
+
35
+ /**
36
+ * Returns the parameters.
37
+ *
38
+ * @return array An array of parameters
39
+ */
40
+ public function all()
41
+ {
42
+ return $this->parameters;
43
+ }
44
+
45
+ /**
46
+ * Returns the parameter keys.
47
+ *
48
+ * @return array An array of parameter keys
49
+ */
50
+ public function keys()
51
+ {
52
+ return array_keys($this->parameters);
53
+ }
54
+
55
+ /**
56
+ * Replaces the current parameters by a new set.
57
+ *
58
+ * @param array $parameters An array of parameters
59
+ */
60
+ public function replace(array $parameters = [])
61
+ {
62
+ $this->parameters = $parameters;
63
+ }
64
+
65
+ /**
66
+ * Adds parameters.
67
+ *
68
+ * @param array $parameters An array of parameters
69
+ */
70
+ public function add(array $parameters = [])
71
+ {
72
+ $this->parameters = array_replace($this->parameters, $parameters);
73
+ }
74
+
75
+ /**
76
+ * Returns a parameter by name.
77
+ *
78
+ * @param string $key The key
79
+ * @param mixed $default The default value if the parameter key does not exist
80
+ *
81
+ * @return mixed
82
+ */
83
+ public function get($key, $default = null)
84
+ {
85
+ return array_key_exists($key, $this->parameters) ? $this->parameters[$key] : $default;
86
+ }
87
+
88
+ /**
89
+ * Sets a parameter by name.
90
+ *
91
+ * @param string $key The key
92
+ * @param mixed $value The value
93
+ */
94
+ public function set($key, $value)
95
+ {
96
+ $this->parameters[$key] = $value;
97
+ }
98
+
99
+ /**
100
+ * Returns true if the parameter is defined.
101
+ *
102
+ * @param string $key The key
103
+ *
104
+ * @return bool true if the parameter exists, false otherwise
105
+ */
106
+ public function has($key)
107
+ {
108
+ return array_key_exists($key, $this->parameters);
109
+ }
110
+
111
+ /**
112
+ * Removes a parameter.
113
+ *
114
+ * @param string $key The key
115
+ */
116
+ public function remove($key)
117
+ {
118
+ unset($this->parameters[$key]);
119
+ }
120
+
121
+ /**
122
+ * Returns the alphabetic characters of the parameter value.
123
+ *
124
+ * @param string $key The parameter key
125
+ * @param string $default The default value if the parameter key does not exist
126
+ *
127
+ * @return string The filtered value
128
+ */
129
+ public function getAlpha($key, $default = '')
130
+ {
131
+ return preg_replace('/[^[:alpha:]]/', '', $this->get($key, $default));
132
+ }
133
+
134
+ /**
135
+ * Returns the alphabetic characters and digits of the parameter value.
136
+ *
137
+ * @param string $key The parameter key
138
+ * @param string $default The default value if the parameter key does not exist
139
+ *
140
+ * @return string The filtered value
141
+ */
142
+ public function getAlnum($key, $default = '')
143
+ {
144
+ return preg_replace('/[^[:alnum:]]/', '', $this->get($key, $default));
145
+ }
146
+
147
+ /**
148
+ * Returns the digits of the parameter value.
149
+ *
150
+ * @param string $key The parameter key
151
+ * @param string $default The default value if the parameter key does not exist
152
+ *
153
+ * @return string The filtered value
154
+ */
155
+ public function getDigits($key, $default = '')
156
+ {
157
+ // we need to remove - and + because they're allowed in the filter
158
+ return str_replace(['-', '+'], '', $this->filter($key, $default, FILTER_SANITIZE_NUMBER_INT));
159
+ }
160
+
161
+ /**
162
+ * Returns the parameter value converted to integer.
163
+ *
164
+ * @param string $key The parameter key
165
+ * @param int $default The default value if the parameter key does not exist
166
+ *
167
+ * @return int The filtered value
168
+ */
169
+ public function getInt($key, $default = 0)
170
+ {
171
+ return (int)$this->get($key, $default);
172
+ }
173
+
174
+ /**
175
+ * Returns the parameter value converted to boolean.
176
+ *
177
+ * @param string $key The parameter key
178
+ * @param mixed $default The default value if the parameter key does not exist
179
+ *
180
+ * @return bool The filtered value
181
+ */
182
+ public function getBoolean($key, $default = false)
183
+ {
184
+ return $this->filter($key, $default, FILTER_VALIDATE_BOOLEAN);
185
+ }
186
+
187
+ /**
188
+ * Filter key.
189
+ *
190
+ * @param string $key Key
191
+ * @param mixed $default Default = null
192
+ * @param int $filter FILTER_* constant
193
+ * @param mixed $options Filter options
194
+ *
195
+ * @see http://php.net/manual/en/function.filter-var.php
196
+ *
197
+ * @return mixed
198
+ */
199
+ public function filter($key, $default = null, $filter = FILTER_DEFAULT, $options = [])
200
+ {
201
+ $value = $this->get($key, $default);
202
+
203
+ // Always turn $options into an array - this allows filter_var option shortcuts.
204
+ if (!is_array($options) && $options) {
205
+ $options = ['flags' => $options];
206
+ }
207
+
208
+ // Add a convenience check for arrays.
209
+ if (is_array($value) && !isset($options['flags'])) {
210
+ $options['flags'] = FILTER_REQUIRE_ARRAY;
211
+ }
212
+
213
+ return filter_var($value, $filter, $options);
214
+ }
215
+
216
+ /**
217
+ * Returns an iterator for parameters.
218
+ *
219
+ * @return \ArrayIterator An \ArrayIterator instance
220
+ */
221
+ public function getIterator()
222
+ {
223
+ return new \ArrayIterator($this->parameters);
224
+ }
225
+
226
+ /**
227
+ * Returns the number of parameters.
228
+ *
229
+ * @return int The number of parameters
230
+ */
231
+ public function count()
232
+ {
233
+ return count($this->parameters);
234
+ }
235
+ }
app/code/community/Ecocode/Profiler/Model/Http/ResponseHeaderBag.php ADDED
@@ -0,0 +1,240 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+
13
+ /**
14
+ * ResponseHeaderBag is a container for Response HTTP headers.
15
+ *
16
+ * @author Fabien Potencier <fabien@symfony.com>
17
+ */
18
+ class Ecocode_Profiler_Model_Http_ResponseHeaderBag
19
+ extends Ecocode_Profiler_Model_Http_HeaderBag
20
+ {
21
+ const COOKIES_FLAT = 'flat';
22
+ const COOKIES_ARRAY = 'array';
23
+
24
+ const DISPOSITION_ATTACHMENT = 'attachment';
25
+ const DISPOSITION_INLINE = 'inline';
26
+
27
+ /**
28
+ * @var array
29
+ */
30
+ protected $computedCacheControl = [];
31
+
32
+ /**
33
+ * @var array
34
+ */
35
+ protected $cookies = [];
36
+
37
+ /**
38
+ * @var array
39
+ */
40
+ protected $headerNames = [];
41
+
42
+ /**
43
+ * Constructor.
44
+ *
45
+ * @param array $headers An array of HTTP headers
46
+ */
47
+ public function __construct(array $headers = [])
48
+ {
49
+ parent::__construct($headers);
50
+
51
+ if (!isset($this->headers['cache-control'])) {
52
+ $this->set('Cache-Control', '');
53
+ }
54
+ }
55
+
56
+ /**
57
+ * {@inheritdoc}
58
+ */
59
+ public function __toString()
60
+ {
61
+ $cookies = '';
62
+ foreach ($this->getCookies() as $cookie) {
63
+ $cookies .= 'Set-Cookie: ' . $cookie . "\r\n";
64
+ }
65
+
66
+ ksort($this->headerNames);
67
+
68
+ return parent::__toString() . $cookies;
69
+ }
70
+
71
+ /**
72
+ * Returns the headers, with original capitalizations.
73
+ *
74
+ * @return array An array of headers
75
+ */
76
+ public function allPreserveCase()
77
+ {
78
+ return array_combine($this->headerNames, $this->headers);
79
+ }
80
+
81
+ /**
82
+ * {@inheritdoc}
83
+ */
84
+ public function replace(array $headers = [])
85
+ {
86
+ $this->headerNames = [];
87
+
88
+ parent::replace($headers);
89
+
90
+ if (!isset($this->headers['cache-control'])) {
91
+ $this->set('Cache-Control', '');
92
+ }
93
+ }
94
+
95
+ /**
96
+ * {@inheritdoc}
97
+ */
98
+ public function set($key, $values, $replace = true)
99
+ {
100
+ parent::set($key, $values, $replace);
101
+
102
+ $uniqueKey = str_replace('_', '-', strtolower($key));
103
+ $this->headerNames[$uniqueKey] = $key;
104
+
105
+ // ensure the cache-control header has sensible defaults
106
+ if (in_array($uniqueKey, ['cache-control', 'etag', 'last-modified', 'expires'])) {
107
+ $computed = $this->computeCacheControlValue();
108
+ $this->headers['cache-control'] = [$computed];
109
+ $this->headerNames['cache-control'] = 'Cache-Control';
110
+ $this->computedCacheControl = $this->parseCacheControl($computed);
111
+ }
112
+ }
113
+
114
+ /**
115
+ * {@inheritdoc}
116
+ */
117
+ public function remove($key)
118
+ {
119
+ parent::remove($key);
120
+
121
+ $uniqueKey = str_replace('_', '-', strtolower($key));
122
+ unset($this->headerNames[$uniqueKey]);
123
+
124
+ if ('cache-control' === $uniqueKey) {
125
+ $this->computedCacheControl = [];
126
+ }
127
+ }
128
+
129
+ /**
130
+ * Returns an array with all cookies.
131
+ *
132
+ * @param string $format
133
+ *
134
+ * @return array
135
+ *
136
+ * @throws \InvalidArgumentException When the $format is invalid
137
+ */
138
+ public function getCookies($format = self::COOKIES_FLAT)
139
+ {
140
+ if (!in_array($format, [self::COOKIES_FLAT, self::COOKIES_ARRAY])) {
141
+ throw new \InvalidArgumentException(sprintf('Format "%s" invalid (%s).', $format, implode(', ', [self::COOKIES_FLAT, self::COOKIES_ARRAY])));
142
+ }
143
+
144
+ if (self::COOKIES_ARRAY === $format) {
145
+ return $this->cookies;
146
+ }
147
+
148
+ $flattenedCookies = [];
149
+ foreach ($this->cookies as $path) {
150
+ foreach ($path as $cookies) {
151
+ foreach ($cookies as $cookie) {
152
+ $flattenedCookies[] = $cookie;
153
+ }
154
+ }
155
+ }
156
+
157
+ return $flattenedCookies;
158
+ }
159
+
160
+ /**
161
+ * Generates a HTTP Content-Disposition field-value.
162
+ *
163
+ * @param string $disposition One of "inline" or "attachment"
164
+ * @param string $filename A unicode string
165
+ * @param string $filenameFallback A string containing only ASCII characters that
166
+ * is semantically equivalent to $filename. If the filename is already ASCII,
167
+ * it can be omitted, or just copied from $filename
168
+ *
169
+ * @return string A string suitable for use as a Content-Disposition field-value
170
+ *
171
+ * @throws \InvalidArgumentException
172
+ *
173
+ * @see RFC 6266
174
+ */
175
+ public function makeDisposition($disposition, $filename, $filenameFallback = '')
176
+ {
177
+ if (!in_array($disposition, [self::DISPOSITION_ATTACHMENT, self::DISPOSITION_INLINE])) {
178
+ throw new \InvalidArgumentException(sprintf('The disposition must be either "%s" or "%s".', self::DISPOSITION_ATTACHMENT, self::DISPOSITION_INLINE));
179
+ }
180
+
181
+ if ('' == $filenameFallback) {
182
+ $filenameFallback = $filename;
183
+ }
184
+
185
+ // filenameFallback is not ASCII.
186
+ if (!preg_match('/^[\x20-\x7e]*$/', $filenameFallback)) {
187
+ throw new \InvalidArgumentException('The filename fallback must only contain ASCII characters.');
188
+ }
189
+
190
+ // percent characters aren't safe in fallback.
191
+ if (false !== strpos($filenameFallback, '%')) {
192
+ throw new \InvalidArgumentException('The filename fallback cannot contain the "%" character.');
193
+ }
194
+
195
+ // path separators aren't allowed in either.
196
+ if (false !== strpos($filename, '/') || false !== strpos($filename, '\\') || false !== strpos($filenameFallback, '/') || false !== strpos($filenameFallback, '\\')) {
197
+ throw new \InvalidArgumentException('The filename and the fallback cannot contain the "/" and "\\" characters.');
198
+ }
199
+
200
+ $output = sprintf('%s; filename="%s"', $disposition, str_replace('"', '\\"', $filenameFallback));
201
+
202
+ if ($filename !== $filenameFallback) {
203
+ $output .= sprintf("; filename*=utf-8''%s", rawurlencode($filename));
204
+ }
205
+
206
+ return $output;
207
+ }
208
+
209
+ /**
210
+ * Returns the calculated value of the cache-control header.
211
+ *
212
+ * This considers several other headers and calculates or modifies the
213
+ * cache-control header to a sensible, conservative value.
214
+ *
215
+ * @return string
216
+ */
217
+ protected function computeCacheControlValue()
218
+ {
219
+ if (!$this->cacheControl && !$this->has('ETag') && !$this->has('Last-Modified') && !$this->has('Expires')) {
220
+ return 'no-cache';
221
+ }
222
+
223
+ if (!$this->cacheControl) {
224
+ // conservative by default
225
+ return 'private, must-revalidate';
226
+ }
227
+
228
+ $header = $this->getCacheControlHeader();
229
+ if (isset($this->cacheControl['public']) || isset($this->cacheControl['private'])) {
230
+ return $header;
231
+ }
232
+
233
+ // public if s-maxage is defined, private otherwise
234
+ if (!isset($this->cacheControl['s-maxage'])) {
235
+ return $header . ', private';
236
+ }
237
+
238
+ return $header;
239
+ }
240
+ }
app/code/community/Ecocode/Profiler/Model/Logger.php ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ use Monolog\Logger as BaseLogger;
13
+
14
+ /**
15
+ * Logger.
16
+ *
17
+ * @author Fabien Potencier <fabien@symfony.com>
18
+ */
19
+ class Ecocode_Profiler_Model_Logger
20
+ extends BaseLogger
21
+ implements Ecocode_Profiler_Model_DebugLoggerInterface
22
+ {
23
+
24
+ protected static $levelMap = [
25
+ Zend_Log::DEBUG => self::DEBUG,
26
+ Zend_Log::INFO => self::INFO,
27
+ Zend_Log::NOTICE => self::NOTICE,
28
+ Zend_Log::WARN => self::WARNING,
29
+ Zend_Log::ERR => self::ERROR,
30
+ Zend_Log::CRIT => self::CRITICAL,
31
+ Zend_Log::ALERT => self::ALERT,
32
+ Zend_Log::EMERG => self::EMERGENCY
33
+ ];
34
+
35
+
36
+ public function mageLog($level, $message, array $context = [])
37
+ {
38
+ $level = self::$levelMap[$level];
39
+ return $this->log($level, $message, $context);
40
+ }
41
+
42
+ /**
43
+ * {@inheritdoc}
44
+ */
45
+ public function getLogs()
46
+ {
47
+ if ($logger = $this->getDebugLogger()) {
48
+ return $logger->getLogs();
49
+ }
50
+
51
+ return [];
52
+ }
53
+
54
+ /**
55
+ * {@inheritdoc}
56
+ */
57
+ public function countErrors()
58
+ {
59
+ if ($logger = $this->getDebugLogger()) {
60
+ return $logger->countErrors();
61
+ }
62
+
63
+ return 0;
64
+ }
65
+
66
+ /**
67
+ * Returns a DebugLoggerInterface instance if one is registered with this logger.
68
+ *
69
+ * @return Ecocode_Profiler_Model_DebugLoggerInterface|null A DebugLoggerInterface instance or null if none is registered
70
+ */
71
+ private function getDebugLogger()
72
+ {
73
+ foreach ($this->handlers as $handler) {
74
+ if ($handler instanceof Ecocode_Profiler_Model_DebugLoggerInterface) {
75
+ return $handler;
76
+ }
77
+ }
78
+ }
79
+ }
app/code/community/Ecocode/Profiler/Model/Logger/DebugHandler.php ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+
13
+ use Monolog\Logger;
14
+ use Monolog\Handler\TestHandler;
15
+
16
+ /**
17
+ * DebugLogger.
18
+ *
19
+ * @author Jordi Boggiano <j.boggiano@seld.be>
20
+ */
21
+ class Ecocode_Profiler_Model_Logger_DebugHandler extends TestHandler
22
+ implements Ecocode_Profiler_Model_DebugLoggerInterface
23
+ {
24
+ /**
25
+ * {@inheritdoc}
26
+ */
27
+ public function getLogs()
28
+ {
29
+ $records = [];
30
+ foreach ($this->records as $record) {
31
+ $records[] = [
32
+ 'timestamp' => $record['datetime']->getTimestamp(),
33
+ 'message' => $record['message'],
34
+ 'priority' => $record['level'],
35
+ 'priorityName' => $record['level_name'],
36
+ 'context' => $record['context'],
37
+ 'channel' => isset($record['channel']) ? $record['channel'] : '',
38
+ ];
39
+ }
40
+
41
+ return $records;
42
+ }
43
+
44
+ /**
45
+ * {@inheritdoc}
46
+ */
47
+ public function countErrors()
48
+ {
49
+ $cnt = 0;
50
+ $levels = [Logger::ERROR, Logger::CRITICAL, Logger::ALERT, Logger::EMERGENCY];
51
+ foreach ($levels as $level) {
52
+ if (isset($this->recordsByLevel[$level])) {
53
+ $cnt += count($this->recordsByLevel[$level]);
54
+ }
55
+ }
56
+
57
+ return $cnt;
58
+ }
59
+ }
60
+
app/code/community/Ecocode/Profiler/Model/Observer.php ADDED
@@ -0,0 +1,116 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Ecocode_Profiler_Model_Observer
5
+ */
6
+ class Ecocode_Profiler_Model_Observer
7
+ {
8
+ /** @var Ecocode_Profiler_Model_Profiler */
9
+ protected $profiler;
10
+
11
+ protected $profiles;
12
+
13
+ public function __construct()
14
+ {
15
+ $this->profiles = new \SplObjectStorage();
16
+ }
17
+
18
+ public function controllerFrontSendResponseBefore(Varien_Event_Observer $observer)
19
+ {
20
+ if (!$this->getProfiler()->isEnabled()) {
21
+ return;
22
+ }
23
+
24
+ $event = $observer->getEvent();
25
+ /** @var Mage_Core_Controller_Varien_Front $front */
26
+ $front = $event->getData('front');
27
+ $request = $front->getRequest();
28
+ $response = $front->getResponse();
29
+ $profile = $this->getProfiler()->collect($front->getRequest(), $response);
30
+ if ($profile) {
31
+ $this->profiles[$request] = $profile;
32
+ }
33
+
34
+ $token = null;
35
+ foreach ($response->getHeaders() as $header) {
36
+ if ($header['name'] === 'X-Debug-Token') {
37
+ $token = $header['value'];
38
+ break;
39
+ }
40
+ }
41
+
42
+ if ($token) {
43
+ $url = Mage::helper('ecocode_profiler')->getUrl($token);
44
+ $response->setHeader('X-Debug-Token-Link', $url);
45
+ }
46
+
47
+ $this->injectToolbar($response, $request, $token);
48
+ }
49
+
50
+ public function onTerminate()
51
+ {
52
+ foreach ($this->profiles as $request) {
53
+ $this->getProfiler()->saveProfile($this->profiles[$request]);
54
+ }
55
+ }
56
+
57
+ /**
58
+ * Injects the web debug toolbar into the given Response.
59
+ *
60
+ * @param Mage_Core_Controller_Response_Http $response A Response instance
61
+ * @param Mage_Core_Controller_Request_Http $request
62
+ * @param null $token
63
+ */
64
+ protected function injectToolbar(
65
+ Mage_Core_Controller_Response_Http $response,
66
+ Mage_Core_Controller_Request_Http $request,
67
+ $token = null
68
+ )
69
+ {
70
+ $content = $response->getBody();
71
+ $pos = strripos($content, '</body>');
72
+
73
+ if (false !== $pos) {
74
+ $layout = $this->getLayout();
75
+ /** @var Ecocode_Profiler_Block_Toolbar $toolbarBlock */
76
+ $toolbarBlock = $layout
77
+ ->createBlock('ecocode_profiler/toolbar', 'profiler_toolbar')
78
+ ->setData([
79
+ 'token' => $token,
80
+ 'request' => $request,
81
+ ]);
82
+
83
+ $baseJsBlock = $layout->createBlock('core/template', 'profiler_base_js')
84
+ ->setTemplate('ecocode_profiler/profiler/base.js.phtml');
85
+
86
+ $toolbarBlock->setChild('base_js', $baseJsBlock);
87
+
88
+ $toolbar = "\n" . str_replace("\n", '', $toolbarBlock->toHtml()) . "\n";
89
+ $content = substr($content, 0, $pos) . $toolbar . substr($content, $pos);
90
+ $response->setBody($content);
91
+ }
92
+ }
93
+
94
+ /**
95
+ * @codeCoverageIgnore
96
+ * @return Ecocode_Profiler_Model_Profiler
97
+ */
98
+ protected function getProfiler()
99
+ {
100
+ if (!$this->profiler) {
101
+ $this->profiler = Mage::getSingleton('ecocode_profiler/profiler');
102
+ }
103
+
104
+ return $this->profiler;
105
+ }
106
+
107
+
108
+ /**
109
+ * @codeCoverageIgnore
110
+ * @return Mage_Core_Model_Layout
111
+ */
112
+ protected function getLayout()
113
+ {
114
+ return Mage::app()->getLayout();
115
+ }
116
+ }
app/code/community/Ecocode/Profiler/Model/Observer/Context.php ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Ecocode_Profiler_Model_Observer_Context
5
+ */
6
+ class Ecocode_Profiler_Model_Observer_Context
7
+ {
8
+ protected $helper;
9
+
10
+
11
+ public function openBlockContext(Varien_Event_Observer $observer)
12
+ {
13
+ $event = $observer->getEvent();
14
+ $block = $event->getData('block');
15
+
16
+ $data = [
17
+ 'class' => get_class($block),
18
+ 'module' => $block->getModuleName()
19
+ ];
20
+
21
+ $context = new Ecocode_Profiler_Model_Context('block::' . $block->getNameInLayout(), $data);
22
+ $block->setData('__context', $context);
23
+
24
+ $this->getHelper()
25
+ ->open($context);
26
+ }
27
+
28
+ public function closeBlockContext(Varien_Event_Observer $observer)
29
+ {
30
+ $event = $observer->getEvent();
31
+ $block = $event->getData('block');
32
+
33
+ if ($context = $block->getData('__context')) {
34
+ if ($block instanceof Mage_Core_Block_Template) {
35
+ $context->addData('template', $block->getTemplate());
36
+ }
37
+
38
+ $this->getHelper()
39
+ ->close($context);
40
+ }
41
+ }
42
+
43
+ /**
44
+ * @codeCoverageIgnore
45
+ * @return Ecocode_Profiler_Helper_Context
46
+ */
47
+ public function getHelper()
48
+ {
49
+ if ($this->helper === null) {
50
+ $this->helper = Mage::helper('ecocode_profiler/context');
51
+ }
52
+
53
+ return $this->helper;
54
+ }
55
+ }
app/code/community/Ecocode/Profiler/Model/Profile.php ADDED
@@ -0,0 +1,289 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Profile.
5
+ *
6
+ * @author Fabien Potencier <fabien@symfony.com>
7
+ */
8
+ class Ecocode_Profiler_Model_Profile
9
+ {
10
+ protected $token;
11
+
12
+ /**
13
+ * @var \Ecocode_Profiler_Model_Collector_DataCollectorInterface[]
14
+ */
15
+ protected $collectors = array();
16
+
17
+ protected $ip;
18
+ protected $method;
19
+ protected $url;
20
+ protected $time;
21
+ protected $statusCode;
22
+ protected $collectTime;
23
+
24
+ /**
25
+ * @var Ecocode_Profiler_Model_Profile
26
+ */
27
+ protected $parent;
28
+
29
+ /**
30
+ * @var Ecocode_Profiler_Model_Profile[]
31
+ */
32
+ protected $children = array();
33
+
34
+ /**
35
+ * Constructor.
36
+ *
37
+ * @param string $token The token
38
+ */
39
+ public function __construct($token)
40
+ {
41
+ $this->token = $token;
42
+ }
43
+
44
+ /**
45
+ * Gets the token.
46
+ *
47
+ * @return string The token
48
+ */
49
+ public function getToken()
50
+ {
51
+ return $this->token;
52
+ }
53
+
54
+ /**
55
+ * Sets the parent token.
56
+ *
57
+ * @param Ecocode_Profiler_Model_Profile $parent The parent Profile
58
+ */
59
+ public function setParent(Ecocode_Profiler_Model_Profile $parent)
60
+ {
61
+ $this->parent = $parent;
62
+ }
63
+
64
+ /**
65
+ * Returns the parent profile.
66
+ *
67
+ * @return Ecocode_Profiler_Model_Profile The parent profile
68
+ */
69
+ public function getParent()
70
+ {
71
+ return $this->parent;
72
+ }
73
+
74
+ /**
75
+ * Returns the parent token.
76
+ *
77
+ * @return null|string The parent token
78
+ */
79
+ public function getParentToken()
80
+ {
81
+ return $this->parent ? $this->parent->getToken() : null;
82
+ }
83
+
84
+ /**
85
+ * Returns the IP.
86
+ *
87
+ * @return string The IP
88
+ */
89
+ public function getIp()
90
+ {
91
+ return $this->ip;
92
+ }
93
+
94
+ /**
95
+ * Sets the IP.
96
+ *
97
+ * @param string $ip
98
+ */
99
+ public function setIp($ip)
100
+ {
101
+ $this->ip = $ip;
102
+ }
103
+
104
+ /**
105
+ * Returns the request method.
106
+ *
107
+ * @return string The request method
108
+ */
109
+ public function getMethod()
110
+ {
111
+ return $this->method;
112
+ }
113
+
114
+ public function setMethod($method)
115
+ {
116
+ $this->method = $method;
117
+ }
118
+
119
+ /**
120
+ * Returns the URL.
121
+ *
122
+ * @return string The URL
123
+ */
124
+ public function getUrl()
125
+ {
126
+ return $this->url;
127
+ }
128
+
129
+ public function setUrl($url)
130
+ {
131
+ $this->url = $url;
132
+ }
133
+
134
+ /**
135
+ * Returns the time.
136
+ *
137
+ * @return string The time
138
+ */
139
+ public function getTime()
140
+ {
141
+ if (null === $this->time) {
142
+ return 0;
143
+ }
144
+
145
+ return $this->time;
146
+ }
147
+
148
+ public function setTime($time)
149
+ {
150
+ $this->time = $time;
151
+ }
152
+
153
+ /**
154
+ * @param int $statusCode
155
+ */
156
+ public function setStatusCode($statusCode)
157
+ {
158
+ $this->statusCode = $statusCode;
159
+ }
160
+
161
+ /**
162
+ * @return int
163
+ */
164
+ public function getStatusCode()
165
+ {
166
+ return $this->statusCode;
167
+ }
168
+
169
+ /**
170
+ * @return int
171
+ */
172
+ public function getCollectTime()
173
+ {
174
+ return $this->collectTime;
175
+ }
176
+
177
+
178
+ /**
179
+ * @param $time
180
+ * @return int
181
+ */
182
+ public function setCollectTime($time)
183
+ {
184
+ return $this->collectTime = $time;
185
+ }
186
+
187
+
188
+ /**
189
+ * Finds children profilers.
190
+ *
191
+ * @return Ecocode_Profiler_Model_Profile[] An array of Profile
192
+ */
193
+ public function getChildren()
194
+ {
195
+ return $this->children;
196
+ }
197
+
198
+ /**
199
+ * Sets children profiler.
200
+ *
201
+ * @param Ecocode_Profiler_Model_Profile[] $children An array of Profile
202
+ */
203
+ public function setChildren(array $children)
204
+ {
205
+ $this->children = array();
206
+ foreach ($children as $child) {
207
+ $this->addChild($child);
208
+ }
209
+ }
210
+
211
+ /**
212
+ * Adds the child token.
213
+ *
214
+ * @param Ecocode_Profiler_Model_Profile $child The child Profile
215
+ */
216
+ public function addChild(Ecocode_Profiler_Model_Profile $child)
217
+ {
218
+ $this->children[] = $child;
219
+ $child->setParent($this);
220
+ }
221
+
222
+ /**
223
+ * Gets a Collector by name.
224
+ *
225
+ * @param string $name A collector name
226
+ *
227
+ * @return Ecocode_Profiler_Model_Collector_DataCollectorInterface A DataCollectorInterface instance
228
+ *
229
+ * @throws \InvalidArgumentException if the collector does not exist
230
+ */
231
+ public function getCollector($name)
232
+ {
233
+ if (!isset($this->collectors[$name])) {
234
+ throw new \InvalidArgumentException(sprintf('Collector "%s" does not exist.', $name));
235
+ }
236
+
237
+ return $this->collectors[$name];
238
+ }
239
+
240
+ /**
241
+ * Gets the Collectors associated with this profile.
242
+ *
243
+ * @return Ecocode_Profiler_Model_Collector_DataCollectorInterface[]
244
+ */
245
+ public function getCollectors()
246
+ {
247
+ return $this->collectors;
248
+ }
249
+
250
+ /**
251
+ * Sets the Collectors associated with this profile.
252
+ *
253
+ * @param Ecocode_Profiler_Model_Collector_DataCollectorInterface[] $collectors
254
+ */
255
+ public function setCollectors(array $collectors)
256
+ {
257
+ $this->collectors = array();
258
+ foreach ($collectors as $collector) {
259
+ $this->addCollector($collector);
260
+ }
261
+ }
262
+
263
+ /**
264
+ * Adds a Collector.
265
+ *
266
+ * @param Ecocode_Profiler_Model_Collector_DataCollectorInterface $collector A Ecocode_Profiler_Model_Collector_DataCollectorInterface instance
267
+ */
268
+ public function addCollector(Ecocode_Profiler_Model_Collector_DataCollectorInterface $collector)
269
+ {
270
+ $this->collectors[$collector->getName()] = $collector;
271
+ }
272
+
273
+ /**
274
+ * Returns true if a Collector for the given name exists.
275
+ *
276
+ * @param string $name A collector name
277
+ *
278
+ * @return bool
279
+ */
280
+ public function hasCollector($name)
281
+ {
282
+ return isset($this->collectors[$name]);
283
+ }
284
+
285
+ public function __sleep()
286
+ {
287
+ return array('token', 'parent', 'children', 'collectors', 'ip', 'method', 'url', 'time', 'statusCode', 'collectTime');
288
+ }
289
+ }
app/code/community/Ecocode/Profiler/Model/Profiler.php ADDED
@@ -0,0 +1,172 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Ecocode_Profiler_Model_Profiler
5
+ */
6
+ class Ecocode_Profiler_Model_Profiler
7
+ {
8
+ protected $storage;
9
+
10
+ protected $enabled = false;
11
+ protected $initialized = false;
12
+ protected $dataCollectors = null;
13
+
14
+ const URL_TOKEN_PARAMETER = 'eco_token';
15
+
16
+ public function __construct($storage = null)
17
+ {
18
+ if ($this->storage) {
19
+ $this->storage = $storage;
20
+ }
21
+ }
22
+
23
+ public function init()
24
+ {
25
+ $this->enable();
26
+ if (!$this->initialized) {
27
+ $this->initialized = true;
28
+
29
+ foreach ($this->getDataCollectors() as $dataCollector) {
30
+ /** @var Ecocode_Profiler_Model_Collector_DataCollectorInterface $dataCollector */
31
+ $dataCollector->init();
32
+ }
33
+ }
34
+ }
35
+
36
+
37
+ public function enable()
38
+ {
39
+ $this->enabled = true;
40
+ }
41
+
42
+ public function disable()
43
+ {
44
+ $this->enabled = false;
45
+ }
46
+
47
+ public function isEnabled()
48
+ {
49
+ return $this->enabled;
50
+ }
51
+
52
+
53
+ public function getDataCollectors()
54
+ {
55
+ if ($this->dataCollectors === null) {
56
+ $contextCollector = Mage::getSingleton('ecocode_profiler/collector_contextDataCollector');
57
+ $this->dataCollectors = [];
58
+
59
+ $this->dataCollectors[$contextCollector->getName()] = $contextCollector;
60
+
61
+ $collectors = Mage::getConfig()->getNode('ecocode/profiler/collectors')->asArray();
62
+ foreach ($collectors as $classGroup) {
63
+ $collector = Mage::getSingleton($classGroup);
64
+ if (!$collector instanceof Ecocode_Profiler_Model_Collector_DataCollectorInterface) {
65
+ throw new InvalidArgumentException('collector must implement "Ecocode_Profiler_Model_Collector_DataCollectorInterface"');
66
+ }
67
+ $this->dataCollectors[$collector->getName()] = $collector;
68
+ }
69
+ }
70
+
71
+ return $this->dataCollectors;
72
+ }
73
+
74
+ /**
75
+ * @param Mage_Core_Controller_Request_Http $request
76
+ * @param Mage_Core_Controller_Response_Http $response
77
+ * @return Ecocode_Profiler_Model_Profile|null
78
+ */
79
+ public function collect(Mage_Core_Controller_Request_Http $request, Mage_Core_Controller_Response_Http $response)
80
+ {
81
+ if (false === $this->isEnabled()) {
82
+ return;
83
+ }
84
+
85
+ $start = microtime(true);
86
+ $profile = new Ecocode_Profiler_Model_Profile(substr(hash('sha256', uniqid(mt_rand(), true)), 0, 6));
87
+ $profile->setTime(time());
88
+ $profile->setUrl($request->getRequestString() ? $request->getRequestString() : '/');
89
+ $profile->setMethod($request->getMethod());
90
+ $profile->setStatusCode($response->getHttpResponseCode());
91
+ $profile->setIp($request->getClientIp());
92
+
93
+ $response->setHeader('X-Debug-Token', $profile->getToken());
94
+
95
+ foreach ($this->getDataCollectors() as $collector) {
96
+ /** @var Ecocode_Profiler_Model_Collector_DataCollectorInterface $collector */
97
+ $collector->collect($request, $response);
98
+
99
+ $profile->addCollector($collector);
100
+ }
101
+ $collectTime = microtime(true) - $start;
102
+ $profile->setCollectTime($collectTime);
103
+
104
+ return $profile;
105
+ }
106
+
107
+ /**
108
+ * Loads the Profile for the given token.
109
+ *
110
+ * @param string $token A token
111
+ *
112
+ * @return Ecocode_Profiler_Model_Profile A Profile instance
113
+ */
114
+ public function loadProfile($token)
115
+ {
116
+ return $this->getStorage()->read($token);
117
+ }
118
+
119
+
120
+ public function find($ip, $url, $limit, $method, $start, $end)
121
+ {
122
+ return $this->getStorage()->find($ip, $url, $limit, $method, $this->getTimestamp($start), $this->getTimestamp($end));
123
+ }
124
+
125
+ public function saveProfile(Ecocode_Profiler_Model_Profile $profile)
126
+ {
127
+ if (false === $this->isEnabled()) {
128
+ return;
129
+ }
130
+
131
+ // late collect
132
+ foreach ($profile->getCollectors() as $collector) {
133
+ if ($collector instanceof Ecocode_Profiler_Model_Collector_LateDataCollectorInterface) {
134
+ $collector->lateCollect();
135
+ }
136
+ }
137
+
138
+ if (!$this->getStorage()->write($profile)) {
139
+ throw new Exception('Unable to store the profiler information.', ['configured_storage' => get_class($this->storage)]);
140
+ }
141
+
142
+ return true;
143
+ }
144
+
145
+ /**
146
+ * @return Ecocode_Profiler_Model_Profiler_StorageInterface
147
+ */
148
+ protected function getStorage()
149
+ {
150
+ if (!$this->storage) {
151
+ $baseDir = Mage::getBaseDir('var') . DS . '_profile';
152
+ $this->storage = Mage::getSingleton('ecocode_profiler/profiler_fileStorage', ['dsn' => 'file:' . $baseDir]);
153
+ }
154
+
155
+ return $this->storage;
156
+ }
157
+
158
+ private function getTimestamp($value)
159
+ {
160
+ if (null === $value || '' == $value) {
161
+ return;
162
+ }
163
+
164
+ try {
165
+ $value = new \DateTime(is_numeric($value) ? '@' . $value : $value);
166
+ } catch (\Exception $e) {
167
+ return;
168
+ }
169
+
170
+ return $value->getTimestamp();
171
+ }
172
+ }
app/code/community/Ecocode/Profiler/Model/Profiler/FileStorage.php ADDED
@@ -0,0 +1,295 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+
13
+ /**
14
+ * Storage for profiler using files.
15
+ *
16
+ * @author Alexandre Salomé <alexandre.salome@gmail.com>
17
+ */
18
+ class Ecocode_Profiler_Model_Profiler_FileStorage
19
+ implements Ecocode_Profiler_Model_Profiler_StorageInterface
20
+ {
21
+ /**
22
+ * Folder where profiler data are stored.
23
+ *
24
+ * @var string
25
+ */
26
+ protected $folder;
27
+
28
+ /**
29
+ * Constructs the file storage using a "dsn-like" path.
30
+ *
31
+ * Example : "file:/path/to/the/storage/folder"
32
+ *
33
+ * @param array $config
34
+ * @internal param string $dsn The DSN
35
+ *
36
+ */
37
+ public function __construct(array $config)
38
+ {
39
+ $dsn = $config['dsn'];
40
+ if (0 !== strpos($dsn, 'file:')) {
41
+ throw new \RuntimeException(sprintf('Please check your configuration. You are trying to use FileStorage with an invalid dsn "%s". The expected format is "file:/path/to/the/storage/folder".', $dsn));
42
+ }
43
+ $this->folder = substr($dsn, 5);
44
+
45
+ if (!is_dir($this->folder) && false === @mkdir($this->folder, 0777, true) && !is_dir($this->folder)) {
46
+ throw new \RuntimeException(sprintf('Unable to create the storage directory (%s).', $this->folder));
47
+ }
48
+ }
49
+
50
+ /**
51
+ * {@inheritdoc}
52
+ */
53
+ public function find($ip, $url, $limit, $method, $start = null, $end = null, $statusCode = null)
54
+ {
55
+ $file = $this->getIndexFilename();
56
+
57
+ if (!file_exists($file)) {
58
+ return [];
59
+ }
60
+
61
+ $file = fopen($file, 'r');
62
+ fseek($file, 0, SEEK_END);
63
+
64
+ $result = [];
65
+ while (count($result) < $limit && $line = $this->readLineFromFile($file)) {
66
+ $values = str_getcsv($line);
67
+ list($csvToken, $csvIp, $csvMethod, $csvUrl, $csvTime, $csvParent, $csvStatusCode) = $values;
68
+ $csvTime = (int)$csvTime;
69
+
70
+ if ($ip && false === strpos($csvIp, $ip) || $url && false === strpos($csvUrl, $url) || $method && false === strpos($csvMethod, $method) || $statusCode && false === strpos($csvStatusCode, $statusCode)) {
71
+ continue;
72
+ }
73
+
74
+ if (!empty($start) && $csvTime < $start) {
75
+ continue;
76
+ }
77
+
78
+ if (!empty($end) && $csvTime > $end) {
79
+ continue;
80
+ }
81
+
82
+ $result[$csvToken] = [
83
+ 'token' => $csvToken,
84
+ 'ip' => $csvIp,
85
+ 'method' => $csvMethod,
86
+ 'url' => $csvUrl,
87
+ 'time' => $csvTime,
88
+ 'parent' => $csvParent,
89
+ 'status_code' => $csvStatusCode,
90
+ ];
91
+ }
92
+
93
+ fclose($file);
94
+
95
+ return array_values($result);
96
+ }
97
+
98
+ /**
99
+ * {@inheritdoc}
100
+ */
101
+ public function purge()
102
+ {
103
+ $flags = \FilesystemIterator::SKIP_DOTS;
104
+ $iterator = new \RecursiveDirectoryIterator($this->folder, $flags);
105
+ $iterator = new \RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::CHILD_FIRST);
106
+
107
+ foreach ($iterator as $file) {
108
+ if (is_file($file)) {
109
+ unlink($file);
110
+ } else {
111
+ rmdir($file);
112
+ }
113
+ }
114
+ }
115
+
116
+ /**
117
+ * {@inheritdoc}
118
+ */
119
+ public function read($token)
120
+ {
121
+ if (!$token || !file_exists($file = $this->getFilename($token))) {
122
+ return;
123
+ }
124
+
125
+ return $this->createProfileFromData($token, unserialize(file_get_contents($file)));
126
+ }
127
+
128
+ /**
129
+ * {@inheritdoc}
130
+ *
131
+ * @throws \RuntimeException
132
+ */
133
+ public function write(Ecocode_Profiler_Model_Profile $profile)
134
+ {
135
+ $file = $this->getFilename($profile->getToken());
136
+
137
+ $profileIndexed = is_file($file);
138
+ if (!$profileIndexed) {
139
+ // Create directory
140
+ $dir = dirname($file);
141
+ if (!is_dir($dir) && false === @mkdir($dir, 0777, true) && !is_dir($dir)) {
142
+ throw new \RuntimeException(sprintf('Unable to create the storage directory (%s).', $dir));
143
+ }
144
+ }
145
+
146
+ // Store profile
147
+ $data = [
148
+ 'token' => $profile->getToken(),
149
+ 'parent' => $profile->getParentToken(),
150
+ 'children' => array_map(function (Ecocode_Profiler_Model_Profile $p) {
151
+ return $p->getToken();
152
+ }, $profile->getChildren()),
153
+ 'data' => $profile->getCollectors(),
154
+ 'ip' => $profile->getIp(),
155
+ 'method' => $profile->getMethod(),
156
+ 'url' => $profile->getUrl(),
157
+ 'time' => $profile->getTime(),
158
+ 'status_code' => $profile->getStatusCode(),
159
+ 'collect_time' => $profile->getCollectTime(),
160
+ ];
161
+
162
+ if (false === file_put_contents($file, serialize($data))) {
163
+ return false;
164
+ }
165
+
166
+ if (!$profileIndexed) {
167
+ // Add to index
168
+ if (false === $file = fopen($this->getIndexFilename(), 'a')) {
169
+ return false;
170
+ }
171
+
172
+ fputcsv($file, [
173
+ $profile->getToken(),
174
+ $profile->getIp(),
175
+ $profile->getMethod(),
176
+ $profile->getUrl(),
177
+ $profile->getTime(),
178
+ $profile->getParentToken(),
179
+ $profile->getStatusCode(),
180
+ ]);
181
+ fclose($file);
182
+ }
183
+
184
+ return true;
185
+ }
186
+
187
+ /**
188
+ * Gets filename to store data, associated to the token.
189
+ *
190
+ * @param string $token
191
+ *
192
+ * @return string The profile filename
193
+ */
194
+ protected function getFilename($token)
195
+ {
196
+ // Uses 4 last characters, because first are mostly the same.
197
+ $folderA = substr($token, -2, 2);
198
+ $folderB = substr($token, -4, 2);
199
+
200
+ return $this->folder . '/' . $folderA . '/' . $folderB . '/' . $token;
201
+ }
202
+
203
+ /**
204
+ * Gets the index filename.
205
+ *
206
+ * @return string The index filename
207
+ */
208
+ protected function getIndexFilename()
209
+ {
210
+ return $this->folder . '/index.csv';
211
+ }
212
+
213
+ /**
214
+ * Reads a line in the file, backward.
215
+ *
216
+ * This function automatically skips the empty lines and do not include the line return in result value.
217
+ *
218
+ * @param resource $file The file resource, with the pointer placed at the end of the line to read
219
+ *
220
+ * @return mixed A string representing the line or null if beginning of file is reached
221
+ */
222
+ protected function readLineFromFile($file)
223
+ {
224
+ $line = '';
225
+ $position = ftell($file);
226
+
227
+ if (0 === $position) {
228
+ return;
229
+ }
230
+
231
+ while (true) {
232
+ $chunkSize = min($position, 1024);
233
+ $position -= $chunkSize;
234
+ fseek($file, $position);
235
+
236
+ if (0 === $chunkSize) {
237
+ // bof reached
238
+ break;
239
+ }
240
+
241
+ $buffer = fread($file, $chunkSize);
242
+
243
+ if (false === ($upTo = strrpos($buffer, "\n"))) {
244
+ $line = $buffer . $line;
245
+ continue;
246
+ }
247
+
248
+ $position += $upTo;
249
+ $line = substr($buffer, $upTo + 1) . $line;
250
+ fseek($file, max(0, $position), SEEK_SET);
251
+
252
+ if ('' !== $line) {
253
+ break;
254
+ }
255
+ }
256
+
257
+ return '' === $line ? null : $line;
258
+ }
259
+
260
+ /**
261
+ * @param $token
262
+ * @param $data
263
+ * @param null $parent
264
+ * @return Ecocode_Profiler_Model_Profile
265
+ */
266
+ protected function createProfileFromData($token, $data, $parent = null)
267
+ {
268
+ $profile = new Ecocode_Profiler_Model_Profile($token);
269
+ $profile->setIp($data['ip']);
270
+ $profile->setMethod($data['method']);
271
+ $profile->setUrl($data['url']);
272
+ $profile->setTime($data['time']);
273
+ $profile->setStatusCode($data['status_code']);
274
+ $profile->setCollectors($data['data']);
275
+ $profile->setCollectTime($data['collect_time']);
276
+
277
+ if (!$parent && $data['parent']) {
278
+ $parent = $this->read($data['parent']);
279
+ }
280
+
281
+ if ($parent) {
282
+ $profile->setParent($parent);
283
+ }
284
+
285
+ foreach ($data['children'] as $token) {
286
+ if (!$token || !file_exists($file = $this->getFilename($token))) {
287
+ continue;
288
+ }
289
+
290
+ $profile->addChild($this->createProfileFromData($token, unserialize(file_get_contents($file)), $profile));
291
+ }
292
+
293
+ return $profile;
294
+ }
295
+ }
app/code/community/Ecocode/Profiler/Model/Profiler/StorageInterface.php ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+
13
+ /**
14
+ * ProfilerStorageInterface.
15
+ *
16
+ * @author Fabien Potencier <fabien@symfony.com>
17
+ */
18
+ interface Ecocode_Profiler_Model_Profiler_StorageInterface
19
+ {
20
+ /**
21
+ * Finds profiler tokens for the given criteria.
22
+ *
23
+ * @param string $ip The IP
24
+ * @param string $url The URL
25
+ * @param string $limit The maximum number of tokens to return
26
+ * @param string $method The request method
27
+ * @param int|null $start The start date to search from
28
+ * @param int|null $end The end date to search to
29
+ *
30
+ * @return array An array of tokens
31
+ */
32
+ public function find($ip, $url, $limit, $method, $start = null, $end = null);
33
+
34
+ /**
35
+ * Reads data associated with the given token.
36
+ *
37
+ * The method returns false if the token does not exist in the storage.
38
+ *
39
+ * @param string $token A token
40
+ *
41
+ * @return Ecocode_Profiler_Model_Profile The profile associated with token
42
+ */
43
+ public function read($token);
44
+
45
+ /**
46
+ * Saves a Profile.
47
+ *
48
+ * @param Ecocode_Profiler_Model_Profile $profile A Profile instance
49
+ *
50
+ * @return bool Write operation successful
51
+ */
52
+ public function write(Ecocode_Profiler_Model_Profile $profile);
53
+
54
+ /**
55
+ * Purges all data from the database.
56
+ */
57
+ public function purge();
58
+ }
app/code/community/Ecocode/Profiler/Tests/Dev/Controller/AbstractControllerTest.php ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Ecocode_Profiler_AbstractController
5
+ */
6
+ class Ecocode_Profiler_Tests_Dev_Controller_AbstractControllerTest
7
+ extends TestHelper
8
+ {
9
+ protected function tearDown()
10
+ {
11
+ //reset mage as we did some config changes
12
+ $this->resetMage();
13
+ Mage::getConfig();
14
+ }
15
+
16
+
17
+ /**
18
+ * @expectedException RuntimeException
19
+ * @expectExceptionMessageRegExp ^You are not allowed to access this file
20
+ */
21
+ public function testAccessDenied()
22
+ {
23
+ $request = new Mage_Core_Controller_Request_Http();
24
+ $response = new Ecocode_Profiler_Tests_Dev_Fixtures_ResponseHttp();
25
+ $controller = $this->getMockBuilder('Ecocode_Profiler_Controller_AbstractController')
26
+ ->setMethods(['getApp'])
27
+ ->setConstructorArgs([$request, $response])
28
+ ->getMock();
29
+
30
+ $app = new MageOriginal();
31
+ $controller->method('getApp')
32
+ ->willReturn($app);
33
+
34
+ /** @var Ecocode_Profiler_Controller_AbstractController $controller */
35
+ $controller->preDispatch();
36
+ }
37
+
38
+ public function testAccessAllow()
39
+ {
40
+ $request = new Mage_Core_Controller_Request_Http();
41
+ $response = new Ecocode_Profiler_Tests_Dev_Fixtures_ResponseHttp();
42
+ $controller = $this->getMockBuilder('Ecocode_Profiler_Controller_AbstractController')
43
+ ->setMethods(['getApp', '_rewrite'])
44
+ ->setConstructorArgs([$request, $response])
45
+ ->getMock();
46
+
47
+ $app = new Ecocode_Profiler_Model_AppDev();
48
+ $app->init('', 'store');
49
+ $controller->method('getApp')
50
+ ->willReturn($app);
51
+
52
+
53
+ $controller->expects($this->once())
54
+ ->method('_rewrite')
55
+ ->willReturn(true);
56
+
57
+ /** @var Ecocode_Profiler_Controller_AbstractController $controller */
58
+ $controller->preDispatch();
59
+ $this->assertConfigValue(
60
+ $app->getConfig(),
61
+ 'disabled',
62
+ 'frontend/events/core_block_abstract_to_html_before/observers/ecocode_profiler_context/type'
63
+ );
64
+ }
65
+
66
+ protected function assertConfigValue(Mage_Core_Model_Config $config, $expectValue, $configPath)
67
+ {
68
+ $this->assertEquals($expectValue, $config->getNode($configPath));
69
+ }
70
+ }
app/code/community/Ecocode/Profiler/Tests/Dev/DevModeTest.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Ecocode_Profiler_Tests_DevModeTest
4
+ extends TestHelper
5
+ {
6
+
7
+
8
+ public function testDisabledInProduction()
9
+ {
10
+ $app = Mage::app();
11
+
12
+ $this->assertInstanceOf(
13
+ 'Ecocode_Profiler_Model_AppDev',
14
+ $app
15
+ );
16
+ }
17
+
18
+ public function testCollectorsNotLoaded()
19
+ {
20
+ $app = Mage::app();
21
+
22
+ $value = $app->getConfig()->getNode('ecocode/profiler');
23
+ $this->assertNotFalse($value);
24
+ }
25
+
26
+ public function testModelsNotLoaded()
27
+ {
28
+ $app = Mage::app();
29
+
30
+ $value = $app->getConfig()->getNode('global/models/ecocode_profiler');
31
+ $this->assertNotFalse($value);
32
+ }
33
+ }
app/code/community/Ecocode/Profiler/Tests/Dev/Fixtures/DummyCacheBackend.php ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Ecocode_Profiler_Tests_Dev_Fixtures_DummyCacheBackend
4
+ extends Zend_Cache_Backend
5
+ {
6
+ protected $_options = ['test_option' => 0];
7
+ }
app/code/community/Ecocode/Profiler/Tests/Dev/Fixtures/ResponseHttp.php ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Ecocode_Profiler_Tests_Dev_Fixtures_ResponseHttp
4
+ extends Mage_Core_Controller_Response_Http
5
+ {
6
+ public function canSendHeaders($throw = true)
7
+ {
8
+ return true;
9
+ }
10
+ }
app/code/community/Ecocode/Profiler/Tests/Dev/Helper/CodeTest.php ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Ecocode_Profiler_Tests_Dev_Helper_CodeTest
4
+ extends TestHelper
5
+ {
6
+ /**
7
+ * @var Ecocode_Profiler_Helper_Code
8
+ */
9
+ private $helper;
10
+
11
+ protected function setUp()
12
+ {
13
+ $this->helper = new Ecocode_Profiler_Helper_Code('txmt://open?url=file://%f&line=%l', '/root', 'UTF-8');
14
+ }
15
+
16
+ public function testFormatFile()
17
+ {
18
+ $expected = sprintf('<a href="txmt://open?url=file://%s&amp;line=25" title="Click to open this file" class="file_link">%s at line 25</a>', __FILE__, __FILE__);
19
+ $this->assertEquals($expected, $this->helper->formatFile(__FILE__, 25));
20
+ }
21
+
22
+ /**
23
+ * @dataProvider getClassNameProvider
24
+ */
25
+ public function testGettingClassAbbreviation($class, $abbr)
26
+ {
27
+ $this->assertEquals($this->helper->abbrClass($class), $abbr);
28
+ }
29
+
30
+ /**
31
+ * @dataProvider getMethodNameProvider
32
+ */
33
+ public function testGettingMethodAbbreviation($method, $abbr)
34
+ {
35
+ $this->assertEquals($this->helper->abbrMethod($method), $abbr);
36
+ }
37
+
38
+ public function getClassNameProvider()
39
+ {
40
+ return array(
41
+ array('F\Q\N\Foo', '<abbr title="F\Q\N\Foo">Foo</abbr>'),
42
+ array('Bare', '<abbr title="Bare">Bare</abbr>'),
43
+ );
44
+ }
45
+
46
+ public function getMethodNameProvider()
47
+ {
48
+ return array(
49
+ array('F\Q\N\Foo::Method', '<abbr title="F\Q\N\Foo">Foo</abbr>::Method()'),
50
+ array('Bare::Method', '<abbr title="Bare">Bare</abbr>::Method()'),
51
+ array('Closure', '<abbr title="Closure">Closure</abbr>'),
52
+ array('Method', '<abbr title="Method">Method</abbr>()'),
53
+ );
54
+ }
55
+ }
app/code/community/Ecocode/Profiler/Tests/Dev/Helper/ContextTest.php ADDED
@@ -0,0 +1,136 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Ecocode_Profiler_Tests_Dev_Helper_ContextTest
4
+ extends TestHelper
5
+ {
6
+ public function testInit()
7
+ {
8
+ $helper = $this->getNewHelper();
9
+
10
+ $current = $helper->getCurrent();
11
+
12
+ $this->assertEquals('unknown', $current->getKey());
13
+ $this->assertEquals(0, $current->getParentId());
14
+ $this->assertCount(1, $helper->getList());
15
+ }
16
+
17
+ public function testCurrentId()
18
+ {
19
+ $helper = $this->getNewHelper();
20
+ $current = $helper->getCurrent();
21
+ $this->assertEquals($current->getId(), $helper->getCurrentId());
22
+ $helper->close($current);
23
+
24
+ $this->assertNull($helper->getCurrentId());
25
+ }
26
+
27
+ public function testOpen()
28
+ {
29
+ $helper = $this->getNewHelper();
30
+
31
+ $context = new Ecocode_Profiler_Model_Context('test-context');
32
+
33
+ $this->assertNotEquals($context, $helper->getCurrent());
34
+ $helper->open($context);
35
+ $this->assertEquals($context, $helper->getCurrent());
36
+ }
37
+
38
+ public function testClose()
39
+ {
40
+ $helper = $this->getNewHelper();
41
+
42
+ $context = new Ecocode_Profiler_Model_Context('test-context');
43
+
44
+ $helper->open($context);
45
+ $this->assertCount(2, $helper->getStack());
46
+ $helper->close($context);
47
+ $this->assertCount(1, $helper->getStack());
48
+ }
49
+
50
+ /**
51
+ * @expectedException RuntimeException
52
+ * @expectedExceptionMessage unable to close unknown context
53
+ */
54
+ public function testCloseInvalid()
55
+ {
56
+ $helper = $this->getNewHelper();
57
+
58
+ $context = new Ecocode_Profiler_Model_Context('test-context');
59
+
60
+ $helper->close($context);
61
+ }
62
+
63
+ public function testStacking()
64
+ {
65
+ $helper = $this->getNewHelper();
66
+ $rootContext = $helper->getCurrent();
67
+ $context1 = new Ecocode_Profiler_Model_Context('test-context-1');
68
+ $context2 = new Ecocode_Profiler_Model_Context('test-context-2');
69
+
70
+ $helper->open($context1);
71
+ $this->assertCount(2, $helper->getStack());
72
+ $helper->open($context2);
73
+ $this->assertCount(3, $helper->getStack());
74
+ $this->assertEquals(
75
+ [$rootContext->getId(), $context1->getId(), $context2->getId()],
76
+ $this->getStackIds($helper)
77
+ );
78
+
79
+ $helper->close($context2);
80
+ $this->assertEquals(
81
+ [$rootContext->getId(), $context1->getId()],
82
+ $this->getStackIds($helper)
83
+ );
84
+
85
+ }
86
+
87
+ public function testGetContextById()
88
+ {
89
+ $helper = $this->getNewHelper();
90
+
91
+ $context = new Ecocode_Profiler_Model_Context('test-context');
92
+ $profile = new Ecocode_Profiler_Model_Profile('xxx');
93
+ $contextCollector = new Ecocode_Profiler_Model_Collector_ContextDataCollector();
94
+
95
+ $profile->addCollector($contextCollector);
96
+ $helper->open($context);
97
+
98
+ $dataProperty = new ReflectionProperty('Ecocode_Profiler_Model_Collector_ContextDataCollector', 'data');
99
+ $dataProperty->setAccessible(true);
100
+ $dataProperty->setValue($contextCollector, ['list' => $helper->getList()]);
101
+
102
+ $mock = $this
103
+ ->getMockBuilder('Ecocode_Profiler_Helper_Context')
104
+ ->setMethods(['getCurrentProfile'])
105
+ ->getMock();
106
+
107
+ $mock->method('getCurrentProfile')
108
+ ->willReturn($profile);
109
+
110
+ /** @var Ecocode_Profiler_Helper_Context $loadedContext */
111
+ $loadedContext = $mock->getContextById($context->getId());
112
+ $this->assertEquals(
113
+ $context,
114
+ $loadedContext
115
+ );
116
+ }
117
+
118
+
119
+ /**
120
+ * @return Ecocode_Profiler_Helper_Context
121
+ */
122
+ protected function getNewHelper()
123
+ {
124
+ return new Ecocode_Profiler_Helper_Context();
125
+ }
126
+
127
+ protected function getStackIds(Ecocode_Profiler_Helper_Context $helper)
128
+ {
129
+ $ids = [];
130
+ foreach ($helper->getStack() as $context) {
131
+ /** @var Ecocode_Profiler_Model_ContextInterface $context */
132
+ $ids[] = $context->getId();
133
+ }
134
+ return $ids;
135
+ }
136
+ }
app/code/community/Ecocode/Profiler/Tests/Dev/Helper/DataTest.php ADDED
@@ -0,0 +1,94 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Ecocode_Profiler_Tests_Dev_Helper_DataTest
4
+ extends TestHelper
5
+ {
6
+ public function testGetClassGroup()
7
+ {
8
+ $classGroup = 'catalog/category';
9
+ $class = Mage::getModel($classGroup);
10
+
11
+ $helper = $this->getNewHelper();
12
+
13
+ $this->assertEquals(
14
+ $classGroup,
15
+ $helper->getClassGroup($class)
16
+ );
17
+ }
18
+
19
+ public function testUnknownGetClassGroup()
20
+ {
21
+ $classGroup = 'catalog/xxx';
22
+ $class = Mage::getModel($classGroup);
23
+
24
+ $helper = $this->getNewHelper();
25
+
26
+ $this->assertEquals(
27
+ 'unknown',
28
+ $helper->getClassGroup($class)
29
+ );
30
+ }
31
+
32
+ public function testGetCollectorUrl()
33
+ {
34
+ $helper = $this->getNewHelper();
35
+ $collector = new Ecocode_Profiler_Model_Collector_MysqlDataCollector();
36
+ $token = 'xxx';
37
+ $collectorName = $collector->getName();
38
+
39
+ $url = $helper->getCollectorUrl($token, $collector);
40
+ $url = str_replace(Mage::getBaseUrl(), '', $url);
41
+
42
+ $this->assertEquals(
43
+ sprintf('_profiler/index/panel/eco_token/%s/panel/%s/', $token, $collectorName),
44
+ $url
45
+ );
46
+ }
47
+
48
+
49
+ public function testCleanBacktraceBase()
50
+ {
51
+ $helper = $this->getNewHelper();
52
+ $backtrace = [
53
+ ['test' => 'asd', 'function' => 'test'],
54
+ ['class' => 'Test_Class', 'function' => 'asd'],
55
+ ['class' => 'Test_Class2', 'function' => 'asd'],
56
+ ];
57
+
58
+ //test empty error handling
59
+ $this->assertCount(0, $helper->cleanBacktrace([]));
60
+
61
+ $this->assertCount(2, $helper->cleanBacktrace($backtrace));
62
+ $this->assertCount(1, $helper->cleanBacktrace($backtrace, ['Test_Class::asd']));
63
+ }
64
+
65
+ public function testCleanBacktraceInstanceOf()
66
+ {
67
+ $helper = $this->getNewHelper();
68
+ $backtrace = [
69
+ ['test' => 'asd', 'function' => 'test'],
70
+ ['class' => 'Mage_Catalog_Model_Product', 'function' => 'asd'],
71
+ ['class' => 'Ecocode_Profiler_Helper_Data', 'function' => 'asd'],
72
+ ['class' => 'Mage_Catalog_Model_Product', 'function' => 'asd']
73
+ ];
74
+
75
+ foreach ($backtrace as &$trace) {
76
+ if (isset($trace['class'])) {
77
+ $trace['object'] = $this->getMockBuilder($trace['class'])->disableOriginalConstructor()->getMock();
78
+ }
79
+ }
80
+
81
+ $this->assertCount(3, $helper->cleanBacktrace($backtrace));
82
+ $this->assertCount(2, $helper->cleanBacktrace($backtrace, [], ['Varien_Object']));
83
+ $this->assertCount(0, $helper->cleanBacktrace($backtrace, [], ['Varien_Object', 'Ecocode_Profiler_Helper_Data']));
84
+ }
85
+
86
+ /**
87
+ * @return Ecocode_Profiler_Helper_Data
88
+ */
89
+ protected function getNewHelper()
90
+ {
91
+ return new Ecocode_Profiler_Helper_Data();
92
+ }
93
+
94
+ }
app/code/community/Ecocode/Profiler/Tests/Dev/Helper/RewriteTest.php ADDED
@@ -0,0 +1,124 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Ecocode_Profiler_Tests_Dev_Helper_RewriteTest
4
+ extends TestHelper
5
+ {
6
+
7
+ /**
8
+ * Magento doesn't have any conflicts out of the box, so we need to fake one
9
+ */
10
+ public function testLoadRewrites()
11
+ {
12
+ $helperMock = $this->getMockBuilder('Ecocode_Profiler_Helper_Rewrite')
13
+ ->setMethods(['getModules', 'getModuleConfigXml'])
14
+ ->getMock();
15
+
16
+ $modelBaseConfig = new Mage_Core_Model_Config_Element('<data><active>true</active></data>');
17
+ $modelDisabledBaseConfig = new Mage_Core_Model_Config_Element('<data><active>false</active></data>');
18
+ $modelEtcConfig = new Mage_Core_Model_Config_Element('<config>
19
+ <global>
20
+ <models>
21
+ <core_mysql4>
22
+ <rewrite>
23
+ <session>XXX_REWRITE</session>
24
+ </rewrite>
25
+ </core_mysql4>
26
+ </models>
27
+ </global>
28
+ </config>');
29
+
30
+ $helperMock
31
+ ->expects($this->any())
32
+ ->method('getModules')
33
+ ->will($this->returnValue([
34
+ 'test' => $modelBaseConfig,
35
+ 'test2' => $modelDisabledBaseConfig,
36
+ ]));
37
+
38
+ $helperMock
39
+ ->expects($this->at(0))
40
+ ->method('getModuleConfigXml')
41
+ ->willReturn(false);
42
+
43
+ $helperMock
44
+ ->expects($this->at(1))
45
+ ->method('getModuleConfigXml')
46
+ ->with($this->equalTo('test'), $this->equalTo('config.xml'))
47
+ ->will($this->returnValue($modelEtcConfig));
48
+
49
+ /** @var Ecocode_Profiler_Helper_Rewrite $helperMock */
50
+ $result = $helperMock->loadRewrites();
51
+ $this->assertEquals(5, count($result, COUNT_RECURSIVE));
52
+ }
53
+
54
+ /**
55
+ * Magento doesn't have any conflicts out of the box, so we need to fake one
56
+ */
57
+ public function testExecuteConflict()
58
+ {
59
+ $rewrites = [
60
+ 'blocks' => [
61
+ 'n98/mock_conflict' => [
62
+ 'Mage_Customer_Block_Account',
63
+ 'Mage_Tag_Block_All',
64
+ ]
65
+ ],
66
+ 'helpers' => [
67
+ 'n98/mock_conflict' => [
68
+ 'Mage_Catalog_Helper_Data',
69
+ 'Mage_Sales_Helper_Data',
70
+ ]
71
+ ],
72
+ 'models' => [
73
+ 'n98/mock_conflict' => [
74
+ 'Mage_Catalog_Model_Product',
75
+ 'Mage_Sales_Model_Order',
76
+ ]
77
+ ]
78
+ ];
79
+ $helper = $this->getHelperWithMockLoadRewrites($rewrites);
80
+ $result = $helper->getRewriteConflicts();
81
+ $this->assertCount(3, $result);
82
+ }
83
+
84
+ /**
85
+ * This is made to look like a conflict (2 rewrites for the same class) but
86
+ * because Bundle extends Catalog, it's valid. Note that we're implying
87
+ * Bundle depends on Catalog by passing it as the second value in the array.
88
+ */
89
+ public function testExecuteConflictFalsePositive()
90
+ {
91
+ $rewrites = [
92
+ 'blocks' => [
93
+ 'n98/mock_conflict' => [
94
+ 'Mage_Catalog_Block_Product_Price',
95
+ 'Mage_Bundle_Block_Catalog_Product_Price',
96
+ ]
97
+ ]
98
+ ];
99
+ $helper = $this->getHelperWithMockLoadRewrites($rewrites);
100
+ $result = $helper->getRewriteConflicts();
101
+ $this->assertCount(0, $result);
102
+ }
103
+
104
+ /**
105
+ * Mock the ConflictsCommand and change the return value of loadRewrites()
106
+ * to the given argument
107
+ *
108
+ * @param array $return
109
+ * @return Ecocode_Profiler_Helper_Rewrite
110
+ */
111
+ private function getHelperWithMockLoadRewrites(array $return)
112
+ {
113
+ $helperMock = $this->getMockBuilder('Ecocode_Profiler_Helper_Rewrite')
114
+ ->setMethods(['loadRewrites'])
115
+ ->getMock();
116
+
117
+ $helperMock
118
+ ->expects($this->any())
119
+ ->method('loadRewrites')
120
+ ->will($this->returnValue($return));
121
+
122
+ return $helperMock;
123
+ }
124
+ }
app/code/community/Ecocode/Profiler/Tests/Dev/Helper/SqlTest.php ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+
4
+ class Ecocode_Profiler_Tests_Dev_Helper_SqlTest extends \PHPUnit_Framework_TestCase
5
+ {
6
+ /**
7
+ * @var Ecocode_Profiler_Helper_Sql
8
+ */
9
+ private $sql;
10
+
11
+ protected function setUp()
12
+ {
13
+ $this->sql = new Ecocode_Profiler_Helper_Sql();
14
+ }
15
+
16
+ public function testReplaceQueryParametersWithPostgresCasting()
17
+ {
18
+ $query = 'a=? OR (1)::string OR b=?';
19
+ $parameters = [1, 2];
20
+ $result = $this->sql->replaceQueryParameters($query, $parameters);
21
+ $this->assertEquals('a=1 OR (1)::string OR b=2', $result);
22
+ }
23
+
24
+ public function testReplaceQueryParametersWithStartingIndexAtOne()
25
+ {
26
+ $query = 'a=? OR b=?';
27
+ $parameters = [
28
+ 1 => 1,
29
+ 2 => 2
30
+ ];
31
+ $result = $this->sql->replaceQueryParameters($query, $parameters);
32
+ $this->assertEquals('a=1 OR b=2', $result);
33
+ }
34
+
35
+ public function testReplaceQueryParameters()
36
+ {
37
+ $query = 'a=? OR b=?';
38
+ $parameters = [
39
+ 1,
40
+ 2
41
+ ];
42
+ $result = $this->sql->replaceQueryParameters($query, $parameters);
43
+ $this->assertEquals('a=1 OR b=2', $result);
44
+ }
45
+
46
+ public function testReplaceQueryParametersWithNamedIndex()
47
+ {
48
+ $query = 'a=:a OR b=:b';
49
+ $parameters = [
50
+ 'a' => 1,
51
+ 'b' => 2
52
+ ];
53
+ $result = $this->sql->replaceQueryParameters($query, $parameters);
54
+ $this->assertEquals('a=1 OR b=2', $result);
55
+ }
56
+ }
app/code/community/Ecocode/Profiler/Tests/Dev/Helper/ValueExporterTest.php ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Ecocode_Profiler_Tests_Dev_Helper_ValueExporterTest
4
+ extends TestHelper
5
+ {
6
+ /**
7
+ * @var Ecocode_Profiler_Helper_ValueExporter
8
+ */
9
+ private $valueExporter;
10
+
11
+ protected function setUp()
12
+ {
13
+ $this->valueExporter = new Ecocode_Profiler_Helper_ValueExporter();
14
+ }
15
+
16
+ public function exportValueDataProvider()
17
+ {
18
+ $stream = fopen('php://memory', 'w');
19
+ return [
20
+ [new Varien_Object(), 'Object(Varien_Object)'],
21
+ [[new Varien_Object(), new Varien_Object()], '[0 => Object(Varien_Object), 1 => Object(Varien_Object)]'],
22
+ [[1, 2], '[0 => 1, 1 => 2]'],
23
+ [[1 => ['a', 'b'], []], "[\n 1 => [\n 0 => a, \n 1 => b\n ], \n 2 => []\n]"],
24
+ [[null, true, false], '[0 => null, 1 => true, 2 => false]'],
25
+ [$stream, sprintf('Resource(stream#%d)', $stream)],
26
+ [[str_repeat('x', 100)], "[\n 0 => " . str_repeat('x', 100) . "\n]"]
27
+ ];
28
+ }
29
+
30
+ /**
31
+ * @dataProvider exportValueDataProvider
32
+ * @param $value
33
+ * @param $expectValue
34
+ */
35
+ public function testExportValue($value, $expectValue)
36
+ {
37
+ $value = $this->valueExporter->exportValue($value);
38
+ $this->assertEquals($expectValue, $value);
39
+ }
40
+
41
+ public function testDateTime()
42
+ {
43
+ $dateTime = new \DateTime('2014-06-10 07:35:40', new \DateTimeZone('UTC'));
44
+ $this->assertSame('Object(DateTime) - 2014-06-10T07:35:40+0000', $this->valueExporter->exportValue($dateTime));
45
+ }
46
+
47
+ public function testDateTimeImmutable()
48
+ {
49
+ $dateTime = new \DateTimeImmutable('2014-06-10 07:35:40', new \DateTimeZone('UTC'));
50
+ $this->assertSame('Object(DateTimeImmutable) - 2014-06-10T07:35:40+0000', $this->valueExporter->exportValue($dateTime));
51
+ }
52
+
53
+ public function testIncompleteClass()
54
+ {
55
+ $foo = new \__PHP_Incomplete_Class();
56
+ $array = new \ArrayObject($foo);
57
+ $array['__PHP_Incomplete_Class_Name'] = 'AppBundle/Foo';
58
+ $this->assertSame('__PHP_Incomplete_Class(AppBundle/Foo)', $this->valueExporter->exportValue($foo));
59
+ }
60
+ }
app/code/community/Ecocode/Profiler/Tests/Dev/Model/Collector/CacheDataCollectorTest.php ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Ecocode_Profiler_Tests_Dev_Model_Collector_CacheDataCollectorTest
4
+ extends TestHelper
5
+ {
6
+
7
+ public function testCollect()
8
+ {
9
+ $collector = $this->getMockedCollector();
10
+
11
+ $collector->collect(
12
+ new Mage_Core_Controller_Request_Http(),
13
+ new Mage_Core_Controller_Response_Http()
14
+ );
15
+
16
+ $expectCacheList = json_decode('[{"id":"config","cache_type":"Configuration","description":"System(config.xml, local.xml) and modules configuration files(config.xml).","tags":"CONFIG","status":1},{"id":"layout","cache_type":"Layouts","description":"Layout building instructions.","tags":"LAYOUT_GENERAL_CACHE_TAG","status":1},{"id":"block_html","cache_type":"Blocks HTML output","description":"Page blocks HTML.","tags":"BLOCK_HTML","status":1},{"id":"translate","cache_type":"Translations","description":"Translation files.","tags":"TRANSLATE","status":1},{"id":"collections","cache_type":"Collections Data","description":"Collection data files.","tags":"COLLECTION_DATA","status":1},{"id":"eav","cache_type":"EAV types and attributes","description":"Entity types declaration cache.","tags":"EAV","status":1},{"id":"config_api","cache_type":"Web Services Configuration","description":"Web Services definition files (api.xml).","tags":"CONFIG_API","status":1},{"id":"config_api2","cache_type":"Web Services Configuration","description":"Web Services definition files (api2.xml).","tags":"CONFIG_API2","status":1}]', true);
17
+
18
+ $this->assertEquals('Ecocode_Profiler_Tests_Dev_Fixtures_DummyCacheBackend', $collector->getBackendName());
19
+ $this->assertEquals(['test_option' => 1], $collector->getBackendOptions());
20
+ $this->assertEquals($expectCacheList, $collector->getCacheList());
21
+ $this->assertEmpty($collector->getCacheCalls());
22
+ }
23
+
24
+ public function testLateCollect()
25
+ {
26
+ $logs = [
27
+ ['action' => 'clear', 'id' => 'unknown', 'time' => 0.001],
28
+ ['action' => 'load', 'id' => 'core_cache_options1', 'hit' => true, 'time' => 0.005],
29
+ ['action' => 'load', 'id' => 'core_cache_options2', 'hit' => true, 'time' => 0.005],
30
+ ['action' => 'load', 'id' => 'core_cache_options_miss1', 'hit' => false, 'time' => 0.005],
31
+ ['action' => 'load', 'id' => 'core_cache_options_miss2', 'hit' => false, 'time' => 0.005],
32
+ ['action' => 'save', 'id' => 'config_global_admin', 'tags' => ['CONFIG'], 'life_time' => null, 'time' => 0.005],
33
+ ];
34
+
35
+ $collector = $this->getMockedCollector([], $logs);
36
+
37
+
38
+ $collector->lateCollect();
39
+
40
+ $this->assertEquals([
41
+ 'total' => 6,
42
+ 'hit' => 2,
43
+ 'miss' => 2,
44
+ 'save' => 1,
45
+ ], $collector->getStats());
46
+
47
+ $this->assertEquals(6, $collector->getStats('total'));
48
+ $this->assertEquals(0.026, $collector->getTotalTime());
49
+ }
50
+
51
+ public function getMockedCollector($cacheTypes = [], $log = [])
52
+ {
53
+ $cacheBackend = new Ecocode_Profiler_Tests_Dev_Fixtures_DummyCacheBackend(['test_option' => 1]);
54
+
55
+ $cacheMock = $this->getMockBuilder('Ecocode_Profiler_Model_Core_Cache')
56
+ ->setMethods(['getTypes', 'getBackend', 'getLog'])
57
+ ->getMock();
58
+
59
+ $cacheTypes = $cacheTypes ? $cacheTypes : json_decode('[{"id":"config","cache_type":"Configuration","description":"System(config.xml, local.xml) and modules configuration files(config.xml).","tags":"CONFIG","status":1},{"id":"layout","cache_type":"Layouts","description":"Layout building instructions.","tags":"LAYOUT_GENERAL_CACHE_TAG","status":1},{"id":"block_html","cache_type":"Blocks HTML output","description":"Page blocks HTML.","tags":"BLOCK_HTML","status":1},{"id":"translate","cache_type":"Translations","description":"Translation files.","tags":"TRANSLATE","status":1},{"id":"collections","cache_type":"Collections Data","description":"Collection data files.","tags":"COLLECTION_DATA","status":1},{"id":"eav","cache_type":"EAV types and attributes","description":"Entity types declaration cache.","tags":"EAV","status":1},{"id":"config_api","cache_type":"Web Services Configuration","description":"Web Services definition files (api.xml).","tags":"CONFIG_API","status":1},{"id":"config_api2","cache_type":"Web Services Configuration","description":"Web Services definition files (api2.xml).","tags":"CONFIG_API2","status":1}]', true);
60
+ $collectorMock = $this->getMockBuilder('Ecocode_Profiler_Model_Collector_CacheDataCollector')
61
+ ->setMethods(['getCacheInstance', 'getCache'])
62
+ ->getMock();
63
+
64
+ $types = [];
65
+ foreach ($cacheTypes as $typeData) {
66
+ $id = $typeData['id'];
67
+ $types[$id] = new Varien_Object($typeData);
68
+ }
69
+
70
+ $cacheMock
71
+ ->method('getTypes')
72
+ ->willReturn($types);
73
+
74
+ $cacheMock
75
+ ->method('getBackend')
76
+ ->willReturn($cacheBackend);
77
+
78
+ $cacheMock
79
+ ->method('getLog')
80
+ ->willReturn($log);
81
+
82
+
83
+ $collectorMock->method('getCacheInstance')->willReturn($cacheMock);
84
+ $collectorMock->method('getCache')->willReturn($cacheMock);
85
+
86
+
87
+ return $collectorMock;
88
+ }
89
+ }
app/code/community/Ecocode/Profiler/Tests/Dev/Model/Collector/ConfigCollectorTest.php ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Ecocode_Profiler_Tests_Dev_Model_Collector_ConfigCollectorTest
4
+ extends TestHelper
5
+ {
6
+
7
+ public function testCollect()
8
+ {
9
+ $token = 'XXX';
10
+ $response = new Ecocode_Profiler_Tests_Dev_Fixtures_ResponseHttp();
11
+ $response->setHeader('X-Debug-Token', $token);
12
+ $collector = new Ecocode_Profiler_Model_Collector_ConfigDataCollector();
13
+
14
+ Mage::app()->setCurrentStore('admin');
15
+ $collector->collect(
16
+ new Mage_Core_Controller_Request_Http(),
17
+ $response
18
+ );
19
+
20
+
21
+ $this->assertEquals(0, $collector->getStoreId());
22
+ $this->assertEquals('admin', $collector->getStoreCode());
23
+ $this->assertEquals('Admin', $collector->getStoreName());
24
+
25
+ $this->assertEquals(0, $collector->getWebsiteId());
26
+ $this->assertEquals('admin', $collector->getWebsiteCode());
27
+ $this->assertEquals('Admin', $collector->getWebsiteName());
28
+
29
+ $this->assertEquals($token, $collector->getToken());
30
+
31
+ $this->assertFalse($collector->isDeveloperMode());
32
+
33
+ $this->assertGreaterThan(1, count($collector->getMagentoModules()));
34
+
35
+ $this->assertGreaterThan(1, count($collector->geModulesByState(true)));
36
+
37
+ $this->assertNotNull($collector->getMagentoVersion());
38
+ $this->assertNotNull($collector->getPhpVersion());
39
+
40
+ $this->assertNotNull($collector->hasXDebug());
41
+ $this->assertNotNull($collector->hasEAccelerator());
42
+ $this->assertNotNull($collector->hasApc());
43
+ $this->assertNotNull($collector->hasZendOpcache());
44
+ $this->assertNotNull($collector->hasXCache());
45
+ $this->assertNotNull($collector->hasWinCache());
46
+ $this->assertNotNull($collector->hasAccelerator());
47
+ $this->assertNotNull($collector->getSapiName());
48
+
49
+
50
+ }
51
+ }
app/code/community/Ecocode/Profiler/Tests/Dev/Model/Collector/ContextDataCollectorTest.php ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Ecocode_Profiler_Tests_Dev_Model_Collector_ContextDataCollectorTest
4
+ extends TestHelper
5
+ {
6
+
7
+ public function testCollect()
8
+ {
9
+ $collector = new Ecocode_Profiler_Model_Collector_ContextDataCollector();
10
+
11
+ $collector->collect(
12
+ new Mage_Core_Controller_Request_Http(),
13
+ new Mage_Core_Controller_Response_Http()
14
+ );
15
+
16
+
17
+ $this->assertCount(0, $collector->getList());
18
+ }
19
+
20
+ public function testLateCollect()
21
+ {
22
+ $collector = $this->getMockedCollector();
23
+
24
+ $this->assertNull($collector->getById('xx'));
25
+
26
+ $context = new Ecocode_Profiler_Model_Context('block:test');
27
+ $collector->getContextHelper()->open($context);
28
+
29
+
30
+ $collector->lateCollect();
31
+
32
+ $this->assertCount(2, $collector->getList());
33
+
34
+ $this->assertEquals($context, $collector->getById($context->getId()));
35
+ }
36
+
37
+ /**
38
+ * @return Ecocode_Profiler_Model_Collector_ContextDataCollector
39
+ */
40
+ public function getMockedCollector()
41
+ {
42
+ $collectorMock = $this->getMockBuilder('Ecocode_Profiler_Model_Collector_ContextDataCollector')
43
+ ->setMethods(['getContextHelper'])
44
+ ->getMock();
45
+
46
+ $contextHelper = new Ecocode_Profiler_Helper_Context();
47
+ $collectorMock->method('getContextHelper')
48
+ ->willReturn($contextHelper);
49
+
50
+
51
+ return $collectorMock;
52
+ }
53
+
54
+ }
app/code/community/Ecocode/Profiler/Tests/Dev/Model/Collector/CustomerDataCollectorTest.php ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Ecocode_Profiler_Tests_Dev_Model_Collector_CustomerDataCollectorTest
4
+ extends TestHelper
5
+ {
6
+
7
+ public function testCollect()
8
+ {
9
+ $customer = new Mage_Customer_Model_Customer();
10
+ $customer->setData([
11
+ 'email' => 'test@test.com',
12
+ 'firstname' => 'first',
13
+ 'lastname' => 'last'
14
+ ]);
15
+
16
+ $customerHelper = $this->getMockBuilder('Mage_Customer_Helper_Data')
17
+ ->setMethods(['getCustomer', 'isLoggedIn'])
18
+ ->getMock();
19
+
20
+ $customerHelper->method('getCustomer')
21
+ ->willReturn($customer);
22
+
23
+ $customerHelper->method('isLoggedIn')
24
+ ->willReturn(false);
25
+
26
+ /** @var Ecocode_Profiler_Model_Collector_CustomerDataCollector $collector */
27
+ $collector = $this->getMockBuilder('Ecocode_Profiler_Model_Collector_CustomerDataCollector')
28
+ ->setMethods(['getCustomerHelper'])
29
+ ->getMock();
30
+
31
+ $collector->method('getCustomerHelper')
32
+ ->willReturn($customerHelper);
33
+
34
+ $collector->collect(
35
+ new Mage_Core_Controller_Request_Http(),
36
+ new Mage_Core_Controller_Response_Http()
37
+ );
38
+
39
+ $this->assertFalse($collector->isLoggedIn());
40
+
41
+ $this->assertEquals('test@test.com', $collector->getCustomerEmail());
42
+ $this->assertEquals('first last', $collector->getCustomerName());
43
+
44
+ $this->assertEquals(1, $collector->getGroupId());
45
+ $this->assertEquals('General', $collector->getGroupCode());
46
+
47
+
48
+ $this->assertEquals('3', $collector->getTaxClassId());
49
+ $this->assertEquals('Retail Customer', $collector->getTaxClassName());
50
+ $this->assertEquals('CUSTOMER', $collector->getTaxClassType());
51
+
52
+
53
+ }
54
+ }
app/code/community/Ecocode/Profiler/Tests/Dev/Model/Collector/EventDataCollectorTest.php ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Ecocode_Profiler_Tests_Dev_Model_Collector_EventDataCollectorTest
4
+ extends TestHelper
5
+ {
6
+
7
+ public function testCollect()
8
+ {
9
+ $collector = new Ecocode_Profiler_Model_Collector_EventDataCollector();
10
+
11
+ $collector->collect(
12
+ new Mage_Core_Controller_Request_Http(),
13
+ new Mage_Core_Controller_Response_Http()
14
+ );
15
+
16
+
17
+ $this->assertCount(0, $collector->getCalledListeners());
18
+ $this->assertCount(0, $collector->getFiredEvents());
19
+ }
20
+
21
+ public function testLateCollect()
22
+ {
23
+ $collector = $this->getMockedCollector();
24
+
25
+ $app = new Ecocode_Profiler_Model_AppDev();
26
+ $app->init('admin', 'store');
27
+ $collector->method('getApp')
28
+ ->willReturn($app);
29
+
30
+ $preDispatchData = json_decode('{"observers":{"log":{"type":"","model":"log\/visitor","method":"initByRequest","args":[]},"pagecache":{"type":"","model":"pagecache\/observer","method":"processPreDispatch","args":[]}}}', true);
31
+ $events = ['global' => ['controller_action_predispatch' => $preDispatchData]];
32
+
33
+ $app->dispatchEvent('resource_get_tablename', []);
34
+ $app->dispatchEvent('controller_action_predispatch', []);
35
+ $app->dispatchEvent('controller_action_predispatch', []);
36
+
37
+ $appEvents = new ReflectionProperty('Ecocode_Profiler_Model_AppDev', '_events');
38
+ $appEvents->setAccessible(true);
39
+ $appEvents->setValue($app, $events);
40
+
41
+
42
+ $collector->lateCollect();
43
+
44
+ $firedEvents = $collector->getFiredEvents();
45
+ $this->assertCount(0, $collector->getCalledListeners());
46
+ $this->assertCount(2, $collector->getFiredEvents());
47
+
48
+ $data = $firedEvents['controller_action_predispatch'];
49
+ $this->assertEquals(2, $data['count']);
50
+ $this->assertEquals(2, $data['observer_count']);
51
+ $this->assertCount(1, $data['observer']);
52
+ $this->assertCount(2, $data['observer']['global']);
53
+
54
+ }
55
+
56
+ /**
57
+ * @return Ecocode_Profiler_Model_Collector_EventDataCollector
58
+ */
59
+ public function getMockedCollector()
60
+ {
61
+ $collectorMock = $this->getMockBuilder('Ecocode_Profiler_Model_Collector_EventDataCollector')
62
+ ->setMethods(['getApp'])
63
+ ->getMock();
64
+
65
+
66
+ return $collectorMock;
67
+ }
68
+ }
app/code/community/Ecocode/Profiler/Tests/Dev/Model/Collector/LayoutDataCollectorTest.php ADDED
@@ -0,0 +1,221 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Ecocode_Profiler_Tests_Dev_Model_Collector_LayoutDataCollectorTest
4
+ extends TestHelper
5
+ {
6
+ public function testBeforeToHtmlNoParent()
7
+ {
8
+ $start = microtime(true);
9
+ $observer = new Varien_Event_Observer();
10
+ $event = new Varien_Event();
11
+ $testBlock = new Mage_Core_Block_Template();
12
+
13
+ $observer->setData('event', $event);
14
+ $event->setData('block', $testBlock);
15
+
16
+ $collector = new Ecocode_Profiler_Model_Collector_LayoutDataCollector();
17
+
18
+ $collector->beforeToHtml($observer);
19
+
20
+ $id = $testBlock->getData('profiler_id');
21
+ $this->assertNotNull($id);
22
+
23
+ $renderLogProperty = new ReflectionProperty('Ecocode_Profiler_Model_Collector_LayoutDataCollector', 'renderLog');
24
+ $renderLogProperty->setAccessible(true);
25
+ $log = $renderLogProperty->getValue($collector);
26
+
27
+ $this->assertTrue(isset($log[$id]));
28
+
29
+ $logEntry = $log[$id];
30
+ $this->assertFalse($logEntry['parent_id']);
31
+ $this->assertGreaterThan($start, $logEntry['start_render']);
32
+ $this->assertEquals(spl_object_hash($testBlock), $logEntry['hash']);
33
+ $this->assertCount(0, $logEntry['children']);
34
+ $this->assertFalse($logEntry['parent_id']);
35
+ }
36
+
37
+ public function testBeforeToHtmlWithParent()
38
+ {
39
+ $observer = new Varien_Event_Observer();
40
+ $event = new Varien_Event();
41
+ $childBlock = new Mage_Core_Block_Template();
42
+ $parentBlock = new Mage_Core_Block_Template();
43
+
44
+ $parentBlock->setChild('test-child', $childBlock);
45
+
46
+ $observer->setData('event', $event);
47
+ $event->setData('block', $parentBlock);
48
+
49
+ $collector = new Ecocode_Profiler_Model_Collector_LayoutDataCollector();
50
+
51
+ $collector->beforeToHtml($observer);
52
+
53
+ $event->setData('block', $childBlock);
54
+ $collector->beforeToHtml($observer);
55
+
56
+ $parentId = $parentBlock->getData('profiler_id');
57
+ $childId = $childBlock->getData('profiler_id');
58
+
59
+ $this->assertNotNull($parentId);
60
+ $this->assertNotNull($childId);
61
+
62
+ $renderLogProperty = new ReflectionProperty('Ecocode_Profiler_Model_Collector_LayoutDataCollector', 'renderLog');
63
+ $renderLogProperty->setAccessible(true);
64
+ $log = $renderLogProperty->getValue($collector);
65
+
66
+
67
+ $this->assertCount(2, $log);
68
+ $this->assertTrue(isset($log[$parentId]));
69
+ $this->assertTrue(isset($log[$childId]));
70
+
71
+ $parentLogEntry = $log[$parentId];
72
+ $childLogEntry = $log[$childId];
73
+
74
+ $this->assertFalse($parentLogEntry['parent_id']);
75
+ $this->assertEquals($parentId, $childLogEntry['parent_id']);
76
+
77
+ $this->assertCount(1, $parentLogEntry['children']);
78
+ }
79
+
80
+ public function testBeforeToHtmlWidget()
81
+ {
82
+ $observer = new Varien_Event_Observer();
83
+ $event = new Varien_Event();
84
+
85
+ $parentBlock = new Mage_Core_Block_Template();
86
+ $widgetBlock = new Mage_Catalog_Block_Product_Widget_New();
87
+ $widgetChildBlock = new Mage_Core_Block_Template();
88
+
89
+ $widgetBlock->setChild('widget-child', $widgetChildBlock);
90
+
91
+ $observer->setData('event', $event);
92
+
93
+
94
+ $collector = new Ecocode_Profiler_Model_Collector_LayoutDataCollector();
95
+
96
+ $blocks = [$parentBlock, $widgetBlock, $widgetChildBlock];
97
+
98
+ foreach ($blocks as $block) {
99
+ $event->setData('block', $block);
100
+ $collector->beforeToHtml($observer);
101
+ }
102
+
103
+ $renderLogProperty = new ReflectionProperty('Ecocode_Profiler_Model_Collector_LayoutDataCollector', 'renderLog');
104
+ $renderLogProperty->setAccessible(true);
105
+ $log = $renderLogProperty->getValue($collector);
106
+
107
+
108
+ $this->assertCount(3, $log);
109
+
110
+ $this->assertEquals(
111
+ $parentBlock->getData('profiler_id'),
112
+ $log[$widgetBlock->getData('profiler_id')]['parent_id']
113
+ );
114
+ }
115
+
116
+
117
+ public function testAfterToHtml()
118
+ {
119
+ $collector = new Ecocode_Profiler_Model_Collector_LayoutDataCollector();
120
+
121
+ $observer = new Varien_Event_Observer();
122
+ $event = new Varien_Event();
123
+ $testBlock = new Mage_Core_Block_Template();
124
+
125
+ $testBlock->setTemplate('test.html.php');
126
+
127
+ $observer->setData('event', $event);
128
+ $event->setData('block', $testBlock);
129
+
130
+
131
+ $collector->beforeToHtml($observer);
132
+ $collector->afterToHtml($observer);
133
+
134
+ $id = $testBlock->getData('profiler_id');
135
+ $this->assertNotNull($id);
136
+
137
+ $renderLogProperty = new ReflectionProperty('Ecocode_Profiler_Model_Collector_LayoutDataCollector', 'renderLog');
138
+ $renderLogProperty->setAccessible(true);
139
+ $log = $renderLogProperty->getValue($collector);
140
+
141
+ $blockData = $log[$id];
142
+
143
+
144
+ $this->assertNotNull($blockData['stop_render']);
145
+ $this->assertEquals($blockData['stop_render'] - $blockData['start_render'], $blockData['render_time_incl']);
146
+ $this->assertEquals('test.html.php', $blockData['template']);
147
+
148
+ }
149
+
150
+
151
+ public function testCollect()
152
+ {
153
+ /** @var Ecocode_Profiler_Model_Collector_LayoutDataCollector $collector */
154
+ $collector = $this->getMockBuilder('Ecocode_Profiler_Model_Collector_LayoutDataCollector')
155
+ ->setMethods(['getLayout'])
156
+ ->getMock();
157
+
158
+ /** @var Mage_Core_Model_Layout $layout */
159
+ $layout = new Mage_Core_Model_Layout();
160
+
161
+ $collector->method('getLayout')
162
+ ->willReturn($layout);
163
+
164
+ $observer = new Varien_Event_Observer();
165
+ $event = new Varien_Event();
166
+
167
+ $childBlock = new Mage_Core_Block_Template();
168
+ $parentBlock = new Mage_Core_Block_Template();
169
+ $notRenderedBlock = new Mage_Core_Block_Template();
170
+
171
+ $layout->getUpdate()->addHandle('default');
172
+ $layout->getUpdate()->addHandle('test');
173
+ $layout->addBlock($childBlock, 'root');
174
+ $layout->addBlock($parentBlock, 'block-2');
175
+ $layout->addBlock($notRenderedBlock, 'block-3');
176
+
177
+ $layout->addOutputBlock('root');
178
+ $blocks = [$parentBlock, $childBlock];
179
+
180
+ $observer->setData('event', $event);
181
+
182
+ $parentBlock->setChild('test-child', $childBlock);
183
+
184
+ foreach ($blocks as $block) {
185
+ $event->setData('block', $block);
186
+ $collector->beforeToHtml($observer);
187
+ }
188
+
189
+ foreach (array_reverse($blocks) as $block) {
190
+ $event->setData('block', $block);
191
+ $collector->afterToHtml($observer);
192
+ }
193
+
194
+ $collector->collect(
195
+ new Mage_Core_Controller_Request_Http(),
196
+ new Mage_Core_Controller_Response_Http()
197
+ );
198
+
199
+ $this->assertCount(2, $collector->getLayoutHandles());
200
+ $this->assertEquals(3, $collector->getBlocksCreatedCount());
201
+ $this->assertEquals(2, $collector->getBlocksRenderedCount());
202
+
203
+ $blocksNotRendered = $collector->getBlocksNotRendered();
204
+ $this->assertCount(1, $blocksNotRendered);
205
+ $this->assertEquals('block-3', $blocksNotRendered[0]['name']);
206
+ $this->assertGreaterThan(0, $collector->getTotalRenderTime());
207
+ }
208
+
209
+ /**
210
+ * @return Ecocode_Profiler_Model_Collector_LayoutDataCollector
211
+ */
212
+ public function getMockedCollector()
213
+ {
214
+ $collectorMock = $this->getMockBuilder('Ecocode_Profiler_Model_Collector_LayoutDataCollector')
215
+ ->setMethods(['getLayout'])
216
+ ->getMock();
217
+
218
+
219
+ return $collectorMock;
220
+ }
221
+ }
app/code/community/Ecocode/Profiler/Tests/Dev/Model/Collector/LogDataCollectorTest.php ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Ecocode_Profiler_Tests_Dev_Model_Collector_LogDataCollectorTest
5
+ *
6
+ *
7
+ * @requires
8
+ */
9
+ class Ecocode_Profiler_Tests_Dev_Model_Collector_LogDataCollectorTest
10
+ extends TestHelper
11
+ {
12
+ protected function setUp()
13
+ {
14
+
15
+ }
16
+
17
+
18
+ public function testCollect()
19
+ {
20
+ /** @var Ecocode_Profiler_Model_Collector_LogDataCollector $collector */
21
+ $collector = new Ecocode_Profiler_Model_Collector_LogDataCollector();
22
+
23
+
24
+ $collector->collect(
25
+ new Mage_Core_Controller_Request_Http(),
26
+ new Mage_Core_Controller_Response_Http()
27
+ );
28
+
29
+ $this->assertEmpty(0, $collector->getLogs());
30
+ $this->assertEquals(0, $collector->getLogCount());
31
+ }
32
+
33
+ public function testLateCollect()
34
+ {
35
+ if (!class_exists('Monolog\Handler\TestHandler')) {
36
+ $this->markTestSkipped(
37
+ 'Monolog not installed skipping.'
38
+ );
39
+ }
40
+ $logHandler = new Ecocode_Profiler_Model_Logger_DebugHandler();
41
+ $logger = new Ecocode_Profiler_Model_Logger('test', [$logHandler]);
42
+
43
+ $collector = $this->getMockBuilder('Ecocode_Profiler_Model_Collector_LogDataCollector')
44
+ ->setMethods(['getLogger'])
45
+ ->getMock();
46
+
47
+ $collector->method('getLogger')
48
+ ->willReturn($logger);
49
+
50
+
51
+ $logger->debug('test');
52
+ $logger->debug('test');
53
+
54
+ $context = [
55
+ "type" => 8192, "file" => "path/xxxxCategoryController.php", "line" => 43, "level" => 32767
56
+ ];
57
+ //simulate 3 times same error like in a loop
58
+ $logger->info('iconv_set_encoding(): Use of iconv.internal_encoding is deprecated', $context);
59
+ $logger->info('iconv_set_encoding(): Use of iconv.internal_encoding is deprecated', $context);
60
+ $logger->info('iconv_set_encoding(): Use of iconv.internal_encoding is deprecated', $context);
61
+
62
+ $logger->info('another deprecation', ['level' => E_USER_ERROR, 'type' => E_USER_DEPRECATED]);
63
+
64
+
65
+ $logger->critical('Fatal Parse Error:', ['level' => E_ALL, 'type' => E_PARSE]);
66
+
67
+ /** @var Ecocode_Profiler_Model_Collector_LogDataCollector $collector */
68
+ $collector->lateCollect();
69
+
70
+
71
+
72
+ $logsByPriorities = $collector->getPriorities();
73
+
74
+ $this->assertEquals(2, $logsByPriorities[Ecocode_Profiler_Model_Logger::DEBUG]['count']);
75
+ $this->assertEquals(4, $logsByPriorities[Ecocode_Profiler_Model_Logger::INFO]['count']);
76
+ $this->assertEquals(1, $logsByPriorities[Ecocode_Profiler_Model_Logger::CRITICAL]['count']);
77
+
78
+
79
+ $this->assertEquals(0, $collector->countScreams());
80
+ $this->assertEquals(1, $collector->countErrors());
81
+ $this->assertEquals(4, $collector->countDeprecations());
82
+
83
+ }
84
+ }
app/code/community/Ecocode/Profiler/Tests/Dev/Model/Collector/MemoryDataCollectorTest.php ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Ecocode_Profiler_Tests_Dev_Model_Collector_MemoryDataCollectorTest
4
+ extends TestHelper
5
+ {
6
+
7
+ public function collectDataProvider()
8
+ {
9
+ return [
10
+ ['0x1DD5650000', '128134217728'], //hexa //128MB
11
+ ['01672531200000', '128134217728'], //octal //128MB
12
+ ['-1', -1],
13
+ ['1048576K', 1073741824],
14
+ ['2048M', 2147483648],
15
+ ['2G', 2147483648],
16
+ ['1T', 1099511627776]
17
+ ];
18
+ }
19
+
20
+ /**
21
+ * @dataProvider collectDataProvider
22
+ * @param $limit
23
+ * @param $expectedBytes
24
+ */
25
+ public function testConvertToBytes($limit, $expectedBytes)
26
+ {
27
+ /** @var Ecocode_Profiler_Model_Collector_MemoryDataCollector $collector */
28
+ $collector = $this->getMockBuilder('Ecocode_Profiler_Model_Collector_MemoryDataCollector')
29
+ ->setMethods(['getCurrentMemoryLimit'])
30
+ ->getMock();
31
+
32
+
33
+ $collector->method('getCurrentMemoryLimit')
34
+ ->willReturn($limit);
35
+
36
+ $collector->collect(
37
+ new Mage_Core_Controller_Request_Http(),
38
+ new Mage_Core_Controller_Response_Http()
39
+ );
40
+
41
+ $this->assertEquals($expectedBytes, $collector->getMemoryLimit());
42
+ }
43
+
44
+ public function testCollect()
45
+ {
46
+ /** @var Ecocode_Profiler_Model_Collector_MemoryDataCollector $collector */
47
+ $collector = $this->getMockBuilder('Ecocode_Profiler_Model_Collector_MemoryDataCollector')
48
+ ->setMethods(['getCurrentMemoryUsage'])
49
+ ->getMock();
50
+
51
+
52
+ $collector->method('getCurrentMemoryUsage')
53
+ ->willReturn(100000);
54
+
55
+
56
+ $collector->collect(
57
+ new Mage_Core_Controller_Request_Http(),
58
+ new Mage_Core_Controller_Response_Http()
59
+ );
60
+
61
+ $this->assertGreaterThan(100000, $collector->getMemory());
62
+ }
63
+
64
+ public function testLateCollect()
65
+ {
66
+ $collector = new Ecocode_Profiler_Model_Collector_MemoryDataCollector();
67
+
68
+ $collector->lateCollect();
69
+ $this->assertGreaterThan(0, $collector->getMemory());
70
+ }
71
+ }
app/code/community/Ecocode/Profiler/Tests/Dev/Model/Collector/ModelDataCollectorTest.php ADDED
@@ -0,0 +1,177 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Ecocode_Profiler_Tests_Dev_Model_Collector_ModelDataCollectorTest
4
+ extends TestHelper
5
+ {
6
+ public function testCollect()
7
+ {
8
+ /** @var Ecocode_Profiler_Model_Collector_ModelDataCollector $collector */
9
+ $collector = new Ecocode_Profiler_Model_Collector_ModelDataCollector();
10
+
11
+ $callLog = [
12
+ ['action' => 'load', 'trace_hash' => 'hash-1', 'time' => 10],
13
+ ['action' => 'load', 'trace_hash' => 'hash-2', 'time' => 10],
14
+ ['action' => 'load', 'trace_hash' => 'hash-3', 'time' => 10],
15
+ ['action' => 'load', 'trace_hash' => 'hash-4'],
16
+ ['action' => 'load', 'trace_hash' => 'hash-1', 'time' => 10],
17
+ ['action' => 'load', 'trace_hash' => 'hash-1', 'time' => 10],
18
+ ['action' => 'load', 'trace_hash' => 'hash-2', 'time' => 11],
19
+ ['action' => 'save', 'time' => 10],
20
+ ['action' => 'delete', 'time' => 10],
21
+ ];
22
+
23
+ $callLogProperty = new ReflectionProperty('Ecocode_Profiler_Model_Collector_ModelDataCollector', 'callLog');
24
+ $callLogProperty->setAccessible(true);
25
+ $callLogProperty->setValue($collector, $callLog);
26
+
27
+ $collector->collect(
28
+ new Mage_Core_Controller_Request_Http(),
29
+ new Mage_Core_Controller_Response_Http()
30
+ );
31
+
32
+ $this->assertEquals(81, $collector->getTotalTime());
33
+ $stats = $collector->getMetric();
34
+ $this->assertEquals(5, $collector->getMetric('loop_load'));
35
+ $this->assertEquals(7, $stats['load']);
36
+ $this->assertEquals(1, $stats['save']);
37
+ $this->assertEquals(1, $stats['delete']);
38
+
39
+ return $collector;
40
+ }
41
+
42
+ /**
43
+ * @param Ecocode_Profiler_Model_Collector_ModelDataCollector $collector
44
+ *
45
+ * @depends testCollect
46
+ */
47
+ public function testGetLoopCalls(Ecocode_Profiler_Model_Collector_ModelDataCollector $collector)
48
+ {
49
+ $loopCalls = $collector->getLoadLoopCalls();
50
+
51
+ $this->assertCount(2, $loopCalls);
52
+ $loopCall = reset($loopCalls);
53
+
54
+ $this->assertEquals(3, $loopCall['count']);
55
+ $this->assertEquals(30, $loopCall['total_time']);
56
+ }
57
+
58
+ public function testTrackModelLoad()
59
+ {
60
+ $model = Mage::getModel('catalog/product');
61
+ /** @var Ecocode_Profiler_Model_Collector_ModelDataCollector $collector */
62
+ $collector = new Ecocode_Profiler_Model_Collector_ModelDataCollector();
63
+
64
+
65
+ $collector->trackModelLoad($this->getObserver(['object' => $model, 'time' => 100]));
66
+
67
+ $callLogProperty = new ReflectionProperty('Ecocode_Profiler_Model_Collector_ModelDataCollector', 'callLog');
68
+ $callLogProperty->setAccessible(true);
69
+
70
+ $callLog = $callLogProperty->getValue($collector);
71
+
72
+ $this->assertCount(1, $callLog);
73
+
74
+ $callLogItem = reset($callLog);
75
+
76
+ $this->assertEquals('load', $callLogItem['action']);
77
+ $this->assertEquals('Mage_Catalog_Model_Product', $callLogItem['class']);
78
+ $this->assertEquals('catalog/product', $callLogItem['class_group']);
79
+ $this->assertEquals('load', $callLogItem['action']);
80
+ $this->assertEquals(100, $callLogItem['time']);
81
+ $this->assertCount(0, $callLogItem['trace']);
82
+
83
+
84
+ }
85
+
86
+ public function testTrackModelDelete()
87
+ {
88
+ $model = Mage::getModel('catalog/product');
89
+ $collector = new Ecocode_Profiler_Model_Collector_ModelDataCollector();
90
+
91
+ $collector->trackModelDelete($this->getObserver(['object' => $model]));
92
+
93
+ $callLogProperty = new ReflectionProperty('Ecocode_Profiler_Model_Collector_ModelDataCollector', 'callLog');
94
+ $callLogProperty->setAccessible(true);
95
+
96
+ $callLog = $callLogProperty->getValue($collector);
97
+
98
+ $this->assertCount(1, $callLog);
99
+
100
+ $callLogItem = reset($callLog);
101
+
102
+ $this->assertEquals('delete', $callLogItem['action']);
103
+ $this->assertCount(0, $callLogItem['trace']);
104
+ }
105
+
106
+ public function testTrackModelSave()
107
+ {
108
+ $model = Mage::getModel('catalog/product');
109
+ $collector = new Ecocode_Profiler_Model_Collector_ModelDataCollector();
110
+
111
+ $collector->trackModelSave($this->getObserver(['object' => $model]));
112
+
113
+ $callLogProperty = new ReflectionProperty('Ecocode_Profiler_Model_Collector_ModelDataCollector', 'callLog');
114
+ $callLogProperty->setAccessible(true);
115
+
116
+ $callLog = $callLogProperty->getValue($collector);
117
+
118
+ $this->assertCount(1, $callLog);
119
+
120
+ $callLogItem = reset($callLog);
121
+
122
+ $this->assertEquals('save', $callLogItem['action']);
123
+ $this->assertCount(0, $callLogItem['trace']);
124
+ }
125
+
126
+
127
+ public function testCleanBacktrace()
128
+ {
129
+ $collector = new Ecocode_Profiler_Model_Collector_ModelDataCollector();
130
+
131
+ $cleanBacktraceMethod = new ReflectionMethod('Ecocode_Profiler_Model_Collector_ModelDataCollector', 'cleanBacktrace');
132
+ $cleanBacktraceMethod->setAccessible(true);
133
+
134
+ $trace = json_decode('[{"file":"xdebug:\/\/debug-eval(1) : eval()\'d code","line":1,"function":"getBacktrace","class":"Ecocode_Profiler_Model_Collector_AbstractDataCollector","type":"->"},{"file":"xdebug:\/\/debug-eval","line":1,"function":"eval"},{"file":"\/projects\/ecocode\/ecocode_profiler_test\/magento-1.8.1.0\/vendor\/ecocode\/magento_profiler\/app\/code\/community\/Ecocode\/Profiler\/Model\/Collector\/ModelDataCollector.php","line":157,"function":"track","class":"Ecocode_Profiler_Model_Collector_ModelDataCollector","type":"::"},{"file":"\/projects\/ecocode\/ecocode_profiler_test\/magento-1.8.1.0\/vendor\/ecocode\/magento_profiler\/app\/code\/community\/Ecocode\/Profiler\/Model\/Collector\/ModelDataCollector.php","line":140,"function":"track","class":"Ecocode_Profiler_Model_Collector_ModelDataCollector","type":"->"},{"file":"\/projects\/ecocode\/ecocode_profiler_test\/magento-1.8.1.0\/vendor\/ecocode\/magento_profiler\/app\/code\/community\/Ecocode\/Profiler\/Model\/Collector\/ModelDataCollector.php","line":123,"function":"trackEvent","class":"Ecocode_Profiler_Model_Collector_ModelDataCollector","type":"->"},{"file":"\/projects\/ecocode\/ecocode_profiler_test\/magento-1.8.1.0\/httpdocs\/app\/code\/core\/Mage\/Core\/Model\/App.php","line":1338,"function":"trackModelLoad","class":"Ecocode_Profiler_Model_Collector_ModelDataCollector","type":"->"},{"file":"\/projects\/ecocode\/ecocode_profiler_test\/magento-1.8.1.0\/vendor\/ecocode\/magento_profiler\/app\/code\/community\/Ecocode\/Profiler\/Model\/AppDev.php","line":124,"function":"_callObserverMethod","class":"Mage_Core_Model_App","type":"->"},{"file":"\/projects\/ecocode\/ecocode_profiler_test\/magento-1.8.1.0\/httpdocs\/app\/code\/core\/Mage\/Core\/Model\/App.php","line":1317,"function":"_callObserverMethod","class":"Ecocode_Profiler_Model_AppDev","type":"->"},{"file":"\/projects\/ecocode\/ecocode_profiler_test\/magento-1.8.1.0\/vendor\/ecocode\/magento_profiler\/app\/code\/community\/Ecocode\/Profiler\/Model\/AppDev.php","line":91,"function":"dispatchEvent","class":"Mage_Core_Model_App","type":"->"},{"file":"\/projects\/ecocode\/ecocode_profiler_test\/magento-1.8.1.0\/httpdocs\/var\/cache\/Original_Mage_1.0.11-a6f179080788cdb98ede80fce0a470e1.php","line":456,"function":"dispatchEvent","class":"Ecocode_Profiler_Model_AppDev","type":"->"},{"file":"\/projects\/ecocode\/ecocode_profiler_test\/magento-1.8.1.0\/vendor\/ecocode\/magento_profiler\/app\/code\/community\/Ecocode\/Profiler\/overwrite\/Mage.php","line":102,"function":"dispatchEvent","class":"MageOriginal","type":"::"},{"file":"\/projects\/ecocode\/ecocode_profiler_test\/magento-1.8.1.0\/vendor\/ecocode\/magento_profiler\/app\/code\/community\/Ecocode\/Profiler\/overwrite\/MageCoreModelResourceDbAbstract.php","line":24,"function":"dispatchDebugEvent","class":"Mage","type":"::"},{"file":"\/projects\/ecocode\/ecocode_profiler_test\/magento-1.8.1.0\/httpdocs\/app\/code\/core\/Mage\/Cms\/Model\/Resource\/Page.php","line":170,"function":"load","class":"Mage_Core_Model_Resource_Db_Abstract","type":"->"},{"file":"\/projects\/ecocode\/ecocode_profiler_test\/magento-1.8.1.0\/httpdocs\/app\/code\/core\/Mage\/Core\/Model\/Abstract.php","line":225,"function":"load","class":"Mage_Cms_Model_Resource_Page","type":"->"},{"file":"\/projects\/ecocode\/ecocode_profiler_test\/magento-1.8.1.0\/httpdocs\/app\/code\/core\/Mage\/Cms\/Model\/Page.php","line":113,"function":"load","class":"Mage_Core_Model_Abstract","type":"->"},{"file":"\/projects\/ecocode\/ecocode_profiler_test\/magento-1.8.1.0\/httpdocs\/app\/code\/core\/Mage\/Cms\/Helper\/Page.php","line":74,"function":"load","class":"Mage_Cms_Model_Page","type":"->"},{"file":"\/projects\/ecocode\/ecocode_profiler_test\/magento-1.8.1.0\/httpdocs\/app\/code\/core\/Mage\/Cms\/Helper\/Page.php","line":52,"function":"_renderPage","class":"Mage_Cms_Helper_Page","type":"->"},{"file":"\/projects\/ecocode\/ecocode_profiler_test\/magento-1.8.1.0\/httpdocs\/app\/code\/core\/Mage\/Cms\/controllers\/IndexController.php","line":45,"function":"renderPage","class":"Mage_Cms_Helper_Page","type":"->"},{"file":"\/projects\/ecocode\/ecocode_profiler_test\/magento-1.8.1.0\/httpdocs\/app\/code\/core\/Mage\/Core\/Controller\/Varien\/Action.php","line":418,"function":"indexAction","class":"Mage_Cms_IndexController","type":"->"},{"file":"\/projects\/ecocode\/ecocode_profiler_test\/magento-1.8.1.0\/httpdocs\/app\/code\/core\/Mage\/Core\/Controller\/Varien\/Router\/Standard.php","line":250,"function":"dispatch","class":"Mage_Core_Controller_Varien_Action","type":"->"},{"file":"\/projects\/ecocode\/ecocode_profiler_test\/magento-1.8.1.0\/httpdocs\/app\/code\/core\/Mage\/Core\/Controller\/Varien\/Front.php","line":172,"function":"match","class":"Mage_Core_Controller_Varien_Router_Standard","type":"->"},{"file":"\/projects\/ecocode\/ecocode_profiler_test\/magento-1.8.1.0\/httpdocs\/app\/code\/core\/Mage\/Core\/Model\/App.php","line":354,"function":"dispatch","class":"Mage_Core_Controller_Varien_Front","type":"->"},{"file":"\/projects\/ecocode\/ecocode_profiler_test\/magento-1.8.1.0\/httpdocs\/var\/cache\/Original_Mage_1.0.11-a6f179080788cdb98ede80fce0a470e1.php","line":692,"function":"run","class":"Mage_Core_Model_App","type":"->"},{"file":"\/projects\/ecocode\/ecocode_profiler_test\/magento-1.8.1.0\/vendor\/ecocode\/magento_profiler\/dev.php","line":68,"function":"run","class":"MageOriginal","type":"::"}]', true);
135
+ $cleanedTrace = $cleanBacktraceMethod->invoke($collector, $trace);
136
+
137
+
138
+ $firstTraceItem = reset($cleanedTrace);
139
+ $this->assertCount(12, $cleanedTrace);
140
+ $this->assertEquals('load', $firstTraceItem['function']);
141
+ $this->assertFalse(isset($firstTraceItem['object']));
142
+ $this->assertFalse(isset($firstTraceItem['args']));
143
+ $this->assertFalse(isset($firstTraceItem['type']));
144
+ }
145
+
146
+ public function shouldRemoveBacktraceProvider()
147
+ {
148
+ return [
149
+ [[], true],
150
+ [['class' => 'test'], true],
151
+ [['class' => 'Mage_Cms_Model_Resource_Page', 'function' => 'load'], true],
152
+ [['class' => 'Mage_Cms_Model_Resource_Page', 'function' => '_load'], true],
153
+ [false, false],
154
+ [['class' => 'Mage_Core_Model_Resource_Db_Abstract', 'function' => '_load'], true],
155
+ [['class' => 'Mage_Core_Model_Resource_Db_Abstract', 'function' => 'load'], false],
156
+ [['class' => 'Mage_Eav_Model_Entity_Abstract', 'function' => 'load'], false],
157
+ ];
158
+ }
159
+
160
+ /**
161
+ * @dataProvider shouldRemoveBacktraceProvider
162
+ *
163
+ * @param $data
164
+ * @param $expect
165
+ */
166
+ public function testShouldRemoveBacktrace($data, $expect)
167
+ {
168
+ $collector = new Ecocode_Profiler_Model_Collector_ModelDataCollector();
169
+
170
+ $shouldRemoveBacktraceMethod = new ReflectionMethod('Ecocode_Profiler_Model_Collector_ModelDataCollector', 'shouldRemoveBacktrace');
171
+ $shouldRemoveBacktraceMethod->setAccessible(true);
172
+
173
+ $shouldRemove = $shouldRemoveBacktraceMethod->invoke($collector, $data);
174
+
175
+ $this->assertEquals($expect, $shouldRemove);
176
+ }
177
+ }
app/code/community/Ecocode/Profiler/Tests/Dev/Model/Collector/MysqlDataCollectorTest.php ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Ecocode_Profiler_Tests_Dev_Model_Collector_MysqlDataCollectorTest
4
+ extends TestHelper
5
+ {
6
+
7
+ public function testBackTrace()
8
+ {
9
+ $originalTrace = json_decode('[{"file":"\/projects\/ecocode\/ecocode_profiler_test\/magento-1.8.1.0\/vendor\/ecocode\/magento_profiler\/app\/code\/community\/Ecocode\/Profiler\/Model\/Collector\/MysqlDataCollector.php","line":95,"function":"getBackTrace","class":"Ecocode_Profiler_Model_Collector_MysqlDataCollector","object":{},"type":"->","args":[]},{"file":"\/projects\/ecocode\/ecocode_profiler_test\/magento-1.8.1.0\/vendor\/ecocode\/magento_profiler\/app\/code\/community\/Ecocode\/Profiler\/Model\/Collector\/MysqlDataCollector.php","line":40,"function":"getTrace","class":"Ecocode_Profiler_Model_Collector_MysqlDataCollector","object":{},"type":"->","args":[]},{"file":"\/projects\/ecocode\/ecocode_profiler_test\/magento-1.8.1.0\/vendor\/ecocode\/magento_profiler\/app\/code\/community\/Ecocode\/Profiler\/Db\/Statement\/Pdo\/Mysql.php","line":55,"function":"logQuery","class":"Ecocode_Profiler_Model_Collector_MysqlDataCollector","object":{},"type":"->","args":[{}]},{"file":"\/projects\/ecocode\/ecocode_profiler_test\/magento-1.8.1.0\/vendor\/ecocode\/magento_profiler\/app\/code\/community\/Ecocode\/Profiler\/Db\/Statement\/Pdo\/Mysql.php","line":48,"function":"log","class":"Ecocode_Profiler_Db_Statement_Pdo_Mysql","object":{},"type":"->","args":[]},{"file":"\/projects\/ecocode\/ecocode_profiler_test\/magento-1.8.1.0\/httpdocs\/app\/code\/core\/Zend\/Db\/Statement.php","line":291,"function":"_execute","class":"Ecocode_Profiler_Db_Statement_Pdo_Mysql","object":{},"type":"->","args":[{":path0":"",":path1":"\/"}]},{"file":"\/projects\/ecocode\/ecocode_profiler_test\/magento-1.8.1.0\/httpdocs\/lib\/Zend\/Db\/Adapter\/Abstract.php","line":479,"function":"execute","class":"Zend_Db_Statement","object":{},"type":"->","args":[{":path0":"",":path1":"\/"}]},{"file":"\/projects\/ecocode\/ecocode_profiler_test\/magento-1.8.1.0\/httpdocs\/lib\/Zend\/Db\/Adapter\/Pdo\/Abstract.php","line":238,"function":"query","class":"Zend_Db_Adapter_Abstract","object":{},"type":"->","args":["SELECT `core_url_rewrite`.* FROM `core_url_rewrite` WHERE (request_path IN (:path0, :path1)) AND (store_id IN(0, 1))",{":path0":"",":path1":"\/"}]},{"file":"\/projects\/ecocode\/ecocode_profiler_test\/magento-1.8.1.0\/httpdocs\/lib\/Varien\/Db\/Adapter\/Pdo\/Mysql.php","line":428,"function":"query","class":"Zend_Db_Adapter_Pdo_Abstract","object":{},"type":"->","args":["SELECT `core_url_rewrite`.* FROM `core_url_rewrite` WHERE (request_path IN (:path0, :path1)) AND (store_id IN(0, 1))",{":path0":"",":path1":"\/"}]},{"file":"\/projects\/ecocode\/ecocode_profiler_test\/magento-1.8.1.0\/httpdocs\/lib\/Zend\/Db\/Adapter\/Abstract.php","line":734,"function":"query","class":"Varien_Db_Adapter_Pdo_Mysql","object":{},"type":"->","args":[{},{"path0":"","path1":"\/"}]},{"file":"\/projects\/ecocode\/ecocode_profiler_test\/magento-1.8.1.0\/httpdocs\/app\/code\/core\/Mage\/Core\/Model\/Resource\/Url\/Rewrite.php","line":151,"function":"fetchAll","class":"Zend_Db_Adapter_Abstract","object":{},"type":"->","args":[{},{"path0":"","path1":"\/"}]},{"file":"\/projects\/ecocode\/ecocode_profiler_test\/magento-1.8.1.0\/httpdocs\/app\/code\/core\/Mage\/Core\/Model\/Url\/Rewrite.php","line":100,"function":"loadByRequestPath","class":"Mage_Core_Model_Resource_Url_Rewrite","object":{},"type":"->","args":[{},["","\/"]]},{"file":"\/projects\/ecocode\/ecocode_profiler_test\/magento-1.8.1.0\/httpdocs\/app\/code\/core\/Mage\/Core\/Model\/Url\/Rewrite\/Request.php","line":139,"function":"loadByRequestPath","class":"Mage_Core_Model_Url_Rewrite","object":{},"type":"->","args":[["","\/"]]},{"file":"\/projects\/ecocode\/ecocode_profiler_test\/magento-1.8.1.0\/httpdocs\/app\/code\/core\/Mage\/Core\/Model\/Url\/Rewrite\/Request.php","line":116,"function":"_rewriteDb","class":"Mage_Core_Model_Url_Rewrite_Request","object":{},"type":"->","args":[]},{"file":"\/projects\/ecocode\/ecocode_profiler_test\/magento-1.8.1.0\/httpdocs\/app\/code\/core\/Mage\/Core\/Controller\/Varien\/Front.php","line":165,"function":"rewrite","class":"Mage_Core_Model_Url_Rewrite_Request","object":{},"type":"->","args":[]},{"file":"\/projects\/ecocode\/ecocode_profiler_test\/magento-1.8.1.0\/httpdocs\/app\/code\/core\/Mage\/Core\/Model\/App.php","line":354,"function":"dispatch","class":"Mage_Core_Controller_Varien_Front","object":{},"type":"->","args":[]},{"file":"\/projects\/ecocode\/ecocode_profiler_test\/magento-1.8.1.0\/httpdocs\/var\/cache\/Original_Mage_1.0.11-a6f179080788cdb98ede80fce0a470e1.php","line":692,"function":"run","class":"Mage_Core_Model_App","object":{},"type":"->","args":[{"scope_code":"","scope_type":"store","options":{"cache":{"id_prefix":"dev"},"config_model":"Ecocode_Profiler_Model_Core_Config"}}]},{"file":"\/projects\/ecocode\/ecocode_profiler_test\/magento-1.8.1.0\/vendor\/ecocode\/magento_profiler\/dev.php","line":68,"function":"run","class":"MageOriginal","type":"::","args":["","store",{"cache":{"id_prefix":"dev"},"config_model":"Ecocode_Profiler_Model_Core_Config"}]}]', true);
10
+ $expectedTrace = json_decode('[{"file":"\/projects\/ecocode\/ecocode_profiler_test\/magento-1.8.1.0\/httpdocs\/app\/code\/core\/Mage\/Core\/Model\/Url\/Rewrite.php","line":100,"function":"loadByRequestPath","class":"Mage_Core_Model_Resource_Url_Rewrite","object":{},"type":"->","args":[{},["","\/"]]},{"file":"\/projects\/ecocode\/ecocode_profiler_test\/magento-1.8.1.0\/httpdocs\/app\/code\/core\/Mage\/Core\/Model\/Url\/Rewrite\/Request.php","line":139,"function":"loadByRequestPath","class":"Mage_Core_Model_Url_Rewrite","object":{},"type":"->","args":[["","\/"]]},{"file":"\/projects\/ecocode\/ecocode_profiler_test\/magento-1.8.1.0\/httpdocs\/app\/code\/core\/Mage\/Core\/Model\/Url\/Rewrite\/Request.php","line":116,"function":"_rewriteDb","class":"Mage_Core_Model_Url_Rewrite_Request","object":{},"type":"->","args":[]},{"file":"\/projects\/ecocode\/ecocode_profiler_test\/magento-1.8.1.0\/httpdocs\/app\/code\/core\/Mage\/Core\/Controller\/Varien\/Front.php","line":165,"function":"rewrite","class":"Mage_Core_Model_Url_Rewrite_Request","object":{},"type":"->","args":[]},{"file":"\/projects\/ecocode\/ecocode_profiler_test\/magento-1.8.1.0\/httpdocs\/app\/code\/core\/Mage\/Core\/Model\/App.php","line":354,"function":"dispatch","class":"Mage_Core_Controller_Varien_Front","object":{},"type":"->","args":[]},{"file":"\/projects\/ecocode\/ecocode_profiler_test\/magento-1.8.1.0\/httpdocs\/var\/cache\/Original_Mage_1.0.11-a6f179080788cdb98ede80fce0a470e1.php","line":692,"function":"run","class":"Mage_Core_Model_App","object":{},"type":"->","args":[{"scope_code":"","scope_type":"store","options":{"cache":{"id_prefix":"dev"},"config_model":"Ecocode_Profiler_Model_Core_Config"}}]},{"file":"\/projects\/ecocode\/ecocode_profiler_test\/magento-1.8.1.0\/vendor\/ecocode\/magento_profiler\/dev.php","line":68,"function":"run","class":"MageOriginal","type":"::","args":["","store",{"cache":{"id_prefix":"dev"},"config_model":"Ecocode_Profiler_Model_Core_Config"}]}]', true);
11
+
12
+ foreach ($originalTrace as &$trace) {
13
+ if (isset($trace['class'])) {
14
+ $trace['object'] = $this->getMockBuilder($trace['class'])->disableOriginalConstructor()->getMock();
15
+ }
16
+ }
17
+ $dataCollector = new Ecocode_Profiler_Model_Collector_MysqlDataCollector();
18
+
19
+ $cleanedTrace = $dataCollector->cleanBacktrace($originalTrace);
20
+
21
+ $this->assertCount(count($expectedTrace), $cleanedTrace);
22
+ }
23
+ }
app/code/community/Ecocode/Profiler/Tests/Dev/Model/Collector/RequestDataCollectorTest.php ADDED
@@ -0,0 +1,158 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Ecocode_Profiler_Tests_Dev_Model_Collector_RequestDataCollectorTest
4
+ extends TestHelper
5
+ {
6
+ public function testCollect()
7
+ {
8
+ $collector = new Ecocode_Profiler_Model_Collector_RequestDataCollector();
9
+
10
+
11
+ $request = $this->getMockBuilder('Mage_Core_Controller_Request_Http')
12
+ ->setMethods(['getMethod', 'getServer', 'getCookie'])
13
+ ->getMock();
14
+
15
+ $serverData = [
16
+ 'REDIRECT_STATUS' => 200,
17
+ 'HTTP_HOST' => 'profiler.test',
18
+ 'HTTP_ACCEPT_ENCODING' => 'gzip, deflate, sdch',
19
+ ];
20
+ $cookieData = [
21
+ 'frontend' => 'session-key'
22
+ ];
23
+ $request->method('getMethod')->willReturn('GET');
24
+ $request->method('getServer')->willReturn($serverData);
25
+ $request->method('getCookie')->willReturn($cookieData);
26
+
27
+ $request->setRequestUri('/dev.php/electronics.html');
28
+ $request->setBaseUrl('/dev.php');
29
+ $request->setPathInfo();
30
+
31
+ $request->setRequestUri('/dev.php/catalog/category/view/id/13');
32
+ $request->setPathInfo('catalog/category/view/id/13');
33
+ $request->setParams(['id' => '13']);
34
+ $request->setRouteName('catalog');
35
+ $request->setControllerName('category');
36
+ $request->setActionName('view');
37
+
38
+
39
+ /** @var Mage_Core_Controller_Request_Http $request */
40
+
41
+ $response = new Ecocode_Profiler_Tests_Dev_Fixtures_ResponseHttp();
42
+ $response->setHttpResponseCode(201);
43
+ $response->setHeader('content-Type', 'application/json');
44
+ $response->setHeader('X-DEBUG-TOKEN', 'XXX');
45
+
46
+
47
+ $collector->collect(
48
+ $request,
49
+ $response
50
+ );
51
+
52
+ $this->assertEquals('GET', $collector->getMethod());
53
+ $this->assertEquals('application/json', $collector->getContentType());
54
+ $this->assertEquals(201, $collector->getStatusCode());
55
+ $this->assertEquals(Ecocode_Profiler_Model_Collector_RequestDataCollector::$statusTexts[201], $collector->getStatusText());
56
+ $this->assertEquals(
57
+ ['host' => ['profiler.test'], 'accept-encoding' => ['gzip, deflate, sdch']],
58
+ $collector->getRequestHeaders()->all()
59
+ );
60
+
61
+ $this->assertEquals(
62
+ $serverData,
63
+ $collector->getRequestServer()->all()
64
+ );
65
+
66
+ $this->assertEquals(
67
+ $cookieData,
68
+ $collector->getRequestCookies()->all()
69
+ );
70
+
71
+ $this->assertEquals('catalog/category/view/id/13', $collector->getPathInfo());
72
+ //no post data
73
+ $this->assertEmpty($collector->getRequestRequest());
74
+
75
+ //no get data
76
+ $this->assertEmpty($collector->getRequestQuery());
77
+
78
+ $this->assertCount(4, $collector->getController());
79
+
80
+ $this->assertInstanceOf('Ecocode_Profiler_Model_Http_ResponseHeaderBag', $collector->getResponseHeaders());
81
+
82
+ return $collector;
83
+ }
84
+
85
+ public function testCollectParameters()
86
+ {
87
+ $collector = new Ecocode_Profiler_Model_Collector_RequestDataCollector();
88
+
89
+
90
+ $request = $this->getMockBuilder('Mage_Core_Controller_Request_Http')
91
+ ->setMethods(['getQuery', 'getPost'])
92
+ ->getMock();
93
+
94
+ $request->method('getQuery')->willReturn(['q' => 'search']);
95
+ $request->method('getPost')->willReturn(['key' => 'data']);
96
+
97
+ $response = new Ecocode_Profiler_Tests_Dev_Fixtures_ResponseHttp();
98
+ $collector->collect($request, $response);
99
+
100
+ //no post data
101
+ $this->assertEquals(['key' => 'data'], $collector->getRequestRequest()->all());
102
+
103
+ //no get data
104
+ $this->assertEquals(['q' => 'search'], $collector->getRequestQuery()->all());
105
+ }
106
+
107
+
108
+ public function testParseController()
109
+ {
110
+ $collector = new Ecocode_Profiler_Model_Collector_RequestDataCollector();
111
+
112
+ $controller = new Mage_Core_Controller_Varien_Front();
113
+
114
+ $parseControllerMethod = new ReflectionMethod('Ecocode_Profiler_Model_Collector_RequestDataCollector', 'parseController');
115
+ $parseControllerMethod->setAccessible(true);
116
+
117
+
118
+ $controllerData = $parseControllerMethod->invoke($collector, false);
119
+ $this->assertEquals('n/a', $controllerData);
120
+
121
+ $controllerData = $parseControllerMethod->invoke($collector, $controller);
122
+
123
+ $this->assertEquals('Mage_Core_Controller_Varien_Front', $controllerData['class']);
124
+ }
125
+
126
+ public function testDetectStatusCode()
127
+ {
128
+ $collector = new Ecocode_Profiler_Model_Collector_RequestDataCollector();
129
+
130
+ $response = new Ecocode_Profiler_Tests_Dev_Fixtures_ResponseHttp();
131
+ $response->setHttpResponseCode(200);
132
+
133
+ $detectStatusCodeMethod = new ReflectionMethod('Ecocode_Profiler_Model_Collector_RequestDataCollector', 'detectStatusCode');
134
+ $detectStatusCodeMethod->setAccessible(true);
135
+
136
+ $this->assertEquals(200, $detectStatusCodeMethod->invoke($collector, $response));
137
+
138
+ //magento does not set the status 100% correct, sometime only the header is present
139
+ $response->setHeader('Http/1.1', '404 Not Found');
140
+ $this->assertEquals(404, $detectStatusCodeMethod->invoke($collector, $response));
141
+ }
142
+
143
+ /**
144
+ * @depends testCollect
145
+ */
146
+ public function testCollectRequestAttributes(Ecocode_Profiler_Model_Collector_RequestDataCollector $collector)
147
+ {
148
+ $this->assertInstanceOf('Ecocode_Profiler_Model_Http_ParameterBag', $collector->getRequestAttributes());
149
+ $this->assertEquals('/electronics.html', $collector->getRequestString());
150
+ $this->assertEquals('/dev.php/catalog/category/view/id/13', $collector->getRequestUri());
151
+ $this->assertEquals('catalog', $collector->getModuleName());
152
+ $this->assertEquals('category', $collector->getControllerName());
153
+ $this->assertEquals('view', $collector->getActionName());
154
+ $this->assertEquals('catalog_category_view', $collector->getRoute());
155
+ $this->assertEquals('catalog', $collector->getRouteName());
156
+ $this->assertEquals(['id' => '13'], $collector->getRouteParams());
157
+ }
158
+ }
app/code/community/Ecocode/Profiler/Tests/Dev/Model/Collector/RewriteDataCollectorTest.php ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Ecocode_Profiler_Tests_Dev_Model_Collector_RewriteDataCollectorTest
4
+ extends TestHelper
5
+ {
6
+ public function testCollect()
7
+ {
8
+ $rewriteHelperMock = $this->getMockBuilder('Ecocode_Profiler_Helper_Rewrite')
9
+ ->setMethods(['loadRewrites', 'getRewriteConflicts'])
10
+ ->getMock();
11
+
12
+ //fake a conflict and sample load rewrites
13
+ $rewrites = json_decode('{"blocks":[],"helpers":[],"models":{"core_mysql4\/session":["XXX_REWRITE"]}}', true);
14
+ $conflicts = json_decode('[{"type":"blocks","class":"n98\/mock_conflict","rewrites":["Mage_Customer_Block_Account","Mage_Tag_Block_All"],"loaded_class":"Mage_N98_Block_Mock_Conflict"}]', true);
15
+
16
+ $rewriteHelperMock->method('loadRewrites')->willReturn($rewrites);
17
+ $rewriteHelperMock->method('getRewriteConflicts')->willReturn($conflicts);
18
+
19
+ /** @var Ecocode_Profiler_Model_Collector_RewriteDataCollector $collector */
20
+ $collector = $this->getMockBuilder('Ecocode_Profiler_Model_Collector_RewriteDataCollector')
21
+ ->setMethods(['getRewriteHelper'])
22
+ ->getMock();
23
+
24
+
25
+ $collector->method('getRewriteHelper')->willReturn($rewriteHelperMock);
26
+
27
+ $collector->collect(
28
+ new Mage_Core_Controller_Request_Http(),
29
+ new Mage_Core_Controller_Response_Http()
30
+ );
31
+
32
+ $rewrites = $collector->getModuleRewrites();
33
+ $this->assertCount(0, $rewrites['blocks']);
34
+ $this->assertCount(0, $rewrites['helpers']);
35
+ $this->assertCount(1, $rewrites['models']);
36
+ $this->assertCount(1, $collector->getModuleRewriteConflicts());
37
+ $this->assertEquals(1, $collector->getModuleRewriteConflictCount());
38
+ }
39
+ }
app/code/community/Ecocode/Profiler/Tests/Dev/Model/Collector/TimeDataCollectorTest.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Ecocode_Profiler_Tests_Dev_Model_Collector_TimeDataCollectorTest
4
+ extends TestHelper
5
+ {
6
+
7
+ public function testCollect()
8
+ {
9
+ /** @var Ecocode_Profiler_Model_Collector_TimeDataCollector $collector */
10
+ $collector = new Ecocode_Profiler_Model_Collector_TimeDataCollector();
11
+
12
+ $collector->collect(
13
+ new Mage_Core_Controller_Request_Http(),
14
+ new Mage_Core_Controller_Response_Http()
15
+ );
16
+
17
+ $this->assertEquals(0, $collector->getTotalTime());
18
+ return $collector;
19
+ }
20
+
21
+ /**
22
+ * @depends testCollect
23
+ */
24
+ public function testLateCollect(Ecocode_Profiler_Model_Collector_TimeDataCollector $collector)
25
+ {
26
+ $collector->lateCollect();
27
+ $this->assertGreaterThan(0, $collector->getTotalTime());
28
+ }
29
+
30
+ }
app/code/community/Ecocode/Profiler/Tests/Dev/Model/Collector/TranslationDataCollectorTest.php ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Ecocode_Profiler_Tests_Dev_Model_Collector_TranslationDataCollectorTest
4
+ extends TestHelper
5
+ {
6
+
7
+ public function testCollect()
8
+ {
9
+ $translate = new Mage_Core_Model_Translate();
10
+ /** @var Ecocode_Profiler_Model_Collector_TranslationDataCollector $collector */
11
+ $collector = $this->getMockBuilder('Ecocode_Profiler_Model_Collector_TranslationDataCollector')
12
+ ->setMethods(['getTranslator'])
13
+ ->getMock();
14
+
15
+ $collector->method('getTranslator')->willReturn($translate);
16
+
17
+ $messageLog = [
18
+ ['DE_de', 'code-1', 'the-text', 'the-translation', 'translated'],
19
+ ['DE_de', 'code-1', 'the-text', 'the-translation', 'translated'],
20
+ ['DE_de', 'code-2', 'the-text', 'the-translation', 'missing'],
21
+ ['DE_de', 'code-3', 'the-text', 'the-translation', 'invalid'],
22
+ ['DE_de', 'with-trace', 'the-text', 'the-translation', 'fallback', [], null, ['trace1' => []]],
23
+ ['DE_de', 'with-trace', 'the-text', 'the-translation', 'fallback', [], null, ['trace2' => []]],
24
+ ['DE_de', 'multiple-parameters', 'the-text', 'the-translation', 'fallback', ['a' => 'b'], 'catalog'],
25
+ ['DE_de', 'multiple-parameters', 'the-text', 'the-translation', 'fallback', ['c' => 'd'], 'catalog']
26
+ ];
27
+
28
+ $messages = [];
29
+ foreach ($messageLog as $message) {
30
+ $messages[] = [
31
+ 'locale' => $message[0],
32
+ 'code' => $message[1],
33
+ 'text' => $message[2],
34
+ 'translation' => $message[3],
35
+ 'state' => $message[4],
36
+ 'parameters' => isset($message[5]) ? $message[5] : [],
37
+ 'module' => isset($message[6]) ? $message[6] : null,
38
+ 'trace' => isset($message[7]) ? $message[7] : [],
39
+ ];
40
+ }
41
+ $messagesProperty = new ReflectionProperty('Mage_Core_Model_Translate', 'messages');
42
+ $messagesProperty->setAccessible(true);
43
+ $messagesProperty->setValue($translate, $messages);
44
+
45
+ $collector->collect(
46
+ new Mage_Core_Controller_Request_Http(),
47
+ new Mage_Core_Controller_Response_Http()
48
+ );
49
+
50
+ $translations = $collector->getTranslations();
51
+ $this->assertCount(5, $translations);
52
+ $this->assertEquals(5, $collector->getTranslationCount());
53
+
54
+ $this->assertEquals(2, $translations['code-1']['count']);
55
+ $this->assertEquals(1, $translations['code-2']['count']);
56
+
57
+ //test stats counts
58
+
59
+ //test trace set
60
+ $this->assertCount(2, $translations['with-trace']['traces']);
61
+
62
+ //test parameters
63
+ $this->assertEmpty($translations['code-1']['parameters']);
64
+ $this->assertNotEmpty($translations['multiple-parameters']['parameters']);
65
+ $this->assertEquals([['a' => 'b'], ['c' => 'd']], $translations['multiple-parameters']['parameters']);
66
+
67
+ //getStateCount
68
+ $this->assertTrue(is_array($collector->getStateCount()));
69
+ $this->assertEquals(1, $collector->getStateCount('translated'));
70
+ $this->assertEquals(1, $collector->getStateCount('missing'));
71
+ $this->assertEquals(1, $collector->getStateCount('invalid'));
72
+ $this->assertEquals(2, $collector->getStateCount('fallback'));
73
+
74
+ $this->assertEquals(4, $collector->getNotOkCount());
75
+
76
+
77
+ return $collector;
78
+ }
79
+ }
app/code/community/Ecocode/Profiler/Tests/Dev/Model/Http/HeaderBagTest.php ADDED
@@ -0,0 +1,192 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+
13
+ class HeaderBagTest extends \PHPUnit_Framework_TestCase
14
+ {
15
+ public function testConstructor()
16
+ {
17
+ $bag = new Ecocode_Profiler_Model_Http_HeaderBag(array('foo' => 'bar'));
18
+ $this->assertTrue($bag->has('foo'));
19
+ }
20
+
21
+ public function testToStringNull()
22
+ {
23
+ $bag = new Ecocode_Profiler_Model_Http_HeaderBag();
24
+ $this->assertEquals('', $bag->__toString());
25
+ }
26
+
27
+ public function testToStringNotNull()
28
+ {
29
+ $bag = new Ecocode_Profiler_Model_Http_HeaderBag(array('foo' => 'bar'));
30
+ $this->assertEquals("Foo: bar\r\n", $bag->__toString());
31
+ }
32
+
33
+ public function testKeys()
34
+ {
35
+ $bag = new Ecocode_Profiler_Model_Http_HeaderBag(array('foo' => 'bar'));
36
+ $keys = $bag->keys();
37
+ $this->assertEquals('foo', $keys[0]);
38
+ }
39
+
40
+ public function testGetDate()
41
+ {
42
+ $bag = new Ecocode_Profiler_Model_Http_HeaderBag(array('foo' => 'Tue, 4 Sep 2012 20:00:00 +0200'));
43
+ $headerDate = $bag->getDate('foo');
44
+ $this->assertInstanceOf('DateTime', $headerDate);
45
+ }
46
+
47
+ /**
48
+ * @expectedException \RuntimeException
49
+ */
50
+ public function testGetDateException()
51
+ {
52
+ $bag = new Ecocode_Profiler_Model_Http_HeaderBag(array('foo' => 'Tue'));
53
+ $headerDate = $bag->getDate('foo');
54
+ }
55
+
56
+ public function testGetCacheControlHeader()
57
+ {
58
+ $bag = new Ecocode_Profiler_Model_Http_HeaderBag();
59
+ $bag->addCacheControlDirective('public', '#a');
60
+ $this->assertTrue($bag->hasCacheControlDirective('public'));
61
+ $this->assertEquals('#a', $bag->getCacheControlDirective('public'));
62
+ }
63
+
64
+ public function testAll()
65
+ {
66
+ $bag = new Ecocode_Profiler_Model_Http_HeaderBag(array('foo' => 'bar'));
67
+ $this->assertEquals(array('foo' => array('bar')), $bag->all(), '->all() gets all the input');
68
+
69
+ $bag = new Ecocode_Profiler_Model_Http_HeaderBag(array('FOO' => 'BAR'));
70
+ $this->assertEquals(array('foo' => array('BAR')), $bag->all(), '->all() gets all the input key are lower case');
71
+ }
72
+
73
+ public function testReplace()
74
+ {
75
+ $bag = new Ecocode_Profiler_Model_Http_HeaderBag(array('foo' => 'bar'));
76
+
77
+ $bag->replace(array('NOPE' => 'BAR'));
78
+ $this->assertEquals(array('nope' => array('BAR')), $bag->all(), '->replace() replaces the input with the argument');
79
+ $this->assertFalse($bag->has('foo'), '->replace() overrides previously set the input');
80
+ }
81
+
82
+ public function testGet()
83
+ {
84
+ $bag = new Ecocode_Profiler_Model_Http_HeaderBag(array('foo' => 'bar', 'fuzz' => 'bizz'));
85
+ $this->assertEquals('bar', $bag->get('foo'), '->get return current value');
86
+ $this->assertEquals('bar', $bag->get('FoO'), '->get key in case insensitive');
87
+ $this->assertEquals(array('bar'), $bag->get('foo', 'nope', false), '->get return the value as array');
88
+
89
+ // defaults
90
+ $this->assertNull($bag->get('none'), '->get unknown values returns null');
91
+ $this->assertEquals('default', $bag->get('none', 'default'), '->get unknown values returns default');
92
+ $this->assertEquals(array('default'), $bag->get('none', 'default', false), '->get unknown values returns default as array');
93
+
94
+ $bag->set('foo', 'bor', false);
95
+ $this->assertEquals('bar', $bag->get('foo'), '->get return first value');
96
+ $this->assertEquals(array('bar', 'bor'), $bag->get('foo', 'nope', false), '->get return all values as array');
97
+ }
98
+
99
+ public function testSetAssociativeArray()
100
+ {
101
+ $bag = new Ecocode_Profiler_Model_Http_HeaderBag();
102
+ $bag->set('foo', array('bad-assoc-index' => 'value'));
103
+ $this->assertSame('value', $bag->get('foo'));
104
+ $this->assertEquals(array('value'), $bag->get('foo', 'nope', false), 'assoc indices of multi-valued headers are ignored');
105
+ }
106
+
107
+ public function testContains()
108
+ {
109
+ $bag = new Ecocode_Profiler_Model_Http_HeaderBag(array('foo' => 'bar', 'fuzz' => 'bizz'));
110
+ $this->assertTrue($bag->contains('foo', 'bar'), '->contains first value');
111
+ $this->assertTrue($bag->contains('fuzz', 'bizz'), '->contains second value');
112
+ $this->assertFalse($bag->contains('nope', 'nope'), '->contains unknown value');
113
+ $this->assertFalse($bag->contains('foo', 'nope'), '->contains unknown value');
114
+
115
+ // Multiple values
116
+ $bag->set('foo', 'bor', false);
117
+ $this->assertTrue($bag->contains('foo', 'bar'), '->contains first value');
118
+ $this->assertTrue($bag->contains('foo', 'bor'), '->contains second value');
119
+ $this->assertFalse($bag->contains('foo', 'nope'), '->contains unknown value');
120
+ }
121
+
122
+ public function testCacheControlDirectiveAccessors()
123
+ {
124
+ $bag = new Ecocode_Profiler_Model_Http_HeaderBag();
125
+ $bag->addCacheControlDirective('public');
126
+
127
+ $this->assertTrue($bag->hasCacheControlDirective('public'));
128
+ $this->assertTrue($bag->getCacheControlDirective('public'));
129
+ $this->assertEquals('public', $bag->get('cache-control'));
130
+
131
+ $bag->addCacheControlDirective('max-age', 10);
132
+ $this->assertTrue($bag->hasCacheControlDirective('max-age'));
133
+ $this->assertEquals(10, $bag->getCacheControlDirective('max-age'));
134
+ $this->assertEquals('max-age=10, public', $bag->get('cache-control'));
135
+
136
+ $bag->removeCacheControlDirective('max-age');
137
+ $this->assertFalse($bag->hasCacheControlDirective('max-age'));
138
+ }
139
+
140
+ public function testCacheControlDirectiveParsing()
141
+ {
142
+ $bag = new Ecocode_Profiler_Model_Http_HeaderBag(array('cache-control' => 'public, max-age=10'));
143
+ $this->assertTrue($bag->hasCacheControlDirective('public'));
144
+ $this->assertTrue($bag->getCacheControlDirective('public'));
145
+
146
+ $this->assertTrue($bag->hasCacheControlDirective('max-age'));
147
+ $this->assertEquals(10, $bag->getCacheControlDirective('max-age'));
148
+
149
+ $bag->addCacheControlDirective('s-maxage', 100);
150
+ $this->assertEquals('max-age=10, public, s-maxage=100', $bag->get('cache-control'));
151
+ }
152
+
153
+ public function testCacheControlDirectiveParsingQuotedZero()
154
+ {
155
+ $bag = new Ecocode_Profiler_Model_Http_HeaderBag(array('cache-control' => 'max-age="0"'));
156
+ $this->assertTrue($bag->hasCacheControlDirective('max-age'));
157
+ $this->assertEquals(0, $bag->getCacheControlDirective('max-age'));
158
+ }
159
+
160
+ public function testCacheControlDirectiveOverrideWithReplace()
161
+ {
162
+ $bag = new Ecocode_Profiler_Model_Http_HeaderBag(array('cache-control' => 'private, max-age=100'));
163
+ $bag->replace(array('cache-control' => 'public, max-age=10'));
164
+ $this->assertTrue($bag->hasCacheControlDirective('public'));
165
+ $this->assertTrue($bag->getCacheControlDirective('public'));
166
+
167
+ $this->assertTrue($bag->hasCacheControlDirective('max-age'));
168
+ $this->assertEquals(10, $bag->getCacheControlDirective('max-age'));
169
+ }
170
+
171
+ public function testGetIterator()
172
+ {
173
+ $headers = array('foo' => 'bar', 'hello' => 'world', 'third' => 'charm');
174
+ $headerBag = new Ecocode_Profiler_Model_Http_HeaderBag($headers);
175
+
176
+ $i = 0;
177
+ foreach ($headerBag as $key => $val) {
178
+ ++$i;
179
+ $this->assertEquals(array($headers[$key]), $val);
180
+ }
181
+
182
+ $this->assertEquals(count($headers), $i);
183
+ }
184
+
185
+ public function testCount()
186
+ {
187
+ $headers = array('foo' => 'bar', 'HELLO' => 'WORLD');
188
+ $headerBag = new Ecocode_Profiler_Model_Http_HeaderBag($headers);
189
+
190
+ $this->assertEquals(count($headers), count($headerBag));
191
+ }
192
+ }
app/code/community/Ecocode/Profiler/Tests/Dev/Model/Http/ParameterBagTest.php ADDED
@@ -0,0 +1,181 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+
4
+ class ParameterBagTest extends \PHPUnit_Framework_TestCase
5
+ {
6
+ public function testConstructor()
7
+ {
8
+ $this->testAll();
9
+ }
10
+
11
+ public function testAll()
12
+ {
13
+ $bag = new Ecocode_Profiler_Model_Http_ParameterBag(array('foo' => 'bar'));
14
+ $this->assertEquals(array('foo' => 'bar'), $bag->all(), '->all() gets all the input');
15
+ }
16
+
17
+ public function testKeys()
18
+ {
19
+ $bag = new Ecocode_Profiler_Model_Http_ParameterBag(array('foo' => 'bar'));
20
+ $this->assertEquals(array('foo'), $bag->keys());
21
+ }
22
+
23
+ public function testAdd()
24
+ {
25
+ $bag = new Ecocode_Profiler_Model_Http_ParameterBag(array('foo' => 'bar'));
26
+ $bag->add(array('bar' => 'bas'));
27
+ $this->assertEquals(array('foo' => 'bar', 'bar' => 'bas'), $bag->all());
28
+ }
29
+
30
+ public function testRemove()
31
+ {
32
+ $bag = new Ecocode_Profiler_Model_Http_ParameterBag(array('foo' => 'bar'));
33
+ $bag->add(array('bar' => 'bas'));
34
+ $this->assertEquals(array('foo' => 'bar', 'bar' => 'bas'), $bag->all());
35
+ $bag->remove('bar');
36
+ $this->assertEquals(array('foo' => 'bar'), $bag->all());
37
+ }
38
+
39
+ public function testReplace()
40
+ {
41
+ $bag = new Ecocode_Profiler_Model_Http_ParameterBag(array('foo' => 'bar'));
42
+
43
+ $bag->replace(array('FOO' => 'BAR'));
44
+ $this->assertEquals(array('FOO' => 'BAR'), $bag->all(), '->replace() replaces the input with the argument');
45
+ $this->assertFalse($bag->has('foo'), '->replace() overrides previously set the input');
46
+ }
47
+
48
+ public function testGet()
49
+ {
50
+ $bag = new Ecocode_Profiler_Model_Http_ParameterBag(array('foo' => 'bar', 'null' => null));
51
+
52
+ $this->assertEquals('bar', $bag->get('foo'), '->get() gets the value of a parameter');
53
+ $this->assertEquals('default', $bag->get('unknown', 'default'), '->get() returns second argument as default if a parameter is not defined');
54
+ $this->assertNull($bag->get('null', 'default'), '->get() returns null if null is set');
55
+ }
56
+
57
+ public function testGetDoesNotUseDeepByDefault()
58
+ {
59
+ $bag = new Ecocode_Profiler_Model_Http_ParameterBag(array('foo' => array('bar' => 'moo')));
60
+
61
+ $this->assertNull($bag->get('foo[bar]'));
62
+ }
63
+
64
+ public function testSet()
65
+ {
66
+ $bag = new Ecocode_Profiler_Model_Http_ParameterBag(array());
67
+
68
+ $bag->set('foo', 'bar');
69
+ $this->assertEquals('bar', $bag->get('foo'), '->set() sets the value of parameter');
70
+
71
+ $bag->set('foo', 'baz');
72
+ $this->assertEquals('baz', $bag->get('foo'), '->set() overrides previously set parameter');
73
+ }
74
+
75
+ public function testHas()
76
+ {
77
+ $bag = new Ecocode_Profiler_Model_Http_ParameterBag(array('foo' => 'bar'));
78
+
79
+ $this->assertTrue($bag->has('foo'), '->has() returns true if a parameter is defined');
80
+ $this->assertFalse($bag->has('unknown'), '->has() return false if a parameter is not defined');
81
+ }
82
+
83
+ public function testGetAlpha()
84
+ {
85
+ $bag = new Ecocode_Profiler_Model_Http_ParameterBag(array('word' => 'foo_BAR_012'));
86
+
87
+ $this->assertEquals('fooBAR', $bag->getAlpha('word'), '->getAlpha() gets only alphabetic characters');
88
+ $this->assertEquals('', $bag->getAlpha('unknown'), '->getAlpha() returns empty string if a parameter is not defined');
89
+ }
90
+
91
+ public function testGetAlnum()
92
+ {
93
+ $bag = new Ecocode_Profiler_Model_Http_ParameterBag(array('word' => 'foo_BAR_012'));
94
+
95
+ $this->assertEquals('fooBAR012', $bag->getAlnum('word'), '->getAlnum() gets only alphanumeric characters');
96
+ $this->assertEquals('', $bag->getAlnum('unknown'), '->getAlnum() returns empty string if a parameter is not defined');
97
+ }
98
+
99
+ public function testGetDigits()
100
+ {
101
+ $bag = new Ecocode_Profiler_Model_Http_ParameterBag(array('word' => 'foo_BAR_012'));
102
+
103
+ $this->assertEquals('012', $bag->getDigits('word'), '->getDigits() gets only digits as string');
104
+ $this->assertEquals('', $bag->getDigits('unknown'), '->getDigits() returns empty string if a parameter is not defined');
105
+ }
106
+
107
+ public function testGetInt()
108
+ {
109
+ $bag = new Ecocode_Profiler_Model_Http_ParameterBag(array('digits' => '0123'));
110
+
111
+ $this->assertEquals(123, $bag->getInt('digits'), '->getInt() gets a value of parameter as integer');
112
+ $this->assertEquals(0, $bag->getInt('unknown'), '->getInt() returns zero if a parameter is not defined');
113
+ }
114
+
115
+ public function testFilter()
116
+ {
117
+ $bag = new Ecocode_Profiler_Model_Http_ParameterBag(array(
118
+ 'digits' => '0123ab',
119
+ 'email' => 'example@example.com',
120
+ 'url' => 'http://example.com/foo',
121
+ 'dec' => '256',
122
+ 'hex' => '0x100',
123
+ 'array' => array('bang'),
124
+ ));
125
+
126
+ $this->assertEmpty($bag->filter('nokey'), '->filter() should return empty by default if no key is found');
127
+
128
+ $this->assertEquals('0123', $bag->filter('digits', '', FILTER_SANITIZE_NUMBER_INT), '->filter() gets a value of parameter as integer filtering out invalid characters');
129
+
130
+ $this->assertEquals('example@example.com', $bag->filter('email', '', FILTER_VALIDATE_EMAIL), '->filter() gets a value of parameter as email');
131
+
132
+ $this->assertEquals('http://example.com/foo', $bag->filter('url', '', FILTER_VALIDATE_URL, array('flags' => FILTER_FLAG_PATH_REQUIRED)), '->filter() gets a value of parameter as URL with a path');
133
+
134
+ // This test is repeated for code-coverage
135
+ $this->assertEquals('http://example.com/foo', $bag->filter('url', '', FILTER_VALIDATE_URL, FILTER_FLAG_PATH_REQUIRED), '->filter() gets a value of parameter as URL with a path');
136
+
137
+ $this->assertFalse($bag->filter('dec', '', FILTER_VALIDATE_INT, array(
138
+ 'flags' => FILTER_FLAG_ALLOW_HEX,
139
+ 'options' => array('min_range' => 1, 'max_range' => 0xff),
140
+ )), '->filter() gets a value of parameter as integer between boundaries');
141
+
142
+ $this->assertFalse($bag->filter('hex', '', FILTER_VALIDATE_INT, array(
143
+ 'flags' => FILTER_FLAG_ALLOW_HEX,
144
+ 'options' => array('min_range' => 1, 'max_range' => 0xff),
145
+ )), '->filter() gets a value of parameter as integer between boundaries');
146
+
147
+ $this->assertEquals(array('bang'), $bag->filter('array', ''), '->filter() gets a value of parameter as an array');
148
+ }
149
+
150
+ public function testGetIterator()
151
+ {
152
+ $parameters = array('foo' => 'bar', 'hello' => 'world');
153
+ $bag = new Ecocode_Profiler_Model_Http_ParameterBag($parameters);
154
+
155
+ $i = 0;
156
+ foreach ($bag as $key => $val) {
157
+ ++$i;
158
+ $this->assertEquals($parameters[$key], $val);
159
+ }
160
+
161
+ $this->assertEquals(count($parameters), $i);
162
+ }
163
+
164
+ public function testCount()
165
+ {
166
+ $parameters = array('foo' => 'bar', 'hello' => 'world');
167
+ $bag = new Ecocode_Profiler_Model_Http_ParameterBag($parameters);
168
+
169
+ $this->assertEquals(count($parameters), count($bag));
170
+ }
171
+
172
+ public function testGetBoolean()
173
+ {
174
+ $parameters = array('string_true' => 'true', 'string_false' => 'false');
175
+ $bag = new Ecocode_Profiler_Model_Http_ParameterBag($parameters);
176
+
177
+ $this->assertTrue($bag->getBoolean('string_true'), '->getBoolean() gets the string true as boolean true');
178
+ $this->assertFalse($bag->getBoolean('string_false'), '->getBoolean() gets the string false as boolean false');
179
+ $this->assertFalse($bag->getBoolean('unknown'), '->getBoolean() returns false if a parameter is not defined');
180
+ }
181
+ }
app/code/community/Ecocode/Profiler/Tests/Dev/Model/Http/ResponseHeaderBagTest.php ADDED
@@ -0,0 +1,160 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+
13
+ /**
14
+ * @group time-sensitive
15
+ */
16
+ class ResponseHeaderBagTest extends \PHPUnit_Framework_TestCase
17
+ {
18
+ /**
19
+ * @dataProvider provideAllPreserveCase
20
+ */
21
+ public function testAllPreserveCase($headers, $expected)
22
+ {
23
+ $bag = new Ecocode_Profiler_Model_Http_ResponseHeaderBag($headers);
24
+
25
+ $this->assertEquals($expected, $bag->allPreserveCase(), '->allPreserveCase() gets all input keys in original case');
26
+ }
27
+
28
+ public function provideAllPreserveCase()
29
+ {
30
+ return array(
31
+ array(
32
+ array('fOo' => 'BAR'),
33
+ array('fOo' => array('BAR'), 'Cache-Control' => array('no-cache')),
34
+ ),
35
+ array(
36
+ array('ETag' => 'xyzzy'),
37
+ array('ETag' => array('xyzzy'), 'Cache-Control' => array('private, must-revalidate')),
38
+ ),
39
+ array(
40
+ array('Content-MD5' => 'Q2hlY2sgSW50ZWdyaXR5IQ=='),
41
+ array('Content-MD5' => array('Q2hlY2sgSW50ZWdyaXR5IQ=='), 'Cache-Control' => array('no-cache')),
42
+ ),
43
+ array(
44
+ array('P3P' => 'CP="CAO PSA OUR"'),
45
+ array('P3P' => array('CP="CAO PSA OUR"'), 'Cache-Control' => array('no-cache')),
46
+ ),
47
+ array(
48
+ array('WWW-Authenticate' => 'Basic realm="WallyWorld"'),
49
+ array('WWW-Authenticate' => array('Basic realm="WallyWorld"'), 'Cache-Control' => array('no-cache')),
50
+ ),
51
+ array(
52
+ array('X-UA-Compatible' => 'IE=edge,chrome=1'),
53
+ array('X-UA-Compatible' => array('IE=edge,chrome=1'), 'Cache-Control' => array('no-cache')),
54
+ ),
55
+ array(
56
+ array('X-XSS-Protection' => '1; mode=block'),
57
+ array('X-XSS-Protection' => array('1; mode=block'), 'Cache-Control' => array('no-cache')),
58
+ ),
59
+ );
60
+ }
61
+
62
+ public function testReplace()
63
+ {
64
+ $bag = new Ecocode_Profiler_Model_Http_ResponseHeaderBag(array());
65
+ $this->assertEquals('no-cache', $bag->get('Cache-Control'));
66
+
67
+ $bag->replace(array('Cache-Control' => 'public'));
68
+ $this->assertEquals('public', $bag->get('Cache-Control'));
69
+ }
70
+
71
+ public function testReplaceWithRemove()
72
+ {
73
+ $bag = new Ecocode_Profiler_Model_Http_ResponseHeaderBag(array());
74
+ $this->assertEquals('no-cache', $bag->get('Cache-Control'));
75
+
76
+ $bag->remove('Cache-Control');
77
+ $bag->replace(array());
78
+ $this->assertEquals('no-cache', $bag->get('Cache-Control'));
79
+ }
80
+
81
+
82
+ /**
83
+ * @expectedException \InvalidArgumentException
84
+ */
85
+ public function testGetCookiesWithInvalidArgument()
86
+ {
87
+ $bag = new Ecocode_Profiler_Model_Http_ResponseHeaderBag();
88
+
89
+ $cookies = $bag->getCookies('invalid_argument');
90
+ }
91
+
92
+ /**
93
+ * @expectedException \InvalidArgumentException
94
+ */
95
+ public function testMakeDispositionInvalidDisposition()
96
+ {
97
+ $headers = new Ecocode_Profiler_Model_Http_ResponseHeaderBag();
98
+
99
+ $headers->makeDisposition('invalid', 'foo.html');
100
+ }
101
+
102
+ /**
103
+ * @dataProvider provideMakeDisposition
104
+ */
105
+ public function testMakeDisposition($disposition, $filename, $filenameFallback, $expected)
106
+ {
107
+ $headers = new Ecocode_Profiler_Model_Http_ResponseHeaderBag();
108
+
109
+ $this->assertEquals($expected, $headers->makeDisposition($disposition, $filename, $filenameFallback));
110
+ }
111
+
112
+ public function testToStringDoesntMessUpHeaders()
113
+ {
114
+ $headers = new Ecocode_Profiler_Model_Http_ResponseHeaderBag();
115
+
116
+ $headers->set('Location', 'http://www.symfony.com');
117
+ $headers->set('Content-type', 'text/html');
118
+
119
+ (string) $headers;
120
+
121
+ $allHeaders = $headers->allPreserveCase();
122
+ $this->assertEquals(array('http://www.symfony.com'), $allHeaders['Location']);
123
+ $this->assertEquals(array('text/html'), $allHeaders['Content-type']);
124
+ }
125
+
126
+ public function provideMakeDisposition()
127
+ {
128
+ return array(
129
+ array('attachment', 'foo.html', 'foo.html', 'attachment; filename="foo.html"'),
130
+ array('attachment', 'foo.html', '', 'attachment; filename="foo.html"'),
131
+ array('attachment', 'foo bar.html', '', 'attachment; filename="foo bar.html"'),
132
+ array('attachment', 'foo "bar".html', '', 'attachment; filename="foo \\"bar\\".html"'),
133
+ array('attachment', 'foo%20bar.html', 'foo bar.html', 'attachment; filename="foo bar.html"; filename*=utf-8\'\'foo%2520bar.html'),
134
+ array('attachment', 'föö.html', 'foo.html', 'attachment; filename="foo.html"; filename*=utf-8\'\'f%C3%B6%C3%B6.html'),
135
+ );
136
+ }
137
+
138
+ /**
139
+ * @dataProvider provideMakeDispositionFail
140
+ * @expectedException \InvalidArgumentException
141
+ */
142
+ public function testMakeDispositionFail($disposition, $filename)
143
+ {
144
+ $headers = new Ecocode_Profiler_Model_Http_ResponseHeaderBag();
145
+
146
+ $headers->makeDisposition($disposition, $filename);
147
+ }
148
+
149
+ public function provideMakeDispositionFail()
150
+ {
151
+ return array(
152
+ array('attachment', 'foo%20bar.html'),
153
+ array('attachment', 'foo/bar.html'),
154
+ array('attachment', '/foo.html'),
155
+ array('attachment', 'foo\bar.html'),
156
+ array('attachment', '\foo.html'),
157
+ array('attachment', 'föö.html'),
158
+ );
159
+ }
160
+ }
app/code/community/Ecocode/Profiler/Tests/Dev/Model/LoggerTest.php ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ use Monolog\Handler\TestHandler;
4
+
5
+ class Ecocode_Profiler_Tests_Dev_Model_LoggerTest
6
+ extends TestHelper
7
+ {
8
+ protected function setUp()
9
+ {
10
+ if (!class_exists('Monolog\Handler\TestHandler')) {
11
+ $this->markTestSkipped(
12
+ 'Monolog not installed skipping.'
13
+ );
14
+ }
15
+ }
16
+
17
+ public function testMageLog()
18
+ {
19
+ $handler = new Ecocode_Profiler_Model_Logger_DebugHandler();
20
+ $logger = new Ecocode_Profiler_Model_Logger(__METHOD__, [$handler]);
21
+
22
+ $this->assertTrue($logger->mageLog(Zend_Log::ERR, 'error message'));
23
+ $logs = $logger->getLogs();
24
+
25
+ $this->assertCount(1, $logs);
26
+ $log = reset($logs);
27
+ $this->assertEquals(Ecocode_Profiler_Model_Logger::ERROR, $log['priority']);
28
+ }
29
+
30
+ public function testGetLogsWithDebugHandler()
31
+ {
32
+ $handler = new Ecocode_Profiler_Model_Logger_DebugHandler();
33
+ $logger = new Ecocode_Profiler_Model_Logger(__METHOD__, [$handler]);
34
+
35
+ $this->assertTrue($logger->error('error message'));
36
+ $this->assertSame(1, count($logger->getLogs()));
37
+ }
38
+
39
+ public function testGetLogsWithoutDebugHandler()
40
+ {
41
+ $handler = new TestHandler();
42
+ $logger = new Ecocode_Profiler_Model_Logger(__METHOD__, [$handler]);
43
+
44
+ $this->assertTrue($logger->error('error message'));
45
+ $this->assertSame([], $logger->getLogs());
46
+ }
47
+
48
+ public function testCountErrorsWithDebugHandler()
49
+ {
50
+ $handler = new Ecocode_Profiler_Model_Logger_DebugHandler();
51
+ $logger = new Ecocode_Profiler_Model_Logger(__METHOD__, [$handler]);
52
+
53
+ $this->assertTrue($logger->debug('test message'));
54
+ $this->assertTrue($logger->info('test message'));
55
+ $this->assertTrue($logger->notice('test message'));
56
+ $this->assertTrue($logger->warning('test message'));
57
+
58
+ $this->assertTrue($logger->error('test message'));
59
+ $this->assertTrue($logger->critical('test message'));
60
+ $this->assertTrue($logger->alert('test message'));
61
+ $this->assertTrue($logger->emergency('test message'));
62
+
63
+ $this->assertSame(4, $logger->countErrors());
64
+ }
65
+
66
+ public function testGetLogs()
67
+ {
68
+ $logger = new Ecocode_Profiler_Model_Logger('test');
69
+ $logger->pushHandler(new Ecocode_Profiler_Model_Logger_DebugHandler());
70
+
71
+ $logger->addInfo('test');
72
+ $this->assertCount(1, $logger->getLogs());
73
+ list($record) = $logger->getLogs();
74
+
75
+ $this->assertEquals('test', $record['message']);
76
+ $this->assertEquals(Ecocode_Profiler_Model_Logger::INFO, $record['priority']);
77
+ }
78
+
79
+ public function testCountErrorsWithoutDebugHandler()
80
+ {
81
+ $handler = new TestHandler();
82
+ $logger = new Ecocode_Profiler_Model_Logger(__METHOD__, [$handler]);
83
+
84
+ $this->assertTrue($logger->error('error message'));
85
+ $this->assertSame(0, $logger->countErrors());
86
+ }
87
+ }
app/code/community/Ecocode/Profiler/Tests/Dev/Model/Observer/ContextTest.php ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+
4
+ class Ecocode_Profiler_Tests_Dev_Model_Observer_ContextTest
5
+ extends TestHelper
6
+ {
7
+ protected $contextHelper;
8
+
9
+ protected function setUp()
10
+ {
11
+ parent::setUp();
12
+
13
+ /** @var Ecocode_Profiler_Helper_Context $contextHelper */
14
+ $this->contextHelper = $this->getMockBuilder('Ecocode_Profiler_Helper_Context')
15
+ ->getMock();
16
+ }
17
+
18
+
19
+ public function testOpenBlockContext()
20
+ {
21
+ /** @var Ecocode_Profiler_Model_Observer_Context $contextHelper */
22
+ $observer = $this->getMockBuilder('Ecocode_Profiler_Model_Observer_Context')
23
+ ->setMethods(['getHelper'])
24
+ ->getMock();
25
+
26
+ $observer->method('getHelper')->willReturn($this->contextHelper);
27
+
28
+ $block = new Mage_Core_Block_Template();
29
+ $block->setTemplate('test.phtml');
30
+ $eventObserver = $this->getObserver(['block' => $block]);
31
+
32
+ $this->contextHelper->expects($this->once())->method('open');
33
+ $observer->openBlockContext($eventObserver);
34
+
35
+ /** @var Ecocode_Profiler_Model_ContextInterface $context */
36
+ $context = $block->getData('__context');
37
+ $this->assertInstanceOf('Ecocode_Profiler_Model_ContextInterface', $context);
38
+
39
+ return $block;
40
+ }
41
+
42
+ /**
43
+ * @depends testOpenBlockContext
44
+ */
45
+ public function testCloseBlockContext(Mage_Core_Block_Template $block )
46
+ {
47
+ /** @var Ecocode_Profiler_Model_Observer_Context $contextHelper */
48
+ $observer = $this->getMockBuilder('Ecocode_Profiler_Model_Observer_Context')
49
+ ->setMethods(['getHelper'])
50
+ ->getMock();
51
+
52
+ $observer->method('getHelper')->willReturn($this->contextHelper);
53
+
54
+ $eventObserver = $this->getObserver(['block' => $block]);
55
+
56
+ $this->contextHelper->expects($this->once())->method('close');
57
+ $observer->closeBlockContext($eventObserver);
58
+
59
+ /** @var Ecocode_Profiler_Model_ContextInterface $context */
60
+ $contextData = $block->getData('__context')->getData();
61
+ $this->assertEquals('test.phtml', $contextData['template']);
62
+
63
+
64
+ return $block;
65
+ }
66
+ }
app/code/community/Ecocode/Profiler/Tests/Dev/Model/ObserverTest.php ADDED
@@ -0,0 +1,163 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+
4
+ class Ecocode_Profiler_Tests_Dev_Model_ObserverTest
5
+ extends TestHelper
6
+ {
7
+ protected function setUp()
8
+ {
9
+ parent::setUp();
10
+
11
+ /** @var Ecocode_Profiler_Helper_Context $contextHelper */
12
+ $this->contextHelper = $this->getMockBuilder('Ecocode_Profiler_Helper_Context')
13
+ ->getMock();
14
+ }
15
+
16
+
17
+ public function testControllerFrontSendResponseBefore()
18
+ {
19
+ /** @var Ecocode_Profiler_Model_Profiler $profiler */
20
+ $profiler = $this->getMockBuilder('Ecocode_Profiler_Model_Profiler')
21
+ ->setMethods(['saveProfile', 'collect'])
22
+ ->getMock();
23
+
24
+ $profiler->method('collect')
25
+ ->willReturn(new Ecocode_Profiler_Model_Profile('xxx'));
26
+
27
+
28
+ $profiler->disable();
29
+ $this->checkIfToolbarIsInjected($profiler);
30
+ $profiler->enable();
31
+ $observer = $this->checkIfToolbarIsInjected($profiler);
32
+
33
+ return $observer;
34
+ }
35
+
36
+ public function testLinkTokenHeader()
37
+ {
38
+ $profiler = $this->getMockBuilder('Ecocode_Profiler_Model_Profiler')
39
+ ->setMethods(['collect'])
40
+ ->getMock();
41
+
42
+ $frontController = $this->getMockBuilder('Mage_Core_Controller_Varien_Front')
43
+ ->setMethods(['getResponse'])
44
+ ->getMock();
45
+
46
+ $response = new Ecocode_Profiler_Tests_Dev_Fixtures_ResponseHttp();
47
+ $response->setHeader('X-Debug-Token', 'XXX');
48
+
49
+ $frontController->method('getResponse')->willReturn($response);
50
+
51
+ $eventObserver = $this->getObserver(['front' => $frontController]);
52
+
53
+ $observer = $this->getMockBuilder('Ecocode_Profiler_Model_Observer')
54
+ ->setMethods(['getProfiler', 'injectToolbar'])
55
+ ->getMock();
56
+
57
+
58
+ $observer->method('getProfiler')->willReturn($profiler);
59
+
60
+ $profiler->enable();
61
+ /** @var Ecocode_Profiler_Model_Observer $observer */
62
+ $observer->controllerFrontSendResponseBefore($eventObserver);
63
+
64
+ $headers = $response->getHeaders();
65
+ $tokenLinkHeader = false;
66
+ foreach ($headers as $header) {
67
+ if ($header['name'] === 'X-Debug-Token-Link') {
68
+ $tokenLinkHeader = $header;
69
+ break;
70
+ }
71
+ }
72
+ $this->assertNotFalse($tokenLinkHeader);
73
+ }
74
+
75
+ public function checkIfToolbarIsInjected(Ecocode_Profiler_Model_Profiler $profiler)
76
+ {
77
+ $frontController = $this->getMockBuilder('Mage_Core_Controller_Varien_Front')
78
+ ->setMethods(['getResponse'])
79
+ ->getMock();
80
+
81
+ $response = new Ecocode_Profiler_Tests_Dev_Fixtures_ResponseHttp();
82
+
83
+ $frontController->method('getResponse')->willReturn($response);
84
+
85
+ $eventObserver = $this->getObserver(['front' => $frontController]);
86
+
87
+ $observer = $this->getMockBuilder('Ecocode_Profiler_Model_Observer')
88
+ ->setMethods(['getProfiler', 'injectToolbar'])
89
+ ->getMock();
90
+
91
+
92
+ $observer->method('getProfiler')->willReturn($profiler);
93
+
94
+ if ($profiler->isEnabled()) {
95
+ $observer->expects($this->once())
96
+ ->method('injectToolbar');
97
+ } else {
98
+ $observer->expects($this->never())
99
+ ->method('injectToolbar');
100
+ }
101
+ /** @var Ecocode_Profiler_Model_Observer $observer */
102
+ $observer->controllerFrontSendResponseBefore($eventObserver);
103
+
104
+ return [$profiler, $observer];
105
+ }
106
+
107
+
108
+ /**
109
+ */
110
+ public function testOnTerminate()
111
+ {
112
+ $observer = $this->getMockBuilder('Ecocode_Profiler_Model_Observer')
113
+ ->setMethods(['getProfiler'])
114
+ ->getMock();
115
+
116
+ $profilesProperty = new ReflectionProperty('Ecocode_Profiler_Model_Observer', 'profiles');
117
+ $profilesProperty->setAccessible(true);
118
+
119
+ $profile = new Ecocode_Profiler_Model_Profile('token');
120
+
121
+ $request = new Mage_Core_Controller_Request_Http();
122
+ $storage = $profilesProperty->getValue($observer);
123
+ $storage[$request] = $profile;
124
+
125
+
126
+ $profiler = $this->getMockBuilder('Ecocode_Profiler_Model_Profiler')
127
+ ->setMethods(['saveProfile'])
128
+ ->getMock();
129
+
130
+ $observer->method('getProfiler')->willReturn($profiler);
131
+
132
+ $profiler->expects($this->once())
133
+ ->method('saveProfile');
134
+
135
+ $observer->onTerminate($this->getObserver([]));
136
+ }
137
+
138
+
139
+ public function testInjectToolbar()
140
+ {
141
+ $layout = new Mage_Core_Model_Layout();
142
+ $observer = $this->getMockBuilder('Ecocode_Profiler_Model_Observer')
143
+ ->setMethods(['getLayout'])
144
+ ->getMock();
145
+
146
+ $observer->method('getLayout')->willReturn($layout);
147
+
148
+ $injectToolbarMethod = new ReflectionMethod('Ecocode_Profiler_Model_Observer', 'injectToolbar');
149
+ $injectToolbarMethod->setAccessible(true);
150
+
151
+ $request = new Mage_Core_Controller_Request_Http();
152
+ $response = new Ecocode_Profiler_Tests_Dev_Fixtures_ResponseHttp();
153
+ $response->setBody('<html><body>Some Content</body></html>');
154
+
155
+ $injectToolbarMethod->invoke($observer, $response, $request);
156
+
157
+ $this->assertContains('Some Content', $response->getBody());
158
+ $this->assertContains('<!-- START of ecocode Web Debug Toolbar -->', $response->getBody());
159
+
160
+ $this->assertNotFalse($layout->getBlock('profiler_toolbar'));
161
+ $this->assertNotFalse($layout->getBlock('profiler_base_js'));
162
+ }
163
+ }
app/code/community/Ecocode/Profiler/Tests/Dev/Model/Overwrite/MageCoreModelResourceDbAbstractTest.php ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Ecocode_Profiler_Tests_Dev_Model_Overwrite_MageCoreModelResourceDbAbstract
4
+ extends TestHelper
5
+ {
6
+ public function testLoad()
7
+ {
8
+ $testData = ['a' => 'b'];
9
+ $readAdapter = $this->getMockBuilder('Magento_Db_Adapter_Pdo_Mysql')
10
+ ->disableOriginalConstructor()
11
+ ->setMethods(['fetchRow'])
12
+ ->getMock();
13
+
14
+ $readAdapter->method('fetchRow')->willReturn($testData);
15
+
16
+ $resourceLog = $this->getMockBuilder('Mage_Log_Model_Resource_Log')
17
+ ->setMethods(['dispatch', '_getReadAdapter', '_getLoadSelect', 'unserializeFields', '_afterLoad'])
18
+ ->getMock();
19
+
20
+ $resourceLog->method('_getReadAdapter')->willReturn($readAdapter);
21
+
22
+ $visitor = new Mage_Log_Model_Visitor();
23
+
24
+
25
+ $resourceLog->expects($this->once())
26
+ ->method('dispatch')
27
+ ->with(
28
+ $this->equalTo('model_resource_db_load'),
29
+ $this->callback(function ($subject) use ($visitor) {
30
+ return $subject['object'] === $visitor && isset($subject['time']);
31
+ })
32
+ );
33
+
34
+
35
+ $resourceLog->load($visitor, 1);
36
+ }
37
+
38
+ public function testSave()
39
+ {
40
+ $writeAdapter = $this->getMockBuilder('Magento_Db_Adapter_Pdo_Mysql')
41
+ ->disableOriginalConstructor()
42
+ ->setMethods(['insert', 'lastInsertId'])
43
+ ->getMock();
44
+
45
+
46
+ $resourceLog = $this->getMockBuilder('Mage_Log_Model_Resource_Log')
47
+ ->setMethods([
48
+ 'dispatch', '_serializeFields', '_getWriteAdapter',
49
+ '_beforeSave', '_checkUnique', '_prepareDataForSave',
50
+ 'getIdFieldName', 'unserializeFields', 'afterSave'])
51
+ ->getMock();
52
+
53
+ $resourceLog->method('_getWriteAdapter')->willReturn($writeAdapter);
54
+ $resourceLog->method('getIdFieldName')->willReturn('id');
55
+ $resourceLog->method('_prepareDataForSave')->willReturn([]);
56
+
57
+
58
+ $visitor = new Mage_Log_Model_Visitor();
59
+ $resourceLog->expects($this->once())
60
+ ->method('dispatch')
61
+ ->with(
62
+ $this->equalTo('model_resource_db_save'),
63
+ $this->callback(function ($subject) use ($visitor) {
64
+ return $subject['object'] === $visitor && isset($subject['time']);
65
+ })
66
+ );
67
+
68
+
69
+ $resourceLog->save($visitor, 1);
70
+ }
71
+
72
+ public function testSaveDeleted()
73
+ {
74
+ $resourceLog = $this->getMockBuilder('Mage_Log_Model_Resource_Log')
75
+ ->setMethods(['dispatch', 'delete'])
76
+ ->getMock();
77
+
78
+ $visitor = new Mage_Log_Model_Visitor();
79
+ $visitor->isDeleted(true);
80
+ $resourceLog->expects($this->never())
81
+ ->method('dispatch');
82
+
83
+ $resourceLog->save($visitor, 1);
84
+ }
85
+
86
+ public function testDelete()
87
+ {
88
+ $writeAdapter = $this->getMockBuilder('Magento_Db_Adapter_Pdo_Mysql')
89
+ ->disableOriginalConstructor()
90
+ ->setMethods(['delete', 'quoteInto'])
91
+ ->getMock();
92
+
93
+
94
+ $resourceLog = $this->getMockBuilder('Mage_Log_Model_Resource_Log')
95
+ ->setMethods([
96
+ 'dispatch', '_beforeDelete',
97
+ 'getMainTable', '_getWriteAdapter',
98
+ '_afterDelete'])
99
+ ->getMock();
100
+
101
+ $resourceLog->method('_getWriteAdapter')->willReturn($writeAdapter);
102
+
103
+
104
+ $visitor = new Mage_Log_Model_Visitor();
105
+
106
+ $resourceLog->expects($this->once())
107
+ ->method('dispatch')
108
+ ->with(
109
+ $this->equalTo('model_resource_db_delete'),
110
+ $this->callback(function ($subject) use ($visitor) {
111
+ return $subject['object'] === $visitor && isset($subject['time']);
112
+ })
113
+ );
114
+
115
+
116
+ $resourceLog->delete($visitor, 1);
117
+ }
118
+ }
app/code/community/Ecocode/Profiler/Tests/Dev/Model/Overwrite/MageCoreModelResourceTest.php ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Ecocode_Profiler_Tests_Dev_Model_Overwrite_MageCoreModelResourceTest
4
+ extends TestHelper
5
+ {
6
+
7
+
8
+ public function testGetConnection()
9
+ {
10
+ $configProperty = new ReflectionProperty('Varien_Db_Adapter_Pdo_Mysql', '_config');
11
+ $configProperty->setAccessible(true);
12
+
13
+ $resource = new Mage_Core_Model_Resource();
14
+
15
+
16
+ /** @var Varien_Db_Adapter_Pdo_Mysql $connection */
17
+ $connection = $resource->getConnection('core_read');
18
+
19
+ $this->assertEquals(
20
+ 'Ecocode_Profiler_Db_Statement_Pdo_Mysql',
21
+ $connection->getStatementClass()
22
+ );
23
+
24
+
25
+ $connectionConfig = $configProperty->getValue($connection);
26
+ $this->assertEquals('core_read', $connectionConfig['connection_name']);
27
+
28
+ }
29
+ }
app/code/community/Ecocode/Profiler/Tests/Dev/Model/Overwrite/MageCoreModelTranslateTest.php ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Ecocode_Profiler_Tests_Dev_Model_Overwrite_MageCoreModelTranslateTest
4
+ extends TestHelper
5
+ {
6
+ public function testTranslatedString()
7
+ {
8
+ $translate = new Mage_Core_Model_Translate();
9
+
10
+
11
+ $this->addTranslations($translate, [
12
+ 'test' => 'test-core'
13
+ ], 'Mage_Core');
14
+
15
+ $this->addTranslations($translate, [
16
+ 'test' => 'test-page',
17
+ 'test %' => 'test-page %s',
18
+ ], 'Mage_Page');
19
+
20
+
21
+ $this->assertTranslation($translate, 'test-core', 'test', 'none');
22
+ $this->assertTranslation($translate, 'test-core', 'test', 'Mage_Core');
23
+ $this->assertTranslation($translate, 'test-page', 'test', 'Mage_Page');
24
+ $this->assertTranslation($translate, 'test-untranslated', 'test-untranslated', 'Mage_Page');
25
+ $this->assertTranslation($translate, 'test %s', 'test %s', 'Mage_Page');
26
+ $this->assertTranslation($translate, 'test-page asd', 'test %', 'Mage_Page', ['asd']);
27
+
28
+ $stats = [];
29
+ foreach ($translate->getMessages() as $message) {
30
+ if (!isset($stats[$message['state']])) {
31
+ $stats[$message['state']] = 0;
32
+ }
33
+ $stats[$message['state']]++;
34
+ }
35
+
36
+ $this->assertEquals(3, $stats[Mage_Core_Model_Translate::STATE_TRANSLATED]);
37
+ $this->assertEquals(1, $stats[Mage_Core_Model_Translate::STATE_FALLBACK]);
38
+ $this->assertEquals(1, $stats[Mage_Core_Model_Translate::STATE_MISSING]);
39
+ $this->assertEquals(1, $stats[Mage_Core_Model_Translate::STATE_INVALID]);
40
+ }
41
+
42
+ protected function assertTranslation(Mage_Core_Model_Translate $translate, $expect, $key, $module, array $params = [])
43
+ {
44
+ $this->assertEquals($expect, $this->__($translate, $key, $module, $params));
45
+ }
46
+
47
+ protected function __(Mage_Core_Model_Translate $translate, $key, $module, array $params = [])
48
+ {
49
+ $expr = new Mage_Core_Model_Translate_Expr($key, $module);
50
+
51
+ $args = $params;
52
+ array_unshift($args, $expr);
53
+ return $translate->translate($args);
54
+ }
55
+
56
+
57
+ protected function addTranslations($translate, $data, $scope)
58
+ {
59
+ $addDataMethod = new ReflectionMethod('Mage_Core_Model_Translate', '_addData');
60
+ $addDataMethod->setAccessible(true);
61
+
62
+ $addDataMethod->invoke($translate, $data, $scope);
63
+
64
+ return $translate;
65
+ }
66
+ }
app/code/community/Ecocode/Profiler/Tests/Dev/Model/Overwrite/MageEavModelEntityAbstractTest.php ADDED
@@ -0,0 +1,111 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Ecocode_Profiler_Tests_Dev_Model_Overwrite_MageEavModelEntityAbstractTest
4
+ extends TestHelper
5
+ {
6
+ public function testLoad()
7
+ {
8
+ $testData = ['a' => 'b'];
9
+ $readAdapter = $this->getMockBuilder('Magento_Db_Adapter_Pdo_Mysql')
10
+ ->disableOriginalConstructor()
11
+ ->setMethods(['fetchRow'])
12
+ ->getMock();
13
+
14
+ $readAdapter->method('fetchRow')->willReturn($testData);
15
+
16
+ $entityAbstract = $this->getMockBuilder('Mage_Eav_Model_Entity_Abstract')
17
+ ->setMethods(['dispatch', '_getReadAdapter', '_getLoadRowSelect', 'loadAllAttributes'])
18
+ ->getMock();
19
+
20
+ $entityAbstract->method('_getReadAdapter')->willReturn($readAdapter);
21
+
22
+ $product = new Mage_Catalog_Model_Product();
23
+
24
+
25
+ $entityAbstract->expects($this->once())
26
+ ->method('dispatch')
27
+ ->with(
28
+ $this->equalTo('model_resource_db_load'),
29
+ $this->callback(function($subject) use ($product) {
30
+ return $subject['object'] === $product && isset($subject['time']);
31
+ })
32
+ );
33
+
34
+
35
+ $entityAbstract->load($product, 1);
36
+ }
37
+
38
+ public function testSave()
39
+ {
40
+ $entityAbstract = $this->getMockBuilder('Mage_Eav_Model_Entity_Abstract')
41
+ ->setMethods(['dispatch', 'loadAllAttributes', '_beforeSave', '_processSaveData', '_collectSaveData', '_afterSave'])
42
+ ->getMock();
43
+
44
+ $product = new Mage_Catalog_Model_Product();
45
+ $product->setData('entity_type_id', 1);
46
+
47
+ $entityAbstract->expects($this->once())
48
+ ->method('dispatch')
49
+ ->with(
50
+ $this->equalTo('model_resource_db_save'),
51
+ $this->callback(function($subject) use ($product) {
52
+ return $subject['object'] === $product && isset($subject['time']);
53
+ })
54
+ );
55
+
56
+
57
+ $entityAbstract->save($product, 1);
58
+ }
59
+
60
+ public function testSaveDeleted()
61
+ {
62
+ $entityAbstract = $this->getMockBuilder('Mage_Eav_Model_Entity_Abstract')
63
+ ->setMethods(['dispatch', 'delete', 'loadAllAttributes', '_beforeSave', '_processSaveData', '_collectSaveData', '_afterSave'])
64
+ ->getMock();
65
+
66
+ $product = new Mage_Catalog_Model_Product();
67
+ $product->setData('entity_type_id', 1);
68
+ $product->isDeleted(true);
69
+ $entityAbstract->expects($this->never())
70
+ ->method('dispatch');
71
+
72
+
73
+ $entityAbstract->save($product, 1);
74
+ }
75
+
76
+ public function testDelete()
77
+ {
78
+ $writeAdapter = $this->getMockBuilder('Magento_Db_Adapter_Pdo_Mysql')
79
+ ->disableOriginalConstructor()
80
+ ->setMethods(['delete'])
81
+ ->getMock();
82
+
83
+
84
+ $entityAbstract = $this->getMockBuilder('Mage_Eav_Model_Entity_Abstract')
85
+ ->setMethods([
86
+ 'dispatch', '_beforeDelete',
87
+ 'getEntityIdField', '_getWriteAdapter',
88
+ 'getEntityTable', 'loadAllAttributes', '_afterDelete'])
89
+ ->getMock();
90
+
91
+ $entityAbstract->method('_getWriteAdapter')->willReturn($writeAdapter);
92
+ $entityAbstract->method('getEntityIdField')->willReturn('id');
93
+
94
+
95
+ $product = new Mage_Catalog_Model_Product();
96
+ $product->setData('entity_type_id', 1);
97
+
98
+ $entityAbstract->expects($this->once())
99
+ ->method('dispatch')
100
+ ->with(
101
+ $this->equalTo('model_resource_db_delete'),
102
+ $this->callback(function($subject) use ($product) {
103
+ return $subject['object'] === $product && isset($subject['time']);
104
+ })
105
+ );
106
+
107
+
108
+
109
+ $entityAbstract->delete($product, 1);
110
+ }
111
+ }
app/code/community/Ecocode/Profiler/Tests/Dev/Model/Overwrite/MageTest.php ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+
4
+ class Ecocode_Profiler_Tests_Dev_Model_Overwrite_MageTest
5
+ extends TestHelper
6
+ {
7
+ public function testGetLogger()
8
+ {
9
+ if (!class_exists('Monolog\Handler\TestHandler')) {
10
+ $this->markTestSkipped(
11
+ 'Monolog not installed skipping.'
12
+ );
13
+ }
14
+ $logger = Mage::getLogger();
15
+
16
+ $this->assertInstanceOf('Ecocode_Profiler_Model_Logger', $logger);
17
+ $this->assertEquals(Mage::getDefaultLogger(), $logger);
18
+
19
+ $this->assertNotEquals(Mage::getDefaultLogger(), Mage::getLogger('new'));
20
+ }
21
+
22
+ public function testLog()
23
+ {
24
+ if (!class_exists('Monolog\Handler\TestHandler')) {
25
+ $this->markTestSkipped(
26
+ 'Monolog not installed skipping.'
27
+ );
28
+ }
29
+ $logger = Mage::getLogger();
30
+
31
+ $this->assertCount(0, $logger->getLogs());
32
+
33
+ Mage::log('test');
34
+ Mage::log('test', Zend_Log::ALERT, 'error.log');
35
+
36
+ $logs = $logger->getLogs();
37
+ $this->assertCount(2, $logs);
38
+ $lastLog = end($logs);
39
+
40
+ $this->assertEquals(Ecocode_Profiler_Model_Logger::ALERT, $lastLog['priority']);
41
+ $this->assertEquals('error', $lastLog['channel']);
42
+ }
43
+ }
app/code/community/Ecocode/Profiler/Tests/Dev/Model/Profiler/FileStorageTest.php ADDED
@@ -0,0 +1,346 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+
13
+ class Ecocode_Profiler_Tests_Dev_Model_Profiler_FileStorageTest
14
+ extends \TestHelper
15
+ {
16
+ private $tmpDir;
17
+ private $storage;
18
+
19
+ protected function setUp()
20
+ {
21
+ $this->tmpDir = sys_get_temp_dir() . '/sf2_profiler_file_storage';
22
+ if (is_dir($this->tmpDir)) {
23
+ self::cleanDir();
24
+ }
25
+ $this->storage = new Ecocode_Profiler_Model_Profiler_FileStorage(['dsn' => 'file:' . $this->tmpDir]);
26
+ $this->storage->purge();
27
+ }
28
+
29
+ protected function tearDown()
30
+ {
31
+ self::cleanDir();
32
+ }
33
+
34
+ public function testStore()
35
+ {
36
+ for ($i = 0; $i < 10; ++$i) {
37
+ $profile = new Ecocode_Profiler_Model_Profile('token_' . $i);
38
+ $profile->setIp('127.0.0.1');
39
+ $profile->setUrl('http://foo.bar');
40
+ $profile->setMethod('GET');
41
+ $this->storage->write($profile);
42
+ }
43
+ $this->assertCount(10, $this->storage->find('127.0.0.1', 'http://foo.bar', 20, 'GET'), '->write() stores data in the storage');
44
+ }
45
+
46
+ public function testChildren()
47
+ {
48
+ $parentProfile = new Ecocode_Profiler_Model_Profile('token_parent');
49
+ $parentProfile->setIp('127.0.0.1');
50
+ $parentProfile->setUrl('http://foo.bar/parent');
51
+
52
+ $childProfile = new Ecocode_Profiler_Model_Profile('token_child');
53
+ $childProfile->setIp('127.0.0.1');
54
+ $childProfile->setUrl('http://foo.bar/child');
55
+
56
+ $parentProfile->addChild($childProfile);
57
+
58
+ $this->storage->write($parentProfile);
59
+ $this->storage->write($childProfile);
60
+
61
+ // Load them from storage
62
+ $parentProfile = $this->storage->read('token_parent');
63
+ $childProfile = $this->storage->read('token_child');
64
+
65
+ // Check child has link to parent
66
+ $this->assertNotNull($childProfile->getParent());
67
+ $this->assertEquals($parentProfile->getToken(), $childProfile->getParentToken());
68
+
69
+ // Check parent has child
70
+ $children = $parentProfile->getChildren();
71
+ $this->assertCount(1, $children);
72
+ $this->assertEquals($childProfile->getToken(), $children[0]->getToken());
73
+ }
74
+
75
+ public function testStoreSpecialCharsInUrl()
76
+ {
77
+ // The storage accepts special characters in URLs (Even though URLs are not
78
+ // supposed to contain them)
79
+ $profile = new Ecocode_Profiler_Model_Profile('simple_quote');
80
+ $profile->setUrl('http://foo.bar/\'');
81
+ $this->storage->write($profile);
82
+ $this->assertTrue(false !== $this->storage->read('simple_quote'), '->write() accepts single quotes in URL');
83
+
84
+ $profile = new Ecocode_Profiler_Model_Profile('double_quote');
85
+ $profile->setUrl('http://foo.bar/"');
86
+ $this->storage->write($profile);
87
+ $this->assertTrue(false !== $this->storage->read('double_quote'), '->write() accepts double quotes in URL');
88
+
89
+ $profile = new Ecocode_Profiler_Model_Profile('backslash');
90
+ $profile->setUrl('http://foo.bar/\\');
91
+ $this->storage->write($profile);
92
+ $this->assertTrue(false !== $this->storage->read('backslash'), '->write() accepts backslash in URL');
93
+
94
+ $profile = new Ecocode_Profiler_Model_Profile('comma');
95
+ $profile->setUrl('http://foo.bar/,');
96
+ $this->storage->write($profile);
97
+ $this->assertTrue(false !== $this->storage->read('comma'), '->write() accepts comma in URL');
98
+ }
99
+
100
+ public function testStoreDuplicateToken()
101
+ {
102
+ $profile = new Ecocode_Profiler_Model_Profile('token');
103
+ $profile->setUrl('http://example.com/');
104
+
105
+ $this->assertTrue($this->storage->write($profile), '->write() returns true when the token is unique');
106
+
107
+ $profile->setUrl('http://example.net/');
108
+
109
+ $this->assertTrue($this->storage->write($profile), '->write() returns true when the token is already present in the storage');
110
+ $this->assertEquals('http://example.net/', $this->storage->read('token')->getUrl(), '->write() overwrites the current profile data');
111
+
112
+ $this->assertCount(1, $this->storage->find('', '', 1000, ''), '->find() does not return the same profile twice');
113
+ }
114
+
115
+ public function testRetrieveByIp()
116
+ {
117
+ $profile = new Ecocode_Profiler_Model_Profile('token');
118
+ $profile->setIp('127.0.0.1');
119
+ $profile->setMethod('GET');
120
+ $this->storage->write($profile);
121
+
122
+ $this->assertCount(1, $this->storage->find('127.0.0.1', '', 10, 'GET'), '->find() retrieve a record by IP');
123
+ $this->assertCount(0, $this->storage->find('127.0.%.1', '', 10, 'GET'), '->find() does not interpret a "%" as a wildcard in the IP');
124
+ $this->assertCount(0, $this->storage->find('127.0._.1', '', 10, 'GET'), '->find() does not interpret a "_" as a wildcard in the IP');
125
+ }
126
+
127
+ public function testRetrieveByStatusCode()
128
+ {
129
+ $profile200 = new Ecocode_Profiler_Model_Profile('statuscode200');
130
+ $profile200->setStatusCode(200);
131
+ $this->storage->write($profile200);
132
+
133
+ $profile404 = new Ecocode_Profiler_Model_Profile('statuscode404');
134
+ $profile404->setStatusCode(404);
135
+ $this->storage->write($profile404);
136
+
137
+ $this->assertCount(1, $this->storage->find(null, null, 10, null, null, null, '200'), '->find() retrieve a record by Status code 200');
138
+ $this->assertCount(1, $this->storage->find(null, null, 10, null, null, null, '404'), '->find() retrieve a record by Status code 404');
139
+ }
140
+
141
+ public function testRetrieveByUrl()
142
+ {
143
+ $profile = new Ecocode_Profiler_Model_Profile('simple_quote');
144
+ $profile->setIp('127.0.0.1');
145
+ $profile->setUrl('http://foo.bar/\'');
146
+ $profile->setMethod('GET');
147
+ $this->storage->write($profile);
148
+
149
+ $profile = new Ecocode_Profiler_Model_Profile('double_quote');
150
+ $profile->setIp('127.0.0.1');
151
+ $profile->setUrl('http://foo.bar/"');
152
+ $profile->setMethod('GET');
153
+ $this->storage->write($profile);
154
+
155
+ $profile = new Ecocode_Profiler_Model_Profile('backslash');
156
+ $profile->setIp('127.0.0.1');
157
+ $profile->setUrl('http://foo\\bar/');
158
+ $profile->setMethod('GET');
159
+ $this->storage->write($profile);
160
+
161
+ $profile = new Ecocode_Profiler_Model_Profile('percent');
162
+ $profile->setIp('127.0.0.1');
163
+ $profile->setUrl('http://foo.bar/%');
164
+ $profile->setMethod('GET');
165
+ $this->storage->write($profile);
166
+
167
+ $profile = new Ecocode_Profiler_Model_Profile('underscore');
168
+ $profile->setIp('127.0.0.1');
169
+ $profile->setUrl('http://foo.bar/_');
170
+ $profile->setMethod('GET');
171
+ $this->storage->write($profile);
172
+
173
+ $profile = new Ecocode_Profiler_Model_Profile('semicolon');
174
+ $profile->setIp('127.0.0.1');
175
+ $profile->setUrl('http://foo.bar/;');
176
+ $profile->setMethod('GET');
177
+ $this->storage->write($profile);
178
+
179
+ $this->assertCount(1, $this->storage->find('127.0.0.1', 'http://foo.bar/\'', 10, 'GET'), '->find() accepts single quotes in URLs');
180
+ $this->assertCount(1, $this->storage->find('127.0.0.1', 'http://foo.bar/"', 10, 'GET'), '->find() accepts double quotes in URLs');
181
+ $this->assertCount(1, $this->storage->find('127.0.0.1', 'http://foo\\bar/', 10, 'GET'), '->find() accepts backslash in URLs');
182
+ $this->assertCount(1, $this->storage->find('127.0.0.1', 'http://foo.bar/;', 10, 'GET'), '->find() accepts semicolon in URLs');
183
+ $this->assertCount(1, $this->storage->find('127.0.0.1', 'http://foo.bar/%', 10, 'GET'), '->find() does not interpret a "%" as a wildcard in the URL');
184
+ $this->assertCount(1, $this->storage->find('127.0.0.1', 'http://foo.bar/_', 10, 'GET'), '->find() does not interpret a "_" as a wildcard in the URL');
185
+ }
186
+
187
+ public function testStoreTime()
188
+ {
189
+ $dt = new \DateTime('now');
190
+ $start = $dt->getTimestamp();
191
+
192
+ for ($i = 0; $i < 3; ++$i) {
193
+ $dt->modify('+1 minute');
194
+ $profile = new Ecocode_Profiler_Model_Profile('time_' . $i);
195
+ $profile->setIp('127.0.0.1');
196
+ $profile->setUrl('http://foo.bar');
197
+ $profile->setTime($dt->getTimestamp());
198
+ $profile->setMethod('GET');
199
+ $this->storage->write($profile);
200
+ }
201
+
202
+ $records = $this->storage->find('', '', 3, 'GET', $start, time() + 3 * 60);
203
+ $this->assertCount(3, $records, '->find() returns all previously added records');
204
+ $this->assertEquals($records[0]['token'], 'time_2', '->find() returns records ordered by time in descendant order');
205
+ $this->assertEquals($records[1]['token'], 'time_1', '->find() returns records ordered by time in descendant order');
206
+ $this->assertEquals($records[2]['token'], 'time_0', '->find() returns records ordered by time in descendant order');
207
+
208
+ $records = $this->storage->find('', '', 3, 'GET', $start, time() + 2 * 60);
209
+ $this->assertCount(2, $records, '->find() should return only first two of the previously added records');
210
+ }
211
+
212
+ public function testRetrieveByEmptyUrlAndIp()
213
+ {
214
+ for ($i = 0; $i < 5; ++$i) {
215
+ $profile = new Ecocode_Profiler_Model_Profile('token_' . $i);
216
+ $profile->setMethod('GET');
217
+ $this->storage->write($profile);
218
+ }
219
+ $this->assertCount(5, $this->storage->find('', '', 10, 'GET'), '->find() returns all previously added records');
220
+ $this->storage->purge();
221
+ }
222
+
223
+ public function testRetrieveByMethodAndLimit()
224
+ {
225
+ foreach (['POST', 'GET'] as $method) {
226
+ for ($i = 0; $i < 5; ++$i) {
227
+ $profile = new Ecocode_Profiler_Model_Profile('token_' . $i . $method);
228
+ $profile->setMethod($method);
229
+ $this->storage->write($profile);
230
+ }
231
+ }
232
+
233
+ $this->assertCount(5, $this->storage->find('', '', 5, 'POST'));
234
+
235
+ $this->storage->purge();
236
+ }
237
+
238
+ public function testPurge()
239
+ {
240
+ $profile = new Ecocode_Profiler_Model_Profile('token1');
241
+ $profile->setIp('127.0.0.1');
242
+ $profile->setUrl('http://example.com/');
243
+ $profile->setMethod('GET');
244
+ $this->storage->write($profile);
245
+
246
+ $this->assertTrue(false !== $this->storage->read('token1'));
247
+ $this->assertCount(1, $this->storage->find('127.0.0.1', '', 10, 'GET'));
248
+
249
+ $profile = new Ecocode_Profiler_Model_Profile('token2');
250
+ $profile->setIp('127.0.0.1');
251
+ $profile->setUrl('http://example.net/');
252
+ $profile->setMethod('GET');
253
+ $this->storage->write($profile);
254
+
255
+ $this->assertTrue(false !== $this->storage->read('token2'));
256
+ $this->assertCount(2, $this->storage->find('127.0.0.1', '', 10, 'GET'));
257
+
258
+ $this->storage->purge();
259
+
260
+ $this->assertEmpty($this->storage->read('token'), '->purge() removes all data stored by profiler');
261
+ $this->assertCount(0, $this->storage->find('127.0.0.1', '', 10, 'GET'), '->purge() removes all items from index');
262
+ }
263
+
264
+ public function testDuplicates()
265
+ {
266
+ for ($i = 1; $i <= 5; ++$i) {
267
+ $profile = new Ecocode_Profiler_Model_Profile('foo' . $i);
268
+ $profile->setIp('127.0.0.1');
269
+ $profile->setUrl('http://example.net/');
270
+ $profile->setMethod('GET');
271
+
272
+ ///three duplicates
273
+ $this->storage->write($profile);
274
+ $this->storage->write($profile);
275
+ $this->storage->write($profile);
276
+ }
277
+ $this->assertCount(3, $this->storage->find('127.0.0.1', 'http://example.net/', 3, 'GET'), '->find() method returns incorrect number of entries');
278
+ }
279
+
280
+ public function testStatusCode()
281
+ {
282
+ $profile = new Ecocode_Profiler_Model_Profile('token1');
283
+ $profile->setStatusCode(200);
284
+ $this->storage->write($profile);
285
+
286
+ $profile = new Ecocode_Profiler_Model_Profile('token2');
287
+ $profile->setStatusCode(404);
288
+ $this->storage->write($profile);
289
+
290
+ $tokens = $this->storage->find('', '', 10, '');
291
+ $this->assertCount(2, $tokens);
292
+ $this->assertContains($tokens[0]['status_code'], [200, 404]);
293
+ $this->assertContains($tokens[1]['status_code'], [200, 404]);
294
+ }
295
+
296
+ public function testMultiRowIndexFile()
297
+ {
298
+ $iteration = 3;
299
+ for ($i = 0; $i < $iteration; ++$i) {
300
+ $profile = new Ecocode_Profiler_Model_Profile('token' . $i);
301
+ $profile->setIp('127.0.0.' . $i);
302
+ $profile->setUrl('http://foo.bar/' . $i);
303
+
304
+ $this->storage->write($profile);
305
+ $this->storage->write($profile);
306
+ $this->storage->write($profile);
307
+ }
308
+
309
+ $handle = fopen($this->tmpDir . '/index.csv', 'r');
310
+ for ($i = 0; $i < $iteration; ++$i) {
311
+ $row = fgetcsv($handle);
312
+ $this->assertEquals('token' . $i, $row[0]);
313
+ $this->assertEquals('127.0.0.' . $i, $row[1]);
314
+ $this->assertEquals('http://foo.bar/' . $i, $row[3]);
315
+ }
316
+ $this->assertFalse(fgetcsv($handle));
317
+ }
318
+
319
+ public function testReadLineFromFile()
320
+ {
321
+ $r = new \ReflectionMethod($this->storage, 'readLineFromFile');
322
+
323
+ $r->setAccessible(true);
324
+
325
+ $h = tmpfile();
326
+
327
+ fwrite($h, "line1\n\n\nline2\n");
328
+ fseek($h, 0, SEEK_END);
329
+
330
+ $this->assertEquals('line2', $r->invoke($this->storage, $h));
331
+ $this->assertEquals('line1', $r->invoke($this->storage, $h));
332
+ }
333
+
334
+ protected function cleanDir()
335
+ {
336
+ $flags = \FilesystemIterator::SKIP_DOTS;
337
+ $iterator = new \RecursiveDirectoryIterator($this->tmpDir, $flags);
338
+ $iterator = new \RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::SELF_FIRST);
339
+
340
+ foreach ($iterator as $file) {
341
+ if (is_file($file)) {
342
+ unlink($file);
343
+ }
344
+ }
345
+ }
346
+ }
app/code/community/Ecocode/Profiler/Tests/Dev/Model/ProfilerTest.php ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+
4
+ class Ecocode_Profiler_Tests_Dev_Model_ProfilerTest extends TestHelper
5
+ {
6
+ private $tmp;
7
+ /** @var Ecocode_Profiler_Model_Profiler_FileStorage */
8
+ private $storage;
9
+
10
+ public function testFindWorksWithDates()
11
+ {
12
+ $profiler = new Ecocode_Profiler_Model_Profiler($this->storage);
13
+
14
+ $this->assertCount(0, $profiler->find(null, null, null, null, '7th April 2014', '9th April 2014'));
15
+ }
16
+
17
+ public function testFindWorksWithTimestamps()
18
+ {
19
+ $profiler = new Ecocode_Profiler_Model_Profiler($this->storage);
20
+
21
+ $this->assertCount(0, $profiler->find(null, null, null, null, '1396828800', '1397001600'));
22
+ }
23
+
24
+ public function testFindWorksWithInvalidDates()
25
+ {
26
+ $profiler = new Ecocode_Profiler_Model_Profiler($this->storage);
27
+
28
+ $this->assertCount(0, $profiler->find(null, null, null, null, 'some string', ''));
29
+ }
30
+
31
+ public function testFindWorksWithStatusCode()
32
+ {
33
+ $profiler = new Ecocode_Profiler_Model_Profiler($this->storage);
34
+
35
+ $this->assertCount(0, $profiler->find(null, null, null, null, null, null, '204'));
36
+ }
37
+
38
+ protected function setUp()
39
+ {
40
+ $this->tmp = tempnam(sys_get_temp_dir(), 'sf2_profiler');
41
+ if (file_exists($this->tmp)) {
42
+ @unlink($this->tmp);
43
+ }
44
+
45
+ $this->storage = new Ecocode_Profiler_Model_Profiler_FileStorage(['dsn' => 'file:' . $this->tmp]);
46
+ $this->storage->purge();
47
+ }
48
+
49
+ protected function tearDown()
50
+ {
51
+ if (null !== $this->storage) {
52
+ $this->storage->purge();
53
+ $this->storage = null;
54
+
55
+ @unlink($this->tmp);
56
+ }
57
+ }
58
+ }
app/code/community/Ecocode/Profiler/Tests/Dev/bootstrap.php ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if (isset($_SERVER['MAGENTO_DIRECTORY'])) {
4
+ $_baseDir = $_SERVER['MAGENTO_DIRECTORY'];
5
+ } else {
6
+ $_baseDir = getcwd();
7
+ }
8
+
9
+ /**
10
+ * Define MAGE_PATH
11
+ * Path to Magento
12
+ */
13
+ define('MAGENTO_ROOT', $_baseDir);
14
+
15
+ // Include Mage file by detecting app root
16
+ require_once $_baseDir . DIRECTORY_SEPARATOR . 'app' . DIRECTORY_SEPARATOR . 'MageDev.php';
17
+
18
+ if (!Mage::isInstalled()) {
19
+ throw new RuntimeException('Magento Unit Tests can run only on installed version');
20
+ }
21
+
22
+
23
+ /* Replace server variables for proper file naming */
24
+ $_SERVER['SCRIPT_NAME'] = $_baseDir . DS . 'index.php';
25
+ $_SERVER['SCRIPT_FILENAME'] = $_baseDir . DS . 'index.php';
26
+
27
+ //fill the session to prevent session_start issues
28
+ $_SESSION = ['x' => 'y'];
29
+
30
+ //flag to check for unittets
31
+ define('BASE_TESTS_PATH', realpath(dirname(__FILE__)));
32
+ require_once BASE_TESTS_PATH . '/../TestHelper.php';
33
+
34
+ $options = [
35
+ 'cache' => ['id_prefix' => 'test-dev'],
36
+ 'config_model' => 'Ecocode_Profiler_Model_Core_Config'
37
+ ];
38
+ Mage::app('', 'store', $options);
39
+
40
+ // Removing Varien Autoload, to prevent errors with PHPUnit components
41
+ spl_autoload_unregister([\Varien_Autoload::instance(), 'autoload']);
42
+ spl_autoload_register(function ($className) {
43
+ $filePath = strtr(
44
+ ltrim($className, '\\'),
45
+ [
46
+ '\\' => '/',
47
+ '_' => '/'
48
+ ]
49
+ );
50
+ $file = $filePath . '.php';
51
+ if (stream_resolve_include_path($file)) {
52
+ include $filePath . '.php';
53
+ }
54
+ });
app/code/community/Ecocode/Profiler/Tests/Dev/controllers/CacheControllerTest.php ADDED
@@ -0,0 +1,168 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Ecocode_Profiler_Tests_Dev_CacheControllerTest extends TestHelper
4
+ {
5
+ protected function getMockedController($class, $request = null, $response = null, $app = null)
6
+ {
7
+ if (!$request instanceof Mage_Core_Controller_Request_Http) {
8
+ $_request = new Mage_Core_Controller_Request_Http();
9
+ if (is_array($request)) {
10
+ $_request->setParams($request);
11
+
12
+ }
13
+ $request = $_request;
14
+
15
+ }
16
+ $response = new Ecocode_Profiler_Tests_Dev_Fixtures_ResponseHttp();
17
+ $appMock = $app ? $app : $this->getMockBuilder('Mage_Core_Model_App')->getMock();
18
+
19
+ $controller = $this->getMockBuilder($class)
20
+ ->setMethods(['getApp'])
21
+ ->setConstructorArgs([$request, $response])
22
+ ->getMock();
23
+
24
+ $controller->method('getApp')
25
+ ->willReturn($appMock);
26
+
27
+
28
+ return $controller;
29
+ }
30
+
31
+ public function setUp()
32
+ {
33
+ parent::setUp();
34
+
35
+ require_once Mage::getModuleDir('controllers', 'Ecocode_Profiler') . DS . 'CacheController.php';
36
+ }
37
+
38
+
39
+ public function testClearAction()
40
+ {
41
+ $appMock = $this->getMockBuilder('Mage_Core_Model_App')->getMock();
42
+ $controller = $this->getMockedController(
43
+ 'Ecocode_Profiler_CacheController',
44
+ ['types' => join(',', ['test', 'block_html', 'config'])],
45
+ null, $appMock
46
+ );
47
+
48
+ $cache = $this->getMockBuilder('Mage_Core_Model_Cache')->getMock();
49
+ $appMock->method('getCacheInstance')
50
+ ->willReturn($cache);
51
+
52
+ $cache
53
+ ->expects($this->exactly(3))
54
+ ->method('cleanType');
55
+
56
+
57
+ /** @var Ecocode_Profiler_CacheController $controller */
58
+ $controller->clearAction();
59
+ }
60
+
61
+ public function testClearAllAction()
62
+ {
63
+ $appMock = $this->getMockBuilder('Mage_Core_Model_App')->getMock();
64
+ $controller = $this->getMockedController(
65
+ 'Ecocode_Profiler_CacheController',
66
+ null, null, $appMock
67
+ );
68
+
69
+ $cache = $this->getMockBuilder('Mage_Core_Model_Cache')->getMock();
70
+ $appMock->method('getCacheInstance')
71
+ ->willReturn($cache);
72
+
73
+ $cache
74
+ ->expects($this->once())
75
+ ->method('flush');
76
+
77
+ /** @var Ecocode_Profiler_CacheController $controller */
78
+ $controller->clearAllAction();
79
+ }
80
+
81
+ public function testEnableAction()
82
+ {
83
+ $request = new Mage_Core_Controller_Request_Http();
84
+ $request->setParams(['types' => 'config,block_html']);
85
+
86
+ $response = new Ecocode_Profiler_Tests_Dev_Fixtures_ResponseHttp();
87
+ $controller = $this->getMockBuilder('Ecocode_Profiler_CacheController')
88
+ ->setMethods(['setCacheStatus'])
89
+ ->setConstructorArgs([$request, $response])
90
+ ->getMock();
91
+
92
+
93
+ $controller
94
+ ->expects($this->once())
95
+ ->method('setCacheStatus')
96
+ ->with(
97
+ $this->equalTo(['config', 'block_html']),
98
+ $this->equalTo(1)
99
+ );
100
+
101
+ /** @var Ecocode_Profiler_CacheController $controller */
102
+ $controller->enableAction();
103
+ }
104
+
105
+ public function testDisableAction()
106
+ {
107
+ $request = new Mage_Core_Controller_Request_Http();
108
+ $request->setParams(['types' => 'config,block_html']);
109
+
110
+ $response = new Ecocode_Profiler_Tests_Dev_Fixtures_ResponseHttp();
111
+ $controller = $this->getMockBuilder('Ecocode_Profiler_CacheController')
112
+ ->setMethods(['setCacheStatus'])
113
+ ->setConstructorArgs([$request, $response])
114
+ ->getMock();
115
+
116
+
117
+ $controller
118
+ ->expects($this->once())
119
+ ->method('setCacheStatus')
120
+ ->with(
121
+ $this->equalTo(['config', 'block_html']),
122
+ $this->equalTo(0)
123
+ );
124
+
125
+ /** @var Ecocode_Profiler_CacheController $controller */
126
+ $controller->disableAction();
127
+ }
128
+
129
+ public function testSetCacheStatus()
130
+ {
131
+ $types = [
132
+ 'config' => new Varien_Object(['id' => 'config', 'status' => 0]),
133
+ 'block_html' => new Varien_Object(['id' => 'block_html', 'status' => 0])
134
+ ];
135
+
136
+
137
+ $cacheMock = $this->getMockBuilder('Mage_Core_Model_Cache')
138
+ ->getMock();
139
+ $cacheMock->method('getTypes')->willReturn($types);
140
+
141
+ $appMock = $this->getMockBuilder('Mage_Core_Model_App')
142
+ ->setMethods(['saveUseCache', 'getCacheInstance', 'getCache'])
143
+ ->getMock();
144
+
145
+ $appMock->method('getCacheInstance')->willReturn($cacheMock);
146
+ $appMock->method('getCache')->willReturn($cacheMock);
147
+
148
+ $this->initApp($appMock);
149
+ $controller = $this->getMockedController(
150
+ 'Ecocode_Profiler_CacheController',
151
+ null, null, $appMock
152
+ );
153
+
154
+ $status = 1;
155
+
156
+ $setCacheStatusMethod = new ReflectionMethod('Ecocode_Profiler_CacheController', 'setCacheStatus');
157
+ $setCacheStatusMethod->setAccessible(true);
158
+
159
+ $types = array_fill_keys(array_keys($types), 0);
160
+ $types['block_html'] = 1;
161
+
162
+ $appMock->expects($this->once())
163
+ ->method('saveUseCache')
164
+ ->with($this->equalTo($types));
165
+
166
+ $setCacheStatusMethod->invoke($controller, ['block_html', 'test'], $status);
167
+ }
168
+ }
app/code/community/Ecocode/Profiler/Tests/Prod/DevModeTest.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Ecocode_Profiler_Tests_DevModeTest
4
+ extends TestHelper
5
+ {
6
+
7
+
8
+ public function testDisabledInProduction()
9
+ {
10
+ $app = Mage::app();
11
+
12
+ $this->assertNotInstanceOf(
13
+ 'Ecocode_Profiler_Model_AppDev',
14
+ $app
15
+ );
16
+ }
17
+
18
+ public function testCollectorsNotLoaded()
19
+ {
20
+ $app = Mage::app();
21
+
22
+ $value = $app->getConfig()->getNode('ecocode/profiler');
23
+ $this->assertFalse($value);
24
+ }
25
+
26
+ public function testModelsNotLoaded()
27
+ {
28
+ $app = Mage::app();
29
+
30
+ $value = $app->getConfig()->getNode('global/models/ecocode_profiler');
31
+ $this->assertFalse($value);
32
+ }
33
+ }
app/code/community/Ecocode/Profiler/Tests/Prod/bootstrap.php ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if (isset($_SERVER['MAGENTO_DIRECTORY'])) {
4
+ $_baseDir = $_SERVER['MAGENTO_DIRECTORY'];
5
+ } else {
6
+ $_baseDir = getcwd();
7
+ }
8
+
9
+ /**
10
+ * Define MAGE_PATH
11
+ * Path to Magento
12
+ */
13
+ define('MAGENTO_ROOT', $_baseDir);
14
+
15
+ // Include Mage file by detecting app root
16
+ require_once $_baseDir . DIRECTORY_SEPARATOR . 'app' . DIRECTORY_SEPARATOR . 'Mage.php';
17
+
18
+ if (!Mage::isInstalled()) {
19
+ throw new RuntimeException('Magento Unit Tests can run only on installed version');
20
+ }
21
+
22
+
23
+ /* Replace server variables for proper file naming */
24
+ $_SERVER['SCRIPT_NAME'] = $_baseDir . DS . 'index.php';
25
+ $_SERVER['SCRIPT_FILENAME'] = $_baseDir . DS . 'index.php';
26
+
27
+
28
+ //flag to check for unittets
29
+ define('BASE_TESTS_PATH', realpath(dirname(__FILE__)));
30
+ require_once BASE_TESTS_PATH . '/../TestHelper.php';
31
+
32
+ $options = [
33
+ 'cache' => ['id_prefix' => 'test-prod']
34
+ ];
35
+ Mage::app()->cleanCache();
36
+ Mage::app('', 'store', $options);
37
+ // Removing Varien Autoload, to prevent errors with PHPUnit components
38
+ spl_autoload_unregister([\Varien_Autoload::instance(), 'autoload']);
39
+ spl_autoload_register(function ($className) {
40
+ $filePath = strtr(
41
+ ltrim($className, '\\'),
42
+ [
43
+ '\\' => '/',
44
+ '_' => '/'
45
+ ]
46
+ );
47
+ $file = $filePath . '.php';
48
+ if (stream_resolve_include_path($file)) {
49
+ include $filePath . '.php';
50
+ }
51
+ });
app/code/community/Ecocode/Profiler/Tests/TestHelper.php ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class TestHelper extends PHPUnit_Framework_TestCase
4
+ {
5
+ protected static $mageAppReflection;
6
+
7
+ protected $reInetMage = false;
8
+
9
+ protected $mageDefaultProperties = [
10
+ '_registry' => [],
11
+ '_isDownloader' => false,
12
+ '_isDeveloperMode' => false,
13
+ 'headersSentThrowsException' => true,
14
+ ];
15
+
16
+ /**
17
+ * @beforeClass
18
+ */
19
+ protected function setUp()
20
+ {
21
+ $this->initAppOnMageClass($this->reInetMage);
22
+ }
23
+
24
+ public function resetMage()
25
+ {
26
+ if (!isset($this->mageDefaultProperties['_appRoot'])) {
27
+ //save to original mage root
28
+ $this->mageDefaultProperties['_appRoot'] = Mage::getRoot();
29
+ }
30
+ $mageReflectionClass = new \ReflectionClass('Mage');
31
+ $properties = $mageReflectionClass->getStaticProperties();
32
+
33
+ foreach($properties as $key => $value) {
34
+ $reflectedProperty = $mageReflectionClass->getProperty($key);
35
+ $reflectedProperty->setAccessible(true);
36
+ $value = null;
37
+ if (isset($this->mageDefaultProperties[$key])) {
38
+ $value = $this->mageDefaultProperties[$key];
39
+ }
40
+ $reflectedProperty->setValue($value);
41
+ }
42
+ $this->initApp();
43
+ }
44
+
45
+ public function initAppOnMageClass($force = false)
46
+ {
47
+ $mageReflectionClass = new \ReflectionClass('Mage');
48
+
49
+ if ($force) {
50
+ $reflectedProperty = $mageReflectionClass->getProperty('_app');
51
+ $reflectedProperty->setAccessible(true);
52
+ $reflectedProperty->setValue(null);
53
+ }
54
+ $this->initApp();
55
+ }
56
+
57
+ protected function initApp(Mage_Core_Model_App $app = null)
58
+ {
59
+ $options = [
60
+ 'cache' => ['id_prefix' => 'dev-test'],
61
+ 'config_model' => 'Ecocode_Profiler_Model_Core_Config'
62
+ ];
63
+ if ($app) {
64
+ $app->init('', 'store', $options);
65
+ } else {
66
+ Mage::app('', 'store', $options);
67
+ }
68
+
69
+ }
70
+
71
+ /**
72
+ * @param $data
73
+ * @return Varien_Event_Observer
74
+ */
75
+ protected function getObserver($data)
76
+ {
77
+ $observer = new Varien_Event_Observer();
78
+ $event = new Varien_Event($data);
79
+ $observer->setEvent($event);
80
+
81
+ return $observer;
82
+ }
83
+
84
+ public function getProtectedValue($object, $property)
85
+ {
86
+ $property = new ReflectionProperty(get_class($object), $property);
87
+ $property->setAccessible(true);
88
+
89
+ return $property->getValue($object);
90
+ }
91
+ }
app/code/community/Ecocode/Profiler/autoloader.php ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+
4
+ class Ecocode_Profiler_Autoloader
5
+ {
6
+ public static $autoloader;
7
+
8
+ /** @var Closure */
9
+ protected $includeFile;
10
+ protected $classMap = [];
11
+
12
+
13
+ public static function getAutoloader()
14
+ {
15
+ if (self::$autoloader === null) {
16
+ self::$autoloader = new Ecocode_Profiler_Autoloader();
17
+ }
18
+ return self::$autoloader;
19
+ }
20
+
21
+ /**
22
+ * Registers this instance as an autoloader.
23
+ *
24
+ * @param bool $prepend Whether to prepend the autoloader or not
25
+ */
26
+ public function register($prepend = false)
27
+ {
28
+ spl_autoload_register([$this, 'loadClass'], true, $prepend);
29
+ }
30
+
31
+ /**
32
+ * Unregisters this instance as an autoloader.
33
+ */
34
+ public function unregister()
35
+ {
36
+ spl_autoload_unregister([$this, 'loadClass']);
37
+ }
38
+
39
+ public function loadClass($class)
40
+ {
41
+ if (isset($this->classMap[$class])) {
42
+ /**
43
+ * Scope isolated include.
44
+ *
45
+ * Prevents access to $this/self from included files.
46
+ *
47
+ * @param $file
48
+ */
49
+ $includeFile = function ($file) {
50
+ include $file;
51
+ };
52
+ $includeFile($this->classMap[$class]);
53
+ return true;
54
+ }
55
+ }
56
+
57
+ public function addOverwrite($className, $file)
58
+ {
59
+ if (strpos($file, '/') !== 0) {
60
+ $overwriteDir = __DIR__ . DIRECTORY_SEPARATOR . 'overwrite' . DIRECTORY_SEPARATOR;
61
+ $file = $overwriteDir . $file;
62
+ }
63
+ $this->classMap[$className] = $file;
64
+
65
+ return $this;
66
+ }
67
+
68
+ }
app/code/community/Ecocode/Profiler/controllers/CacheController.php ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Ecocode_Profiler_CacheController
4
+ extends Ecocode_Profiler_Controller_AbstractController
5
+ {
6
+ public function clearAction()
7
+ {
8
+ $app = $this->getApp();
9
+ $types = $this->getRequest()->getParam('types', '');
10
+ $types = explode(',', $types);
11
+
12
+ foreach ($types as $type) {
13
+ $app->getCacheInstance()->cleanType($type);
14
+ }
15
+
16
+ $this->getResponse()
17
+ ->setHeader('content-type', 'application/json')
18
+ ->setBody(json_encode(['ok']));
19
+ }
20
+
21
+ public function clearAllAction()
22
+ {
23
+ $this->getApp()->getCacheInstance()->flush();
24
+
25
+ $this->getResponse()
26
+ ->setHeader('content-type', 'application/json')
27
+ ->setBody(json_encode(['ok']));
28
+ }
29
+
30
+ public function enableAction()
31
+ {
32
+ $types = $this->getRequest()->getParam('types', '');
33
+ $types = explode(',', $types);
34
+ $this->setCacheStatus($types, 1);
35
+
36
+ $this->getResponse()
37
+ ->setHeader('content-type', 'application/json')
38
+ ->setBody(json_encode(['ok']));
39
+ }
40
+
41
+ public function disableAction()
42
+ {
43
+ $types = $this->getRequest()->getParam('types', '');
44
+ $types = explode(',', $types);
45
+ $this->setCacheStatus($types, 0);
46
+
47
+ $this->getResponse()
48
+ ->setHeader('content-type', 'application/json')
49
+ ->setBody(json_encode(['ok']));
50
+ }
51
+
52
+ protected function setCacheStatus(array $types, $status)
53
+ {
54
+ $app = $this->getApp();
55
+ $allTypes = $app->getCacheInstance()->getTypes();
56
+ $allTypes = array_map(function (Varien_Object $type) {
57
+ return $type->getData('status');
58
+ }, $allTypes);
59
+
60
+ $updatedTypes = 0;
61
+ foreach ($types as $code) {
62
+ if (isset($allTypes[$code])) {
63
+ $allTypes[$code] = $status;
64
+ $updatedTypes++;
65
+ }
66
+ }
67
+ if ($updatedTypes > 0) {
68
+ $app->saveUseCache($allTypes);
69
+ }
70
+ }
71
+ }
app/code/community/Ecocode/Profiler/controllers/IndexController.php ADDED
@@ -0,0 +1,155 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Ecocode_Profiler_IndexController extends Ecocode_Profiler_Controller_AbstractController
4
+ {
5
+ public function indexAction()
6
+ {
7
+ $this->loadLayout('profiler_default');
8
+ $this->renderLayout();
9
+ }
10
+
11
+ /**
12
+ *
13
+ */
14
+ public function toolbarAction()
15
+ {
16
+ $token = $this->getRequest()->getParam(Ecocode_Profiler_Model_Profiler::URL_TOKEN_PARAMETER);
17
+ $profiler = $this->getProfiler();
18
+
19
+ $profile = $profiler->loadProfile($token);
20
+ Mage::register('current_profile', $profile);
21
+
22
+ $this->loadLayout(false);
23
+ $this->renderLayout();
24
+ }
25
+
26
+ public function searchAction()
27
+ {
28
+ $request = $this->getRequest();
29
+
30
+ $ip = preg_replace('/[^:\d\.]/', '', $request->getParam('ip'));
31
+ $method = $request->getParam('method');
32
+ $url = $request->getParam('url');
33
+ $start = $request->getParam('start');
34
+ $end = $request->getParam('end');
35
+ $limit = $request->getParam('limit');
36
+ $token = $request->getParam('_token');
37
+
38
+ if (null !== $session = Mage::getSingleton('core/session')) {
39
+ $session->setData('_profiler_search_ip', $ip);
40
+ $session->setData('_profiler_search_method', $method);
41
+ $session->setData('_profiler_search_url', $url);
42
+ $session->setData('_profiler_search_start', $start);
43
+ $session->setData('_profiler_search_end', $end);
44
+ $session->setData('_profiler_search_limit', $limit);
45
+ $session->setData('_profiler_search_token', $token);
46
+ }
47
+
48
+ if (!empty($token)) {
49
+ return $this->_redirect('_profiler/index/panel', [Ecocode_Profiler_Model_Profiler::URL_TOKEN_PARAMETER => $token]);
50
+ }
51
+
52
+ return $this->_redirect('_profiler/index/searchResults',
53
+ [
54
+ 'ip' => $ip,
55
+ 'method' => $method,
56
+ 'url' => $url,
57
+ 'start' => $start,
58
+ 'end' => $end,
59
+ 'limit' => $limit,
60
+ ]
61
+ );
62
+ }
63
+
64
+ public function searchResultsAction()
65
+ {
66
+ $request = $this->getRequest();
67
+ $profiler = $this->getProfiler();
68
+
69
+ $ip = $request->getParam('ip');
70
+ $method = $request->getParam('method');
71
+ $statusCode = $request->getParam('status_code');
72
+ $url = $request->getParam('url');
73
+ $start = $request->getParam('start');
74
+ $end = $request->getParam('end');
75
+ $limit = $request->getParam('limit');
76
+
77
+ $data = [
78
+ 'request' => $request,
79
+ 'tokens' => $profiler->find($ip, $url, $limit, $method, $start, $end),
80
+ 'ip' => $ip,
81
+ 'method' => $method,
82
+ 'status_code' => $statusCode,
83
+ 'url' => $url,
84
+ 'start' => $start,
85
+ 'end' => $end,
86
+ 'limit' => $limit,
87
+ 'panel' => null,
88
+ ];
89
+
90
+ $this->loadLayout('profiler_default');
91
+
92
+ $this
93
+ ->getLayout()
94
+ ->getBlock('profiler.search.results')
95
+ ->addData($data);
96
+
97
+ $this->renderLayout();
98
+ }
99
+
100
+ public function panelAction()
101
+ {
102
+ $profiler = $this->getProfiler();
103
+
104
+ /** @var Mage_Core_Controller_Request_Http $request */
105
+ $request = $this->getRequest();
106
+
107
+ $token = $request->getParam(Ecocode_Profiler_Model_Profiler::URL_TOKEN_PARAMETER);
108
+ if (!$token) {
109
+ return $this->_redirect('_profiler');
110
+ }
111
+
112
+
113
+ $panel = $request->getParam('panel', 'request');
114
+
115
+ if ('latest' === $token && $latest = current($profiler->find(null, null, 1, null, null, null))) {
116
+ $token = $latest['token'];
117
+ }
118
+
119
+ if (!$profile = $this->profiler->loadProfile($token)) {
120
+ return $this->norouteAction();
121
+ }
122
+
123
+ /** @var Ecocode_Profiler_Model_Profile $profile */
124
+ if (!$profile->hasCollector($panel)) {
125
+ throw new Exception(sprintf('Panel "%s" is not available for token "%s".', $panel, $token));
126
+ }
127
+
128
+ Mage::register('current_profile', $profile);
129
+ Mage::register('current_panel', $panel);
130
+
131
+ $collector = $profile->getCollector($panel);
132
+
133
+ $layoutHandler = 'collector_' . $collector->getName();
134
+ $this->loadLayout(['profiler_default', $layoutHandler]);
135
+
136
+ $panelBlock = $this->getLayout()->getBlock('panel');
137
+
138
+ /** @var Ecocode_Profiler_Model_Profile $profile */
139
+ if (!$panelBlock) {
140
+ throw new Exception(sprintf('Panel Block for "%s" is not available for token "%s".', $panel, $token));
141
+ }
142
+ if (!($panelBlock instanceof Ecocode_Profiler_Block_Collector_Base)) {
143
+ throw new Exception(sprintf('Panel Block must extend "Ecocode_Profiler_Block_Collector_AbstractBase"'));
144
+ }
145
+
146
+ $panelBlock->setCollector($collector);
147
+
148
+ return $this->renderLayout();
149
+ }
150
+
151
+ public function phpinfoAction()
152
+ {
153
+ phpinfo();
154
+ }
155
+ }
app/code/community/Ecocode/Profiler/debug.php ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ use Symfony\Component\Debug\BufferingLogger;
3
+ use Symfony\Component\Debug\Debug;
4
+ use Symfony\Component\Debug\ErrorHandler;
5
+
6
+ if (class_exists('\Symfony\Component\Debug\Debug')) {
7
+ class MagentoErrorHandler extends ErrorHandler
8
+ {
9
+ public function handleException($exception, array $error = null)
10
+ {
11
+ while (ob_get_level()) {
12
+ ob_end_clean();
13
+ }
14
+ parent::handleException($exception, $error);
15
+ }
16
+ }
17
+
18
+ Debug::enable();
19
+ $errorHandler = new MagentoErrorHandler(new BufferingLogger());
20
+ $errorHandler->throwAt(-1, true);
21
+
22
+ ErrorHandler::register($errorHandler);
23
+ $errorHandler->setDefaultLogger(Mage::getLogger());
24
+ }
app/code/community/Ecocode/Profiler/etc/config.xml ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <modules>
4
+ <Ecocode_Profiler>
5
+ <version>1.1.0</version>
6
+ </Ecocode_Profiler>
7
+ </modules>
8
+ </config>
app/code/community/Ecocode/Profiler/etc/development.xml ADDED
@@ -0,0 +1,139 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <ecocode>
4
+ <profiler>
5
+ <toolbar>1</toolbar>
6
+ <allow_ip>127.0.0.1</allow_ip>
7
+ <collectors>
8
+ <request>ecocode_profiler/collector_requestDataCollector</request>
9
+ <memory>ecocode_profiler/collector_memoryDataCollector</memory>
10
+ <time>ecocode_profiler/collector_timeDataCollector</time>
11
+ <ajax>ecocode_profiler/collector_ajaxDataCollector</ajax>
12
+ <mysql>ecocode_profiler/collector_mysqlDataCollector</mysql>
13
+ <translation>ecocode_profiler/collector_translationDataCollector</translation>
14
+ <rewrite>ecocode_profiler/collector_rewriteDataCollector</rewrite>
15
+ <customer>ecocode_profiler/collector_customerDataCollector</customer>
16
+ <layout>ecocode_profiler/collector_layoutDataCollector</layout>
17
+ <config>ecocode_profiler/collector_configDataCollector</config>
18
+ <event>ecocode_profiler/collector_eventDataCollector</event>
19
+ <cache>ecocode_profiler/collector_cacheDataCollector</cache>
20
+ <log>ecocode_profiler/collector_logDataCollector</log>
21
+ <model>ecocode_profiler/collector_modelDataCollector</model>
22
+ </collectors>
23
+ </profiler>
24
+ </ecocode>
25
+ <global>
26
+ <models>
27
+ <ecocode_profiler>
28
+ <class>Ecocode_Profiler_Model</class>
29
+ <resourceModel>ecocode_profiler_resource</resourceModel>
30
+ </ecocode_profiler>
31
+ <ecocode_profiler_resource>
32
+ <class>Ecocode_Profiler_Model_Resource</class>
33
+ </ecocode_profiler_resource>
34
+ </models>
35
+ <blocks>
36
+ <ecocode_profiler>
37
+ <class>Ecocode_Profiler_Block</class>
38
+ </ecocode_profiler>
39
+ </blocks>
40
+ <helpers>
41
+ <ecocode_profiler>
42
+ <class>Ecocode_Profiler_Helper</class>
43
+ </ecocode_profiler>
44
+ </helpers>
45
+ </global>
46
+ <frontend>
47
+ <layout>
48
+ <updates>
49
+ <ecocode_profiler>
50
+ <file>ecocode_profiler.xml</file>
51
+ </ecocode_profiler>
52
+ </updates>
53
+ </layout>
54
+ <routers>
55
+ <profiler>
56
+ <use>standard</use>
57
+ <args>
58
+ <frontName>_profiler</frontName>
59
+ <module>Ecocode_Profiler</module>
60
+ </args>
61
+ </profiler>
62
+ </routers>
63
+ <events>
64
+ <controller_front_send_response_before>
65
+ <observers>
66
+ <ecocode_profiler>
67
+ <type>singleton</type>
68
+ <class>ecocode_profiler/observer</class>
69
+ <method>controllerFrontSendResponseBefore</method>
70
+ </ecocode_profiler>
71
+ </observers>
72
+ </controller_front_send_response_before>
73
+ <mage_terminate>
74
+ <observers>
75
+ <ecocode_profiler>
76
+ <type>singleton</type>
77
+ <class>ecocode_profiler/observer</class>
78
+ <method>onTerminate</method>
79
+ </ecocode_profiler>
80
+ </observers>
81
+ </mage_terminate>
82
+ <core_block_abstract_to_html_before>
83
+ <observers>
84
+ <ecocode_profiler_context>
85
+ <type>singleton</type>
86
+ <class>ecocode_profiler/observer_context</class>
87
+ <method>openBlockContext</method>
88
+ </ecocode_profiler_context>
89
+ <ecocode_layout_profiler>
90
+ <type>singleton</type>
91
+ <class>ecocode_profiler/collector_layoutDataCollector</class>
92
+ <method>beforeToHtml</method>
93
+ </ecocode_layout_profiler>
94
+ </observers>
95
+ </core_block_abstract_to_html_before>
96
+ <core_block_abstract_to_html_after>
97
+ <observers>
98
+ <ecocode_profiler_context>
99
+ <type>singleton</type>
100
+ <class>ecocode_profiler/observer_context</class>
101
+ <method>closeBlockContext</method>
102
+ </ecocode_profiler_context>
103
+ <ecocode_layout_profiler>
104
+ <type>singleton</type>
105
+ <class>ecocode_profiler/collector_layoutDataCollector</class>
106
+ <method>afterToHtml</method>
107
+ </ecocode_layout_profiler>
108
+ </observers>
109
+ </core_block_abstract_to_html_after>
110
+ <model_resource_db_load>
111
+ <observers>
112
+ <ecocode_profiler_model>
113
+ <type>singleton</type>
114
+ <method>trackModelLoad</method>
115
+ <class>ecocode_profiler/collector_modelDataCollector</class>
116
+ </ecocode_profiler_model>
117
+ </observers>
118
+ </model_resource_db_load>
119
+ <model_resource_db_save>
120
+ <observers>
121
+ <ecocode_profiler_model>
122
+ <type>singleton</type>
123
+ <method>trackModelSave</method>
124
+ <class>ecocode_profiler/collector_modelDataCollector</class>
125
+ </ecocode_profiler_model>
126
+ </observers>
127
+ </model_resource_db_save>
128
+ <model_resource_db_delete>
129
+ <observers>
130
+ <ecocode_profiler_model>
131
+ <type>singleton</type>
132
+ <method>trackModelDelete</method>
133
+ <class>ecocode_profiler/collector_modelDataCollector</class>
134
+ </ecocode_profiler_model>
135
+ </observers>
136
+ </model_resource_db_delete>
137
+ </events>
138
+ </frontend>
139
+ </config>
app/code/community/Ecocode/Profiler/overwrite/Mage.php ADDED
@@ -0,0 +1,124 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+
4
+ $mageRoot = MAGENTO_ROOT . DIRECTORY_SEPARATOR;
5
+ $mageVarDir = $mageRoot . 'var' . DIRECTORY_SEPARATOR . 'cache' . DIRECTORY_SEPARATOR;
6
+ $mageFile = $mageRoot . 'app' . DIRECTORY_SEPARATOR . 'Mage.php';
7
+ $mageMd5 = md5_file($mageFile);
8
+ $mageCacheFile = Ecocode_Profiler_Helper_Data::getOverwriteDir() . 'Original_Mage_' . Ecocode_Profiler_Helper_Data::getVersion() . '-' . $mageMd5 . '.php';
9
+
10
+ if (!file_exists($mageCacheFile)) {
11
+ $mageCode = file_get_contents($mageFile);
12
+
13
+ $replace = [
14
+ 'final class Mage' => 'class MageOriginal',
15
+ ' private ' => ' protected ',
16
+ "define('BP', dirname(dirname(__FILE__)));" => '',
17
+ "Mage::register('original_include_path', get_include_path());" => '$originalIncludePath = get_include_path();',
18
+ "Mage::registry('original_include_path')" => '$originalIncludePath',
19
+ 'new Mage_Core_Model_App()' => 'new Ecocode_Profiler_Model_AppDev()',
20
+ 'self::printException($e);' => 'throw $e;'
21
+ ];
22
+ $mageCode = str_replace(array_keys($replace), array_values($replace), $mageCode);
23
+
24
+ $replace = [
25
+ '/(?<!= )self::/' => 'static::'
26
+ ];
27
+ $mageCode = preg_replace(array_keys($replace), array_values($replace), $mageCode);
28
+
29
+ file_put_contents($mageCacheFile, $mageCode);
30
+ }
31
+
32
+ require_once $mageCacheFile;
33
+
34
+
35
+ class Mage extends MageOriginal
36
+ {
37
+ protected static $_logChannels = [];
38
+
39
+ protected static $_logger;
40
+ protected static $_loggerDebugHandler;
41
+
42
+ /**
43
+ * @return Ecocode_Profiler_Model_Logger
44
+ */
45
+ public static function getLogger($channel = null)
46
+ {
47
+ if ($channel === null) {
48
+ return static::getDefaultLogger();
49
+ }
50
+ if (!isset(static::$_logChannels[$channel])) {
51
+ static::$_logChannels[$channel] = static::getNewLogger($channel);
52
+ }
53
+
54
+ return static::$_logChannels[$channel];
55
+ }
56
+
57
+ public static function getDefaultLogger()
58
+ {
59
+ if (static::$_logger === null) {
60
+ static::$_logger = static::getNewLogger('default');
61
+ }
62
+
63
+ return static::$_logger;
64
+ }
65
+
66
+ protected static function getNewLogger($channel)
67
+ {
68
+ if (!@class_exists('\Monolog\Logger')) {
69
+ return false;
70
+ }
71
+ if (static::$_loggerDebugHandler === null) {
72
+ static::$_loggerDebugHandler = new Ecocode_Profiler_Model_Logger_DebugHandler();
73
+ }
74
+
75
+ return new Ecocode_Profiler_Model_Logger(
76
+ $channel,
77
+ [static::$_loggerDebugHandler]
78
+ );
79
+ }
80
+
81
+ public static function log($message, $level = null, $file = '', $forceLog = false)
82
+ {
83
+ $level = is_null($level) ? Zend_Log::DEBUG : $level;
84
+ $file = empty($file) ? 'system.log' : $file;
85
+
86
+ $channel = preg_replace('/(\..+)$/', '', $file);
87
+ static::getLogger($channel)->mageLog($level, $message);
88
+
89
+ return parent::log($message, $level, $file, $forceLog);
90
+ }
91
+
92
+ /**
93
+ * @codeCoverageIgnore
94
+ */
95
+ public static function terminate()
96
+ {
97
+ self::dispatchDebugEvent('mage_terminate');
98
+ }
99
+
100
+
101
+ /**
102
+ * @codeCoverageIgnore
103
+ *
104
+ * @param $name
105
+ * @param array $data
106
+ * @return Mage_Core_Model_App
107
+ */
108
+ public static function dispatchDebugEvent($name, array $data = [])
109
+ {
110
+ $data['debug'] = true;
111
+ return parent::dispatchEvent($name, $data);
112
+ }
113
+
114
+ /**
115
+ * @codeCoverageIgnore
116
+ * @return []
117
+ */
118
+ public static function getAllRegistryEntries()
119
+ {
120
+ return static::$_registry;
121
+ }
122
+ }
123
+
124
+ Mage::register('original_include_path', get_include_path());
app/code/community/Ecocode/Profiler/overwrite/MageCoreModelResource.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ Ecocode_Profiler_Helper_Data::loadRenamedClass('core/Mage/Core/Model/Resource.php', 'Original_Mage_Core_Model_Resource');
4
+
5
+
6
+ class Mage_Core_Model_Resource extends
7
+ Original_Mage_Core_Model_Resource
8
+ {
9
+ protected $configProperty;
10
+
11
+ public function __construct()
12
+ {
13
+ $this->configProperty = new ReflectionProperty('Varien_Db_Adapter_Pdo_Mysql', '_config');
14
+ $this->configProperty->setAccessible(true);
15
+ }
16
+
17
+ public function getConnection($name)
18
+ {
19
+ /** @var Magento_Db_Adapter_Pdo_Mysql $connection */
20
+ $connection = parent::getConnection($name);
21
+ if ($connection->getStatementClass() !== 'Ecocode_Profiler_Db_Statement_Pdo_Mysql') {
22
+ $connection->setStatementClass('Ecocode_Profiler_Db_Statement_Pdo_Mysql');
23
+ $config = $connection->getConfig();
24
+ if (!isset($config['connection_name'])) {
25
+ $config['connection_name'] = $name;
26
+ $this->configProperty->setValue($connection, $config);
27
+ }
28
+ }
29
+
30
+ return $connection;
31
+ }
32
+
33
+ }
app/code/community/Ecocode/Profiler/overwrite/MageCoreModelResourceDbAbstract.php ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ Ecocode_Profiler_Helper_Data::loadRenamedClass('core/Mage/Core/Model/Resource/Db/Abstract.php', 'Original_Mage_Core_Model_Resource_Db_Abstract');
4
+
5
+ abstract class Mage_Core_Model_Resource_Db_Abstract extends
6
+ Original_Mage_Core_Model_Resource_Db_Abstract
7
+ {
8
+ /**
9
+ * @codeCoverageIgnore
10
+ *
11
+ * @param $event
12
+ * @param array $data
13
+ */
14
+ protected function dispatch($event, array $data = [])
15
+ {
16
+ Mage::dispatchDebugEvent($event, $data);
17
+ }
18
+
19
+ /**
20
+ * overwrite load function as "_afterLoad" etc can be overwritten
21
+ *
22
+ * @param Mage_Core_Model_Abstract $object
23
+ * @param mixed $value
24
+ * @param null $field
25
+ * @return Mage_Core_Model_Resource_Db_Abstract
26
+ */
27
+ public function load(Mage_Core_Model_Abstract $object, $value, $field = null)
28
+ {
29
+ $start = microtime(true);
30
+ $result = parent::load($object, $value, $field);
31
+
32
+ $this->dispatch('model_resource_db_load', [
33
+ 'object' => $object,
34
+ 'time' => microtime(true) - $start
35
+ ]);
36
+
37
+ return $result;
38
+ }
39
+
40
+ /**
41
+ * overwrite load function as "_afterSave" etc can be overwritten
42
+ *
43
+ * @param Mage_Core_Model_Abstract $object
44
+ * @return Mage_Core_Model_Resource_Db_Abstract
45
+ */
46
+ public function save(Mage_Core_Model_Abstract $object)
47
+ {
48
+ $start = microtime(true);
49
+ $result = parent::save($object);
50
+
51
+ if (!$object->isDeleted()) {
52
+ //is captured separately
53
+ $this->dispatch('model_resource_db_save', [
54
+ 'object' => $object,
55
+ 'time' => microtime(true) - $start
56
+ ]);
57
+ }
58
+
59
+ return $result;
60
+ }
61
+
62
+ /**
63
+ * overwrite load function as "_afterDelete" etc can be overwritten
64
+ *
65
+ * @param Mage_Core_Model_Abstract $object
66
+ * @return Mage_Core_Model_Resource_Db_Abstract
67
+ */
68
+ public function delete(Mage_Core_Model_Abstract $object)
69
+ {
70
+ $start = microtime(true);
71
+ $result = parent::delete($object);
72
+
73
+ if (!$object->isDeleted()) {
74
+ //is captured separately
75
+ $this->dispatch('model_resource_db_delete', [
76
+ 'object' => $object,
77
+ 'time' => microtime(true) - $start
78
+ ]);
79
+ }
80
+
81
+ return $result;
82
+ }
83
+ }
app/code/community/Ecocode/Profiler/overwrite/MageCoreModelStore.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ Ecocode_Profiler_Helper_Data::loadRenamedClass('core/Mage/Core/Model/Store.php', 'Original_Mage_Core_Model_Store');
4
+
5
+
6
+ class Mage_Core_Model_Store extends
7
+ Original_Mage_Core_Model_Store
8
+ {
9
+ protected $_isDev;
10
+
11
+ /**
12
+ * Remove script file name from url in case when server rewrites are enabled
13
+ *
14
+ * @param string $url
15
+ * @return string
16
+ */
17
+ protected function _updatePathUseRewrites($url)
18
+ {
19
+ $script = $this->isDev() ? 'dev.php' : 'index.php';
20
+ if ($this->isAdmin() || $this->isDev() || !$this->getConfig(self::XML_PATH_USE_REWRITES) || !Mage::isInstalled()) {
21
+ $indexFileName = $this->_isCustomEntryPoint() ? $script : basename($_SERVER['SCRIPT_FILENAME']);
22
+ $url .= $indexFileName . '/';
23
+ }
24
+ return $url;
25
+ }
26
+
27
+ protected function isDev()
28
+ {
29
+ if ($this->_isDev === null) {
30
+ $this->_isDev = Mage::app() instanceof Ecocode_Profiler_Model_AppDev;
31
+ }
32
+
33
+ return $this->_isDev;
34
+ }
35
+ }
app/code/community/Ecocode/Profiler/overwrite/MageCoreModelTranslate.php ADDED
@@ -0,0 +1,154 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ Ecocode_Profiler_Helper_Data::loadRenamedClass('core/Mage/Core/Model/Translate.php', 'Original_Mage_Core_Model_Translate');
4
+
5
+ /**
6
+ * @author ecocode GmbH <jk@ecocode.de>
7
+ * @author Justus Krapp <jk@ecocode.de>
8
+ */
9
+ class Mage_Core_Model_Translate extends Original_Mage_Core_Model_Translate
10
+ {
11
+ const STATE_TRANSLATED = 'translated';
12
+ const STATE_FALLBACK = 'fallback';
13
+ const STATE_MISSING = 'missing';
14
+ const STATE_INVALID = 'invalid';
15
+
16
+ protected $currentMessage = null;
17
+
18
+ protected $messages = [];
19
+
20
+
21
+ public function translate($args)
22
+ {
23
+ $_args = $args;
24
+ $this->currentMessage = [
25
+ 'locale' => $this->_locale,
26
+ 'module' => null,
27
+ 'trace' => []
28
+ ];
29
+
30
+ $text = array_shift($_args);
31
+
32
+ if ($text instanceof Mage_Core_Model_Translate_Expr) {
33
+ $this->currentMessage['module'] = $text->getModule();
34
+ }
35
+
36
+ $translation = parent::translate($args);
37
+ if ($translation === '') {
38
+ //just return nothing we can do here? maybe log a stacktrace?
39
+ return $translation;
40
+ }
41
+
42
+ if (@vsprintf($this->currentMessage['translation'], $_args) === false) {
43
+ $trace = $this->addTrace();
44
+ if ($trace && $this->traceHasFunctionCall($trace, 'getTranslateJson')) {
45
+ //dont log invalid as strings are used with empty placeholders is intended here
46
+ } else {
47
+ $this->currentMessage['state'] = self::STATE_INVALID;
48
+ }
49
+ }
50
+
51
+ $this->currentMessage['parameters'] = $_args;
52
+ $this->currentMessage['translation'] = $translation;
53
+
54
+ $this->log();
55
+ return $translation;
56
+ }
57
+
58
+ public function _getTranslatedString($text, $code)
59
+ {
60
+ $this->currentMessage['text'] = $text;
61
+ $this->currentMessage['code'] = $code;
62
+
63
+ $translated = parent::_getTranslatedString($text, $code);
64
+ if (array_key_exists($code, $this->_data)) {
65
+ $state = self::STATE_TRANSLATED;
66
+ } elseif (array_key_exists($text, $this->_data)) {
67
+ $state = self::STATE_FALLBACK;
68
+ $this->addTrace();
69
+ } else {
70
+ $state = self::STATE_MISSING;
71
+ $this->addTrace();
72
+ }
73
+
74
+ $this->currentMessage['state'] = $state;
75
+ $this->currentMessage['translation'] = $translated;
76
+
77
+ return $translated;
78
+ }
79
+
80
+ public function getMessages()
81
+ {
82
+ return $this->messages;
83
+ }
84
+
85
+ protected function log()
86
+ {
87
+ $this->messages[] = [
88
+ 'locale' => $this->currentMessage['locale'],
89
+ 'code' => $this->currentMessage['code'],
90
+ 'text' => $this->currentMessage['text'],
91
+ 'translation' => $this->currentMessage['translation'],
92
+ 'state' => $this->currentMessage['state'],
93
+ 'parameters' => $this->currentMessage['parameters'],
94
+ 'module' => $this->currentMessage['module'],
95
+ 'trace' => $this->currentMessage['trace']
96
+ ];
97
+ }
98
+
99
+ /**
100
+ * Adding translation data
101
+ *
102
+ * @param array $data
103
+ * @param string $scope
104
+ * @return Mage_Core_Model_Translate
105
+ */
106
+ protected function _addData($data, $scope, $forceReload = false)
107
+ {
108
+ foreach ($data as $key => $value) {
109
+
110
+ /*
111
+ we needed to simplify this to properly detect not translated strings and their scope
112
+ */
113
+ $key = $this->_prepareDataString($key);
114
+ $value = $this->_prepareDataString($value);
115
+
116
+ $scopeKey = $scope . self::SCOPE_SEPARATOR . $key;
117
+
118
+ $this->_data[$scopeKey] = $value;
119
+ if (!isset($this->_data[$key]) && !Mage::getIsDeveloperMode()) {
120
+ $this->_data[$key] = $value;
121
+ }
122
+ }
123
+ return $this;
124
+ }
125
+
126
+ /**
127
+ * @return array
128
+ */
129
+ protected function addTrace()
130
+ {
131
+ $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 10);
132
+
133
+ while (($trace = reset($backtrace)) && (!isset($trace['function']) || $trace['function'] !== '__')) {
134
+ array_shift($backtrace);
135
+ }
136
+
137
+ return $this->currentMessage['trace'] = array_slice($backtrace, 0, 5);
138
+ }
139
+
140
+ /**
141
+ * @param array $trace
142
+ * @param $functionName
143
+ * @return bool
144
+ */
145
+ protected function traceHasFunctionCall(array $trace, $functionName)
146
+ {
147
+ foreach ($trace as $item) {
148
+ if (isset($item['function']) && $item['function'] === $functionName) {
149
+ return true;
150
+ }
151
+ }
152
+ return false;
153
+ }
154
+ }
app/code/community/Ecocode/Profiler/overwrite/MageEavModelEntityAbstract.php ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ Ecocode_Profiler_Helper_Data::loadRenamedClass('core/Mage/Eav/Model/Entity/Abstract.php', 'Original_Mage_Eav_Model_Entity_Abstract');
4
+
5
+ abstract class Mage_Eav_Model_Entity_Abstract extends
6
+ Original_Mage_Eav_Model_Entity_Abstract
7
+ {
8
+ /**
9
+ * @codeCoverageIgnore
10
+ *
11
+ * @param $event
12
+ * @param array $data
13
+ */
14
+ protected function dispatch($event, array $data = [])
15
+ {
16
+ Mage::dispatchDebugEvent($event, $data);
17
+ }
18
+
19
+ public function load($object, $entityId, $attributes = [])
20
+ {
21
+ $start = microtime(true);
22
+ $result = parent::load($object, $entityId, $attributes);
23
+
24
+ $this->dispatch('model_resource_db_load', [
25
+ 'object' => $object,
26
+ 'time' => microtime(true) - $start
27
+ ]);
28
+
29
+ return $result;
30
+ }
31
+
32
+ /**
33
+ * overwrite load function as "_afterSave" etc can be overwritten
34
+ */
35
+ public function save(Varien_Object $object)
36
+ {
37
+ $start = microtime(true);
38
+ $result = parent::save($object);
39
+
40
+ if (!$object->isDeleted()) {
41
+ //is captured separately
42
+ $this->dispatch('model_resource_db_save', [
43
+ 'object' => $object,
44
+ 'time' => microtime(true) - $start
45
+ ]);
46
+ }
47
+
48
+ return $result;
49
+ }
50
+
51
+ /**
52
+ * overwrite load function as "_afterDelete" etc can be overwritten
53
+ *
54
+ * @param $object
55
+ * @return Mage_Eav_Model_Entity_Abstract
56
+ */
57
+ public function delete($object)
58
+ {
59
+ $start = microtime(true);
60
+ $result = parent::delete($object);
61
+
62
+ //is captured separately
63
+ $this->dispatch('model_resource_db_delete', [
64
+ 'object' => $object,
65
+ 'time' => microtime(true) - $start
66
+ ]);
67
+
68
+ return $result;
69
+ }
70
+ }
app/design/frontend/base/default/layout/ecocode_profiler.xml ADDED
@@ -0,0 +1,120 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <layout>
3
+ <profiler_default>
4
+ <block type="page/html" name="root" output="toHtml" template="ecocode_profiler/layout.phtml">
5
+ <block type="core/template" name="profiler_js" template="ecocode_profiler/profiler/base.js.phtml"/>
6
+ <block type="core/template" name="profiler_css" template="ecocode_profiler/profiler/base.css.phtml"/>
7
+ <block type="core/template" name="summery" template="ecocode_profiler/profiler/summery.phtml"/>
8
+ <block type="core/text_list" name="left" as="left" translate="label">
9
+ <label>Left Column</label>
10
+ <block type="ecocode_profiler/profiler_sidebar" name="sidebar" template="ecocode_profiler/layout/sidebar.phtml">
11
+ <block type="ecocode_profiler/profiler_sidebar_menu" name="menu" template="ecocode_profiler/layout/sidebar/menu.phtml">
12
+ <block name="request" type="ecocode_profiler/collector_base" template="ecocode_profiler/collector/request/menu.phtml"/>
13
+ <block name="mysql" type="ecocode_profiler/collector_base" template="ecocode_profiler/collector/mysql/menu.phtml"/>
14
+ <block name="event" type="ecocode_profiler/collector_base" template="ecocode_profiler/collector/event/menu.phtml"/>
15
+ <block name="layout" type="ecocode_profiler/collector_base" template="ecocode_profiler/collector/layout/menu.phtml"/>
16
+ <block name="translation" type="ecocode_profiler/collector_base" template="ecocode_profiler/collector/translation/menu.phtml"/>
17
+ <block name="model" type="ecocode_profiler/collector_base" template="ecocode_profiler/collector/model/menu.phtml"/>
18
+ <block name="rewrite" type="ecocode_profiler/collector_base" template="ecocode_profiler/collector/rewrite/menu.phtml"/>
19
+ <block name="log" type="ecocode_profiler/collector_base" template="ecocode_profiler/collector/log/menu.phtml"/>
20
+ <block name="cache" type="ecocode_profiler/collector_base" template="ecocode_profiler/collector/cache/menu.phtml"/>
21
+ <block name="config" type="ecocode_profiler/collector_base" template="ecocode_profiler/collector/config/menu.phtml"/>
22
+ </block>
23
+ </block>
24
+ </block>
25
+ <block type="core/text_list" name="content" as="content" translate="label">
26
+ <label>Main Content Area</label>
27
+ </block>
28
+ </block>
29
+
30
+
31
+ </profiler_default>
32
+
33
+ <profiler_index_toolbar>
34
+ <block type="ecocode_profiler/toolbar" name="root" output="toHtml" template="ecocode_profiler/toolbar.phtml">
35
+ <block name="profiler.mysql.toolbar" type="ecocode_profiler/collector_base" template="ecocode_profiler/collector/mysql/toolbar.phtml"/>
36
+ <block name="profiler.request.toolbar" type="ecocode_profiler/collector_base" template="ecocode_profiler/collector/request/toolbar.phtml"/>
37
+ <block name="profiler.time.toolbar" type="ecocode_profiler/collector_base" template="ecocode_profiler/collector/time/toolbar.phtml"/>
38
+ <block name="profiler.translation.toolbar" type="ecocode_profiler/collector_base" template="ecocode_profiler/collector/translation/toolbar.phtml"/>
39
+ <block name="profiler.ajax.toolbar" type="ecocode_profiler/collector_base" template="ecocode_profiler/collector/ajax/toolbar.phtml"/>
40
+ <block name="profiler.model.toolbar" type="ecocode_profiler/collector_base" template="ecocode_profiler/collector/model/toolbar.phtml"/>
41
+ <block name="profiler.cache.toolbar" type="ecocode_profiler/collector_base" template="ecocode_profiler/collector/cache/toolbar.phtml"/>
42
+ <block name="profiler.memory.toolbar" type="ecocode_profiler/collector_base" template="ecocode_profiler/collector/memory/toolbar.phtml"/>
43
+ <block name="profiler.rewrite.toolbar" type="ecocode_profiler/collector_base" template="ecocode_profiler/collector/rewrite/toolbar.phtml"/>
44
+ <block name="profiler.log.toolbar" type="ecocode_profiler/collector_base" template="ecocode_profiler/collector/log/toolbar.phtml"/>
45
+ <block name="profiler.customer.toolbar" type="ecocode_profiler/collector_base" template="ecocode_profiler/collector/customer/toolbar.phtml"/>
46
+ <block name="profiler.layout.toolbar" type="ecocode_profiler/collector_base" template="ecocode_profiler/collector/layout/toolbar.phtml"/>
47
+ <block name="profiler.config.toolbar" type="ecocode_profiler/collector_base" template="ecocode_profiler/collector/config/toolbar.phtml"/>
48
+ </block>
49
+
50
+ </profiler_index_toolbar>
51
+
52
+
53
+ <profiler_index_searchresults>
54
+ <reference name="content">
55
+ <block type="core/template" name="profiler.search.summery" template="ecocode_profiler/profiler/search/summery.phtml"/>
56
+ <block type="core/template" name="profiler.search.results" template="ecocode_profiler/profiler/search/results.phtml"/>
57
+ </reference>
58
+ </profiler_index_searchresults>
59
+
60
+
61
+ <collector_mysql>
62
+ <reference name="content">
63
+ <block name="panel" type="ecocode_profiler/collector_mysql_panel" template="ecocode_profiler/collector/mysql/panel.phtml"/>
64
+ </reference>
65
+ </collector_mysql>
66
+
67
+ <collector_request>
68
+ <reference name="content">
69
+ <block name="panel" type="ecocode_profiler/collector_base" template="ecocode_profiler/collector/request/panel.phtml"/>
70
+ </reference>
71
+ </collector_request>
72
+
73
+ <collector_translation>
74
+ <reference name="content">
75
+ <block name="panel" type="ecocode_profiler/collector_translation_panel" template="ecocode_profiler/collector/translation/panel.phtml"/>
76
+ </reference>
77
+ </collector_translation>
78
+
79
+ <collector_config>
80
+ <reference name="content">
81
+ <block name="panel" type="ecocode_profiler/collector_base" template="ecocode_profiler/collector/config/panel.phtml"/>
82
+ </reference>
83
+ </collector_config>
84
+
85
+ <collector_rewrite>
86
+ <reference name="content">
87
+ <block name="panel" type="ecocode_profiler/collector_base" template="ecocode_profiler/collector/rewrite/panel.phtml"/>
88
+ </reference>
89
+ </collector_rewrite>
90
+
91
+ <collector_event>
92
+ <reference name="content">
93
+ <block name="panel" type="ecocode_profiler/collector_base" template="ecocode_profiler/collector/event/panel.phtml"/>
94
+ </reference>
95
+ </collector_event>
96
+
97
+ <collector_layout>
98
+ <reference name="content">
99
+ <block name="panel" type="ecocode_profiler/collector_layout_panel" template="ecocode_profiler/collector/layout/panel.phtml"/>
100
+ </reference>
101
+ </collector_layout>
102
+
103
+ <collector_cache>
104
+ <reference name="content">
105
+ <block name="panel" type="ecocode_profiler/collector_base" template="ecocode_profiler/collector/cache/panel.phtml"/>
106
+ </reference>
107
+ </collector_cache>
108
+
109
+ <collector_log>
110
+ <reference name="content">
111
+ <block name="panel" type="ecocode_profiler/collector_log_panel" template="ecocode_profiler/collector/log/panel.phtml"/>
112
+ </reference>
113
+ </collector_log>
114
+
115
+ <collector_model>
116
+ <reference name="content">
117
+ <block name="panel" type="ecocode_profiler/collector_base" template="ecocode_profiler/collector/model/panel.phtml"/>
118
+ </reference>
119
+ </collector_model>
120
+ </layout>
app/design/frontend/base/default/template/ecocode_profiler/back-trace.phtml ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /** @var Ecocode_Profiler_Block_BackTrace $this */
3
+
4
+ /** @var Ecocode_Profiler_Helper_ValueExporter $valueExport */
5
+ $valueExport = $this->helper('ecocode_profiler/valueExporter');
6
+
7
+ $trace = $this->getTrace();
8
+ ?>
9
+ <?php if ($trace): ?>
10
+ <div id="stack-<?php echo $this->getTraceId() ?>" class="hidden">
11
+ <strong class="font-normal text-small">Trace</strong>:
12
+ <ul class="sf-call-stack ">
13
+
14
+ <?php foreach ($trace as $item): ?>
15
+ <li>
16
+ <?php echo isset($item['class']) ? $item['class'] . '::' : '' ?><?php echo $item['function'] ?><br>
17
+ <?php if (isset($item['file'])): ?>
18
+ <small><?php echo $item['file'] ?>::<?php echo $item['line'] ?></small>
19
+ <?php endif; ?>
20
+ </li>
21
+ <?php endforeach; ?>
22
+ </ul>
23
+ </div>
24
+ <?php endif; ?>
app/design/frontend/base/default/template/ecocode_profiler/bag.phtml ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /** @var Ecocode_Profiler_Block_Bag $this */
3
+
4
+ /** @var Ecocode_Profiler_Helper_ValueExporter $valueExport */
5
+ $valueExport = $this->helper('ecocode_profiler/valueExporter');
6
+
7
+ ?>
8
+
9
+ <table class="<?php echo $this->getData('class')?>">
10
+ <thead>
11
+ <?php $labels = $this->getLabels(); ?>
12
+ <tr>
13
+ <th scope="col" class="key"><?php echo isset($labels[0]) ? $labels[0] : 'Key' ?></th>
14
+ <th scope="col"><?php echo isset($labels[1]) ? $labels[1] : 'Value' ?></th>
15
+ </tr>
16
+ </thead>
17
+ <tbody>
18
+ <?php if ($bag = $this->getBag()): ?>
19
+
20
+ <?php foreach($bag->keys() as $key): ?>
21
+ <tr>
22
+ <th><?php echo $key ?></th>
23
+ <td><?php echo $valueExport->exportValue($bag->get($key)) ?></td>
24
+ </tr>
25
+
26
+ <?php endforeach;?>
27
+ <?php else: ?>
28
+ <tr>
29
+ <td colspan="2">(no data)</td>
30
+ </tr>
31
+ <?php endif;?>
32
+ </tbody>
33
+ </table>
app/design/frontend/base/default/template/ecocode_profiler/collector/ajax/toolbar.phtml ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /** @var Ecocode_Profiler_Model_Collector_MysqlDataCollector $collector */
3
+ $collector = $this->getCollector();
4
+ $token = $this->getToken();
5
+ ?>
6
+
7
+
8
+ <div class="sf-toolbar-block sf-toolbar-block-<?php echo $collector->getName()?> sf-toolbar-status-normal">
9
+ <div class="sf-toolbar-icon">
10
+ <svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="24" height="24" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
11
+ <path fill="#AAAAAA" d="M9.8,18l-3.8,4.4c-0.3,0.3-0.8,0.4-1.1,0L1,18c-0.4-0.5-0.1-1,0.5-1H3V6.4C3,3.8,5.5,2,8.2,2h3.9
12
+ c1.1,0,2,0.9,2,2s-0.9,2-2,2H8.2C7.7,6,7,6,7,6.4V17h2.2C9.8,17,10.2,17.5,9.8,18z M23,6l-3.8-4.5c-0.3-0.3-0.8-0.3-1.1,0L14.2,6
13
+ c-0.4,0.5-0.1,1,0.5,1H17v10.6c0,0.4-0.7,0.4-1.2,0.4h-3.9c-1.1,0-2,0.9-2,2s0.9,2,2,2h3.9c2.6,0,5.2-1.8,5.2-4.4V7h1.5
14
+ C23.1,7,23.4,6.5,23,6z"/>
15
+ </svg>
16
+ <span class="sf-toolbar-value sf-toolbar-ajax-requests">0</span>
17
+
18
+ </div>
19
+ <div class="sf-toolbar-info">
20
+ <div class="sf-toolbar-info-piece">
21
+ <b class="sf-toolbar-ajax-info"></b>
22
+ </div>
23
+ <div class="sf-toolbar-info-piece">
24
+ <table class="sf-toolbar-ajax-requests">
25
+ <thead>
26
+ <tr>
27
+ <th>Method</th>
28
+ <th>Status</th>
29
+ <th>URL</th>
30
+ <th>Time</th>
31
+ <th>Profile</th>
32
+ </tr>
33
+ </thead>
34
+ <tbody class="sf-toolbar-ajax-request-list"></tbody>
35
+ </table>
36
+ </div>
37
+ </div>
38
+ </div>
app/design/frontend/base/default/template/ecocode_profiler/collector/base/menu.phtml ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /** @var Ecocode_Profiler_Model_Collector_DataCollectorInterface $collector */
3
+ $collector = $this->getCollector();
4
+ ?>
5
+
6
+ <span class="label">
7
+ <strong><?php echo ucwords($collector->getName()) ?></strong>
8
+ </span>
app/design/frontend/base/default/template/ecocode_profiler/collector/cache/menu.phtml ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ <span class="label">
2
+ <span class="icon">
3
+ <svg width="24" height="24" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg">
4
+ <path fill="#AAAAAA" d="M1168 1216q0 33-23.5 56.5t-56.5 23.5-56.5-23.5-23.5-56.5 23.5-56.5 56.5-23.5 56.5 23.5 23.5 56.5zm256 0q0 33-23.5 56.5t-56.5 23.5-56.5-23.5-23.5-56.5 23.5-56.5 56.5-23.5 56.5 23.5 23.5 56.5zm112 160v-320q0-13-9.5-22.5t-22.5-9.5h-1216q-13 0-22.5 9.5t-9.5 22.5v320q0 13 9.5 22.5t22.5 9.5h1216q13 0 22.5-9.5t9.5-22.5zm-1230-480h1180l-157-482q-4-13-16-21.5t-26-8.5h-782q-14 0-26 8.5t-16 21.5zm1358 160v320q0 66-47 113t-113 47h-1216q-66 0-113-47t-47-113v-320q0-25 16-75l197-606q17-53 63-86t101-33h782q55 0 101 33t63 86l197 606q16 50 16 75z"/>
5
+ </svg>
6
+ </span>
7
+ <strong>Cache</strong>
8
+ </span>
app/design/frontend/base/default/template/ecocode_profiler/collector/cache/panel.phtml ADDED
@@ -0,0 +1,164 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /** @var Ecocode_Profiler_Block_Collector_Base $this */
3
+
4
+ /** @var Ecocode_Profiler_Model_Collector_CacheDataCollector $collector */
5
+ $collector = $this->getCollector();
6
+ $iconYes = '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="28" height="28" viewBox="0 0 12 12" enable-background="new 0 0 12 12" xml:space="preserve">
7
+ <path fill="#5E976E" d="M12,3.1c0,0.4-0.1,0.8-0.4,1.1L5.9,9.8c-0.3,0.3-0.6,0.4-1,0.4c-0.4,0-0.7-0.1-1-0.4L0.4,6.3
8
+ C0.1,6,0,5.6,0,5.2c0-0.4,0.2-0.7,0.4-0.9C0.6,4,1,3.9,1.3,3.9c0.4,0,0.8,0.1,1.1,0.4l2.5,2.5l4.7-4.7c0.3-0.3,0.7-0.4,1-0.4
9
+ c0.4,0,0.7,0.2,0.9,0.4C11.8,2.4,12,2.7,12,3.1z"/>
10
+ </svg>';
11
+ $iconNo = '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="28" height="28" viewBox="0 0 12 12" enable-background="new 0 0 12 12" xml:space="preserve">
12
+ <path fill="#B0413E" d="M10.4,8.4L8,6l2.4-2.4c0.8-0.8,0.7-1.6,0.2-2.2C10,0.9,9.2,0.8,8.4,1.6L6,4L3.6,1.6C2.8,0.8,2,0.9,1.4,1.4
13
+ C0.9,2,0.8,2.8,1.6,3.6L4,6L1.6,8.4C0.8,9.2,0.9,10,1.4,10.6c0.6,0.6,1.4,0.6,2.2-0.2L6,8l2.4,2.4c0.8,0.8,1.6,0.7,2.2,0.2
14
+ C11.1,10,11.2,9.2,10.4,8.4z"/>
15
+ </svg>';
16
+
17
+ $cacheTypes = Mage::app()->getCacheInstance()->getTypes();
18
+ ?>
19
+ <h2>Cache metrics</h2>
20
+
21
+ <div class="metrics">
22
+ <?php foreach ($collector->getStats() as $key => $value): ?>
23
+ <div class="metric">
24
+ <span class="value"><?php echo $value ?></span>
25
+ <span class="label"><?php echo uc_words($key) ?></span>
26
+ </div>
27
+
28
+ <?php endforeach; ?>
29
+
30
+ <div class="metric">
31
+ <span class="value"><?php echo sprintf('%0.2f', $collector->getTotalTime() * 1000) ?> ms</span>
32
+ <span class="label">Time</span>
33
+ </div>
34
+
35
+ </div>
36
+
37
+ <h2>Cache configuration</h2>
38
+ <table class="cache-table">
39
+ <thead>
40
+ <tr>
41
+ <th class="key">Id</th>
42
+ <th>Type</th>
43
+ <th>Run Status</th>
44
+ <th>Current Status</th>
45
+ <th class="text-right">
46
+ <a data-url="<?php echo Mage::getUrl('_profiler/cache/clearAll') ?>" class="btn btn-sm ajax-action">Clear
47
+ All</a>
48
+ </th>
49
+ </tr>
50
+ </thead>
51
+ <tbody>
52
+ <?php foreach ($collector->getCacheList() as $cache): ?>
53
+ <?php $currentStatus = $cacheTypes[$cache['id']]->getData('status'); ?>
54
+ <tr>
55
+ <td><?php echo $cache['id'] ?></td>
56
+ <td><?php echo $cache['cache_type'] ?></td>
57
+ <td>
58
+ <?php echo $cache['status'] ? $iconYes : $iconNo ?>
59
+ </td>
60
+ <td>
61
+ <?php echo $currentStatus ? $iconYes : $iconNo ?>
62
+ </td>
63
+ <td class="text-right">
64
+ <?php if ($currentStatus): ?>
65
+ <a href="#"
66
+ data-url="<?php echo Mage::getUrl('_profiler/cache/clear', ['types' => $cache['id']]) ?>"
67
+ class="btn btn-sm ajax-action">Clear</a>
68
+ <a href="#"
69
+ data-url="<?php echo Mage::getUrl('_profiler/cache/disable', ['types' => $cache['id']]) ?>"
70
+ class="btn btn-sm ajax-action">Disable</a>
71
+ <?php else: ?>
72
+ <a href="#"
73
+ data-url="<?php echo Mage::getUrl('_profiler/cache/enable', ['types' => $cache['id']]) ?>"
74
+ class="btn btn-sm ajax-action">Enable</a>
75
+ <?php endif; ?>
76
+ </td>
77
+ </tr>
78
+ <?php endforeach; ?>
79
+ </tbody>
80
+ </table>
81
+
82
+ <h2>
83
+ Cache Backend<br>
84
+ <small><?php echo $collector->getBackendName() ?></small>
85
+ </h2>
86
+ <table>
87
+ <thead>
88
+ <tr>
89
+ <th>Key</th>
90
+ <th>Time</th>
91
+ </tr>
92
+ </thead>
93
+ <tbody>
94
+ <?php foreach ($collector->getBackendOptions() as $key => $value): ?>
95
+ <tr>
96
+ <td class="nowrap"><?php echo $key ?> </td>
97
+ <td class="nowrap"><?php echo $value ?></td>
98
+ </tr>
99
+ <?php endforeach; ?>
100
+ </tbody>
101
+ </table>
102
+
103
+ <h2>Cache Calls</h2>
104
+ <table>
105
+ <thead>
106
+ <tr>
107
+ <th>#</th>
108
+ <th>Action</th>
109
+ <th style="width: 100%;">Id</th>
110
+ <th>Hit</th>
111
+ <th>Time</th>
112
+ </tr>
113
+ </thead>
114
+ <tbody>
115
+ <?php foreach ($collector->getCacheCalls() as $index => $call): ?>
116
+ <tr>
117
+ <td class="nowrap"><?php echo $index + 1 ?> </td>
118
+ <td><?php echo $call['action'] ?></td>
119
+ <td>
120
+ <?php echo isset($call['id']) ? $call['id'] : '-'; ?>
121
+ <?php if (!empty($call['tags'])): ?>
122
+ <br>
123
+ <small><strong>Tags:</strong> <?php echo implode(', ', $call['tags']) ?></small>
124
+ <?php endif; ?>
125
+ </td>
126
+ <td>
127
+ <?php if (isset($call['hit'])): ?>
128
+ <span class="label status-<?php echo $call['hit'] ? 'success' : 'error' ?>">
129
+ <?php echo $call['hit'] ? 'Hit' : 'Miss' ?>
130
+ </span>
131
+ <?php else: ?>
132
+ -
133
+ <?php endif ?>
134
+ </td>
135
+ <td class="nowrap"><?php echo sprintf('%0.2f', $call['time'] * 1000) ?> ms</td>
136
+ </tr>
137
+ <?php endforeach; ?>
138
+ </tbody>
139
+ </table>
140
+ <script>
141
+ (function () {
142
+ var actions = document.querySelectorAll('.cache-table .ajax-action');
143
+
144
+ for (var i = 0; i < actions.length; i++) {
145
+ (function () {
146
+
147
+ var button = actions[i],
148
+ url = button.getAttribute('data-url');
149
+
150
+ button.addEventListener('click', function (e) {
151
+ Sfjs.request(url, function () {
152
+ window.location.reload();
153
+ });
154
+ });
155
+ })();
156
+ }
157
+ })();
158
+ </script>
159
+ <style>
160
+ .cache-table td svg {
161
+ width: 16px;
162
+ height: 16px;
163
+ }
164
+ </style>
app/design/frontend/base/default/template/ecocode_profiler/collector/cache/toolbar.phtml ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /** @var Ecocode_Profiler_Model_Collector_CacheDataCollector $collector */
3
+ $collector = $this->getCollector();
4
+ $token = $this->getToken();
5
+
6
+ $cacheList = $collector->getCacheList();
7
+ $cacheTypes = Mage::app()->getCacheInstance()->getTypes();
8
+ ?>
9
+
10
+ <div
11
+ class="sf-toolbar-block sf-toolbar-block-<?php echo $collector->getName() ?>">
12
+ <a target="_blank"
13
+ href="<?php echo Mage::helper('ecocode_profiler')->getCollectorUrl($token, $collector); ?>">
14
+ <div class="sf-toolbar-icon">
15
+ <svg width="24" height="24" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg">
16
+ <path fill="#AAAAAA" d="M1168 1216q0 33-23.5 56.5t-56.5 23.5-56.5-23.5-23.5-56.5 23.5-56.5 56.5-23.5 56.5 23.5 23.5 56.5zm256 0q0 33-23.5 56.5t-56.5 23.5-56.5-23.5-23.5-56.5 23.5-56.5 56.5-23.5 56.5 23.5 23.5 56.5zm112 160v-320q0-13-9.5-22.5t-22.5-9.5h-1216q-13 0-22.5 9.5t-9.5 22.5v320q0 13 9.5 22.5t22.5 9.5h1216q13 0 22.5-9.5t9.5-22.5zm-1230-480h1180l-157-482q-4-13-16-21.5t-26-8.5h-782q-14 0-26 8.5t-16 21.5zm1358 160v320q0 66-47 113t-113 47h-1216q-66 0-113-47t-47-113v-320q0-25 16-75l197-606q17-53 63-86t101-33h782q55 0 101 33t63 86l197 606q16 50 16 75z"/>
17
+ </svg>
18
+ <span class="sf-toolbar-value"><?php echo sprintf('%0.2f', $collector->getTotalTime() * 1000) ?> ms</span>
19
+ </div>
20
+ </a>
21
+ <div class="sf-toolbar-info">
22
+ <div class="sf-toolbar-info-group" style="float: left;">
23
+ <?php foreach ($cacheList as $cache): ?>
24
+ <?php $currentStatus = $cacheTypes[$cache['id']]->getData('status'); ?>
25
+ <div class="sf-toolbar-info-piece">
26
+ <b><?php echo uc_words($cache['id'], ' ')?></b>
27
+ <?php if($cache['status'] == 1): ?>
28
+ <span class="sf-toolbar-status sf-toolbar-status-green">Yes</span>
29
+ <?php else:?>
30
+ <span class="sf-toolbar-status">No</span>
31
+ <?php endif;?>
32
+ &nbsp;
33
+ <?php if ($currentStatus): ?>
34
+ <a href="#"
35
+ data-url="<?php echo Mage::getUrl('_profiler/cache/clear', ['types' => $cache['id']]) ?>"
36
+ class="btn btn-sm ajax-action">Clear</a> /
37
+ <a href="#"
38
+ data-url="<?php echo Mage::getUrl('_profiler/cache/disable', ['types' => $cache['id']]) ?>"
39
+ class="btn btn-sm ajax-action">Disable</a>
40
+ <?php else: ?>
41
+ <a href="#"
42
+ data-url="<?php echo Mage::getUrl('_profiler/cache/enable', ['types' => $cache['id']]) ?>"
43
+ class="btn btn-sm ajax-action">Enable</a>
44
+ <?php endif; ?>
45
+ </div>
46
+ <?php endforeach; ?>
47
+ </div>
48
+ <div class="sf-toolbar-info-group" >
49
+ <div class="sf-toolbar-info-piece">
50
+ <b>Cache calls</b>
51
+ <span class="sf-toolbar-status"><?php echo $collector->getStats('total') ?></span>
52
+ </div>
53
+
54
+ <div class="sf-toolbar-info-piece">
55
+ <b>Time</b>
56
+ <span><?php echo sprintf('%0.2f', $collector->getTotalTime() * 1000) ?> ms</span>
57
+ </div>
58
+ </div>
59
+
60
+ </div>
61
+
62
+ </div>
app/design/frontend/base/default/template/ecocode_profiler/collector/config/menu.phtml ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <span class="label">
2
+ <span class="icon">
3
+ <svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="24" height="24" viewBox="0 0 24 24"
4
+ enable-background="new 0 0 24 24" xml:space="preserve">
5
+ <path fill="#AAAAAA"
6
+ d="M11,5.1C11,3.4,9.6,2,7.9,2H5.1C3.4,2,2,3.4,2,5.1v12.9C2,19.6,3.4,21,5.1,21h2.9c1.7,0,3.1-1.4,3.1-3.1V5.1z M5.2,4h2.7C8.4,4,9,4.8,9,5.3V11H4V5.3C4,4.8,4.6,4,5.2,4z M22,5.1C22,3.4,20.6,2,18.9,2h-2.9C14.4,2,13,3.4,13,5.1v12.9c0,1.7,1.4,3.1,3.1,3.1h2.9c1.7,0,3.1-1.4,3.1-3.1V5.1z M16,4h2.8C19.4,4,20,4.8,20,5.3V8h-5V5.3C15,4.8,15.5,4,16,4z"/>
7
+ </svg>
8
+ </span>
9
+ <strong>Configuration</strong>
10
+ </span>
app/design/frontend/base/default/template/ecocode_profiler/collector/config/panel.phtml ADDED
@@ -0,0 +1,151 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /** @var Ecocode_Profiler_Block_Collector_Base $this */
3
+
4
+ /** @var Ecocode_Profiler_Model_Collector_ConfigDataCollector $collector */
5
+ $collector = $this->getCollector();
6
+ $iconYes = '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="28" height="28" viewBox="0 0 12 12" enable-background="new 0 0 12 12" xml:space="preserve">
7
+ <path fill="#5E976E" d="M12,3.1c0,0.4-0.1,0.8-0.4,1.1L5.9,9.8c-0.3,0.3-0.6,0.4-1,0.4c-0.4,0-0.7-0.1-1-0.4L0.4,6.3
8
+ C0.1,6,0,5.6,0,5.2c0-0.4,0.2-0.7,0.4-0.9C0.6,4,1,3.9,1.3,3.9c0.4,0,0.8,0.1,1.1,0.4l2.5,2.5l4.7-4.7c0.3-0.3,0.7-0.4,1-0.4
9
+ c0.4,0,0.7,0.2,0.9,0.4C11.8,2.4,12,2.7,12,3.1z"/>
10
+ </svg>';
11
+ $iconNo = '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="28" height="28" viewBox="0 0 12 12" enable-background="new 0 0 12 12" xml:space="preserve">
12
+ <path fill="#B0413E" d="M10.4,8.4L8,6l2.4-2.4c0.8-0.8,0.7-1.6,0.2-2.2C10,0.9,9.2,0.8,8.4,1.6L6,4L3.6,1.6C2.8,0.8,2,0.9,1.4,1.4
13
+ C0.9,2,0.8,2.8,1.6,3.6L4,6L1.6,8.4C0.8,9.2,0.9,10,1.4,10.6c0.6,0.6,1.4,0.6,2.2-0.2L6,8l2.4,2.4c0.8,0.8,1.6,0.7,2.2,0.2
14
+ C11.1,10,11.2,9.2,10.4,8.4z"/>
15
+ </svg>';
16
+
17
+ ?>
18
+ <h2>PHP Configuration</h2>
19
+
20
+ <div class="metrics">
21
+ <div class="metric">
22
+ <span class="value"><?php echo $collector->getPhpVersion() ?></span>
23
+ <span class="label">PHP version</span>
24
+ </div>
25
+
26
+ <div class="metric">
27
+ <span class="value"><?php echo $collector->hasAccelerator() ? $iconYes : $iconNo; ?></span>
28
+ <span class="label">PHP acceleration</span>
29
+ </div>
30
+
31
+ <div class="metric">
32
+ <span class="value"><?php echo $collector->hasXDebug() ? $iconYes : $iconNo; ?></span>
33
+ <span class="label">Xdebug</span>
34
+ </div>
35
+ </div>
36
+
37
+ <div class="metrics metrics-horizontal">
38
+ <div class="metric">
39
+ <span
40
+ <span class="value"><?php echo $collector->hasZendOpcache() ? $iconYes : $iconNo; ?></span>
41
+ <span class="label">OPcache</span>
42
+ </div>
43
+
44
+ <div class="metric">
45
+ <span class="value"><?php echo $collector->hasApc() ? $iconYes : $iconNo; ?></span>
46
+ <span class="label">APC</span>
47
+ </div>
48
+
49
+ <div class="metric">
50
+ <span class="value"><?php echo $collector->hasXCache() ? $iconYes : $iconNo; ?></span>
51
+ <span class="label">XCache</span>
52
+ </div>
53
+
54
+ <div class="metric">
55
+ <span
56
+ <span class="value"><?php echo $collector->hasEAccelerator() ? $iconYes : $iconNo; ?></span>
57
+ <span class="label">EAccelerator</span>
58
+ </div>
59
+ </div>
60
+
61
+ <p>
62
+ <a href="<?php echo Mage::getUrl('_profiler/index/phpinfo') ?>">View full PHP configuration</a>
63
+ </p>
64
+
65
+
66
+ <h2>Magento</h2>
67
+ <table>
68
+ <thead>
69
+ <tr>
70
+ <th class="key">Key</th>
71
+ <th>Value</th>
72
+ </tr>
73
+ </thead>
74
+ <tbody>
75
+ <tr>
76
+ <td>Admin Url</td>
77
+ <td><?php $adminUrl = Mage::helper('adminhtml')->getUrl('adminhtml'); ?>
78
+ <a href="<?php echo $adminUrl ?>"><?php echo $adminUrl ?></a>
79
+ </td>
80
+ </tr>
81
+ <tr>
82
+ <td>Website</td>
83
+ <td><?php echo $collector->getWebsiteName() ?> (<?php echo $collector->getWebsiteCode() ?>)</td>
84
+ </tr>
85
+ <tr>
86
+ <td>Store</td>
87
+ <td><?php echo $collector->getStoreName() ?> (<?php echo $collector->getStoreCode() ?>)</td>
88
+ </tr>
89
+ </tbody>
90
+ </table>
91
+
92
+
93
+ <h2>Modules</h2>
94
+ <?php $activeModules = $collector->geModulesByState(true); ?>
95
+ <?php $inActiveModules = $collector->geModulesByState(false); ?>
96
+ <div class="sf-tabs">
97
+ <div class="tab">
98
+ <h3 class="tab-title">Enabled Modules
99
+ <small>(<?php echo count($activeModules) ?>)</small>
100
+ </h3>
101
+
102
+
103
+ <div class="tab-content">
104
+ <table>
105
+ <thead>
106
+ <tr>
107
+ <th>Module</th>
108
+ <th>Namespace</th>
109
+ <th>Version</th>
110
+ </tr>
111
+ </thead>
112
+ <tbody>
113
+ <?php foreach ($activeModules as $name => $data): ?>
114
+ <tr>
115
+ <td><?php echo $name ?></td>
116
+ <td><?php echo $data['codePool'] ?></td>
117
+ <td><?php echo isset($data['version']) ? $data['version'] : '?' ?></td>
118
+ </tr>
119
+
120
+ <?php endforeach; ?>
121
+ </tbody>
122
+ </table>
123
+ </div>
124
+ </div>
125
+ <div class="tab">
126
+ <h3 class="tab-title">Disables Modules
127
+ <small>(<?php echo count($inActiveModules) ?>)</small>
128
+ </h3>
129
+
130
+
131
+ <div class="tab-content">
132
+ <table>
133
+ <thead>
134
+ <tr>
135
+ <th>Module</th>
136
+ <th>Namespace</th>
137
+ </tr>
138
+ </thead>
139
+ <tbody>
140
+ <?php foreach ($inActiveModules as $name => $data): ?>
141
+ <tr>
142
+ <td><?php echo $name ?></td>
143
+ <td><?php echo isset($data['codePool']) ? $data['codePool'] : '?' ?></td>
144
+ </tr>
145
+
146
+ <?php endforeach; ?>
147
+ </tbody>
148
+ </table>
149
+ </div>
150
+ </div>
151
+ </div>
app/design/frontend/base/default/template/ecocode_profiler/collector/config/toolbar.phtml ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /** @var Ecocode_Profiler_Model_Collector_ConfigDataCollector $collector */
3
+ $collector = $this->getCollector();
4
+ $token = $this->getToken();
5
+ ?>
6
+
7
+
8
+ <div
9
+ class="sf-toolbar-block sf-toolbar-block-<?php echo $collector->getName() ?> sf-toolbar-status-normal sf-toolbar-block-right">
10
+ <div class="sf-toolbar-icon">
11
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="svgMageLogo" width="24" xml:space="preserve" height="24" viewBox="0 0 53.692 62" baseProfile="" version="1.1" y="0px" x="0px">
12
+ <g fill="#AAA">
13
+ <path d="m26.845 8.857"/><polygon points="53.692 15.5 53.692 46.5 46.021 50.929 46.021 19.929 26.845 8.857 7.67 19.928 7.67 50.929 0 46.5 0 15.5 26.845 0"/><polygon points="26.847 62 15.341 55.356 15.341 24.357 23.011 19.928 23.011 50.929 26.845 53.257 30.682 50.929 30.682 19.929 38.353 24.357 38.353 55.356"/>
14
+ </g>
15
+ </svg>
16
+ <span class="sf-toolbar-value"><?php echo $collector->getMagentoVersion() ?></span>
17
+
18
+ </div>
19
+ <div class="sf-toolbar-info">
20
+ <div class="sf-toolbar-info-group">
21
+
22
+ <div class="sf-toolbar-info-piece">
23
+ <b>Website</b>
24
+ <span><?php echo $collector->getWebsiteName() ?> (<?php echo $collector->getWebsiteCode() ?>) </span>
25
+ </div>
26
+
27
+ <div class="sf-toolbar-info-piece">
28
+ <b>Store</b>
29
+ <span><?php echo $collector->getStoreName() ?> (<?php echo $collector->getStoreCode() ?>) </span>
30
+ </div>
31
+
32
+ <div class="sf-toolbar-info-piece">
33
+ <b>Profiler token</b>
34
+ <span>
35
+ <?php $profilerUrl = Mage::helper('ecocode_profiler')->getUrl($collector->getToken()) ?>
36
+ <a href="<?php echo $profilerUrl?>"><?php echo $collector->getToken()?></a>
37
+ </span>
38
+ </div>
39
+
40
+ <div class="sf-toolbar-info-piece">
41
+ <b>Admin Url</b>
42
+ <span>
43
+ <?php $adminUrl = Mage::helper('adminhtml')->getUrl('adminhtml'); ?>
44
+ <a href="<?php echo $adminUrl?>">Admin</a>
45
+ </span>
46
+ </div>
47
+
48
+ <div class="sf-toolbar-info-piece">
49
+ <b>Developermode</b>
50
+ <span>
51
+ <?php echo $collector->isDeveloperMode() ? 'on' : 'off'; ?>
52
+ </span>
53
+ </div>
54
+ </div>
55
+
56
+ <div class="sf-toolbar-info-group">
57
+ <div class="sf-toolbar-info-piece sf-toolbar-info-php">
58
+ <b>PHP version</b>
59
+ <span>
60
+ <?php echo $collector->getPhpVersion() ?>
61
+ <a href="<?php echo Mage::getUrl('_profiler/index/phpinfo') ?> ">View phpinfo()</a>
62
+ </span>
63
+ </div>
64
+
65
+ <div class="sf-toolbar-info-piece sf-toolbar-info-php-ext">
66
+ <b>PHP Extensions</b>
67
+ <span
68
+ class="sf-toolbar-status sf-toolbar-status-<?php echo $collector->hasXDebug() ? 'green' : 'red' ?>">xdebug</span>
69
+ <span
70
+ class="sf-toolbar-status sf-toolbar-status-<?php echo $collector->hasAccelerator() ? 'green' : 'red' ?>">accel</span>
71
+ </div>
72
+
73
+ <div class="sf-toolbar-info-piece">
74
+ <b>PHP SAPI</b>
75
+ <span><?php echo $collector->getSapiName() ?></span>
76
+ </div>
77
+ </div>
78
+ </div>
79
+ </div>
app/design/frontend/base/default/template/ecocode_profiler/collector/customer/toolbar.phtml ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /** @var Ecocode_Profiler_Model_Collector_CustomerDataCollector $collector */
3
+ $collector = $this->getCollector();
4
+ $token = $this->getToken();
5
+ ?>
6
+
7
+
8
+ <div
9
+ class="sf-toolbar-block sf-toolbar-block-<?php echo $collector->getName() ?>">
10
+ <div class="sf-toolbar-icon">
11
+ <svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="24" height="24" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
12
+ <path fill="#AAAAAA" d="M21,20.4V22H3v-1.6c0-3.7,2.4-6.9,5.8-8c-1.7-1.1-2.9-3-2.9-5.2c0-3.4,2.7-6.1,6.1-6.1s6.1,2.7,6.1,6.1c0,2.2-1.2,4.1-2.9,5.2C18.6,13.5,21,16.7,21,20.4z"/>
13
+ </svg>
14
+ <span class="sf-toolbar-value">
15
+ <?php if ($collector->isLoggedIn()): ?>
16
+ <?php echo $collector->getCustomerEmail(); ?>
17
+ <?php else: ?>
18
+ n/a
19
+ <?php endif; ?>
20
+ </span>
21
+
22
+ </div>
23
+ <div class="sf-toolbar-info">
24
+ <?php if ($collector->isLoggedIn()): ?>
25
+ <div class="sf-toolbar-info-piece">
26
+ <b>Logged in as</b>
27
+ <span><?php echo $collector->getCustomerEmail(); ?></span>
28
+ </div>
29
+ <div class="sf-toolbar-info-piece">
30
+ <b>Name</b>
31
+ <span><?php echo $collector->getCustomerName(); ?></span>
32
+ </div>
33
+ <?php endif; ?>
34
+
35
+ <div class="sf-toolbar-info-piece">
36
+ <b>Customer Group</b>
37
+ <span><?php echo $collector->getGroupCode(); ?> (Id: <?php echo $collector->getGroupId(); ?>) </span>
38
+ </div>
39
+
40
+ <div class="sf-toolbar-info-piece">
41
+ <b>Tax Class</b>
42
+ <span><?php echo $collector->getTaxClassName(); ?> (Id: <?php echo $collector->getTaxClassId(); ?>) </span>
43
+ </div>
44
+ </div>
45
+ </div>
app/design/frontend/base/default/template/ecocode_profiler/collector/event/menu.phtml ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <span class="label">
2
+ <span class="icon">
3
+ <svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="24" height="24" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
4
+ <path fill="#AAAAAA" d="M19.2,20.8c0.4,0.7,0.1,1.6-0.6,2c-0.2,0.1-0.5,0.2-0.7,0.2c-0.5,0-1-0.3-1.3-0.8l-3.7-6.7
5
+ c-0.3,0.1-0.7,0.1-1,0.1c-0.3,0-0.6,0-0.9-0.1l-3.7,6.7C6.9,22.7,6.4,23,5.8,23c-0.2,0-0.5-0.1-0.7-0.2c-0.7-0.4-1-1.3-0.6-2
6
+ l3.8-6.9c-0.5-0.7-0.9-1.6-0.9-2.6C7.5,8.9,9.4,7,11.8,7s4.3,1.9,4.3,4.3c0,0.9-0.3,1.8-0.8,2.5L19.2,20.8z M5.2,11
7
+ C5.2,11,5.2,11,5.2,11c0.6,0,1-0.3,1-0.8c0-2.1,1.6-3.8,3.7-4.1c0.5-0.1,0.9-0.6,0.8-1.2C10.6,4.4,10.1,4,9.6,4
8
+ c-3.1,0.5-5.3,3-5.3,6.1C4.2,10.7,4.7,11,5.2,11z M13.6,6c2.1,0.3,3.7,2.1,3.8,4.2c0,0.5,0.5,0.8,1,0.8c0,0,0,0,0,0
9
+ c0.6,0,1-0.3,1-0.8c0-3.1-2.4-5.6-5.5-6.1c-0.5-0.1-1.1,0.3-1.1,0.8C12.6,5.5,13,5.9,13.6,6z M9,3c0.5-0.1,0.9-0.6,0.8-1.1
10
+ C9.7,1.3,9.2,1,8.7,1.1C4.5,1.8,1.4,5.5,1.3,9.8c0,0.6,0.4,1.2,1,1.2c0,0,0,0,0,0c0.5,0,1-0.6,1-1.2C3.3,6.5,5.7,3.5,9,3z M14.7,1
11
+ c-0.5-0.1-1.1,0.3-1.1,0.9S13.9,3,14.4,3c3.3,0.5,5.8,3.4,5.8,6.8c0,0.5,0.5,1.2,1,1.2c0,0,0,0,0,0c0.6,0,1-0.7,1-1.2
12
+ C22.2,5.5,19,1.6,14.7,1z"/>
13
+ </svg>
14
+
15
+ </span>
16
+ <strong>Events</strong>
17
+ </span>
app/design/frontend/base/default/template/ecocode_profiler/collector/event/panel.phtml ADDED
@@ -0,0 +1,116 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /** @var Ecocode_Profiler_Block_Collector_Base $this */
4
+
5
+ /** @var Ecocode_Profiler_Model_Collector_EventDataCollector $collector */
6
+ $collector = $this->getCollector();
7
+
8
+ $eventsFired = $collector->getFiredEvents();
9
+ ?>
10
+ <h2>Events</h2>
11
+
12
+ <?php if (!$eventsFired): ?>
13
+ <div class="empty">
14
+ <p>No events have been recorded. Check that you are loading "AppDev"</p>
15
+ </div>
16
+ <?php else: ?>
17
+ <?php
18
+ $calledListeners = $collector->getCalledListeners()
19
+ ?>
20
+ <div class="sf-tabs">
21
+ <div class="tab">
22
+ <h3 class="tab-title">Events Fired <span class="badge"><?php echo count($eventsFired) ?></span></h3>
23
+ <div class="tab-content">
24
+ <table>
25
+ <thead>
26
+ <tr>
27
+ <th>Event</th>
28
+ <th>Observer</th>
29
+ <th>Count</th>
30
+ </tr>
31
+ </thead>
32
+ <tbody>
33
+
34
+ <?php foreach ($eventsFired as $index => $event): ?>
35
+ <tr>
36
+ <td>
37
+ <?php echo $event['name'] ?>
38
+ <?php if ($event['observer_count']): ?>
39
+ <a href="#" class="sf-toggle link-inverse text-small"
40
+ data-toggle-selector="#event-observer-<?php echo $index ?>"
41
+ data-toggle-alt-content="Hide observer">Show observer</a>
42
+ <div id="event-observer-<?php echo $index ?>" class="hidden">
43
+ <ul>
44
+ <?php foreach ($event['observer'] as $area => $observers):?>
45
+ <li>
46
+ <?php echo $area ?>
47
+ <table>
48
+ <thead>
49
+ <tr>
50
+ <th>Name</th>
51
+ <th>Type</th>
52
+ <th>Model</th>
53
+ <th>Method</th>
54
+ </tr>
55
+ </thead>
56
+ <?php foreach ($observers as $name => $observer):?>
57
+ <tr>
58
+ <td><?php echo $name ?></td>
59
+ <td><?php echo $observer['type'] ? $observer['type'] : 'singleton' ?></td>
60
+ <td><?php echo $observer['model'] ?></td>
61
+ <td><?php echo $observer['method'] ?></td>
62
+ </tr>
63
+ <?php endforeach;?>
64
+ </table>
65
+
66
+ </li>
67
+ <?php endforeach;?>
68
+ </ul>
69
+ </div>
70
+ <?php endif; ?>
71
+
72
+ </td>
73
+ <td>
74
+ <?php if ($event['observer_count']): ?>
75
+ <?php echo $event['observer_count'] ?>
76
+ <?php else: ?>
77
+ -
78
+ <?php endif; ?>
79
+ </td>
80
+ <td><?php echo $event['count'] ?></td>
81
+ </tr>
82
+
83
+ <?php endforeach; ?>
84
+ </tbody>
85
+
86
+ </table>
87
+ </div>
88
+ </div>
89
+
90
+ <div class="tab">
91
+ <h3 class="tab-title">Called Listeners <span class="badge"><?php echo count($calledListeners) ?></span></h3>
92
+
93
+ <div class="tab-content">
94
+ <table>
95
+ <thead>
96
+ <tr>
97
+ <th>Event</th>
98
+ <th>Listener</th>
99
+ </tr>
100
+ </thead>
101
+ <tbody>
102
+
103
+ <?php foreach ($calledListeners as $listener): ?>
104
+ <tr>
105
+ <td><?php echo $listener['event_name'] ?></td>
106
+ <td><?php echo $listener['class'] ?>:<?php echo $listener['method'] ?></td>
107
+ </tr>
108
+ <?php endforeach; ?>
109
+ </tbody>
110
+
111
+ </table>
112
+ </div>
113
+ </div>
114
+ </div>
115
+
116
+ <?php endif; ?>
app/design/frontend/base/default/template/ecocode_profiler/collector/layout/menu.phtml ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /** @var Ecocode_Profiler_Model_Collector_RewriteDataCollector $collector */
3
+ $collector = $this->getCollector();
4
+ ?>
5
+
6
+ <span class="label label-status-normal">
7
+ <span class="icon">
8
+ <svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="24" height="24" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
9
+ <path fill="#AAAAAA" d="M20.1,1H3.9C2.3,1,1,2.3,1,3.9v16.3C1,21.7,2.3,23,3.9,23h16.3c1.6,0,2.9-1.3,2.9-2.9V3.9
10
+ C23,2.3,21.7,1,20.1,1z M21,20.1c0,0.5-0.4,0.9-0.9,0.9H3.9C3.4,21,3,20.6,3,20.1V3.9C3,3.4,3.4,3,3.9,3h16.3C20.6,3,21,3.4,21,3.9
11
+ V20.1z M5,5h14v3H5V5z M5,10h3v9H5V10z M10,10h9v9h-9V10z"/>
12
+ </svg>
13
+ </span>
14
+ <strong>Layout</strong>
15
+ </span>
app/design/frontend/base/default/template/ecocode_profiler/collector/layout/panel.phtml ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /** @var Ecocode_Profiler_Block_Collector_Layout_Panel $this */
3
+
4
+ /** @var Ecocode_Profiler_Model_Collector_LayoutDataCollector $collector */
5
+ $collector = $this->getCollector();
6
+
7
+ ?>
8
+ <h2>Render Metrics </h2>
9
+ <div class="metrics">
10
+ <div class="metric">
11
+ <span class="value"><?php echo sprintf('%0.0f', $collector->getTotalRenderTime() * 1000)?> <span class="unit">ms</span></span>
12
+ <span class="label">Render time</span>
13
+ </div>
14
+
15
+
16
+ <div class="metric">
17
+ <span class="value"><?php echo $collector->getBlocksCreatedCount()?></span>
18
+ <span class="label">Block created</span>
19
+ </div>
20
+
21
+ <div class="metric">
22
+ <span class="value"><?php echo $collector->getBlocksRenderedCount()?></span>
23
+ <span class="label">Block rendered</span>
24
+ </div>
25
+ </div>
26
+
27
+ <h2>Layout Handler</h2>
28
+ <table>
29
+ <thead>
30
+ <tr>
31
+ <th scope="col">Handler</th>
32
+ </tr>
33
+ </thead>
34
+ <tbody>
35
+ <?php foreach($collector->getLayoutHandles() as $handle): ?>
36
+ <tr>
37
+ <td><?php echo $handle?></td>
38
+ </tr>
39
+ </tbody>
40
+ <?php endforeach;?>
41
+ </table>
42
+
43
+ <h2>Created but not rendered blocks</h2>
44
+ <table>
45
+ <thead>
46
+ <tr>
47
+ <th scope="col">Name</th>
48
+ <th scope="col">Module</th>
49
+ <th scope="col">Type</th>
50
+ <th scope="col">Class</th>
51
+ </tr>
52
+ </thead>
53
+ <tbody>
54
+ <?php foreach($collector->getBlocksNotRendered() as $block): ?>
55
+ <tr>
56
+ <td><?php echo $block['name']?></td>
57
+ <td><?php echo $block['module']?></td>
58
+ <td><?php echo $block['type']?></td>
59
+ <td><?php echo $block['class']?></td>
60
+ </tr>
61
+ </tbody>
62
+ <?php endforeach;?>
63
+ </table>
64
+
65
+
66
+ <h2>Rendering Call Graph</h2>
67
+ <div id="twig-dump">
68
+ <?php echo $this->renderTree(); ?>
69
+ </div>
app/design/frontend/base/default/template/ecocode_profiler/collector/layout/toolbar.phtml ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /** @var Ecocode_Profiler_Model_Collector_LayoutDataCollector $collector */
3
+ $collector = $this->getCollector();
4
+ $token = $this->getToken();
5
+ ?>
6
+
7
+ <div
8
+ class="sf-toolbar-block sf-toolbar-block-<?php echo $collector->getName() ?>">
9
+ <a target="_blank"
10
+ href="<?php echo Mage::helper('ecocode_profiler')->getCollectorUrl($token, $collector); ?>">
11
+ <div class="sf-toolbar-icon">
12
+ <svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="24" height="24" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
13
+ <path fill="#AAAAAA" d="M20.1,1H3.9C2.3,1,1,2.3,1,3.9v16.3C1,21.7,2.3,23,3.9,23h16.3c1.6,0,2.9-1.3,2.9-2.9V3.9
14
+ C23,2.3,21.7,1,20.1,1z M21,20.1c0,0.5-0.4,0.9-0.9,0.9H3.9C3.4,21,3,20.6,3,20.1V3.9C3,3.4,3.4,3,3.9,3h16.3C20.6,3,21,3.4,21,3.9
15
+ V20.1z M5,5h14v3H5V5z M5,10h3v9H5V10z M10,10h9v9h-9V10z"/>
16
+ </svg>
17
+ <span class="sf-toolbar-value"><?php echo sprintf('%0.0f', $collector->getTotalRenderTime() * 1000)?> <span class="unit">ms</span></span>
18
+ </div>
19
+ </a>
20
+ <div class="sf-toolbar-info">
21
+ <div class="sf-toolbar-info-group" >
22
+ <div class="sf-toolbar-info-piece">
23
+ <b>Layout handles</b>
24
+ <?php foreach ($collector->getLayoutHandles() as $handle): ?>
25
+ <?php echo $handle ?><br>
26
+ <?php endforeach; ?>
27
+ </div>
28
+ </div>
29
+ <div class="sf-toolbar-info-group" >
30
+ <div class="sf-toolbar-info-piece">
31
+ <b>Render Time</b>
32
+ <span><?php echo sprintf('%0.0f', $collector->getTotalRenderTime() * 1000)?> ms</span>
33
+ </div>
34
+
35
+
36
+ <div class="sf-toolbar-info-piece">
37
+ <b>Block created</b>
38
+ <span class="sf-toolbar-status"><?php echo $collector->getBlocksCreatedCount()?></span>
39
+ </div>
40
+
41
+
42
+ <div class="sf-toolbar-info-piece">
43
+ <b>Block rendered</b>
44
+ <span class="sf-toolbar-status"><?php echo $collector->getBlocksRenderedCount()?></span>
45
+ </div>
46
+ </div>
47
+ </div>
48
+ </div>
app/design/frontend/base/default/template/ecocode_profiler/collector/log/menu.phtml ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /** @var Ecocode_Profiler_Model_Collector_LogDataCollector $collector */
3
+ $collector = $this->getCollector();
4
+ $logCount = $collector->getLogCount();
5
+ $statusColor = $collector->countErrors() ? 'error' : ($collector->countDeprecations() ? 'warning' : '');
6
+ ?>
7
+
8
+ <span class="label label-status-<?php echo $statusColor ?>">
9
+ <span class="icon">
10
+ <svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="24" height="24" viewBox="0 0 24 24"
11
+ enable-background="new 0 0 24 24" xml:space="preserve">
12
+ <path fill="#AAAAAA" d="M21,4v13.8c0,2.7-2.5,5.2-5.2,5.2H6c-0.6,0-1-0.4-1-1s0.4-1,1-1h9.8c1.6,0,3.2-1.7,3.2-3.2V4
13
+ c0-0.6,0.4-1,1-1S21,3.4,21,4z M5.5,20C4.1,20,3,18.9,3,17.5V3.5C3,2.1,4.1,1,5.5,1h10.1C16.9,1,18,2.1,18,3.5v14.1
14
+ c0,1.4-1.1,2.5-2.5,2.5H5.5z M9,11.4C9,11.7,9.3,12,9.6,12h1.8c0.3,0,0.6-0.3,0.6-0.6V4.6C12,4.3,11.7,4,11.4,4H9.6
15
+ C9.3,4,9,4.3,9,4.6V11.4z M9,16.4C9,16.7,9.3,17,9.6,17h1.8c0.3,0,0.6-0.3,0.6-0.6v-1.8c0-0.3-0.3-0.6-0.6-0.6H9.6
16
+ C9.3,14,9,14.3,9,14.6V16.4z"></path>
17
+ </svg>
18
+ </span>
19
+ <strong>Log</strong>
20
+ <?php if ($collector->countErrors() || $collector->countDeprecations()): ?>
21
+ <span class="count">
22
+ <span><?php echo $collector->countErrors() ? $collector->countErrors() : $collector->countDeprecations() ?></span>
23
+ </span>
24
+ <?php endif ?>
25
+ </span>
app/design/frontend/base/default/template/ecocode_profiler/collector/log/panel.phtml ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /** @var Ecocode_Profiler_Block_Collector_Log_Panel $this */
3
+
4
+ /** @var Ecocode_Profiler_Model_Collector_LogDataCollector $collector */
5
+ $collector = $this->getCollector();
6
+ ?>
7
+
8
+ <h2>Log Messages</h2>
9
+
10
+ <?php if (Mage::getLogger() === false): ?>
11
+ <div class="empty status-error">
12
+ <p>No log messages available as the "monolog/monolog" is not installed please check the composer.json</p>
13
+ </div>
14
+ <?php elseif (!$collector->getLogs()): ?>
15
+ <div class="empty">
16
+ <p>No log messages available.</p>
17
+ </div>
18
+ <?php else: ?>
19
+ <div class="sf-tabs">
20
+ <?php $showLevel = true;?>
21
+ <?php $groups = $this->getLogGroups();?>
22
+ <div class="tab">
23
+ <h3 class="tab-title">Info. &amp; Errors <span class="badge"><?php echo count($groups['info_and_error']); ?></span></h3>
24
+
25
+ <div class="tab-content">
26
+ <?php if (!$groups['info_and_error']): ?>
27
+ <div class="empty">
28
+ <p>There are no log messages of this level.</p>
29
+ </div>
30
+ <?php else: ?>
31
+ <?php echo $this->renderLogTable($groups['info_and_error'], 'info', true); ?>
32
+ <?php endif;?>
33
+ </div>
34
+ </div>
35
+
36
+ <div class="tab">
37
+ <h3 class="tab-title">Deprecations <span class="badge"><?php echo $collector->countDeprecations()?></span></h3>
38
+
39
+ <div class="tab-content">
40
+ <?php if (empty($groups['deprecation'])): ?>
41
+ <div class="empty">
42
+ <p>There are no log messages about deprecated features.</p>
43
+ </div>
44
+ <?php else: ?>
45
+ <?php echo $this->renderLogTable($groups['deprecation'], 'deprecation', false, true); ?>
46
+ <?php endif;?>
47
+ </div>
48
+ </div>
49
+
50
+ <div class="tab">
51
+ <h3 class="tab-title">Debug <span class="badge"><?php echo count($groups['debug'])?></span></h3>
52
+
53
+ <div class="tab-content">
54
+ <?php if (empty($groups['debug'])): ?>
55
+ <div class="empty">
56
+ <p><p>There are no log messages of this level.</p>
57
+ </div>
58
+ <?php else: ?>
59
+ <?php echo $this->renderLogTable($groups['debug'], 'debug'); ?>
60
+ <?php endif;?>
61
+ </div>
62
+ </div>
63
+
64
+ <div class="tab">
65
+ <h3 class="tab-title">Silenced Errors <span class="badge"><?php echo $collector->countScreams() ?></span></h3>
66
+
67
+ <div class="tab-content">
68
+ <?php if (empty($groups['silenced'])): ?>
69
+ <div class="empty">
70
+ <p><p>There are no log messages of this level.</p>
71
+ </div>
72
+ <?php else: ?>
73
+ <?php echo $this->renderLogTable($groups['silenced'], 'silenced'); ?>
74
+ <?php endif;?>
75
+ </div>
76
+ </div>
77
+
78
+ <?php /* foreach ($this->getLogGroups() as $groupName => $logs): ?>
79
+ <div class="tab">
80
+ <h3 class="tab-title">
81
+ <?php echo $groupData['name'] ?>
82
+ <span class="badge"><?php echo count($groupData['logs']); ?></span><br>
83
+ </h3>
84
+
85
+ <div class="tab-content">
86
+ <small><?php echo $groupData['file']; ?></small>
87
+ <table class="logs">
88
+ <thead>
89
+ <tr>
90
+ <th>Level</th>
91
+ <th>Message</th>
92
+ </tr>
93
+ </thead>
94
+
95
+ <tbody>
96
+ <?php foreach ($groupData['logs'] as $index => $entry): ?>
97
+ <?php
98
+ $level = $entry['level'];
99
+ $cssClass = $this->getEntryCssClass($entry['level']);
100
+ ?>
101
+
102
+ <tr class="<?php echo $cssClass; ?>">
103
+ <td class="font-normal text-small">
104
+ <span
105
+ class="colored text-bold nowrap"><?php echo $this->getPriorityName($level) ?></span>
106
+ <!--<span class="text-muted nowrap newline">{{ log.timestamp|date('H:i:s') }}</span>-->
107
+ </td>
108
+
109
+ <td class="font-normal"><?php echo $entry['message'] ?></td>
110
+ </tr>
111
+ <?php endforeach; ?>
112
+ </tbody>
113
+ </table>
114
+ </div>
115
+ </div>
116
+ <?php endforeach; */?>
117
+ </div>
118
+ <?php endif; ?>
app/design/frontend/base/default/template/ecocode_profiler/collector/log/panel/log-table.phtml ADDED
@@ -0,0 +1,130 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /** @var Ecocode_Profiler_Block_Renderer_Log_LogTable $this */
3
+ $channelIsDefined = $this->isChannelDefined();
4
+ $showLevel = $this->getShowLevel();
5
+ $isDeprecation = $this->isDeprecation();
6
+
7
+ /** @var Ecocode_Profiler_Helper_Code $codeHelper */
8
+ $codeHelper = Mage::helper('ecocode_profiler/code');
9
+
10
+ /** @var Ecocode_Profiler_Helper_ValueExporter $valueExporter */
11
+ $valueExporter = Mage::helper('ecocode_profiler/valueExporter');
12
+ ?>
13
+ <table class="logs" xmlns="http://www.w3.org/1999/html">
14
+ <thead>
15
+ <tr>
16
+ <th><?php echo $showLevel ? 'Level' : 'Time' ?></th>
17
+ <?php echo $channelIsDefined ? '<th>Channel</th>' : '' ?>
18
+ <th style="width: 100%">Message</th>
19
+ </tr>
20
+ </thead>
21
+
22
+ <tbody>
23
+ <?php foreach ($this->getLogs() as $index => $log): ?>
24
+ <?php
25
+ $cssClass = '';
26
+ if (!$isDeprecation) {
27
+ switch ($log['priorityName']) {
28
+ case 'CRITICAL':
29
+ case 'ERROR':
30
+ case 'ALERT':
31
+ case 'EMERGENCY':
32
+ $cssClass = 'status-error';
33
+ break;
34
+ case 'WARNING':
35
+ case 'NOTICE':
36
+ $cssClass = 'status-warning';
37
+
38
+ }
39
+ }
40
+ ?>
41
+ <tr class="<?php echo $cssClass ?>">
42
+ <td class="font-normal text-small">
43
+ <?php if ($showLevel): ?>
44
+ <span class="colored text-bold nowrap"><?php echo $log['priorityName'] ?></span>
45
+ <?php endif ?>
46
+ <span class="text-muted nowrap newline"><?php echo date('H:i:s', $log['timestamp']) ?></span>
47
+ </td>
48
+
49
+ <?php if ($channelIsDefined): ?>
50
+ <td class="font-normal text-small text-bold nowrap"><?php echo $log['channel'] ?></td>
51
+ <?php endif; ?>
52
+
53
+ <td class="font-normal">
54
+ <?php echo $log['message']; ?>
55
+
56
+ <?php if ($this->isDeprecation()): ?>
57
+ <?php $stack = isset($log['context']['stack']) ? $log['context']['stack'] : []; ?>
58
+ <?php array_shift($stack); //remove the error handler from stack ?>
59
+ <?php $stackId = 'sf-call-stack-' . $this->getCategory() . '-' . $index; ?>
60
+
61
+ <?php if (isset($log['context']['errorCount'])): ?>
62
+ <span class="text-small text-bold">(<?php echo $log['context']['errorCount'] ?> times)</span>
63
+ <?php endif; ?>
64
+
65
+ <?php if ($stack): ?>
66
+ <button class="btn-link text-small sf-toggle" data-toggle-selector="#<?php echo $stackId ?>"
67
+ data-toggle-alt-content="Hide stack trace">Show stack trace
68
+ </button>
69
+ <?php endif; ?>
70
+
71
+ <ul class="sf-call-stack hidden" id="<?php echo $stackId ?>">
72
+ <?php foreach ($stack as $index => $call): ?>
73
+ <?php
74
+ $from = '-';
75
+ if (isset($call['class'])) {
76
+ $from = $codeHelper->abbrClass($call['class']) . '::' . $codeHelper->abbrMethod($call['function']);
77
+ } elseif (isset($call['function'])) {
78
+ $from = $codeHelper->abbrMethod($call['function']);
79
+ } elseif (isset($call['file'])) {
80
+ $from = $call['file'];
81
+ }
82
+
83
+ $fileName = null;
84
+ if (isset($call['file'], $call['line'])) {
85
+ $fileName = str_replace('\\', '/', $call['file']);
86
+ $fileName = explode('/', $fileName);
87
+ $fileName = end($fileName);
88
+ }
89
+ ?>
90
+
91
+ <li>
92
+ <?php echo $from; ?>
93
+ <?php if ($fileName): ?>
94
+ <span
95
+ class="text-small">(called from <?php echo $codeHelper->formatFile($call['file'], $call['line'], $fileName) ?>
96
+ )</span>
97
+ <?php endif; ?>
98
+ </li>
99
+ <?php endforeach; ?>
100
+ </ul>
101
+ <?php else: ?>
102
+ <?php if (!empty($log['context'])): ?>
103
+ <?php $contextId = 'context-' . $this->getCategory() . '-' . $index; ?>
104
+ <?php $contextDump = $valueExporter->exportValue($log['context']); ?>
105
+
106
+ <div class="metadata">
107
+ <strong>Context</strong>:
108
+ <?php if (strlen($contextDump) > 120): ?>
109
+ <?php substr($contextDump, 120); ?> ...
110
+
111
+ <a class="btn-link text-small sf-toggle"
112
+ data-toggle-selector="#<?php echo $contextId ?>"
113
+ data-toggle-alt-content="Hide full context">Show full context</a>
114
+
115
+ <div id="<?php echo $contextId ?>" class="context">
116
+ <pre><?php echo $contextDump ?></pre>
117
+ </div>
118
+ <?php else: ?>
119
+ <?php echo $contextDump ?>
120
+ <?php endif; ?>
121
+ </div>
122
+ <?php endif; ?>
123
+ <?php endif; ?>
124
+
125
+
126
+ </td>
127
+ </tr>
128
+ <?php endforeach; ?>
129
+ </tbody>
130
+ </table>
app/design/frontend/base/default/template/ecocode_profiler/collector/log/toolbar.phtml ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /** @var Ecocode_Profiler_Model_Collector_LogDataCollector $collector */
3
+ $collector = $this->getCollector();
4
+ $token = $this->getToken();
5
+ $logCount = $collector->getLogCount();
6
+ $statusColor = $collector->countErrors() ? 'red' : ($collector->countDeprecations() ? 'yellow' : '');
7
+ ?>
8
+
9
+ <?php if ($logCount): ?>
10
+ <div
11
+ class="sf-toolbar-block sf-toolbar-block-<?php echo $collector->getName() ?> sf-toolbar-status-<?php echo $statusColor ?>">
12
+ <a target="_blank"
13
+ href="<?php echo Mage::helper('ecocode_profiler')->getCollectorUrl($token, $collector); ?>">
14
+ <div class="sf-toolbar-icon">
15
+ <svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="24" height="24"
16
+ viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
17
+ <path fill="#AAAAAA" d="M21,4v13.8c0,2.7-2.5,5.2-5.2,5.2H6c-0.6,0-1-0.4-1-1s0.4-1,1-1h9.8c1.6,0,3.2-1.7,3.2-3.2V4
18
+ c0-0.6,0.4-1,1-1S21,3.4,21,4z M5.5,20C4.1,20,3,18.9,3,17.5V3.5C3,2.1,4.1,1,5.5,1h10.1C16.9,1,18,2.1,18,3.5v14.1
19
+ c0,1.4-1.1,2.5-2.5,2.5H5.5z M9,11.4C9,11.7,9.3,12,9.6,12h1.8c0.3,0,0.6-0.3,0.6-0.6V4.6C12,4.3,11.7,4,11.4,4H9.6
20
+ C9.3,4,9,4.3,9,4.6V11.4z M9,16.4C9,16.7,9.3,17,9.6,17h1.8c0.3,0,0.6-0.3,0.6-0.6v-1.8c0-0.3-0.3-0.6-0.6-0.6H9.6
21
+ C9.3,14,9,14.3,9,14.6V16.4z"></path>
22
+ </svg>
23
+ <?php $errorCount = $collector->countErrors() + $collector->countScreams(); ?>
24
+ <span class="sf-toolbar-value"><?php echo $errorCount ? $errorCount : '' ?> </span>
25
+ </div>
26
+ </a>
27
+
28
+ <div class="sf-toolbar-info">
29
+ <div class="sf-toolbar-info-piece">
30
+ <b>All</b>
31
+ <span class="sf-toolbar-status"><?php echo $logCount ?></span>
32
+ </div>
33
+ <div class="sf-toolbar-info-piece">
34
+ <b>Errors</b>
35
+ <span
36
+ class="sf-toolbar-status sf-toolbar-status-<?php echo $collector->countErrors() ? 'red' : '' ?>"><?php echo $collector->countErrors() ?></span>
37
+ </div>
38
+
39
+ <div class="sf-toolbar-info-piece">
40
+ <b>Deprecated Calls</b>
41
+ <span
42
+ class="sf-toolbar-status sf-toolbar-status-<?php echo $collector->countDeprecations() ? 'yellow' : '' ?>"><?php echo $collector->countDeprecations() ?></span>
43
+ </div>
44
+
45
+ <div class="sf-toolbar-info-piece">
46
+ <b>Silenced Errors</b>
47
+ <span class="sf-toolbar-status"><?php echo $collector->countScreams() ?></span>
48
+ </div>
49
+ </div>
50
+
51
+ </div>
52
+ <?php endif; ?>
app/design/frontend/base/default/template/ecocode_profiler/collector/memory/toolbar.phtml ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /** @var Ecocode_Profiler_Model_Collector_MemoryDataCollector $collector */
3
+ $collector = $this->getCollector();
4
+ $token = $this->getToken();
5
+ ?>
6
+
7
+
8
+ <div class="sf-toolbar-block sf-toolbar-block-<?php echo $collector->getName() ?> sf-toolbar-status-normal">
9
+ <div class="sf-toolbar-icon">
10
+ <svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="24" height="24" viewBox="0 0 24 24"
11
+ enable-background="new 0 0 24 24" xml:space="preserve">
12
+ <path fill="#AAAAAA" d="M6,18.9V15h12v3.9c0,0.7-0.2,1.1-1,1.1H7C6.2,20,6,19.6,6,18.9z M20,1C20,1,20,1,20,1c-0.6,0-1,0.5-1,1.1
13
+ l0,18c0,0.5-0.4,0.9-0.9,0.9H5.9C5.4,21,5,20.6,5,20.1l0-18C5,1.5,4.6,1,4,1c0,0,0,0,0,0C3.5,1,3,1.5,3,2.1l0,18
14
+ C3,21.7,4.3,23,5.9,23h12.2c1.6,0,2.9-1.3,2.9-2.9l0-18C21,1.5,20.6,1,20,1z M18,9H6v5h12V9z"/>
15
+ </svg>
16
+ <span class="sf-toolbar-value"><?php echo sprintf('%.1f', $collector->getMemory() / 1024 / 1024) ?></span>
17
+ <span class="sf-toolbar-label">MB</span>
18
+
19
+ </div>
20
+ <div class="sf-toolbar-info">
21
+ <div class="sf-toolbar-info-piece">
22
+ <b>Peak memory usage</b>
23
+ <span><?php echo sprintf('%.1f', $collector->getMemory() / 1024 / 1024) ?> MB</span>
24
+ </div>
25
+
26
+ <div class="sf-toolbar-info-piece">
27
+ <b>PHP memory limit</b>
28
+ <span><?php echo $collector->getMemoryLimit() == -1 ? 'Unlimited' : sprintf('%.0f MB', $collector->getMemoryLimit() / 1024 / 1024) ?></span>
29
+ </div>
30
+ </div>
31
+ </div>
app/design/frontend/base/default/template/ecocode_profiler/collector/model/menu.phtml ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /** @var Ecocode_Profiler_Model_Collector_ModelDataCollector $collector */
3
+ $collector = $this->getCollector();
4
+
5
+ $statusColor = $collector->getMetric('loop_load') ? 'error' : ($collector->getMetric('load') > $collector->getLoadCallThreshold() ? 'warning' : 'normal');
6
+ ?>
7
+
8
+ <span class="label label-status-<?php echo $statusColor ?>">
9
+ <span class="icon">
10
+ <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="31" height="24" viewBox="0 0 576 448">
11
+ <path fill="#AAAAAA" d="M576 192h-32v160h32v96h-96v-32h-224v32h-96v-96h32v-32h-96v32h-96v-96h32v-160h-32v-96h96v32h224v-32h96v96h-32v32h96v-32h96v96zM512 128v32h32v-32h-32zM352 32v32h32v-32h-32zM32 32v32h32v-32h-32zM64 320v-32h-32v32h32zM384 288h-32v32h32v-32zM96 288h224v-32h32v-160h-32v-32h-224v32h-32v160h32v32zM224 416v-32h-32v32h32zM544 416v-32h-32v32h32zM512 352v-160h-32v-32h-96v96h32v96h-96v-32h-96v32h32v32h224v-32h32z"></path>
12
+ </svg>
13
+ </span>
14
+ <strong>Models</strong>
15
+ <?php if ($collector->getMetric('loop_load')): ?>
16
+ <span class="count">
17
+ <span><?php echo $collector->getMetric('loop_load')?></span>
18
+ </span>
19
+ <?php endif; ?>
20
+ </span>
app/design/frontend/base/default/template/ecocode_profiler/collector/model/panel.phtml ADDED
@@ -0,0 +1,177 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /** @var Ecocode_Profiler_Model_Collector_ModelDataCollector $collector */
3
+ $collector = $this->getCollector();
4
+ $operations = ['save', 'delete', 'load'];
5
+
6
+ /** @var Ecocode_Profiler_Helper_Renderer $rendererHelper */
7
+ $rendererHelper = Mage::helper('ecocode_profiler/renderer');
8
+ ?>
9
+
10
+
11
+ <h2>Model CRUD metrics</h2>
12
+ <p class="help">
13
+ All model <strong>->load</strong> calls. Collection loads are not included
14
+ </p>
15
+ <div class="metrics">
16
+ <?php foreach ($collector->getMetric() as $name => $value): ?>
17
+ <div class="metric">
18
+ <span class="value"><?php echo $value ?></span>
19
+ <span class="label"><?php echo ucfirst(str_replace('_', ' ', $name)) ?> count</span>
20
+ </div>
21
+ <?php endforeach; ?>
22
+ <div class="metric">
23
+ <span class="value"><?php echo sprintf('%0.2f', $collector->getTotalTime() * 1000) ?> ms</span>
24
+ <span class="label">Total time</span>
25
+ </div>
26
+ </div>
27
+
28
+ <div class="sf-tabs">
29
+ <div class="tab">
30
+ <?php $callLog = $collector->getCallLog(); ?>
31
+ <h3 class="tab-title">
32
+ All
33
+ <span class="badge"><?php echo count($callLog) ?></span>
34
+ </h3>
35
+ <div id="all-crud-operations" class="tab-content">
36
+ <strong>Operation: </strong>
37
+ <?php foreach ($operations as $operation): ?>
38
+ <span data-toggle="crud-operation" data-operation="<?php echo $operation ?>" class="label">
39
+ <strong><?php echo strtoupper($operation) ?></strong>
40
+ <span class="count">
41
+ (<span><?php echo $collector->getMetric($operation) ?></span>)
42
+ </span>
43
+ </span>
44
+ <?php endforeach; ?>
45
+ <table>
46
+ <thead>
47
+ <tr>
48
+ <th>#</th>
49
+ <th>Action</th>
50
+ <th>Time</th>
51
+ <th style="width:100%;">Class</th>
52
+ </tr>
53
+ </thead>
54
+ <tbody>
55
+ <?php $prefix = 'all-'; ?>
56
+
57
+ <?php foreach ($callLog as $index => $log): ?>
58
+
59
+ <tr data-operation="<?php echo $log['action'] ?>">
60
+ <td class="nowrap"><?php echo $index + 1 ?></td>
61
+ <td><?php echo $log['action'] ?></td>
62
+ <td class="nowrap"><?php echo sprintf('%0.2f', $log['time'] * 1000) ?> ms</td>
63
+ <td>
64
+ <?php echo $log['class'] ?><br>
65
+ <div class="text-small font-normal">
66
+ <strong><?php echo $log['class_group'] ?></strong>
67
+ <?php if (isset($log['trace'])): ?>
68
+ <a href="#" class="sf-toggle link-inverse"
69
+ data-toggle-selector="#stack-<?php echo $prefix . $index ?>"
70
+ data-toggle-alt-content="Hide stack trace">Show trace</a>
71
+ <?php endif; ?>
72
+ </div>
73
+ <?php if (isset($log['trace'])): ?>
74
+ <?php echo $rendererHelper->renderBackTrace($prefix . $index, $log['trace']) ?>
75
+ <?php endif; ?>
76
+ </td>
77
+ </tr>
78
+
79
+ <?php endforeach; ?>
80
+ </tbody>
81
+ </table>
82
+ </div>
83
+ </div>
84
+ <div class="tab">
85
+ <?php $loadLoopCalls = $collector->getLoadLoopCalls(); ?>
86
+ <h3 class="tab-title">
87
+ Load calls in loops
88
+ <span class="badge"><?php echo count($loadLoopCalls) ?></span>
89
+ </h3>
90
+ <div class="tab-content">
91
+ <p class="help">
92
+ Calling <strong>->load</strong> within a "loop" is a sign of bad coding style and should be fixed!
93
+ </p>
94
+ <?php if (!$loadLoopCalls): ?>
95
+ <div class="empty">
96
+ <p>No load calls in loops detected</p>
97
+ </div>
98
+ <?php else: ?>
99
+ <table>
100
+ <thead>
101
+ <tr>
102
+ <th>#</th>
103
+ <th>Count</th>
104
+ <th>Total time</th>
105
+ <th style="width:100%;">Class</th>
106
+ </tr>
107
+ </thead>
108
+ <tbody>
109
+ <?php $prefix = 'loop-'; ?>
110
+
111
+ <?php foreach ($loadLoopCalls as $index => $log): ?>
112
+
113
+ <tr>
114
+ <td class="nowrap"><?php echo $index + 1 ?></td>
115
+ <td class="nowrap"><?php echo $log['count'] ?></td>
116
+ <td class="nowrap"><?php echo sprintf('%0.2f', $log['total_time'] * 1000) ?> ms</td>
117
+ <td>
118
+ <?php echo $log['class'] ?><br>
119
+ <div class="text-small font-normal">
120
+ <strong><?php echo $log['class_group'] ?></strong>
121
+ <?php if (isset($log['trace'])): ?>
122
+ <a href="#" class="sf-toggle link-inverse"
123
+ data-toggle-selector="#stack-<?php echo $prefix . $index ?>"
124
+ data-toggle-alt-content="Hide stack trace">Show trace</a>
125
+ <?php endif; ?>
126
+ </div>
127
+ <?php if (isset($log['trace'])): ?>
128
+ <?php echo $rendererHelper->renderBackTrace($prefix . $index, $log['trace']) ?>
129
+ <?php endif; ?>
130
+ </td>
131
+ </tr>
132
+
133
+ <?php endforeach; ?>
134
+ </tbody>
135
+ </table>
136
+ <?php endif; ?>
137
+
138
+ </div>
139
+ </div>
140
+ </div>
141
+ <script>
142
+ $(function () {
143
+ var allOperations = $('#all-crud-operations'),
144
+ crudOperations = allOperations.find('span[data-toggle="crud-operation"]');
145
+
146
+
147
+ crudOperations.click(function () {
148
+ var $this = $(this),
149
+ operation = $this.data('operation'),
150
+ makeActive = !$this.hasClass('status-success');
151
+
152
+ crudOperations.removeClass('status-success');
153
+ allOperations.removeAttr('data-operation');
154
+
155
+ if (makeActive) {
156
+ $this.addClass('status-success');
157
+ allOperations.attr('data-operation', operation);
158
+ }
159
+ });
160
+ });
161
+ </script>
162
+ <style>
163
+ #all-crud-operations span[data-toggle="crud-operation"] {
164
+ cursor: pointer;
165
+ }
166
+
167
+ <?php foreach ($operations as $name): ?>
168
+ #all-crud-operations[data-operation="<?php echo $name ?>"] tbody > tr:not([data-operation="<?php echo $name ?>"]) {
169
+ display: none;
170
+ }
171
+
172
+ <?php endforeach;?>
173
+ </style>
174
+
175
+
176
+
177
+
app/design/frontend/base/default/template/ecocode_profiler/collector/model/toolbar.phtml ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /** @var Ecocode_Profiler_Model_Collector_ModelDataCollector $collector */
3
+ $collector = $this->getCollector();
4
+ $token = $this->getToken();
5
+
6
+ ?>
7
+ <?php $statusColor = $collector->getMetric('loop_load') ? 'red' : ($collector->getMetric('load') > $collector->getLoadCallThreshold() ? 'yellow' : 'normal') ?>
8
+
9
+ <div class="sf-toolbar-block sf-toolbar-block-<?php echo $collector->getName()?> sf-toolbar-status-<?php echo $statusColor ?>">
10
+ <a target="_blank"
11
+ href="<?php echo Mage::helper('ecocode_profiler')->getCollectorUrl($token, $collector); ?>">
12
+ <div class="sf-toolbar-icon">
13
+ <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 576 448">
14
+ <path fill="#AAAAAA" d="M576 192h-32v160h32v96h-96v-32h-224v32h-96v-96h32v-32h-96v32h-96v-96h32v-160h-32v-96h96v32h224v-32h96v96h-32v32h96v-32h96v96zM512 128v32h32v-32h-32zM352 32v32h32v-32h-32zM32 32v32h32v-32h-32zM64 320v-32h-32v32h32zM384 288h-32v32h32v-32zM96 288h224v-32h32v-160h-32v-32h-224v32h-32v160h32v32zM224 416v-32h-32v32h32zM544 416v-32h-32v32h32zM512 352v-160h-32v-32h-96v96h32v96h-96v-32h-96v32h32v32h224v-32h32z"></path>
15
+ </svg>
16
+ <span class="sf-toolbar-value"><?php echo array_sum($collector->getMetric()) - $collector->getMetric('loop_load') ?></span>
17
+ </div>
18
+ </a>
19
+ <div class="sf-toolbar-info">
20
+ <div class="sf-toolbar-info-piece">
21
+ <b>Model loads</b>
22
+ <span class="sf-toolbar-status sf-toolbar-status-<?php echo $collector->getMetric('load') > $collector->getLoadCallThreshold() ? 'yellow' : '' ?>">
23
+ <?php echo $collector->getMetric('load') ?>
24
+ </span>
25
+ </div>
26
+
27
+ <div class="sf-toolbar-info-piece">
28
+ <b>Loads in loops</b>
29
+ <span class="sf-toolbar-status sf-toolbar-status-<?php echo $collector->getMetric('loop_load') ? 'red' : '' ?>">
30
+ <?php echo $collector->getMetric('loop_load') ?>
31
+ </span>
32
+ </div>
33
+
34
+ <div class="sf-toolbar-info-piece">
35
+ <b>Model save</b>
36
+ <span class="sf-toolbar-status">
37
+ <?php echo $collector->getMetric('save') ?>
38
+ </span>
39
+ </div>
40
+
41
+ <div class="sf-toolbar-info-piece">
42
+ <b>Model delete</b>
43
+ <span class="sf-toolbar-status">
44
+ <?php echo $collector->getMetric('delete') ?>
45
+ </span>
46
+ </div>
47
+ </div>
48
+ </div>
app/design/frontend/base/default/template/ecocode_profiler/collector/mysql/menu.phtml ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /** @var Ecocode_Profiler_Model_Collector_MysqlDataCollector $collector */
3
+ $collector = $this->getCollector();
4
+ ?>
5
+
6
+ <span class="label <?php echo $collector->getQueryCount() == 0 ? 'disabled' : '' ?>">
7
+ <span class="icon">
8
+ <svg version="1.1"xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" height="24" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
9
+ <path fill="#AAAAAA" d="M5,8h14c1.7,0,3-1.3,3-3s-1.3-3-3-3H5C3.3,2,2,3.3,2,5S3.3,8,5,8z M18,3.6c0.8,0,1.5,0.7,1.5,1.5S18.8,6.6,18,6.6s-1.5-0.7-1.5-1.5S17.2,3.6,18,3.6z M19,9H5c-1.7,0-3,1.3-3,3s1.3,3,3,3h14c1.7,0,3-1.3,3-3S20.7,9,19,9z M18,13.6
10
+ c-0.8,0-1.5-0.7-1.5-1.5s0.7-1.5,1.5-1.5s1.5,0.7,1.5,1.5S18.8,13.6,18,13.6z M19,16H5c-1.7,0-3,1.3-3,3s1.3,3,3,3h14c1.7,0,3-1.3,3-3S20.7,16,19,16z M18,20.6c-0.8,0-1.5-0.7-1.5-1.5s0.7-1.5,1.5-1.5s1.5,0.7,1.5,1.5S18.8,20.6,18,20.6z"/>
11
+ </svg>
12
+ </span>
13
+ <strong>Mysql</strong>
14
+ <!-- {% if collector.invalidEntityCount %}
15
+ <span class="count">
16
+ <span>{{ collector.invalidEntityCount }}</span>
17
+ </span>
18
+ {% endif %}-->
19
+ </span>
app/design/frontend/base/default/template/ecocode_profiler/collector/mysql/panel.phtml ADDED
@@ -0,0 +1,343 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /** @var Ecocode_Profiler_Block_Collector_Mysql_Panel $this */
3
+
4
+ /** @var Ecocode_Profiler_Model_Collector_MysqlDataCollector $collector */
5
+ $collector = $this->getCollector();
6
+ $identicalQueries = $this->getIdenticalQueries();
7
+ $identicalQueriesCount = count($identicalQueries);
8
+
9
+ $queriesByContext = $this->getByContext();
10
+ $contextHelper = Mage::helper('ecocode_profiler/context');
11
+ $queryTableRenderer = $this->getQueryTableRenderer();
12
+ ?>
13
+
14
+
15
+ <div style="float:left; width: 50%">
16
+ <h2>Query metrics</h2>
17
+ <div class="metrics">
18
+ <div class="metric">
19
+ <span class="value"><?php echo $collector->getQueryCount() ?></span>
20
+ <span class="label">Database queries</span>
21
+ </div>
22
+
23
+ <div class="metric">
24
+ <span class="value"><?php echo $identicalQueriesCount ?></span>
25
+ <span class="label">Identical queries</span>
26
+ </div>
27
+
28
+ <div class="metric">
29
+ <span class="value"><?php echo sprintf('%0.2f', $collector->getTotalTime() * 1000) ?> ms</span>
30
+ <span class="label">Query time</span>
31
+ </div>
32
+ </div>
33
+ </div>
34
+ <?php $connections = $collector->getConnectionData(); ?>
35
+ <?php if (count($connections) > 1): ?>
36
+ <div style="float:left; width: 50%">
37
+ <h2>Queries by connection</h2>
38
+
39
+ <div class="metrics">
40
+ <?php foreach ($connections as $name => $queryCount): ?>
41
+ <div class="metric">
42
+ <span class="value"><?php echo $queryCount ?></span>
43
+ <span class="label"><?php echo $name ?></span>
44
+ </div>
45
+ <?php endforeach; ?>
46
+ </div>
47
+ </div>
48
+ <?php endif; ?>
49
+ <div style="clear: both;"></div>
50
+
51
+ <div class="sf-tabs">
52
+ <div class="tab">
53
+ <h3 class="tab-title">
54
+ Queries
55
+ <span class="badge"><?php echo $collector->getQueryCount() ?></span>
56
+ </h3>
57
+ <div id="all-queries" class="tab-content">
58
+ <?php if ($this->getQueryCountByType()): ?>
59
+ <div style="float:left; width: 50%">
60
+ <strong>Type: </strong>
61
+ <?php foreach ($this->getQueryCountByType() as $type => $count): ?>
62
+ <span data-toggle="query-type" data-type="<?php echo $type ?>" class="label">
63
+ <strong><?php echo strtoupper($type) ?></strong>
64
+ <span class="count">
65
+ (<span><?php echo $count ?></span>)
66
+ </span>
67
+ </span>
68
+ <?php endforeach; ?>
69
+ </div>
70
+ <?php endif; ?>
71
+ <?php if (count($connections) > 1): ?>
72
+ <div style="float:left; width: 50%">
73
+ <strong>Connection: </strong>
74
+ <?php foreach ($connections as $connection => $count): ?>
75
+ <span data-toggle="query-connection" data-connection="<?php echo $connection ?>" class="label">
76
+ <strong><?php echo $connection ?></strong>
77
+ <span class="count">
78
+ (<span><?php echo $count ?></span>)
79
+ </span>
80
+ </span>
81
+ <?php endforeach; ?>
82
+ </div>
83
+ <?php endif; ?>
84
+ <div style="clear: both;"></div>
85
+ <?php echo $this->renderQueryTable('all', $this->getQueries()); ?>
86
+ </div>
87
+ </div>
88
+ <div class="tab">
89
+ <h3 class="tab-title">
90
+ Queries by context
91
+ <span class="badge"><?php echo count($queriesByContext) ?></span>
92
+ </h3>
93
+
94
+ <div class="tab-content">
95
+ <table>
96
+ <thead>
97
+ <tr>
98
+ <th>#</th>
99
+ <th>Context</th>
100
+ <th>Queries</th>
101
+ <th>Total Time</th>
102
+ <th></th>
103
+ </tr>
104
+ </thead>
105
+ <tbody>
106
+
107
+ <?php foreach ($queriesByContext as $index => $contextData): ?>
108
+ <tr>
109
+ <td><?php echo $index + 1 ?> </td>
110
+ <td>
111
+ <?php echo $contextHelper->render('context', $contextData['name']); ?>
112
+ </td>
113
+ <td><?php echo $contextData['count'] ?></td>
114
+ <td><?php echo sprintf('%0.2f', $contextData['total_time'] * 1000) ?> ms</td>
115
+ <td class="text-right">
116
+ <a href="#" class="sf-toggle link-inverse"
117
+ data-toggle-selector="#context-queries-<?php echo $index ?>"
118
+ data-toggle-alt-content="Hide queries">View queries</a>
119
+ </td>
120
+ </tr>
121
+ <tr class="hidden" id="context-queries-<?php echo $index ?>">
122
+ <td colspan="5">
123
+ Queries:<br>
124
+ <?php echo $this->renderQueryTable('context-' . $index, $contextData['queries']); ?>
125
+ </td>
126
+ </tr>
127
+ <?php endforeach; ?>
128
+ </tbody>
129
+
130
+ </table>
131
+ </div>
132
+ </div>
133
+ <div class="tab">
134
+ <h3 class="tab-title">
135
+ Identical queries
136
+ <span class="badge"><?php echo $identicalQueriesCount ?></span>
137
+ </h3>
138
+
139
+
140
+ <div class="tab-content">
141
+ <?php $prefix = 'identical-'; ?>
142
+ <table class="alt queries-table">
143
+ <thead>
144
+ <tr>
145
+ <th class="nowrap">#</th>
146
+ <th class="nowrap">Count</th>
147
+ <th class="nowrap">Total time<span></span></th>
148
+ <th style="width: 100%;">Info</th>
149
+ </tr>
150
+ </thead>
151
+ <tbody>
152
+ <?php foreach ($identicalQueries as $index => $query): ?>
153
+ <?php $queryData = $query['query']; ?>
154
+ <tr>
155
+ <td class="nowrap"><?php echo $index + 1 ?> </td>
156
+ <td class="nowrap"><?php echo $query['count'] ?> </td>
157
+ <td class="nowrap"><?php echo sprintf('%0.2f', $query['total_time'] * 1000) ?> ms</td>
158
+ <td>
159
+ <?php echo $queryData['sql_highlighted'] ?>
160
+ <div>
161
+ <strong class="font-normal text-small">Parameters</strong>:
162
+ <?php echo $queryTableRenderer->dumpParameters($queryData['params']) ?>
163
+
164
+ </div>
165
+ <div>
166
+ <?php echo $contextHelper->render('identical', $queryData['context']); ?>
167
+ </div>
168
+
169
+ <div class="text-small font-normal">
170
+ <?php if (isset($query['traces'])): ?>
171
+ <a href="#" class="sf-toggle link-inverse"
172
+ data-toggle-selector="#stack-<?php echo $prefix . $index ?>"
173
+ data-toggle-alt-content="Hide stack trace">Show trace</a>
174
+ <?php endif; ?>
175
+ <a href="#" class="sf-toggle link-inverse"
176
+ data-toggle-selector="#formatted-query-<?php echo $prefix . $index ?>"
177
+ data-toggle-alt-content="Hide formatted query">View formatted query</a>
178
+ <a href="#" class="sf-toggle link-inverse"
179
+ data-toggle-selector="#original-query-<?php echo $prefix . $index ?>"
180
+ data-toggle-alt-content="Hide runnable query">View runnable query</a>
181
+ </div>
182
+
183
+ <div id="formatted-query-<?php echo $prefix . $index ?>" class="sql-runnable hidden">
184
+ <?php echo $queryData['sql_formatted']; ?>
185
+ </div>
186
+
187
+ <div id="original-query-<?php echo $prefix . $index ?>" class="sql-runnable hidden">
188
+ <?php echo $queryData['sql_runnable']; ?>
189
+ </div>
190
+
191
+ <?php if (isset($query['traces'])): ?>
192
+ <div id="stack-<?php echo $prefix . $index ?>" class="hidden">
193
+ <strong class="font-normal text-small">Traces</strong>:
194
+ <table class="">
195
+ <tbody>
196
+ <?php foreach ($query['traces'] as $j => $trace): ?>
197
+ <tr>
198
+ <td class="nowrap">#<?php echo $j + 1 ?></td>
199
+ <td>
200
+ <ul class="sf-call-stack ">
201
+ <?php foreach ($trace as $item): ?>
202
+ <li>
203
+ <?php echo isset($item['class']) ? $item['class'] : '' ?>
204
+ ::<?php echo $item['function'] ?><br>
205
+ <?php if (isset($item['file'])): ?>
206
+ <small><?php echo $item['file'] ?>
207
+ ::<?php echo $item['line'] ?></small>
208
+ <?php endif; ?>
209
+ </li>
210
+ <?php endforeach; ?>
211
+ </ul>
212
+ </td>
213
+ </tr>
214
+ <?php endforeach; ?>
215
+ </tbody>
216
+ </table>
217
+ </div>
218
+ <?php endif; ?>
219
+ </td>
220
+ </tr>
221
+ <?php endforeach; ?>
222
+ </tbody>
223
+ </table>
224
+ </div>
225
+ </div>
226
+ </div>
227
+ <script>
228
+ $(function () {
229
+ var allQueries = $('#all-queries'),
230
+ queryTypes = allQueries.find('span[data-toggle="query-type"]'),
231
+ connections = allQueries.find('span[data-toggle="query-connection"]');
232
+
233
+
234
+ queryTypes.click(function () {
235
+ var $this = $(this),
236
+ type = $this.data('type'),
237
+ makeActive = !$this.hasClass('status-success');
238
+
239
+ queryTypes.removeClass('status-success');
240
+ allQueries.removeAttr('data-type');
241
+
242
+ if (makeActive) {
243
+ $this.addClass('status-success');
244
+ allQueries.attr('data-type', type);
245
+ }
246
+ });
247
+
248
+ connections.click(function () {
249
+ var $this = $(this),
250
+ connection = $this.data('connection'),
251
+ makeActive = !$this.hasClass('status-success');
252
+
253
+ connections.removeClass('status-success');
254
+ allQueries.removeAttr('data-connection');
255
+
256
+ if (makeActive) {
257
+ $this.addClass('status-success');
258
+ allQueries.attr('data-connection', connection);
259
+ }
260
+ });
261
+ });
262
+ </script>
263
+ <style>
264
+ <?php foreach ($connections as $name => $queryCount): ?>
265
+ #all-queries[data-connection="<?php echo $name ?>"] tbody > tr:not([data-connection="<?php echo $name ?>"]) {
266
+ display: none;
267
+ }
268
+ <?php endforeach; ?>
269
+
270
+ <?php foreach ($this->getQueryCountByType() as $name => $queryCount): ?>
271
+ #all-queries[data-type="<?php echo $name ?>"] tbody > tr:not([data-type="<?php echo $name ?>"]) {
272
+ display: none;
273
+ }
274
+ <?php endforeach; ?>
275
+
276
+ #all-queries span[data-toggle="query-type"],
277
+ #all-queries span[data-toggle="query-connection"] {
278
+ cursor: pointer;
279
+ }
280
+
281
+ tr.sf-toggle-content.sf-toggle-visible {
282
+ display: table-row !important;
283
+ }
284
+
285
+ td > .context > strong {
286
+ display: none;
287
+ }
288
+
289
+ .hidden {
290
+ display: none;
291
+ }
292
+
293
+ .queries-table td, .queries-table th {
294
+ vertical-align: top;
295
+ }
296
+
297
+ .queries-table td > div {
298
+ margin-bottom: 6px;
299
+ }
300
+
301
+ .highlight pre {
302
+ margin: 0;
303
+ white-space: pre-wrap;
304
+ }
305
+
306
+ .highlight .keyword {
307
+ color: #8959A8;
308
+ font-weight: bold;
309
+ }
310
+
311
+ .highlight .word {
312
+ color: #222222;
313
+ }
314
+
315
+ .highlight .variable {
316
+ color: #916319;
317
+ }
318
+
319
+ .highlight .symbol {
320
+ color: #222222;
321
+ }
322
+
323
+ .highlight .comment {
324
+ color: #999999;
325
+ }
326
+
327
+ .highlight .backtick {
328
+ color: #718C00;
329
+ }
330
+
331
+ .highlight .string {
332
+ color: #718C00;
333
+ }
334
+
335
+ .highlight .number {
336
+ color: #F5871F;
337
+ font-weight: bold;
338
+ }
339
+
340
+ .highlight .error {
341
+ color: #C82829;
342
+ }
343
+ </style>
app/design/frontend/base/default/template/ecocode_profiler/collector/mysql/panel/query-table.phtml ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ $prefix = $this->getData('prefix');
3
+ $contextHelper = Mage::helper('ecocode_profiler/context');
4
+
5
+ /** @var Ecocode_Profiler_Helper_Renderer $rendererHelper */
6
+ $rendererHelper = Mage::helper('ecocode_profiler/renderer');
7
+ ?>
8
+ <table class="alt queries-table">
9
+ <thead>
10
+ <tr>
11
+ <th class="nowrap">#</th>
12
+ <th class="nowrap">Connection</th>
13
+ <th class="nowrap">Time<span></span></th>
14
+ <th style="width: 100%;">Info</th>
15
+ </tr>
16
+ </thead>
17
+ <tbody>
18
+ <?php foreach ($this->getData('queries') as $index => $queryData): ?>
19
+ <tr data-type="<?php echo $queryData['type']?>" data-connection="<?php echo $queryData['connection'] ?>">
20
+ <td class="nowrap"><?php echo $index + 1 ?> </td>
21
+ <td class="nowrap"><?php echo $queryData['connection'] ?> </td>
22
+ <td class="nowrap"><?php echo sprintf('%0.2f', $queryData['time'] * 1000) ?> ms</td>
23
+ <td>
24
+ <?php echo $queryData['sql_highlighted']; ?>
25
+ <div>
26
+ <strong class="font-normal text-small">Parameters</strong>:
27
+ <?php echo $this->dumpParameters($queryData['params']) ?>
28
+
29
+ </div>
30
+ <div>
31
+ <?php echo $contextHelper->render($prefix, $queryData['context']); ?>
32
+ </div>
33
+
34
+ <div class="text-small font-normal">
35
+ <?php if (isset($queryData['trace'])): ?>
36
+ <a href="#" class="sf-toggle link-inverse"
37
+ data-toggle-selector="#stack-<?php echo $prefix . $index ?>"
38
+ data-toggle-alt-content="Hide stack trace">Show trace</a>
39
+ <?php endif; ?>
40
+ <a href="#" class="sf-toggle link-inverse"
41
+ data-toggle-selector="#formatted-query-<?php echo $prefix . $index ?>"
42
+ data-toggle-alt-content="Hide formatted query">View formatted query</a>
43
+ <a href="#" class="sf-toggle link-inverse"
44
+ data-toggle-selector="#original-query-<?php echo $prefix . $index ?>"
45
+ data-toggle-alt-content="Hide runnable query">View runnable query</a>
46
+ </div>
47
+
48
+ <div id="formatted-query-<?php echo $prefix . $index ?>" class="sql-runnable hidden">
49
+ <?php echo $queryData['sql_formatted']; ?>
50
+ </div>
51
+
52
+ <div id="original-query-<?php echo $prefix . $index ?>" class="sql-runnable hidden">
53
+ <?php echo $queryData['sql_runnable']; ?>
54
+ </div>
55
+
56
+ <?php if (isset($queryData['trace'])): ?>
57
+ <?php echo $rendererHelper->renderBackTrace($prefix . $index, $queryData['trace']) ?>
58
+ <?php endif; ?>
59
+ </td>
60
+ </tr>
61
+ <?php endforeach; ?>
62
+ </tbody>
63
+ </table>
app/design/frontend/base/default/template/ecocode_profiler/collector/mysql/toolbar.phtml ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /** @var Ecocode_Profiler_Model_Collector_MysqlDataCollector $collector */
3
+ $collector = $this->getCollector();
4
+ $token = $this->getToken();
5
+ ?>
6
+
7
+ <div class="sf-toolbar-block sf-toolbar-block-<?php echo $collector->getName()?> sf-toolbar-status-normal">
8
+ <a target="_blank"
9
+ href="<?php echo Mage::helper('ecocode_profiler')->getCollectorUrl($token, $collector); ?>">
10
+ <div class="sf-toolbar-icon">
11
+ <svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" height="24"
12
+ viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
13
+ <path fill="#AAAAAA" d="M5,8h14c1.7,0,3-1.3,3-3s-1.3-3-3-3H5C3.3,2,2,3.3,2,5S3.3,8,5,8z M18,3.6c0.8,0,1.5,0.7,1.5,1.5S18.8,6.6,18,6.6s-1.5-0.7-1.5-1.5S17.2,3.6,18,3.6z M19,9H5c-1.7,0-3,1.3-3,3s1.3,3,3,3h14c1.7,0,3-1.3,3-3S20.7,9,19,9z M18,13.6
14
+ c-0.8,0-1.5-0.7-1.5-1.5s0.7-1.5,1.5-1.5s1.5,0.7,1.5,1.5S18.8,13.6,18,13.6z M19,16H5c-1.7,0-3,1.3-3,3s1.3,3,3,3h14c1.7,0,3-1.3,3-3S20.7,16,19,16z M18,20.6c-0.8,0-1.5-0.7-1.5-1.5s0.7-1.5,1.5-1.5s1.5,0.7,1.5,1.5S18.8,20.6,18,20.6z"></path>
15
+ </svg>
16
+
17
+ <span class="sf-toolbar-value"><?php echo $collector->getQueryCount() ?></span>
18
+ <span class="sf-toolbar-info-piece-additional-detail">
19
+ <span class="sf-toolbar-label">in</span>
20
+ <span class="sf-toolbar-value"><?php echo sprintf('%0.2f', $collector->getTotalTime() * 1000) ?></span>
21
+ <span class="sf-toolbar-label">ms</span>
22
+ </span>
23
+
24
+ </div>
25
+ </a>
26
+ <div class="sf-toolbar-info">
27
+ <div class="sf-toolbar-info-piece">
28
+ <b>Database Queries</b>
29
+ <span class="sf-toolbar-status "><?php echo $collector->getQueryCount() ?></span>
30
+ </div>
31
+ <div class="sf-toolbar-info-piece">
32
+ <b>Query time</b>
33
+ <span><?php echo sprintf('%0.2f', $collector->getTotalTime() * 1000) ?> ms</span>
34
+ </div>
35
+ </div>
36
+ </div>
app/design/frontend/base/default/template/ecocode_profiler/collector/request/menu.phtml ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <span class="label">
2
+ <span class="icon">
3
+ <svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="24" height="24" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
4
+ <path fill="#AAAAAA" d="M15.8,6.4h-1.1c0,0-0.1,0.1-0.1,0l0.8-0.7c0.5-0.5,0.5-1.3,0-1.9l-1.4-1.4c-0.5-0.5-1.4-0.5-1.9,0l-0.6,0.8
5
+ c-0.1,0,0,0,0-0.1V2.1c0-0.8-1-1.4-1.8-1.4h-2c-0.8,0-1.9,0.6-1.9,1.4v1.1c0,0,0.1,0.1,0.1,0.1L5.1,2.5c-0.5-0.5-1.3-0.5-1.9,0
6
+ L1.8,3.9c-0.5,0.5-0.5,1.4,0,1.9l0.8,0.6c0,0.1,0,0-0.1,0H1.4C0.7,6.4,0,7.5,0,8.2v2c0,0.8,0.7,1.8,1.4,1.8h1.2c0,0,0.1-0.1,0.1-0.1
7
+ l-0.8,0.7c-0.5,0.5-0.5,1.3,0,1.9L3.3,16c0.5,0.5,1.4,0.5,1.9,0l0.6-0.8c0.1,0-0.1,0-0.1,0.1v1.2c0,0.8,1.1,1.4,1.9,1.4h2
8
+ c0.8,0,1.8-0.6,1.8-1.4v-1.2c0,0-0.1-0.1,0-0.1l0.7,0.8c0.5,0.5,1.3,0.5,1.9,0l1.4-1.4c0.5-0.5,0.5-1.4,0-1.9L14.6,12
9
+ c0-0.1,0,0.1,0.1,0.1h1.1c0.8,0,1.3-1.1,1.3-1.8v-2C17.1,7.5,16.5,6.4,15.8,6.4z M8.6,13c-2.1,0-3.8-1.7-3.8-3.8
10
+ c0-2.1,1.7-3.8,3.8-3.8c2.1,0,3.8,1.7,3.8,3.8C12.3,11.3,10.6,13,8.6,13z"/>
11
+ <path fill="#AAAAAA" d="M22.3,15.6l-0.6,0.2c0,0,0,0.1,0,0l0.3-0.5c0.2-0.4,0-0.8-0.4-1l-1-0.4c-0.4-0.2-0.8,0-1,0.4l-0.1,0.5
12
+ c0,0,0,0,0,0l-0.2-0.6c-0.2-0.4-0.8-0.5-1.2-0.3l-1.1,0.4c-0.4,0.2-0.8,0.7-0.7,1.1l0.2,0.6c0,0,0.1,0,0.1,0l-0.5-0.3
13
+ c-0.4-0.2-0.8,0-1,0.4l-0.4,1c-0.2,0.4,0,0.8,0.4,1l0.5,0.1c0,0,0,0,0,0l-0.6,0.2c-0.4,0.2-0.5,0.8-0.4,1.2l0.4,1.1
14
+ c0.2,0.4,0.7,0.8,1.1,0.7l0.6-0.2c0,0,0-0.1,0,0l-0.3,0.5c-0.2,0.4,0,0.8,0.4,1l1,0.4c0.4,0.2,0.8,0,1-0.4l0.1-0.5c0,0,0,0,0,0
15
+ l0.2,0.6c0.2,0.4,0.9,0.5,1.2,0.3l1.1-0.4c0.4-0.2,0.8-0.7,0.6-1.1l-0.2-0.6c0,0-0.1,0,0,0l0.5,0.3c0.4,0.2,0.8,0,1-0.4l0.4-1
16
+ c0.2-0.4,0-0.8-0.4-1l-0.5-0.1c0,0,0,0,0,0l0.6-0.2c0.4-0.2,0.5-0.8,0.3-1.2l-0.4-1.1C23.2,15.9,22.7,15.5,22.3,15.6z M19.9,20.5
17
+ c-1.1,0.4-2.3-0.1-2.7-1.2c-0.4-1.1,0.1-2.3,1.2-2.7c1.1-0.4,2.3,0.1,2.7,1.2C21.5,18.9,21,20.1,19.9,20.5z"/>
18
+ </svg>
19
+
20
+ </span>
21
+ <strong>Request / Response</strong>
22
+ </span>
app/design/frontend/base/default/template/ecocode_profiler/collector/request/panel.phtml ADDED
@@ -0,0 +1,163 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /** @var Ecocode_Profiler_Block_Collector_Base $this */
3
+
4
+ /** @var Ecocode_Profiler_Model_Collector_RequestDataCollector $collector */
5
+ $collector = $this->getCollector();
6
+ ?>
7
+
8
+
9
+ <div class="sf-tabs">
10
+ <div class="tab">
11
+ <h3 class="tab-title">Request</h3>
12
+
13
+ <div class="tab-content">
14
+ <h3>GET Parameters</h3>
15
+
16
+ <?php if (!count($collector->getRequestQuery())): ?>
17
+ <div class="empty">
18
+ <p>No GET parameters</p>
19
+ </div>
20
+ <?php else: ?>
21
+ <?php echo $this->renderBag($collector->getRequestQuery()) ?>
22
+ <?php endif ?>
23
+
24
+ <h3>POST Parameters</h3>
25
+
26
+ <?php if (!count($collector->getRequestRequest())): ?>
27
+ <div class="empty">
28
+ <p>No POST parameters</p>
29
+ </div>
30
+ <?php else: ?>
31
+ <?php echo $this->renderBag($collector->getRequestRequest()) ?>
32
+ <?php endif ?>
33
+
34
+ <h3>Request Attributes</h3>
35
+
36
+ <?php if (!count($collector->getRequestAttributes())): ?>
37
+ <div class="empty">
38
+ <p>No attributes</p>
39
+ </div>
40
+ <?php else: ?>
41
+ <?php echo $this->renderBag($collector->getRequestAttributes()) ?>
42
+ <?php endif ?>
43
+
44
+ <h3>Cookies</h3>
45
+
46
+ <?php if (!count($collector->getRequestCookies())): ?>
47
+ <div class="empty">
48
+ <p>No cookies</p>
49
+ </div>
50
+ <?php else: ?>
51
+ <?php echo $this->renderBag($collector->getRequestCookies()) ?>
52
+ <?php endif ?>
53
+
54
+ <h3>Request Headers</h3>
55
+ <?php echo $this->renderBag($collector->getRequestHeaders()) ?>
56
+
57
+ <h3>Request Content</h3>
58
+
59
+ <?php if ($collector->getContent() === false): ?>
60
+ <div class="empty">
61
+ <p>Request content not available (it was retrieved as a resource).</p>
62
+ </div>
63
+ <?php elseif ($collector->getContent()): ?>
64
+ <div class="card">
65
+ <pre class="break-long-words"><?php echo $collector->getContent() ?></pre>
66
+ </div>
67
+ <?php else: ?>
68
+ <div class="empty">
69
+ <p>No content</p>
70
+ </div>
71
+ <?php endif ?>
72
+
73
+ <h3>Server Parameters</h3>
74
+ <?php echo $this->renderBag($collector->getRequestServer()) ?>
75
+ </div>
76
+ </div>
77
+
78
+ <div class="tab">
79
+ <h3 class="tab-title">Response</h3>
80
+
81
+ <div class="tab-content">
82
+ <h3>Response Headers</h3>
83
+
84
+ <?php echo $this->renderBag($collector->getResponseHeaders()) ?>
85
+ </div>
86
+ </div>
87
+
88
+ <!--<div class="tab {{ collector.sessionmetadata is empty ? 'disabled' }}">
89
+ <h3 class="tab-title">Session</h3>
90
+
91
+ <div class="tab-content">
92
+ <h3>Session Metadata</h3>
93
+
94
+ {% if collector.sessionmetadata is empty %}
95
+ <div class="empty">
96
+ <p>No session metadata</p>
97
+ </div>
98
+ {% else %}
99
+ {{ include('@WebProfiler/Profiler/table.html.twig', { data: collector.sessionmetadata }, with_context = false) }}
100
+ {% endif %}
101
+
102
+ <h3>Session Attributes</h3>
103
+
104
+ {% if collector.sessionattributes is empty %}
105
+ <div class="empty">
106
+ <p>No session attributes</p>
107
+ </div>
108
+ {% else %}
109
+ {{ include('@WebProfiler/Profiler/table.html.twig', { data: collector.sessionattributes, labels: ['Attribute', 'Value'] }, with_context = false) }}
110
+ {% endif %}
111
+ </div>
112
+ </div>
113
+
114
+ <div class="tab {{ collector.flashes is empty ? 'disabled' }}">
115
+ <h3 class="tab-title">Flashes</h3>
116
+
117
+ <div class="tab-content">
118
+ <h3>Flashes</h3>
119
+
120
+ {% if collector.flashes is empty %}
121
+ <div class="empty">
122
+ <p>No flash messages were created.</p>
123
+ </div>
124
+ {% else %}
125
+ {{ include('@WebProfiler/Profiler/table.html.twig', { data: collector.flashes }, with_context = false) }}
126
+ {% endif %}
127
+ </div>
128
+ </div>
129
+
130
+ {% if profile.parent %}
131
+ <div class="tab">
132
+ <h3 class="tab-title">Parent Request</h3>
133
+
134
+ <div class="tab-content">
135
+ <h3>
136
+ <a href="{{ path('_profiler', { token: profile.parent.token }) }}">Return to parent request</a>
137
+ <small>(token = {{ profile.parent.token }})</small>
138
+ </h3>
139
+
140
+ {{ include('@WebProfiler/Profiler/bag.html.twig', { bag: profile.parent.getcollector('request').requestattributes }, with_context = false) }}
141
+ </div>
142
+ </div>
143
+ {% endif %}
144
+
145
+ {% if profile.children|length %}
146
+ <div class="tab">
147
+ <h3 class="tab-title">Sub Requests <span class="badge">{{ profile.children|length }}</span></h3>
148
+
149
+ <div class="tab-content">
150
+ {% for child in profile.children %}
151
+ <h3>
152
+ <a href="{{ path('_profiler', { token: child.token }) }}">
153
+ {{- child.getcollector('request').requestattributes.get('_controller') -}}
154
+ </a>
155
+ <small>(token = {{ child.token }})</small>
156
+ </h3>
157
+
158
+ {{ include('@WebProfiler/Profiler/bag.html.twig', { bag: child.getcollector('request').requestattributes }, with_context = false) }}
159
+ {% endfor %}
160
+ </div>
161
+ </div>
162
+ {% endif %}-->
163
+ </div>
app/design/frontend/base/default/template/ecocode_profiler/collector/request/toolbar.phtml ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /** @var Ecocode_Profiler_Block_Collector_Base $this */
3
+
4
+ /** @var Ecocode_Profiler_Model_Collector_RequestDataCollector $collector */
5
+ $collector = $this->getCollector();
6
+ $token = $this->getToken();
7
+ $requestStatusCodeColor = $collector->getStatusCode() >= 400 ? 'red' : $collector->getStatusCode() >= 300 ? 'yellow' : 'green';
8
+ ?>
9
+
10
+ <div class="sf-toolbar-block sf-toolbar-block-<?php echo $collector->getName()?> sf-toolbar-status-normal ">
11
+ <a target="_blank" href="<?php echo Mage::helper('ecocode_profiler')->getCollectorUrl($token, $collector); ?>">
12
+ <div class="sf-toolbar-icon">
13
+ <span class="sf-toolbar-status sf-toolbar-status-<?php echo $requestStatusCodeColor?>"><?php echo $collector->getStatusCode()?></span>
14
+ <?php if($collector->getRoute()): ?>
15
+ <span class="sf-toolbar-label"><?php echo $collector->getMethod() !== 'GET' ? $collector->getMethod() : ''?> @</span>
16
+ <span class="sf-toolbar-value sf-toolbar-info-piece-additional"><?php echo $collector->getRoute()?></span>
17
+ <?php endif?>
18
+ </div>
19
+ </a>
20
+ <div class="sf-toolbar-info">
21
+ <div class="sf-toolbar-info-group">
22
+ <div class="sf-toolbar-info-piece">
23
+ <b>HTTP status</b>
24
+ <span><?php echo $collector->getStatusCode() ?></span>
25
+ </div>
26
+
27
+
28
+ <div class="sf-toolbar-info-piece">
29
+ <b>Route Name</b><span><?php echo $collector->getRoute() ?></span>
30
+ </div>
31
+ <div class="sf-toolbar-info-piece">
32
+ <b>Module</b><span><?php echo $collector->getModuleName() ?></span>
33
+ </div>
34
+ <div class="sf-toolbar-info-piece">
35
+ <b>Controller</b>
36
+ <span><?php echo $collector->getControllerName() ?>::<?php echo $collector->getActionName() ?> </span>
37
+ </div>
38
+
39
+ <?php $controllerData = $collector->getController(); ?>
40
+ <div class="sf-toolbar-info-piece">
41
+ <b>Controller class</b>
42
+ <span><?php echo $controllerData['class'] ?></span>
43
+ </div>
44
+ <div class="sf-toolbar-info-piece">
45
+ <b>Full action name</b>
46
+ <span><?php echo $collector->getRoute(); ?></span>
47
+ </div>
48
+ </div>
49
+
50
+ </div>
51
+ </div>
app/design/frontend/base/default/template/ecocode_profiler/collector/rewrite/menu.phtml ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /** @var Ecocode_Profiler_Model_Collector_RewriteDataCollector $collector */
3
+ $collector = $this->getCollector();
4
+ $conflictCount = $collector->getModuleRewriteConflictCount();
5
+ $statusColor = $conflictCount ? 'error' : 'normal';
6
+ ?>
7
+
8
+ <span class="label label-status-<?php echo $statusColor ?>">
9
+ <span class="icon">
10
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
11
+ <path style="fill:#aaa" d="M23.61,11.07L17.07,4.35A1.2,1.2,0,0,0,15,5.28V9H1.4A1.82,1.82,0,0,0,0,10.82v2.61A1.55,
12
+ 1.55,0,0,0,1.4,15H15v3.72a1.2,1.2,0,0,0,2.07.93l6.63-6.72A1.32,1.32,0,0,0,23.61,11.07Z"/>
13
+ </svg>
14
+
15
+ </span>
16
+ <strong>Rewrites</strong>
17
+ <?php if ($conflictCount): ?>
18
+ <span class="count">
19
+ <span><?php echo $conflictCount ?> </span>
20
+ </span>
21
+ <?php endif ?>
22
+ </span>
app/design/frontend/base/default/template/ecocode_profiler/collector/rewrite/panel.phtml ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /** @var Ecocode_Profiler_Block_Collector_Base $this */
3
+
4
+ /** @var Ecocode_Profiler_Model_Collector_RewriteDataCollector $collector */
5
+ $collector = $this->getCollector();
6
+
7
+ ?>
8
+ <?php $conflicts = $collector->getModuleRewriteConflicts(); ?>
9
+ <h2>Rewrite Conflicts</h2>
10
+ <?php if ($conflicts): ?>
11
+ <table>
12
+ <thead>
13
+ <tr>
14
+ <th>Type</th>
15
+ <th>Class</th>
16
+ <th>Rewrites</th>
17
+ <th>Loaded Class</th>
18
+ </tr>
19
+ </thead>
20
+ <tbody>
21
+ <?php foreach ($conflicts as $conflict): ?>
22
+ <tr>
23
+ <td><?php echo $conflict['type'] ?></td>
24
+ <td><?php echo $conflict['class'] ?></td>
25
+ <td><?php echo implode('<br>', $conflict['rewrites']) ?></td>
26
+ <td><?php echo $conflict['loaded_class'] ?></td>
27
+ </tr>
28
+
29
+ <?php endforeach; ?>
30
+ </tbody>
31
+ </table>
32
+
33
+ <?php else: ?>
34
+ <div class="empty">
35
+ <p>No rewrite conflicts</p>
36
+ </div>
37
+
38
+ <?php endif; ?>
39
+
40
+ <?php
41
+ $rewrites = $collector->getModuleRewrites();
42
+ ?>
43
+ <h2>Rewrites</h2>
44
+
45
+ <div class="sf-tabs">
46
+ <?php foreach ($rewrites as $type => $typeRewrites): ?>
47
+ <div class="tab">
48
+ <h3 class="tab-title"><?php echo ucwords($type) ?>
49
+ <small>(<?php echo count($typeRewrites) ?>)</small>
50
+ </h3>
51
+ <div class="tab-content">
52
+ <?php if ($typeRewrites): ?>
53
+ <table>
54
+ <thead>
55
+ <tr>
56
+ <th>Class Group</th>
57
+ <th>Rewrites</th>
58
+ </tr>
59
+ </thead>
60
+ <tbody>
61
+ <?php foreach ($typeRewrites as $classGroup => $rewrites): ?>
62
+ <tr>
63
+ <td><?php echo $classGroup ?></td>
64
+ <td><?php echo implode('<br>', $rewrites) ?></td>
65
+ </tr>
66
+ <?php endforeach; ?>
67
+ </tbody>
68
+ </table>
69
+ <?php else: ?>
70
+ <div class="empty">
71
+ <p>No rewrite conflicts</p>
72
+ </div>
73
+ <?php endif; ?>
74
+ </div>
75
+ </div>
76
+ <?php endforeach; ?>
77
+ </div>
app/design/frontend/base/default/template/ecocode_profiler/collector/rewrite/toolbar.phtml ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /** @var Ecocode_Profiler_Model_Collector_RewriteDataCollector $collector */
3
+ $collector = $this->getCollector();
4
+ $token = $this->getToken();
5
+
6
+ $conflictCount = $collector->getModuleRewriteConflictCount();
7
+ ?>
8
+
9
+ <?php if ($conflictCount): ?>
10
+ <div
11
+ class="sf-toolbar-block sf-toolbar-block-<?php echo $collector->getName() ?> sf-toolbar-status-<?php echo $conflictCount ? 'red' : 'normal' ?>">
12
+ <a target="_blank"
13
+ href="<?php echo Mage::helper('ecocode_profiler')->getCollectorUrl($token, $collector); ?>">
14
+ <div class="sf-toolbar-icon">
15
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
16
+ <path style="fill:#aaa" d="M23.61,11.07L17.07,4.35A1.2,1.2,0,0,0,15,5.28V9H1.4A1.82,1.82,0,0,0,0,10.82v2.61A1.55,
17
+ 1.55,0,0,0,1.4,15H15v3.72a1.2,1.2,0,0,0,2.07.93l6.63-6.72A1.32,1.32,0,0,0,23.61,11.07Z"/>
18
+ </svg>
19
+
20
+ <span class="sf-toolbar-value"><?php echo $conflictCount ? $conflictCount : '' ?> </span>
21
+
22
+ </div>
23
+ </a>
24
+ <div class="sf-toolbar-info">
25
+
26
+ <?php foreach($collector->getModuleRewrites() as $type => $typeRewrites):?>
27
+ <div class="sf-toolbar-info-piece">
28
+ <b><?php echo ucwords($type)?> Rewrites</b>
29
+ <span><?php echo count($typeRewrites) ?></span>
30
+ </div>
31
+ <?php endforeach;?>
32
+
33
+ <div class="sf-toolbar-info-piece">
34
+ <b>Rewrite Conflict Count</b>
35
+ <span class="sf-toolbar-status sf-toolbar-status-<?php echo $conflictCount ? 'red' : 'normal' ?>"><?php echo $conflictCount ?></span>
36
+ </div>
37
+ </div>
38
+
39
+ </div>
40
+ <?php endif; ?>
app/design/frontend/base/default/template/ecocode_profiler/collector/time/toolbar.phtml ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /** @var Ecocode_Profiler_Model_Collector_TimeDataCollector $collector */
3
+ $collector = $this->getCollector();
4
+ $token = $this->getToken();
5
+ ?>
6
+
7
+ <div class="sf-toolbar-block sf-toolbar-block-<?php echo $collector->getName()?> sf-toolbar-status-normal">
8
+ <div class="sf-toolbar-icon">
9
+ <svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="24" height="24" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
10
+ <path fill="#AAAAAA" d="M15.1,4.3c-2.1-0.5-4.2-0.5-6.2,0C8.6,4.3,8.2,4.1,8.2,3.8V3.4c0-1.2,1-2.3,2.3-2.3h3c1.2,0,2.3,1,2.3,2.3
11
+ v0.3C15.8,4.1,15.4,4.3,15.1,4.3z M20.9,14c0,4.9-4,8.9-8.9,8.9s-8.9-4-8.9-8.9s4-8.9,8.9-8.9S20.9,9.1,20.9,14z M16.7,15
12
+ c0-0.6-0.4-1-1-1H13V8.4c0-0.6-0.4-1-1-1s-1,0.4-1,1v6.2c0,0.6,0.4,1.3,1,1.3h3.7C16.2,16,16.7,15.6,16.7,15z"/>
13
+ </svg>
14
+ <span class="sf-toolbar-value"><?php echo sprintf('%0.0f', $collector->getTotalTime() * 1000)?></span>
15
+ <span class="sf-toolbar-label">ms</span>
16
+ </div>
17
+ <div class="sf-toolbar-info">
18
+ <div class="sf-toolbar-info-piece">
19
+ <b>Total Time</b>
20
+ <span><?php echo sprintf('%0.0f', $collector->getTotalTime() * 1000)?> ms</span>
21
+ </div>
22
+ </div>
23
+ </div>
app/design/frontend/base/default/template/ecocode_profiler/collector/translation/menu.phtml ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /** @var Ecocode_Profiler_Model_Collector_TranslationDataCollector $collector */
3
+ $collector = $this->getCollector();
4
+ $statusColor = ($collector->getStateCount('invalid') || $collector->getStateCount('missing')) ? 'error' : ($collector->getStateCount('fallback') ? 'warning' : 'normal');
5
+ ?>
6
+
7
+
8
+ <span class="label label-status-<?php echo $statusColor ?>">
9
+ <span class="icon">
10
+ <svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="24" height="24" viewBox="0 0 24 24"
11
+ enable-background="new 0 0 24 24" xml:space="preserve">
12
+ <path fill="#AAAAAA" d="M5.4,6H7v0.3c0,1.2-0.7,1.9-1.7,1.9c-1.1,0-1.4-0.4-1.4-1.1C3.9,6.2,4.5,6,5.4,6z M9.2,0H2.7
13
+ C1.2,0,0,0.9,0,2.4v6.5C0,10.4,1.2,11,2.7,11h1.2l3.3,3.2C7.6,14.4,8,14.5,8,14.1c0-1.4,0-2.8,0-4.2c0-0.4,0-0.7,0.1-1.1
14
+ c-0.1,0-0.3,0-0.4,0C7.4,8.9,7,8.7,7,8.4V7.9c0,0.7-1,1-1.8,1c-1.5,0-2.4-0.7-2.4-2c0-1.3,1.1-2,2.6-2H7V4.5c0-1-0.4-1.6-1.5-1.6
15
+ C4.8,2.9,4.4,3.1,4,3.6C3.8,3.8,3.8,3.8,3.7,3.8c-0.2,0-0.4-0.2-0.4-0.4c0-0.1,0-0.2,0.1-0.2C3.8,2.5,4.4,2,5.6,2C7.2,2,8,3,8,4.5v3
16
+ c1-1.4,1.8-2.4,4-2.4c0,0,0-1.9,0-2.7C12,0.9,10.7,0,9.2,0z M20.7,6h-8C10.8,6,9,7.2,9,9v8c0,1.8,2,3.3,4,3.3v3
17
+ c0,0.5,0.5,0.7,0.9,0.3l4-3.7h2.7c1.8,0,3.3-1.2,3.3-3V9C24,7.2,22.5,6,20.7,6z M13,9c0,0,0.6,0,1.1,0h4.8C19.3,9,20,9,20,9v0.8
18
+ c0,0-0.7,0.3-1.1,0.3h-4.8C13.7,10,13,9.7,13,9.7V9z M12.5,16.9c-0.2-0.2-0.3-0.3-0.6-0.5c1-0.8,1.8-2.1,2.2-3.4l0.7,0.3
19
+ C14.2,14.8,13.4,15.9,12.5,16.9z M17,12v4.8c0,0.7-0.2,0.8-1.2,0.8c-0.4,0-1,0-1.4-0.1c0-0.3-0.1-0.4-0.2-0.7
20
+ c0.6,0.1,0.9,0.1,1.4,0.1c0.4,0,0.4,0,0.4-0.3V12h-2.9c-0.4,0-1.1,0.1-1.1,0.1v-0.8c0,0,0.7-0.4,1.1-0.4h6.8c0.5,0,1.1,0.4,1.1,0.4
21
+ v0.8c0,0-0.6-0.1-1.1-0.1H17z M20.7,16.8c-1-1.1-1.6-1.9-2.3-3.6L19,13c0.5,1.1,0.8,1.7,1.4,2.4c0.3,0.3,0.5,0.5,0.8,0.9
22
+ C21.1,16.4,20.9,16.6,20.7,16.8z"/>
23
+ </svg>
24
+ </span>
25
+ <strong>Translation</strong>
26
+ <?php if ($collector->getNotOkCount()): ?>
27
+ <span class="count">
28
+ <span><?php echo $collector->getNotOkCount() ?> </span>
29
+ </span>
30
+ <?php endif ?>
31
+ </span>
app/design/frontend/base/default/template/ecocode_profiler/collector/translation/panel.phtml ADDED
@@ -0,0 +1,121 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /** @var Ecocode_Profiler_Block_Collector_Translation_Panel $this */
3
+
4
+ /** @var Ecocode_Profiler_Model_Collector_TranslationDataCollector $collector */
5
+ $collector = $this->getCollector();
6
+ ?>
7
+
8
+
9
+ <h2>Translation Metrics</h2>
10
+
11
+ <div class="metrics">
12
+ <div class="metric">
13
+ <span class="value"><?php echo $collector->getStateCount('translated'); ?></span>
14
+ <span class="label">Defined messages</span>
15
+ </div>
16
+
17
+ <div class="metric">
18
+ <span class="value"><?php echo $collector->getStateCount('fallback'); ?></span>
19
+ <span class="label">Fallback messages</span>
20
+ </div>
21
+
22
+ <div class="metric">
23
+ <span class="value"><?php echo $collector->getStateCount('missing'); ?></span>
24
+ <span class="label">Missing messages</span>
25
+ </div>
26
+
27
+ <div class="metric">
28
+ <span class="value"><?php echo $collector->getStateCount('invalid'); ?></span>
29
+ <span class="label">Invalid messages</span>
30
+ </div>
31
+ </div>
32
+
33
+
34
+
35
+ <h2>Translation Messages</h2>
36
+
37
+ <?php $messageGroups = $this->getMessageGroups();?>
38
+ <div class="sf-tabs">
39
+ <div class="tab">
40
+ <h3 class="tab-title">Defined <span class="badge"><?php echo count($messageGroups['translated']) ?></span></h3>
41
+
42
+ <div class="tab-content">
43
+ <p class="help">
44
+ These messages are correctly translated into the given locale.
45
+ </p>
46
+
47
+ <?php if (empty($messageGroups['translated'])): ?>
48
+ <div class="empty">
49
+ <p>None of the used translation messages are defined for the given locale.</p>
50
+ </div>
51
+ <?php else: ?>
52
+ <?php echo $this->renderTable($messageGroups['translated']); ?>
53
+ <?php endif ?>
54
+ </div>
55
+ </div>
56
+
57
+ <div class="tab">
58
+ <h3 class="tab-title">Fallback <span class="badge"><?php echo count($messageGroups['fallback']) ?></span></h3>
59
+
60
+ <div class="tab-content">
61
+ <p class="help">
62
+ These messages are not available for the given Module
63
+ but Magento found them in the global namespace.
64
+ </p>
65
+
66
+ <?php if (empty($messageGroups['fallback'])): ?>
67
+ <div class="empty">
68
+ <p>No fallback translation messages were used.</p>
69
+ </div>
70
+ <?php else: ?>
71
+ <?php echo $this->renderTable($messageGroups['fallback']); ?>
72
+ <?php endif ?>
73
+ </div>
74
+ </div>
75
+
76
+ <div class="tab">
77
+ <h3 class="tab-title">Missing <span class="badge"><?php echo count($messageGroups['missing']) ?></span></h3>
78
+
79
+ <div class="tab-content">
80
+ <p class="help">
81
+ These messages are not available for the given locale and cannot
82
+ be found in the fallback locales. Add them to the translation
83
+ catalogue to avoid Magento outputting untranslated contents.
84
+ </p>
85
+
86
+
87
+ <?php if (empty($messageGroups['missing'])): ?>
88
+ <div class="empty">
89
+ <p>There are no messages of this category.</p>
90
+ </div>
91
+ <?php else: ?>
92
+ <?php echo $this->renderTable($messageGroups['missing']); ?>
93
+ <?php endif ?>
94
+ </div>
95
+ </div>
96
+
97
+ <div class="tab">
98
+ <h3 class="tab-title">Invalid <span class="badge"><?php echo count($messageGroups['invalid']) ?></span></h3>
99
+
100
+ <div class="tab-content">
101
+ <p class="help">
102
+ These messages are not correctly translated as its not correctly formatted or parameters were missing
103
+ </p>
104
+
105
+ <?php if (empty($messageGroups['invalid'])): ?>
106
+ <div class="empty">
107
+ <p>There are no messages of this category.</p>
108
+ </div>
109
+ <?php else: ?>
110
+ <?php echo $this->renderTable($messageGroups['invalid']); ?>
111
+ <?php endif ?>
112
+ </div>
113
+ </div>
114
+ </div>
115
+
116
+ <style>
117
+ tr.sf-toggle-content.sf-toggle-visible {
118
+ display: table-row!important;
119
+ }
120
+
121
+ </style>
app/design/frontend/base/default/template/ecocode_profiler/collector/translation/panel/table.phtml ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /** @var Ecocode_Profiler_Helper_ValueExporter $valueExporter */
3
+ $valueExporter = $this->helper('ecocode_profiler/valueExporter');
4
+ $prefix = 'trans-' . uniqid(); ?>
5
+ <table>
6
+ <thead>
7
+ <tr>
8
+ <th>Locale</th>
9
+ <th>Module</th>
10
+ <th>Times used</th>
11
+ <th>Message ID</th>
12
+ <th>Message Preview</th>
13
+ </tr>
14
+ </thead>
15
+ <tbody>
16
+ <?php foreach ($this->getData('messages') as $index => $message): ?>
17
+ <tr>
18
+ <td class="font-normal text-small"><?php echo $message['locale'] ?></td>
19
+ <td class="font-normal text-small text-bold"><?php echo $message['module'] ?></td>
20
+ <td class="font-normal text-small"><?php echo $message['count'] ?></td>
21
+ <td>
22
+ <?php echo $message['code'] ?>
23
+
24
+ <?php if ($message['parameters']): ?>
25
+ <button class="btn-link newline text-small sf-toggle"
26
+ data-toggle-selector="#parameters-<?php echo $prefix . $index ?>"
27
+ data-toggle-alt-content="Hide parameters">Show parameters
28
+ </button>
29
+
30
+ <div id="parameters-<?php echo $prefix . $index ?>" class="hidden">
31
+ <?php foreach ($message['parameters'] as $parameters): ?>
32
+ <?php echo $valueExporter->exportValue($parameters); ?>
33
+ <?php endforeach; ?>
34
+ </div>
35
+ <?php endif; ?>
36
+ <?php if ($message['traces']): ?>
37
+ <button class="btn-link newline text-small sf-toggle"
38
+ data-toggle-selector="#traces-<?php echo $prefix . $index ?>"
39
+ data-toggle-alt-content="Hide traces">Show traces
40
+ </button>
41
+
42
+ <?php endif; ?>
43
+ </td>
44
+ <td><?php echo $message['translation'] ?></td>
45
+ </tr>
46
+ <?php if (!empty($message['traces'])): ?>
47
+ <tr class="hidden" id="traces-<?php echo $prefix . $index ?>">
48
+ <td colspan="3"></td>
49
+ <td colspan="2">
50
+ <div id="stack-<?php echo $prefix . $index ?>" class="hiddenx">
51
+ <table class="">
52
+ <tbody>
53
+ <?php foreach ($message['traces'] as $j => $trace): ?>
54
+ <tr>
55
+ <td class="nowrap">#<?php echo $j + 1 ?></td>
56
+ <td>
57
+ <ul class="sf-call-stack ">
58
+ <?php foreach ($trace as $item): ?>
59
+ <li>
60
+ <?php echo isset($item['class']) ? $item['class'] . '::' : '' ?><?php echo $item['function'] ?>
61
+ <br>
62
+ <?php if (isset($item['file'])): ?>
63
+ <small><?php echo $item['file'] ?>
64
+ ::<?php echo $item['line'] ?></small>
65
+ <?php endif; ?>
66
+ </li>
67
+ <?php endforeach; ?>
68
+ </ul>
69
+ </td>
70
+ </tr>
71
+ <?php endforeach; ?>
72
+
73
+ </tbody>
74
+ </table>
75
+ </div>
76
+ </td>
77
+ </tr>
78
+ <?php endif; ?>
79
+
80
+ <?php endforeach; ?>
81
+ </tbody>
82
+ </table>
app/design/frontend/base/default/template/ecocode_profiler/collector/translation/toolbar.phtml ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /** @var Ecocode_Profiler_Model_Collector_TranslationDataCollector $collector */
3
+ $collector = $this->getCollector();
4
+ $token = $this->getToken();
5
+ ?>
6
+ <?php $statusColor = $collector->getStateCount('invalid') || $collector->getStateCount('missing') ? 'red' : $collector->getStateCount('fallback') ? 'yellow' : 'normal' ?>
7
+
8
+ <div class="sf-toolbar-block sf-toolbar-block-<?php echo $collector->getName()?> sf-toolbar-status-<?php echo $statusColor ?>">
9
+ <a target="_blank"
10
+ href="<?php echo Mage::helper('ecocode_profiler')->getCollectorUrl($token, $collector); ?>">
11
+ <div class="sf-toolbar-icon">
12
+ <svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="24" height="24"
13
+ viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
14
+ <path fill="#AAAAAA" d="M5.4,6H7v0.3c0,1.2-0.7,1.9-1.7,1.9c-1.1,0-1.4-0.4-1.4-1.1C3.9,6.2,4.5,6,5.4,6z M9.2,0H2.7
15
+ C1.2,0,0,0.9,0,2.4v6.5C0,10.4,1.2,11,2.7,11h1.2l3.3,3.2C7.6,14.4,8,14.5,8,14.1c0-1.4,0-2.8,0-4.2c0-0.4,0-0.7,0.1-1.1
16
+ c-0.1,0-0.3,0-0.4,0C7.4,8.9,7,8.7,7,8.4V7.9c0,0.7-1,1-1.8,1c-1.5,0-2.4-0.7-2.4-2c0-1.3,1.1-2,2.6-2H7V4.5c0-1-0.4-1.6-1.5-1.6
17
+ C4.8,2.9,4.4,3.1,4,3.6C3.8,3.8,3.8,3.8,3.7,3.8c-0.2,0-0.4-0.2-0.4-0.4c0-0.1,0-0.2,0.1-0.2C3.8,2.5,4.4,2,5.6,2C7.2,2,8,3,8,4.5v3
18
+ c1-1.4,1.8-2.4,4-2.4c0,0,0-1.9,0-2.7C12,0.9,10.7,0,9.2,0z M20.7,6h-8C10.8,6,9,7.2,9,9v8c0,1.8,2,3.3,4,3.3v3
19
+ c0,0.5,0.5,0.7,0.9,0.3l4-3.7h2.7c1.8,0,3.3-1.2,3.3-3V9C24,7.2,22.5,6,20.7,6z M13,9c0,0,0.6,0,1.1,0h4.8C19.3,9,20,9,20,9v0.8
20
+ c0,0-0.7,0.3-1.1,0.3h-4.8C13.7,10,13,9.7,13,9.7V9z M12.5,16.9c-0.2-0.2-0.3-0.3-0.6-0.5c1-0.8,1.8-2.1,2.2-3.4l0.7,0.3
21
+ C14.2,14.8,13.4,15.9,12.5,16.9z M17,12v4.8c0,0.7-0.2,0.8-1.2,0.8c-0.4,0-1,0-1.4-0.1c0-0.3-0.1-0.4-0.2-0.7
22
+ c0.6,0.1,0.9,0.1,1.4,0.1c0.4,0,0.4,0,0.4-0.3V12h-2.9c-0.4,0-1.1,0.1-1.1,0.1v-0.8c0,0,0.7-0.4,1.1-0.4h6.8c0.5,0,1.1,0.4,1.1,0.4
23
+ v0.8c0,0-0.6-0.1-1.1-0.1H17z M20.7,16.8c-1-1.1-1.6-1.9-2.3-3.6L19,13c0.5,1.1,0.8,1.7,1.4,2.4c0.3,0.3,0.5,0.5,0.8,0.9
24
+ C21.1,16.4,20.9,16.6,20.7,16.8z"/>
25
+ </svg>
26
+
27
+ <span class="sf-toolbar-value"><?php echo $collector->getTranslationCount() ?></span>
28
+
29
+ </div>
30
+ </a>
31
+ <div class="sf-toolbar-info">
32
+ <div class="sf-toolbar-info-piece">
33
+ <b>Missing messages</b>
34
+ <span class="sf-toolbar-status sf-toolbar-status-<?php echo $collector->getStateCount('missing') ? 'red' : '' ?>">
35
+ <?php echo $collector->getStateCount('missing') ?>
36
+ </span>
37
+ </div>
38
+
39
+ <div class="sf-toolbar-info-piece">
40
+ <b>Fallback messages</b>
41
+ <span class="sf-toolbar-status sf-toolbar-status-<?php echo $collector->getStateCount('missing') ? 'yellow' : '' ?>">
42
+ <?php echo $collector->getStateCount('fallback') ?>
43
+ </span>
44
+ </div>
45
+ <div class="sf-toolbar-info-piece">
46
+ <b>Invalid messages</b>
47
+ <span class="sf-toolbar-status sf-toolbar-status-<?php echo $collector->getStateCount('invalid') ? 'red' : '' ?>">
48
+ <?php echo $collector->getStateCount('invalid') ?>
49
+ </span>
50
+ </div>
51
+ <div class="sf-toolbar-info-piece">
52
+ <b>Defined messages</b>
53
+ <span class="sf-toolbar-status"><?php echo $collector->getStateCount('translated') ?></span>
54
+ </div>
55
+ </div>
56
+ </div>
app/design/frontend/base/default/template/ecocode_profiler/layout.phtml ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8"/>
5
+ <meta name="robots" content="noindex,nofollow"/>
6
+ <meta name="viewport" content="width=device-width,initial-scale=1"/>
7
+ <title>Magento Profiler</title>
8
+ <link rel="icon" type="image/x-icon" sizes="16x16"
9
+ href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAACXBI
10
+ WXMAAA3XAAAN1wFCKJt4AAAAB3RJTUUH4AkNDCcsxO0sbAAAAYBJREFUOMvdk80rZXEYxz/PPV6u
11
+ bDBervHSdWaklLJQVrKxslQ2QoqNjS5ZTDTNyPYmFrIh6pDF/QvUNOU/UEgmLoW8zGAl3Ov8ntmc
12
+ ezt0yGznu/ye7/OpU5+f8Equeux6YzEDhEFGI87hTtBOXha3A9GilAl9USUG5Ht1GnTZPOVOflz/
13
+ 9ScQoN1YVwWfhlR1GigDnkAXvNkwkAP8FpGv5feHi5LAzQLO+6LtoqFZhGaP9xNDLLKW3AY4661r
14
+ sERmgE4PuCe4oxXO8YYAXPTZ10AJcKDoRKVzlAj638t+u0OVOaARuIk4yQ85/kE6L9Vas3R6czsQ
15
+ LXp0Q98qHpLjAJdhO55vmanileSPk8HqttxU3nXmJuQHhLUwDfBorF0g5vsU87rsJhCQjWrJu7pX
16
+ Af+Q/wWgmC6UrfefyZ5gevD0pNI53tRuWviMPhMnbMdfnpbW7t+xS1NG5axIksDF80+ReUFHfC6k
17
+ FZkHkO+YN19jJj7/cVXHqlaP9oN2fwF3BYdp8BgRAQAAAABJRU5ErkJggg==">
18
+ <?php echo $this->getChildHtml('profiler_head'); ?>
19
+ <style type="text/css">
20
+ <?php echo $this->getChildHtml('profiler_css'); ?>
21
+ </style>
22
+ <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
23
+ <script>
24
+ <?php echo $this->getChildHtml('profiler_js'); ?>
25
+ </script>
26
+ </head>
27
+ <body>
28
+ <div id="header">
29
+ <div class="container">
30
+ <h1>
31
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="svgMageLogo"
32
+ width="24" xml:space="preserve" height="24" viewBox="0 0 53.692 62" baseProfile="" version="1.1"
33
+ y="0px" x="0px">
34
+ <g fill="#E85D22">
35
+ <path d="m26.845 8.857"/>
36
+ <polygon points="53.692 15.5 53.692 46.5 46.021 50.929 46.021 19.929 26.845 8.857 7.67 19.928 7.67 50.929 0 46.5 0 15.5 26.845 0"/>
37
+ <polygon points="26.847 62 15.341 55.356 15.341 24.357 23.011 19.928 23.011 50.929 26.845 53.257 30.682 50.929 30.682 19.929 38.353 24.357 38.353 55.356"/>
38
+ </g>
39
+ </svg>
40
+ Magento <span>Profiler</span>
41
+ </h1>
42
+ </div>
43
+ <div class="logo-ecocode" style="float: right">
44
+ <a href="http://www.ecocode.de">
45
+ <svg version="1.1"
46
+ xmlns="http://www.w3.org/2000/svg"
47
+ viewBox="0 0 606.25408 139.86"
48
+ xml:space="preserve" height="28">
49
+ <g transform="translate(-86.277155,-273.24507)">
50
+ <g fill="#6c3">
51
+ <path d="m 110.93715,360.72507 1.98,6.66 47.16,0 c 0.36,-2.7 0.54,-5.4 0.54,-7.92 0,-19.98 -12.24,-34.56 -34.74,-34.56 -23.94,0 -39.599995,19.44 -39.599995,45.72 0,23.76 15.659995,41.4 39.059995,41.4 11.16,0 25.2,-2.16 32.04,-10.08 l -5.4,-3.96 c -7.38,4.14 -12.42,5.22 -18.72,5.22 -20.88,0 -30.06,-14.58 -30.06,-35.82 0,-14.4 3.24,-36.9 21.24,-36.9 14.76,0 20.16,12.42 20.16,30.24 l -33.66,0 z"/>
52
+ <path d="m 408.97778,398.52507 c -6.3,3.6 -11.52,5.58 -18.54,5.58 -23.4,0 -29.16,-22.14 -29.16,-40.32 0,-19.8 13.32,-29.52 29.16,-29.52 5.58,0 12.24,2.88 16.56,6.3 l 5.76,-5.76 c -4.86,-5.22 -12.78,-9.9 -23.76,-9.9 -28.26,0 -44.1,21.78 -44.1,46.98 0,24.3 13.68,41.22 38.7,41.22 17.82,0 24.66,-5.22 30.42,-10.98 l -5.04,-3.6 z"/>
53
+ </g>
54
+ <g fill="#666">
55
+ <path d="m 234.95434,398.52507 c -6.3,3.6 -11.52,5.58 -18.54,5.58 -23.4,0 -29.16,-22.14 -29.16,-40.32 0,-19.8 13.32,-29.52 29.16,-29.52 5.58,0 12.24,2.88 16.56,6.3 l 5.76,-5.76 c -4.86,-5.22 -12.78,-9.9 -23.76,-9.9 -28.26,0 -44.1,21.78 -44.1,46.98 0,24.3 13.68,41.22 38.7,41.22 17.82,0 24.66,-5.22 30.42,-10.98 l -5.04,-3.6 z"/>
56
+ <path d="m 332.64653,366.48507 c 0,-26.82 -14.58,-41.22 -39.96,-41.22 l -4.68,0 c 23.58,9.18 27.72,23.94 27.72,47.88 0,21.42 -11.88,33.3 -25.02,33.3 -15.84,0 -25.2,-18.36 -25.2,-43.38 0,-21.06 8.64,-32.4 23.94,-32.4 l 0.36,0 c -3.06,-1.44 -5.94,-2.16 -9,-2.16 -4.86,0 -10.08,1.8 -15.48,5.22 -10.26,7.92 -16.02,19.8 -16.02,34.92 0,26.1 13.5,44.46 38.7,44.46 26.46,0 44.64,-18.72 44.64,-46.62 z"/>
57
+ <path d="m 509.48247,366.48507 c 0,-26.82 -14.58,-41.22 -39.96,-41.22 l -4.68,0 c 23.58,9.18 27.72,23.94 27.72,47.88 0,21.42 -11.88,33.3 -25.02,33.3 -15.84,0 -25.2,-18.36 -25.2,-43.38 0,-21.06 8.64,-32.4 23.94,-32.4 l 0.36,0 c -3.06,-1.44 -5.94,-2.16 -9,-2.16 -4.86,0 -10.08,1.8 -15.48,5.22 -10.26,7.92 -16.02,19.8 -16.02,34.92 0,26.1 13.5,44.46 38.7,44.46 26.46,0 44.64,-18.72 44.64,-46.62 z"/>
58
+ <path d="m 537.21372,366.48507 c 0,-15.3 5.76,-32.76 23.76,-32.76 9.36,0 12.24,3.24 15.48,6.66 l 4.86,-5.4 c -6.3,-7.02 -11.7,-10.26 -20.34,-10.26 -26.82,0 -39.6,23.94 -39.6,46.98 0,22.68 12.6,41.22 36.36,41.22 16.2,0 21.6,-10.26 26.82,-16.92 0,8.1 -0.18,10.8 -0.18,13.5 l 27.72,0 0,-4.86 c -3.24,0 -9.18,-1.08 -10.26,-2.7 -1.44,-2.16 -1.62,-5.22 -1.62,-11.7 l 0,-76.32 c 0,-10.98 0,-28.8 1.44,-40.68 l -18.18,9.18 c 0.72,0.9 1.08,3.06 1.08,6.48 l 0,81.9 c 0,9.36 -1.8,17.82 -6.12,23.04 -3.78,4.86 -9,8.82 -16.74,8.82 -21.78,0 -24.48,-16.92 -24.48,-36.18 z"/>
59
+ <path d="m 642.85122,360.72507 1.98,6.66 47.16,0 c 0.36,-2.7 0.54,-5.4 0.54,-7.92 0,-19.98 -12.24,-34.56 -34.74,-34.56 -23.94,0 -39.6,19.44 -39.6,45.72 0,23.76 15.66,41.4 39.06,41.4 11.16,0 25.2,-2.16 32.04,-10.08 l -5.4,-3.96 c -7.38,4.14 -12.42,5.22 -18.72,5.22 -20.88,0 -30.06,-14.58 -30.06,-35.82 0,-14.4 3.24,-36.9 21.24,-36.9 14.76,0 20.16,12.42 20.16,30.24 l -33.66,0 z"/>
60
+ </g>
61
+ </g>
62
+ </svg><br>
63
+
64
+ <small>Made with Herzblut in Berlin</small>
65
+ </a>
66
+ </div>
67
+ </div>
68
+
69
+
70
+ <div id="summary">
71
+ <?php echo $this->getChildHtml('summery'); ?>
72
+ </div>
73
+
74
+ <div id="content" class="container">
75
+ <div id="main">
76
+ <div id="collector-wrapper">
77
+ <div id="collector-content">
78
+ <?php echo $this->getChildHtml('content'); ?>
79
+ </div>
80
+ </div>
81
+ <?php echo $this->getChildHtml('left'); ?>
82
+ </div>
83
+ </div>
84
+
85
+
86
+ </body>
87
+ </html>
app/design/frontend/base/default/template/ecocode_profiler/layout/sidebar.phtml ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /** @var Ecocode_Profiler_Model_Profile $profile */
3
+ $profile = Mage::registry('current_profile');
4
+
5
+ $request = $this->getRequest();
6
+ $token = false;
7
+ if ($profile && $profile->getToken()) {
8
+ $token = $profile->getToken();
9
+ }
10
+ ?>
11
+
12
+ <div id="sidebar">
13
+ <div id="sidebar-shortcuts">
14
+ <div class="shortcuts">
15
+ <a href="#" class="visible-small"
16
+ onclick="Sfjs.toggleClass(document.getElementById('sidebar'), 'expanded'); return false;">
17
+ <span class="icon">
18
+ <svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="24" height="24" viewBox="0 0 24 24" xml:space="preserve">
19
+ <path fill="#AAAAAA" d="m 2.571,17.5 18.859,0 c 0.87,0 1.57,0.7 1.57,1.57 l 0,1.57 c 0,0.87 -0.7,1.57 -1.57,1.57 l -18.859,0 C 1.702,22.21 1,21.51 1,20.64 L 1,19.07 C 1,18.2 1.702,17.5 2.571,17.5 Z M 1,11.21 1,12.79 c 0,0.86 0.702,1.56 1.571,1.56 l 18.859,0 c 0.87,0 1.57,-0.7 1.57,-1.56 l 0,-1.58 C 23,10.35 22.3,9.644 21.43,9.644 l -18.859,0 C 1.702,9.644 1,10.35 1,11.21 Z M 1,3.357 1,4.929 c 0,0.869 0.702,1.572 1.571,1.572 l 18.859,0 C 22.3,6.501 23,5.798 23,4.929 L 23,3.357 C 23,2.489 22.3,1.786 21.43,1.786 l -18.859,0 C 1.702,1.786 1,2.489 1,3.357 Z" />
20
+ </svg>
21
+ </span>
22
+ </a>
23
+
24
+ <a class="btn btn-sm" href="<?php echo Mage::getUrl('_profiler/index/search', ['limit' => 10])?>">Last 10</a>
25
+ <a class="btn btn-sm"
26
+ href="<?php echo Mage::helper('ecocode_profiler')->getUrl('latest'); ?>">Latest</a>
27
+
28
+ <a class="sf-toggle btn btn-sm" data-toggle-selector="#sidebar-search" <?php echo $token ?: 'data-toggle-initial="display"'?>>
29
+ <svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="24" height="24"
30
+ viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
31
+ <path fill="#AAAAAA" d="M11.61,0.357c-4.4,0-7.98,3.58-7.98,7.98c0,1.696,0.526,3.308,1.524,4.679l-4.374,4.477
32
+ c-0.238,0.238-0.369,0.554-0.369,0.891c0,0.336,0.131,0.653,0.369,0.891c0.238,0.238,0.554,0.369,0.891,0.369
33
+ c0.336,0,0.653-0.131,0.893-0.371l4.372-4.475c1.369,0.996,2.98,1.521,4.674,1.521c4.4,0,7.98-3.58,7.98-7.98
34
+ S16.01,0.357,11.61,0.357z M17.07,8.337c0,3.011-2.449,5.46-5.46,5.46c-3.011,0-5.46-2.449-5.46-5.46s2.449-5.46,5.46-5.46
35
+ C14.62,2.877,17.07,5.326,17.07,8.337z"/>
36
+ </svg>
37
+ <span class="hidden-small">Search</span>
38
+ </a>
39
+
40
+ <!--{{ render(path('_profiler_search_bar', request.query.all)) }}-->
41
+ <div id="sidebar-search">
42
+ <form action="<?php echo Mage::getUrl('_profiler/index/search', [])?>" method="get">
43
+ <div class="form-group">
44
+ <label for="ip">IP</label>
45
+ <input type="text" name="ip" id="ip" value="<?php echo $request->getParam('ip');?> ">
46
+ </div>
47
+
48
+ <div class="form-group">
49
+ <label for="method">Method</label>
50
+ <select name="method" id="method">
51
+ <option value="">Any</option>
52
+ <?php foreach (['DELETE', 'GET', 'HEAD', 'PATCH', 'POST', 'PUT'] as $m):?>
53
+ <option <?php echo $request->getParam('method') === $m ? 'selected="selected"' : ''?>><?php echo $m?></option>
54
+ <?php endforeach;?>
55
+ </select>
56
+ </div>
57
+
58
+ <div class="form-group">
59
+ <label for="status_code">Status</label>
60
+ <input type="number" name="status_code" id="status_code" value="<?php echo $request->getParam('status_code');?>">
61
+ </div>
62
+
63
+ <div class="form-group">
64
+ <label for="url">URL</label>
65
+ <input type="text" name="url" id="url" value="<?php echo $request->getParam('url');?>">
66
+ </div>
67
+
68
+ <div class="form-group">
69
+ <label for="token">Token</label>
70
+ <input type="text" name="_token" id="token" value="<?php echo $request->getParam('_token');?>">
71
+ </div>
72
+
73
+ <div class="form-group">
74
+ <label for="start">From</label>
75
+ <input type="date" name="start" id="start" value="<?php echo $request->getParam('start');?>">
76
+ </div>
77
+
78
+ <div class="form-group">
79
+ <label for="end">Until</label>
80
+ <input type="date" name="end" id="end" value="<?php echo $request->getParam('end');?>">
81
+ </div>
82
+
83
+ <div class="form-group">
84
+ <label for="limit">Results</label>
85
+ <select name="limit" id="limit">
86
+ <?php foreach ([10, 50, 100] as $l):?>
87
+ <option <?php echo $request->getParam('limit') === $l ? 'selected="selected"' : ''?>><?php echo $l?></option>
88
+ <?php endforeach;?>
89
+ </select>
90
+ </div>
91
+
92
+ <div class="form-group">
93
+ <button type="submit" class="btn btn-sm">Search</button>
94
+ </div>
95
+ </form>
96
+ </div>
97
+ </div>
98
+ </div>
99
+
100
+ <ul id="menu-profiler">
101
+ <?php echo $this->getChildHtml('menu'); ?>
102
+ </ul>
103
+ </div>
app/design/frontend/base/default/template/ecocode_profiler/layout/sidebar/menu.phtml ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php /** @var Ecocode_Profiler_Block_Profiler_Sidebar_Menu $this */ ?>
2
+ <?php
3
+ if (!$this->getProfile()) {
4
+ return '';
5
+ }
6
+ $token = $this->getProfile()->getToken();
7
+ $panel = Mage::registry('current_panel');
8
+ $helper = Mage::helper('ecocode_profiler');
9
+ ?>
10
+ <?php foreach ($this->getMenuBlocks() as $name => $block): ?>
11
+ <?php
12
+ /** @var Ecocode_Profiler_Block_Collector_Base $block */
13
+ /** @var Ecocode_Profiler_Model_Collector_DataCollectorInterface $collector */
14
+ $collector = $block->getCollector();
15
+ $url = $helper->getUrl($token, $name);
16
+ ?>
17
+ <li class="<?php echo $name ?> <?php echo $name === $panel ? 'selected' : '' ?>">
18
+ <a href="<?php echo $url ?>"><?php echo $block->toHtml(); ?></a>
19
+ </li>
20
+
21
+ <?php endforeach; ?>
22
+
app/design/frontend/base/default/template/ecocode_profiler/profiler/base.css.phtml ADDED
@@ -0,0 +1,935 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ $colors = [
3
+ 'success' => '#4F805D',
4
+ 'warning' => '#A46A1F',
5
+ 'error' => '#B0413E'
6
+ ]
7
+ ?>
8
+ html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0;font-size:2em}mark{color:#000;background:#ff0}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{height:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{margin:0;font:inherit;color:inherit}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid silver}legend{padding:0;border:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-spacing:0;border-collapse:collapse}td,th{padding:0}
9
+
10
+ body {
11
+ background-color: #F9F9F9;
12
+ color: #222;
13
+ font-family: Helvetica, Arial, sans-serif;
14
+ font-size: 14px;
15
+ line-height: 1.4;
16
+ }
17
+
18
+ .logo-ecocode{
19
+ float: right;
20
+ }
21
+
22
+ .logo-ecocode{
23
+ float: right;
24
+ text-align: center;
25
+ padding: 0 10px;
26
+ }
27
+ .logo-ecocode a{
28
+ color: #CCC;
29
+ }
30
+
31
+
32
+ h2, h3, h4 {
33
+ font-weight: 500;
34
+ margin: 1.5em 0 .5em;
35
+ }
36
+ h2 + h3,
37
+ h3 + h4 {
38
+ margin-top: 1em;
39
+ }
40
+ h2 {
41
+ font-size: 24px;
42
+ }
43
+ h3 {
44
+ font-size: 21px;
45
+ }
46
+ h4 {
47
+ font-size: 18px;
48
+ }
49
+ h2 span, h3 span, h4 span,
50
+ h2 small, h3 small, h4 small {
51
+ color: #999;
52
+ }
53
+
54
+ li {
55
+ margin-bottom: 10px;
56
+ }
57
+
58
+ p {
59
+ font-size: 16px;
60
+ margin-bottom: 1em;
61
+ }
62
+
63
+ a {
64
+ color: #218BC3;
65
+ text-decoration: none;
66
+ }
67
+ a:hover {
68
+ text-decoration: underline;
69
+ }
70
+ a.link-inverse {
71
+ text-decoration: underline;
72
+ }
73
+ a.link-inverse:hover {
74
+ text-decoration: none;
75
+ }
76
+ a:active,
77
+ a:hover {
78
+ outline: 0;
79
+ }
80
+ h2 a,
81
+ h3 a,
82
+ h4 a {
83
+ text-decoration: underline;
84
+ }
85
+ h2 a:hover,
86
+ h3 a:hover,
87
+ h4 a:hover {
88
+ text-decoration: none;
89
+ }
90
+
91
+ abbr {
92
+ border-bottom: 1px dotted #444;
93
+ cursor: help;
94
+ }
95
+
96
+ code, pre {
97
+ font-family: Helvetica, Arial, sans-serif;
98
+ }
99
+
100
+ button {
101
+ font-family: Helvetica, Arial, sans-serif;
102
+ }
103
+ .btn {
104
+ background: #777;
105
+ border-radius: 2px;
106
+ border: 0;
107
+ color: #F5F5F5;
108
+ display: inline-block;
109
+ padding: .5em .75em;
110
+ }
111
+ .btn:hover {
112
+ cursor: pointer;
113
+ opacity: 0.8;
114
+ text-decoration: none;
115
+ }
116
+ .btn-sm {
117
+ font-size: 12px;
118
+ }
119
+ .btn-sm svg {
120
+ height: 16px;
121
+ width: 16px;
122
+ vertical-align: middle;
123
+ }
124
+ .btn-link {
125
+ border-color: transparent;
126
+ color: #218BC3;
127
+ text-decoration: none;
128
+ background-color: transparent;
129
+ outline: none;
130
+ border: 0;
131
+ padding: 0;
132
+ }
133
+ .btn-link:hover {
134
+ text-decoration: underline;
135
+ }
136
+
137
+ table, tr, th, td {
138
+ background: #FFF;
139
+ border-collapse: collapse;
140
+ line-height: 1.5;
141
+ vertical-align: top;
142
+ }
143
+ table {
144
+ background: #FFF; border: 1px solid #E0E0E0; box-shadow: 0px 0px 1px rgba(128, 128, 128, .2);;
145
+ margin: 1em 0;
146
+ width: 100%;
147
+ }
148
+
149
+ table th, table td {
150
+ padding: 8px 10px;
151
+ }
152
+
153
+ table th {
154
+ font-weight: bold;
155
+ text-align: left;
156
+ }
157
+ table thead th {
158
+ background-color: #E0E0E0;
159
+ }
160
+ table thead th.key {
161
+ width: 19%;
162
+ }
163
+
164
+ table tbody th,
165
+ table tbody td {
166
+ font-family: Helvetica, Arial, sans-serif;
167
+ border: 1px solid #E0E0E0;
168
+ border-width: 1px 0;
169
+ }
170
+
171
+ table tbody td {
172
+ word-break: break-all; -webkit-hyphens: auto; -moz-hyphens: auto; hyphens: auto;
173
+ }
174
+
175
+ table tbody div {
176
+ margin: .25em 0;
177
+ }
178
+ table tbody ul {
179
+ margin: 0;
180
+ padding: 0 0 0 1em;
181
+ }
182
+
183
+ .block {
184
+ display: block;
185
+ }
186
+ .hidden {
187
+ display: none;
188
+ }
189
+ .nowrap {
190
+ white-space: pre;
191
+ }
192
+ .newline {
193
+ display: block;
194
+ }
195
+ .break-long-words {
196
+ word-break: break-all; -webkit-hyphens: auto; -moz-hyphens: auto; hyphens: auto;
197
+ }
198
+ .text-small {
199
+ font-size: 12px !important;
200
+ }
201
+ .text-muted {
202
+ color: #999;
203
+ }
204
+ .text-bold {
205
+ font-weight: bold;
206
+ }
207
+ .text-right {
208
+ text-align: right;
209
+ }
210
+ .text-center {
211
+ text-align: center;
212
+ }
213
+ .font-normal {
214
+ font-family: Helvetica, Arial, sans-serif;
215
+ font-size: 14px;
216
+ }
217
+ .help {
218
+ color: #999;
219
+ font-size: 14px;
220
+ margin-bottom: .5em;
221
+ }
222
+ .empty {
223
+ border: 4px dashed #E0E0E0;
224
+ color: #999;
225
+ margin: 1em 0;
226
+ padding: .5em 2em;
227
+ }
228
+
229
+ .label {
230
+ background-color: #666;
231
+ color: #FAFAFA;
232
+ display: inline-block;
233
+ font-size: 12px;
234
+ font-weight: bold;
235
+ padding: 3px 7px;
236
+ white-space: nowrap;
237
+ }
238
+ .label.same-width {
239
+ min-width: 70px;
240
+ text-align: center;
241
+ }
242
+ .label.status-success { background: <?php echo $colors['success']; ?>; color: #FFF; }
243
+ .label.status-warning { background: <?php echo $colors['warning']; ?>; color: #FFF; }
244
+ .label.status-error { background: <?php echo $colors['error']; ?>; color: #FFF; }
245
+
246
+ .metrics {
247
+ margin: 1em 0;
248
+ overflow: auto;
249
+ }
250
+ .metrics .metric {
251
+ float: left;
252
+ margin-right: 1em;
253
+ }
254
+
255
+ .metric {
256
+ background: #FFF; border: 1px solid #E0E0E0; box-shadow: 0px 0px 1px rgba(128, 128, 128, .2);
257
+ min-width: 100px;
258
+ min-height: 70px;
259
+ }
260
+ .metric .value {
261
+ display: block;
262
+ font-size: 28px;
263
+ padding: 8px 15px 4px;
264
+ text-align: center;
265
+ }
266
+ .metric .value svg {
267
+ margin: 5px 0 -5px;
268
+ }
269
+ .metric .unit {
270
+ color: #999;
271
+ font-size: 18px;
272
+ margin-left: -4px;
273
+ }
274
+ .metric .label {
275
+ background: #E0E0E0;
276
+ color: #222;
277
+ display: block;
278
+ font-size: 12px;
279
+ padding: 5px;
280
+ text-align: center;
281
+ }
282
+
283
+ .metrics-horizontal .metric {
284
+ min-height: 0;
285
+ min-width: 0;
286
+ }
287
+ .metrics-horizontal .metric .value,
288
+ .metrics-horizontal .metric .label {
289
+ display: inline;
290
+ padding: 2px 6px;
291
+ }
292
+ .metrics-horizontal .metric .label {
293
+ display: inline-block;
294
+ padding: 6px;
295
+ }
296
+ .metrics-horizontal .metric .value {
297
+ font-size: 16px;
298
+ }
299
+ .metrics-horizontal .metric .value svg {
300
+ max-height: 14px;
301
+ line-height: 10px;
302
+ margin: 0;
303
+ padding-left: 4px;
304
+ vertical-align: middle;
305
+ }
306
+
307
+ .card {
308
+ background: #FFF; border: 1px solid #E0E0E0; box-shadow: 0px 0px 1px rgba(128, 128, 128, .2);;
309
+ margin: 1em 0;
310
+ padding: 10px;
311
+ }
312
+ .card-block + .card-block {
313
+ border-top: 1px solid #E0E0E0;
314
+ padding-top: 10px;
315
+ }
316
+ .card *:first-child,
317
+ .card-block *:first-child {
318
+ margin-top: 0;
319
+ }
320
+ .card .label {
321
+ background-color: #EEE;
322
+ color: #222;
323
+ }
324
+
325
+ .status-success {
326
+ background: rgba(94, 151, 110, 0.3);
327
+ }
328
+ .status-warning {
329
+ background: rgba(240, 181, 24, 0.3);
330
+ }
331
+ .status-error {
332
+ background: rgba(176, 65, 62, 0.2);
333
+ }
334
+ .status-success td,
335
+ .status-warning td,
336
+ .status-error td {
337
+ background: transparent;
338
+ }
339
+ tr.status-error td,
340
+ tr.status-warning td {
341
+ border-bottom: 1px solid #FAFAFA;
342
+ border-top: 1px solid #FAFAFA;
343
+ }
344
+
345
+ .status-warning .colored {
346
+ color: <?php echo $colors['warning']; ?>;
347
+ }
348
+ .status-error .colored {
349
+ color: <?php echo $colors['error']; ?>;
350
+ }
351
+
352
+ .highlight pre {
353
+ margin: 0;
354
+ white-space: pre-wrap;
355
+ }
356
+
357
+ .highlight .keyword { color: #8959A8; font-weight: bold; }
358
+ .highlight .word { color: #222222; }
359
+ .highlight .variable { color: #916319; }
360
+ .highlight .symbol { color: #222222; }
361
+ .highlight .comment { color: #999999; }
362
+ .highlight .backtick { color: #718C00; }
363
+ .highlight .string { color: #718C00; }
364
+ .highlight .number { color: #F5871F; font-weight: bold; }
365
+ .highlight .error { color: #C82829; }
366
+
367
+ .sf-icon {
368
+ vertical-align: middle;
369
+ background-repeat: no-repeat;
370
+ background-size: contain;
371
+ width: 16px;
372
+ height: 16px;
373
+ display: inline-block;
374
+ }
375
+ .sf-icon svg {
376
+ width: 16px;
377
+ height: 16px;
378
+ }
379
+ .sf-icon.sf-medium,
380
+ .sf-icon.sf-medium svg {
381
+ width: 24px;
382
+ height: 24px;
383
+ }
384
+ .sf-icon.sf-large,
385
+ .sf-icon.sf-large svg {
386
+ width: 32px;
387
+ height: 32px;
388
+ }
389
+
390
+
391
+ .container {
392
+ max-width: 1300px;
393
+ padding-right: 15px;
394
+ }
395
+ #content {
396
+ min-height: 1024px;
397
+ overflow: hidden;
398
+ }
399
+ #collector-wrapper {
400
+ float: left;
401
+ width: 100%;
402
+ }
403
+ #collector-content {
404
+ margin: 0 0 30px 220px;
405
+ padding: 14px 0 14px 20px;
406
+ }
407
+
408
+ #main h2:first-of-type {
409
+ margin-top: 0;
410
+ }
411
+
412
+ #header {
413
+ background-color: #222;
414
+ overflow: hidden;
415
+ }
416
+ #header h1 {
417
+ color: #FFF;
418
+ font-weight: normal;
419
+ font-size: 21px;
420
+ float: left;
421
+ margin: 0;
422
+ padding: 10px 10px 8px;
423
+ }
424
+ #header h1 span {
425
+ color: #CCC;
426
+ }
427
+ #header h1 svg {
428
+ height: 40px;
429
+ width: 40px;
430
+ margin-top: -4px;
431
+ vertical-align: middle;
432
+ }
433
+ #header h1 svg path {
434
+ fill: #FFF;
435
+ }
436
+ #header .search {
437
+ float: right;
438
+ padding-top: 11px;
439
+ }
440
+ #header .search input {
441
+ border: 1px solid #DDD;
442
+ margin-right: 4px;
443
+ padding: 7px 8px;
444
+ width: 200px;
445
+ }
446
+
447
+ #summary .status {
448
+ background: #E0E0E0;
449
+ border: solid rgba(0, 0, 0, 0.1);
450
+ border-width: 2px 0;
451
+ padding: 10px;
452
+ }
453
+ #summary h2,
454
+ #summary h2 a {
455
+ color: #222;
456
+ font-size: 21px;
457
+ margin: 0;
458
+ text-decoration: none;
459
+ }
460
+ #summary h2 a:hover {
461
+ text-decoration: underline;
462
+ }
463
+
464
+ #summary .status-success { background: <?php echo $colors['success']; ?>; }
465
+ #summary .status-warning { background: <?php echo $colors['warning']; ?>; }
466
+ #summary .status-error { background: <?php echo $colors['error']; ?>; }
467
+
468
+ #summary .status-success h2,
469
+ #summary .status-success a,
470
+ #summary .status-warning h2,
471
+ #summary .status-warning a,
472
+ #summary .status-error h2,
473
+ #summary .status-error a {
474
+ color: #FFF;
475
+ }
476
+
477
+ #summary dl.metadata {
478
+ margin: 5px 0 0;
479
+ color: rgba(255, 255, 255, 0.75);
480
+ }
481
+ #summary dl.metadata dt,
482
+ #summary dl.metadata dd {
483
+ display: inline-block;
484
+ font-size: 13px;
485
+ }
486
+ #summary dl.metadata dt {
487
+ font-weight: bold;
488
+ }
489
+ #summary dl.metadata dt:after {
490
+ content: ':';
491
+ }
492
+ #summary dl.metadata dd {
493
+ margin: 0 1.5em 0 0;
494
+ }
495
+
496
+ #summary dl.metadata .label {
497
+ background: rgba(255, 255, 255, 0.2);
498
+ }
499
+
500
+ #sidebar {
501
+ background: #444;
502
+ color: #CCC;
503
+ float: left;
504
+ margin-bottom: -99999px;
505
+ margin-left: -100%;
506
+ padding-bottom: 99999px;
507
+ position: relative;
508
+ width: 220px;
509
+ z-index: 9999;
510
+ }
511
+ #sidebar .module {
512
+ padding: 10px;
513
+ width: 220px;
514
+ }
515
+
516
+ #sidebar #sidebar-shortcuts {
517
+ background: #333;
518
+ width: 220px;
519
+ }
520
+ #sidebar #sidebar-shortcuts .shortcuts {
521
+ position: relative;
522
+ padding: 16px 10px;
523
+ }
524
+ #sidebar-shortcuts .icon {
525
+ display: block;
526
+ float: left;
527
+ width: 50px;
528
+ margin: 2px 0 0 -10px;
529
+ text-align: center;
530
+ }
531
+ #sidebar #sidebar-shortcuts .btn {
532
+ color: #F5F5F5;
533
+ }
534
+ #sidebar #sidebar-shortcuts .btn + .btn {
535
+ margin-left: 5px;
536
+ }
537
+ #sidebar #sidebar-shortcuts .btn {
538
+ padding: .5em;
539
+ }
540
+
541
+ #sidebar-search .form-group:first-of-type {
542
+ padding-top: 20px;
543
+ }
544
+ #sidebar-search .form-group {
545
+ clear: both;
546
+ overflow: hidden;
547
+ padding-bottom: 10px;
548
+ }
549
+ #sidebar-search .form-group label {
550
+ float: left;
551
+ font-size: 13px;
552
+ line-height: 24px;
553
+ width: 60px;
554
+ }
555
+ #sidebar-search .form-group input,
556
+ #sidebar-search .form-group select {
557
+ float: left;
558
+ font-size: 13px;
559
+ padding: 3px 6px;
560
+ }
561
+ #sidebar-search .form-group input {
562
+ background: #CCC;
563
+ border: 1px solid #999;
564
+ color: #222;
565
+ width: 120px;
566
+ }
567
+ #sidebar-search .form-group select {
568
+ color: #222;
569
+ }
570
+ #sidebar-search .form-group .btn {
571
+ float: right;
572
+ margin-right: 10px;
573
+ }
574
+
575
+ #menu-profiler {
576
+ margin: 0;
577
+ padding: 0;
578
+ list-style-type: none;
579
+ }
580
+ #menu-profiler li {
581
+ position: relative;
582
+ margin-bottom: 0;
583
+ width: 220px;
584
+ }
585
+ #menu-profiler li a {
586
+ border: solid transparent;
587
+ border-width: 2px 0;
588
+ color: #CCC;
589
+ display: block;
590
+ }
591
+ #menu-profiler li a:hover {
592
+ text-decoration: none;
593
+ }
594
+ #menu-profiler li a .label {
595
+ background: transparent;
596
+ color: #EEE;
597
+ display: block;
598
+ padding: 8px 10px 8px 50px;
599
+ overflow: hidden;
600
+ white-space: nowrap;
601
+ }
602
+ #menu-profiler li a .label .icon {
603
+ display: block;
604
+ position: absolute;
605
+ left: 0;
606
+ top: 8px;
607
+ width: 50px;
608
+ text-align: center;
609
+ }
610
+ #menu-profiler .label .icon img,
611
+ #menu-profiler .label .icon svg {
612
+ height: 24px;
613
+ max-width: 24px;
614
+ }
615
+ #menu-profiler li a .label .icon svg path {
616
+ fill: #DDD;
617
+ }
618
+ #menu-profiler li a .label strong {
619
+ font-size: 16px;
620
+ font-weight: normal;
621
+ }
622
+ #menu-profiler li a .label.disabled {
623
+ opacity: .25;
624
+ }
625
+ #menu-profiler li a:hover .label.disabled,
626
+ #menu-profiler li.selected a .label.disabled {
627
+ opacity: 1;
628
+ }
629
+
630
+ #menu-profiler li.selected a,
631
+ #menu-profiler:hover li.selected a:hover,
632
+ #menu-profiler li a:hover {
633
+ background: #666;
634
+ border: solid #555;
635
+ border-width: 2px 0;
636
+ }
637
+ #menu-profiler li.selected a .label,
638
+ #menu-profiler li a:hover .label {
639
+ color: #FFF;
640
+ }
641
+ #menu-profiler li.selected a .icon svg path,
642
+ #menu-profiler li a:hover .icon svg path {
643
+ fill: #FFF;
644
+ }
645
+
646
+ #menu-profiler li a .count {
647
+ background-color: #666;
648
+ color: #FFF;
649
+ display: inline-block;
650
+ font-weight: bold;
651
+ min-width: 10px;
652
+ padding: 2px 6px;
653
+ position: absolute;
654
+ right: 10px;
655
+ text-align: center;
656
+ vertical-align: baseline;
657
+ white-space: nowrap;
658
+ }
659
+ #menu-profiler li a span.count span {
660
+ font-size: 12px;
661
+
662
+ }
663
+ #menu-profiler li a span.count span + span::before {
664
+ content: " / ";
665
+ color: #AAA;
666
+ }
667
+
668
+ #menu-profiler .label-status-warning .count {
669
+ background: <?php echo $colors['warning']; ?>;
670
+ }
671
+ #menu-profiler .label-status-error .count {
672
+ background: <?php echo $colors['error']; ?>;
673
+ }
674
+
675
+ #timeline-control {
676
+ background: #FFF;
677
+ margin: 1em 0;
678
+ padding: 10px;
679
+ }
680
+ #timeline-control label {
681
+ font-weight: bold;
682
+ margin-right: 1em;
683
+ }
684
+ #timeline-control input {
685
+ font-size: 16px;
686
+ padding: 4px;
687
+ text-align: right;
688
+ width: 40px;
689
+ }
690
+ #timeline-control .help {
691
+ margin-left: 1em;
692
+ }
693
+
694
+ .sf-profiler-timeline .legends {
695
+ font-size: 12px;
696
+ line-height: 1.5em;
697
+ }
698
+ .sf-profiler-timeline .legends span {
699
+ border-left: solid 14px;
700
+ padding: 0 10px 0 5px;
701
+ }
702
+ .sf-profiler-timeline canvas {
703
+ border: 1px solid #DDD;
704
+ background: #FFF;
705
+ margin: .5em 0;
706
+ }
707
+ .sf-profiler-timeline + p.help {
708
+ margin-top: 0;
709
+ }
710
+
711
+ .tab-navigation {
712
+ margin: 0 0 1em 0;
713
+ padding: 0;
714
+ }
715
+ .tab-navigation li {
716
+ background: #FFF;
717
+ border: 1px solid #DDD;
718
+ color: #444;
719
+ cursor: pointer;
720
+ display: inline-block;
721
+ font-size: 16px;
722
+ margin: 0 0 0 -1px;
723
+ padding: .5em .75em;
724
+ z-index: 1;
725
+ }
726
+ .tab-navigation li:hover {
727
+ background: #EEE;
728
+ }
729
+ .tab-navigation li .badge {
730
+ background-color: #F5F5F5;
731
+ color: #777;
732
+ display: inline-block;
733
+ font-size: 14px;
734
+ font-weight: bold;
735
+ margin-left: 8px;
736
+ min-width: 10px;
737
+ padding: 1px 6px;
738
+ text-align: center;
739
+ white-space: nowrap;
740
+ }
741
+ .tab-navigation li:hover .badge {
742
+ background: #FAFAFA;
743
+ color: #777;
744
+ }
745
+ .tab-navigation li.disabled {
746
+ background: #F5F5F5;
747
+ color: #999;
748
+ }
749
+ .tab-navigation li.active {
750
+ background: #666;
751
+ border-color: #666;
752
+ color: #FAFAFA;
753
+ z-index: 1100;
754
+ }
755
+ .tab-navigation li.active .badge {
756
+ background-color: #444;
757
+ color: #FFF;
758
+ }
759
+ .tab-content > *:first-child {
760
+ margin-top: 0;
761
+ }
762
+
763
+ .sf-toggle-content {
764
+ -moz-transition: display .25s ease;
765
+ -webkit-transition: display .25s ease;
766
+ transition: display .25s ease;
767
+ }
768
+ .sf-toggle-content.sf-toggle-hidden {
769
+ display: none!important;
770
+ }
771
+ .sf-toggle-content.sf-toggle-visible {
772
+ display: block!important;
773
+ }
774
+
775
+ #twig-dump pre {
776
+ font-size: 12px;
777
+ line-height: 1.7;
778
+ }
779
+ #twig-dump span {
780
+ border-radius: 2px;
781
+ padding: 1px 2px;
782
+ }
783
+ #twig-dump .status-error { background: transparent; color: #B0413E; }
784
+ #twig-dump .status-warning { background: rgba(240, 181, 24, 0.3); }
785
+ #twig-dump .status-success { background: rgba(100, 189, 99, 0.2); }
786
+
787
+ table.logs .metadata {
788
+ color: #777;
789
+ display: block;
790
+ font-size: 12px;
791
+ padding-top: 4px;
792
+ }
793
+ table.logs .metadata strong {
794
+ color: #222;
795
+ }
796
+ table.logs .metadata .context {
797
+ background: #F5F5F5;
798
+ color: #222;
799
+ }
800
+ table.logs .metadata .context pre {
801
+ margin: 5px 0;
802
+ padding: 5px 10px;
803
+ white-space: pre-wrap;
804
+ }
805
+
806
+ table.logs .sf-call-stack {
807
+ margin: 1em 0 1em 1.5em;
808
+ }
809
+ table.logs .sf-call-stack li {
810
+ margin-bottom: 5px;
811
+ }
812
+ table.logs .sf-call-stack abbr {
813
+ border: none;
814
+ }
815
+
816
+ .sql-runnable {
817
+ background: #F5F5F5;
818
+ margin: .5em 0;
819
+ padding: 1em;
820
+ }
821
+ .queries-table pre {
822
+ word-break: break-all; -webkit-hyphens: auto; -moz-hyphens: auto; hyphens: auto;
823
+ margin: 0;
824
+ white-space: pre-wrap;
825
+ }
826
+
827
+ #collector-content .sf-dump {
828
+ margin-bottom: 2em;
829
+ }
830
+ #collector-content pre.sf-dump,
831
+ #collector-content .sf-dump code,
832
+ #collector-content .sf-dump samp {
833
+ font-family: Helvetica, Arial, sans-serif;
834
+ }
835
+ #collector-content pre.sf-dump {
836
+ background: #222;
837
+ line-height: 1.4;
838
+ margin-top: .5em;
839
+ padding: 1em;
840
+ }
841
+ #collector-content .sf-dump h3 {
842
+ font-size: 18px;
843
+ margin: .5em 0 0;
844
+ }
845
+ #collector-content .sf-dump h3 a {
846
+ cursor: pointer;
847
+ }
848
+
849
+ #collector-content pre.sf-dump { color: #CC7832; }
850
+ #collector-content .sf-dump-str { color: #629755; }
851
+ #collector-content .sf-dump-private,
852
+ #collector-content .sf-dump-protected,
853
+ #collector-content .sf-dump-public { color: #E0E0E0; }
854
+ #collector-content .sf-dump-note { color: #6897BB; }
855
+ #collector-content .sf-dump-key { color: #A5C261; }
856
+
857
+ #collector-content .sf-dump .trace {
858
+ border: 1px solid #DDD;
859
+ background: #FFF;
860
+ padding: 10px;
861
+ margin: 1em 0;
862
+ }
863
+ #collector-content .sf-dump .trace {
864
+ font-size: 12px;
865
+ }
866
+ #collector-content .sf-dump .trace code {
867
+ font-size: 14px;
868
+ }
869
+ #collector-content .sf-dump .trace li {
870
+ margin-bottom: 0;
871
+ padding: 5px 0;
872
+ }
873
+ #collector-content .sf-dump .trace li.selected {
874
+ background: rgba(255, 255, 153, 0.5);
875
+ }
876
+
877
+ #search-results td {
878
+ font-family: Helvetica, Arial, sans-serif;
879
+ vertical-align: middle;
880
+ }
881
+
882
+ #search-results .sf-search {
883
+ visibility: hidden;
884
+ margin-left: 2px;
885
+ }
886
+ #search-results tr:hover .sf-search {
887
+ visibility: visible;
888
+ }
889
+
890
+ .visible-small {
891
+ display: none;
892
+ }
893
+ .hidden-small {
894
+ display: inherit;
895
+ }
896
+
897
+ @media (max-width: 768px) {
898
+ #collector-content {
899
+ margin-left: 50px;
900
+ }
901
+
902
+ #sidebar {
903
+ width: 50px;
904
+ overflow-y: hidden;
905
+ transition: width 200ms ease-out;
906
+ }
907
+ #sidebar:hover, #sidebar.expanded {
908
+ width: 220px;
909
+ }
910
+
911
+ #sidebar-search {
912
+ display: none;
913
+ }
914
+ #sidebar:hover #sidebar-search.sf-toggle-visible, #sidebar.expanded #sidebar-search.sf-toggle-visible {
915
+ display: block;
916
+ }
917
+
918
+ #sidebar .module {
919
+ display: none;
920
+ }
921
+ #sidebar:hover .module, #sidebar.expanded .module {
922
+ display: block;
923
+ }
924
+
925
+ .visible-small {
926
+ display: inherit;
927
+ }
928
+ .hidden-small {
929
+ display: none;
930
+ }
931
+
932
+ .btn-sm svg {
933
+ margin-left: 2px;
934
+ }
935
+ }
app/design/frontend/base/default/template/ecocode_profiler/profiler/base.js.phtml ADDED
@@ -0,0 +1,464 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ $request = Mage::app()->getRequest();
3
+ $schemeAndHost = $request->getScheme() . '://' . $request->getHttpHost();
4
+ $this->setData('excluded_ajax_paths', '^/_profiler');
5
+ ?>
6
+ <?php /* Caution: the contents of this file are processed by Twig before loading
7
+ them as JavaScript source code. Always use '/*' comments instead
8
+ of '//' comments to avoid impossible-to-debug side-effects */ ?>
9
+
10
+ Sfjs = (function() {
11
+ "use strict";
12
+
13
+ var classListIsSupported = 'classList' in document.documentElement;
14
+
15
+ if (classListIsSupported) {
16
+ var hasClass = function (el, cssClass) { return el.classList.contains(cssClass); };
17
+ var removeClass = function(el, cssClass) { el.classList.remove(cssClass); };
18
+ var addClass = function(el, cssClass) { el.classList.add(cssClass); };
19
+ var toggleClass = function(el, cssClass) { el.classList.toggle(cssClass); };
20
+ } else {
21
+ var hasClass = function (el, cssClass) { return el.className.match(new RegExp('\\b' + cssClass + '\\b')); };
22
+ var removeClass = function(el, cssClass) { el.className = el.className.replace(new RegExp('\\b' + cssClass + '\\b'), ' '); };
23
+ var addClass = function(el, cssClass) { if (!hasClass(el, cssClass)) { el.className += " " + cssClass; } };
24
+ var toggleClass = function(el, cssClass) { hasClass(el, cssClass) ? removeClass(el, cssClass) : addClass(el, cssClass); };
25
+ }
26
+
27
+ var noop = function() {},
28
+
29
+ collectionToArray = function (collection) {
30
+ var length = collection.length || 0,
31
+ results = new Array(length);
32
+
33
+ while (length--) {
34
+ results[length] = collection[length];
35
+ }
36
+
37
+ return results;
38
+ },
39
+
40
+ profilerStorageKey = 'sf2/profiler/',
41
+
42
+ request = function(url, onSuccess, onError, payload, options) {
43
+ var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');
44
+ options = options || {};
45
+ options.maxTries = options.maxTries || 0;
46
+ xhr.open(options.method || 'GET', url, true);
47
+ xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
48
+ xhr.onreadystatechange = function(state) {
49
+ if (4 !== xhr.readyState) {
50
+ return null;
51
+ }
52
+
53
+ if (xhr.status == 404 && options.maxTries > 1) {
54
+ setTimeout(function(){
55
+ options.maxTries--;
56
+ request(url, onSuccess, onError, payload, options);
57
+ }, 500);
58
+
59
+ return null;
60
+ }
61
+
62
+ if (200 === xhr.status) {
63
+ (onSuccess || noop)(xhr);
64
+ } else {
65
+ (onError || noop)(xhr);
66
+ }
67
+ };
68
+ xhr.send(payload || '');
69
+ },
70
+
71
+ getPreference = function(name) {
72
+ if (!window.localStorage) {
73
+ return null;
74
+ }
75
+
76
+ return localStorage.getItem(profilerStorageKey + name);
77
+ },
78
+
79
+ setPreference = function(name, value) {
80
+ if (!window.localStorage) {
81
+ return null;
82
+ }
83
+
84
+ localStorage.setItem(profilerStorageKey + name, value);
85
+ },
86
+
87
+ requestStack = [],
88
+
89
+ extractHeaders = function(xhr, stackElement) {
90
+ /* Here we avoid to call xhr.getResponseHeader in order to */
91
+ /* prevent polluting the console with CORS security errors */
92
+ var allHeaders = xhr.getAllResponseHeaders();
93
+ var ret;
94
+ console.log(allHeaders);
95
+ if (ret = allHeaders.match(/^x-debug-token:\s+(.*)$/im)) {
96
+ stackElement.profile = ret[1];
97
+ }
98
+ if (ret = allHeaders.match(/^x-debug-token-link:\s+(.*)$/im)) {
99
+ stackElement.profilerUrl = ret[1];
100
+ }
101
+ },
102
+
103
+ renderAjaxRequests = function() {
104
+ var requestCounter = document.querySelectorAll('.sf-toolbar-ajax-requests');
105
+ if (!requestCounter.length) {
106
+ return;
107
+ }
108
+
109
+ var ajaxToolbarPanel = document.querySelector('.sf-toolbar-block-ajax');
110
+ var tbodies = document.querySelectorAll('.sf-toolbar-ajax-request-list');
111
+ var state = 'ok';
112
+ if (tbodies.length) {
113
+ var tbody = tbodies[0];
114
+
115
+ var rows = document.createDocumentFragment();
116
+ if (requestStack.length) {
117
+ for (var i = 0; i < requestStack.length; i++) {
118
+ var request = requestStack[i];
119
+
120
+ var row = document.createElement('tr');
121
+ rows.insertBefore(row, rows.firstChild);
122
+
123
+ var methodCell = document.createElement('td');
124
+ if (request.error) {
125
+ methodCell.className = 'sf-ajax-request-error';
126
+ }
127
+ methodCell.textContent = request.method;
128
+ row.appendChild(methodCell);
129
+
130
+ var statusCodeCell = document.createElement('td');
131
+ var statusCode = document.createElement('span');
132
+ if (request.statusCode < 300) {
133
+ statusCode.setAttribute('class', 'sf-toolbar-status');
134
+ } else if (request.statusCode < 400) {
135
+ statusCode.setAttribute('class', 'sf-toolbar-status sf-toolbar-status-yellow');
136
+ } else {
137
+ statusCode.setAttribute('class', 'sf-toolbar-status sf-toolbar-status-red');
138
+ }
139
+ statusCode.textContent = request.statusCode || '-';
140
+ statusCodeCell.appendChild(statusCode);
141
+ row.appendChild(statusCodeCell);
142
+
143
+ var pathCell = document.createElement('td');
144
+ pathCell.className = 'sf-ajax-request-url';
145
+ if ('GET' === request.method) {
146
+ var pathLink = document.createElement('a');
147
+ pathLink.setAttribute('href', request.url);
148
+ pathLink.textContent = request.url;
149
+ pathCell.appendChild(pathLink);
150
+ } else {
151
+ pathCell.textContent = request.url;
152
+ }
153
+ pathCell.setAttribute('title', request.url);
154
+ row.appendChild(pathCell);
155
+
156
+ var durationCell = document.createElement('td');
157
+ durationCell.className = 'sf-ajax-request-duration';
158
+
159
+ if (request.duration) {
160
+ durationCell.textContent = request.duration + "ms";
161
+ } else {
162
+ durationCell.textContent = '-';
163
+ }
164
+ row.appendChild(durationCell);
165
+
166
+ row.appendChild(document.createTextNode(' '));
167
+ var profilerCell = document.createElement('td');
168
+
169
+ if (request.profilerUrl) {
170
+ var profilerLink = document.createElement('a');
171
+ profilerLink.setAttribute('href', request.profilerUrl);
172
+ profilerLink.textContent = request.profile;
173
+ profilerCell.appendChild(profilerLink);
174
+ } else {
175
+ profilerCell.textContent = 'n/a';
176
+ }
177
+
178
+ row.appendChild(profilerCell);
179
+
180
+ var requestState = 'ok';
181
+ if (request.error) {
182
+ requestState = 'error';
183
+ if (state != "loading" && i > requestStack.length - 4) {
184
+ state = 'error';
185
+ }
186
+ } else if (request.loading) {
187
+ requestState = 'loading';
188
+ state = 'loading';
189
+ }
190
+ row.className = 'sf-ajax-request sf-ajax-request-' + requestState;
191
+ }
192
+
193
+ var infoSpan = document.querySelectorAll(".sf-toolbar-ajax-info")[0];
194
+ var children = collectionToArray(tbody.children);
195
+ for (var i = 0; i < children.length; i++) {
196
+ tbody.removeChild(children[i]);
197
+ }
198
+ tbody.appendChild(rows);
199
+
200
+ if (infoSpan) {
201
+ var text = requestStack.length + ' AJAX request' + (requestStack.length > 1 ? 's' : '');
202
+ infoSpan.textContent = text;
203
+ }
204
+
205
+ ajaxToolbarPanel.style.display = 'block';
206
+ } else {
207
+ ajaxToolbarPanel.style.display = 'none';
208
+ }
209
+ }
210
+
211
+ requestCounter[0].textContent = requestStack.length;
212
+
213
+ var className = 'sf-toolbar-ajax-requests sf-toolbar-value';
214
+ requestCounter[0].className = className;
215
+
216
+ if (state == 'ok') {
217
+ Sfjs.removeClass(ajaxToolbarPanel, 'sf-ajax-request-loading');
218
+ Sfjs.removeClass(ajaxToolbarPanel, 'sf-toolbar-status-red');
219
+ } else if (state == 'error') {
220
+ Sfjs.addClass(ajaxToolbarPanel, 'sf-toolbar-status-red');
221
+ Sfjs.removeClass(ajaxToolbarPanel, 'sf-ajax-request-loading');
222
+ } else {
223
+ Sfjs.addClass(ajaxToolbarPanel, 'sf-ajax-request-loading');
224
+ }
225
+ };
226
+
227
+ var addEventListener;
228
+
229
+ var el = document.createElement('div');
230
+ if (!('addEventListener' in el)) {
231
+ addEventListener = function (element, eventName, callback) {
232
+ element.attachEvent('on' + eventName, callback);
233
+ };
234
+ } else {
235
+ addEventListener = function (element, eventName, callback) {
236
+ element.addEventListener(eventName, callback, false);
237
+ };
238
+ }
239
+
240
+ <?php if ($this->getData('excluded_ajax_paths')): ?>
241
+ if (window.XMLHttpRequest && XMLHttpRequest.prototype.addEventListener) {
242
+ var proxied = XMLHttpRequest.prototype.open;
243
+
244
+ XMLHttpRequest.prototype.open = function(method, url, async, user, pass) {
245
+ var self = this;
246
+
247
+ /* prevent logging AJAX calls to static and inline files, like templates */
248
+ var path = url;
249
+
250
+ /*if (url.substr(0, 1) === '/') {
251
+ if (0 === url.indexOf('{{ request.basePath|e('js') }}')) {
252
+ path = url.substr({{ request.basePath|length }});
253
+ }
254
+ } else */
255
+ if (0 === url.indexOf('<?php echo Mage::getBaseUrl()?>')) {
256
+ path = url.substr(<?php echo strlen(rtrim(Mage::getBaseUrl(), '/'))?>);
257
+ }
258
+
259
+ if (!path.match(new RegExp(<?php echo json_encode($this->getData('excluded_ajax_paths'));?>))) {
260
+ var stackElement = {
261
+ loading: true,
262
+ error: false,
263
+ url: url,
264
+ method: method,
265
+ start: new Date()
266
+ };
267
+
268
+ requestStack.push(stackElement);
269
+
270
+ this.addEventListener('readystatechange', function() {
271
+ if (self.readyState == 4) {
272
+ stackElement.duration = new Date() - stackElement.start;
273
+ stackElement.loading = false;
274
+ stackElement.error = self.status < 200 || self.status >= 400;
275
+ stackElement.statusCode = self.status;
276
+ extractHeaders(self, stackElement);
277
+
278
+ Sfjs.renderAjaxRequests();
279
+ }
280
+ }, false);
281
+
282
+ Sfjs.renderAjaxRequests();
283
+ }
284
+
285
+ proxied.apply(this, Array.prototype.slice.call(arguments));
286
+ };
287
+ }
288
+ <?php endif;?>
289
+
290
+ return {
291
+ hasClass: hasClass,
292
+
293
+ removeClass: removeClass,
294
+
295
+ addClass: addClass,
296
+
297
+ toggleClass: toggleClass,
298
+
299
+ getPreference: getPreference,
300
+
301
+ setPreference: setPreference,
302
+
303
+ addEventListener: addEventListener,
304
+
305
+ request: request,
306
+
307
+ renderAjaxRequests: renderAjaxRequests,
308
+
309
+ load: function(selector, url, onSuccess, onError, options) {
310
+ var el = document.getElementById(selector);
311
+
312
+ if (el && el.getAttribute('data-sfurl') !== url) {
313
+ request(
314
+ url,
315
+ function(xhr) {
316
+ el.innerHTML = xhr.responseText;
317
+ el.setAttribute('data-sfurl', url);
318
+ removeClass(el, 'loading');
319
+ (onSuccess || noop)(xhr, el);
320
+ },
321
+ function(xhr) { (onError || noop)(xhr, el); },
322
+ '',
323
+ options
324
+ );
325
+ }
326
+
327
+ return this;
328
+ },
329
+
330
+ toggle: function(selector, elOn, elOff) {
331
+ var tmp = elOn.style.display,
332
+ el = document.getElementById(selector);
333
+
334
+ elOn.style.display = elOff.style.display;
335
+ elOff.style.display = tmp;
336
+
337
+ if (el) {
338
+ el.style.display = 'none' === tmp ? 'none' : 'block';
339
+ }
340
+
341
+ return this;
342
+ },
343
+
344
+ createTabs: function() {
345
+ var tabGroups = document.querySelectorAll('.sf-tabs');
346
+
347
+ /* create the tab navigation for each group of tabs */
348
+ for (var i = 0; i < tabGroups.length; i++) {
349
+ var tabs = tabGroups[i].querySelectorAll('.tab');
350
+ var tabNavigation = document.createElement('ul');
351
+ tabNavigation.className = 'tab-navigation';
352
+
353
+ for (var j = 0; j < tabs.length; j++) {
354
+ var tabId = 'tab-' + i + '-' + j;
355
+ var tabTitle = tabs[j].querySelector('.tab-title').innerHTML;
356
+
357
+ var tabNavigationItem = document.createElement('li');
358
+ tabNavigationItem.setAttribute('data-tab-id', tabId);
359
+ if (j == 0) { Sfjs.addClass(tabNavigationItem, 'active'); }
360
+ if (Sfjs.hasClass(tabs[j], 'disabled')) { Sfjs.addClass(tabNavigationItem, 'disabled'); }
361
+ tabNavigationItem.innerHTML = tabTitle;
362
+ tabNavigation.appendChild(tabNavigationItem);
363
+
364
+ var tabContent = tabs[j].querySelector('.tab-content');
365
+ tabContent.parentElement.setAttribute('id', tabId);
366
+ }
367
+
368
+ tabGroups[i].insertBefore(tabNavigation, tabGroups[i].firstChild);
369
+ }
370
+
371
+ /* display the active tab and add the 'click' event listeners */
372
+ for (i = 0; i < tabGroups.length; i++) {
373
+ tabNavigation = tabGroups[i].querySelectorAll('.tab-navigation li');
374
+
375
+ for (j = 0; j < tabNavigation.length; j++) {
376
+ tabId = tabNavigation[j].getAttribute('data-tab-id');
377
+ document.getElementById(tabId).querySelector('.tab-title').className = 'hidden';
378
+
379
+ if (Sfjs.hasClass(tabNavigation[j], 'active')) {
380
+ document.getElementById(tabId).className = 'block';
381
+ } else {
382
+ document.getElementById(tabId).className = 'hidden';
383
+ }
384
+
385
+ tabNavigation[j].addEventListener('click', function(e) {
386
+ var activeTab = e.target || e.srcElement;
387
+
388
+ /* needed because when the tab contains HTML contents, user can click */
389
+ /* on any of those elements instead of their parent '<li>' element */
390
+ while (activeTab.tagName.toLowerCase() !== 'li') {
391
+ activeTab = activeTab.parentNode;
392
+ }
393
+
394
+ /* get the full list of tabs through the parent of the active tab element */
395
+ var tabNavigation = activeTab.parentNode.children;
396
+ for (var k = 0; k < tabNavigation.length; k++) {
397
+ var tabId = tabNavigation[k].getAttribute('data-tab-id');
398
+ document.getElementById(tabId).className = 'hidden';
399
+ Sfjs.removeClass(tabNavigation[k], 'active');
400
+ }
401
+
402
+ Sfjs.addClass(activeTab, 'active');
403
+ var activeTabId = activeTab.getAttribute('data-tab-id');
404
+ document.getElementById(activeTabId).className = 'block';
405
+ });
406
+ }
407
+ }
408
+ },
409
+
410
+ createToggles: function() {
411
+ var toggles = document.querySelectorAll('.sf-toggle');
412
+
413
+ for (var i = 0; i < toggles.length; i++) {
414
+ var elementSelector = toggles[i].getAttribute('data-toggle-selector');
415
+ var element = document.querySelector(elementSelector);
416
+
417
+ Sfjs.addClass(element, 'sf-toggle-content');
418
+
419
+ if (toggles[i].hasAttribute('data-toggle-initial') && toggles[i].getAttribute('data-toggle-initial') == 'display') {
420
+ Sfjs.addClass(element, 'sf-toggle-visible');
421
+ } else {
422
+ Sfjs.addClass(element, 'sf-toggle-hidden');
423
+ }
424
+
425
+ Sfjs.addEventListener(toggles[i], 'click', function(e) {
426
+ e.preventDefault();
427
+
428
+ var toggle = e.target || e.srcElement;
429
+
430
+ /* needed because when the toggle contains HTML contents, user can click */
431
+ /* on any of those elements instead of their parent '.sf-toggle' element */
432
+ while (!Sfjs.hasClass(toggle, 'sf-toggle')) {
433
+ toggle = toggle.parentNode;
434
+ }
435
+
436
+ var element = document.querySelector(toggle.getAttribute('data-toggle-selector'));
437
+
438
+ Sfjs.toggleClass(element, 'sf-toggle-hidden');
439
+ Sfjs.toggleClass(element, 'sf-toggle-visible');
440
+
441
+ /* the toggle doesn't change its contents when clicking on it */
442
+ if (!toggle.hasAttribute('data-toggle-alt-content')) {
443
+ return;
444
+ }
445
+
446
+ if (!toggle.hasAttribute('data-toggle-original-content')) {
447
+ toggle.setAttribute('data-toggle-original-content', toggle.innerHTML);
448
+ }
449
+
450
+ var currentContent = toggle.innerHTML;
451
+ var originalContent = toggle.getAttribute('data-toggle-original-content');
452
+ var altContent = toggle.getAttribute('data-toggle-alt-content');
453
+ toggle.innerHTML = currentContent !== altContent ? altContent : originalContent;
454
+ });
455
+ }
456
+ }
457
+ };
458
+ })();
459
+
460
+ Sfjs.addEventListener(window, 'load', function() {
461
+ Sfjs.createTabs();
462
+ Sfjs.createToggles();
463
+ });
464
+
app/design/frontend/base/default/template/ecocode_profiler/profiler/search/results.phtml ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ $data = $this->getData();
3
+ ?>
4
+ <h2><?php echo $data['tokens'] ? count($data['tokens']) : 'No' ?> results found</h2>
5
+
6
+ <?php if ($data['tokens']): ?>
7
+ <table id="search-results">
8
+ <thead>
9
+ <tr>
10
+ <th scope="col" class="text-center">Status</th>
11
+ <th scope="col">IP</th>
12
+ <th scope="col">Method</th>
13
+ <th scope="col">URL</th>
14
+ <th scope="col">Time</th>
15
+ <th scope="col">Token</th>
16
+ </tr>
17
+ </thead>
18
+ <tbody>
19
+ <?php foreach ($data['tokens'] as $result): ?>
20
+ <?php
21
+ $statusCode = isset($result['status_code']) ? $result['status_code'] : 0;
22
+ $cssClass = $statusCode > 399 ? 'status-error' : $statusCode > 299 ? 'status-warning' : 'status-success';
23
+ ?>
24
+
25
+ <tr>
26
+ <td class="text-center">
27
+ <span class="label <?php echo $cssClass?>"><?php echo $statusCode ? $statusCode : 'n/a'?></span>
28
+ </td>
29
+ <td>
30
+ <span class="nowrap"><?php echo $result['ip']?></span>
31
+ <!-- {% if request.session is not null %}
32
+ <a href="{{ path('_profiler_search_results', request.query.all|merge({'ip': result.ip, 'token': result.token})) }}"
33
+ title="Search">
34
+ <span title="Search" class="sf-icon sf-search">{{ include('@WebProfiler/Icon/search.svg') }}</span>
35
+ </a>
36
+ {% endif %}-->
37
+ </td>
38
+ <td>
39
+ <?php echo $result['method']?>
40
+ <!-- {% if request.session is not null %}
41
+ <a href="{{ path('_profiler_search_results', request.query.all|merge({'method': result.method, 'token': result.token})) }}"
42
+ title="Search">
43
+ <span title="Search" class="sf-icon sf-search">{{ include('@WebProfiler/Icon/search.svg') }}</span>
44
+ </a>
45
+ {% endif %}-->
46
+ </td>
47
+ <td class="break-long-words">
48
+ <?php echo $result['url']?>
49
+ <!-- {% if request.session is not null %}
50
+ <a href="{{ path('_profiler_search_results', request.query.all|merge({'url': result.url, 'token': result.token})) }}"
51
+ title="Search">
52
+ <span title="Search" class="sf-icon sf-search">{{ include('@WebProfiler/Icon/search.svg') }}</span>
53
+ </a>
54
+ {% endif %}-->
55
+ </td>
56
+ <td class="text-small">
57
+ <?php $date = (new DateTime())->setTimestamp($result['time']);?>
58
+ <span class="nowrap"><?php echo $date->format('d-M-Y')?></span>
59
+ <span class="nowrap newline"><?php echo $date->format('H:i:s')?></span>
60
+ </td>
61
+ <td class="nowrap"><a href="<?php echo Mage::helper('ecocode_profiler')->getUrl($result['token']) ?>"><?php echo $result['token']?></a></td>
62
+ </tr>
63
+ <?php endforeach;?>
64
+ </tbody>
65
+ </table>
66
+ <?php else: ?>
67
+ <div class="empty">
68
+ <p>The query returned no result.</p>
69
+ </div>
70
+ <?php endif ?>
71
+
app/design/frontend/base/default/template/ecocode_profiler/profiler/search/summery.phtml ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
1
+ <div class="status">
2
+ <div class="container">
3
+ <h2>Profile Search</h2>
4
+ </div>
5
+ </div>
app/design/frontend/base/default/template/ecocode_profiler/profiler/summery.phtml ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /** @var Ecocode_Profiler_Model_Profile $profile */
3
+ $profile = Mage::registry('current_profile');
4
+ ?>
5
+ <?php if ($profile): ?>
6
+ <?php
7
+ /** @var Ecocode_Profiler_Model_Collector_RequestDataCollector $requestCollector */
8
+ $requestCollector = $profile->getCollector('request');
9
+ $statusCode = $requestCollector->getStatusCode();
10
+ $cssClass = ($statusCode > 399) ? 'status-error' : $statusCode > 299 ? 'status-warning' : 'status-success';
11
+ ?>
12
+
13
+ <div class="status <?php echo $cssClass?>">
14
+ <div class="container">
15
+ <h2 class="break-long-words">
16
+ <?php if (in_array(strtoupper($profile->getMethod()), ['GET', 'HEAD'])): ?>
17
+ <a href="<?php echo $profile->getUrl()?>"><?php echo $profile->getUrl()?></a>
18
+ <?php else: ?>
19
+ <?php echo $profile->getUrl()?>
20
+ <?php endif;?>
21
+ </h2>
22
+
23
+ <!-- {% if request_collector is defined and request_collector.redirect -%}
24
+ {%- set redirect = request_collector.redirect -%}
25
+ {%- set controller = redirect.controller -%}
26
+ {%- set redirect_route = '@' ~ redirect.route %}
27
+ <dl class="metadata">
28
+ <dt>
29
+ <span class="label">{{ redirect.status_code }}</span>
30
+ Redirect from
31
+ </dt>
32
+ <dd>
33
+ {{ 'GET' != redirect.method ? redirect.method }}
34
+ {% if redirect.controller.class is defined -%}
35
+ {%- set link = controller.file|file_link(controller.line) -%}
36
+ {% if link %}<a href="{{ link }}" title="{{ controller.file }}">{% endif -%}
37
+ {{ redirect_route }}
38
+ {%- if link %}</a>{% endif -%}
39
+ {%- else -%}
40
+ {{ redirect_route }}
41
+ {%- endif %}
42
+ (<a href="{{ path('_profiler', { token: redirect.token }) }}">{{ redirect.token }}</a>)
43
+ </dd>
44
+ </dl>
45
+ {%- endif %}-->
46
+
47
+ <!-- {% if request_collector and request_collector.forward|default(false) and request_collector.forward.controller.class is defined -%}
48
+ {%- set forward = request_collector.forward -%}
49
+ {%- set controller = forward.controller -%}
50
+ <dl class="metadata">
51
+ <dt>Forwarded to</dt>
52
+ <dd>
53
+ {% set link = controller.file|file_link(controller.line) -%}
54
+ {%- if link %}<a href="{{ link }}" title="{{ controller.file }}">{% endif -%}
55
+ {{- controller.class|abbr_class|striptags -}}
56
+ {{- controller.method ? ' :: ' ~ controller.method }}
57
+ {%- if link %}</a>{% endif %}
58
+ (<a href="{{ path('_profiler', { token: forward.token }) }}">{{ forward.token }}</a>)
59
+ </dd>
60
+ </dl>
61
+ {%- endif %}-->
62
+
63
+ <dl class="metadata">
64
+ <dt>Method</dt>
65
+ <dd><?php echo strtoupper($profile->getMethod()) ?></dd>
66
+
67
+ <?php if ($profile->hasCollector('request')):?>
68
+ <?php
69
+ /** @var Ecocode_Profiler_Model_Collector_RequestDataCollector $collector */
70
+ $collector = $profile->getCollector('request');
71
+ ?>
72
+ <dt>Route</dt>
73
+ <dd><?php echo $collector->getRoute(); ?></dd>
74
+ <?php endif; ?>
75
+
76
+ <dt>HTTP Status</dt>
77
+ <dd><?php echo $statusCode ?></dd>
78
+
79
+ <dt>IP</dt>
80
+ <dd><?php echo $profile->getIp() ?></dd>
81
+
82
+ <dt>Profiled on</dt>
83
+ <dd><?php echo date('r', $profile->getTime()) ?></dd>
84
+
85
+ <dt>Token</dt>
86
+ <dd><?php echo $profile->getToken(); ?></dd>
87
+ </dl>
88
+ </div>
89
+ </div>
90
+ <?php endif;?>
app/design/frontend/base/default/template/ecocode_profiler/renderer/context.phtml ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /** @var Ecocode_Profiler_Block_Renderer_Context $this */
3
+ $prefix = $this->getData('prefix');
4
+
5
+ /** @var Ecocode_Profiler_Model_Context $context */
6
+ $context = $this->getData('context');
7
+
8
+ /** @var Ecocode_Profiler_Helper_ValueExporter $exporter */
9
+ $exporter = Mage::helper('ecocode_profiler/valueExporter')
10
+ ?>
11
+
12
+ <div class="context font-normal text-small">
13
+ <strong>Context: </strong><?php echo $context->getKey()?>
14
+ <?php if($context->getData()):?>
15
+ <a href="#" class="sf-toggle link-inverse text-small"
16
+ data-toggle-selector="#context-<?php echo $prefix . $context->getId() ?>"
17
+ data-toggle-alt-content="Hide metadata">View metadata</a>
18
+ <div id="context-<?php echo $prefix . $context->getId() ?>" class="hidden text-small">
19
+ <table>
20
+ <?php foreach($context->getData() as $key => $value):?>
21
+ <tr>
22
+ <th class="key"><?php echo $key?></th>
23
+ <td><?php echo $exporter->exportValue($value, true)?></td>
24
+ </tr>
25
+ <?php endforeach;?>
26
+ </table>
27
+ </div>
28
+
29
+ <?php endif?>
30
+ </div>
app/design/frontend/base/default/template/ecocode_profiler/toolbar.css.phtml ADDED
@@ -0,0 +1,479 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ <?php
3
+ $colors = [
4
+ 'success' => '#4F805D',
5
+ 'warning' => '#A46A1F',
6
+ 'error' => '#B0413E'
7
+ ]
8
+ ?>
9
+ .sf-minitoolbar {
10
+ background-color: #222;
11
+ border-top-left-radius: 4px;
12
+ bottom: 0;
13
+ -webkit-box-sizing: border-box;
14
+ -moz-box-sizing: border-box;
15
+ box-sizing: border-box;
16
+ display: none;
17
+ height: 36px;
18
+ padding: 6px;
19
+ position: fixed;
20
+ right: 0;
21
+ z-index: 99999;
22
+ }
23
+
24
+ .sf-minitoolbar a {
25
+ display: block;
26
+ }
27
+ .sf-minitoolbar svg,
28
+ .sf-minitoolbar img {
29
+ max-height: 24px;
30
+ max-width: 24px;
31
+ display: inline;
32
+ }
33
+
34
+ .sf-toolbarreset * {
35
+ -webkit-box-sizing: content-box;
36
+ -moz-box-sizing: content-box;
37
+ box-sizing: content-box;
38
+ vertical-align: baseline;
39
+ }
40
+
41
+ .sf-toolbarreset {
42
+ background-color: #222;
43
+ bottom: 0;
44
+ box-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2);
45
+ color: #EEE;
46
+ font: 11px Arial, sans-serif;
47
+ left: 0;
48
+ margin: 0;
49
+ padding: 0 36px 0 0;
50
+ position: fixed;
51
+ right: 0;
52
+ text-align: left;
53
+ text-transform: none;
54
+ z-index: 99999;
55
+
56
+ /* neutralize the aliasing defined by external CSS styles */
57
+ -webkit-font-smoothing: subpixel-antialiased;
58
+ -moz-osx-font-smoothing: auto;
59
+ }
60
+ .sf-toolbarreset abbr {
61
+ border: dashed #777;
62
+ border-width: 0 0 1px;
63
+ }
64
+ .sf-toolbarreset svg,
65
+ .sf-toolbarreset img {
66
+ height: 20px;
67
+ display: inline-block;
68
+ }
69
+
70
+ .sf-toolbarreset .hide-button {
71
+ background: #444;
72
+ display: block;
73
+ position: absolute;
74
+ top: 0;
75
+ right: 0;
76
+ width: 36px;
77
+ height: 36px;
78
+ cursor: pointer;
79
+ text-align: center;
80
+ }
81
+ .sf-toolbarreset .hide-button svg {
82
+ max-height: 18px;
83
+ margin-top: 10px;
84
+ }
85
+
86
+ .sf-toolbar-block {
87
+ cursor: default;
88
+ display: block;
89
+ float: left;
90
+ height: 36px;
91
+ margin-right: 0;
92
+ white-space: nowrap;
93
+ }
94
+ .sf-toolbar-block > a,
95
+ .sf-toolbar-block > a:hover {
96
+ display: block;
97
+ text-decoration: none;
98
+ }
99
+
100
+ .sf-toolbar-block span {
101
+ display: inline-block;
102
+ }
103
+ .sf-toolbar-block .sf-toolbar-value {
104
+ color: #F5F5F5;
105
+ font-size: 13px;
106
+ line-height: 36px;
107
+ padding: 0;
108
+ }
109
+ .sf-toolbar-block .sf-toolbar-label,
110
+ .sf-toolbar-block .sf-toolbar-class-separator {
111
+ color: #AAA;
112
+ font-size: 12px;
113
+ }
114
+
115
+ .sf-toolbar-block .sf-toolbar-info {
116
+ border-collapse: collapse;
117
+ display: table;
118
+ z-index: 100000;
119
+ }
120
+ .sf-toolbar-block hr {
121
+ border-top: 1px solid #777;
122
+ margin: 4px 0;
123
+ padding-top: 4px;
124
+ }
125
+ .sf-toolbar-block .sf-toolbar-info-piece {
126
+ /* this 'border-bottom' trick is needed because 'margin-bottom' doesn't work for table rows */
127
+ border-bottom: solid transparent 3px;
128
+ display: table-row;
129
+ }
130
+ .sf-toolbar-block .sf-toolbar-info-piece-additional,
131
+ .sf-toolbar-block .sf-toolbar-info-piece-additional-detail {
132
+ display: none;
133
+ }
134
+ .sf-toolbar-block .sf-toolbar-info-group {
135
+ margin-bottom: 4px;
136
+ padding-bottom: 2px;
137
+ border-bottom: 1px solid #333333;
138
+ }
139
+ .sf-toolbar-block .sf-toolbar-info-group:last-child {
140
+ margin-bottom: 0;
141
+ padding-bottom: 0;
142
+ border-bottom: none;
143
+ }
144
+
145
+ .sf-toolbar-block .sf-toolbar-info-piece .sf-toolbar-status {
146
+ padding: 2px 5px;
147
+ margin-bottom: 0;
148
+ }
149
+ .sf-toolbar-block .sf-toolbar-info-piece .sf-toolbar-status + .sf-toolbar-status {
150
+ margin-left: 4px;
151
+ }
152
+
153
+ .sf-toolbar-block .sf-toolbar-info-piece:last-child {
154
+ margin-bottom: 0;
155
+ }
156
+
157
+ .sf-toolbar-block .sf-toolbar-info-piece a {
158
+ color: #99CDD8;
159
+ text-decoration: underline;
160
+ }
161
+ .sf-toolbar-block .sf-toolbar-info-piece a:hover {
162
+ text-decoration: none;
163
+ }
164
+
165
+ .sf-toolbar-block .sf-toolbar-info-piece b {
166
+ color: #AAA;
167
+ display: table-cell;
168
+ font-size: 11px;
169
+ padding: 4px 8px 4px 0;
170
+ }
171
+ .sf-toolbar-block .sf-toolbar-info-piece span {
172
+
173
+ }
174
+ .sf-toolbar-block .sf-toolbar-info-piece span {
175
+ color: #F5F5F5;
176
+ font-size: 12px;
177
+ }
178
+
179
+ .sf-toolbar-block .sf-toolbar-info {
180
+ background-color: #444;
181
+ bottom: 36px;
182
+ color: #F5F5F5;
183
+ display: none;
184
+ padding: 9px 0;
185
+ position: absolute;
186
+ }
187
+
188
+ .sf-toolbar-block .sf-toolbar-info:empty {
189
+ visibility: hidden;
190
+ }
191
+
192
+ .sf-toolbar-block .sf-toolbar-status {
193
+ display: inline-block;
194
+ color: #FFF;
195
+ background-color: #666;
196
+ padding: 3px 6px;
197
+ margin-bottom: 2px;
198
+ vertical-align: middle;
199
+ min-width: 15px;
200
+ min-height: 13px;
201
+ text-align: center;
202
+ }
203
+
204
+ .sf-toolbar-block .sf-toolbar-status-green {
205
+ background-color: <?php echo $colors['success']; ?>;
206
+ }
207
+ .sf-toolbar-block .sf-toolbar-status-red {
208
+ background-color: <?php echo $colors['error']; ?>;
209
+ }
210
+ .sf-toolbar-block .sf-toolbar-status-yellow {
211
+ background-color: <?php echo $colors['warning']; ?>;
212
+ }
213
+
214
+ .sf-toolbar-block.sf-toolbar-status-green {
215
+ background-color: <?php echo $colors['success']; ?>;
216
+ color: #FFF;
217
+ }
218
+ .sf-toolbar-block.sf-toolbar-status-red {
219
+ background-color: <?php echo $colors['error']; ?>;
220
+ color: #FFF;
221
+ }
222
+ .sf-toolbar-block.sf-toolbar-status-yellow {
223
+ background-color: <?php echo $colors['warning']; ?>;
224
+ color: #FFF;
225
+ }
226
+
227
+ .sf-toolbar-block-request .sf-toolbar-status {
228
+ color: #FFF;
229
+ display: inline-block;
230
+ font-size: 14px;
231
+ height: 36px;
232
+ line-height: 36px;
233
+ padding: 0 10px;
234
+ }
235
+ .sf-toolbar-block-request .sf-toolbar-info-piece a {
236
+ text-decoration: none;
237
+ }
238
+ .sf-toolbar-block-request .sf-toolbar-info-piece a:hover {
239
+ text-decoration: underline;
240
+ }
241
+ .sf-toolbar-block-request .sf-toolbar-redirection-status {
242
+ font-weight: normal;
243
+ padding: 2px 4px;
244
+ line-height: 18px;
245
+ }
246
+ .sf-toolbar-block-request .sf-toolbar-info-piece span.sf-toolbar-redirection-method {
247
+ font-size: 12px;
248
+ height: 17px;
249
+ line-height: 17px;
250
+ }
251
+
252
+ .sf-toolbar-status-green .sf-toolbar-label,
253
+ .sf-toolbar-status-yellow .sf-toolbar-label,
254
+ .sf-toolbar-status-red .sf-toolbar-label {
255
+ color: #FFF;
256
+ }
257
+ .sf-toolbar-status-green svg path,
258
+ .sf-toolbar-status-red svg path,
259
+ .sf-toolbar-status-yellow svg path {
260
+ fill: #FFF;
261
+ }
262
+ .sf-toolbar-block-config svg path {
263
+ fill: #FFF;
264
+ }
265
+
266
+ .sf-toolbar-block .sf-toolbar-icon {
267
+ display: block;
268
+ height: 36px;
269
+ padding: 0 7px;
270
+ }
271
+ .sf-toolbar-block-request .sf-toolbar-icon {
272
+ padding-left: 0;
273
+ padding-right: 0;
274
+ }
275
+
276
+ .sf-toolbar-block .sf-toolbar-icon img,
277
+ .sf-toolbar-block .sf-toolbar-icon svg {
278
+ border-width: 0;
279
+ position: relative;
280
+ top: 8px;
281
+ }
282
+
283
+ .sf-toolbar-block .sf-toolbar-icon img + span,
284
+ .sf-toolbar-block .sf-toolbar-icon svg + span {
285
+ margin-left: 4px;
286
+ }
287
+ .sf-toolbar-block-config .sf-toolbar-icon .sf-toolbar-value {
288
+ margin-left: 4px;
289
+ }
290
+
291
+ .sf-toolbar-block:hover {
292
+ position: relative;
293
+ }
294
+ .sf-toolbar-block:hover .sf-toolbar-icon {
295
+ background-color: #444;
296
+ position: relative;
297
+ z-index: 10002;
298
+ }
299
+ .sf-toolbar-block:hover .sf-toolbar-info {
300
+ display: block;
301
+ padding: 10px;
302
+ max-width: 480px;
303
+ max-height: 480px;
304
+ word-wrap: break-word;
305
+ overflow: hidden;
306
+ overflow-y: auto;
307
+ }
308
+ .sf-toolbar-info-piece b.sf-toolbar-ajax-info {
309
+ color: #F5F5F5;
310
+ }
311
+ .sf-toolbar-ajax-requests {
312
+ table-layout: auto;
313
+ width: 100%;
314
+ }
315
+ .sf-toolbar-ajax-requests td {
316
+ background-color: #444;
317
+ border-bottom: 1px solid #777;
318
+ color: #F5F5F5;
319
+ font-size: 12px;
320
+ padding: 4px;
321
+ }
322
+ .sf-toolbar-ajax-requests tr:last-child td {
323
+ border-bottom: 0;
324
+ }
325
+ .sf-toolbar-ajax-requests th {
326
+ background-color: #222;
327
+ border-bottom: 0;
328
+ color: #AAA;
329
+ font-size: 11px;
330
+ padding: 4px;
331
+ }
332
+ .sf-ajax-request-url {
333
+ max-width: 300px;
334
+ line-height: 9px;
335
+ overflow: hidden;
336
+ text-overflow: ellipsis;
337
+ }
338
+ .sf-toolbar-ajax-requests .sf-ajax-request-url a {
339
+ text-decoration: none;
340
+ }
341
+ .sf-toolbar-ajax-requests .sf-ajax-request-url a:hover {
342
+ text-decoration: underline;
343
+ }
344
+ .sf-ajax-request-duration {
345
+ text-align: right;
346
+ }
347
+ .sf-ajax-request-loading {
348
+ -webkit-animation: sf-blink .5s ease-in-out infinite;
349
+ -o-animation: sf-blink .5s ease-in-out infinite;
350
+ -moz-animation: sf-blink .5s ease-in-out infinite;
351
+ animation: sf-blink .5s ease-in-out infinite;
352
+ }
353
+ @-webkit-keyframes sf-blink {
354
+ 0% { background: #222; }
355
+ 50% { background: #444; }
356
+ 100% { background: #222; }
357
+ }
358
+ @-moz-keyframes sf-blink {
359
+ 0% { background: #222; }
360
+ 50% { background: #444; }
361
+ 100% { background: #222; }
362
+ }
363
+ @keyframes sf-blink {
364
+ 0% { background: #222; }
365
+ 50% { background: #444; }
366
+ 100% { background: #222; }
367
+ }
368
+
369
+ .sf-toolbar-block-dump pre.sf-dump {
370
+ background-color: #222;
371
+ border-color: #777;
372
+ border-radius: 0;
373
+ margin: 6px 0 12px 0;
374
+ width: 200px;
375
+ }
376
+ .sf-toolbar-block-dump pre.sf-dump:last-child {
377
+ margin-bottom: 0;
378
+ }
379
+ .sf-toolbar-block-dump .sf-toolbar-info-piece .sf-toolbar-file-line {
380
+ color: #AAA;
381
+ margin-left: 4px;
382
+ }
383
+ .sf-toolbar-block-dump .sf-toolbar-info img {
384
+ display: none;
385
+ }
386
+
387
+ /* Responsive Design */
388
+ .sf-toolbar-icon .sf-toolbar-label,
389
+ .sf-toolbar-icon .sf-toolbar-value {
390
+ display: none;
391
+ }
392
+ .sf-toolbar-block-config .sf-toolbar-icon .sf-toolbar-label {
393
+ display: inline-block;
394
+ }
395
+
396
+ /* Legacy Design - these styles are maintained to make old panels look
397
+ a bit better on the new toolbar */
398
+ .sf-toolbar-block .sf-toolbar-info-piece-additional-detail {
399
+ color: #AAA;
400
+ font-size: 12px;
401
+ }
402
+ .sf-toolbar-status-green .sf-toolbar-info-piece-additional-detail,
403
+ .sf-toolbar-status-yellow .sf-toolbar-info-piece-additional-detail,
404
+ .sf-toolbar-status-red .sf-toolbar-info-piece-additional-detail {
405
+ color: #FFF;
406
+ }
407
+
408
+ @media (min-width: 768px) {
409
+
410
+ .sf-toolbar-icon .sf-toolbar-label,
411
+ .sf-toolbar-icon .sf-toolbar-value {
412
+ display: inline;
413
+ }
414
+
415
+ .sf-toolbar-block .sf-toolbar-icon img,
416
+ .sf-toolbar-block .sf-toolbar-icon svg {
417
+ top: 6px;
418
+ }
419
+ .sf-toolbar-block-time .sf-toolbar-icon svg,
420
+ .sf-toolbar-block-memory .sf-toolbar-icon svg {
421
+ display: none;
422
+ }
423
+ .sf-toolbar-block-time .sf-toolbar-icon svg + span,
424
+ .sf-toolbar-block-memory .sf-toolbar-icon svg + span {
425
+ margin-left: 0;
426
+ }
427
+
428
+ .sf-toolbar-block .sf-toolbar-icon {
429
+ padding: 0 10px;
430
+ }
431
+ .sf-toolbar-block-time .sf-toolbar-icon {
432
+ padding-right: 5px;
433
+ }
434
+ .sf-toolbar-block-memory .sf-toolbar-icon {
435
+ padding-left: 5px;
436
+ }
437
+ .sf-toolbar-block-request .sf-toolbar-icon {
438
+ padding-left: 0;
439
+ padding-right: 0;
440
+ }
441
+ .sf-toolbar-block-request .sf-toolbar-status {
442
+ margin-right: 5px;
443
+ }
444
+ .sf-toolbar-block-request .sf-toolbar-icon svg + .sf-toolbar-label {
445
+ margin-left: 0;
446
+ }
447
+ .sf-toolbar-block-request .sf-toolbar-label + .sf-toolbar-value {
448
+ margin-right: 10px;
449
+ }
450
+
451
+ .sf-toolbar-block-request:hover .sf-toolbar-info {
452
+ max-width: none;
453
+ }
454
+
455
+ .sf-toolbar-block .sf-toolbar-info-piece b {
456
+ font-size: 12px;
457
+ }
458
+ .sf-toolbar-block .sf-toolbar-info-piece span {
459
+ font-size: 13px;
460
+ }
461
+
462
+ .sf-toolbar-block-right {
463
+ float: right;
464
+ margin-left: 0;
465
+ margin-right: 0;
466
+ }
467
+ }
468
+
469
+ @media (min-width: 1024px) {
470
+ .sf-toolbar-block .sf-toolbar-info-piece-additional,
471
+ .sf-toolbar-block .sf-toolbar-info-piece-additional-detail {
472
+ display: inline-block;
473
+ }
474
+
475
+ .sf-toolbar-block .sf-toolbar-info-piece-additional:empty,
476
+ .sf-toolbar-block .sf-toolbar-info-piece-additional-detail:empty {
477
+ display: none;
478
+ }
479
+ }
app/design/frontend/base/default/template/ecocode_profiler/toolbar.phtml ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!-- START of ecocode Web Debug Toolbar -->
2
+ <?php $token = $this->getToken(); ?>
3
+ <style>
4
+ <?php include 'toolbar.css.phtml';?>
5
+ </style>
6
+ <div id="sfwdt<?php echo $token; ?>" class="sf-toolbar">
7
+ <div id="sfMiniToolbar-<?php echo $token; ?>" class="sf-minitoolbar" data-no-turbolink>
8
+ <a href="javascript:void(0);" title="Show Symfony toolbar" tabindex="-1" accesskey="D" onclick="
9
+ var elem = this.parentNode;
10
+ if (elem.style.display == 'none') {
11
+ document.getElementById('sfToolbarMainContent-<?php echo $token; ?>').style.display = 'none';
12
+ document.getElementById('sfToolbarClearer-<?php echo $token; ?>').style.display = 'none';
13
+ elem.style.display = 'block';
14
+ } else {
15
+ document.getElementById('sfToolbarMainContent-<?php echo $token; ?>').style.display = 'block';
16
+ document.getElementById('sfToolbarClearer-<?php echo $token; ?>').style.display = 'block';
17
+ elem.style.display = 'none'
18
+ }
19
+ ">
20
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="svgMageLogo" width="24" xml:space="preserve" height="24" viewBox="0 0 53.692 62" baseProfile="" version="1.1" y="0px" x="0px">
21
+ <g fill="#AAAAAA">
22
+ <path d="m26.845 8.857"></path><polygon points="53.692 15.5 53.692 46.5 46.021 50.929 46.021 19.929 26.845 8.857 7.67 19.928 7.67 50.929 0 46.5 0 15.5 26.845 0"></polygon><polygon points="26.847 62 15.341 55.356 15.341 24.357 23.011 19.928 23.011 50.929 26.845 53.257 30.682 50.929 30.682 19.929 38.353 24.357 38.353 55.356"></polygon>
23
+ </g>
24
+ </svg>
25
+ </a>
26
+ </div>
27
+
28
+ <div id="sfToolbarClearer-<?php echo $token; ?>" style="clear: both; height: 36px;"></div>
29
+
30
+ <?php
31
+ $action = Mage::app()->getFrontController()->getAction();
32
+ $request = Mage::app()->getRequest();
33
+ $response = Mage::app()->getResponse();
34
+ ?>
35
+ <div id="sfToolbarMainContent-<?php echo $token; ?>" class="sf-toolbarreset clear-fix" data-no-turbolink>
36
+ <?php foreach ($this->getToolbarItems() as $block): ?>
37
+ <?php echo $block->toHtml(); ?>
38
+ <?Php endforeach;?>
39
+
40
+ <a class="hide-button" title="Close Toolbar" tabindex="-1" accesskey="D" onclick="
41
+ var p = this.parentNode;
42
+ p.style.display = 'none';
43
+ (p.previousElementSibling || p.previousSibling).style.display = 'none';
44
+ document.getElementById('sfMiniToolbar-<?php echo $token; ?>').style.display = 'block';
45
+ ">
46
+ <svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="24" height="24"
47
+ viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
48
+ <path fill="#AAAAAA" d="M21.1,18.3c0.8,0.8,0.8,2,0,2.8c-0.4,0.4-0.9,0.6-1.4,0.6s-1-0.2-1.4-0.6L12,14.8l-6.3,6.3
49
+ c-0.4,0.4-0.9,0.6-1.4,0.6s-1-0.2-1.4-0.6c-0.8-0.8-0.8-2,0-2.8L9.2,12L2.9,5.7c-0.8-0.8-0.8-2,0-2.8c0.8-0.8,2-0.8,2.8,0L12,9.2
50
+ l6.3-6.3c0.8-0.8,2-0.8,2.8,0c0.8,0.8,0.8,2,0,2.8L14.8,12L21.1,18.3z"/>
51
+ </svg>
52
+
53
+ </a>
54
+ </div>
55
+ </div>
56
+
57
+ <!-- END of Symfony Web Debug Toolbar -->
58
+
59
+
60
+ <style>
61
+ /*remove me*/
62
+ .sf-toggle-content {
63
+ -moz-transition: display .25s ease;
64
+ -webkit-transition: display .25s ease;
65
+ transition: display .25s ease;
66
+ }
67
+
68
+ .sf-toggle-content.sf-toggle-hidden {
69
+ display: none !important;
70
+ }
71
+
72
+ .sf-toggle-content.sf-toggle-visible {
73
+ display: block !important;
74
+ }
75
+ </style>
app/design/frontend/base/default/template/ecocode_profiler/toolbar_js.phtml ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!-- START of ecocode Web Debug Toolbar -->
2
+ <?php $token = $this->getToken(); ?>
3
+
4
+ <div id="sfwdt<?php echo $token?>" class="sf-toolbar" style="display: none"></div>
5
+ <script>
6
+ <?php echo $this->getChildHtml('base_js');?>
7
+ (function () {
8
+ Sfjs.load(
9
+ 'sfwdt<?php echo $token?>',
10
+ '<?php echo Mage::getUrl('_profiler/index/toolbar', [Ecocode_Profiler_Model_Profiler::URL_TOKEN_PARAMETER => $token])?>',
11
+ function(xhr, el) {
12
+ el.style.display = -1 !== xhr.responseText.indexOf('sf-toolbarreset') ? 'block' : 'none';
13
+
14
+ if (el.style.display == 'none') {
15
+ return;
16
+ }
17
+
18
+ if (Sfjs.getPreference('toolbar/displayState') == 'none') {
19
+ document.getElementById('sfToolbarMainContent-<?php echo $token?>').style.display = 'none';
20
+ document.getElementById('sfToolbarClearer-<?php echo $token?>').style.display = 'none';
21
+ document.getElementById('sfMiniToolbar-<?php echo $token?>').style.display = 'block';
22
+ } else {
23
+ document.getElementById('sfToolbarMainContent-<?php echo $token?>').style.display = 'block';
24
+ document.getElementById('sfToolbarClearer-<?php echo $token?>').style.display = 'block';
25
+ document.getElementById('sfMiniToolbar-<?php echo $token?>').style.display = 'none';
26
+ }
27
+
28
+ Sfjs.renderAjaxRequests();
29
+
30
+ /* Handle toolbar-info position */
31
+ var toolbarBlocks = document.querySelectorAll('.sf-toolbar-block');
32
+ for (var i = 0; i < toolbarBlocks.length; i += 1) {
33
+ toolbarBlocks[i].onmouseover = function () {
34
+ var toolbarInfo = this.querySelectorAll('.sf-toolbar-info')[0];
35
+ var pageWidth = document.body.clientWidth;
36
+ var elementWidth = toolbarInfo.offsetWidth;
37
+ var leftValue = (elementWidth + this.offsetLeft) - pageWidth;
38
+ var rightValue = (elementWidth + (pageWidth - this.offsetLeft)) - pageWidth;
39
+
40
+ /* Reset right and left value, useful on window resize */
41
+ toolbarInfo.style.right = '';
42
+ toolbarInfo.style.left = '';
43
+
44
+ if (elementWidth > pageWidth) {
45
+ toolbarInfo.style.left = 0;
46
+ }
47
+ else if (leftValue > 0 && rightValue > 0) {
48
+ toolbarInfo.style.right = (rightValue * -1) + 'px';
49
+ } else if (leftValue < 0) {
50
+ toolbarInfo.style.left = 0;
51
+ } else {
52
+ toolbarInfo.style.right = '0px';
53
+ }
54
+ };
55
+ }
56
+
57
+ var actions = document.querySelectorAll('.sf-toolbar .ajax-action');
58
+
59
+ for (var j = 0; j < actions.length; j++) {
60
+ (function () {
61
+
62
+ var button = actions[j],
63
+ url = button.getAttribute('data-url');
64
+
65
+ button.addEventListener('click', function (e) {
66
+ Sfjs.request(url, function () {
67
+ window.location.reload();
68
+ });
69
+ });
70
+ })();
71
+ }
72
+ },
73
+ function(xhr) {
74
+ if (xhr.status !== 0) {
75
+ confirm('An error occurred while loading the web debug toolbar (' + xhr.status + ': ' + xhr.statusText + ').\n\nDo you want to open the profiler?') && (window.location = '<?php echo Mage::helper('ecocode_profiler')->getUrl($token)?>');
76
+ }
77
+ },
78
+ {'maxTries': 5}
79
+ );
80
+ })();
81
+ </script>
app/etc/modules/Ecocode_Profiler.xml ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <modules>
4
+ <Ecocode_Profiler>
5
+ <active>true</active>
6
+ <codePool>community</codePool>
7
+ </Ecocode_Profiler>
8
+ </modules>
9
+ </config>
dev.php ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if ((!isset($_SERVER['ALLOW_PROFILER']) || $_SERVER['ALLOW_PROFILER'] !== '1') && (
3
+ isset($_SERVER['HTTP_CLIENT_IP'])
4
+ || isset($_SERVER['HTTP_X_FORWARDED_FOR'])
5
+ || !(in_array(@$_SERVER['REMOTE_ADDR'], ['127.0.0.1', '::1']) || php_sapi_name() === 'cli-server')
6
+ )
7
+ ) {
8
+ header('HTTP/1.0 403 Forbidden');
9
+ //exit here, if you do not deploy the profiler on production you can comment these lines
10
+ exit('You are not allowed to access this file. Check ' . basename(__FILE__) . ' for more information.');
11
+ }
12
+
13
+ if (version_compare(phpversion(), '5.4.0', '<') === true) {
14
+ throw new RuntimeException('ERROR: Whoops, it looks like you have an invalid PHP version. Magento supports PHP 5.4.0 or newer.');
15
+ }
16
+
17
+
18
+ /**
19
+ * Error reporting
20
+ */
21
+ error_reporting(E_ALL | E_STRICT);
22
+
23
+
24
+ define('MAGENTO_ROOT', getcwd());
25
+
26
+ set_include_path(dirname(__FILE__) . PATH_SEPARATOR . get_include_path());
27
+ $mageFilename = MAGENTO_ROOT . '/app/MageDev.php';
28
+ $maintenanceFile = 'maintenance.flag';
29
+
30
+ if (!file_exists($mageFilename)) {
31
+ throw new RuntimeException($mageFilename . " was not found");
32
+ }
33
+
34
+ require_once $mageFilename;
35
+ require_once PROFILER_DIR . 'debug.php';
36
+
37
+
38
+
39
+ if (isset($_SERVER['MAGE_IS_DEVELOPER_MODE'])) {
40
+ Mage::setIsDeveloperMode(true);
41
+ }
42
+
43
+
44
+ umask(0);
45
+
46
+ /* Store or website code */
47
+ $mageRunCode = isset($_SERVER['MAGE_RUN_CODE']) ? $_SERVER['MAGE_RUN_CODE'] : '';
48
+
49
+ /* Run store or run website */
50
+ $mageRunType = isset($_SERVER['MAGE_RUN_TYPE']) ? $_SERVER['MAGE_RUN_TYPE'] : 'store';
51
+
52
+
53
+ $options = [
54
+ 'cache' => ['id_prefix' => 'dev'],
55
+ 'config_model' => 'Ecocode_Profiler_Model_Core_Config'
56
+ ];
57
+ Mage::run($mageRunCode, $mageRunType, $options);
58
+
59
+ Mage::terminate();
package.xml ADDED
@@ -0,0 +1,448 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2
+ <root>
3
+ <name>Ecocode_Profiler</name>
4
+ <channel>community</channel>
5
+ <version>1.1.0</version>
6
+ <description>&lt;h1 id="ecocode-profiler-magento-1-x-web-profiler"&gt;ecocode Profiler - Magento 1.x Web Profiler&lt;/h1&gt;
7
+ &lt;p&gt;&lt;a href="https://travis-ci.org/ecoco/magento_profiler"&gt;&lt;img src="https://travis-ci.org/ecoco/magento_profiler.svg?branch=master" alt="Build Status"&gt;&lt;/a&gt;
8
+ &lt;a href="https://coveralls.io/github/ecoco/magento_profiler?branch=master"&gt;&lt;img src="https://coveralls.io/repos/github/ecoco/magento_profiler/badge.svg?branch=master" alt="Coverage Status"&gt;&lt;/a&gt;
9
+ &lt;a href="https://codeclimate.com/github/ecoco/magento_profiler"&gt;&lt;img src="https://codeclimate.com/github/ecoco/magento_profiler/badges/gpa.svg" alt="Code Climate"&gt;&lt;/a&gt;
10
+ &lt;a href="https://insight.sensiolabs.com/projects/f86c6354-5604-4472-8c59-daa3f71dad54"&gt;&lt;img src="https://insight.sensiolabs.com/projects/f86c6354-5604-4472-8c59-daa3f71dad54/mini.png" alt="SensioLabsInsight"&gt;&lt;/a&gt;&lt;/p&gt;
11
+ &lt;p&gt;The ecocode profiler provides a development toolbar for Magento which displays a wide range of metrics and page load data for all the pages of the shop. It gives you direct access to the page&amp;#39;s database queries, memory usage, events, requests, layout rendering, translation resolution and many other useful statistics. It is also easily extendable if you need to track additional metrics.&lt;/p&gt;
12
+ &lt;p&gt;This profiler is based on the awesome &lt;a href="https://github.com/symfony/web-profiler-bundle"&gt;Symfony WebProfiler&lt;/a&gt;.
13
+ The concept and code of the WebProfiler have been ported to assist with Magento as much as possible.&lt;/p&gt;
14
+ &lt;h2 id="requirements"&gt;Requirements&lt;/h2&gt;
15
+ &lt;ul&gt;
16
+ &lt;li&gt;php &amp;gt;= 5.5.9&lt;/li&gt;
17
+ &lt;li&gt;magento &amp;lt; 2&lt;/li&gt;
18
+ &lt;/ul&gt;
19
+ &lt;p&gt;Tested with magento
20
+ 1.7, 1.8. 1.9&lt;/p&gt;
21
+ &lt;p&gt;Demo Stores:&lt;/p&gt;
22
+ &lt;ul&gt;
23
+ &lt;li&gt;&lt;a href="http://1.7.0.2.magento-profiler.ecocode.de/dev.php"&gt;Profiler with Magento 1.7.0.2&lt;/a&gt;&lt;/li&gt;
24
+ &lt;li&gt;&lt;a href="http://1.8.1.0.magento-profiler.ecocode.de/dev.php"&gt;Profiler with Magento 1.8.1.0&lt;/a&gt;&lt;/li&gt;
25
+ &lt;li&gt;&lt;a href="http://1.9.2.4.magento-profiler.ecocode.de/dev.php"&gt;Profiler with Magento 1.9.2.4&lt;/a&gt;&lt;/li&gt;
26
+ &lt;/ul&gt;
27
+ &lt;hr&gt;
28
+ &lt;p&gt;&lt;img src="https://github.com/ecoco/magento_profiler/raw/v1.1.0/docs/image/toolbar.jpg" alt="Toolbar" title="Toolbar"&gt;&lt;/p&gt;
29
+ &lt;p&gt;&lt;img src="/docs/image/profiler.jpg" alt="Profiler" title="Profiler"&gt;&lt;/p&gt;
30
+ &lt;p&gt;&lt;a href="docs/images.md"&gt;More Images&lt;/a&gt;&lt;/p&gt;
31
+ &lt;h2 id="installation"&gt;Installation&lt;/h2&gt;
32
+ &lt;h3 id="composer-recommended-"&gt;Composer (recommended)&lt;/h3&gt;
33
+ &lt;p&gt;If you have not already configured &lt;a href="https://github.com/Cotya/magento-composer-installer"&gt;magento-composer-installer&lt;/a&gt; add&lt;/p&gt;
34
+ &lt;pre&gt;&lt;code&gt;&amp;quot;extra&amp;quot;: {
35
+ &amp;quot;magento-root-dir&amp;quot;: &amp;quot;httpdocs/&amp;quot;
36
+ }
37
+ &lt;/code&gt;&lt;/pre&gt;&lt;p&gt;to your &lt;strong&gt;composer.json&lt;/strong&gt;. If your magento root dir is the same directory as the one containing your &lt;strong&gt;composer.json&lt;/strong&gt; use &lt;code&gt;&amp;quot;.&amp;quot;&lt;/code&gt; as the &lt;code&gt;magento-root-dir&lt;/code&gt;&lt;/p&gt;
38
+ &lt;p&gt;&lt;code&gt;composer require --dev ecocode/magento-profiler&lt;/code&gt;&lt;/p&gt;
39
+ &lt;h3 id="manually"&gt;Manually&lt;/h3&gt;
40
+ &lt;p&gt;Download the module and copy the &lt;strong&gt;app&lt;/strong&gt; folder + &amp;quot;dev.php&amp;quot; into your magento
41
+ root directory&lt;/p&gt;
42
+ &lt;p&gt;If you install the module manually, it will miss some functionality until you install
43
+ the dependencies. This is currently only possible via composer as we do need the composer autoloader.&lt;/p&gt;
44
+ &lt;p&gt;To install the dependencies run the following from your magento root dir or a parent directory:&lt;/p&gt;
45
+ &lt;pre&gt;&lt;code&gt;composer require --dev symfony/debug 3.1
46
+ composer require --dev symfony/yaml 3.1
47
+ composer require --dev jdorn/sql-formatter 1.2
48
+ composer require --dev monolog/monolog 1.11
49
+ &lt;/code&gt;&lt;/pre&gt;&lt;h3 id="magento-connect"&gt;Magento Connect&lt;/h3&gt;
50
+ &lt;p&gt;In progress&lt;/p&gt;
51
+ &lt;h3 id="webserver-config"&gt;Webserver Config&lt;/h3&gt;
52
+ &lt;p&gt;It might be necessary to extend your webserver config to handle &amp;quot;dev.php&amp;quot; correctly&lt;/p&gt;
53
+ &lt;h3 id="nginx-"&gt;Nginx:&lt;/h3&gt;
54
+ &lt;p&gt;If you are using nginx and get a &lt;code&gt;404&lt;/code&gt; for the profiler, try adding the following to your nginx config before the php location definition:&lt;/p&gt;
55
+ &lt;pre&gt;&lt;code&gt;location /dev.php/ {
56
+ rewrite / /dev.php;
57
+ }
58
+ &lt;/code&gt;&lt;/pre&gt;&lt;hr&gt;
59
+ &lt;h4 id="apache-"&gt;Apache:&lt;/h4&gt;
60
+ &lt;p&gt;nothing to do here, should run out of the box&lt;/p&gt;
61
+ &lt;h2 id="usage"&gt;Usage&lt;/h2&gt;
62
+ &lt;p&gt;The profiler is only enabled if you open your shop via &lt;code&gt;http://myshop.local/dev.php/&lt;/code&gt;.
63
+ The idea is to develop always in dev mode alias &amp;quot;dev.php&amp;quot; and only switch back to &amp;quot;production&amp;quot; from
64
+ time to time to verify the result.&lt;/p&gt;
65
+ &lt;h2 id="features"&gt;Features&lt;/h2&gt;
66
+ &lt;ul&gt;
67
+ &lt;li&gt;Improved exception handling in dev mode with the &lt;a href="https://github.com/symfony/debug"&gt;symfony/debug&lt;/a&gt;. No more checking the log files!&lt;/li&gt;
68
+ &lt;li&gt;Easily extendable, just add a new &lt;strong&gt;collector&lt;/strong&gt; via your configuration&lt;/li&gt;
69
+ &lt;/ul&gt;
70
+ &lt;h2 id="collectors"&gt;Collectors&lt;/h2&gt;
71
+ &lt;ul&gt;
72
+ &lt;li&gt;Request/Response&lt;ul&gt;
73
+ &lt;li&gt;Display of request/response server parameters&lt;/li&gt;
74
+ &lt;/ul&gt;
75
+ &lt;/li&gt;
76
+ &lt;li&gt;Memory&lt;ul&gt;
77
+ &lt;li&gt;Display of memory usage &lt;/li&gt;
78
+ &lt;/ul&gt;
79
+ &lt;/li&gt;
80
+ &lt;li&gt;Mysql&lt;ul&gt;
81
+ &lt;li&gt;Display of all queries with syntax highlighting and stack traces to locate the origin&lt;/li&gt;
82
+ &lt;li&gt;Queries by context so you can easily determine the origin block&lt;/li&gt;
83
+ &lt;li&gt;&lt;strong&gt;Detection of identical&lt;/strong&gt; queries that can be avoided&lt;/li&gt;
84
+ &lt;li&gt;Metrics for &amp;quot;mysql crud&amp;quot; operations&lt;/li&gt;
85
+ &lt;li&gt;Support for multiple database connections&lt;/li&gt;
86
+ &lt;/ul&gt;
87
+ &lt;/li&gt;
88
+ &lt;li&gt;Events&lt;ul&gt;
89
+ &lt;li&gt;Display of all events that have been fired during page load&lt;/li&gt;
90
+ &lt;li&gt;List of all called observers&lt;/li&gt;
91
+ &lt;/ul&gt;
92
+ &lt;/li&gt;
93
+ &lt;li&gt;Ajax&lt;ul&gt;
94
+ &lt;li&gt;Recording of ajax calls&lt;/li&gt;
95
+ &lt;/ul&gt;
96
+ &lt;/li&gt;
97
+ &lt;li&gt;Customer&lt;ul&gt;
98
+ &lt;li&gt;Display of customer group and tax class &lt;/li&gt;
99
+ &lt;/ul&gt;
100
+ &lt;/li&gt;
101
+ &lt;li&gt;Layout&lt;ul&gt;
102
+ &lt;li&gt;Metrics including created and rendered blocks and total rendering time&lt;/li&gt;
103
+ &lt;li&gt;List of layout handlers used&lt;/li&gt;
104
+ &lt;li&gt;List of blocks created but not rendered&lt;/li&gt;
105
+ &lt;li&gt;Call graph including rendering times by block, including and excluding children&lt;/li&gt;
106
+ &lt;/ul&gt;
107
+ &lt;/li&gt;
108
+ &lt;li&gt;Translations&lt;ul&gt;
109
+ &lt;li&gt;Display of translations that are defined, missing, invalid or are using a fallback&lt;/li&gt;
110
+ &lt;/ul&gt;
111
+ &lt;/li&gt;
112
+ &lt;li&gt;Rewrites&lt;ul&gt;
113
+ &lt;li&gt;Detection of rewrites and rewrite conflicts (credits to &lt;a href="https://github.com/netz98/n98-magerun"&gt;magen98-magerun&lt;/a&gt; for the detection)&lt;/li&gt;
114
+ &lt;/ul&gt;
115
+ &lt;/li&gt;
116
+ &lt;li&gt;Logs&lt;ul&gt;
117
+ &lt;li&gt;Display of all &lt;code&gt;Mage::log&lt;/code&gt; calls&lt;/li&gt;
118
+ &lt;/ul&gt;
119
+ &lt;/li&gt;
120
+ &lt;li&gt;Models&lt;ul&gt;
121
+ &lt;li&gt;Display of all model load, delete and save calls&lt;/li&gt;
122
+ &lt;li&gt;&lt;strong&gt;Detection of &amp;quot;load&amp;quot; calls within loops!&lt;/strong&gt;&lt;/li&gt;
123
+ &lt;/ul&gt;
124
+ &lt;/li&gt;
125
+ &lt;li&gt;Cache&lt;ul&gt;
126
+ &lt;li&gt;Display of current cache configuration including the option to enable/disable and flush from the profiler&lt;/li&gt;
127
+ &lt;li&gt;Display of all cache calls including not-for-cache &lt;strong&gt;hits&lt;/strong&gt; and &lt;strong&gt;misses&lt;/strong&gt;&lt;/li&gt;
128
+ &lt;/ul&gt;
129
+ &lt;/li&gt;
130
+ &lt;li&gt;Configuration&lt;ul&gt;
131
+ &lt;li&gt;Base PHP configuration&lt;/li&gt;
132
+ &lt;li&gt;Option to view &lt;code&gt;phpinfo()&lt;/code&gt;&lt;/li&gt;
133
+ &lt;li&gt;Basic magento configuration&lt;/li&gt;
134
+ &lt;li&gt;Display of enabled and disabled modules&lt;/li&gt;
135
+ &lt;/ul&gt;
136
+ &lt;/li&gt;
137
+ &lt;/ul&gt;
138
+ &lt;h2 id="security"&gt;Security&lt;/h2&gt;
139
+ &lt;p&gt;It should be safe to add this module to your own vcs by default. The profiler
140
+ is only active when you are visiting your page via &amp;quot;dev.php&amp;quot;, which is restricted to
141
+ localhost by default.&lt;/p&gt;
142
+ &lt;p&gt;If you are using a vm you can edit the &lt;code&gt;dev.php&lt;/code&gt; or set &lt;code&gt;$_SERVER[&amp;#39;ALLOW_PROFILER&amp;#39;] = 1&lt;/code&gt;
143
+ via your nginx or htaccess&lt;/p&gt;
144
+ &lt;h2 id="todo"&gt;TODO&lt;/h2&gt;
145
+ &lt;ul&gt;
146
+ &lt;li&gt;Session Data&lt;/li&gt;
147
+ &lt;li&gt;Catch url redirects&lt;/li&gt;
148
+ &lt;li&gt;Improve docs&lt;/li&gt;
149
+ &lt;li&gt;&amp;quot;how to extend&amp;quot;&lt;/li&gt;
150
+ &lt;/ul&gt;
151
+ &lt;h2 id="mixed"&gt;Mixed&lt;/h2&gt;
152
+ &lt;p&gt;If you get a &lt;code&gt;gateway timeout 503&lt;/code&gt; instead of an error message please try to adjust your
153
+ nginx config&lt;/p&gt;
154
+ &lt;pre&gt;&lt;code&gt;http {
155
+ ...
156
+ fastcgi_buffers 8 16k;
157
+ fastcgi_buffer_size 32k;
158
+ ...
159
+ }
160
+ &lt;/code&gt;&lt;/pre&gt;&lt;h2 id="need-help-"&gt;Need help?&lt;/h2&gt;
161
+ &lt;p&gt;Feel free to contact me jk@ecocode.de&lt;/p&gt;
162
+ &lt;h2 id="thanks-to"&gt;Thanks to&lt;/h2&gt;
163
+ &lt;ul&gt;
164
+ &lt;li&gt;&lt;a href="https://github.com/symfony/debug"&gt;symfony/debug&lt;/a&gt; for the awesome debug component&lt;/li&gt;
165
+ &lt;li&gt;&lt;a href="https://github.com/netz98/n98-magerun"&gt;magen98-magerun&lt;/a&gt; for the rewrite conflict detection&lt;/li&gt;
166
+ &lt;li&gt;&lt;a href="https://github.com/symfony/web-profiler-bundle"&gt;Symfony WebProfiler&lt;/a&gt;&lt;/li&gt;
167
+ &lt;/ul&gt;
168
+ </description>
169
+ <summery>Web Profiler for Magento 1.x</summery>
170
+ <license>MIT</license>
171
+ <stability>stable</stability>
172
+ <notes/>
173
+ <date>2016-10-11</date>
174
+ <time>19:23:09</time>
175
+ <authors>
176
+ <author>
177
+ <name>Justus Krapp</name>
178
+ <email>jk@ecocode.de</email>
179
+ <user>MAG000111800</user>
180
+ </author>
181
+ </authors>
182
+ <dependencies>
183
+ <required>
184
+ <php>
185
+ <min>5.5.9</min>
186
+ <max>7.0.10</max>
187
+ </php>
188
+ </required>
189
+ </dependencies>
190
+ <contents>
191
+ <target name="mage">
192
+ <file name="dev.php" hash="614dafcdeea3f796b0f2b9111ed3f1e3"/>
193
+ <dir name="app">
194
+ <file name="MageDev.php" hash="0c7257cd6c825f65ecdc230e172d9cca"/>
195
+ </dir>
196
+ </target>
197
+ <target name="mageetc">
198
+ <dir name="modules">
199
+ <file name="Ecocode_Profiler.xml" hash="7d3910686ef4f32eedfdadf3e3ccdcaf"/>
200
+ </dir>
201
+ </target>
202
+ <target name="magedesign">
203
+ <dir name="frontend">
204
+ <dir name="base">
205
+ <dir name="default">
206
+ <dir name="layout">
207
+ <file name="ecocode_profiler.xml" hash="77c53c870841abec7e9b991d3d13be23"/>
208
+ </dir>
209
+ <dir name="template">
210
+ <dir name="ecocode_profiler">
211
+ <file name="back-trace.phtml" hash="3e87214048db56081377577284b0ed92"/>
212
+ <file name="bag.phtml" hash="bd4363dfe3f58bb352cd2f7aecc220a0"/>
213
+ <file name="layout.phtml" hash="4b7a285bcf3811a63089f23de5f7bb2a"/>
214
+ <file name="toolbar_js.phtml" hash="4c55d25dba7c8528fc12fb132cf95670"/>
215
+ <file name="toolbar.css.phtml" hash="e69c6cab4024a1c92859bd6d9a5c90bc"/>
216
+ <file name="toolbar.phtml" hash="8fcffc1866e836ddd02939c67b75cc26"/>
217
+ <dir name="collector">
218
+ <dir name="ajax">
219
+ <file name="toolbar.phtml" hash="82f3f425377c110b2b2931c0a2021b5e"/>
220
+ </dir>
221
+ <dir name="base">
222
+ <file name="menu.phtml" hash="a9ce631d4f2e5f1422e24b85904d266b"/>
223
+ </dir>
224
+ <dir name="cache">
225
+ <file name="menu.phtml" hash="7c84720f0d33760a719d1700fb4aeb90"/>
226
+ <file name="panel.phtml" hash="4ec12213e351cf5b8ef33710abeee8eb"/>
227
+ <file name="toolbar.phtml" hash="ef01eabfdee95829d4f4a6e71daac816"/>
228
+ </dir>
229
+ <dir name="config">
230
+ <file name="menu.phtml" hash="3413b99ba04b314a14c1ee3394ea0cde"/>
231
+ <file name="panel.phtml" hash="c02443a2aacb437474a72c051a60b186"/>
232
+ <file name="toolbar.phtml" hash="658434996a5dc668093f395663f6872b"/>
233
+ </dir>
234
+ <dir name="customer">
235
+ <file name="toolbar.phtml" hash="0d9c3fcd3ef232d5be1b3057c6db1c28"/>
236
+ </dir>
237
+ <dir name="event">
238
+ <file name="menu.phtml" hash="de69ecbd1f53771890c9156325e80729"/>
239
+ <file name="panel.phtml" hash="a01c50694d3c17142a43fb75d169b4a0"/>
240
+ </dir>
241
+ <dir name="layout">
242
+ <file name="menu.phtml" hash="f69f33c6d3bd734c3a3742dca91c81bd"/>
243
+ <file name="panel.phtml" hash="dcaf56b67e95691a2a685b039df53db8"/>
244
+ <file name="toolbar.phtml" hash="2e9e5942ad2e202ecb36069f4520285f"/>
245
+ </dir>
246
+ <dir name="log">
247
+ <file name="menu.phtml" hash="38c8d9ba8e803dcdffcba07c532e8cfa"/>
248
+ <file name="panel.phtml" hash="c1580c5591d9ed1e7508223e0440139e"/>
249
+ <file name="toolbar.phtml" hash="f9f4c1aa7eb6e2b4c5f9fb29c4355c3b"/>
250
+ <dir name="panel">
251
+ <file name="log-table.phtml" hash="0d305d9cecc0f8cd2daa559577f22e59"/>
252
+ </dir>
253
+ </dir>
254
+ <dir name="memory">
255
+ <file name="toolbar.phtml" hash="01d23d6a986ea9a838ff37974814c17d"/>
256
+ </dir>
257
+ <dir name="model">
258
+ <file name="menu.phtml" hash="00a2226bc05b0fef429160ecafd60204"/>
259
+ <file name="panel.phtml" hash="fb85a775faea43e0fddc3e71179e8310"/>
260
+ <file name="toolbar.phtml" hash="cbd77333b03d1ade489c249346b4e5fe"/>
261
+ </dir>
262
+ <dir name="mysql">
263
+ <file name="menu.phtml" hash="e9ff757f0330116f232961470ab63ffe"/>
264
+ <file name="panel.phtml" hash="c291f1492478fe99ffd90efc974d041d"/>
265
+ <file name="toolbar.phtml" hash="166394a1bef92a73f3a9c60b35249eb9"/>
266
+ <dir name="panel">
267
+ <file name="query-table.phtml" hash="68d4a6d2206477ef1d4ecca49ceda721"/>
268
+ </dir>
269
+ </dir>
270
+ <dir name="request">
271
+ <file name="menu.phtml" hash="45de32145ba7d367dd400ffdfb726295"/>
272
+ <file name="panel.phtml" hash="2b4543345ad9ab659d165f71b0837539"/>
273
+ <file name="toolbar.phtml" hash="d31ee40313be5c70d844bf85204432d4"/>
274
+ </dir>
275
+ <dir name="rewrite">
276
+ <file name="menu.phtml" hash="881118b3135e5a2f15e2cb8072b0c2ed"/>
277
+ <file name="panel.phtml" hash="b354f137b3b6fb4a58d0c1b0018c3273"/>
278
+ <file name="toolbar.phtml" hash="03f8a4320132fa28a1bdd53b6aeb15bb"/>
279
+ </dir>
280
+ <dir name="time">
281
+ <file name="toolbar.phtml" hash="f32576053b7f4f4e8063eee3ad915d19"/>
282
+ </dir>
283
+ <dir name="translation">
284
+ <file name="menu.phtml" hash="27a3539bb8a93b2cc811e68f5e07a898"/>
285
+ <file name="panel.phtml" hash="1eef90a79983a141c1db14ca0bcd2afb"/>
286
+ <file name="toolbar.phtml" hash="12702548344ed6a63487394201f0eb56"/>
287
+ <dir name="panel">
288
+ <file name="table.phtml" hash="e0f080dbe249cede69b8f566dd7be82c"/>
289
+ </dir>
290
+ </dir>
291
+ </dir>
292
+ <dir name="layout">
293
+ <file name="sidebar.phtml" hash="0cdebfdd9daabcd6e8d36d13c094fb59"/>
294
+ <dir name="sidebar">
295
+ <file name="menu.phtml" hash="5ba837a64ccb3ade9e178a67865b0363"/>
296
+ </dir>
297
+ </dir>
298
+ <dir name="profiler">
299
+ <file name="base.css.phtml" hash="5aa4306149ccb84867915bce7e4a5f12"/>
300
+ <file name="base.js.phtml" hash="dc8fdc11af0a8458aceee4766e337620"/>
301
+ <file name="summery.phtml" hash="9a71359e8e47ded85f55299aed93371e"/>
302
+ <dir name="search">
303
+ <file name="results.phtml" hash="970d81fff56177afcc882f8efb467f7e"/>
304
+ <file name="summery.phtml" hash="7d3e70179beef079a5efde9fea6dd504"/>
305
+ </dir>
306
+ </dir>
307
+ <dir name="renderer">
308
+ <file name="context.phtml" hash="38f3f9e0b17f96eb6e01332e78337f55"/>
309
+ </dir>
310
+ </dir>
311
+ </dir>
312
+ </dir>
313
+ </dir>
314
+ </dir>
315
+ </target>
316
+ <target name="magecommunity">
317
+ <dir name="Ecocode">
318
+ <dir name="Profiler">
319
+ <file name="autoloader.php" hash="625350c21fc1ce3b298e5cef41198308"/>
320
+ <file name="debug.php" hash="f5b9e0a679f16a948f540b2e7fa6c25b"/>
321
+ <dir name="Block">
322
+ <file name="Bag.php" hash="6f574bbd70410b7cc4198c88131ab9fd"/>
323
+ <file name="Toolbar.php" hash="f1a247c7cc273598d80d0b3c69263536"/>
324
+ <dir name="Collector">
325
+ <file name="Base.php" hash="8f6852999389c3e6159c93a8dc21a3a7"/>
326
+ <file name="Menu.php" hash="be064554e1868ef0d06d0a9393fbe460"/>
327
+ <dir name="Layout">
328
+ <file name="Panel.php" hash="a3250d15e46573d07e6be930bff09bbc"/>
329
+ </dir>
330
+ <dir name="Log">
331
+ <file name="Panel.php" hash="7836cb8d57f778765c433e1887908aac"/>
332
+ </dir>
333
+ <dir name="Mysql">
334
+ <file name="Panel.php" hash="95c41d688e01ab371a8b74a207342e07"/>
335
+ </dir>
336
+ <dir name="Translation">
337
+ <file name="Panel.php" hash="f3da35eb4848ad9bc8baa99f89ae6748"/>
338
+ </dir>
339
+ </dir>
340
+ <dir name="Profiler">
341
+ <file name="Sidebar.php" hash="9b0727ba0af64f5f4f395c36d32b0bcc"/>
342
+ <dir name="Sidebar">
343
+ <file name="Menu.php" hash="b336bdb43b417d00b6c4e8aeed306c0e"/>
344
+ </dir>
345
+ </dir>
346
+ <dir name="Renderer">
347
+ <file name="AbstractRenderer.php" hash="451a64191ddd17741195511b357179f0"/>
348
+ <file name="BackTrace.php" hash="7bf2d900481bed0c5a06613ab687b7ef"/>
349
+ <file name="Context.php" hash="d570e34a9565e3cad0781ee354bd4ef9"/>
350
+ <file name="RendererInterface.php" hash="a34a484b2c7859696c214ade11208b04"/>
351
+ <dir name="Log">
352
+ <file name="LogTable.php" hash="ace6bc645cbbcd0f5fb4cfd9b08e6859"/>
353
+ </dir>
354
+ <dir name="Mysql">
355
+ <file name="QueryTable.php" hash="38a9b601e5f1379285d07e4361d94ac1"/>
356
+ </dir>
357
+ </dir>
358
+ </dir>
359
+ <dir name="Controller">
360
+ <file name="AbstractController.php" hash="df479a9daa699be75d49930cc7468648"/>
361
+ </dir>
362
+ <dir name="controllers">
363
+ <file name="CacheController.php" hash="cba1eefa1c5b487abbd44eaa6167900b"/>
364
+ <file name="IndexController.php" hash="263e2bf4631e037fb61a5d1f131cb555"/>
365
+ </dir>
366
+ <dir name="Db">
367
+ <dir name="Statement">
368
+ <dir name="Pdo">
369
+ <file name="Mysql.php" hash="a9772c14b6e5d517e4a1900210ec76fe"/>
370
+ </dir>
371
+ </dir>
372
+ </dir>
373
+ <dir name="etc">
374
+ <file name="config.xml" hash="3e655889fd41aa91071c68fa0b63d93e"/>
375
+ <file name="development.xml" hash="569481da5b5fc6a17e0f69747ddb41be"/>
376
+ </dir>
377
+ <dir name="Helper">
378
+ <file name="AbstractHelper.php" hash="f3b8fc47c99b7a9f492c09ee38d2a4dd"/>
379
+ <file name="Code.php" hash="5cd26ca017a787618fdf552e48ac0f72"/>
380
+ <file name="Context.php" hash="c8d0d66a13a558b26092fbe375643819"/>
381
+ <file name="Data.php" hash="d2a72158860ba97e4c493bec643e2bed"/>
382
+ <file name="Renderer.php" hash="5129f2242f9456cb72cd10fb205531af"/>
383
+ <file name="Rewrite.php" hash="5d14a5cade6df7fe4f0fdb14b381d21c"/>
384
+ <file name="Sql.php" hash="2daba313727d3376f63f5096f4c67532"/>
385
+ <file name="ValueExporter.php" hash="d5c47a798bf0bc63e22ac8e530c97513"/>
386
+ </dir>
387
+ <dir name="Model">
388
+ <file name="AppDev.php" hash="3452f2a7476bda585f2e117fe6b2007f"/>
389
+ <file name="Context.php" hash="6f88c38762b1cea9b61dceffa28d4bfe"/>
390
+ <file name="ContextInterface.php" hash="6fa0b665a1f66469072c7a15064241fe"/>
391
+ <file name="DebugLoggerInterface.php" hash="fb77da964513216bced10423f9e9ef79"/>
392
+ <file name="Logger.php" hash="6b7a41a4b32d61c757291f4611bcb065"/>
393
+ <file name="Observer.php" hash="d470dd34415b67c1d210322cafbe6b52"/>
394
+ <file name="Profile.php" hash="b109854a402cb400d689939db515a8f7"/>
395
+ <file name="Profiler.php" hash="d656aa79765761d6af7d41c0692db62c"/>
396
+ <dir name="Collector">
397
+ <file name="AbstractDataCollector.php" hash="7a58e7a7f781fcb25596ec454a0941fa"/>
398
+ <file name="AjaxDataCollector.php" hash="8abe36cbc71801d9509a1607cb510872"/>
399
+ <file name="CacheDataCollector.php" hash="121234aaeff67cfb7e367f4d0ea6ca74"/>
400
+ <file name="ConfigDataCollector.php" hash="2717afc87c5c67af0b09219c14ebb10f"/>
401
+ <file name="ContextDataCollector.php" hash="ea8e04938af2e1ec2a095306d8c0a07d"/>
402
+ <file name="CustomerDataCollector.php" hash="b49edceafe5c60a2ffb96dc3c62b4a82"/>
403
+ <file name="DataCollectorInterface.php" hash="33082cfb75eedf75b6af2c6afac3d782"/>
404
+ <file name="EventDataCollector.php" hash="b54c69b72dd4694c33a8934c4588aa14"/>
405
+ <file name="LateDataCollectorInterface.php" hash="11f0136ac985fbadde129c2de7082df1"/>
406
+ <file name="LayoutDataCollector.php" hash="a0161acecfe24eae72f1a23055d8dd31"/>
407
+ <file name="LogDataCollector.php" hash="ed5554e57957606f11debbf4f5d3b6a9"/>
408
+ <file name="MemoryDataCollector.php" hash="6b9df2616c98fb717fe987650b05e839"/>
409
+ <file name="ModelDataCollector.php" hash="1942b69c4b7e205e85a03f400f25e357"/>
410
+ <file name="MysqlDataCollector.php" hash="6b22fb7c698632f38516ae67f5e72e3e"/>
411
+ <file name="RequestDataCollector.php" hash="2a7c8fcea477da650c6fde974fdddd54"/>
412
+ <file name="RewriteDataCollector.php" hash="94c7822840a6a8e56662df45c3c05a13"/>
413
+ <file name="TimeDataCollector.php" hash="9ba56d95b0cdf1b736ec09c101bcc17a"/>
414
+ <file name="TranslationDataCollector.php" hash="f2dbb421aded73ecad1d28288c0852f2"/>
415
+ </dir>
416
+ <dir name="Core">
417
+ <file name="Cache.php" hash="4d5153b5ef8d3f32b01a20b6f33a694c"/>
418
+ <file name="Config.php" hash="57785aff3f8db11bbbea1f29b6c30ad3"/>
419
+ </dir>
420
+ <dir name="Http">
421
+ <file name="HeaderBag.php" hash="271c1a70189c1be4c2016274528df777"/>
422
+ <file name="ParameterBag.php" hash="07feaabf7c5c355c330624f94d3a4073"/>
423
+ <file name="ResponseHeaderBag.php" hash="d27b8d35c3a4fc7ff050f5971ffea835"/>
424
+ </dir>
425
+ <dir name="Logger">
426
+ <file name="DebugHandler.php" hash="2e64a8afb1f054668992ab9026155988"/>
427
+ </dir>
428
+ <dir name="Observer">
429
+ <file name="Context.php" hash="46486a8e8d854dc8c022addae27eb713"/>
430
+ </dir>
431
+ <dir name="Profiler">
432
+ <file name="FileStorage.php" hash="0f7b9b499d7d0ef070db55d00608d086"/>
433
+ <file name="StorageInterface.php" hash="fe90e695474f4354bd6481d904c6c56c"/>
434
+ </dir>
435
+ </dir>
436
+ <dir name="overwrite">
437
+ <file name="Mage.php" hash="6141bb3e6e7e307d37e4bc9d92a409da"/>
438
+ <file name="MageCoreModelResource.php" hash="f800cbedca91b1ffbd522b7e2e9262ca"/>
439
+ <file name="MageCoreModelResourceDbAbstract.php" hash="1cac148b8666cf267f8d3cfeca80a114"/>
440
+ <file name="MageCoreModelStore.php" hash="8b254445c375ecba32f02eb67566b759"/>
441
+ <file name="MageCoreModelTranslate.php" hash="981b052d60c99afbfce2499d624438de"/>
442
+ <file name="MageEavModelEntityAbstract.php" hash="2f8f6ed49f554d0eb68a6ccf83464a5b"/>
443
+ </dir>
444
+ </dir>
445
+ </dir>
446
+ </target>
447
+ </contents>
448
+ </root>