Oink - Version 3.0.1

Version Notes

Bug fixes

Download this release

Release Info

Developer Dane De Forest
Extension Oink
Version 3.0.1
Comparing to
See all releases


Version 3.0.1

Files changed (162) hide show
  1. app/code/community/EcomDev/PHPUnit/Controller/Front.php +52 -0
  2. app/code/community/EcomDev/PHPUnit/Controller/Request/Http.php +378 -0
  3. app/code/community/EcomDev/PHPUnit/Controller/Response/Http.php +227 -0
  4. app/code/community/EcomDev/PHPUnit/Model/App.php +554 -0
  5. app/code/community/EcomDev/PHPUnit/Model/App/Area.php +85 -0
  6. app/code/community/EcomDev/PHPUnit/Model/Config.php +302 -0
  7. app/code/community/EcomDev/PHPUnit/Model/Design/Package.php +75 -0
  8. app/code/community/EcomDev/PHPUnit/Model/Expectation.php +160 -0
  9. app/code/community/EcomDev/PHPUnit/Model/Expectation/Interface.php +44 -0
  10. app/code/community/EcomDev/PHPUnit/Model/Expectation/Object.php +128 -0
  11. app/code/community/EcomDev/PHPUnit/Model/Fixture.php +495 -0
  12. app/code/community/EcomDev/PHPUnit/Model/Fixture/Interface.php +35 -0
  13. app/code/community/EcomDev/PHPUnit/Model/Layout.php +494 -0
  14. app/code/community/EcomDev/PHPUnit/Model/Mysql4/Fixture.php +120 -0
  15. app/code/community/EcomDev/PHPUnit/Model/Mysql4/Fixture/Eav/Abstract.php +344 -0
  16. app/code/community/EcomDev/PHPUnit/Model/Mysql4/Fixture/Eav/Catalog/Abstract.php +141 -0
  17. app/code/community/EcomDev/PHPUnit/Model/Mysql4/Fixture/Eav/Catalog/Category.php +67 -0
  18. app/code/community/EcomDev/PHPUnit/Model/Mysql4/Fixture/Eav/Catalog/Product.php +210 -0
  19. app/code/community/EcomDev/PHPUnit/Model/Mysql4/Fixture/Eav/Default.php +27 -0
  20. app/code/community/EcomDev/PHPUnit/Model/Mysql4/Fixture/Exception.php +9 -0
  21. app/code/community/EcomDev/PHPUnit/Model/Test/Loadable/Interface.php +46 -0
  22. app/code/community/EcomDev/PHPUnit/Test/Case.php +804 -0
  23. app/code/community/EcomDev/PHPUnit/Test/Case/Config.php +916 -0
  24. app/code/community/EcomDev/PHPUnit/Test/Case/Controller.php +1985 -0
  25. app/code/community/EcomDev/PHPUnit/Test/Suite.php +177 -0
  26. app/code/community/EcomDev/PHPUnit/Test/Suite/Group.php +84 -0
  27. app/code/community/EcomDev/PHPUnit/etc/config.xml +125 -0
  28. app/code/local/Oink/MatrixrateIntegration/Model/Observer.php +40 -0
  29. app/code/local/Oink/MatrixrateIntegration/etc/config.xml +47 -0
  30. app/code/local/Oink/Oink/Block/Adminhtml/Sales/Order/View/Tab/Oink.php +37 -0
  31. app/code/local/Oink/Oink/Block/Adminhtml/System/Config/TestConnection.php +11 -0
  32. app/code/local/Oink/Oink/Block/Adminhtml/System/Config/TestConnection/Html.php +16 -0
  33. app/code/local/Oink/Oink/Block/Adminhtml/System/Config/Version.php +12 -0
  34. app/code/local/Oink/Oink/Block/Checkout/Button.php +71 -0
  35. app/code/local/Oink/Oink/Block/Checkout/ParentConfirm.php +17 -0
  36. app/code/local/Oink/Oink/Block/Checkout/ParentConfirm/CSelect.php +15 -0
  37. app/code/local/Oink/Oink/Block/Checkout/ParentConfirm/Payment.php +23 -0
  38. app/code/local/Oink/Oink/Block/Checkout/Review.php +18 -0
  39. app/code/local/Oink/Oink/Block/Checkout/Review/Info.php +34 -0
  40. app/code/local/Oink/Oink/Block/Payment/Form/Oink.php +17 -0
  41. app/code/local/Oink/Oink/Block/Payment/Info/Oink.php +25 -0
  42. app/code/local/Oink/Oink/Block/Rewrite/Checkout/Onepage/Login.php +21 -0
  43. app/code/local/Oink/Oink/Helper/Checkout.php +528 -0
  44. app/code/local/Oink/Oink/Helper/Data.php +238 -0
  45. app/code/local/Oink/Oink/Helper/LibLoader.php +47 -0
  46. app/code/local/Oink/Oink/Model/Admin/Checkout.php +12 -0
  47. app/code/local/Oink/Oink/Model/Admin/Enablestatus.php +13 -0
  48. app/code/local/Oink/Oink/Model/ErrorHandler.php +35 -0
  49. app/code/local/Oink/Oink/Model/Mysql4/Order.php +30 -0
  50. app/code/local/Oink/Oink/Model/Mysql4/Order/Collection.php +22 -0
  51. app/code/local/Oink/Oink/Model/Observer.php +79 -0
  52. app/code/local/Oink/Oink/Model/Order.php +39 -0
  53. app/code/local/Oink/Oink/Model/Payment/Method/Oink.php +164 -0
  54. app/code/local/Oink/Oink/Model/Sales/Order.php +26 -0
  55. app/code/local/Oink/Oink/Model/Sales/Order/Payment.php +92 -0
  56. app/code/local/Oink/Oink/Model/System/Config/Source/Shipping/Carriers.php +80 -0
  57. app/code/local/Oink/Oink/Model/User.php +141 -0
  58. app/code/local/Oink/Oink/Model/User/Children.php +48 -0
  59. app/code/local/Oink/Oink/Model/User/Parent.php +113 -0
  60. app/code/local/Oink/Oink/Test/Controller2/CheckoutController.php +45 -0
  61. app/code/local/Oink/Oink/Test/Controller2/CheckoutController/providers/badLogin.yaml +3 -0
  62. app/code/local/Oink/Oink/Test/Controller2/CheckoutController/providers/goodLogin.yaml +3 -0
  63. app/code/local/Oink/Oink/Test/Helper/Data.php +111 -0
  64. app/code/local/Oink/Oink/Test/Helper/Data/fixtures/processTransaction.yaml +38 -0
  65. app/code/local/Oink/Oink/Test/Helper/Data/providers/badLogin.yaml +3 -0
  66. app/code/local/Oink/Oink/Test/Helper/Data/providers/badLoginMultipleTimes.yaml +3 -0
  67. app/code/local/Oink/Oink/Test/Helper/Data/providers/getChildProfiles.yaml +3 -0
  68. app/code/local/Oink/Oink/Test/Helper/Data/providers/getUserAddress.yaml +3 -0
  69. app/code/local/Oink/Oink/Test/Helper/Data/providers/goodLogin.yaml +3 -0
  70. app/code/local/Oink/Oink/Test/Helper/Data/providers/processTransaction.yaml +3 -0
  71. app/code/local/Oink/Oink/controllers/Adminhtml/OinkController.php +27 -0
  72. app/code/local/Oink/Oink/controllers/CheckoutController.php +328 -0
  73. app/code/local/Oink/Oink/etc/adminhtml.xml +4 -0
  74. app/code/local/Oink/Oink/etc/config.xml +210 -0
  75. app/code/local/Oink/Oink/etc/system.xml +328 -0
  76. app/code/local/Oink/Oink/sql/oink_setup/mysql4-install-1.0.0.0.php +24 -0
  77. app/code/local/Oink/Oink/sql/oink_setup/mysql4-upgrade-1.0.0.0-1.0.0.1.php +20 -0
  78. app/code/local/Oink/Oink/sql/oink_setup/mysql5-install-1.0.0.0.php +24 -0
  79. app/code/local/Oink/Oink/sql/oink_setup/mysql5-upgrade-1.0.0.0-1.0.0.1.php +20 -0
  80. app/design/adminhtml/base/default/layout/oink.xml +12 -0
  81. app/design/adminhtml/base/default/template/oink/payment/form/oink.phtml +19 -0
  82. app/design/adminhtml/base/default/template/oink/payment/info/oink.phtml +2 -0
  83. app/design/adminhtml/base/default/template/oink/sales/order/view/tab/oink.phtml +37 -0
  84. app/design/adminhtml/base/default/template/oink/system/config/testConnection.phtml +34 -0
  85. app/design/frontend/base/default/layout/oink.xml +54 -0
  86. app/design/frontend/base/default/template/oink/checkout/button.phtml +70 -0
  87. app/design/frontend/base/default/template/oink/checkout/button/form.phtml +207 -0
  88. app/design/frontend/base/default/template/oink/checkout/cart/button.phtml +5 -0
  89. app/design/frontend/base/default/template/oink/checkout/parent_confirm.phtml +44 -0
  90. app/design/frontend/base/default/template/oink/checkout/parent_confirm/c_select.phtml +45 -0
  91. app/design/frontend/base/default/template/oink/checkout/parent_confirm/payment.phtml +33 -0
  92. app/design/frontend/base/default/template/oink/checkout/review.phtml +29 -0
  93. app/design/frontend/base/default/template/oink/checkout/review/button.phtml +2 -0
  94. app/design/frontend/base/default/template/oink/checkout/review/info.phtml +58 -0
  95. app/design/frontend/base/default/template/oink/payment/form/oink.phtml +19 -0
  96. app/design/frontend/base/default/template/oink/payment/info/oink.phtml +13 -0
  97. app/etc/local.xml.phpunit +25 -0
  98. app/etc/modules/EcomDev_PHPUnit.xml +27 -0
  99. app/etc/modules/Oink_MatrixrateIntegration.xml +13 -0
  100. app/etc/modules/Oink_Oink.xml +9 -0
  101. app/locale/en_US/Oink_Oink.csv +29 -0
  102. lib/EcomDev/PHPUnit/Constraint/Abstract.php +217 -0
  103. lib/EcomDev/PHPUnit/Constraint/Config.php +111 -0
  104. lib/EcomDev/PHPUnit/Constraint/Config/Abstract.php +110 -0
  105. lib/EcomDev/PHPUnit/Constraint/Config/ClassAlias.php +140 -0
  106. lib/EcomDev/PHPUnit/Constraint/Config/EventObserver.php +178 -0
  107. lib/EcomDev/PHPUnit/Constraint/Config/Interface.php +26 -0
  108. lib/EcomDev/PHPUnit/Constraint/Config/Layout.php +192 -0
  109. lib/EcomDev/PHPUnit/Constraint/Config/Module.php +228 -0
  110. lib/EcomDev/PHPUnit/Constraint/Config/Node.php +306 -0
  111. lib/EcomDev/PHPUnit/Constraint/Config/Resource.php +236 -0
  112. lib/EcomDev/PHPUnit/Constraint/Config/Resource/Script.php +365 -0
  113. lib/EcomDev/PHPUnit/Constraint/Config/TableAlias.php +105 -0
  114. lib/EcomDev/PHPUnit/Constraint/Controller/Request.php +308 -0
  115. lib/EcomDev/PHPUnit/Constraint/Controller/Response/Abstract.php +38 -0
  116. lib/EcomDev/PHPUnit/Constraint/Controller/Response/Body.php +64 -0
  117. lib/EcomDev/PHPUnit/Constraint/Controller/Response/Header.php +100 -0
  118. lib/EcomDev/PHPUnit/Constraint/Exception.php +48 -0
  119. lib/EcomDev/PHPUnit/Constraint/Json.php +174 -0
  120. lib/EcomDev/PHPUnit/Constraint/Layout.php +84 -0
  121. lib/EcomDev/PHPUnit/Constraint/Layout/Abstract.php +55 -0
  122. lib/EcomDev/PHPUnit/Constraint/Layout/Block.php +308 -0
  123. lib/EcomDev/PHPUnit/Constraint/Layout/Block/Action.php +202 -0
  124. lib/EcomDev/PHPUnit/Constraint/Layout/Block/Property.php +121 -0
  125. lib/EcomDev/PHPUnit/Constraint/Layout/Handle.php +201 -0
  126. lib/EcomDev/PHPUnit/Constraint/Layout/Logger/Interface.php +119 -0
  127. lib/EcomDev/PHPUnit/Controller/Request/Interface.php +66 -0
  128. lib/EcomDev/PHPUnit/Controller/Response/Interface.php +55 -0
  129. lib/EcomDev/PHPUnit/Design/Package/Interface.php +37 -0
  130. lib/EcomDev/PHPUnit/Isolation/Interface.php +33 -0
  131. lib/EcomDev/Utils/Reflection.php +124 -0
  132. lib/Oink/Data/dtos.php +634 -0
  133. lib/Oink/Schemas/cart.xml +17 -0
  134. lib/Oink/Schemas/cart_02.xml +38 -0
  135. lib/Oink/Schemas/cart_03.xml +26 -0
  136. lib/Oink/Schemas/cart_04.xml +15 -0
  137. lib/Oink/Schemas/oink.xsd +70 -0
  138. lib/Oink/Services/Implementations/FormPaymentServiceConfiguration.php +14 -0
  139. lib/Oink/Services/Implementations/MagentoPaymentServiceConfiguration.php +13 -0
  140. lib/Oink/Services/Implementations/MerchantFormServiceConfiguration.php +53 -0
  141. lib/Oink/Services/Implementations/MerchantPaymentServiceConfiguration.php +28 -0
  142. lib/Oink/Services/Implementations/MockCartService.php +78 -0
  143. lib/Oink/Services/Implementations/OinkCallbackService.php +75 -0
  144. lib/Oink/Services/Implementations/OinkException.php +9 -0
  145. lib/Oink/Services/Implementations/OinkFormService.php +61 -0
  146. lib/Oink/Services/Implementations/OinkLoggingService.php +18 -0
  147. lib/Oink/Services/Implementations/OinkParentService.php +70 -0
  148. lib/Oink/Services/Implementations/OinkPaymentService.php +585 -0
  149. lib/Oink/Services/Implementations/OinkSoapClient.php +320 -0
  150. lib/Oink/Services/Implementations/XmlSerializationService.php +56 -0
  151. lib/Oink/Services/Implementations/XmlToArray.php +72 -0
  152. lib/Oink/Services/Interfaces/ICallbackService.php +17 -0
  153. lib/Oink/Services/Interfaces/ICartService.php +10 -0
  154. lib/Oink/Services/Interfaces/IFormService.php +17 -0
  155. lib/Oink/Services/Interfaces/IFormServiceConfiguration.php +11 -0
  156. lib/Oink/Services/Interfaces/ILoggingService.php +17 -0
  157. lib/Oink/Services/Interfaces/IParentService.php +10 -0
  158. lib/Oink/Services/Interfaces/IPaymentService.php +69 -0
  159. lib/Oink/Services/Interfaces/IPaymentServiceConfiguration.php +9 -0
  160. lib/Oink/Services/Interfaces/ISerializationService.php +12 -0
  161. lib/Spyc/spyc.php +1024 -0
  162. package.xml +18 -0
app/code/community/EcomDev/PHPUnit/Controller/Front.php ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PHP Unit test suite for Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ *
12
+ * @category EcomDev
13
+ * @package EcomDev_PHPUnit
14
+ * @copyright Copyright (c) 2011 Ecommerce Developers (http://www.ecomdev.org)
15
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
+ * @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
17
+ */
18
+
19
+ /**
20
+ * Front controller for test suite
21
+ *
22
+ */
23
+ class EcomDev_PHPUnit_Controller_Front extends Mage_Core_Controller_Varien_Front
24
+ {
25
+ /**
26
+ * Overriden for getting rid of unusual behavior in the test case,
27
+ * because test should be isolated
28
+ *
29
+ * (non-PHPdoc)
30
+ * @see Mage_Core_Controller_Varien_Front::_checkBaseUrl()
31
+ */
32
+ protected function _checkBaseUrl()
33
+ {
34
+ // Does nothing
35
+ }
36
+
37
+ /**
38
+ * Overriden for getting rid
39
+ * of initialization of routers for each test case
40
+ *
41
+ * (non-PHPdoc)
42
+ * @see Mage_Core_Controller_Varien_Front::init()
43
+ */
44
+ public function init()
45
+ {
46
+ if (!$this->_routers) {
47
+ parent::init();
48
+ }
49
+
50
+ return $this;
51
+ }
52
+ }
app/code/community/EcomDev/PHPUnit/Controller/Request/Http.php ADDED
@@ -0,0 +1,378 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PHP Unit test suite for Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ *
12
+ * @category EcomDev
13
+ * @package EcomDev_PHPUnit
14
+ * @copyright Copyright (c) 2011 Ecommerce Developers (http://www.ecomdev.org)
15
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
+ * @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
17
+ */
18
+
19
+ /**
20
+ * Request class for usage in the controller test cases
21
+ *
22
+ * By default set for test app instance,
23
+ * you can change to your class,
24
+ * but you should extend it from this one
25
+ *
26
+ */
27
+ class EcomDev_PHPUnit_Controller_Request_Http
28
+ extends Mage_Core_Controller_Request_Http
29
+ implements EcomDev_PHPUnit_Isolation_Interface,
30
+ EcomDev_PHPUnit_Controller_Request_Interface
31
+ {
32
+ /**
33
+ * List of $_SERVER variable changes
34
+ * that were done by test case
35
+ *
36
+ * @var array
37
+ */
38
+ protected $_originalServerValues = array();
39
+
40
+ /**
41
+ * List of headers that were set for test case
42
+ *
43
+ * @return array
44
+ */
45
+ protected $_headers = array();
46
+
47
+ /**
48
+ * Initializes forward data
49
+ *
50
+ * (non-PHPdoc)
51
+ * @see Mage_Core_Controller_Request_Http::initForward()
52
+ */
53
+ public function initForward()
54
+ {
55
+ if (empty($this->_beforeForwardInfo)) {
56
+ parent::initForward();
57
+ $this->_beforeForwardInfo['route_name'] = $this->getRouteName();
58
+ return $this;
59
+ }
60
+
61
+ return parent::initForward();
62
+ }
63
+
64
+ /**
65
+ * Returns only request uri that was set before
66
+ * (non-PHPdoc)
67
+ * @see Zend_Controller_Request_Http::getRequestUri()
68
+ */
69
+ public function getRequestUri()
70
+ {
71
+ return $this->_requestUri;
72
+ }
73
+
74
+ /**
75
+ * Sets cookie value for test,
76
+ *
77
+ * @param string|array $name
78
+ * @param string|null $value
79
+ * @return EcomDev_PHPUnit_Controller_Request_Http_Test
80
+ */
81
+ public function setCookie($name, $value)
82
+ {
83
+ $_COOKIE[$name] = $value;
84
+ return $this;
85
+ }
86
+
87
+ /**
88
+ * Sets more than one cookie
89
+ *
90
+ * @param array $cookies
91
+ * @return EcomDev_PHPUnit_Controller_Request_Http_Test
92
+ */
93
+ public function setCookies(array $cookies)
94
+ {
95
+ $_COOKIE += $cookies;
96
+ return $this;
97
+ }
98
+
99
+ /**
100
+ * Resets all cookies for the test request
101
+ *
102
+ * @return EcomDev_PHPUnit_Controller_Request_Http_Test
103
+ */
104
+ public function resetCookies()
105
+ {
106
+ $_COOKIE = array();
107
+ return $this;
108
+ }
109
+
110
+ /**
111
+ * Resets query for the current request
112
+ *
113
+ * @return EcomDev_PHPUnit_Controller_Request_Http_Test
114
+ */
115
+ public function resetQuery()
116
+ {
117
+ $_GET = array();
118
+ return $this;
119
+ }
120
+
121
+ /**
122
+ * Resets $_POST superglobal for test request
123
+ *
124
+ * @return EcomDev_PHPUnit_Controller_Request_Http_Test
125
+ */
126
+ public function resetPost()
127
+ {
128
+ $_POST = array();
129
+ return $this;
130
+ }
131
+
132
+ /**
133
+ * Resets user defined request params for test request
134
+ *
135
+ * @return EcomDev_PHPUnit_Controller_Request_Http_Test
136
+ */
137
+ public function resetParams()
138
+ {
139
+ $this->_params = array();
140
+ return $this;
141
+ }
142
+
143
+ /**
144
+ * Resets internal properties to its default values
145
+ *
146
+ * @return EcomDev_PHPUnit_Controller_Request_Http_Test
147
+ */
148
+ public function resetInternalProperties()
149
+ {
150
+ // From abstract request
151
+ $this->_dispatched = false;
152
+ $this->_module = null;
153
+ $this->_moduleKey = 'module';
154
+ $this->_controller = null;
155
+ $this->_controllerKey = 'controller';
156
+ $this->_action = null;
157
+ $this->_actionKey = 'action';
158
+
159
+ // From Http request
160
+ $this->_paramSources = array('_GET', '_POST');
161
+ $this->_requestUri = null;
162
+ $this->_baseUrl = null;
163
+ $this->_basePath = null;
164
+ $this->_pathInfo = '';
165
+ $this->_rawBody = null;
166
+ $this->_aliases = array();
167
+
168
+ // From Magento Http request
169
+ $this->_originalPathInfo = '';
170
+ $this->_storeCode = null;
171
+ $this->_requestString = '';
172
+ $this->_rewritedPathInfo = null;
173
+ $this->_requestedRouteName = null;
174
+ $this->_routingInfo = array();
175
+ $this->_route = null;
176
+ $this->_directFrontNames = null;
177
+ $this->_controllerModule = null;
178
+ return $this;
179
+ }
180
+
181
+ /**
182
+ * Set custom http header
183
+ *
184
+ * @param string $name
185
+ * @param string $value
186
+ * @return EcomDev_PHPUnit_Controller_Request_Http_Test
187
+ */
188
+ public function setHeader($name, $value)
189
+ {
190
+ $name = $this->headerName($name);
191
+ $this->_headers[$name] = $value;
192
+ // Additionally set $_SERVER http header value
193
+ $this->setServer('HTTP_' . $name, $value);
194
+ return $this;
195
+ }
196
+
197
+ /**
198
+ * Sets more than one header,
199
+ * headers list is an associative array
200
+ *
201
+ * @param array $headers
202
+ * @return EcomDev_PHPUnit_Controller_Request_Http_Test
203
+ */
204
+ public function setHeaders(array $headers)
205
+ {
206
+ foreach ($headers as $name => $value) {
207
+ $this->setHeader($name, $value);
208
+ }
209
+
210
+ return $this;
211
+ }
212
+
213
+ /**
214
+ * Returns header from test request parameters
215
+ *
216
+ * (non-PHPdoc)
217
+ * @see Zend_Controller_Request_Http::getHeader()
218
+ */
219
+ public function getHeader($header)
220
+ {
221
+ $name = $this->headerName($header);
222
+ if (isset($this->_headers[$name])) {
223
+ return $this->_headers[$name];
224
+ }
225
+
226
+ return false;
227
+ }
228
+
229
+ /**
230
+ * Resets headers in test request
231
+ *
232
+ * @return EcomDev_PHPUnit_Controller_Request_Http_Test
233
+ */
234
+ public function resetHeaders()
235
+ {
236
+ $this->_headers = array();
237
+ return $this;
238
+ }
239
+
240
+ /**
241
+ * Returns unified header name for internal storage
242
+ *
243
+ * @param string $name
244
+ * @return string
245
+ */
246
+ protected function headerName($name)
247
+ {
248
+ return strtr(strtoupper($name), '-', '_');
249
+ }
250
+
251
+ /**
252
+ * Sets value for a particular $_SERVER superglobal array key for test request
253
+ *
254
+ * Saves original value for returning it back
255
+ *
256
+ * @param string $name
257
+ * @param string $value
258
+ * @return EcomDev_PHPUnit_Controller_Request_Http_Test
259
+ */
260
+ public function setServer($name, $value)
261
+ {
262
+ if (!isset($this->_originalServerValues[$name])) {
263
+ $originalValue = (isset($_SERVER[$name]) ? $_SERVER[$name] : null);
264
+ $this->_originalServerValues[$name] = $originalValue;
265
+ }
266
+
267
+ $_SERVER[$name] = $value;
268
+ return $this;
269
+ }
270
+
271
+ /**
272
+ * Sets multiple values for $_SERVER superglobal in test request
273
+ *
274
+ * @param array $values
275
+ * @return EcomDev_PHPUnit_Controller_Request_Http_Test
276
+ */
277
+ public function setServers(array $values)
278
+ {
279
+ foreach ($values as $name => $value) {
280
+ $this->setServer($name, $value);
281
+ }
282
+ return $this;
283
+ }
284
+
285
+ /**
286
+ * Resets $_SERVER superglobal to previous state
287
+ *
288
+ * @return EcomDev_PHPUnit_Controller_Request_Http_Test
289
+ */
290
+ public function resetServer()
291
+ {
292
+ foreach ($this->_originalServerValues as $name => $value) {
293
+ if ($value !== null) {
294
+ $_SERVER[$name] = $value;
295
+ } elseif (isset($_SERVER[$name])) {
296
+ // If original value was not set,
297
+ // then unsetting the changed value
298
+ unset($_SERVER[$name]);
299
+ }
300
+ }
301
+
302
+ $this->_originalServerValues = array();
303
+ return $this;
304
+ }
305
+
306
+ /**
307
+ * Sets request method for test request
308
+ *
309
+ * @param string $requestMethod
310
+ * @return EcomDev_PHPUnit_Controller_Request_Http_Test
311
+ */
312
+ public function setMethod($requestMethod)
313
+ {
314
+ $this->setServer('REQUEST_METHOD', $requestMethod);
315
+ return $this;
316
+ }
317
+
318
+ /**
319
+ * Sets current request scheme for test request,
320
+ * accepts boolean flag for HTTPS
321
+ *
322
+ * @param boolean $flag
323
+ * @return EcomDev_PHPUnit_Controller_Request_Http_Test
324
+ */
325
+ public function setIsSecure($flag = true)
326
+ {
327
+ $this->setServer('HTTPS', $flag ? 'on' : null);
328
+ return $this;
329
+ }
330
+
331
+ /**
332
+ * Returns HTTP host from base url that were set in the controller
333
+ *
334
+ * (non-PHPdoc)
335
+ * @see Mage_Core_Controller_Request_Http::getHttpHost()
336
+ */
337
+ public function getHttpHost($trimPort = false)
338
+ {
339
+ $baseUrl = $this->getBaseUrl();
340
+
341
+ $parts = parse_url($baseUrl);
342
+ $httpHost = $parts['host'];
343
+ if (!$trimPort && isset($parts['port'])) {
344
+ $httpHost .= ':' . $parts['port'];
345
+ }
346
+
347
+ return $httpHost;
348
+ }
349
+
350
+ /**
351
+ * Returns only base url that was set before
352
+ *
353
+ * (non-PHPdoc)
354
+ * @see Mage_Core_Controller_Request_Http::getBaseUrl()
355
+ */
356
+ public function getBaseUrl()
357
+ {
358
+ return $this->_baseUrl;
359
+ }
360
+
361
+ /**
362
+ * Resets all request data for test
363
+ *
364
+ * @return EcomDev_PHPUnit_Controller_Request_Http_Test
365
+ */
366
+ public function reset()
367
+ {
368
+ $this->resetInternalProperties()
369
+ ->resetHeaders()
370
+ ->resetParams()
371
+ ->resetPost()
372
+ ->resetQuery()
373
+ ->resetCookies()
374
+ ->resetServer();
375
+
376
+ return $this;
377
+ }
378
+ }
app/code/community/EcomDev/PHPUnit/Controller/Response/Http.php ADDED
@@ -0,0 +1,227 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PHP Unit test suite for Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ *
12
+ * @category EcomDev
13
+ * @package EcomDev_PHPUnit
14
+ * @copyright Copyright (c) 2011 Ecommerce Developers (http://www.ecomdev.org)
15
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
+ * @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
17
+ */
18
+
19
+ /**
20
+ * Response class for usage in the controller test cases
21
+ *
22
+ * By default set for test app instance,
23
+ * you can change to your class,
24
+ * but you should extend it from this one
25
+ *
26
+ */
27
+ class EcomDev_PHPUnit_Controller_Response_Http
28
+ extends Mage_Core_Controller_Response_Http
29
+ implements EcomDev_PHPUnit_Isolation_Interface,
30
+ EcomDev_PHPUnit_Controller_Response_Interface
31
+ {
32
+ const LINE_ENDING = "\r\n";
33
+
34
+ /**
35
+ * Headers that was sent via sendHeaders() method
36
+ *
37
+ * @var array
38
+ */
39
+ protected $_sentHeaders = null;
40
+
41
+ /**
42
+ * Response that was sent via sendRespose()
43
+ * or sendHeaders() or outputBody() methods
44
+ *
45
+ * @var string
46
+ */
47
+ protected $_sentResponse = null;
48
+
49
+ /**
50
+ * Response body that was sent via outputBody()
51
+ * method
52
+ *
53
+ * @var string
54
+ */
55
+ protected $_outputBody = null;
56
+
57
+ /**
58
+ * Resets response object
59
+ *
60
+ * @return EcomDev_PHPUnit_Controller_Response_Http_Test
61
+ */
62
+ public function reset()
63
+ {
64
+ $this->_sentHeaders = null;
65
+ $this->_sentResponse = null;
66
+ $this->_outputBody = null;
67
+ $this->_body = array();
68
+ $this->_exceptions = array();
69
+ $this->_headers = array();
70
+ $this->_headersRaw = array();
71
+ $this->_httpResponseCode = 200;
72
+ $this->_isRedirect = false;
73
+ $this->_renderExceptions = false;
74
+
75
+ $this->headersSentThrowsException = Mage::$headersSentThrowsException;
76
+ $this->setHeader('Content-Type', 'text/html; charset=UTF-8');
77
+ return $this;
78
+ }
79
+
80
+ /**
81
+ * Implementation of sending the headers to output
82
+ *
83
+ * (non-PHPdoc)
84
+ * @see Mage_Core_Controller_Response_Http::sendHeaders()
85
+ */
86
+ public function sendHeaders()
87
+ {
88
+ $this->canSendHeaders(true);
89
+ $this->_sentHeaders= array();
90
+
91
+ $this->_sentHeaders[null] = 'HTTP/1.1 ' . $this->_httpResponseCode;
92
+
93
+ foreach ($this->_headersRaw as $headerRaw) {
94
+ list($headerName, $headerValue) = explode(':', $headerRaw, 2);
95
+ $headerName = $this->_normalizeHeader($headerName);
96
+ if (isset($this->_sentHeaders[$headerName])) {
97
+ // Merge headers, if already any was sent with the same name
98
+ // Set-Cookie header is usually not sent via response
99
+ // so it should be ok.
100
+ $this->_sentHeaders[$headerName] .= '; ' . $headerValue;
101
+ } else {
102
+ $this->_sentHeaders[$headerName] = $headerValue;
103
+ }
104
+ }
105
+
106
+ foreach ($this->_headers as $header) {
107
+ if (isset($this->_sentHeaders[$header['name']])) {
108
+ $this->_sentHeaders[$header['name']] .= '; ' . $header['value'];
109
+ } else {
110
+ $this->_sentHeaders[$header['name']] = $header['value'];
111
+ }
112
+ }
113
+
114
+ $this->_sentResponse = '';
115
+
116
+ foreach ($this->_sentHeaders as $headerName => $headerValue) {
117
+ $headerString = '';
118
+ if ($headerName === null) {
119
+ $headerString .= $headerName . ': ';
120
+ }
121
+ $headerString .= $headerValue . self::LINE_ENDING;
122
+ $this->_sentResponse .= $headerString;
123
+ }
124
+
125
+ $this->_sentResponse .= self::LINE_ENDING;
126
+ }
127
+
128
+ /**
129
+ * Returns rendered headers array that was sent,
130
+ * if headers was not sent, then returns null
131
+ *
132
+ * @return array|null
133
+ */
134
+ public function getSentHeaders()
135
+ {
136
+ return $this->_sentHeaders;
137
+ }
138
+
139
+ /**
140
+ * Returns a particular header that was sent
141
+ *
142
+ * @param string $headerName
143
+ * @return string|false
144
+ */
145
+ public function getSentHeader($headerName)
146
+ {
147
+ $headerName = $this->_normalizeHeader($headerName);
148
+
149
+ if (isset($this->_sentHeaders[$headerName])) {
150
+ return $this->_sentHeaders[$headerName];
151
+ }
152
+
153
+ return false;
154
+ }
155
+
156
+ /**
157
+ * Implementation of sending response for test case
158
+ * (non-PHPdoc)
159
+ * @see Mage_Core_Controller_Response_Http::sendResponse()
160
+ */
161
+ public function sendResponse()
162
+ {
163
+ //Mage::dispatchEvent('http_response_send_before', array('response'=>$this));
164
+ $this->sendHeaders();
165
+
166
+ if ($this->isException() && $this->renderExceptions()) {
167
+ $exceptions = '';
168
+ foreach ($this->getException() as $e) {
169
+ $exceptions .= (string)$e . "\n";
170
+ }
171
+
172
+ $this->_sentResponse .= $exceptions;
173
+ return;
174
+ }
175
+
176
+ $this->outputBody();
177
+ }
178
+
179
+ /**
180
+ * Returns rendered response, if response was not sent,
181
+ * then it returns null
182
+ *
183
+ * @return string|null
184
+ */
185
+ public function getSentResponse()
186
+ {
187
+ return $this->_sentResponse;
188
+ }
189
+
190
+ /**
191
+ * Implementation of outputting the body of response
192
+ *
193
+ * (non-PHPdoc)
194
+ * @see Zend_Controller_Response_Abstract::outputBody()
195
+ */
196
+ public function outputBody()
197
+ {
198
+ $this->_outputBody = implode('', $this->_body);
199
+ $this->_sentResponse .= $this->_outputBody;
200
+ }
201
+
202
+ /**
203
+ * Returns rendered body output
204
+ *
205
+ * @return string
206
+ */
207
+ public function getOutputBody()
208
+ {
209
+ return $this->_outputBody;
210
+ }
211
+
212
+ /**
213
+ * Can send headers implementation for test case
214
+ *
215
+ * (non-PHPdoc)
216
+ * @see Zend_Controller_Response_Abstract::canSendHeaders()
217
+ */
218
+ public function canSendHeaders($throw = false)
219
+ {
220
+ if ($this->_sentHeaders !== null && $throw && $this->headersSentThrowsException) {
221
+ #require_once 'Zend/Controller/Response/Exception.php';
222
+ throw new Zend_Controller_Response_Exception('Cannot send headers; headers already sent');
223
+ }
224
+
225
+ return $this->_sentHeaders === null;
226
+ }
227
+ }
app/code/community/EcomDev/PHPUnit/Model/App.php ADDED
@@ -0,0 +1,554 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PHP Unit test suite for Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ *
12
+ * @category EcomDev
13
+ * @package EcomDev_PHPUnit
14
+ * @copyright Copyright (c) 2011 Ecommerce Developers (http://www.ecomdev.org)
15
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
+ * @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
17
+ */
18
+
19
+ /**
20
+ * Application model for phpunit tests
21
+ *
22
+ */
23
+ class EcomDev_PHPUnit_Model_App extends Mage_Core_Model_App
24
+ {
25
+ // Run types constants,
26
+ // Don't know why
27
+ // they are not defined in core application
28
+ const RUN_TYPE_STORE = 'store';
29
+ const RUN_TYPE_WEBSITE = 'website';
30
+ const RUN_TYPE_GROUP = 'group';
31
+
32
+ // Admin store code
33
+ const ADMIN_STORE_CODE = 'admin';
34
+
35
+ const AREA_ADMINHTML = EcomDev_PHPUnit_Model_App_Area::AREA_ADMINHTML;
36
+ const AREA_ADMIN = EcomDev_PHPUnit_Model_App_Area::AREA_ADMIN;
37
+ const AREA_FRONTEND = EcomDev_PHPUnit_Model_App_Area::AREA_FRONTEND;
38
+ const AREA_GLOBAL = EcomDev_PHPUnit_Model_App_Area::AREA_GLOBAL;
39
+ const AREA_TEST = EcomDev_PHPUnit_Model_App_Area::AREA_TEST;
40
+
41
+ const AREA_PART_EVENTS = EcomDev_PHPUnit_Model_App_Area::PART_EVENTS;
42
+ const AREA_PART_DESIGN = EcomDev_PHPUnit_Model_App_Area::PART_DESIGN;
43
+ const AREA_PART_TRANSLATE = EcomDev_PHPUnit_Model_App_Area::PART_TRANSLATE;
44
+ const AREA_PART_CONFIG = EcomDev_PHPUnit_Model_App_Area::PART_CONFIG;
45
+
46
+ const INTERFACE_ISOLATION = 'EcomDev_PHPUnit_Isolation_Interface';
47
+
48
+ const REGISTRY_PATH_LAYOUT_SINGLETON = '_singleton/core/layout';
49
+ const REGISTRY_PATH_DESIGN_PACKAGE_SINGLETON = '_singleton/core/design_package';
50
+
51
+ const XML_PATH_LAYOUT_MODEL_FOR_TEST = 'phpunit/suite/layout/model';
52
+ const XML_PATH_DESIGN_PACKAGE_MODEL_FOR_TEST = 'phpunit/suite/design/package/model';
53
+
54
+ const XML_PATH_APP_AREA = 'phpunit/suite/app/area/class';
55
+ const XML_PATH_CONTROLLER_FRONT = 'phpunit/suite/controller/front/class';
56
+ const XML_PATH_CONTROLLER_REQUEST = 'phpunit/suite/controller/request/class';
57
+ const XML_PATH_CONTROLLER_RESPONSE = 'phpunit/suite/controller/response/class';
58
+
59
+ /**
60
+ * Old configuration model to be returned back
61
+ * after unit tests are finished
62
+ *
63
+ * @var Mage_Core_Model_Config
64
+ */
65
+ protected static $_oldConfig = null;
66
+
67
+ /**
68
+ * Old application model to be returned back
69
+ * after unit tests are finished
70
+ *
71
+ * @var Mage_Core_Model_App
72
+ */
73
+ protected static $_oldApplication = null;
74
+
75
+ /**
76
+ * Old event collection to be returned back
77
+ * after the unit tests are finished
78
+ *
79
+ * @var Varien_Event_Collection
80
+ */
81
+ protected static $_oldEventCollection = null;
82
+
83
+ /**
84
+ * List of singletons in original application
85
+ *
86
+ * @var array
87
+ */
88
+ protected static $_oldRegistry = null;
89
+
90
+ /**
91
+ * Configuration model class name for unit tests
92
+ *
93
+ * @var string
94
+ */
95
+ protected static $_configClass = 'EcomDev_PHPUnit_Model_Config';
96
+
97
+ /**
98
+ * Configuration model class name for unit tests
99
+ *
100
+ * @var string
101
+ */
102
+ protected static $_eventCollectionClass = 'Varien_Event_Collection';
103
+
104
+ /**
105
+ * List of areas that will be ignored in resetAreas() method
106
+ *
107
+ * @var array
108
+ */
109
+ protected $_resetIgnoreAreas = array(
110
+ self::AREA_GLOBAL,
111
+ self::AREA_TEST
112
+ );
113
+
114
+ /**
115
+ * Enabled events flag
116
+ *
117
+ * @var boolean
118
+ */
119
+ protected $_eventsEnabled = true;
120
+
121
+ /**
122
+ * Dispatched events array
123
+ *
124
+ * @var array
125
+ */
126
+ protected $_dispatchedEvents = array();
127
+
128
+ /**
129
+ * List of module names stored by class name
130
+ *
131
+ * @var array
132
+ */
133
+ protected $_moduleNameByClassName = array();
134
+
135
+ /**
136
+ * This method replaces application, event and config objects
137
+ * in Mage to perform unit tests in separate Magento steam
138
+ *
139
+ */
140
+ public static function applyTestScope()
141
+ {
142
+ // Save old environment variables
143
+ self::$_oldApplication = EcomDev_Utils_Reflection::getRestrictedPropertyValue('Mage', '_app');
144
+ self::$_oldConfig = EcomDev_Utils_Reflection::getRestrictedPropertyValue('Mage', '_config');
145
+ self::$_oldEventCollection = EcomDev_Utils_Reflection::getRestrictedPropertyValue('Mage', '_events');
146
+ self::$_oldRegistry = EcomDev_Utils_Reflection::getRestrictedPropertyValue('Mage', '_registry');
147
+
148
+
149
+ // Setting environment variables for unit tests
150
+ EcomDev_Utils_Reflection::setRestrictedPropertyValue('Mage', '_config', new self::$_configClass);
151
+ EcomDev_Utils_Reflection::setRestrictedPropertyValue('Mage', '_app', new self);
152
+ EcomDev_Utils_Reflection::setRestrictedPropertyValue('Mage', '_events', new self::$_eventCollectionClass);
153
+ EcomDev_Utils_Reflection::setRestrictedPropertyValue('Mage', '_registry', array());
154
+
155
+ // All unit tests will be runned in admin scope, to get rid of frontend restrictions
156
+ Mage::app()->initTest();
157
+ }
158
+
159
+ /**
160
+ * Initializes test scope for PHPUnit
161
+ *
162
+ * @return EcomDev_PHPUnit_Model_App
163
+ */
164
+ public function initTest()
165
+ {
166
+ if (version_compare(PHP_VERSION, '5.3.0', '>=')) {
167
+ // If garbage collector is not enabled,
168
+ // we enable it for tests
169
+ if (!gc_enabled()) {
170
+ gc_enable();
171
+ }
172
+ }
173
+
174
+ $this->_config = Mage::getConfig();
175
+ $this->_initBaseConfig();
176
+ $this->_initCache();
177
+
178
+ // Set using cache
179
+ // for things that shouldn't be reloaded each time
180
+ EcomDev_Utils_Reflection::setRestrictedPropertyValue(
181
+ $this->_cache,
182
+ '_allowedCacheOptions',
183
+ array(
184
+ 'eav' => 1,
185
+ 'layout' => 1,
186
+ 'translate' => 1
187
+ )
188
+ );
189
+
190
+ // Clean cache before the whole suite is running
191
+ $this->getCache()->clean();
192
+
193
+ // Init modules runs install proccess for table structures,
194
+ // It is required for setting up proper setup script
195
+ $this->_initModules();
196
+
197
+ $this->loadAreaPart(self::AREA_GLOBAL, self::AREA_PART_EVENTS);
198
+
199
+ if ($this->_config->isLocalConfigLoaded()) {
200
+ $this->_initCurrentStore(self::ADMIN_STORE_CODE, self::RUN_TYPE_STORE);
201
+ $this->_initRequest();
202
+ Mage_Core_Model_Resource_Setup::applyAllDataUpdates();
203
+ }
204
+
205
+ $layoutModel = $this->_getModelFromConfig(
206
+ self::XML_PATH_LAYOUT_MODEL_FOR_TEST,
207
+ self::INTERFACE_ISOLATION,
208
+ 'Layout model'
209
+ );
210
+
211
+ $this->replaceRegistry(self::REGISTRY_PATH_LAYOUT_SINGLETON,
212
+ $layoutModel);
213
+
214
+ $designPackageModel = $this->_getModelFromConfig(
215
+ self::XML_PATH_DESIGN_PACKAGE_MODEL_FOR_TEST,
216
+ self::INTERFACE_ISOLATION,
217
+ 'Design package model'
218
+ );
219
+
220
+ $this->replaceRegistry(self::REGISTRY_PATH_DESIGN_PACKAGE_SINGLETON,
221
+ $designPackageModel);
222
+
223
+ $this->loadAreaPart(self::AREA_TEST, self::AREA_PART_EVENTS);
224
+ return $this;
225
+ }
226
+
227
+ /**
228
+ * Retrieves a model from config and checks it on interface implementation
229
+ *
230
+ * @param string $configPath
231
+ * @param string $interface
232
+ * @param string $modelName
233
+ * @return Mage_Core_Model_Abstract
234
+ */
235
+ protected function _getModelFromConfig($configPath, $interface, $modelName = 'Model')
236
+ {
237
+ $model = Mage::getModel(
238
+ (string)$this->getConfig()->getNode($configPath)
239
+ );
240
+
241
+ if (!$model instanceof $interface) {
242
+ throw new RuntimeException(
243
+ sprintf('%s should implement %s to make possible running tests in isolation',
244
+ $modelName, $interface)
245
+ );
246
+ }
247
+
248
+ return $model;
249
+ }
250
+
251
+ /**
252
+ * Initialize front controller for test suite
253
+ *
254
+ * @return EcomDev_PHPUnit_Model_App
255
+ */
256
+ protected function _initFrontController()
257
+ {
258
+ $frontControllerClass = $this->_getClassNameFromConfig(self::XML_PATH_CONTROLLER_FRONT);
259
+ $this->_frontController = new $frontControllerClass();
260
+ Mage::register('controller', $this->_frontController);
261
+ $this->_frontController->init();
262
+ return $this;
263
+ }
264
+
265
+ /**
266
+ * Retrieve application area
267
+ *
268
+ * @param string $code
269
+ * @return EcomDev_PHPUnit_Model_App_Area
270
+ */
271
+ public function getArea($code)
272
+ {
273
+ if (!isset($this->_areas[$code])) {
274
+ $appAreaClass = $this->_getClassNameFromConfig(
275
+ self::XML_PATH_APP_AREA, self::INTERFACE_ISOLATION
276
+ );
277
+ $this->_areas[$code] = new $appAreaClass($code, $this);
278
+ }
279
+ return $this->_areas[$code];
280
+ }
281
+
282
+ /**
283
+ * Resets areas parts, like events, translations, design
284
+ *
285
+ * @return EcomDev_PHPUnit_Model_App
286
+ */
287
+ public function resetAreas()
288
+ {
289
+ /* @var $area EcomDev_PHPUnit_Model_App_Area */
290
+ foreach ($this->_areas as $code => $area) {
291
+ if (!in_array($code, $this->_resetIgnoreAreas)) {
292
+ $area->reset();
293
+ }
294
+ }
295
+ return $this;
296
+ }
297
+
298
+ /**
299
+ * Replace registry item value
300
+ *
301
+ * @param string $key
302
+ * @param string $value
303
+ */
304
+ public function replaceRegistry($key, $value)
305
+ {
306
+ $registry = EcomDev_Utils_Reflection::getRestrictedPropertyValue('Mage', '_registry');
307
+ $registry[$key] = $value;
308
+ EcomDev_Utils_Reflection::setRestrictedPropertyValue('Mage', '_registry', $registry);
309
+ return $this;
310
+ }
311
+
312
+ /**
313
+ * Removes event area
314
+ *
315
+ * @param string $code area code
316
+ * @return EcomDev_PHPUnit_Model_App
317
+ */
318
+ public function removeEventArea($code)
319
+ {
320
+ if (isset($this->_events[$code])) {
321
+ unset($this->_events[$code]);
322
+ }
323
+
324
+ return $this;
325
+ }
326
+
327
+ /**
328
+ * Returns request for test suite
329
+ * (non-PHPdoc)
330
+ * @see Mage_Core_Model_App::getRequest()
331
+ * @return EcomDev_PHPUnit_Controller_Request_Http
332
+ */
333
+ public function getRequest()
334
+ {
335
+ if ($this->_request === null) {
336
+ $requestClass = $this->_getClassNameFromConfig(
337
+ self::XML_PATH_CONTROLLER_REQUEST, self::INTERFACE_ISOLATION
338
+ );
339
+ $this->_request = new $requestClass;
340
+ }
341
+
342
+ return $this->_request;
343
+ }
344
+
345
+ /**
346
+ * Returns response for test suite
347
+ * (non-PHPdoc)
348
+ * @see Mage_Core_Model_App::getResponse()
349
+ * @return EcomDev_PHPUnit_Controller_Response_Http
350
+ */
351
+ public function getResponse()
352
+ {
353
+ if ($this->_response === null) {
354
+ $responseClass = $this->_getClassNameFromConfig(
355
+ self::XML_PATH_CONTROLLER_RESPONSE, self::INTERFACE_ISOLATION
356
+ );
357
+ $this->_response = new $responseClass;
358
+ }
359
+
360
+ return $this->_response;
361
+ }
362
+
363
+ /**
364
+ * Returns class name from configuration path,
365
+ * If $interface is specified, then it additionaly checks it for implementation
366
+ *
367
+ *
368
+ * @param string $configPath
369
+ * @param string $interface
370
+ * @return string
371
+ */
372
+ protected function _getClassNameFromConfig($configPath, $interface = null)
373
+ {
374
+ $className = (string)$this->getConfig()->getNode($configPath);
375
+
376
+ $reflection = EcomDev_Utils_Reflection::getRelflection($className);
377
+ if ($interface !== null && !$reflection->implementsInterface($interface)) {
378
+ throw new RuntimeException(
379
+ sprintf('Invalid class name defined in configuration path %s, because %s does not implement %s interface',
380
+ $configPath, $interface)
381
+ );
382
+ }
383
+ return $className;
384
+ }
385
+
386
+ /**
387
+ * Overriden to fix issue with stores loading
388
+ * (non-PHPdoc)
389
+ * @see Mage_Core_Model_App::_initStores()
390
+ */
391
+ protected function _initStores()
392
+ {
393
+ $this->_store = null;
394
+ parent::_initStores();
395
+ return $this;
396
+ }
397
+
398
+ /**
399
+ * Discard test scope for application, returns all the objects from live version
400
+ *
401
+ */
402
+ public static function discardTestScope()
403
+ {
404
+ // Setting environment variables for unit tests
405
+ EcomDev_Utils_Reflection::setRestrictedPropertyValue('Mage', '_app', self::$_oldApplication);
406
+ EcomDev_Utils_Reflection::setRestrictedPropertyValue('Mage', '_config', self::$_oldConfig);
407
+ EcomDev_Utils_Reflection::setRestrictedPropertyValue('Mage', '_events', self::$_oldEventCollection);
408
+ EcomDev_Utils_Reflection::setRestrictedPropertyValue('Mage', '_registry', self::$_oldRegistry);
409
+ }
410
+
411
+ /**
412
+ * Returns module name for a particular object
413
+ *
414
+ * @param string|object $className
415
+ * @throws RuntimeException if module name was not found for the passed class name
416
+ * @return string
417
+ */
418
+ public function getModuleNameByClassName($className)
419
+ {
420
+ if (is_object($className)) {
421
+ $className = get_class($className);
422
+ }
423
+
424
+ if (!isset($this->_moduleNameByClassName[$className])) {
425
+ // Try to find the module name by class name
426
+ $moduleName = false;
427
+ foreach ($this->getConfig()->getNode('modules')->children() as $module) {
428
+ if (strpos($className, $module->getName()) === 0) {
429
+ $moduleName = $module->getName();
430
+ break;
431
+ }
432
+ }
433
+
434
+ if (!$moduleName) {
435
+ throw new RuntimeException('Cannot to find the module name for class name: ' . $className);
436
+ }
437
+
438
+ $this->setModuleNameForClassName($className, $moduleName);
439
+ }
440
+
441
+ return $this->_moduleNameByClassName[$className];
442
+ }
443
+
444
+ /**
445
+ * Set associated module name for a class name,
446
+ * Usually used for making possible dependency injection in the test cases
447
+ *
448
+ *
449
+ * @param string $className
450
+ * @param string $moduleName
451
+ * @return EcomDev_PHPUnit_Model_App
452
+ */
453
+ public function setModuleNameForClassName($className, $moduleName)
454
+ {
455
+ $this->_moduleNameByClassName[$className] = $moduleName;
456
+ return $this;
457
+ }
458
+
459
+ /**
460
+ * Overriden for typehinting
461
+ *
462
+ * @return EcomDev_PHPUnit_Model_Config
463
+ * (non-PHPdoc)
464
+ * @see Mage_Core_Model_App::getConfig()
465
+ */
466
+ public function getConfig()
467
+ {
468
+ return parent::getConfig();
469
+ }
470
+
471
+ /**
472
+ * Overriden for typehinting
473
+ *
474
+ * @return EcomDev_PHPUnit_Model_Layout
475
+ * (non-PHPdoc)
476
+ * @see Mage_Core_Model_App::getLayout()
477
+ */
478
+ public function getLayout()
479
+ {
480
+ return parent::getLayout();
481
+ }
482
+
483
+ /**
484
+ * Disables events fire
485
+ *
486
+ * @return EcomDev_PHPUnit_Model_App
487
+ */
488
+ public function disableEvents()
489
+ {
490
+ $this->_eventsEnabled = false;
491
+ return $this;
492
+ }
493
+
494
+ /**
495
+ * Enable events fire
496
+ *
497
+ * @return EcomDev_PHPUnit_Model_App
498
+ */
499
+ public function enableEvents()
500
+ {
501
+ $this->_eventsEnabled = true;
502
+ return $this;
503
+ }
504
+
505
+ /**
506
+ * Overriden for disabling events
507
+ * fire during fixutre loading
508
+ *
509
+ * (non-PHPdoc)
510
+ * @see Mage_Core_Model_App::dispatchEvent()
511
+ */
512
+ public function dispatchEvent($eventName, $args)
513
+ {
514
+ if ($this->_eventsEnabled) {
515
+ parent::dispatchEvent($eventName, $args);
516
+
517
+ if (!isset($this->_dispatchedEvents[$eventName])) {
518
+ $this->_dispatchedEvents[$eventName] = 0;
519
+ }
520
+
521
+ $this->_dispatchedEvents[$eventName]++;
522
+ }
523
+
524
+ return $this;
525
+ }
526
+
527
+
528
+ /**
529
+ * Returns number of times when the event was dispatched
530
+ *
531
+ * @param string $eventName
532
+ * @return int
533
+ */
534
+ public function getDispatchedEventCount($eventName)
535
+ {
536
+ if (isset($this->_dispatchedEvents[$eventName])) {
537
+ return $this->_dispatchedEvents[$eventName];
538
+ }
539
+
540
+ return 0;
541
+ }
542
+
543
+
544
+ /**
545
+ * Resets dispatched events information
546
+ *
547
+ * @return EcomDev_PHPUnit_Model_App
548
+ */
549
+ public function resetDispatchedEvents()
550
+ {
551
+ $this->_dispatchedEvents = array();
552
+ return $this;
553
+ }
554
+ }
app/code/community/EcomDev/PHPUnit/Model/App/Area.php ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PHP Unit test suite for Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ *
12
+ * @category EcomDev
13
+ * @package EcomDev_PHPUnit
14
+ * @copyright Copyright (c) 2011 Ecommerce Developers (http://www.ecomdev.org)
15
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
+ * @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
17
+ */
18
+
19
+ /**
20
+ * Implementation of app area for a test
21
+ *
22
+ *
23
+ */
24
+
25
+ class EcomDev_PHPUnit_Model_App_Area
26
+ extends Mage_Core_Model_App_Area
27
+ implements EcomDev_PHPUnit_Isolation_Interface
28
+ {
29
+ const AREA_TEST = 'test';
30
+
31
+ /**
32
+ * Reset all the data,
33
+ * related to a particular area
34
+ *
35
+ * @return EcomDev_PHPUnit_Model_App_Area
36
+ */
37
+ public function reset()
38
+ {
39
+ $this->resetEvents();
40
+ $this->resetDesign();
41
+ $this->resetTranslate();
42
+ return $this;
43
+ }
44
+
45
+ /**
46
+ * Resets events area data
47
+ *
48
+ * @return EcomDev_PHPUnit_Model_App_Area
49
+ */
50
+ public function resetEvents()
51
+ {
52
+ $this->_application->removeEventArea($this->_code);
53
+ return $this;
54
+ }
55
+
56
+ /**
57
+ * Resets design related area data
58
+ *
59
+ *
60
+ * @return EcomDev_PHPUnit_Model_App_Area
61
+ */
62
+ public function resetDesign()
63
+ {
64
+ Mage::getSingleton('core/design')->unsetData();
65
+ Mage::getSingleton('core/design_package')->reset();
66
+ return $this;
67
+ }
68
+
69
+ /**
70
+ * Resets translator data
71
+ *
72
+ * @return EcomDev_PHPUnit_Model_App_Area
73
+ */
74
+ public function resetTranslate()
75
+ {
76
+ $translator = $this->_application->getTranslator();
77
+ EcomDev_Utils_Reflection::setRestrictedPropertyValue($translator, '_config', null);
78
+ EcomDev_Utils_Reflection::setRestrictedPropertyValue($translator, '_locale', null);
79
+ EcomDev_Utils_Reflection::setRestrictedPropertyValue($translator, '_cacheId', null);
80
+ EcomDev_Utils_Reflection::setRestrictedPropertyValue($translator, '_translateInline', null);
81
+ EcomDev_Utils_Reflection::setRestrictedPropertyValue($translator, '_dataScope', null);
82
+ EcomDev_Utils_Reflection::setRestrictedPropertyValue($translator, '_data', array());
83
+ return $this;
84
+ }
85
+ }
app/code/community/EcomDev/PHPUnit/Model/Config.php ADDED
@@ -0,0 +1,302 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PHP Unit test suite for Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ *
12
+ * @category EcomDev
13
+ * @package EcomDev_PHPUnit
14
+ * @copyright Copyright (c) 2011 Ecommerce Developers (http://www.ecomdev.org)
15
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
+ * @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
17
+ */
18
+
19
+ /**
20
+ * Configution model extended to make unit tests to be available
21
+ * at separate configuration scope
22
+ *
23
+ */
24
+ class EcomDev_PHPUnit_Model_Config extends Mage_Core_Model_Config
25
+ {
26
+ const XML_PATH_SECURE_BASE_URL = 'default/web/secure/base_url';
27
+ const XML_PATH_UNSECURE_BASE_URL = 'default/web/unsecure/base_url';
28
+
29
+ const CHANGE_ME = '[change me]';
30
+ /**
31
+ * Scope snapshot without applied configurations,
32
+ * It is used for proper store/website/default loading on per store basis
33
+ *
34
+ * @var Mage_Core_Model_Config_Base
35
+ */
36
+ protected $_scopeSnapshot = null;
37
+
38
+ /**
39
+ * List of replaced instance creation
40
+ *
41
+ * @return array
42
+ */
43
+ protected $_replaceInstanceCreation = array();
44
+
45
+ /**
46
+ * Load config data from DB
47
+ *
48
+ * @return Mage_Core_Model_Config
49
+ */
50
+ public function loadDb()
51
+ {
52
+ if ($this->_isLocalConfigLoaded
53
+ && Mage::isInstalled()
54
+ && $this->_scopeSnapshot === null) {
55
+ $this->saveScopeSnapshot();
56
+ }
57
+ parent::loadDb();
58
+ return $this;
59
+ }
60
+
61
+ /**
62
+ * Replaces creation of some instance by mock object
63
+ *
64
+ *
65
+ * @param string $type
66
+ * @param string $classAlias
67
+ * @param PHPUnit_Framework_MockObject_MockObject|PHPUnit_Framework_MockObject_MockBuilder $mock
68
+ * @return EcomDev_PHPUnit_Model_Config
69
+ */
70
+ public function replaceInstanceCreation($type, $classAlias, $mock)
71
+ {
72
+ $this->_replaceInstanceCreation[$type][$classAlias] = $mock;
73
+ return $this;
74
+ }
75
+
76
+ /**
77
+ * Flushes instance creation instruction list
78
+ *
79
+ * @return EcomDev_PHPUnit_Model_Config
80
+ */
81
+ public function flushReplaceInstanceCreation()
82
+ {
83
+ $this->_replaceInstanceCreation = array();
84
+ return $this;
85
+ }
86
+
87
+ /**
88
+ * Overriden for test case model instance creation mocking
89
+ *
90
+ * (non-PHPdoc)
91
+ * @see Mage_Core_Model_Config::getModelInstance()
92
+ */
93
+ public function getModelInstance($modelClass='', $constructArguments=array())
94
+ {
95
+ if (!isset($this->_replaceInstanceCreation['model'][$modelClass])) {
96
+ return parent::getModelInstance($modelClass, $constructArguments);
97
+ }
98
+
99
+ return $this->_replaceInstanceCreation['model'][$modelClass];
100
+ }
101
+
102
+ /**
103
+ * Overriden for test case model instance creation mocking
104
+ *
105
+ * (non-PHPdoc)
106
+ * @see Mage_Core_Model_Config::getModelInstance()
107
+ */
108
+ public function getResourceModelInstance($modelClass='', $constructArguments=array())
109
+ {
110
+ if (!isset($this->_replaceInstanceCreation['resource_model'][$modelClass])) {
111
+ return parent::getResourceModelInstance($modelClass, $constructArguments);
112
+ }
113
+
114
+ return $this->_replaceInstanceCreation['resource_model'][$modelClass];
115
+ }
116
+
117
+ /**
118
+ * Retrieves real resource model class alias
119
+ *
120
+ * @param string $classAlias
121
+ * @return string
122
+ */
123
+ public function getRealResourceModelClassAlias($classAlias)
124
+ {
125
+ list($classAliasPrefix,) = explode('/', $classAlias, 2);
126
+
127
+ if (isset($this->_xml->global->models->$classAliasPrefix->resourceModel)) {
128
+ $realClassAliasPrefix = $this->_xml->global->models->$classAliasPrefix->resourceModel;
129
+ $classAlias = $realClassAliasPrefix . substr(
130
+ $classAlias, strlen($classAliasPrefix)
131
+ );
132
+ }
133
+
134
+ return $classAlias;
135
+ }
136
+
137
+ /**
138
+ * Loads scope snapshot
139
+ *
140
+ * @return EcomDev_PHPUnit_Model_Config
141
+ */
142
+ public function loadScopeSnapshot()
143
+ {
144
+ if ($this->_scopeSnapshot === null) {
145
+ throw new RuntimeException('Cannot load scope snapshot, because it was not saved before');
146
+ }
147
+
148
+ $scopeNode = $this->_scopeSnapshot->getNode();
149
+ foreach ($scopeNode->children() as $nodeName => $values) {
150
+ // Remove somehow modified before xml node
151
+ unset($this->getNode()->$nodeName);
152
+ // Add saved snapshot of configuration node
153
+ $this->getNode()->addChild($nodeName);
154
+ $this->getNode()->$nodeName->extend($values);
155
+ }
156
+
157
+ return $this;
158
+ }
159
+
160
+ /**
161
+ * Saves current configuration snapshot,
162
+ * for pussible restoring in feature
163
+ *
164
+ * @param array $nodesToSave list of nodes for saving data, by default it is 'default', 'webistes', 'stores'
165
+ * @return EcomDev_PHPUnit_Model_Config
166
+ */
167
+ public function saveScopeSnapshot($nodesToSave = array('default', 'websites', 'stores'))
168
+ {
169
+ $this->_scopeSnapshot = clone $this->_prototype;
170
+ $this->_scopeSnapshot->loadString('<config />');
171
+ $scopeNode = $this->_scopeSnapshot->getNode();
172
+
173
+ foreach ($nodesToSave as $node) {
174
+ $scopeNode->addChild($node);
175
+ $scopeNode->{$node}->extend(
176
+ $this->getNode($node),
177
+ true
178
+ );
179
+ }
180
+
181
+ return $this;
182
+ }
183
+
184
+ /**
185
+ * Loads additional configuration for unit tests
186
+ * (non-PHPdoc)
187
+ * @see Mage_Core_Model_Config::loadBase()
188
+ */
189
+ public function loadBase()
190
+ {
191
+ parent::loadBase();
192
+ $this->_loadTestCacheConfig();
193
+ return $this;
194
+ }
195
+
196
+ /**
197
+ * (non-PHPdoc)
198
+ * @see Mage_Core_Model_Config::loadModules()
199
+ */
200
+ public function loadModules()
201
+ {
202
+ parent::loadModules();
203
+ $this->_loadTestConfig();
204
+ $this->_loadTestCacheConfig();
205
+ return $this;
206
+ }
207
+
208
+ /**
209
+ * Loads local.xml.phpunit file
210
+ * for overriding DB credentials
211
+ *
212
+ * @return EcomDev_PHPUnit_Model_Config
213
+ */
214
+ protected function _loadTestConfig()
215
+ {
216
+ $merge = clone $this->_prototype;
217
+ if ($merge->loadFile($this->_getLocalXmlForTest())) {
218
+ $this->_checkDbCredentialForDuplicate($this, $merge);
219
+ $this->_checkBaseUrl($this, $merge);
220
+ $this->extend($merge);
221
+ } else {
222
+ throw new Exception('Unable to load local.xml.phpunit');
223
+ }
224
+ return $this;
225
+ }
226
+
227
+ /**
228
+ * Loads cache configuration for PHPUnit tests scope
229
+ *
230
+ * @return EcomDev_PHPUnit_Model_Config
231
+ */
232
+ protected function _loadTestCacheConfig()
233
+ {
234
+ // Cache beckend initialization for unit tests,
235
+ // because it should be separate from live one
236
+ $this->setNode('global/cache/backend', 'file');
237
+ $this->getOptions()->setData('cache_dir', $this->getVarDir() . DS . 'phpunit.cache');
238
+ $this->getOptions()->setData('session_dir', $this->getVarDir() . DS . 'phpunit.session');
239
+ return $this;
240
+ }
241
+
242
+ /**
243
+ * Checks DB credentials for phpunit test case.
244
+ * They shouldn't be the same as live ones.
245
+ *
246
+ * @param Mage_Core_Model_Config_Base $original
247
+ * @param Mage_Core_Model_Config_Base $test
248
+ * @return EcomDev_PHPUnit_Model_Config
249
+ * @throws RuntimeException
250
+ */
251
+ protected function _checkDbCredentialForDuplicate($original, $test)
252
+ {
253
+ $originalDbName = (string) $original->getNode('global/resources/default_setup/connection/dbname');
254
+ $testDbName = (string) $test->getNode('global/resources/default_setup/connection/dbname');
255
+
256
+ if ($originalDbName == $testDbName) {
257
+ throw new RuntimeException('Test DB cannot be the same as the live one');
258
+ }
259
+ return $this;
260
+ }
261
+
262
+ /**
263
+ * Check base url settings, if not set it rises an exception
264
+ *
265
+ * @param Mage_Core_Model_Config_Base $original
266
+ * @param Mage_Core_Model_Config_Base $test
267
+ * @return EcomDev_PHPUnit_Model_Config
268
+ * @throws RuntimeException
269
+ */
270
+ protected function _checkBaseUrl($original, $test)
271
+ {
272
+ $baseUrlSecure = (string)$test->getNode(self::XML_PATH_SECURE_BASE_URL);
273
+ $baseUrlUnsecure = (string)$test->getNode(self::XML_PATH_UNSECURE_BASE_URL);
274
+
275
+ if (empty($baseUrlSecure) || empty($baseUrlUnsecure)
276
+ || $baseUrlSecure == self::CHANGE_ME || $baseUrlUnsecure == self::CHANGE_ME) {
277
+ echo sprintf(
278
+ 'Please change values in %s file for nodes %s and %s. '
279
+ . 'It will help in setting up proper controller test cases',
280
+ 'app/etc/local.phpunit', self::XML_PATH_SECURE_BASE_URL, self::XML_PATH_UNSECURE_BASE_URL
281
+ );
282
+ exit();
283
+ }
284
+ }
285
+
286
+ /**
287
+ * Retrieves local.xml file path for tests,
288
+ * If it is not found, method will rise an exception
289
+ *
290
+ * @return string
291
+ * @throws RuntimeException
292
+ */
293
+ protected function _getLocalXmlForTest()
294
+ {
295
+ $filePath = $this->getOptions()->getEtcDir() . DS . 'local.xml.phpunit';
296
+ if (!file_exists($filePath)) {
297
+ throw new RuntimeException('There is no local.xml.phpunit file');
298
+ }
299
+
300
+ return $filePath;
301
+ }
302
+ }
app/code/community/EcomDev/PHPUnit/Model/Design/Package.php ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class EcomDev_PHPUnit_Model_Design_Package
4
+ extends Mage_Core_Model_Design_Package
5
+ implements EcomDev_PHPUnit_Design_Package_Interface,
6
+ EcomDev_PHPUnit_Isolation_Interface
7
+
8
+ {
9
+ /**
10
+ * Asserts layout file existance in design packages,
11
+ * and returns actual and expected filenames as result
12
+ *
13
+ * @param string $fileName
14
+ * @param string $area
15
+ * @param string|null $designPackage if not specified any theme will be used
16
+ * @param string|null $theme if not specified any theme will be used
17
+ * @return array of 'expected' and 'actual' file names
18
+ */
19
+ public function getLayoutFileAssertion($fileName, $area, $designPackage = null, $theme = null)
20
+ {
21
+ $this->reset();
22
+ $this->setArea($area);
23
+
24
+ if ($area == EcomDev_PHPUnit_Model_App::AREA_ADMINHTML) {
25
+ $this->setStore(EcomDev_PHPUnit_Model_App::ADMIN_STORE_CODE);
26
+ } else {
27
+ $this->setStore(Mage::app()->getAnyStoreView()->getCode());
28
+ }
29
+
30
+ $this->setPackageName($designPackage);
31
+ $this->setTheme($theme);
32
+
33
+ $actualFileName = $this->getLayoutFilename($fileName, $params);
34
+
35
+ if ($theme !== null || $designPackage !== null) {
36
+ $expectedTheme = $this->getTheme('layout');
37
+ $expectedDesignPackage = $this->getPackageName();
38
+ $params = array(
39
+ '_type' => 'layout',
40
+ '_theme' => $expectedTheme,
41
+ '_package' => $expectedDesignPackage
42
+ );
43
+
44
+ $expectedFileName = Mage::getBaseDir('design') . DS . $this->_renderFilename($fileName, $params);
45
+ } else {
46
+ $expectedFileName = $actualFileName;
47
+ if (!file_exists($actualFileName)) {
48
+ $actualFileName = false;
49
+ }
50
+ }
51
+
52
+ return array(
53
+ 'actual' => $actualFileName,
54
+ 'expected' => $expectedFileName
55
+ );
56
+ }
57
+
58
+ /**
59
+ * Resets design data
60
+ *
61
+ * @return EcomDev_PHPUnit_Model_Design_Package
62
+ */
63
+ public function reset()
64
+ {
65
+ $this->_store = null;
66
+ $this->_area = null;
67
+ $this->_name = null;
68
+ $this->_theme = null;
69
+ $this->_config = null;
70
+ $this->_rootDir = null;
71
+ $this->_callbackFileDir = null;
72
+
73
+ return $this;
74
+ }
75
+ }
app/code/community/EcomDev/PHPUnit/Model/Expectation.php ADDED
@@ -0,0 +1,160 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // Loading Spyc yaml parser,
4
+ // becuase Symfony component is not working propertly with nested
5
+ require_once 'Spyc/spyc.php';
6
+
7
+ class EcomDev_PHPUnit_Model_Expectation
8
+ implements EcomDev_PHPUnit_Model_Expectation_Interface
9
+ {
10
+ /**
11
+ * List of created data object ids by path format
12
+ *
13
+ * @var array
14
+ */
15
+ protected $_dataObjectIds = array();
16
+
17
+ /**
18
+ * Loaded data from Yaml files
19
+ *
20
+ * @var Varien_Object
21
+ */
22
+ protected $_loadedData = null;
23
+
24
+ /**
25
+ * Data object used for managing
26
+ * expectation data
27
+ *
28
+ * @var string
29
+ */
30
+ protected $_dataObjectClassAlias = 'ecomdev_phpunit/expectation_object';
31
+
32
+ /**
33
+ * Returns class alias for fixture data object
34
+ *
35
+ * @return string
36
+ */
37
+ public function getDataObjectClassAlias()
38
+ {
39
+ return $this->_dataObjectClassAlias;
40
+ }
41
+
42
+ /**
43
+ * Retrieves data object for a particular path format
44
+ *
45
+ * @see EcomDev_PHPUnit_Model_Expectation_Interface::getDataObject()
46
+ */
47
+ public function getDataObject($pathFormat = null, $args = array())
48
+ {
49
+ if ($pathFormat === null) {
50
+ return $this->_loadedData;
51
+ }
52
+
53
+ $argsHash = $pathFormat . '_' . md5(serialize($args));
54
+
55
+ // Check already created objects by path
56
+ if (!isset($this->_dataObjectIds[$argsHash])) {
57
+ if ($args) {
58
+ array_unshift($args, $pathFormat);
59
+ $dataPath = call_user_func_array('sprintf', $args);
60
+ } else {
61
+ $dataPath = $pathFormat;
62
+ }
63
+
64
+ $data = $this->_loadedData->getData($dataPath);
65
+
66
+ if (!is_array($data)) {
67
+ throw new InvalidArgumentException(
68
+ 'Argument values for specifying special scope of expectations should be presented '
69
+ . ' in expectation file and should be an associative list (path: "' . $dataPath . '")'
70
+ );
71
+ }
72
+
73
+ $this->_dataObjectIds[$argsHash] = Mage::objects()->save(
74
+ Mage::getModel($this->getDataObjectClassAlias(), $data)
75
+ );
76
+ }
77
+
78
+ return Mage::objects($this->_dataObjectIds[$argsHash]);
79
+ }
80
+
81
+ /**
82
+ * Applies loaded data
83
+ *
84
+ * @see EcomDev_PHPUnit_Model_Test_Loadable_Interface::apply()
85
+ */
86
+ public function apply()
87
+ {
88
+ // For now it does nothing :(
89
+ return $this;
90
+ }
91
+
92
+ /**
93
+ * Removes objects created in object cache
94
+ * Clears loaded data property
95
+ *
96
+ * @see EcomDev_PHPUnit_Model_Test_Loadable_Interface::discard()
97
+ */
98
+ public function discard()
99
+ {
100
+ foreach ($this->_dataObjectIds as $objectId) {
101
+ Mage::objects()->delete($objectId);
102
+ }
103
+
104
+ $this->_dataObjectIds = array();
105
+ $this->_loadedData = null;
106
+
107
+ return $this;
108
+ }
109
+
110
+ /**
111
+ * Check that expectations is loaded
112
+ *
113
+ * @return boolean
114
+ */
115
+ public function isLoaded()
116
+ {
117
+ return $this->_loadedData !== null;
118
+ }
119
+
120
+ /**
121
+ * Loads expected data from test case annotations
122
+ *
123
+ * @see EcomDev_PHPUnit_Model_Test_Loadable_Interface::loadByTestCase()
124
+ */
125
+ public function loadByTestCase(EcomDev_PHPUnit_Test_Case $testCase)
126
+ {
127
+ $expectations = $testCase->getAnnotationByName('loadExpectation');
128
+
129
+ if (!$expectations) {
130
+ $expectations[] = null;
131
+ }
132
+
133
+ $expectationData = array();
134
+
135
+ foreach ($expectations as $expectation) {
136
+ if (empty($expectation)) {
137
+ $expectation = null;
138
+ }
139
+
140
+ $expectationFile = $testCase->getYamlFilePath('expectations', $expectation);
141
+
142
+ if (!$expectationFile) {
143
+ $text = 'There was no expectation defined for current test case';
144
+ if ($expectation) {
145
+ $text = sprintf('Cannot load expectation %s', $expectation);
146
+ }
147
+ throw new RuntimeException($text);
148
+ }
149
+
150
+ $expectationData = array_merge_recursive(
151
+ $expectationData, Spyc::YAMLLoad($expectationFile)
152
+ );
153
+ }
154
+
155
+ $this->_loadedData = new Varien_Object($expectationData);
156
+ return $this;
157
+ }
158
+
159
+
160
+ }
app/code/community/EcomDev/PHPUnit/Model/Expectation/Interface.php ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * PHP Unit test suite for Magento
5
+ *
6
+ * NOTICE OF LICENSE
7
+ *
8
+ * This source file is subject to the Open Software License (OSL 3.0)
9
+ * that is bundled with this package in the file LICENSE.txt.
10
+ * It is also available through the world-wide-web at this URL:
11
+ * http://opensource.org/licenses/osl-3.0.php
12
+ *
13
+ * @category EcomDev
14
+ * @package EcomDev_PHPUnit
15
+ * @copyright Copyright (c) 2011 Ecommerce Developers (http://www.ecomdev.org)
16
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
17
+ * @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
18
+ */
19
+
20
+ /**
21
+ * Interface for fixture model
22
+ * Can be used for creation of
23
+ * absolutely different implementation of fixture,
24
+ * then current one.
25
+ *
26
+ */
27
+ interface EcomDev_PHPUnit_Model_Expectation_Interface extends EcomDev_PHPUnit_Model_Test_Loadable_Interface
28
+ {
29
+ /**
30
+ * Returns data object with expectations
31
+ *
32
+ * @param string $pathFormat
33
+ * @param array $args arguments for format function
34
+ * @return EcomDev_PHPUnit_Model_Expectation_Object
35
+ */
36
+ public function getDataObject($pathFormat = null, $args = array());
37
+
38
+ /**
39
+ * Check is expectation loaded
40
+ *
41
+ * @return boolean
42
+ */
43
+ public function isLoaded();
44
+ }
app/code/community/EcomDev/PHPUnit/Model/Expectation/Object.php ADDED
@@ -0,0 +1,128 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PHP Unit test suite for Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ *
12
+ * @category EcomDev
13
+ * @package EcomDev_PHPUnit
14
+ * @copyright Copyright (c) 2011 Ecommerce Developers (http://www.ecomdev.org)
15
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
+ * @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
17
+ */
18
+
19
+ /**
20
+ * Expectation data object used for retrieving of data from expectations array
21
+ * Created to make possible iteration of expected data,
22
+ * for instance if you have list of orders
23
+ *
24
+ */
25
+ class EcomDev_PHPUnit_Model_Expectation_Object
26
+ extends Varien_Object
27
+ implements Iterator
28
+ {
29
+ protected $_createdObjectIds = array();
30
+
31
+ /**
32
+ * Current key in iterator
33
+ *
34
+ * @var array
35
+ */
36
+ protected $_iterationKeys = array();
37
+
38
+ /**
39
+ * If current element is an array,
40
+ * then it will be automatically wrapped by
41
+ * the same class instance as this one
42
+ *
43
+ * @see Iterator::current()
44
+ * @return null|int|string|boolean|decimal|EcomDev_PHPUnit_Model_Expectation_Object
45
+ */
46
+ public function current()
47
+ {
48
+ if ($this->key() === null) {
49
+ return null;
50
+ }
51
+
52
+ $current = $this->_data[$this->key()];
53
+ if (is_array($current)) {
54
+ $newObject = new self($current);
55
+ $this->_createdObjectIds = Mage::objects()
56
+ ->save($current);
57
+ return $newObject;
58
+ }
59
+ return $current;
60
+ }
61
+
62
+ /* (non-PHPdoc)
63
+ * @see Iterator::key()
64
+ */
65
+ public function key()
66
+ {
67
+ return current($this->_iterationKeys);
68
+ }
69
+
70
+ /* (non-PHPdoc)
71
+ * @see Iterator::next()
72
+ */
73
+ public function next()
74
+ {
75
+ next($this->_iterationKeys);
76
+ }
77
+
78
+ /* (non-PHPdoc)
79
+ * @see Iterator::rewind()
80
+ */
81
+ public function rewind()
82
+ {
83
+ $this->_iterationKeys = $this->keys();
84
+ }
85
+
86
+ /* (non-PHPdoc)
87
+ * @see Iterator::valid()
88
+ */
89
+ public function valid()
90
+ {
91
+ return key($this->_iterationKeys) !== null;
92
+ }
93
+
94
+ /**
95
+ * Object destructor removes
96
+ * created objects from object pool
97
+ *
98
+ *
99
+ */
100
+ public function __destruct()
101
+ {
102
+ if (!empty($this->_createdObjectIds)) {
103
+ foreach ($this->_createdObjectIds as $objectId) {
104
+ Mage::objects()->delete($objectId);
105
+ }
106
+ }
107
+ }
108
+
109
+ /**
110
+ * Returns data array keys
111
+ *
112
+ * @return array
113
+ */
114
+ public function keys()
115
+ {
116
+ return array_keys($this->_data);
117
+ }
118
+
119
+ /**
120
+ * Returns data array values
121
+ *
122
+ * @return array
123
+ */
124
+ public function values()
125
+ {
126
+ return array_values($this->_data);
127
+ }
128
+ }
app/code/community/EcomDev/PHPUnit/Model/Fixture.php ADDED
@@ -0,0 +1,495 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PHP Unit test suite for Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ *
12
+ * @category EcomDev
13
+ * @package EcomDev_PHPUnit
14
+ * @copyright Copyright (c) 2011 Ecommerce Developers (http://www.ecomdev.org)
15
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
+ * @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
17
+ */
18
+
19
+ // Loading Spyc yaml parser,
20
+ // becuase Symfony component is not working propertly with nested
21
+ require_once 'Spyc/spyc.php';
22
+
23
+ /**
24
+ * Fixture model for Magento unit tests
25
+ *
26
+ * Created for operations with different fixture types
27
+ *
28
+ */
29
+ class EcomDev_PHPUnit_Model_Fixture
30
+ extends Mage_Core_Model_Abstract
31
+ implements EcomDev_PHPUnit_Model_Fixture_Interface
32
+ {
33
+ // Configuration path for eav loaders
34
+ const XML_PATH_FIXTURE_EAV_LOADERS = 'phpunit/suite/fixture/eav';
35
+
36
+ // Default eav loader class node in loaders configuration
37
+ const DEFAULT_EAV_LOADER_NODE = 'default';
38
+
39
+ // Default eav loader class alias
40
+ const DEFAULT_EAV_LOADER_CLASS = 'ecomdev_phpunit/fixture_eav_default';
41
+
42
+ /**
43
+ * Fixtures array, contains config,
44
+ * table and eav keys.
45
+ * Each of them loads data into its area.
46
+ *
47
+ * @example
48
+ * array(
49
+ * 'config' => array(
50
+ * 'node/path' => 'value'
51
+ * ),
52
+ * 'table' => array(
53
+ * 'tablename' => array(
54
+ * array(
55
+ * 'column1' => 'value'
56
+ * 'column2' => 'value'
57
+ * 'column3' => 'value'
58
+ * ), // row 1
59
+ * array(
60
+ * 'column1' => 'value'
61
+ * 'column2' => 'value'
62
+ * 'column3' => 'value'
63
+ * ) // row 2
64
+ * )
65
+ * )
66
+ *
67
+ * )
68
+ *
69
+ * @var array
70
+ */
71
+ protected $_fixture = array();
72
+
73
+
74
+ /**
75
+ * Fixture options
76
+ *
77
+ * @var array
78
+ */
79
+ protected $_options = array();
80
+
81
+ /**
82
+ * Associative array of configuration nodes xml that was changed by fixture,
83
+ * it is used to preserve
84
+ *
85
+ * @var array
86
+ */
87
+ protected $_originalConfigurationXml = array();
88
+
89
+ /**
90
+ * Hash of current scope instances (store, website, group)
91
+ *
92
+ * @return array
93
+ */
94
+ protected $_currentScope = array();
95
+
96
+
97
+ /**
98
+ * Model constuctor, just defines wich resource model to use
99
+ * (non-PHPdoc)
100
+ * @see Varien_Object::_construct()
101
+ */
102
+ protected function _construct()
103
+ {
104
+ $this->_init('ecomdev_phpunit/fixture');
105
+ }
106
+
107
+ /**
108
+ * Set fixture options
109
+ *
110
+ * @param array $options
111
+ * @return EcomDev_PHPUnit_Model_Fixture
112
+ */
113
+ public function setOptions(array $options)
114
+ {
115
+ $this->_options = $options;
116
+ return $this;
117
+ }
118
+
119
+ /**
120
+ * Loads fixture from test case annotations
121
+ *
122
+ * @param EcomDev_PHPUnit_Test_Case $testCase
123
+ * @return EcomDev_PHPUnit_Model_Fixture
124
+ */
125
+ public function loadByTestCase(EcomDev_PHPUnit_Test_Case $testCase)
126
+ {
127
+ $fixtures = $testCase->getAnnotationByName(
128
+ 'loadFixture',
129
+ array('class', 'method')
130
+ );
131
+
132
+ foreach ($fixtures as $fixture) {
133
+ if (empty($fixture)) {
134
+ $fixture = null;
135
+ }
136
+
137
+ $filePath = $testCase->getYamlFilePath('fixtures', $fixture);
138
+
139
+ if (!$filePath) {
140
+ throw new RuntimeException('Unable to load fixture for test');
141
+ }
142
+
143
+ $this->loadYaml($filePath);
144
+ }
145
+
146
+ return $this;
147
+ }
148
+
149
+ /**
150
+ * Load YAML file
151
+ *
152
+ * @param string $filePath
153
+ * @return EcomDev_PHPUnit_Model_Fixture
154
+ * @throws InvalidArgumentException if file is not a valid YAML file
155
+ */
156
+ public function loadYaml($filePath)
157
+ {
158
+ $data = Spyc::YAMLLoad($filePath);
159
+
160
+ if (empty($this->_fixture)) {
161
+ $this->_fixture = $data;
162
+ } else {
163
+ $this->_fixture = array_merge_recursive($this->_fixture, $data);
164
+ }
165
+
166
+ return $this;
167
+ }
168
+
169
+ /**
170
+ * Applies loaded fixture
171
+ *
172
+ * @return EcomDev_PHPUnit_Model_Fixture
173
+ */
174
+ public function apply()
175
+ {
176
+ $reflection = EcomDev_Utils_Reflection::getRelflection($this);
177
+ foreach ($this->_fixture as $part => $data) {
178
+ $method = '_apply' . uc_words($part, '', '_');
179
+ if ($reflection->hasMethod($method)) {
180
+ $this->$method($data);
181
+ }
182
+ }
183
+
184
+ return $this;
185
+ }
186
+
187
+ /**
188
+ * Reverts environment to previous state
189
+ *
190
+ * @return EcomDev_PHPUnit_Model_Fixture
191
+ */
192
+ public function discard()
193
+ {
194
+ $reflection = EcomDev_Utils_Reflection::getRelflection($this);
195
+ foreach ($this->_fixture as $part => $data) {
196
+ $method = '_discard' . uc_words($part, '', '_');
197
+ if ($reflection->hasMethod($method)) {
198
+ $this->$method($data);
199
+ }
200
+ }
201
+
202
+ $this->_fixture = array();
203
+ }
204
+
205
+ /**
206
+ * Applies fixture configuration values into Mage_Core_Model_Config
207
+ *
208
+ * @param array $configuration
209
+ * @return EcomDev_PHPUnit_Model_Fixture
210
+ */
211
+ protected function _applyConfig($configuration)
212
+ {
213
+ if (!is_array($configuration)) {
214
+ throw new InvalidArgumentException('Configuration part should be an associative list');
215
+ }
216
+ Mage::getConfig()->loadScopeSnapshot();
217
+ foreach ($configuration as $path => $value) {
218
+ $this->_setConfigNodeValue($path, $value);
219
+ }
220
+ Mage::getConfig()->loadDb();
221
+ Mage::app()->reinitStores();
222
+ return $this;
223
+ }
224
+
225
+ /**
226
+ * Applies raw xml data to config node
227
+ *
228
+ * @param array $configuration
229
+ * @return EcomDev_PHPUnit_Model_Fixture
230
+ */
231
+ protected function _applyConfigXml($configuration)
232
+ {
233
+ if (!is_array($configuration)) {
234
+ throw new InvalidArgumentException('Configuration part should be an associative list');
235
+ }
236
+
237
+ foreach ($configuration as $path => $value) {
238
+ if (!is_string($value)) {
239
+ throw new InvalidArgumentException('Configuration value should be a valid xml string');
240
+ }
241
+ try {
242
+ $xmlElement = new Varien_Simplexml_Element($value);
243
+ } catch (Exception $e) {
244
+ throw new InvalidArgumentException('Configuration value should be a valid xml string', 0, $e);
245
+ }
246
+
247
+ $node = Mage::getConfig()->getNode($path);
248
+
249
+ if (!$node) {
250
+ throw new InvalidArgumentException('Configuration value should be a valid xml string');
251
+ }
252
+
253
+ $this->_originalConfigurationXml[$path] = $node->asNiceXml();
254
+ $node->extend($xmlElement, true);
255
+ }
256
+
257
+ return $this;
258
+ }
259
+
260
+ /**
261
+ * Reverts fixture configuration values in Mage_Core_Model_Config
262
+ *
263
+ * @return EcomDev_PHPUnit_Model_Fixture
264
+ */
265
+ protected function _discardConfig()
266
+ {
267
+ Mage::getConfig()->loadScopeSnapshot();
268
+ Mage::getConfig()->loadDb();
269
+ Mage::app()->reinitStores();
270
+ return $this;
271
+ }
272
+
273
+ /**
274
+ * Reverts fixture configuration xml values in Mage_Core_Model_Config
275
+ *
276
+ * @return EcomDev_PHPUnit_Model_Fixture
277
+ */
278
+ protected function _discardConfigXml()
279
+ {
280
+ foreach ($this->_originalConfigurationXml as $path => $value) {
281
+ $node = Mage::getConfig()->getNode($path);
282
+ $parentNode = $node->getParent();
283
+ unset($parentNode->{$node->getName()});
284
+ $oldXml = new Varien_Simplexml_Element($value);
285
+ $parentNode->appendChild($oldXml);
286
+ }
287
+
288
+ $this->_originalConfigurationXml = array();
289
+ return $this;
290
+ }
291
+
292
+ /**
293
+ * Applies table data into test database
294
+ *
295
+ * @param array $tables
296
+ * @return EcomDev_PHPUnit_Model_Fixture
297
+ */
298
+ protected function _applyTables($tables)
299
+ {
300
+ if (!is_array($tables)) {
301
+ throw new InvalidArgumentException(
302
+ 'Tables part should be an associative list with keys as table entity and values as list of associative rows'
303
+ );
304
+ }
305
+
306
+ foreach ($tables as $tableEntity => $data) {
307
+ $this->getResource()->cleanTable($tableEntity);
308
+ if (!empty($data)) {
309
+ $this->getResource()->loadTableData($tableEntity, $data);
310
+ }
311
+ }
312
+ }
313
+
314
+ /**
315
+ * Removes table data from test data base
316
+ *
317
+ * @param array $tables
318
+ * @return EcomDev_PHPUnit_Model_Fixture
319
+ */
320
+ protected function _discardTables($tables)
321
+ {
322
+ if (!is_array($tables)) {
323
+ throw new InvalidArgumentException(
324
+ 'Tables part should be an associative list with keys as table entity and values as list of associative rows'
325
+ );
326
+ }
327
+
328
+ foreach ($tables as $tableEntity => $data) {
329
+ $this->getResource()->cleanTable($tableEntity);
330
+ }
331
+ }
332
+
333
+ /**
334
+ * Setting config value with applying the values to stores and websites
335
+ *
336
+ * @param string $path
337
+ * @param string $value
338
+ * @return EcomDev_PHPUnit_Model_Fixture
339
+ */
340
+ protected function _setConfigNodeValue($path, $value)
341
+ {
342
+ $pathArray = explode('/', $path);
343
+
344
+ $scope = array_shift($pathArray);
345
+
346
+ switch ($scope) {
347
+ case 'stores':
348
+ $storeCode = array_shift($pathArray);
349
+ Mage::app()->getStore($storeCode)->setConfig(
350
+ implode('/', $pathArray), $value
351
+ );
352
+ break;
353
+
354
+ case 'websites':
355
+ $websiteCode = array_shift($pathArray);
356
+ $website = Mage::app()->getWebsite($websiteCode);
357
+ $website->setConfig(implode('/', $pathArray), $value);
358
+ break;
359
+
360
+ default:
361
+ Mage::getConfig()->setNode($path, $value);
362
+ break;
363
+ }
364
+
365
+ return $this;
366
+ }
367
+
368
+ /**
369
+ * Retrieves eav loader for a particular entity type
370
+ *
371
+ * @param string $entityType
372
+ * @return EcomDev_PHPUnit_Model_Mysql4_Fixture_Eav_Abstract
373
+ */
374
+ protected function _getEavLoader($entityType)
375
+ {
376
+ $loaders = Mage::getConfig()->getNode(self::XML_PATH_FIXTURE_EAV_LOADERS);
377
+
378
+ if (isset($loaders->$entityType)) {
379
+ $classAlias = (string)$loaders->$entityType;
380
+ } elseif (isset($loaders->{self::DEFAULT_EAV_LOADER_NODE})) {
381
+ $classAlias = (string)$loaders->{self::DEFAULT_EAV_LOADER_NODE};
382
+ } else {
383
+ $classAlias = self::DEFAULT_EAV_LOADER_CLASS;
384
+ }
385
+
386
+ return Mage::getResourceSingleton($classAlias);
387
+ }
388
+
389
+ /**
390
+ * Applies fixture EAV values
391
+ *
392
+ * @param array $configuration
393
+ * @return EcomDev_PHPUnit_Model_Fixture
394
+ */
395
+ protected function _applyEav($entities)
396
+ {
397
+ if (!is_array($entities)) {
398
+ throw new InvalidArgumentException('EAV part should be an associative list with rows as value and entity type as key');
399
+ }
400
+
401
+ foreach ($entities as $entityType => $values) {
402
+ $this->_getEavLoader($entityType)
403
+ ->setOptions($this->_options)
404
+ ->loadEntity($entityType, $values);
405
+ }
406
+
407
+ return $this;
408
+ }
409
+
410
+ /**
411
+ * Clean applied eav data
412
+ *
413
+ * @param array $entities
414
+ * @return EcomDev_PHPUnit_Model_Fixture
415
+ */
416
+ protected function _discardEav($entities)
417
+ {
418
+ foreach (array_keys($entities) as $entityType) {
419
+ $this->_getEavLoader($entityType)
420
+ ->cleanEntity($entityType);
421
+ }
422
+
423
+ return $this;
424
+ }
425
+
426
+ /**
427
+ * Applies scope fixture,
428
+ * i.e., website, store, store group
429
+ *
430
+ * @param array $types
431
+ * @return EcomDev_PHPUnit_Model_Fixture
432
+ */
433
+ protected function _applyScope($types)
434
+ {
435
+ $modelByType = array(
436
+ 'store' => 'core/store',
437
+ 'group' => 'core/store_group',
438
+ 'website' => 'core/website'
439
+ );
440
+
441
+ Mage::app()->disableEvents();
442
+
443
+ foreach ($types as $type => $rows) {
444
+ if (!isset($modelByType[$type])) {
445
+ throw new RuntimeException(sprintf('Unknown "%s" scope type specified', $type));
446
+ }
447
+
448
+ foreach ($rows as $row) {
449
+ $scopeModel = Mage::getModel($modelByType[$type]);
450
+ $this->_currentScope[$type][] = $scopeModel;
451
+ $scopeModel->setData($row);
452
+ // Change property for saving new objects with specified ids
453
+ EcomDev_Utils_Reflection::setRestrictedPropertyValue(
454
+ $scopeModel->getResource(), '_useIsObjectNew', true
455
+ );
456
+ $scopeModel->isObjectNew(true);
457
+ $scopeModel->save();
458
+ // Revert changed property
459
+ EcomDev_Utils_Reflection::setRestrictedPropertyValue(
460
+ $scopeModel->getResource(), '_useIsObjectNew', false
461
+ );
462
+
463
+ }
464
+ }
465
+ Mage::app()->enableEvents();
466
+ Mage::app()->reinitStores();
467
+ return $this;
468
+ }
469
+
470
+ /**
471
+ * Removes scope fixture changes,
472
+ * i.e., website, store, store group
473
+ *
474
+ * @return EcomDev_PHPUnit_Model_Fixture
475
+ */
476
+ protected function _discardScope()
477
+ {
478
+ Mage::app()->disableEvents();
479
+ $scope = array_reverse($this->_currentScope);
480
+ foreach ($scope as $models) {
481
+ foreach ($models as $model) {
482
+ $model->delete();
483
+ }
484
+ }
485
+
486
+ $this->_currentScope = array();
487
+ Mage::app()->getCache()->clean(
488
+ Zend_Cache::CLEANING_MODE_MATCHING_TAG,
489
+ array(Mage_Core_Model_Mysql4_Collection_Abstract::CACHE_TAG)
490
+ );
491
+ Mage::app()->enableEvents();
492
+ Mage::app()->reinitStores();
493
+ return $this;
494
+ }
495
+ }
app/code/community/EcomDev/PHPUnit/Model/Fixture/Interface.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PHP Unit test suite for Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ *
12
+ * @category EcomDev
13
+ * @package EcomDev_PHPUnit
14
+ * @copyright Copyright (c) 2011 Ecommerce Developers (http://www.ecomdev.org)
15
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
+ * @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
17
+ */
18
+
19
+ /**
20
+ * Interface for fixture model
21
+ * Can be used for creation of
22
+ * absolutely different implementation of fixture,
23
+ * then current one.
24
+ *
25
+ */
26
+ interface EcomDev_PHPUnit_Model_Fixture_Interface extends EcomDev_PHPUnit_Model_Test_Loadable_Interface
27
+ {
28
+ /**
29
+ * Sets fixture options
30
+ *
31
+ * @param array $options
32
+ * @return EcomDev_PHPUnit_Model_Fixture_Interface
33
+ */
34
+ public function setOptions(array $options);
35
+ }
app/code/community/EcomDev/PHPUnit/Model/Layout.php ADDED
@@ -0,0 +1,494 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PHP Unit test suite for Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ *
12
+ * @category EcomDev
13
+ * @package EcomDev_PHPUnit
14
+ * @copyright Copyright (c) 2011 Ecommerce Developers (http://www.ecomdev.org)
15
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
+ * @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
17
+ */
18
+
19
+
20
+ /**
21
+ * Layout model that adds additional functionality
22
+ * for testing the layout itself
23
+ *
24
+ */
25
+ class EcomDev_PHPUnit_Model_Layout
26
+ extends Mage_Core_Model_Layout
27
+ implements EcomDev_PHPUnit_Constraint_Layout_Logger_Interface,
28
+ EcomDev_PHPUnit_Isolation_Interface
29
+ {
30
+ /**
31
+ * List of replaced blocks creation
32
+ *
33
+ * @return array
34
+ */
35
+ protected $_replaceBlockCreation = array();
36
+
37
+ /**
38
+ * Records for gethering information about all,
39
+ * the actions that was performed
40
+ *
41
+ *
42
+ * @var array
43
+ */
44
+ protected $_records = array();
45
+
46
+ /**
47
+ * List of collected args for action call
48
+ *
49
+ * @var array
50
+ */
51
+ protected $_collectedArgs = null;
52
+
53
+ /**
54
+ * Collected block during block creation
55
+ *
56
+ * @var Mage_Core_Block_Abstract
57
+ */
58
+ protected $_collectedBlock = null;
59
+
60
+
61
+ /**
62
+ * Replaces creation of some block by mock object
63
+ *
64
+ * @param string $classAlias
65
+ * @param PHPUnit_Framework_MockObject_MockObject|PHPUnit_Framework_MockObject_MockBuilder $mock
66
+ * @return EcomDev_PHPUnit_Model_Layout
67
+ */
68
+ public function replaceBlockCreation($classAlias, $mock)
69
+ {
70
+ $this->_replaceBlockCreation[$classAlias] = $mock;
71
+ return $this;
72
+ }
73
+
74
+ /**
75
+ * Flushes instance creation instruction list
76
+ *
77
+ * @return EcomDev_PHPUnit_Model_Layout
78
+ */
79
+ public function flushReplaceBlockCreation()
80
+ {
81
+ $this->_replaceBlockCreation = array();
82
+ return $this;
83
+ }
84
+
85
+ /**
86
+ * Overriden for possibility of replacing a block by mock object
87
+ * (non-PHPdoc)
88
+ * @see Mage_Core_Model_Layout::_getBlockInstance()
89
+ */
90
+ protected function _getBlockInstance($block, array $attributes=array())
91
+ {
92
+ if (!isset($this->_replaceBlockCreation[$block])) {
93
+ return parent::_getBlockInstance($block, $attributes);
94
+ }
95
+
96
+ return $this->_replaceBlockCreation[$block];
97
+ }
98
+
99
+ /**
100
+ * Resets layout instance properties
101
+ *
102
+ * @return EcomDev_PHPUnit_Model_Layout
103
+ */
104
+ public function reset()
105
+ {
106
+ $this->setXml(simplexml_load_string('<layout/>', $this->_elementClass));
107
+ $this->_update = Mage::getModel('core/layout_update');
108
+ $this->_area = null;
109
+ $this->_helpers = array();
110
+ $this->_directOutput = false;
111
+ $this->_output = array();
112
+ $this->_records = array();
113
+
114
+ foreach ($this->_blocks as $block) {
115
+ // Remove references between blocks
116
+ $block->setParentBlock(null);
117
+ $block->setMessageBlock(null);
118
+ $block->unsetChildren();
119
+ }
120
+
121
+ $this->_blocks = array();
122
+ return $this;
123
+ }
124
+
125
+
126
+ /**
127
+ * Returns all the recorded actions
128
+ *
129
+ * @return array
130
+ */
131
+ public function getRecords()
132
+ {
133
+ return $this->_records;
134
+ }
135
+
136
+ /**
137
+ * Returns all actions performed on the target
138
+ * or if target is null returns actions for all targets
139
+ *
140
+ * @param string $action
141
+ * @param string|null $target
142
+ * @return array
143
+ */
144
+ public function findAll($action, $target = null)
145
+ {
146
+ if ($target !== null && isset($this->_records[$action][$target])) {
147
+ return $this->_records[$action][$target];
148
+ } elseif ($target !== null) {
149
+ return array();
150
+ } elseif (!isset($this->_records[$action])) {
151
+ return array();
152
+ }
153
+
154
+ $result = array();
155
+ foreach ($this->_records[$action] as $target => $records) {
156
+ $record['target'] = $target;
157
+ $result = array_merge($result, $records);
158
+ }
159
+
160
+ return $result;
161
+ }
162
+
163
+ /**
164
+ * Returns all actions targets
165
+ *
166
+ * @param string $action
167
+ * @return array
168
+ */
169
+ public function findAllTargets($action)
170
+ {
171
+ if (isset($this->_records[$action])) {
172
+ return array_keys($this->_records[$action]);
173
+ }
174
+
175
+ return array();
176
+ }
177
+
178
+ /**
179
+ * Returns a single target action record by specified parameters
180
+ *
181
+ * @param string $action
182
+ * @param string $target
183
+ * @param array $parameters
184
+ * @return boolean
185
+ */
186
+ public function findByParameters($action, $target, array $parameters, $searchType = self::SEARCH_TYPE_AND)
187
+ {
188
+ if (!isset($this->_records[$action][$target])) {
189
+ return array();
190
+ }
191
+
192
+ $records = array();
193
+ $arrayValues = false;
194
+
195
+ // If it is a numeric array, then actual parameters should transformed as well
196
+ if (count(array_filter(array_keys($parameters), 'is_int')) === count($parameters)) {
197
+ $arrayValues = true;
198
+ }
199
+
200
+
201
+ foreach ($this->_records[$action][$target] as $actualParameters) {
202
+ if ($arrayValues) {
203
+ $actualParameters = array_values($actualParameters);
204
+ }
205
+
206
+ $intersection = array_intersect_assoc($actualParameters, $parameters);
207
+ switch ($searchType) {
208
+ case self::SEARCH_TYPE_OR:
209
+ $match = !empty($intersection);
210
+ break;
211
+ case self::SEARCH_TYPE_EXACT:
212
+ $match = count($intersection) === count($actualParameters);
213
+ break;
214
+ case self::SEARCH_TYPE_AND:
215
+ default:
216
+ $match = count($intersection) === count($parameters);
217
+ break;
218
+ }
219
+
220
+ if ($match) {
221
+ $records[] = $actualParameters;
222
+ }
223
+ }
224
+
225
+ return $records;
226
+ }
227
+
228
+ /**
229
+ * Returns first action that was recorded for target
230
+ *
231
+ * @param string $action
232
+ * @param string $target
233
+ * @return array
234
+ */
235
+ public function findFirst($action, $target)
236
+ {
237
+ if (!isset($this->_records[$action][$target])) {
238
+ return false;
239
+ }
240
+
241
+ reset($this->_records[$action][$target]);
242
+
243
+ return current($this->_records[$action][$target]);
244
+ }
245
+
246
+ /**
247
+ * Records a particular target action
248
+ *
249
+ * @param string $action
250
+ * @param string|null $target
251
+ * @param array $parameters
252
+ * @return EcomDev_PHPUnit_Model_Layout
253
+ */
254
+ public function record($action, $target = null, array $parameters = array())
255
+ {
256
+ $this->_records[$action][$target][] = $parameters;
257
+ return $this;
258
+ }
259
+
260
+ /**
261
+ * Observes a system event that is triggered on block render process start
262
+ *
263
+ * @param Varien_Event_Observer $observer
264
+ * @return EcomDev_PHPUnit_Model_Layout
265
+ */
266
+ public function recordBlockRender(Varien_Event_Observer $observer)
267
+ {
268
+ /* @var $block Mage_Core_Block_Abstract */
269
+ $block = $observer->getEvent()->getBlock();
270
+ $transport = $observer->getEvent()->getTransport();
271
+
272
+ $this->record(
273
+ self::ACTION_BLOCK_RENDERED,
274
+ $block->getNameInLayout(),
275
+ array('content' => $transport->getHtml())
276
+ );
277
+ }
278
+
279
+ /**
280
+ * Records action call
281
+ * (non-PHPdoc)
282
+ * @see Mage_Core_Model_Layout::_generateAction()
283
+ */
284
+ protected function _generateAction($node, $parent)
285
+ {
286
+ $this->_collectedArgs = null;
287
+ parent::_generateAction($node, $parent);
288
+ if ($this->_collectedArgs !== null) {
289
+ $method = (string)$node['method'];
290
+ if (!empty($node['block'])) {
291
+ $parentName = (string)$node['block'];
292
+ } else {
293
+ $parentName = $parent->getBlockName();
294
+ }
295
+
296
+ $target = $parentName . '::' . $method;
297
+ $this->record(self::ACTION_BLOCK_ACTION, $target, $this->_collectedArgs);
298
+ }
299
+ return $this;
300
+ }
301
+
302
+ /**
303
+ * Collects arguments if was not collected before
304
+ * (non-PHPdoc)
305
+ * @see Mage_Core_Model_Layout::_translateLayoutNode()
306
+ */
307
+ protected function _translateLayoutNode($node, $args)
308
+ {
309
+ parent::_translateLayoutNode($node, $args);
310
+ if ($this->_collectedArgs === null) {
311
+ $this->_collectedArgs = $args;
312
+ }
313
+ }
314
+
315
+ /**
316
+ * Records information about new block creation
317
+ * (non-PHPdoc)
318
+ * @see Mage_Core_Model_Layout::_generateBlock()
319
+ */
320
+ protected function _generateBlock($node, $parent)
321
+ {
322
+ $this->_collectedBlock = null;
323
+ parent::_generateBlock($node, $parent);
324
+ if ($this->_collectedBlock !== null) {
325
+ $target = $this->_collectedBlock->getNameInLayout();
326
+ $params = array();
327
+ if (isset($node['as'])) {
328
+ $params['alias'] = (string)$node['as'];
329
+ } else {
330
+ $params['alias'] = $target;
331
+ }
332
+
333
+ if (isset($node['class'])) {
334
+ $params['type'] = (string)$node['class'];
335
+ } elseif (isset($node['type'])) {
336
+ $params['type'] = (string)$node['type'];
337
+ }
338
+
339
+ $params['class'] = get_class($this->_collectedBlock);
340
+
341
+ $params['is_root'] = isset($node['output']);
342
+ $this->record(self::ACTION_BLOCK_CREATED, $target, $params);
343
+
344
+ if (isset($node['template'])) {
345
+ $this->record(self::ACTION_BLOCK_ACTION, $target . '::setTemplate',
346
+ array('template' => (string)$node['template']));
347
+ }
348
+ }
349
+ return $this;
350
+ }
351
+
352
+ /**
353
+ * Collects block creation
354
+ * (non-PHPdoc)
355
+ * @see Mage_Core_Model_Layout::addBlock()
356
+ */
357
+ public function addBlock($block, $blockName)
358
+ {
359
+ $block = parent::addBlock($block, $blockName);
360
+
361
+ if ($this->_collectedBlock === null) {
362
+ $this->_collectedBlock = $block;
363
+ }
364
+
365
+ return $block;
366
+ }
367
+
368
+
369
+ /**
370
+ * Records information about blocks removal and loaded layout handles
371
+ * (non-PHPdoc)
372
+ * @see Mage_Core_Model_Layout::generateXml()
373
+ */
374
+ public function generateXml()
375
+ {
376
+ $loadedHandles = $this->getUpdate()->getHandles();
377
+ foreach ($loadedHandles as $key => $handle) {
378
+ $params = array();
379
+ if ($key > 0) {
380
+ $params['after'] = array_slice($loadedHandles, 0, $key);
381
+ } else {
382
+ $params['after'] = array();
383
+ }
384
+
385
+ if ($key < count($loadedHandles)) {
386
+ $params['before'] = array_slice($loadedHandles, $key + 1);
387
+ } else {
388
+ $params['before'] = array();
389
+ }
390
+
391
+ $this->record(self::ACTION_HANDLE_LOADED, $handle, $params);
392
+ }
393
+
394
+ parent::generateXml();
395
+
396
+ $removedBlocks = $this->_xml->xpath('//block[@ignore]');
397
+
398
+ if (is_array($removedBlocks)) {
399
+ foreach ($removedBlocks as $block) {
400
+ $this->record(self::ACTION_BLOCK_REMOVED, $block->getBlockName());
401
+ }
402
+ }
403
+
404
+ return $this;
405
+ }
406
+
407
+
408
+ /**
409
+ * Returns block position information in the parent subling.
410
+ * Returned array contains two keys "before" and "after"
411
+ * which are list of block names in this positions
412
+ *
413
+ * @param string $block
414
+ * @return array
415
+ */
416
+ public function getBlockPosition($block)
417
+ {
418
+ $result = array(
419
+ 'before' => array(),
420
+ 'after' => array()
421
+ );
422
+
423
+ $block = $this->getBlock($block);
424
+ if (!$block || !$block->getParentBlock()) {
425
+ return $result;
426
+ }
427
+
428
+ $sortedBlockNames = $block->getParentBlock()->getSortedChildren();
429
+ $key = 'before';
430
+ foreach ($sortedBlockNames as $blockName) {
431
+ if ($blockName == $block->getNameInLayout()) {
432
+ $key = 'after';
433
+ continue;
434
+ }
435
+ $result[$key][] = $blockName;
436
+ }
437
+
438
+ return $result;
439
+ }
440
+
441
+ /**
442
+ * Returns block parent
443
+ *
444
+ * @param string $block
445
+ * @return srting|boolean
446
+ */
447
+ public function getBlockParent($block)
448
+ {
449
+ $block = $this->getBlock($block);
450
+ if (!$block || !$block->getParentBlock()) {
451
+ return false;
452
+ }
453
+
454
+ return $block->getParentBlock()->getNameInLayout();
455
+ }
456
+
457
+ /**
458
+ * Returns block property by getter
459
+ *
460
+ * @param string $block
461
+ * @return mixed
462
+ */
463
+ public function getBlockProperty($block, $property)
464
+ {
465
+ $block = $this->getBlock($block);
466
+
467
+ if (!$block) {
468
+ throw new RuntimeException('Received a call to block, that does not exist');
469
+ }
470
+
471
+ return $block->getDataUsingMethod($property);
472
+ }
473
+
474
+ /**
475
+ * Retuns a boolean flag for layout load status
476
+ *
477
+ * @return boolean
478
+ */
479
+ public function isLoaded()
480
+ {
481
+ return $this->_xml->hasChildren();
482
+ }
483
+
484
+ /**
485
+ * Records that layout was rendered
486
+ * (non-PHPdoc)
487
+ * @see Mage_Core_Model_Layout::getOutput()
488
+ */
489
+ public function getOutput()
490
+ {
491
+ $this->record(self::ACTION_RENDER, 'layout');
492
+ return parent::getOutput();
493
+ }
494
+ }
app/code/community/EcomDev/PHPUnit/Model/Mysql4/Fixture.php ADDED
@@ -0,0 +1,120 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PHP Unit test suite for Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ *
12
+ * @category EcomDev
13
+ * @package EcomDev_PHPUnit
14
+ * @copyright Copyright (c) 2011 Ecommerce Developers (http://www.ecomdev.org)
15
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
+ * @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
17
+ */
18
+
19
+ /**
20
+ * Fixture resource model.
21
+ *
22
+ * Created for direct operations with DB.
23
+ *
24
+ */
25
+ class EcomDev_PHPUnit_Model_Mysql4_Fixture extends Mage_Core_Model_Mysql4_Abstract
26
+ {
27
+ protected function _construct()
28
+ {
29
+ $this->_setResource('ecomdev_phpunit');
30
+ }
31
+
32
+ /**
33
+ * Cleans table in test database
34
+ *
35
+ * @param string $tableEntity
36
+ * @return EcomDev_PHPUnit_Model_Mysql4_Fixture
37
+ */
38
+ public function cleanTable($tableEntity)
39
+ {
40
+ $this->_getWriteAdapter()
41
+ ->truncate($this->getTable($tableEntity));
42
+ return $this;
43
+ }
44
+
45
+ /**
46
+ * Loads multiple data rows into table
47
+ *
48
+ * @param string $tableEntity
49
+ * @param array $tableData
50
+ */
51
+ public function loadTableData($tableEntity, $tableData)
52
+ {
53
+ $tableColumns = $this->_getWriteAdapter()
54
+ ->describeTable($this->getTable($tableEntity));
55
+
56
+ $records = array();
57
+ foreach ($tableData as $row) {
58
+ $records[] = $this->_getTableRecord($row, $tableColumns);
59
+ }
60
+
61
+ $this->_getWriteAdapter()->insertMultiple(
62
+ $this->getTable($tableEntity),
63
+ $records
64
+ );
65
+
66
+ return $this;
67
+ }
68
+
69
+ /**
70
+ * Prepares entity table record from array
71
+ *
72
+ * @param array $row
73
+ * @param array $tableColumns list of entity_table columns
74
+ * @return array
75
+ */
76
+ protected function _getTableRecord($row, $tableColumns)
77
+ {
78
+ $record = array();
79
+
80
+ // Fullfil table records with data
81
+ foreach ($tableColumns as $columnName => $definition) {
82
+ if (isset($row[$columnName])) {
83
+ $record[$columnName] = $this->_getTableRecordValue($row[$columnName]);
84
+ } elseif ($definition['DEFAULT'] !== null) {
85
+ $record[$columnName] = $definition['DEFAULT'];
86
+ } else {
87
+ $record[$columnName] = (($definition['NULLABLE']) ? null : '');
88
+ }
89
+ }
90
+
91
+ return $record;
92
+ }
93
+
94
+ /**
95
+ * Processes table record values,
96
+ * used for transforming custom values like serialized
97
+ * or JSON data
98
+ *
99
+ *
100
+ * @param mixed $value
101
+ * @return string
102
+ */
103
+ protected function _getTableRecordValue($value)
104
+ {
105
+ // If it is scalar php type, then just return itself
106
+ if (!is_array($value)) {
107
+ return $value;
108
+ }
109
+
110
+ if (isset($value['json'])) {
111
+ return Mage::helper('core')->jsonEncode($value['json']);
112
+ }
113
+
114
+ if (isset($value['serialized'])) {
115
+ return serialize($value['serialized']);
116
+ }
117
+
118
+ throw new InvalidArgumentException('Unrecognized type for DB column');
119
+ }
120
+ }
app/code/community/EcomDev/PHPUnit/Model/Mysql4/Fixture/Eav/Abstract.php ADDED
@@ -0,0 +1,344 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PHP Unit test suite for Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ *
12
+ * @category EcomDev
13
+ * @package EcomDev_PHPUnit
14
+ * @copyright Copyright (c) 2011 Ecommerce Developers (http://www.ecomdev.org)
15
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
+ * @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
17
+ */
18
+
19
+ /**
20
+ * Base implementation of EAV fixtures loader
21
+ *
22
+ */
23
+ abstract class EcomDev_PHPUnit_Model_Mysql4_Fixture_Eav_Abstract extends EcomDev_PHPUnit_Model_Mysql4_Fixture
24
+ {
25
+ /**
26
+ * List of indexers required to build
27
+ *
28
+ * @var array
29
+ */
30
+ protected $_requiredIndexers = array();
31
+
32
+ /**
33
+ * Fixture options
34
+ *
35
+ * @var array
36
+ */
37
+ protected $_options = array();
38
+
39
+ /**
40
+ * Retrieve required indexers for re-building
41
+ *
42
+ * @var array
43
+ */
44
+ public function getRequiredIndexers()
45
+ {
46
+ return $this->_requiredIndexers;
47
+ }
48
+
49
+ /**
50
+ * Set fixture options
51
+ *
52
+ * @param array $options
53
+ * @return EcomDev_PHPUnit_Model_Mysql4_Fixture_Eav_Abstract
54
+ */
55
+ public function setOptions(array $options)
56
+ {
57
+ $this->_options = $options;
58
+ return $this;
59
+ }
60
+
61
+ /**
62
+ * Add indexer by specific code to required indexers list
63
+ *
64
+ * @param string $code
65
+ * @return EcomDev_PHPUnit_Model_Mysql4_Fixture_Eav_Abstract
66
+ */
67
+ public function addRequiredIndexer($code)
68
+ {
69
+ if (!in_array($code, $this->_requiredIndexers)) {
70
+ $this->_requiredIndexers[] = $code;
71
+ }
72
+ return $this;
73
+ }
74
+
75
+ /**
76
+ * Clean entity data table
77
+ *
78
+ * @param string $entityType
79
+ * @return EcomDev_PHPUnit_Model_Mysql4_Fixture_Eav_Abstract
80
+ */
81
+ public function cleanEntity($entityType)
82
+ {
83
+ $entityTypeModel = Mage::getSingleton('eav/config')->getEntityType($entityType);
84
+ $this->cleanTable($entityTypeModel->getEntityTable());
85
+ return $this;
86
+ }
87
+
88
+ /**
89
+ * Loads EAV data into DB tables
90
+ *
91
+ * @param string $entityType
92
+ * @param array $values
93
+ * @return EcomDev_PHPUnit_Model_Mysql4_Fixture_Eav_Abstract
94
+ * @throws RuntimeException
95
+ */
96
+ public function loadEntity($entityType, $values)
97
+ {
98
+ $entityTypeModel = Mage::getSingleton('eav/config')->getEntityType($entityType);
99
+
100
+ $entityTableColumns = $this->_getWriteAdapter()->describeTable(
101
+ $this->getTable($entityTypeModel->getEntityTable())
102
+ );
103
+
104
+ $attributeTableColumns = $this->_getAttributeTablesColumnList($entityTypeModel);
105
+
106
+
107
+ $entities = array();
108
+ $entityValues = array();
109
+
110
+ // Custom values array is used for
111
+ // inserting custom entity data in custom tables.
112
+ // It is an associative array with table name as key,
113
+ // and rows list as value
114
+ // See getCustomTableRecords
115
+ $customValues = array();
116
+
117
+ foreach ($values as $index => &$row) {
118
+ if (!isset($row[$this->_getEntityIdField($entityTypeModel)])) {
119
+ throw new RuntimeException('Entity Id should be specified in EAV fixture');
120
+ }
121
+
122
+ // Fullfil neccessary information
123
+ $row['entity_type_id'] = $entityTypeModel->getEntityTypeId();
124
+ if (!isset($row['attribute_set_id'])) {
125
+ $row['attribute_set_id'] = $entityTypeModel->getDefaultAttributeSetId();
126
+ }
127
+
128
+ // Preparing entity table record
129
+ $entity = $this->_getTableRecord($row, $entityTableColumns);
130
+ $entities[] = $entity;
131
+
132
+ // Preparing simple attributes records
133
+ foreach ($entityTypeModel->getAttributeCollection() as $attribute) {
134
+ $attributeBackendTable = $attribute->getBackendTable();
135
+ if (!$attribute->isStatic()
136
+ && $attributeBackendTable
137
+ && isset($attributeTableColumns[$attributeBackendTable])) {
138
+
139
+ // Prepearing data for insert per attribute table
140
+ $attributeRecords = $this->_getAttributeRecords(
141
+ $row,
142
+ $attribute,
143
+ $attributeTableColumns[$attributeBackendTable]
144
+ );
145
+
146
+ if ($attributeRecords) {
147
+ if (!isset($entityValues[$attributeBackendTable])) {
148
+ $entityValues[$attributeBackendTable] = array();
149
+ }
150
+
151
+ $entityValues[$attributeBackendTable] = array_merge(
152
+ $entityValues[$attributeBackendTable],
153
+ $attributeRecords
154
+ );
155
+ }
156
+ }
157
+ }
158
+
159
+ // Processing custom entity values
160
+ $customValues = array_merge_recursive(
161
+ $customValues,
162
+ $this->_getCustomTableRecords($row, $entityTypeModel)
163
+ );
164
+ }
165
+
166
+ $this->_getWriteAdapter()->insertOnDuplicate(
167
+ $this->getTable($entityTypeModel->getEntityTable()),
168
+ $entities
169
+ );
170
+
171
+ foreach ($entityValues as $tableName => $records) {
172
+ $this->_getWriteAdapter()->insertOnDuplicate(
173
+ $tableName,
174
+ $records
175
+ );
176
+ }
177
+
178
+ foreach ($customValues as $tableName => $records) {
179
+ $this->_getWriteAdapter()->insertOnDuplicate(
180
+ (strpos($tableName, '/') !== false ? $this->getTable($tableName) : $tableName),
181
+ $records
182
+ );
183
+ }
184
+
185
+ foreach ($entities as $entity) {
186
+ $this->_customEntityAction($entity, $entityTypeModel);
187
+ }
188
+
189
+ if (empty($this->_options['doNotIndexAll'])) {
190
+ $indexer = Mage::getSingleton('index/indexer');
191
+ foreach ($this->getRequiredIndexers() as $indexerCode) {
192
+ if (empty($this->_options['doNotIndex'])
193
+ || !in_array($indexerCode, $this->_options['doNotIndex'])) {
194
+ $indexer->getProcessByCode($indexerCode)
195
+ ->reindexAll();
196
+ }
197
+ }
198
+ }
199
+
200
+ return $this;
201
+ }
202
+
203
+
204
+ /**
205
+ * Performs custom action on entity
206
+ *
207
+ * @param array $entity
208
+ * @param Mage_Eav_Model_Entity_Type $entityTypeModel
209
+ * @return EcomDev_PHPUnit_Model_Mysql4_Fixture_Eav_Abstract
210
+ */
211
+ protected function _customEntityAction($entity, $entityTypeModel)
212
+ {
213
+ return $this;
214
+ }
215
+
216
+ /**
217
+ * If you have some custom EAV tables,
218
+ * this method will help you to insert
219
+ * them on fixture processing step
220
+ * It should return an associative array, where an entry key
221
+ * is the table name and its value is a list of table rows
222
+ *
223
+ * @example
224
+ * return array(
225
+ * 'some/table' => array(
226
+ * array(
227
+ * 'field' => 'value'
228
+ * )
229
+ * )
230
+ * )
231
+ *
232
+ * @param array $row
233
+ * @param Mage_Eav_Model_Entity_Type $entityTypeModel
234
+ * @return array
235
+ */
236
+ protected function _getCustomTableRecords($row, $entityTypeModel)
237
+ {
238
+ return array();
239
+ }
240
+
241
+ /**
242
+ * Retrieves associative list of attribute tables and their columns
243
+ *
244
+ * @param Mage_Eav_Model_Entity_Type $entityTypeModel
245
+ * @return array
246
+ */
247
+ protected function _getAttributeTablesColumnList($entityTypeModel)
248
+ {
249
+ $tableNames = array_unique(
250
+ $entityTypeModel->getAttributeCollection()
251
+ ->walk('getBackendTable')
252
+ );
253
+
254
+ $columnsByTable = array();
255
+
256
+ foreach ($tableNames as $table) {
257
+ if ($table) {
258
+ $columnsByTable[$table] = $this->_getWriteAdapter()
259
+ ->describeTable(
260
+ $table
261
+ );
262
+ }
263
+ }
264
+
265
+ return $columnsByTable;
266
+ }
267
+
268
+
269
+ /**
270
+ * Retrieves attribute records for single entity
271
+ *
272
+ * @param array $row
273
+ * @param array $attribute
274
+ * @param Mage_Eav_Model_Entity_Type $entityTypeModel
275
+ */
276
+ protected function _getAttributeRecords($row, $attribute, $tableColumns)
277
+ {
278
+ $records = array();
279
+
280
+ $value = $this->_getAttributeValue($row, $attribute);
281
+
282
+ if ($value !== null) {
283
+ $valueInfo = $this->_getAttributeValueInfo($row, $attribute);
284
+ $valueInfo['value'] = $value;
285
+ $records[] = $this->_getTableRecord($valueInfo, $tableColumns);
286
+ }
287
+
288
+ return $records;
289
+ }
290
+
291
+ /**
292
+ * Returns attribute meta info for record,
293
+ * e.g. entity_type_id, attribute_id, etc
294
+ *
295
+ * @param Mage_Eav_Model_Entity_Attribute $attribute
296
+ * @return array
297
+ */
298
+ protected function _getAttributeValueInfo($row, $attribute)
299
+ {
300
+ return array(
301
+ 'attribute_id' => $attribute->getId(),
302
+ 'entity_type_id' => $attribute->getEntityTypeId(),
303
+ $this->_getEntityIdField($attribute) => $row[$this->_getEntityIdField($attribute)]
304
+ );
305
+ }
306
+
307
+
308
+ /**
309
+ * Retrieves attribute value
310
+ *
311
+ * @param array $row
312
+ * @param Mage_Eav_Model_Entity_Attribute $attribute
313
+ * @return mixed|null
314
+ */
315
+ protected function _getAttributeValue($row, $attribute)
316
+ {
317
+ if (isset($row[$attribute->getAttributeCode()]) && !is_array($row[$attribute->getAttributeCode()])) {
318
+ $value = $row[$attribute->getAttributeCode()];
319
+ } elseif ($attribute->getIsRequired()
320
+ && $attribute->getDefaultValue() !== null
321
+ && $attribute->getDefaultValue() !== ''
322
+ && !is_array($attribute->getDefaultValue())) {
323
+ $value = $attribute->getDefaultValue();
324
+ } else {
325
+ $value = null;
326
+ }
327
+
328
+ return $value;
329
+ }
330
+
331
+ /**
332
+ * Retrieves entity id field, based on entity configuration
333
+ *
334
+ * @param Mage_Eav_Model_Entity_Type|Mage_Eav_Model_Entity_Attribute $entityTypeModel
335
+ * @return string
336
+ */
337
+ protected function _getEntityIdField($entityTypeModel)
338
+ {
339
+ if ($entityTypeModel->getEntityIdField()) {
340
+ return $entityTypeModel->getEntityIdField();
341
+ }
342
+ return Mage_Eav_Model_Entity::DEFAULT_ENTITY_ID_FIELD;
343
+ }
344
+ }
app/code/community/EcomDev/PHPUnit/Model/Mysql4/Fixture/Eav/Catalog/Abstract.php ADDED
@@ -0,0 +1,141 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PHP Unit test suite for Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ *
12
+ * @category EcomDev
13
+ * @package EcomDev_PHPUnit
14
+ * @copyright Copyright (c) 2011 Ecommerce Developers (http://www.ecomdev.org)
15
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
+ * @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
17
+ */
18
+
19
+ /**
20
+ * Base Catalog EAV fixture loader
21
+ *
22
+ *
23
+ */
24
+ abstract class EcomDev_PHPUnit_Model_Mysql4_Fixture_Eav_Catalog_Abstract extends EcomDev_PHPUnit_Model_Mysql4_Fixture_Eav_Abstract
25
+ {
26
+ const SCOPE_TYPE_STORE = 'stores';
27
+ const SCOPE_TYPE_WEBSITE = 'websites';
28
+
29
+ /**
30
+ * Overriden to add GWS implementation for attribute records
31
+ *
32
+ * @param array $row
33
+ * @param Mage_Catalog_Model_Resource_Eav_Attribute $attribute
34
+ * @param array $tableColumns
35
+ * @return array
36
+ * (non-PHPdoc)
37
+ * @see EcomDev_PHPUnit_Model_Mysql4_Fixture_Eav_Abstract::_getAttributeRecords()
38
+ */
39
+ protected function _getAttributeRecords($row, $attribute, $tableColumns)
40
+ {
41
+ $records = parent::_getAttributeRecords($row, $attribute, $tableColumns);
42
+
43
+ // If the attribute is not global,
44
+ // then walk over all websites and stores scopes for attribute value
45
+ if ($attribute->isScopeStore() || $attribute->isScopeWebsite()) {
46
+ // Search for website values and fullfil data per website's store
47
+ $storeValues = array();
48
+ foreach ($this->_getGwsCodes($row, self::SCOPE_TYPE_WEBSITE) as $websiteCode) {
49
+ $website = Mage::app()->getWebsite($websiteCode);
50
+
51
+ $value = $this->_getGwsValue($row, $attribute, $websiteCode, self::SCOPE_TYPE_WEBSITE);
52
+ if ($value !== null) {
53
+ foreach ($website->getStoreIds() as $storeId) {
54
+ $storeValues[$storeId] = $value;
55
+ }
56
+ }
57
+ }
58
+
59
+ // If attribute has store scope, then override website values by store ones
60
+ if ($attribute->isScopeStore()) {
61
+ foreach ($this->_getGwsCodes($row, self::SCOPE_TYPE_STORE) as $storeCode) {
62
+ $store = Mage::app()->getStore($storeCode);
63
+ $value = $this->_getGwsValue($row, $attribute, $storeCode, self::SCOPE_TYPE_STORE);
64
+ if ($value !== null) {
65
+ $storeValues[$store->getId()] = $value;
66
+ }
67
+ }
68
+ }
69
+
70
+ // Apply collected values
71
+ $valueInfo = $this->_getAttributeValueInfo($row, $attribute);
72
+ foreach ($storeValues as $storeId => $value) {
73
+ $valueInfo['store_id'] = $storeId;
74
+ $valueInfo['value'] = $value;
75
+ $records[] = $this->_getTableRecord($valueInfo, $tableColumns);
76
+ }
77
+ }
78
+
79
+ return $records;
80
+ }
81
+
82
+ /**
83
+ * Check is available store/website values
84
+ *
85
+ * @param array $row
86
+ * @param string $scopeType
87
+ * @return boolean
88
+ */
89
+ protected function _hasGwsValues($row, $scopeType = self::SCOPE_TYPE_STORE)
90
+ {
91
+ return isset($row['/' . $scopeType]);
92
+ }
93
+
94
+ /**
95
+ * Retrieves list of websites/stores codes
96
+ *
97
+ * @param array $row
98
+ * @param string $scopeType
99
+ */
100
+ protected function _getGwsCodes($row, $scopeType = self::SCOPE_TYPE_STORE)
101
+ {
102
+ if (!$this->_hasGwsValues($row, $scopeType)) {
103
+ return array();
104
+ }
105
+
106
+ return array_keys($row['/' . $scopeType]);
107
+ }
108
+
109
+ /**
110
+ * Retrieves scope dependent value from fixture value, i.e,
111
+ * store view or
112
+ * website attribute value
113
+ *
114
+ *
115
+ * @param array $row
116
+ * @param Mage_Eav_Model_Entity_Attribute $attribute
117
+ * @param string $scopeCode
118
+ * @param string $scopeType
119
+ * @return mixed|null
120
+ */
121
+ protected function _getGwsValue($row, $attribute, $scopeCode, $scopeType = self::SCOPE_TYPE_STORE)
122
+ {
123
+ if (!isset($row['/' . $scopeType][$scopeCode]) || !is_array($row['/' . $scopeType][$scopeCode])) {
124
+ return null;
125
+ }
126
+
127
+ return $this->_getAttributeValue($row['/' . $scopeType][$scopeCode], $attribute);
128
+ }
129
+
130
+ /**
131
+ * Overriden to add default store id
132
+ * (non-PHPdoc)
133
+ * @see EcomDev_PHPUnit_Model_Mysql4_Fixture_Eav_Abstract::_getAttributeValueInfo()
134
+ */
135
+ protected function _getAttributeValueInfo($row, $attribute)
136
+ {
137
+ $info = parent::_getAttributeValueInfo($row, $attribute);
138
+ $info['store_id'] = 0;
139
+ return $info;
140
+ }
141
+ }
app/code/community/EcomDev/PHPUnit/Model/Mysql4/Fixture/Eav/Catalog/Category.php ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PHP Unit test suite for Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ *
12
+ * @category EcomDev
13
+ * @package EcomDev_PHPUnit
14
+ * @copyright Copyright (c) 2011 Ecommerce Developers (http://www.ecomdev.org)
15
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
+ * @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
17
+ */
18
+
19
+ /**
20
+ * Category EAV fixture loader
21
+ *
22
+ *
23
+ */
24
+ class EcomDev_PHPUnit_Model_Mysql4_Fixture_Eav_Catalog_Category extends EcomDev_PHPUnit_Model_Mysql4_Fixture_Eav_Catalog_Abstract
25
+ {
26
+ protected $_requiredIndexers = array(
27
+ 'catalog_category_flat'
28
+ );
29
+
30
+ /**
31
+ * Overriden to add easy fixture loading for product associations
32
+ * (non-PHPdoc)
33
+ * @see EcomDev_PHPUnit_Model_Mysql4_Fixture_Eav_Abstract::_getCustomTableRecords()
34
+ */
35
+ protected function _getCustomTableRecords($row, $entityTypeModel)
36
+ {
37
+ return $this->_getProductAssociationRecords($row, $entityTypeModel);
38
+ }
39
+
40
+
41
+ /**
42
+ * Generates records for catalog_category_product table
43
+ *
44
+ * @param array $row
45
+ * @param Mage_Eav_Model_Entity_Type $entityTypeModel
46
+ * @return array
47
+ */
48
+ protected function _getProductAssociationRecords($row, $entityTypeModel)
49
+ {
50
+ if (isset($row['products']) && is_array($row['products'])) {
51
+ $records = array();
52
+ foreach ($row['products'] as $productId => $position) {
53
+ $records[] = array(
54
+ 'category_id' => $row[$this->_getEntityIdField($entityTypeModel)],
55
+ 'product_id' => $productId,
56
+ 'position' => $position
57
+ );
58
+ }
59
+
60
+ if ($records) {
61
+ $this->addRequiredIndexer('catalog_category_product');
62
+ return array('catalog/category_product' => $records);
63
+ }
64
+ }
65
+ return array();
66
+ }
67
+ }
app/code/community/EcomDev/PHPUnit/Model/Mysql4/Fixture/Eav/Catalog/Product.php ADDED
@@ -0,0 +1,210 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PHP Unit test suite for Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ *
12
+ * @category EcomDev
13
+ * @package EcomDev_PHPUnit
14
+ * @copyright Copyright (c) 2011 Ecommerce Developers (http://www.ecomdev.org)
15
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
+ * @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
17
+ */
18
+
19
+ /**
20
+ * Product EAV fixture loader
21
+ *
22
+ *
23
+ */
24
+ class EcomDev_PHPUnit_Model_Mysql4_Fixture_Eav_Catalog_Product extends EcomDev_PHPUnit_Model_Mysql4_Fixture_Eav_Catalog_Abstract
25
+ {
26
+ protected $_requiredIndexers = array(
27
+ 'cataloginventory_stock',
28
+ 'catalog_product_flat',
29
+ 'catalog_product_attribute',
30
+ 'catalog_product_price'
31
+ );
32
+
33
+
34
+ /**
35
+ * Ovveriden to fix issue with flat tables existance mark
36
+ * (non-PHPdoc)
37
+ * @see EcomDev_PHPUnit_Model_Mysql4_Fixture_Eav_Abstract::loadEntity()
38
+ */
39
+ public function loadEntity($entityType, $values)
40
+ {
41
+ // Fix of Product Flat Indexer
42
+ EcomDev_Utils_Reflection::setRestrictedPropertyValue(
43
+ Mage::getResourceSingleton('catalog/product_flat_indexer'),
44
+ '_existsFlatTables',
45
+ array()
46
+ );
47
+
48
+ return parent::loadEntity($entityType, $values);
49
+ }
50
+
51
+ /**
52
+ * Overriden to add easy fixture loading for websites and categories associations
53
+ * (non-PHPdoc)
54
+ * @see EcomDev_PHPUnit_Model_Mysql4_Fixture_Eav_Abstract::_getCustomTableRecords()
55
+ */
56
+ protected function _getCustomTableRecords($row, $entityTypeModel)
57
+ {
58
+ $records = array();
59
+ $records += $this->_getWebsiteVisibilityRecords($row, $entityTypeModel);
60
+ $records += $this->_getTierPriceRecords($row, $entityTypeModel);
61
+ $records += $this->_getCategoryAssociationRecords($row, $entityTypeModel);
62
+ $records += $this->_getProductStockRecords($row, $entityTypeModel);
63
+ return $records;
64
+ }
65
+
66
+ /**
67
+ * Changed to support price attribute type multi-scope
68
+ * (non-PHPdoc)
69
+ * @param Mage_Eav_Model_Entity_Attribute $attribute
70
+ * @see EcomDev_PHPUnit_Model_Mysql4_Fixture_Eav_Catalog_Abstract::_getAttributeRecords()
71
+ */
72
+ protected function _getAttributeRecords($row, $attribute, $tableColumns)
73
+ {
74
+ if ($attribute->getFrontendInput() == 'price') {
75
+ $attribute->setIsGlobal(
76
+ Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_WEBSITE
77
+ );
78
+ }
79
+
80
+ return parent::_getAttributeRecords($row, $attribute, $tableColumns);
81
+ }
82
+
83
+ /**
84
+ * Generates records for catalog_product_website table
85
+ *
86
+ * @param array $row
87
+ * @param Mage_Eav_Model_Entity_Type $entityTypeModel
88
+ * @return array
89
+ * @throws RuntimeException
90
+ */
91
+ protected function _getWebsiteVisibilityRecords($row, $entityTypeModel)
92
+ {
93
+ if (isset($row['website_ids']) && is_array($row['website_ids'])) {
94
+ $records = array();
95
+ foreach ($row['website_ids'] as $websiteId) {
96
+ $website = Mage::app()->getWebsite($websiteId);
97
+ $records[] = array(
98
+ 'product_id' => $row[$this->_getEntityIdField($entityTypeModel)],
99
+ 'website_id' => $website->getId()
100
+ );
101
+ }
102
+
103
+ // We shouldn't return empty table data
104
+ if ($records) {
105
+ return array('catalog/product_website' => $records);
106
+ }
107
+ }
108
+
109
+ return array();
110
+ }
111
+
112
+ /**
113
+ * Generates records for catalog_product_entity_tier_price table
114
+ *
115
+ * @param array $row
116
+ * @param Mage_Eav_Model_Entity_Type $entityTypeModel
117
+ * @return array
118
+ */
119
+ protected function _getTierPriceRecords($row, $entityTypeModel)
120
+ {
121
+ if (isset($row['tier_price']) && is_array($row['tier_price'])) {
122
+ $tableName = $entityTypeModel->getValueTablePrefix() . '_tier_price';
123
+ $columns = $this->_getWriteAdapter()->describeTable(
124
+ $tableName
125
+ );
126
+
127
+ $records = array();
128
+ foreach ($row['tier_price'] as $tierPrice) {
129
+ $tierPrice[$this->_getEntityIdField($entityTypeModel)] = $row[$this->_getEntityIdField($entityTypeModel)];
130
+ $records[] = $this->_getTableRecord($tierPrice, $columns);
131
+ }
132
+
133
+ if ($records) {
134
+ return array($tableName => $records);
135
+ }
136
+ }
137
+ return array();
138
+ }
139
+
140
+ /**
141
+ * Generates records for catalog_category_product table
142
+ *
143
+ * @param array $row
144
+ * @param Mage_Eav_Model_Entity_Type $entityTypeModel
145
+ * @return array
146
+ */
147
+ protected function _getCategoryAssociationRecords($row, $entityTypeModel)
148
+ {
149
+ if (isset($row['category_ids']) && is_array($row['category_ids'])) {
150
+ $records = array();
151
+ foreach ($row['category_ids'] as $categoryId) {
152
+ $records[] = array(
153
+ 'category_id' => $categoryId,
154
+ 'product_id' => $row[$this->_getEntityIdField($entityTypeModel)]
155
+ );
156
+ }
157
+
158
+ if ($records) {
159
+ $this->addRequiredIndexer('catalog_category_product');
160
+ return array('catalog/category_product' => $records);
161
+ }
162
+ }
163
+ return array();
164
+ }
165
+
166
+ /**
167
+ * Generates records for cataloginventory_stock_item table
168
+ *
169
+ * @param array $row
170
+ * @param Mage_Eav_Model_Entity_Type $entityTypeModel
171
+ * @return array
172
+ */
173
+ protected function _getProductStockRecords($row, $entityTypeModel)
174
+ {
175
+ if (isset($row['stock']) && is_array($row['stock'])) {
176
+ $columns = $this->_getWriteAdapter()->describeTable(
177
+ $this->getTable('cataloginventory/stock_item')
178
+ );
179
+
180
+ $row['stock']['product_id'] = $row[$this->_getEntityIdField($entityTypeModel)];
181
+
182
+ if (!isset($row['stock']['stock_id'])) {
183
+ $row['stock']['stock_id'] = 1;
184
+ }
185
+
186
+ return array(
187
+ 'cataloginventory/stock_item' => array(
188
+ $this->_getTableRecord($row['stock'], $columns)
189
+ )
190
+ );
191
+ }
192
+ return array();
193
+ }
194
+
195
+
196
+ /**
197
+ * Adding enabled and visibility indexes
198
+ *
199
+ * (non-PHPdoc)
200
+ * @see EcomDev_PHPUnit_Model_Mysql4_Fixture_Eav_Abstract::_customEntityAction()
201
+ */
202
+ protected function _customEntityAction($entity, $entityTypeModel)
203
+ {
204
+ Mage::getResourceSingleton('catalog/product_status')
205
+ ->refreshEnabledIndex($entity[$this->_getEntityIdField($entityTypeModel)], 0);
206
+
207
+ parent::_customEntityAction($entity, $entityTypeModel);
208
+ return $this;
209
+ }
210
+ }
app/code/community/EcomDev/PHPUnit/Model/Mysql4/Fixture/Eav/Default.php ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PHP Unit test suite for Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ *
12
+ * @category EcomDev
13
+ * @package EcomDev_PHPUnit
14
+ * @copyright Copyright (c) 2011 Ecommerce Developers (http://www.ecomdev.org)
15
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
+ * @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
17
+ */
18
+
19
+ /**
20
+ * Default EAV fixture loaded
21
+ *
22
+ *
23
+ */
24
+ class EcomDev_PHPUnit_Model_Mysql4_Fixture_Eav_Default extends EcomDev_PHPUnit_Model_Mysql4_Fixture_Eav_Abstract
25
+ {
26
+
27
+ }
app/code/community/EcomDev/PHPUnit/Model/Mysql4/Fixture/Exception.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class EcomDev_PHPUnit_Model_Mysql4_Fixture_Exception extends RuntimeException
4
+ {
5
+ public function __construct($message, Exception $previous)
6
+ {
7
+ parent::__construct($message, 0, $previous);
8
+ }
9
+ }
app/code/community/EcomDev/PHPUnit/Model/Test/Loadable/Interface.php ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PHP Unit test suite for Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ *
12
+ * @category EcomDev
13
+ * @package EcomDev_PHPUnit
14
+ * @copyright Copyright (c) 2011 Ecommerce Developers (http://www.ecomdev.org)
15
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
+ * @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
17
+ */
18
+
19
+ /**
20
+ * Interface for loadable test environment data
21
+ *
22
+ */
23
+ interface EcomDev_PHPUnit_Model_Test_Loadable_Interface
24
+ {
25
+ /**
26
+ * Loads external data by test case instance
27
+ *
28
+ * @param EcomDev_PHPUnit_Test_Case $testCase
29
+ * @return EcomDev_PHPUnit_Model_Test_Loadable_Interface
30
+ */
31
+ public function loadByTestCase(EcomDev_PHPUnit_Test_Case $testCase);
32
+
33
+ /**
34
+ * Applies external data
35
+ *
36
+ * @return EcomDev_PHPUnit_Model_Test_Loadable_Interface
37
+ */
38
+ public function apply();
39
+
40
+ /**
41
+ * Reverts applied data
42
+ *
43
+ * @return EcomDev_PHPUnit_Model_Test_Loadable_Interface
44
+ */
45
+ public function discard();
46
+ }
app/code/community/EcomDev/PHPUnit/Test/Case.php ADDED
@@ -0,0 +1,804 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PHP Unit test suite for Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ *
12
+ * @category EcomDev
13
+ * @package EcomDev_PHPUnit
14
+ * @copyright Copyright (c) 2011 Ecommerce Developers (http://www.ecomdev.org)
15
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
+ * @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
17
+ */
18
+
19
+ // Loading Spyc yaml parser,
20
+ // becuase Symfony component is not working propertly with nested associations
21
+ require_once 'Spyc/spyc.php';
22
+
23
+ /**
24
+ * Basic test case class
25
+ *
26
+ *
27
+ */
28
+ abstract class EcomDev_PHPUnit_Test_Case extends PHPUnit_Framework_TestCase
29
+ {
30
+
31
+ const XML_PATH_DEFAULT_FIXTURE_MODEL = 'phpunit/suite/fixture/model';
32
+ const XML_PATH_DEFAULT_EXPECTATION_MODEL = 'phpunit/suite/expectation/model';
33
+
34
+
35
+ /**
36
+ * List of system registry values replaced by test case
37
+ *
38
+ * @var array
39
+ */
40
+ protected $_replacedRegistry = array();
41
+
42
+ /**
43
+ * The expectations for current test are loaded here
44
+ *
45
+ * @var Varien_Object|null
46
+ * @deprecated since 0.2.0
47
+ */
48
+ protected $_expectations = null;
49
+
50
+ /**
51
+ * Original store kept for tearDown,
52
+ * if was set in test method
53
+ *
54
+ * @var Mage_Core_Model_Store
55
+ */
56
+ protected $_originalStore = null;
57
+
58
+ /**
59
+ * Returns app for test case, created for type hinting
60
+ * in the test case code
61
+ *
62
+ * @return EcomDev_PHPUnit_Model_App
63
+ */
64
+ public static function app()
65
+ {
66
+ return Mage::app();
67
+ }
68
+
69
+ /**
70
+ * Asserts that event was dispatched at least once
71
+ *
72
+ * @param string|array $event
73
+ * @param string $message
74
+ */
75
+ public static function assertEventDispatched($eventName)
76
+ {
77
+ if (is_array($eventName)) {
78
+ foreach ($eventNames as $eventName) {
79
+ self::assertEventDispatched($eventName);
80
+ }
81
+ return;
82
+ }
83
+
84
+ $actual = self::app()->getDispatchedEventCount($eventName);
85
+ $message = sprintf('%s event was not dispatched', $eventName);
86
+ self::assertGreaterThanOrEqual(1, $actual, $message);
87
+ }
88
+
89
+ /**
90
+ * Asserts that event was not dispatched
91
+ *
92
+ * @param string|array $event
93
+ * @param string $message
94
+ */
95
+ public static function assertEventNotDispatched($eventName)
96
+ {
97
+ if (is_array($eventName)) {
98
+ foreach ($eventNames as $eventName) {
99
+ self::assertEventNotDispatched($eventName);
100
+ }
101
+ return;
102
+ }
103
+
104
+ $actual = self::app()->getDispatchedEventCount($eventName);
105
+ $message = sprintf('%s event was dispatched', $eventName);
106
+ self::assertEquals(0, $actual, $message);
107
+ }
108
+
109
+ /**
110
+ * Assert that event was dispatched exactly $times
111
+ *
112
+ * @param string $eventName
113
+ * @param int
114
+ */
115
+ public static function assertEventDispatchedExactly($eventName, $times)
116
+ {
117
+ $actual = self::app()->getDispatchedEventCount($eventName);
118
+ $message = sprintf(
119
+ '%s event was dispatched only %d times, but expected to be dispatched %d times',
120
+ $eventName, $actual, $times
121
+ );
122
+
123
+ self::assertEquals($times, $actual, $message);
124
+ }
125
+
126
+ /**
127
+ * Assert that event was dispatched at least $times
128
+ *
129
+ * @param string $eventName
130
+ * @param int
131
+ */
132
+ public static function assertEventDispatchedAtLeast($eventName, $times)
133
+ {
134
+ $actual = self::app()->getDispatchedEventCount($eventName);
135
+ $message = sprintf(
136
+ '%s event was dispatched only %d times, but expected to be dispatched at least %d times',
137
+ $eventName, $actual, $times
138
+ );
139
+
140
+ self::assertGreaterThanOrEqual($times, $actual, $message);
141
+ }
142
+
143
+ /**
144
+ * Creates a constraint for checking that string is valid JSON
145
+ *
146
+ * @return EcomDev_PHPUnit_Constraint_Json
147
+ */
148
+ public static function isJson()
149
+ {
150
+ return new EcomDev_PHPUnit_Constraint_Json(
151
+ EcomDev_PHPUnit_Constraint_Json::TYPE_VALID
152
+ );
153
+ }
154
+
155
+ /**
156
+ * Creates a constraint for checking that string
157
+ * is matched expected JSON structure
158
+ *
159
+ * @param array $expectedValue
160
+ * @param strign $matchType
161
+ * @return EcomDev_PHPUnit_Constraint_Json
162
+ */
163
+ public static function matchesJson(array $expectedValue, $matchType = EcomDev_PHPUnit_Constraint_Json::MATCH_AND)
164
+ {
165
+ return new EcomDev_PHPUnit_Constraint_Json(
166
+ EcomDev_PHPUnit_Constraint_Json::TYPE_MATCH,
167
+ $expectedValue,
168
+ $matchType
169
+ );
170
+ }
171
+
172
+ /**
173
+ * Assert that string is a valid JSON
174
+ *
175
+ * @param string $string
176
+ * @param string $message
177
+ */
178
+ public static function assertJson($string, $message = '')
179
+ {
180
+ self::assertThat($string, self::isJson(), $message);
181
+ }
182
+
183
+ /**
184
+ * Assert that string is not a valid JSON
185
+ *
186
+ * @param string $string
187
+ * @param string $message
188
+ */
189
+ public static function assertNotJson($string, $message = '')
190
+ {
191
+ self::assertThat($string, self::logicalNot(self::isJson()), $message);
192
+ }
193
+
194
+ /**
195
+ * Assert that JSON string matches expected value,
196
+ * Can accept different match type for matching logic.
197
+ *
198
+ * @param string $string
199
+ * @param array $expectedValue
200
+ * @param string $message
201
+ * @param strign $matchType
202
+ */
203
+ public static function assertJsonMatch($string, array $expectedValue, $message = '',
204
+ $matchType = EcomDev_PHPUnit_Constraint_Json::MATCH_AND)
205
+ {
206
+ self::assertThat(
207
+ $string,
208
+ self::matchesJson($expectedValue, $matchType),
209
+ $message
210
+ );
211
+ }
212
+
213
+ /**
214
+ * Assert that JSON string doesn't matches expected value,
215
+ * Can accept different match type for matching logic.
216
+ *
217
+ * @param string $string
218
+ * @param array $expectedValue
219
+ * @param string $message
220
+ * @param strign $matchType
221
+ */
222
+ public static function assertJsonNotMatch($string, array $expectedValue, $message = '',
223
+ $matchType = EcomDev_PHPUnit_Constraint_Json::MATCH_AND)
224
+ {
225
+ self::assertThat(
226
+ $string,
227
+ self::logicalNot(
228
+ self::matchesJson($expectedValue, $matchType)
229
+ ),
230
+ $message
231
+ );
232
+ }
233
+
234
+
235
+ /**
236
+ * Retrieves the module name for current test case
237
+ *
238
+ * @return string
239
+ * @throws RuntimeException if module name was not found for the passed class name
240
+ */
241
+ public function getModuleName()
242
+ {
243
+ return $this->app()->getModuleNameByClassName($this);
244
+ }
245
+
246
+ /**
247
+ * Retrieves module name from call stack objects
248
+ *
249
+ * @return string
250
+ * @throws RuntimeException if assertion is called in not from EcomDev_PHPUnit_Test_Case
251
+ */
252
+ protected static function getModuleNameFromCallStack()
253
+ {
254
+ $backTrace = debug_backtrace(true);
255
+ foreach ($backTrace as $call) {
256
+ if (isset($call['object']) && $call['object'] instanceof EcomDev_PHPUnit_Test_Case) {
257
+ return $call['object']->getModuleName();
258
+ }
259
+ }
260
+
261
+ throw new RuntimeException('Unable to retrieve module name from call stack, because assertion is not called from EcomDev_PHPUnit_Test_Case based class method');
262
+ }
263
+
264
+
265
+ /**
266
+ * Retrieves annotation by its name from different sources (class, method)
267
+ *
268
+ *
269
+ * @param string $name
270
+ * @param array|string $sources
271
+ * @return array
272
+ */
273
+ public function getAnnotationByName($name, $sources = 'method')
274
+ {
275
+ if (is_string($sources)) {
276
+ $sources = array($sources);
277
+ }
278
+
279
+ $allAnnotations = $this->getAnnotations();
280
+ $annotation = array();
281
+
282
+ // Walkthrough sources for annotation retrieval
283
+ foreach ($sources as $source) {
284
+ if (isset($allAnnotations[$source][$name])) {
285
+ $annotation = array_merge(
286
+ $allAnnotations[$source][$name],
287
+ $annotation
288
+ );
289
+ }
290
+ }
291
+
292
+ return $annotation;
293
+ }
294
+
295
+ /**
296
+ * Loads expectations for current test case
297
+ *
298
+ * @throws RuntimeException if no expectation was found
299
+ * @return Varien_Object
300
+ * @deprecated since 0.2.0, use self::expected() instead.
301
+ */
302
+ protected function _getExpectations()
303
+ {
304
+ $arguments = func_get_args();
305
+
306
+ return $this->expected($arguments);
307
+ }
308
+
309
+ /**
310
+ * Replaces Magento resource by mock object
311
+ *
312
+ *
313
+ * @param string $type
314
+ * @param string $classAlias
315
+ * @param PHPUnit_Framework_MockObject_MockObject|PHPUnit_Framework_MockObject_MockBuilder $mock
316
+ * @return EcomDev_PHPUnit_Test_Case
317
+ */
318
+ protected function replaceByMock($type, $classAlias, $mock)
319
+ {
320
+ if ($mock instanceof PHPUnit_Framework_MockObject_MockBuilder) {
321
+ $mock = $mock->getMock();
322
+ } elseif (!$mock instanceof PHPUnit_Framework_MockObject_MockObject) {
323
+ throw PHPUnit_Util_InvalidArgumentHelper::factory(
324
+ 1, 'PHPUnit_Framework_MockObject_MockObject'
325
+ );
326
+ }
327
+
328
+
329
+ if ($type == 'helper' && strpos($classAlias, '/') === false) {
330
+ $classAlias .= '/data';
331
+ }
332
+
333
+ if (in_array($type, array('model', 'resource_model'))) {
334
+ $this->app()->getConfig()->replaceInstanceCreation($type, $classAlias, $mock);
335
+ $type = str_replace('model', 'singleton', $type);
336
+ } elseif ($type == 'block') {
337
+ $this->app()->getLayout()->replaceBlockCreation($classAlias, $mock);
338
+ }
339
+
340
+ if (in_array($type, array('singleton', 'resource_singleton', 'helper'))) {
341
+ $registryPath = '_' . $type . '/' . $classAlias;
342
+ $this->replaceRegistry($registryPath, $mock);
343
+ }
344
+
345
+ return $this;
346
+ }
347
+
348
+ /**
349
+ * Replaces value in Magento system registry
350
+ *
351
+ * @param string $key
352
+ * @param mixed $value
353
+ */
354
+ protected function replaceRegistry($key, $value)
355
+ {
356
+ $oldValue = Mage::registry($key);
357
+
358
+ $this->app()->replaceRegistry($key, $value);
359
+
360
+ $this->_replacedRegistry[$key] = $oldValue;
361
+ return $this;
362
+ }
363
+
364
+ /**
365
+ * Shortcut for expectation data object retrieval
366
+ * Can be called with arguments array or in usual method
367
+ *
368
+ * @param string|array $pathFormat
369
+ * @param mixed $arg1
370
+ * @param mixed $arg2 ...
371
+ * @return Varien_Object
372
+ */
373
+ protected function expected($firstArgument = null)
374
+ {
375
+ if (!$this->getExpectation()->isLoaded()) {
376
+ $this->getExpectation()->loadByTestCase($this);
377
+ $this->getExpectation()->apply();
378
+ }
379
+
380
+ if (!is_array($firstArgument)) {
381
+ $arguments = func_get_args();
382
+ } else {
383
+ $arguments = $firstArgument;
384
+ }
385
+
386
+ $pathFormat = null;
387
+ if ($arguments) {
388
+ $pathFormat = array_shift($arguments);
389
+ }
390
+
391
+ return $this->getExpectation()
392
+ ->getDataObject($pathFormat, $arguments);
393
+ }
394
+
395
+ /**
396
+ * Retrieve mock builder for grouped class alias
397
+ *
398
+ * @param string $type block|model|helper
399
+ * @param string $classAlias
400
+ * @return PHPUnit_Framework_MockObject_MockBuilder
401
+ */
402
+ public function getGroupedClassMockBuilder($type, $classAlias)
403
+ {
404
+ $className = $this->getGroupedClassName($type, $classAlias);
405
+
406
+ return $this->getMockBuilder($className);
407
+ }
408
+
409
+ /**
410
+ * Retrieves a mock builder for a block class alias
411
+ *
412
+ * @param string $classAlias
413
+ * @return PHPUnit_Framework_MockObject_MockBuilder
414
+ */
415
+ public function getBlockMockBuilder($classAlias)
416
+ {
417
+ return $this->getGroupedClassMockBuilder('block', $classAlias);
418
+ }
419
+
420
+ /**
421
+ * Retrieves a mock builder for a model class alias
422
+ *
423
+ * @param string $classAlias
424
+ * @return PHPUnit_Framework_MockObject_MockBuilder
425
+ */
426
+ public function getModelMockBuilder($classAlias)
427
+ {
428
+ return $this->getGroupedClassMockBuilder('model', $classAlias);
429
+ }
430
+
431
+ /**
432
+ * Retrieves a mock builder for a resource model class alias
433
+ *
434
+ * @param string $classAlias
435
+ * @return PHPUnit_Framework_MockObject_MockBuilder
436
+ */
437
+ public function getResourceModelMockBuilder($classAlias)
438
+ {
439
+ return $this->getGroupedClassMockBuilder('resource_model', $classAlias);
440
+ }
441
+
442
+ /**
443
+ * Retrieves a mock builder for a helper class alias
444
+ *
445
+ * @param string $classAlias
446
+ * @return PHPUnit_Framework_MockObject_MockBuilder
447
+ */
448
+ public function getHelperMockBuilder($classAlias)
449
+ {
450
+ return $this->getGroupedClassMockBuilder('helper', $classAlias);
451
+ }
452
+
453
+ /**
454
+ * Retrieves a mock object for the specified model class alias.
455
+ *
456
+ * @param string $classAlias
457
+ * @param array $methods
458
+ * @param boolean $isAbstract
459
+ * @param array $constructorArguments
460
+ * @param string $mockClassAlias
461
+ * @param boolean $callOriginalConstructor
462
+ * @param boolean $callOriginalClone
463
+ * @param boolean $callAutoload
464
+ * @return PHPUnit_Framework_MockObject_MockObject
465
+ */
466
+ public function getModelMock($classAlias, $methods = array(), $isAbstract = false,
467
+ array $constructorArguments = array(),
468
+ $mockClassAlias = '', $callOriginalConstructor = true,
469
+ $callOriginalClone = true, $callAutoload = true)
470
+ {
471
+ return $this->getGroupedClassMock('model', $classAlias, $methods, $isAbstract,
472
+ $constructorArguments, $mockClassAlias,
473
+ $callOriginalConstructor, $callOriginalClone,
474
+ $callAutoload);
475
+ }
476
+
477
+ /**
478
+ * Retrieves a mock object for the specified resource model class alias.
479
+ *
480
+ * @param string $classAlias
481
+ * @param array $methods
482
+ * @param boolean $isAbstract
483
+ * @param array $constructorArguments
484
+ * @param string $mockClassAlias
485
+ * @param boolean $callOriginalConstructor
486
+ * @param boolean $callOriginalClone
487
+ * @param boolean $callAutoload
488
+ * @return PHPUnit_Framework_MockObject_MockObject
489
+ */
490
+ public function getResourceModelMock($classAlias, $methods = array(), $isAbstract = false,
491
+ array $constructorArguments = array(),
492
+ $mockClassAlias = '', $callOriginalConstructor = true,
493
+ $callOriginalClone = true, $callAutoload = true)
494
+ {
495
+ return $this->getGroupedClassMock('resource_model', $classAlias, $methods, $isAbstract,
496
+ $constructorArguments, $mockClassAlias,
497
+ $callOriginalConstructor, $callOriginalClone,
498
+ $callAutoload);
499
+ }
500
+
501
+ /**
502
+ * Retrieves a mock object for the specified helper class alias.
503
+ *
504
+ * @param string $classAlias
505
+ * @param array $methods
506
+ * @param boolean $isAbstract
507
+ * @param array $constructorArguments
508
+ * @param string $mockClassAlias
509
+ * @param boolean $callOriginalConstructor
510
+ * @param boolean $callOriginalClone
511
+ * @param boolean $callAutoload
512
+ * @return PHPUnit_Framework_MockObject_MockObject
513
+ */
514
+ public function getHelperMock($classAlias, $methods = array(), $isAbstract = false,
515
+ array $constructorArguments = array(),
516
+ $mockClassAlias = '', $callOriginalConstructor = true,
517
+ $callOriginalClone = true, $callAutoload = true)
518
+ {
519
+ return $this->getGroupedClassMock('helper', $classAlias, $methods, $isAbstract,
520
+ $constructorArguments, $mockClassAlias,
521
+ $callOriginalConstructor, $callOriginalClone,
522
+ $callAutoload);
523
+ }
524
+
525
+ /**
526
+ * Retrieves a mock object for the specified helper class alias.
527
+ *
528
+ * @param string $classAlias
529
+ * @param array $methods
530
+ * @param boolean $isAbstract
531
+ * @param array $constructorArguments
532
+ * @param string $mockClassAlias
533
+ * @param boolean $callOriginalConstructor
534
+ * @param boolean $callOriginalClone
535
+ * @param boolean $callAutoload
536
+ * @return PHPUnit_Framework_MockObject_MockObject
537
+ */
538
+ public function getBlockMock($classAlias, $methods = array(), $isAbstract = false,
539
+ array $constructorArguments = array(),
540
+ $mockClassAlias = '', $callOriginalConstructor = true,
541
+ $callOriginalClone = true, $callAutoload = true)
542
+ {
543
+ return $this->getGroupedClassMock('block', $classAlias, $methods, $isAbstract,
544
+ $constructorArguments, $mockClassAlias,
545
+ $callOriginalConstructor, $callOriginalClone,
546
+ $callAutoload);
547
+ }
548
+
549
+ /**
550
+ * Returns class name by grouped class alias
551
+ *
552
+ * @param string $type block/model/helper/resource_model
553
+ * @param string $classAlias
554
+ */
555
+ protected function getGroupedClassName($type, $classAlias)
556
+ {
557
+ if ($type === 'resource_model') {
558
+ return $this->app()->getConfig()->getResourceModelClassName($classAlias);
559
+ }
560
+
561
+ return $this->app()->getConfig()->getGroupedClassName($type, $classAlias);
562
+ }
563
+
564
+ /**
565
+ * Retrieves a mock object for the specified grouped class alias.
566
+ *
567
+ * @param string $type
568
+ * @param string $classAlias
569
+ * @param array $methods
570
+ * @param boolean $isAbstract
571
+ * @param array $constructorArguments
572
+ * @param string $mockClassAlias
573
+ * @param boolean $callOriginalConstructor
574
+ * @param boolean $callOriginalClone
575
+ * @param boolean $callAutoload
576
+ * @return PHPUnit_Framework_MockObject_MockObject
577
+ */
578
+ public function getGroupedClassMock($type, $classAlias, array $methods = array(), $isAbstract = false,
579
+ array $constructorArguments = array(),
580
+ $mockClassAlias = '', $callOriginalConstructor = true,
581
+ $callOriginalClone = true, $callAutoload = true)
582
+ {
583
+ if (!empty($mockClassAlias)) {
584
+ $mockClassName = $this->getGroupedClassName($type, $mockClassAlias);
585
+ } else {
586
+ $mockClassName = '';
587
+ }
588
+
589
+ $mockBuilder = $this->getGroupedClassMockBuilder($type, $classAlias);
590
+
591
+ if ($callOriginalConstructor === false) {
592
+ $mockBuilder->disableOriginalConstructor();
593
+ }
594
+
595
+ if ($callOriginalClone === false) {
596
+ $mockBuilder->disableOriginalClone();
597
+ }
598
+
599
+ if ($callAutoload === false) {
600
+ $mockBuilder->disableAutoload();
601
+ }
602
+
603
+ $mockBuilder->setMethods($methods);
604
+ $mockBuilder->setConstructorArgs($constructorArguments);
605
+ $mockBuilder->setMockClassName($mockClassName);
606
+
607
+ if ($isAbstract) {
608
+ return $mockBuilder->getMockForAbstractClass();
609
+ }
610
+
611
+ return $mockBuilder->getMock();
612
+ }
613
+
614
+ /**
615
+ * Retrieves fixture model singleton
616
+ *
617
+ * @return EcomDev_PHPUnit_Model_Fixture
618
+ * @deprecated since 0.2.0 use getFixture() method instead
619
+ */
620
+ protected function _getFixture()
621
+ {
622
+ return $this->getFixture();
623
+ }
624
+
625
+ /**
626
+ * Retrieves fixture model singleton
627
+ *
628
+ * @return EcomDev_PHPUnit_Model_Fixture
629
+ */
630
+ protected function getFixture()
631
+ {
632
+ return Mage::getSingleton($this->getLoadableClassAlias(
633
+ 'fixture',
634
+ self::XML_PATH_DEFAULT_FIXTURE_MODEL
635
+ ));;
636
+ }
637
+
638
+ /**
639
+ * Returns expectation model singleton
640
+ *
641
+ * @return EcomDev_PHPUnit_Model_Expectation
642
+ */
643
+ protected function getExpectation()
644
+ {
645
+ return Mage::getSingleton($this->getLoadableClassAlias(
646
+ 'expectation',
647
+ self::XML_PATH_DEFAULT_EXPECTATION_MODEL
648
+ ));
649
+ }
650
+
651
+
652
+ /**
653
+ * Retrieves loadable class alias from annotation or configuration node
654
+ * E.g. class alias for fixture model can be specified via @fixtureModel annotation
655
+ *
656
+ * @param string $type
657
+ * @param string $configPath
658
+ */
659
+ protected function getLoadableClassAlias($type, $configPath)
660
+ {
661
+ $annotationValue = $this->getAnnotationByName($type .'Model' , 'class');
662
+
663
+ if (current($annotationValue)) {
664
+ $classAlias = current($annotationValue);
665
+ } else {
666
+ $classAlias = $this->app()->getConfig()->getNode($configPath);
667
+ }
668
+
669
+ return $classAlias;
670
+ }
671
+
672
+ /**
673
+ * Protected wrapper for _getYamlFilePath method. Backward campatibility.
674
+ *
675
+ * @see EcomDev_PHPUnit_Test_Case::getYamlFilePath()
676
+ *
677
+ * @param string $type type of YAML data (fixtures,expectations,dataproviders)
678
+ * @param string|null $name the file name for loading, if equals to null,
679
+ * the current test name will be used
680
+ * @return string|boolean
681
+ * @deprecated since 0.2.0
682
+ */
683
+ protected function _getYamlFilePath($type, $name = null)
684
+ {
685
+ return $this->getYamlFilePath($type, $name);
686
+ }
687
+
688
+ /**
689
+ * Loads YAML file from directory inside of the unit test class
690
+ *
691
+ * @param string $type type of YAML data (fixtures,expectations,dataproviders)
692
+ * @param string|null $name the file name for loading, if equals to null,
693
+ * the current test name will be used
694
+ * @return string|boolean
695
+ */
696
+ public function getYamlFilePath($type, $name = null)
697
+ {
698
+ if ($name === null) {
699
+ $name = $this->getName(false);
700
+ }
701
+
702
+ if (strrpos($name, '.yaml') !== strlen($name) - 5) {
703
+ $name .= '.yaml';
704
+ }
705
+
706
+ $classFileObject = new SplFileInfo(
707
+ EcomDev_Utils_Reflection::getRelflection($this)->getFileName()
708
+ );
709
+
710
+ $filePath = $classFileObject->getPath() . DS
711
+ . $classFileObject->getBasename('.php') . DS
712
+ . $type . DS . $name;
713
+
714
+ if (file_exists($filePath)) {
715
+ return $filePath;
716
+ }
717
+
718
+ return false;
719
+ }
720
+
721
+ /**
722
+ * Initializes a particular test environment
723
+ *
724
+ * (non-PHPdoc)
725
+ * @see PHPUnit_Framework_TestCase::setUp()
726
+ */
727
+ protected function setUp()
728
+ {
729
+ $this->getFixture()->loadByTestCase($this);
730
+
731
+ $annotations = $this->getAnnotations();
732
+ $this->getFixture()->setOptions($annotations['method']);
733
+ $this->getFixture()->apply();
734
+ $this->app()->resetDispatchedEvents();
735
+ parent::setUp();
736
+ }
737
+
738
+ /**
739
+ * Implements default data provider functionality,
740
+ * returns array data loaded from Yaml file with the same name as test method
741
+ *
742
+ * @param string $testName
743
+ * @return array
744
+ */
745
+ public function dataProvider($testName)
746
+ {
747
+ $this->setName($testName);
748
+ $filePath = $this->getYamlFilePath('providers');
749
+ $this->setName(null);
750
+
751
+ if (!$filePath) {
752
+ throw new RuntimeException('Unable to load data provider for the current test');
753
+ }
754
+
755
+ return Spyc::YAMLLoad($filePath);
756
+ }
757
+
758
+ /**
759
+ * Set current store scope for test
760
+ *
761
+ * @param int|string|Mage_Core_Model_Store $store
762
+ * @return EcomDev_PHPUnit_Test_Case
763
+ */
764
+ public function setCurrentStore($store)
765
+ {
766
+ if (!$this->_originalStore) {
767
+ $this->_originalStore = $this->app()->getStore();
768
+ }
769
+
770
+ $this->app()->setCurrentStore(
771
+ $this->app()->getStore($store)
772
+ );
773
+ return $this;
774
+ }
775
+
776
+ /**
777
+ * Performs a clean up after a particular test was run
778
+ * (non-PHPdoc)
779
+ * @see PHPUnit_Framework_TestCase::tearDown()
780
+ */
781
+ protected function tearDown()
782
+ {
783
+ if ($this->_originalStore) { // Remove store scope, that was set in test
784
+ $this->app()->setCurrentStore($this->_originalStore);
785
+ $this->_originalStore = null;
786
+ }
787
+
788
+ if ($this->getExpectation()->isLoaded()) {
789
+ $this->getExpectation()->discard();
790
+ }
791
+
792
+ $this->app()->getConfig()->flushReplaceInstanceCreation();
793
+ $this->app()->getLayout()->flushReplaceBlockCreation();
794
+
795
+ foreach ($this->_replacedRegistry as $registryPath => $originalValue) {
796
+ $this->app()->replaceRegistry($registryPath, $originalValue);
797
+ }
798
+
799
+ $this->getFixture()->discard(); // Clear applied fixture
800
+ parent::tearDown();
801
+ }
802
+
803
+
804
+ }
app/code/community/EcomDev/PHPUnit/Test/Case/Config.php ADDED
@@ -0,0 +1,916 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PHP Unit test suite for Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ *
12
+ * @category EcomDev
13
+ * @package EcomDev_PHPUnit
14
+ * @copyright Copyright (c) 2011 Ecommerce Developers (http://www.ecomdev.org)
15
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
+ * @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
17
+ */
18
+
19
+
20
+ /**
21
+ * Base test case for testing module configurations
22
+ *
23
+ */
24
+ abstract class EcomDev_PHPUnit_Test_Case_Config extends EcomDev_PHPUnit_Test_Case
25
+ {
26
+ /**
27
+ * Returns a new instance of EcomDev_PHPUnit_Constraint_Config
28
+ *
29
+ * @param EcomDev_PHPUnit_Constraint_Config_Interface $configContstraint
30
+ * @return EcomDev_PHPUnit_Constraint_Config
31
+ */
32
+ public static function config($configContstraint)
33
+ {
34
+ return new EcomDev_PHPUnit_Constraint_Config($configContstraint);
35
+ }
36
+
37
+ /**
38
+ * A new constraint for checking node value
39
+ *
40
+ * @param string $nodePath
41
+ * @param string $type
42
+ * @param mixed $expectedValue
43
+ */
44
+ public static function configNode($nodePath, $type, $expectedValue = null)
45
+ {
46
+ return self::config(
47
+ new EcomDev_PHPUnit_Constraint_Config_Node($nodePath, $type, $expectedValue)
48
+ );
49
+ }
50
+
51
+ /**
52
+ * A new constraint for checking module node
53
+ *
54
+ * @param string $moduleName
55
+ * @param string $type
56
+ * @param string|null $expectedValue
57
+ */
58
+ public static function configModule($moduleName, $type, $expectedValue = null)
59
+ {
60
+ return self::config(
61
+ new EcomDev_PHPUnit_Constraint_Config_Module($moduleName, $type, $expectedValue)
62
+ );
63
+ }
64
+
65
+ /**
66
+ * A new constraint for checking module node
67
+ *
68
+ * @param string $moduleName
69
+ * @param string $type
70
+ * @param string|null $expectedValue
71
+ */
72
+ public static function configClassAlias($group, $classAlias, $expectedClassName,
73
+ $type = EcomDev_PHPUnit_Constraint_Config_ClassAlias::TYPE_CLASS_ALIAS)
74
+ {
75
+ return self::config(
76
+ new EcomDev_PHPUnit_Constraint_Config_ClassAlias($group, $classAlias, $expectedClassName, $type)
77
+ );
78
+ }
79
+
80
+ /**
81
+ * Creates layout constraint
82
+ *
83
+ * @param string $area
84
+ * @param string $expectedFile
85
+ * @param string $type
86
+ * @param string|null $layoutUpdate
87
+ * @param string|null $theme
88
+ * @param string|null $designPackage
89
+ */
90
+ public static function configLayout($area, $expectedFile, $type, $layoutUpdate = null, $theme = null, $designPackage = null)
91
+ {
92
+ if (!EcomDev_PHPUnit_Constraint_Config_Layout::getDesignPackageModel()) {
93
+ EcomDev_PHPUnit_Constraint_Config_Layout::setDesignPackageModel(Mage::getModel('ecomdev_phpunit/design_package'));
94
+ }
95
+
96
+ return self::config(
97
+ new EcomDev_PHPUnit_Constraint_Config_Layout($area, $expectedFile, $type, $layoutUpdate, $theme, $designPackage)
98
+ );
99
+ }
100
+
101
+ /**
102
+ * Constraint for testing observer
103
+ * event definitions in configuration
104
+ *
105
+ * @param string $area
106
+ * @param string $eventName
107
+ * @param string $observerClassAlias
108
+ * @param string $observerMethod
109
+ * @param string|null $observerName
110
+ */
111
+ public static function configEventObserver($area, $eventName, $observerClassAlias, $observerMethod,
112
+ $type = EcomDev_PHPUnit_Constraint_Config_EventObserver::TYPE_DEFINDED, $observerName = null)
113
+ {
114
+ return self::config(
115
+ new EcomDev_PHPUnit_Constraint_Config_EventObserver($area, $eventName, $observerClassAlias, $observerMethod, $type, $observerName)
116
+ );
117
+ }
118
+
119
+ /**
120
+ * Executes configuration constraint
121
+ *
122
+ * @param EcomDev_PHPUnit_Constraint_Config $constraint
123
+ * @param string $message
124
+ */
125
+ public static function assertThatConfig(EcomDev_PHPUnit_Constraint_Config $constraint, $message)
126
+ {
127
+ self::assertThat(Mage::getConfig(), $constraint, $message);
128
+ }
129
+
130
+ /**
131
+ * Asserts that config node value is equal to the expected value.
132
+ *
133
+ *
134
+ * @param string $nodePath
135
+ * @param mixed $expectedValue
136
+ * @param string $message
137
+ * @param string $type type of assertion (string, xml, child, etc)
138
+ */
139
+ public static function assertConfigNodeValue($nodePath, $expectedValue, $message = '',
140
+ $type = EcomDev_PHPUnit_Constraint_Config_Node::TYPE_EQUALS_STRING)
141
+ {
142
+ self::assertThatConfig(
143
+ self::configNode($nodePath, $type, $expectedValue),
144
+ $message
145
+ );
146
+ }
147
+
148
+ /**
149
+ * Asserts that config node value is not equal to the expected value.
150
+ *
151
+ *
152
+ * @param string $nodePath
153
+ * @param mixed $expectedValue
154
+ * @param string $message
155
+ * @param string $type type of assertion (EcomDev_PHPUnit_Constraint_Config_Node::TYPE_*)
156
+ */
157
+ public static function assertConfigNodeNotValue($nodePath, $expectedValue, $message = '',
158
+ $type = EcomDev_PHPUnit_Constraint_Config_Node::TYPE_EQUALS_STRING)
159
+ {
160
+ self::assertThatConfig(
161
+ self::logicalNot(
162
+ self::configNode($nodePath, $type, $expectedValue)
163
+ ),
164
+ $message
165
+ );
166
+ }
167
+
168
+
169
+ /**
170
+ * Assert that configuration node $nodePath has child with tag name $childName
171
+ *
172
+ * @param string $nodePath
173
+ * @param string $childName
174
+ * @param string $message
175
+ */
176
+ public static function assertConfigNodeHasChild($nodePath, $childName, $message = '')
177
+ {
178
+ self::assertConfigNodeValue(
179
+ $nodePath, $childName, $message,
180
+ EcomDev_PHPUnit_Constraint_Config_Node::TYPE_HAS_CHILD
181
+ );
182
+ }
183
+
184
+ /**
185
+ * Assert that configuration node $nodePath doesn't have child with tag name $childName
186
+ *
187
+ * @param string $nodePath
188
+ * @param string $childName
189
+ * @param string $message
190
+ */
191
+ public static function assertConfigNodeNotHasChild($nodePath, $childName, $message = '')
192
+ {
193
+ self::assertConfigNodeNotValue(
194
+ $nodePath, $childName, $message,
195
+ EcomDev_PHPUnit_Constraint_Config_Node::TYPE_HAS_CHILD
196
+ );
197
+ }
198
+
199
+ /**
200
+ * Assert that configuration node $nodePath has children
201
+ *
202
+ * @param string $nodePath
203
+ * @param string $message
204
+ */
205
+ public static function assertConfigNodeHasChildren($nodePath, $message = '')
206
+ {
207
+ self::assertConfigNodeValue(
208
+ $nodePath, null, $message,
209
+ EcomDev_PHPUnit_Constraint_Config_Node::TYPE_HAS_CHILDREN
210
+ );
211
+ }
212
+
213
+ /**
214
+ * Assert config node $nodePath doesn't have children
215
+ *
216
+ * @param string $nodePath
217
+ * @param string $message
218
+ */
219
+ public static function assertConfigNodeNotHasChildren($nodePath, $message = '')
220
+ {
221
+ self::assertConfigNodeNotValue(
222
+ $nodePath, null, $message,
223
+ EcomDev_PHPUnit_Constraint_Config_Node::TYPE_HAS_CHILDREN
224
+ );
225
+ }
226
+
227
+ /**
228
+ * Assert that configuration node $nodePath contains $expectedValue in comma separated value list
229
+ *
230
+ * @param string $nodePath
231
+ * @param scalar $expectedValue
232
+ * @param string $message
233
+ */
234
+ public static function assertConfigNodeContainsValue($nodePath, $expectedValue, $message = '')
235
+ {
236
+ self::assertConfigNodeValue(
237
+ $nodePath, $expectedValue, $message,
238
+ EcomDev_PHPUnit_Constraint_Config_Node::TYPE_CONTAIN_VALUE
239
+ );
240
+ }
241
+
242
+ /**
243
+ * Assert that configuration node $nodePath doesn't contain $expectedValue in comma separated value list
244
+ *
245
+ * @param string $nodePath
246
+ * @param scalar $expectedValue
247
+ * @param string $message
248
+ */
249
+ public static function assertConfigNodeNotContainsValue($nodePath, $expectedValue, $message = '')
250
+ {
251
+ self::assertConfigNodeValue(
252
+ $nodePath, $expectedValue, $message,
253
+ EcomDev_PHPUnit_Constraint_Config_Node::TYPE_CONTAIN_VALUE
254
+ );
255
+ }
256
+
257
+ /**
258
+ * Assert config node is equal to content of simple xml element
259
+ *
260
+ * @param string $nodePath
261
+ * @param SimpleXmlElement $simpleXml
262
+ * @param string $message
263
+ */
264
+ public static function assertConfigNodeSimpleXml($nodePath, SimpleXmlElement $simpleXml, $message = '')
265
+ {
266
+ self::assertConfigNodeValue(
267
+ $nodePath, $simpleXml, $message,
268
+ EcomDev_PHPUnit_Constraint_Config_Node::TYPE_EQUALS_XML
269
+ );
270
+ }
271
+
272
+ /**
273
+ * Assert config node is not equal to content of simple xml element
274
+ *
275
+ * @param string $nodePath
276
+ * @param SimpleXmlElement $simpleXml
277
+ * @param string $message
278
+ */
279
+ public static function assertConfigNodeNotSimpleXml($nodePath, SimpleXmlElement $simpleXml, $message = '')
280
+ {
281
+ self::assertConfigNodeNotValue(
282
+ $nodePath, $simpleXml, $message,
283
+ EcomDev_PHPUnit_Constraint_Config_Node::TYPE_EQUALS_XML
284
+ );
285
+ }
286
+
287
+ /**
288
+ * Assert config node is less than expected decimal value
289
+ *
290
+ * @param string $nodePath
291
+ * @param decimal $expectedValue
292
+ * @param string $message
293
+ */
294
+ public static function assertConfigNodeLessThan($nodePath, $expectedValue, $message = '')
295
+ {
296
+ self::assertConfigNodeValue(
297
+ $nodePath, $expectedValue, $message,
298
+ EcomDev_PHPUnit_Constraint_Config_Node::TYPE_LESS_THAN
299
+ );
300
+ }
301
+
302
+ /**
303
+ * Assert config node is less or equals than expected decimal value
304
+ *
305
+ * @param string $nodePath
306
+ * @param decimal $expectedValue
307
+ */
308
+ public static function assertConfigNodeLessThanOrEquals($nodePath, $expectedValue, $message = '')
309
+ {
310
+ self::assertThatConfig(
311
+ self::logicalOr(
312
+ self::configNode(
313
+ $nodePath,
314
+ EcomDev_PHPUnit_Constraint_Config_Node::TYPE_EQUALS_NUMBER,
315
+ $expectedValue
316
+ ),
317
+ self::configNode(
318
+ $nodePath,
319
+ EcomDev_PHPUnit_Constraint_Config_Node::TYPE_LESS_THAN,
320
+ $expectedValue
321
+ )
322
+ ),
323
+ $message
324
+ );
325
+ }
326
+
327
+ /**
328
+ * Assert config node is greater than expected decimal value
329
+ *
330
+ * @param string $nodePath
331
+ * @param decimal $expectedValue
332
+ * @param string $message
333
+ */
334
+ public static function assertConfigNodeGreaterThan($nodePath, $expectedValue, $message = '')
335
+ {
336
+ self::assertConfigNodeValue(
337
+ $nodePath, $expectedValue, $message,
338
+ EcomDev_PHPUnit_Constraint_Config_Node::TYPE_GREATER_THAN
339
+ );
340
+ }
341
+
342
+ /**
343
+ * Assert config node is less or equalsthan expected decimal value
344
+ *
345
+ * @param string $nodePath
346
+ * @param decimal $expectedValue
347
+ */
348
+ public static function assertConfigNodeGreaterThanOrEquals($nodePath, $expectedValue, $message = '')
349
+ {
350
+ self::assertThatConfig(
351
+ self::logicalOr(
352
+ self::configNode(
353
+ $nodePath,
354
+ EcomDev_PHPUnit_Constraint_Config_Node::TYPE_EQUALS_NUMBER,
355
+ $expectedValue
356
+ ),
357
+ self::configNode(
358
+ $nodePath,
359
+ EcomDev_PHPUnit_Constraint_Config_Node::TYPE_GREATER_THAN,
360
+ $expectedValue
361
+ )
362
+ ),
363
+ $message
364
+ );
365
+ }
366
+
367
+ /**
368
+ * Assert that the module is active
369
+ *
370
+ * @param string $message
371
+ * @param string $moduleName
372
+ */
373
+ public static function assertModuleIsActive($message = '', $moduleName = null)
374
+ {
375
+ if ($moduleName === null) {
376
+ $moduleName = self::getModuleNameFromCallStack();
377
+ }
378
+
379
+ self::assertThatConfig(
380
+ self::configModule(
381
+ $moduleName,
382
+ EcomDev_PHPUnit_Constraint_Config_Module::TYPE_IS_ACTIVE
383
+ ),
384
+ $message
385
+ );
386
+ }
387
+
388
+ /**
389
+ * Assert that the module is not active
390
+ *
391
+ * @param string $message
392
+ * @param string $moduleName
393
+ */
394
+ public static function assertModuleIsNotActive($message = '', $moduleName = null)
395
+ {
396
+ if ($moduleName === null) {
397
+ $moduleName = self::getModuleNameFromCallStack();
398
+ }
399
+
400
+ self::assertThatConfig(
401
+ self::logicalNot(
402
+ self::configModule(
403
+ $moduleName,
404
+ EcomDev_PHPUnit_Constraint_Config_Module::TYPE_IS_ACTIVE
405
+ )
406
+ ),
407
+ $message
408
+ );
409
+ }
410
+
411
+ /**
412
+ * Assert that the module is in a particular code pool
413
+ *
414
+ * @param string $expected
415
+ * @param string $message
416
+ * @param string $moduleName
417
+ */
418
+ public static function assertModuleCodePool($expected, $message = '', $moduleName = null)
419
+ {
420
+ if ($moduleName === null) {
421
+ $moduleName = self::getModuleNameFromCallStack();
422
+ }
423
+
424
+ self::assertThatConfig(
425
+ self::configModule(
426
+ $moduleName,
427
+ EcomDev_PHPUnit_Constraint_Config_Module::TYPE_CODE_POOL,
428
+ $expected
429
+ ),
430
+ $message
431
+ );
432
+ }
433
+
434
+ /**
435
+ * Assert that the module depends on another module
436
+ *
437
+ * @param string $requiredModuleName
438
+ * @param string $message
439
+ * @param string $moduleName
440
+ */
441
+ public static function assertModuleDepends($requiredModuleName, $message = '', $moduleName = null)
442
+ {
443
+ if ($moduleName === null) {
444
+ $moduleName = self::getModuleNameFromCallStack();
445
+ }
446
+
447
+ self::assertThatConfig(
448
+ self::configModule(
449
+ $moduleName,
450
+ EcomDev_PHPUnit_Constraint_Config_Module::TYPE_DEPENDS,
451
+ $requiredModuleName
452
+ ),
453
+ $message
454
+ );
455
+ }
456
+
457
+ /**
458
+ * Assert that the module doesn't depend on another module
459
+ *
460
+ * @param string $requiredModuleName
461
+ * @param string $message
462
+ * @param string $moduleName
463
+ */
464
+ public static function assertModuleNotDepends($requiredModuleName, $message = '', $moduleName = null)
465
+ {
466
+ if ($moduleName === null) {
467
+ $moduleName = self::getModuleNameFromCallStack();
468
+ }
469
+
470
+ self::assertThatConfig(
471
+ self::logicalNot(
472
+ self::configModule(
473
+ $moduleName,
474
+ EcomDev_PHPUnit_Constraint_Config_Module::TYPE_DEPENDS,
475
+ $requiredModuleName
476
+ )
477
+ ),
478
+ $message
479
+ );
480
+ }
481
+
482
+ /**
483
+ * Assert that the module version is equal to expected one
484
+ *
485
+ * @param string $expectedVersion
486
+ * @param string $message
487
+ * @param string $moduleName
488
+ */
489
+ public static function assertModuleVersion($expectedVersion, $message = '', $moduleName = null)
490
+ {
491
+ if ($moduleName === null) {
492
+ $moduleName = self::getModuleNameFromCallStack();
493
+ }
494
+
495
+ self::assertThatConfig(
496
+ self::configModule(
497
+ $moduleName,
498
+ EcomDev_PHPUnit_Constraint_Config_Module::TYPE_EQUALS_VERSION,
499
+ $expectedVersion
500
+ ),
501
+ $message
502
+ );
503
+ }
504
+
505
+ /**
506
+ * Assert that the module version is not equal to expected one
507
+ *
508
+ * @param string $expectedVersion
509
+ * @param string $message
510
+ * @param string $moduleName
511
+ */
512
+ public static function assertModuleVersionNot($expectedVersion, $message = '', $moduleName = null)
513
+ {
514
+ if ($moduleName === null) {
515
+ $moduleName = self::getModuleNameFromCallStack();
516
+ }
517
+
518
+ self::assertThatConfig(
519
+ self::logicalNot(
520
+ self::configModule(
521
+ $moduleName,
522
+ EcomDev_PHPUnit_Constraint_Config_Module::TYPE_EQUALS_VERSION,
523
+ $expectedVersion
524
+ )
525
+ ),
526
+ $message
527
+ );
528
+ }
529
+
530
+ /**
531
+ * Assert that the module version is less than expected one
532
+ *
533
+ * @param string $expectedVersion
534
+ * @param string $message
535
+ * @param string $moduleName
536
+ */
537
+ public static function assertModuleVersionLessThan($expectedVersion, $message = '', $moduleName = null)
538
+ {
539
+ if ($moduleName === null) {
540
+ $moduleName = self::getModuleNameFromCallStack();
541
+ }
542
+
543
+ self::assertThatConfig(
544
+ self::configModule(
545
+ $moduleName,
546
+ EcomDev_PHPUnit_Constraint_Config_Module::TYPE_LESS_THAN_VERSION,
547
+ $expectedVersion
548
+ ),
549
+ $message
550
+ );
551
+ }
552
+
553
+ /**
554
+ * Assert that the module version is less than or equal to expected one
555
+ *
556
+ * @param string $expectedVersion
557
+ * @param string $message
558
+ * @param string $moduleName
559
+ */
560
+ public static function assertModuleVersionLessThanOrEquals($expectedVersion, $message = '', $moduleName = null)
561
+ {
562
+ if ($moduleName === null) {
563
+ $moduleName = self::getModuleNameFromCallStack();
564
+ }
565
+
566
+ self::assertThatConfig(
567
+ self::logicalOr(
568
+ self::configModule(
569
+ $moduleName,
570
+ EcomDev_PHPUnit_Constraint_Config_Module::TYPE_EQUALS_VERSION,
571
+ $expectedVersion
572
+ ),
573
+ self::configModule(
574
+ $moduleName,
575
+ EcomDev_PHPUnit_Constraint_Config_Module::TYPE_LESS_THAN_VERSION,
576
+ $expectedVersion
577
+ )
578
+ ),
579
+ $message
580
+ );
581
+ }
582
+
583
+ /**
584
+ * Assert that the module version is greater than expected one
585
+ *
586
+ * @param string $expectedVersion
587
+ * @param string $message
588
+ * @param string $moduleName
589
+ */
590
+ public static function assertModuleVersionGreaterThan($expectedVersion, $message = '', $moduleName = null)
591
+ {
592
+ if ($moduleName === null) {
593
+ $moduleName = self::getModuleNameFromCallStack();
594
+ }
595
+
596
+ self::assertThatConfig(
597
+ self::configModule(
598
+ $moduleName,
599
+ EcomDev_PHPUnit_Constraint_Config_Module::TYPE_GREATER_THAN_VERSION,
600
+ $expectedVersion
601
+ ),
602
+ $message
603
+ );
604
+ }
605
+
606
+ /**
607
+ * Assert that the module version is greater than or equal to expected one
608
+ *
609
+ * @param string $expectedVersion
610
+ * @param string $message
611
+ * @param string $moduleName
612
+ */
613
+ public static function assertModuleVersionGreaterThanOrEquals($expectedVersion, $message = '', $moduleName = null)
614
+ {
615
+ if ($moduleName === null) {
616
+ $moduleName = self::getModuleNameFromCallStack();
617
+ }
618
+
619
+ self::assertThatConfig(
620
+ self::logicalOr(
621
+ self::configModule(
622
+ $moduleName,
623
+ EcomDev_PHPUnit_Constraint_Config_Module::TYPE_EQUALS_VERSION,
624
+ $expectedVersion
625
+ ),
626
+ self::configModule(
627
+ $moduleName,
628
+ EcomDev_PHPUnit_Constraint_Config_Module::TYPE_GREATER_THAN_VERSION,
629
+ $expectedVersion
630
+ )
631
+ ),
632
+ $message
633
+ );
634
+ }
635
+
636
+
637
+ /**
638
+ * Assert that grouped class alias is mapped to expected class name
639
+ *
640
+ * @param string $group
641
+ * @param string $classAlias
642
+ * @param string $expectedClassName
643
+ */
644
+ public static function assertGroupedClassAlias($group, $classAlias, $expectedClassName, $message = '')
645
+ {
646
+ self::assertThatConfig(
647
+ self::configClassAlias($group, $classAlias, $expectedClassName),
648
+ $message
649
+ );
650
+ }
651
+
652
+ /**
653
+ * Assert that grouped class alias is not mapped to expected class name
654
+ *
655
+ * @param string $group
656
+ * @param string $classAlias
657
+ * @param string $expectedClassName
658
+ */
659
+ public static function assertGroupedClassAliasNot($group, $classAlias, $expectedClassName, $message = '')
660
+ {
661
+ self::assertThatConfig(
662
+ self::logicalNot(
663
+ self::configClassAlias($group, $classAlias, $expectedClassName)
664
+ ),
665
+ $message
666
+ );
667
+ }
668
+
669
+ /**
670
+ * Assert that block alias is mapped to expected class name
671
+ *
672
+ * @param string $classAlias
673
+ * @param string $expectedClassName
674
+ * @param string $message
675
+ */
676
+ public static function assertBlockAlias($classAlias, $expectedClassName, $message = '')
677
+ {
678
+ self::assertGroupedClassAlias(
679
+ EcomDev_PHPUnit_Constraint_Config_ClassAlias::GROUP_BLOCK,
680
+ $classAlias,
681
+ $expectedClassName
682
+ );
683
+ }
684
+
685
+ /**
686
+ * Assert that block alias is not mapped to expected class name
687
+ *
688
+ * @param string $classAlias
689
+ * @param string $expectedClassName
690
+ * @param string $message
691
+ */
692
+ public static function assertBlockAliasNot($classAlias, $expectedClassName, $message = '')
693
+ {
694
+ self::assertGroupedClassAliasNot(
695
+ EcomDev_PHPUnit_Constraint_Config_ClassAlias::GROUP_BLOCK,
696
+ $classAlias,
697
+ $expectedClassName
698
+ );
699
+ }
700
+
701
+ /**
702
+ * Assert that model alias is mapped to expected class name
703
+ *
704
+ * @param string $classAlias
705
+ * @param string $expectedClassName
706
+ * @param string $message
707
+ */
708
+ public static function assertModelAlias($classAlias, $expectedClassName, $message = '')
709
+ {
710
+ self::assertGroupedClassAlias(
711
+ EcomDev_PHPUnit_Constraint_Config_ClassAlias::GROUP_MODEL,
712
+ $classAlias,
713
+ $expectedClassName
714
+ );
715
+ }
716
+
717
+ /**
718
+ * Assert that model alias is not mapped to expected class name
719
+ *
720
+ * @param string $classAlias
721
+ * @param string $expectedClassName
722
+ * @param string $message
723
+ */
724
+ public static function assertModelAliasNot($classAlias, $expectedClassName, $message = '')
725
+ {
726
+ self::assertGroupedClassAliasNot(
727
+ EcomDev_PHPUnit_Constraint_Config_ClassAlias::GROUP_MODEL,
728
+ $classAlias,
729
+ $expectedClassName
730
+ );
731
+ }
732
+
733
+ /**
734
+ * Assert that resource model alias is mapped to expected class name
735
+ *
736
+ * @param string $classAlias
737
+ * @param string $expectedClassName
738
+ * @param string $message
739
+ */
740
+ public static function assertResourceModelAlias($classAlias, $expectedClassName, $message = '')
741
+ {
742
+ $classAlias = Mage::getConfig()->getRealResourceModelClassAlias($classAlias);
743
+
744
+ self::assertGroupedClassAlias(
745
+ EcomDev_PHPUnit_Constraint_Config_ClassAlias::GROUP_MODEL,
746
+ $classAlias,
747
+ $expectedClassName
748
+ );
749
+ }
750
+
751
+ /**
752
+ * Assert that resource model alias is not mapped to expected class name
753
+ *
754
+ * @param string $classAlias
755
+ * @param string $expectedClassName
756
+ * @param string $message
757
+ */
758
+ public static function assertResourceModelAliasNot($classAlias, $expectedClassName, $message = '')
759
+ {
760
+ $classAlias = Mage::getConfig()->getRealResourceModelClassAlias($classAlias);
761
+
762
+ self::assertGroupedClassAliasNot(
763
+ EcomDev_PHPUnit_Constraint_Config_ClassAlias::GROUP_MODEL,
764
+ $classAlias,
765
+ $expectedClassName
766
+ );
767
+ }
768
+
769
+ /**
770
+ * Assert that helper alias is mapped to expected class name
771
+ *
772
+ * @param string $classAlias
773
+ * @param string $expectedClassName
774
+ * @param string $message
775
+ */
776
+ public static function assertHelperAlias($classAlias, $expectedClassName, $message = '')
777
+ {
778
+ self::assertGroupedClassAlias(
779
+ EcomDev_PHPUnit_Constraint_Config_ClassAlias::GROUP_HELPER,
780
+ $classAlias,
781
+ $expectedClassName
782
+ );
783
+ }
784
+
785
+ /**
786
+ * Assert that helper alias is not mapped to expected class name
787
+ *
788
+ * @param string $classAlias
789
+ * @param string $expectedClassName
790
+ * @param string $message
791
+ */
792
+ public static function assertHelperAliasNot($classAlias, $expectedClassName, $message = '')
793
+ {
794
+ self::assertGroupedClassAliasNot(
795
+ EcomDev_PHPUnit_Constraint_Config_ClassAlias::GROUP_HELPER,
796
+ $classAlias,
797
+ $expectedClassName
798
+ );
799
+ }
800
+
801
+ /**
802
+ * Assert that configuration has definition of the layout file.
803
+ * If layout update name is specified, then it will restrict assertion by it.
804
+ *
805
+ * @param string $area (frontend|adminhtml)
806
+ * @param string $expectedFileName
807
+ * @param string $layoutUpdate
808
+ * @param string $message
809
+ */
810
+ public static function assertLayoutFileDefined($area, $expectedFileName, $layoutUpdate = null, $message = '')
811
+ {
812
+ self::assertThatConfig(
813
+ self::configLayout(
814
+ $area, $expectedFileName,
815
+ EcomDev_PHPUnit_Constraint_Config_Layout::TYPE_LAYOUT_DEFINITION,
816
+ $layoutUpdate
817
+ ),
818
+ $message
819
+ );
820
+ }
821
+
822
+ /**
823
+ * Asserts that layout file exists in current design package
824
+ *
825
+ * @param string $area (frontend|adminhtml)
826
+ * @param string $expectedFileName
827
+ * @param string $message
828
+ */
829
+ public static function assertLayoutFileExists($area, $expectedFileName, $message = '')
830
+ {
831
+ self::assertLayoutFileDefined($area, $expectedFileName, null, $message);
832
+
833
+ self::assertThatConfig(
834
+ self::configLayout(
835
+ $area, $expectedFileName,
836
+ EcomDev_PHPUnit_Constraint_Config_Layout::TYPE_LAYOUT_FILE
837
+ ),
838
+ $message
839
+ );
840
+ }
841
+
842
+ /**
843
+ * Asserts that layout file exists in a particular theme and design package
844
+ *
845
+ * @param string $area (frontend|adminhtml)
846
+ * @param string $expectedFileName
847
+ * @param string $message
848
+ */
849
+ public static function assertLayoutFileExistsInTheme($area, $expectedFileName, $theme,
850
+ $designPackage = null, $message = '')
851
+ {
852
+ self::assertLayoutFileDefined($area, $expectedFileName, null, $message);
853
+
854
+ self::assertThatConfig(
855
+ self::configLayout(
856
+ $area, $expectedFileName,
857
+ EcomDev_PHPUnit_Constraint_Config_Layout::TYPE_LAYOUT_FILE,
858
+ null,
859
+ $theme,
860
+ $designPackage
861
+ ),
862
+ $message
863
+ );
864
+ }
865
+
866
+ /**
867
+ * Asserts that event observer is defined for an event
868
+ * and not disabled. If observer name is defined, it additionaly checks it.
869
+ *
870
+ * @param string $area
871
+ * @param string $eventName
872
+ * @param string $observerClassAlias
873
+ * @param string $observerMethod
874
+ * @param string|null $observerName
875
+ * @param string $message
876
+ */
877
+ public static function assertEventObserverDefined($area, $eventName, $observerClassAlias,
878
+ $observerMethod, $observerName = null, $message = '')
879
+ {
880
+ self::assertThatConfig(
881
+ self::configEventObserver(
882
+ $area, $eventName, $observerClassAlias, $observerMethod,
883
+ EcomDev_PHPUnit_Constraint_Config_EventObserver::TYPE_DEFINDED,
884
+ $observerName
885
+ ),
886
+ $message
887
+ );
888
+ }
889
+
890
+ /**
891
+ * Asserts that event observer is not defined for an event
892
+ * or disabled.
893
+ * If observer name is defined, it additionaly checks it.
894
+ *
895
+ * @param string $area
896
+ * @param string $eventName
897
+ * @param string $observerClassAlias
898
+ * @param string $observerMethod
899
+ * @param string|null $observerName
900
+ * @param string $message
901
+ */
902
+ public static function assertEventObserverNotDefined($area, $eventName, $observerClassAlias,
903
+ $observerMethod, $observerName = null, $message = '')
904
+ {
905
+ self::assertThatConfig(
906
+ self::logicalNot(
907
+ self::configEventObserver(
908
+ $area, $eventName, $observerClassAlias, $observerMethod,
909
+ EcomDev_PHPUnit_Constraint_Config_EventObserver::TYPE_DEFINDED,
910
+ $observerName
911
+ )
912
+ ),
913
+ $message
914
+ );
915
+ }
916
+ }
app/code/community/EcomDev/PHPUnit/Test/Case/Controller.php ADDED
@@ -0,0 +1,1985 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PHP Unit test suite for Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ *
12
+ * @category EcomDev
13
+ * @package EcomDev_PHPUnit
14
+ * @copyright Copyright (c) 2011 Ecommerce Developers (http://www.ecomdev.org)
15
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
+ * @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
17
+ */
18
+
19
+
20
+ /**
21
+ * Base for controller test case
22
+ *
23
+ */
24
+ abstract class EcomDev_PHPUnit_Test_Case_Controller extends EcomDev_PHPUnit_Test_Case
25
+ {
26
+ /**
27
+ * Cookies container
28
+ *
29
+ * @var Zend_Http_CookieJar
30
+ */
31
+ protected static $_cookies = null;
32
+
33
+ /**
34
+ * Returns cookies container,
35
+ * that processes them
36
+ *
37
+ * @return Zend_Http_CookieJar
38
+ */
39
+ protected static function getCookies()
40
+ {
41
+ if (self::$_cookies === null) {
42
+ self::$_cookies = new Zend_Http_CookieJar();
43
+ }
44
+
45
+ return self::$_cookies;
46
+ }
47
+
48
+ /**
49
+ * Returns request object
50
+ *
51
+ * @return EcomDev_PHPUnit_Controller_Request_Http
52
+ */
53
+ protected static function getRequest()
54
+ {
55
+ return self::app()->getRequest();
56
+ }
57
+
58
+ /**
59
+ * Returns response object
60
+ *
61
+ * @return EcomDev_PHPUnit_Controller_Response_Http
62
+ */
63
+ protected static function getResponse()
64
+ {
65
+ return self::app()->getResponse();
66
+ }
67
+
68
+ /**
69
+ * Returns layout model
70
+ *
71
+ * @return EcomDev_PHPUnit_Model_Layout
72
+ */
73
+ protected static function getLayout()
74
+ {
75
+ return self::app()->getLayout();
76
+ }
77
+
78
+ /**
79
+ * Layout main functions constraint
80
+ *
81
+ * @param string $type
82
+ * @return EcomDev_PHPUnit_Constraint_Layout
83
+ */
84
+ public static function layout($type)
85
+ {
86
+ return new EcomDev_PHPUnit_Constraint_Layout($type);
87
+ }
88
+
89
+ /**
90
+ * Layout handle functionality constaint
91
+ *
92
+ * @param string $handle handle name
93
+ * @param string $type
94
+ * @param string|null $position another handle for position check
95
+ * @return EcomDev_PHPUnit_Constraint_Layout_Handle
96
+ */
97
+ public static function layoutHandle($handle, $type, $position = null)
98
+ {
99
+ return new EcomDev_PHPUnit_Constraint_Layout_Handle($handle, $type, $position);
100
+ }
101
+
102
+ /**
103
+ * Layout block functionality constraint
104
+ *
105
+ * @param string $blockName
106
+ * @param string $type
107
+ * @param string|null $expectedValue
108
+ * @return EcomDev_PHPUnit_Constraint_Layout_Block
109
+ */
110
+ public static function layoutBlock($blockName, $type, $expectedValue = null)
111
+ {
112
+ return new EcomDev_PHPUnit_Constraint_Layout_Block($blockName, $type, $expectedValue);
113
+ }
114
+
115
+ /**
116
+ * Layout block action calls functionality constaint
117
+ *
118
+ * @param string $blockName
119
+ * @param string $method
120
+ * @param string $type
121
+ * @param int|null $invocationCount
122
+ * @param array|null $arguments
123
+ * @param string $searchType
124
+ * @return EcomDev_PHPUnit_Constraint_Layout_Block_Action
125
+ */
126
+ public static function layoutBlockAction($blockName, $method, $type, $invocationCount = null,
127
+ array $arguments = null, $searchType = EcomDev_PHPUnit_Constraint_Layout_Block_Action::SEARCH_TYPE_AND)
128
+ {
129
+ return new EcomDev_PHPUnit_Constraint_Layout_Block_Action(
130
+ $blockName, $method, $type, $invocationCount, $arguments, $searchType
131
+ );
132
+ }
133
+
134
+ /**
135
+ * Layout block property constraint creation
136
+ *
137
+ * @param string $blockName
138
+ * @param string $propertyName
139
+ * @param PHPUnit_Framework_Constraint $constraint
140
+ * @return EcomDev_PHPUnit_Constraint_Layout_Block_Property
141
+ */
142
+ public static function layoutBlockProperty($blockName, $propertyName, PHPUnit_Framework_Constraint $constraint)
143
+ {
144
+ return new EcomDev_PHPUnit_Constraint_Layout_Block_Property($blockName, $propertyName, $constraint);
145
+ }
146
+
147
+ /**
148
+ * Controller request constraint creation
149
+ *
150
+ *
151
+ * @param string $type
152
+ * @param string|null $expectedValue
153
+ * @return string
154
+ */
155
+ public static function request($type, $expectedValue = null)
156
+ {
157
+ return new EcomDev_PHPUnit_Constraint_Controller_Request($type, $expectedValue);
158
+ }
159
+
160
+ /**
161
+ * Controller response header constraint creation
162
+ *
163
+ * @param string $type
164
+ * @param string $headerName
165
+ * @param PHPUnit_Framework_Constraint|null $constraint
166
+ * @return string
167
+ */
168
+ public static function responseHeader($headerName, $type, PHPUnit_Framework_Constraint $constraint = null)
169
+ {
170
+ return new EcomDev_PHPUnit_Constraint_Controller_Response_Header($headerName, $type, $constraint);
171
+ }
172
+
173
+ /**
174
+ * Controller response body constraint creation
175
+ *
176
+ * @param PHPUnit_Framework_Constraint $constraint
177
+ * @return string
178
+ */
179
+ public static function responseBody(PHPUnit_Framework_Constraint $constraint)
180
+ {
181
+ return new EcomDev_PHPUnit_Constraint_Controller_Response_Body($constraint);
182
+ }
183
+
184
+ /**
185
+ * Assert that controller request matches assertion type
186
+ *
187
+ * @param string $type type of assertion
188
+ * @param string|null $expectedValue
189
+ * @param string $message
190
+ */
191
+ public static function assertRequest($type, $expectedValue = null, $message = '')
192
+ {
193
+ self::assertThat(
194
+ self::getRequest(),
195
+ self::request($type, $expectedValue),
196
+ $message
197
+ );
198
+ }
199
+
200
+ /**
201
+ * Assert that controller request doesn't matches assertion type
202
+ *
203
+ * @param string $type type of assertion
204
+ * @param string|null $expectedValue
205
+ * @param string $message
206
+ */
207
+ public static function assertRequestNot($type, $expectedValue = null, $message = '')
208
+ {
209
+ self::assertThat(
210
+ self::getRequest(),
211
+ self::logicalNot(
212
+ self::request($type, $expectedValue)
213
+ ),
214
+ $message
215
+ );
216
+ }
217
+
218
+ /**
219
+ * Assert that controller request is dispatched
220
+ *
221
+ * @param string $message
222
+ */
223
+ public static function assertRequestDispatched($message = '')
224
+ {
225
+ self::assertRequest(
226
+ EcomDev_PHPUnit_Constraint_Controller_Request::TYPE_DISPATCHED,
227
+ null, $message
228
+ );
229
+ }
230
+
231
+ /**
232
+ * Assert that controller request is not dispatched
233
+ *
234
+ * @param string $message
235
+ */
236
+ public static function assertRequestNotDispatched($message = '')
237
+ {
238
+ self::assertRequestNot(
239
+ EcomDev_PHPUnit_Constraint_Controller_Request::TYPE_DISPATCHED,
240
+ null, $message
241
+ );
242
+ }
243
+
244
+ /**
245
+ * Assert that controller request is forwarded
246
+ *
247
+ * @param string $message
248
+ */
249
+ public static function assertRequestForwarded($message = '')
250
+ {
251
+ self::assertRequest(
252
+ EcomDev_PHPUnit_Constraint_Controller_Request::TYPE_FORWARDED,
253
+ null, $message
254
+ );
255
+ }
256
+
257
+ /**
258
+ * Assert that controller request is not forwarded
259
+ *
260
+ * @param string $message
261
+ */
262
+ public static function assertRequestNotForwarded($message = '')
263
+ {
264
+ self::assertRequestNot(
265
+ EcomDev_PHPUnit_Constraint_Controller_Request::TYPE_FORWARDED,
266
+ null, $message
267
+ );
268
+ }
269
+
270
+ /**
271
+ * Asserts that current request route is matched expected one
272
+ *
273
+ * @param string $expectedRoute
274
+ * @param string $message
275
+ */
276
+ public static function assertRequestRoute($expectedRoute, $message = '')
277
+ {
278
+ self::assertRequest(
279
+ EcomDev_PHPUnit_Constraint_Controller_Request::TYPE_ROUTE,
280
+ $expectedRoute, $message
281
+ );
282
+ }
283
+
284
+ /**
285
+ * Asserts that current request route is not matched expected one
286
+ *
287
+ * @param string $expectedRoute
288
+ * @param string $message
289
+ */
290
+ public static function assertRequestRouteNot($expectedRoute, $message = '')
291
+ {
292
+ self::assertRequestNot(
293
+ EcomDev_PHPUnit_Constraint_Controller_Request::TYPE_ROUTE,
294
+ $expectedRoute, $message
295
+ );
296
+ }
297
+
298
+ /**
299
+ * Asserts that current request route name is the same as expected
300
+ *
301
+ * @param string $expectedRouteName
302
+ * @param string $message
303
+ */
304
+ public static function assertRequestRouteName($expectedRouteName, $message = '')
305
+ {
306
+ self::assertRequest(
307
+ EcomDev_PHPUnit_Constraint_Controller_Request::TYPE_ROUTE_NAME,
308
+ $expectedRouteName, $message
309
+ );
310
+ }
311
+
312
+ /**
313
+ * Asserts that current request route name is not the same as expected
314
+ *
315
+ * @param string $expectedRouteName
316
+ * @param string $message
317
+ */
318
+ public static function assertRequestRouteNameNot($expectedRouteName, $message = '')
319
+ {
320
+ self::assertRequestNot(
321
+ EcomDev_PHPUnit_Constraint_Controller_Request::TYPE_ROUTE_NAME,
322
+ $expectedRouteName, $message
323
+ );
324
+ }
325
+
326
+ /**
327
+ * Asserts that current request controller name is the same as expected
328
+ *
329
+ * @param string $expectedControllerName
330
+ * @param string $message
331
+ */
332
+ public static function assertRequestControllerName($expectedControllerName, $message = '')
333
+ {
334
+ self::assertRequest(
335
+ EcomDev_PHPUnit_Constraint_Controller_Request::TYPE_CONTROLLER_NAME,
336
+ $expectedControllerName, $message
337
+ );
338
+ }
339
+
340
+ /**
341
+ * Asserts that current request controller name is not the same as expected
342
+ *
343
+ * @param string $expectedControllerName
344
+ * @param string $message
345
+ */
346
+ public static function assertRequestControllerNameNot($expectedControllerName, $message = '')
347
+ {
348
+ self::assertRequestNot(
349
+ EcomDev_PHPUnit_Constraint_Controller_Request::TYPE_CONTROLLER_NAME,
350
+ $expectedControllerName, $message
351
+ );
352
+ }
353
+
354
+ /**
355
+ * Asserts that current request controller module is the same as expected
356
+ *
357
+ * @param string $expectedControllerModule
358
+ * @param string $message
359
+ */
360
+ public static function assertRequestControllerModule($expectedControllerModule, $message = '')
361
+ {
362
+ self::assertRequest(
363
+ EcomDev_PHPUnit_Constraint_Controller_Request::TYPE_CONTROLLER_MODULE,
364
+ $expectedControllerModule, $message
365
+ );
366
+ }
367
+
368
+ /**
369
+ * Asserts that current request controller name is not the same as expected
370
+ *
371
+ * @param string $expectedControllerModule
372
+ * @param string $message
373
+ */
374
+ public static function assertRequestControllerModuleNot($expectedControllerModule, $message = '')
375
+ {
376
+ self::assertRequestNot(
377
+ EcomDev_PHPUnit_Constraint_Controller_Request::TYPE_CONTROLLER_MODULE,
378
+ $expectedControllerModule, $message
379
+ );
380
+ }
381
+
382
+ /**
383
+ * Asserts that current request action name is the same as expected
384
+ *
385
+ * @param string $expectedActionName
386
+ * @param string $message
387
+ */
388
+ public static function assertRequestActionName($expectedActionName, $message = '')
389
+ {
390
+ self::assertRequest(
391
+ EcomDev_PHPUnit_Constraint_Controller_Request::TYPE_ACTION_NAME,
392
+ $expectedActionName, $message
393
+ );
394
+ }
395
+
396
+ /**
397
+ * Asserts that current request action name is not the same as expected
398
+ *
399
+ * @param string $expectedActionName
400
+ * @param string $message
401
+ */
402
+ public static function assertRequestActionNameNot($expectedActionName, $message = '')
403
+ {
404
+ self::assertRequestNot(
405
+ EcomDev_PHPUnit_Constraint_Controller_Request::TYPE_ACTION_NAME,
406
+ $expectedActionName, $message
407
+ );
408
+ }
409
+
410
+ /**
411
+ * Asserts that current request before forwarded route is matched expected
412
+ *
413
+ * @param string $expectedBeforeForwardedRoute
414
+ * @param string $message
415
+ */
416
+ public static function assertRequestBeforeForwardedRoute($expectedBeforeForwardedRoute, $message = '')
417
+ {
418
+ self::assertRequest(
419
+ EcomDev_PHPUnit_Constraint_Controller_Request::TYPE_BEFORE_FORWARD_ROUTE,
420
+ $expectedBeforeForwardedRoute, $message
421
+ );
422
+ }
423
+
424
+ /**
425
+ * Asserts that current request before forwarded route is not matched expected
426
+ *
427
+ * @param string $expectedBeforeForwardedRoute
428
+ * @param string $message
429
+ */
430
+ public static function assertRequestBeforeForwardedRouteNot($expectedBeforeForwardedRoute, $message = '')
431
+ {
432
+ self::assertRequestNot(
433
+ EcomDev_PHPUnit_Constraint_Controller_Request::TYPE_BEFORE_FORWARD_ROUTE,
434
+ $expectedActionName, $message
435
+ );
436
+ }
437
+
438
+ /**
439
+ * Assert shortcut for response assertions
440
+ *
441
+ * @param EcomDev_PHPUnit_Constraint_Controller_Response_Header $constraint
442
+ * @param string $message
443
+ */
444
+ public static function assertThatResponse(EcomDev_PHPUnit_Constraint_Controller_Response_Header $constraint, $message)
445
+ {
446
+ self::assertThat(self::getResponse(), $constraint, $message);
447
+ }
448
+
449
+ /**
450
+ * Assert that response header is sent
451
+ *
452
+ * @param string $headerName
453
+ * @param string $message
454
+ */
455
+ public static function assertResponseHeaderSent($headerName, $message = '')
456
+ {
457
+ self::assertThatResponse(
458
+ self::responseHeader(
459
+ $headerName,
460
+ EcomDev_PHPUnit_Constraint_Controller_Response_Header::TYPE_SENT
461
+ ),
462
+ $message
463
+ );
464
+ }
465
+
466
+ /**
467
+ * Assert that response header is not sent
468
+ *
469
+ * @param string $headerName
470
+ * @param string $message
471
+ */
472
+ public static function assertResponseHeaderNotSent($headerName, $message = '')
473
+ {
474
+ self::assertThatResponse(
475
+ self::logicalNot(
476
+ self::responseHeader(
477
+ $headerName,
478
+ EcomDev_PHPUnit_Constraint_Controller_Response_Header::TYPE_SENT
479
+ )
480
+ ),
481
+ $message
482
+ );
483
+ }
484
+
485
+ /**
486
+ * Assert that response header is evaluated by a specified constraint
487
+ *
488
+ * @param string $headerName
489
+ * @param PHPUnit_Framework_Constraint $constraint
490
+ * @param string $message
491
+ */
492
+ public static function assertResponseHeader($headerName, PHPUnit_Framework_Constraint $constraint, $message = '')
493
+ {
494
+ self::assertThatResponse(
495
+ self::responseHeader(
496
+ $headerName,
497
+ EcomDev_PHPUnit_Constraint_Controller_Response_Header::TYPE_CONSTRAINT,
498
+ $constraint
499
+ ),
500
+ $message
501
+ );
502
+ }
503
+
504
+ /**
505
+ * Assert that response header is not evaluated by a specified constraint
506
+ *
507
+ * @param string $headerName
508
+ * @param PHPUnit_Framework_Constraint $constraint
509
+ * @param string $message
510
+ */
511
+ public static function assertResponseHeaderNot($headerName, PHPUnit_Framework_Constraint $constraint, $message = '')
512
+ {
513
+ self::assertThatResponse(
514
+ self::responseHeader(
515
+ $headerName,
516
+ EcomDev_PHPUnit_Constraint_Controller_Response_Header::TYPE_CONSTRAINT,
517
+ self::logicalNot($constraint)
518
+ ),
519
+ $message
520
+ );
521
+ }
522
+
523
+ /**
524
+ * Assert that response header is equal to expected value
525
+ *
526
+ * @param string $headerName
527
+ * @param mixed $expectedValue
528
+ * @param string $message
529
+ * @param float $delta
530
+ * @param integer $maxDepth
531
+ * @param boolean $canonicalize
532
+ * @param boolean $ignoreCase
533
+ */
534
+ public static function assertResponseHeaderEquals($headerName, $expectedValue, $message = '',
535
+ $delta = 0, $maxDepth = 10, $canonicalize = false, $ignoreCase = false)
536
+ {
537
+ self::assertResponseHeader(
538
+ $headerName,
539
+ self::equalTo($expectedValue, $delta, $maxDepth, $canonicalize, $ignoreCase),
540
+ $message
541
+ );
542
+ }
543
+
544
+ /**
545
+ * Assert that response header is not equal to expected value
546
+ *
547
+ * @param string $headerName
548
+ * @param mixed $expectedValue
549
+ * @param string $message
550
+ * @param float $delta
551
+ * @param integer $maxDepth
552
+ * @param boolean $canonicalize
553
+ * @param boolean $ignoreCase
554
+ */
555
+ public static function assertResponseHeaderNotEquals($headerName, $expectedValue, $message = '',
556
+ $delta = 0, $maxDepth = 10, $canonicalize = false, $ignoreCase = false)
557
+ {
558
+ self::assertResponseHeaderNot(
559
+ $headerName,
560
+ self::equalTo($expectedValue, $delta, $maxDepth, $canonicalize, $ignoreCase),
561
+ $message
562
+ );
563
+ }
564
+
565
+ /**
566
+ * Assert that response header is the same as expected value
567
+ *
568
+ * @param string $headerName
569
+ * @param mixed $expectedValue
570
+ * @param string $message
571
+ */
572
+ public static function assertResponseHeaderSame($headerName, $expectedValue, $message = '')
573
+ {
574
+ self::assertResponseHeader(
575
+ $headerName,
576
+ self::identicalTo($expectedValue),
577
+ $message
578
+ );
579
+ }
580
+
581
+ /**
582
+ * Assert that response header is not the same as expected value
583
+ *
584
+ * @param string $headerName
585
+ * @param mixed $expectedValue
586
+ * @param string $message
587
+ */
588
+ public static function assertResponseHeaderNotSame($headerName, $expectedValue, $message = '')
589
+ {
590
+ self::assertResponseHeaderNot(
591
+ $headerName,
592
+ self::identicalTo($expectedValue),
593
+ $message
594
+ );
595
+ }
596
+
597
+ /**
598
+ * Assert that response header contains expected string value
599
+ *
600
+ * @param string $headerName
601
+ * @param string $expectedValue
602
+ * @param string $message
603
+ * @param boolean $ignoreCase
604
+ */
605
+ public static function assertResponseHeaderContains($headerName, $expectedValue, $message = '', $ignoreCase = true)
606
+ {
607
+ self::assertResponseHeader(
608
+ $headerName,
609
+ self::stringContains($expectedValue, $ignoreCase),
610
+ $message
611
+ );
612
+ }
613
+
614
+ /**
615
+ * Assert that response header doesn't contain expected string value
616
+ *
617
+ * @param string $headerName
618
+ * @param string $expectedValue
619
+ * @param string $message
620
+ * @param boolean $ignoreCase
621
+ */
622
+ public static function assertResponseHeaderNotContains($headerName, $expectedValue, $message = '', $ignoreCase = true)
623
+ {
624
+ self::assertResponseHeaderNot(
625
+ $headerName,
626
+ self::stringContains($expectedValue, $ignoreCase),
627
+ $message
628
+ );
629
+ }
630
+
631
+ /**
632
+ * Assert that response header matches specified PCRE pattern
633
+ *
634
+ * @param string $headerName
635
+ * @param string $pcrePattern
636
+ * @param string $message
637
+ * @param boolean $ignoreCase
638
+ */
639
+ public static function assertResponseHeaderRegExp($headerName, $pcrePattern, $message = '')
640
+ {
641
+ self::assertResponseHeader(
642
+ $headerName,
643
+ self::matchesRegularExpression($pcrePattern),
644
+ $message
645
+ );
646
+ }
647
+
648
+ /**
649
+ * Assert that response header doesn't match specified PCRE pattern
650
+ *
651
+ * @param string $headerName
652
+ * @param string $pcrePattern
653
+ * @param string $message
654
+ * @param boolean $ignoreCase
655
+ */
656
+ public static function assertResponseHeaderNotRegExp($headerName, $pcrePattern, $message = '')
657
+ {
658
+ self::assertResponseHeaderNot(
659
+ $headerName,
660
+ self::matchesRegularExpression($pcrePattern),
661
+ $message
662
+ );
663
+ }
664
+
665
+ /**
666
+ * Assert that response body is evaluated by the constraint
667
+ *
668
+ * @param PHPUnit_Framework_Constraint $constraint
669
+ * @param string $message
670
+ */
671
+ public static function assertResponseBody(PHPUnit_Framework_Constraint $constraint, $message = '')
672
+ {
673
+ self::assertThatResponse(
674
+ self::responseBody($constraint),
675
+ $message
676
+ );
677
+ }
678
+
679
+ /**
680
+ * Assert that response body is not evaluated by the constraint
681
+ *
682
+ * @param PHPUnit_Framework_Constraint $constraint
683
+ * @param string $message
684
+ */
685
+ public static function assertResponseBodyNot(PHPUnit_Framework_Constraint $constraint, $message = '')
686
+ {
687
+ self::assertThatResponse(
688
+ self::logicalNot(
689
+ self::responseBody($constraint)
690
+ ),
691
+ $message
692
+ );
693
+ }
694
+
695
+ /**
696
+ * Assert that response body contains expected string
697
+ *
698
+ * @param string $expectedValue
699
+ * @param string $message
700
+ * @param boolean $ignoreCase
701
+ */
702
+ public static function assertResponseBodyContains($expectedValue, $message = '', $ignoreCase = true)
703
+ {
704
+ self::assertResponseBody(
705
+ self::stringContains($expectedValue, $ignoreCase),
706
+ $message
707
+ );
708
+ }
709
+
710
+ /**
711
+ * Assert that response body doen't contain expected string
712
+ *
713
+ * @param string $expectedValue
714
+ * @param string $message
715
+ * @param boolean $ignoreCase
716
+ */
717
+ public static function assertResponseBodyNotContains($expectedValue, $message = '', $ignoreCase = true)
718
+ {
719
+ self::assertResponseBodyNot(
720
+ self::stringContains($expectedValue, $ignoreCase),
721
+ $message
722
+ );
723
+ }
724
+
725
+ /**
726
+ * Assert that response body is matched by PCRE pattern
727
+ *
728
+ * @param string $pcrePattern
729
+ * @param string $message
730
+ */
731
+ public static function assertResponseBodyRegExp($pcrePattern, $message = '')
732
+ {
733
+ self::assertResponseBody(
734
+ self::matchesRegularExpression($pcrePattern),
735
+ $message
736
+ );
737
+ }
738
+
739
+ /**
740
+ * Assert that response body is not matched by PCRE pattern
741
+ *
742
+ * @param string $pcrePattern
743
+ * @param string $message
744
+ */
745
+ public static function assertResponseBodyNotRegExp($pcrePattern, $message = '')
746
+ {
747
+ self::assertResponseBodyNot(
748
+ self::matchesRegularExpression($pcrePattern),
749
+ $message
750
+ );
751
+ }
752
+
753
+ /**
754
+ * Assert that response body is valid JSON string
755
+ *
756
+ * @param string $message
757
+ */
758
+ public static function assertResponseBodyJson($message = '')
759
+ {
760
+ self::assertResponseBody(
761
+ self::isJson(),
762
+ $message
763
+ );
764
+ }
765
+
766
+ /**
767
+ * Assert that response body is not valid JSON string
768
+ *
769
+ * @param string $message
770
+ */
771
+ public static function assertResponseBodyNotJson($message = '')
772
+ {
773
+ self::assertResponseBody(
774
+ self::logicalNot(self::isJson()),
775
+ $message
776
+ );
777
+ }
778
+
779
+ /**
780
+ * Assert that response body is JSON and matches expected value,
781
+ * Can accept different match type for matching logic.
782
+ *
783
+ * @param array $expectedValue
784
+ * @param string $message
785
+ * @param strign $matchType
786
+ */
787
+ public static function assertResponseBodyJsonMatch(array $expectedValue, $message = '',
788
+ $matchType = EcomDev_PHPUnit_Constraint_Json::MATCH_AND)
789
+ {
790
+ self::assertResponseBodyJson($message);
791
+ self::assertResponseBody(
792
+ self::matchesJson($expectedValue, $matchType),
793
+ $message
794
+ );
795
+ }
796
+
797
+ /**
798
+ * Assert that response body is JSON and not matches expected value,
799
+ * Can accept different match type for matching logic.
800
+ *
801
+ * @param array $expectedValue
802
+ * @param string $message
803
+ * @param strign $matchType
804
+ */
805
+ public static function assertResponseBodyJsonNotMatch(array $expectedValue, $message = '',
806
+ $matchType = EcomDev_PHPUnit_Constraint_Json::MATCH_AND)
807
+ {
808
+ self::assertResponseBodyJson($message);
809
+ self::assertResponseBodyNot(
810
+ self::matchesJson($expectedValue, $matchType),
811
+ $message
812
+ );
813
+ }
814
+
815
+ /**
816
+ * Assert HTTP response code value
817
+ *
818
+ * @param int $code
819
+ */
820
+ public static function assertResponseHttpCode($code, $message = '')
821
+ {
822
+ self::assertEquals(
823
+ $code,
824
+ self::getResponse()->getHttpResponseCode(),
825
+ $message
826
+ . sprintf("\nFailed asserting that response code is equal to %d", $code)
827
+ );
828
+ }
829
+
830
+ /**
831
+ * Assert that controller response is redirect
832
+ *
833
+ * @param string $message
834
+ * @param int|null $code
835
+ */
836
+ public static function assertRedirect($message = '', $responseCode = null)
837
+ {
838
+ self::assertTrue(
839
+ self::getResponse()->isRedirect(),
840
+ $message . "\nFailed asserting that response is redirect"
841
+ );
842
+
843
+ if ($responseCode !== null) {
844
+ self::assertResponseHttpCode($responseCode, $message);
845
+ }
846
+ }
847
+
848
+ /**
849
+ * Assert that controller response is not redirect
850
+ *
851
+ * @param string $message
852
+ */
853
+ public static function assertNotRedirect($message = '')
854
+ {
855
+ self::assertFalse(
856
+ self::getResponse()->isRedirect(),
857
+ $message . "\nFailed asserting that response is not redirect"
858
+ );
859
+ }
860
+
861
+ /**
862
+ * Assert that constroller response is a redirect
863
+ * to a specific url
864
+ *
865
+ * @param string $route route path
866
+ * @param string $params route params
867
+ * @param string $message
868
+ */
869
+ public static function assertRedirectTo($route, array $params = array(), $message = '')
870
+ {
871
+ if (!isset($params['_store']) && strpos($route, EcomDev_PHPUnit_Model_App::AREA_ADMINHTML) !== false) {
872
+ $params['_store'] = EcomDev_PHPUnit_Model_App::ADMIN_STORE_CODE;
873
+ }
874
+
875
+ if ($params['_store'] === EcomDev_PHPUnit_Model_App::ADMIN_STORE_CODE) {
876
+ $urlModel = Mage::getModel('adminhtml/url');
877
+ } else {
878
+ $urlModel = Mage::getModel('core/url');
879
+ }
880
+
881
+ $url = $urlModel->getUrl($route, $params);
882
+ self::assertRedirectToUrl($url, $message);
883
+ }
884
+
885
+ /**
886
+ * Assert that constroller response redirect is equal
887
+ * to a specific url
888
+ *
889
+ * @param string $url
890
+ * @param string $message
891
+ */
892
+ public static function assertRedirectToUrl($url, $message = '')
893
+ {
894
+ self::assertRedirect($message);
895
+ self::assertResponseHeaderEquals('Location', $url, $message);
896
+ }
897
+
898
+ /**
899
+ * Assert that constroller response redirect url
900
+ * starts with expected url part
901
+ *
902
+ * @param string $urlPart
903
+ * @param string $message
904
+ */
905
+ public static function assertRedirectToUrlStartsWith($urlPart, $message = '')
906
+ {
907
+ self::assertRedirect($message);
908
+ self::assertResponseHeader('Location',
909
+ self::stringStartsWith($urlPart),
910
+ $message
911
+ );
912
+ }
913
+
914
+ /**
915
+ * Assert that constroller response redirect url
916
+ * contains expected url part
917
+ *
918
+ * @param string $urlPart
919
+ * @param string $message
920
+ */
921
+ public static function assertRedirectToUrlContains($urlPart, $message = '')
922
+ {
923
+ self::assertRedirect($message);
924
+ self::assertResponseHeaderContains('Location', $urlPart, $message);
925
+ }
926
+
927
+ /**
928
+ * Assert that constroller response redirect url matches PRCE pattern
929
+ *
930
+ * @param string $pcrePattern route path
931
+ * @param string $message
932
+ */
933
+ public static function assertRedirectToUrlRegExp($pcrePattern, $message = '')
934
+ {
935
+ self::assertRedirect($message);
936
+ self::assertResponseHeaderRegExp('Location', $pcrePattern, $message);
937
+ }
938
+
939
+
940
+ /**
941
+ * Assert shortcut for layout constaints
942
+ *
943
+ * @param EcomDev_PHPUnit_Constraint_Layout_Abstract|PHPUnit_Framework_Constraint $constaint
944
+ * @param string $message
945
+ */
946
+ public static function assertThatLayout(PHPUnit_Framework_Constraint $constraint, $message)
947
+ {
948
+ self::assertThat(self::getLayout(), $constraint, $message);
949
+ }
950
+
951
+ /**
952
+ * Assert that layout is loaded
953
+ *
954
+ * @param string $message
955
+ */
956
+ public static function assertLayoutLoaded($message = '')
957
+ {
958
+ self::assertThatLayout(
959
+ self::layout(EcomDev_PHPUnit_Constraint_Layout::TYPE_LOADED),
960
+ $message
961
+ );
962
+ }
963
+
964
+ /**
965
+ * Assert that layout is not loaded
966
+ *
967
+ * @param string $message
968
+ */
969
+ public static function assertLayoutNotLoaded($message = '')
970
+ {
971
+ self::assertThatLayout(
972
+ self::logicalNot(
973
+ self::layout(EcomDev_PHPUnit_Constraint_Layout::TYPE_LOADED)
974
+ ),
975
+ $message
976
+ );
977
+ }
978
+
979
+ /**
980
+ * Assert that layout is rendered
981
+ *
982
+ * @param string $message
983
+ */
984
+ public static function assertLayoutRendered($message = '')
985
+ {
986
+ self::assertThatLayout(
987
+ self::layout(EcomDev_PHPUnit_Constraint_Layout::TYPE_RENDERED),
988
+ $message
989
+ );
990
+ }
991
+
992
+ /**
993
+ * Assert that layout is not rendered
994
+ *
995
+ * @param string $message
996
+ */
997
+ public static function assertLayoutNotRendered($message = '')
998
+ {
999
+ self::assertThatLayout(
1000
+ self::logicalNot(
1001
+ self::layout(EcomDev_PHPUnit_Constraint_Layout::TYPE_RENDERED)
1002
+ ),
1003
+ $message
1004
+ );
1005
+ }
1006
+
1007
+ /**
1008
+ * Assert that layout handle is loaded into layout updates
1009
+ *
1010
+ *
1011
+ * @param string $handle
1012
+ * @param string $message
1013
+ */
1014
+ public static function assertLayoutHandleLoaded($handle, $message = '')
1015
+ {
1016
+ self::assertThatLayout(
1017
+ self::layoutHandle(
1018
+ $handle, EcomDev_PHPUnit_Constraint_Layout_Handle::TYPE_LOADED
1019
+ ),
1020
+ $message
1021
+ );
1022
+ }
1023
+
1024
+ /**
1025
+ * Assert that layout handle is not loaded into layout updates
1026
+ *
1027
+ *
1028
+ * @param string $handle
1029
+ * @param string $message
1030
+ */
1031
+ public static function assertLayoutHandleNotLoaded($handle, $message = '')
1032
+ {
1033
+ self::assertThatLayout(
1034
+ self::logicalNot(
1035
+ self::layoutHandle(
1036
+ $handle, EcomDev_PHPUnit_Constraint_Layout_Handle::TYPE_LOADED
1037
+ )
1038
+ ),
1039
+ $message
1040
+ );
1041
+ }
1042
+
1043
+ /**
1044
+ * Assert that layout handle is loaded into layout updates after expected one
1045
+ *
1046
+ *
1047
+ * @param string $handle
1048
+ * @param string $message
1049
+ */
1050
+ public static function assertLayoutHandleLoadedAfter($handle, $after, $message = '')
1051
+ {
1052
+ self::assertLayoutHandleLoaded($handle);
1053
+ self::assertThatLayout(
1054
+ self::layoutHandle(
1055
+ $handle, EcomDev_PHPUnit_Constraint_Layout_Handle::TYPE_LOADED_AFTER,
1056
+ $after
1057
+ ),
1058
+ $message
1059
+ );
1060
+ }
1061
+
1062
+ /**
1063
+ * Assert that layout handle is loaded into layout updates after expected one
1064
+ *
1065
+ *
1066
+ * @param string $handle
1067
+ * @param string $message
1068
+ */
1069
+ public static function assertLayoutHandleLoadedBefore($handle, $before, $message = '')
1070
+ {
1071
+ self::assertLayoutHandleLoaded($handle);
1072
+ self::assertThatLayout(
1073
+ self::layoutHandle(
1074
+ $handle, EcomDev_PHPUnit_Constraint_Layout_Handle::TYPE_LOADED_BEFORE,
1075
+ $before
1076
+ ),
1077
+ $message
1078
+ );
1079
+ }
1080
+
1081
+ /**
1082
+ * Assert that layout block is created via layout file
1083
+ *
1084
+ *
1085
+ * @param string $blockName
1086
+ * @param string $message
1087
+ */
1088
+ public static function assertLayoutBlockCreated($blockName, $message = '')
1089
+ {
1090
+ self::assertThatLayout(
1091
+ self::layoutBlock(
1092
+ $blockName, EcomDev_PHPUnit_Constraint_Layout_Block::TYPE_CREATED
1093
+ ),
1094
+ $message
1095
+ );
1096
+ }
1097
+
1098
+ /**
1099
+ * Assert that layout block is removed via layout file
1100
+ *
1101
+ * @param string $blockName
1102
+ * @param string $message
1103
+ */
1104
+ public static function assertLayoutBlockRemoved($blockName, $message = '')
1105
+ {
1106
+ self::assertThatLayout(
1107
+ self::layoutBlock(
1108
+ $blockName, EcomDev_PHPUnit_Constraint_Layout_Block::TYPE_REMOVED
1109
+ ),
1110
+ $message
1111
+ );
1112
+ }
1113
+
1114
+ /**
1115
+ * Assert that layout block is rendered
1116
+ *
1117
+ * @param string $blockName
1118
+ * @param string $message
1119
+ */
1120
+ public static function assertLayoutBlockRendered($blockName, $message = '')
1121
+ {
1122
+ self::assertThatLayout(
1123
+ self::layoutBlock(
1124
+ $blockName, EcomDev_PHPUnit_Constraint_Layout_Block::TYPE_RENDERED
1125
+ ),
1126
+ $message
1127
+ );
1128
+ }
1129
+
1130
+ /**
1131
+ * Assert that layout block is not rendered
1132
+ *
1133
+ * @param string $blockName
1134
+ * @param string $message
1135
+ */
1136
+ public static function assertLayoutBlockNotRendered($blockName, $message = '')
1137
+ {
1138
+ self::assertThatLayout(
1139
+ self::logicalNot(
1140
+ self::layoutBlock(
1141
+ $blockName, EcomDev_PHPUnit_Constraint_Layout_Block::TYPE_RENDERED
1142
+ )
1143
+ ),
1144
+ $message
1145
+ );
1146
+ }
1147
+
1148
+ /**
1149
+ * Assert that layout block rendered content is evaluated by constraint
1150
+ *
1151
+ * @param string $blockName
1152
+ * @param PHPUnit_Framework_Constraint $constraint
1153
+ * @param string $message
1154
+ */
1155
+ public static function assertLayoutBlockRenderedContent($blockName,
1156
+ PHPUnit_Framework_Constraint $constraint, $message = '')
1157
+ {
1158
+ self::assertThatLayout(
1159
+ self::layoutBlock(
1160
+ $blockName,
1161
+ EcomDev_PHPUnit_Constraint_Layout_Block::TYPE_RENDERED,
1162
+ $constraint
1163
+ ),
1164
+ $message
1165
+ );
1166
+ }
1167
+
1168
+ /**
1169
+ * Assert that layout block rendered content is not evaluated by constraint
1170
+ *
1171
+ * @param string $blockName
1172
+ * @param PHPUnit_Framework_Constraint $constraint
1173
+ * @param string $message
1174
+ */
1175
+ public static function assertLayoutBlockRenderedContentNot($blockName,
1176
+ PHPUnit_Framework_Constraint $constraint, $message = '')
1177
+ {
1178
+ self::assertThatLayout(
1179
+ self::layoutBlock(
1180
+ $blockName,
1181
+ EcomDev_PHPUnit_Constraint_Layout_Block::TYPE_RENDERED,
1182
+ self::logicalNot($constraint)
1183
+ ),
1184
+ $message
1185
+ );
1186
+ }
1187
+
1188
+ /**
1189
+ * Assert that layout block type is a type of expected class alias
1190
+ *
1191
+ * @param string $blockName
1192
+ * @param string $classAlias
1193
+ * @param string $message
1194
+ */
1195
+ public static function assertLayoutBlockTypeOf($blockName, $classAlias, $message = '')
1196
+ {
1197
+ self::assertThatLayout(
1198
+ self::layoutBlock(
1199
+ $blockName,
1200
+ EcomDev_PHPUnit_Constraint_Layout_Block::TYPE_TYPE,
1201
+ $classAlias
1202
+ ),
1203
+ $message
1204
+ );
1205
+ }
1206
+
1207
+ /**
1208
+ * Assert that layout block type is not a type of expected class alias
1209
+ *
1210
+ * @param string $blockName
1211
+ * @param string $classAlias
1212
+ * @param string $message
1213
+ */
1214
+ public static function assertLayoutBlockNotTypeOf($blockName, $classAlias, $message = '')
1215
+ {
1216
+ self::assertThatLayout(
1217
+ self::logicalNot(
1218
+ self::layoutBlock(
1219
+ $blockName,
1220
+ EcomDev_PHPUnit_Constraint_Layout_Block::TYPE_TYPE,
1221
+ $classAlias
1222
+ )
1223
+ ),
1224
+ $message
1225
+ );
1226
+ }
1227
+
1228
+ /**
1229
+ * Assert that layout block type is an instance of expected class
1230
+ *
1231
+ * @param string $blockName
1232
+ * @param string $className
1233
+ * @param string $message
1234
+ */
1235
+ public static function assertLayoutBlockInstanceOf($blockName, $className, $message = '')
1236
+ {
1237
+ self::assertThatLayout(
1238
+ self::layoutBlock(
1239
+ $blockName,
1240
+ EcomDev_PHPUnit_Constraint_Layout_Block::TYPE_INSTANCE_OF,
1241
+ $className
1242
+ ),
1243
+ $message
1244
+ );
1245
+ }
1246
+
1247
+ /**
1248
+ * Assert that layout block type is an instance of expected class
1249
+ *
1250
+ * @param string $blockName
1251
+ * @param string $className
1252
+ * @param string $message
1253
+ */
1254
+ public static function assertLayoutBlockNotInstanceOf($blockName, $className, $message = '')
1255
+ {
1256
+ self::assertThatLayout(
1257
+ self::logicalNot(
1258
+ self::layoutBlock(
1259
+ $blockName,
1260
+ EcomDev_PHPUnit_Constraint_Layout_Block::TYPE_INSTANCE_OF,
1261
+ $className
1262
+ )
1263
+ ),
1264
+ $message
1265
+ );
1266
+ }
1267
+
1268
+ /**
1269
+ * Assert that layout block parent is equal to expected
1270
+ *
1271
+ * @param string $blockName
1272
+ * @param string $parentBlockName
1273
+ * @param string $message
1274
+ */
1275
+ public static function assertLayoutBlockParentEquals($blockName, $parentBlockName, $message = '')
1276
+ {
1277
+ self::assertThatLayout(
1278
+ self::layoutBlock(
1279
+ $blockName,
1280
+ EcomDev_PHPUnit_Constraint_Layout_Block::TYPE_PARENT_NAME,
1281
+ $parentBlockName
1282
+ ),
1283
+ $message
1284
+ );
1285
+ }
1286
+
1287
+ /**
1288
+ * Assert that layout block parent is not equal to expected
1289
+ *
1290
+ * @param string $blockName
1291
+ * @param string $parentBlockName
1292
+ * @param string $message
1293
+ */
1294
+ public static function assertLayoutBlockParentNotEquals($blockName, $parentBlockName, $message = '')
1295
+ {
1296
+ self::assertThatLayout(
1297
+ self::logicalNot(
1298
+ self::layoutBlock(
1299
+ $blockName,
1300
+ EcomDev_PHPUnit_Constraint_Layout_Block::TYPE_PARENT_NAME,
1301
+ $parentBlockName
1302
+ )
1303
+ ),
1304
+ $message
1305
+ );
1306
+ }
1307
+
1308
+ /**
1309
+ * Assert that layout block is placed after expected
1310
+ *
1311
+ * @param string $blockName
1312
+ * @param string $after
1313
+ * @param string $message
1314
+ */
1315
+ public static function assertLayoutBlockAfter($blockName, $after, $message = '')
1316
+ {
1317
+ self::assertThatLayout(
1318
+ self::layoutBlock(
1319
+ $blockName,
1320
+ EcomDev_PHPUnit_Constraint_Layout_Block::TYPE_AFTER,
1321
+ $after
1322
+ ),
1323
+ $message
1324
+ );
1325
+ }
1326
+
1327
+ /**
1328
+ * Assert that layout block is placed before expected
1329
+ *
1330
+ * @param string $blockName
1331
+ * @param string $before
1332
+ * @param string $message
1333
+ */
1334
+ public static function assertLayoutBlockBefore($blockName, $before, $message = '')
1335
+ {
1336
+ self::assertThatLayout(
1337
+ self::layoutBlock(
1338
+ $blockName,
1339
+ EcomDev_PHPUnit_Constraint_Layout_Block::TYPE_BEFORE,
1340
+ $before
1341
+ ),
1342
+ $message
1343
+ );
1344
+ }
1345
+
1346
+ /**
1347
+ * Assert that layout block is placed after all expected ones
1348
+ *
1349
+ * @param string $blockName
1350
+ * @param array $after
1351
+ * @param string $message
1352
+ */
1353
+ public static function assertLayoutBlockAfterAll($blockName, array $after, $message = '')
1354
+ {
1355
+ $constaints = array();
1356
+ foreach ($after as $value) {
1357
+ $constaints[] = self::layoutBlock(
1358
+ $blockName, EcomDev_PHPUnit_Constraint_Layout_Block::TYPE_AFTER, $value
1359
+ );
1360
+ }
1361
+
1362
+ $logicalAnd = new PHPUnit_Framework_Constraint_And();
1363
+ $logicalAnd->setConstraints($constaints);
1364
+ self::assertThatLayout($logicalAnd, $message);
1365
+ }
1366
+
1367
+ /**
1368
+ * Assert that layout block is placed after all expected ones
1369
+ *
1370
+ * @param string $blockName
1371
+ * @param array $after
1372
+ * @param string $message
1373
+ */
1374
+ public static function assertLayoutBlockBeforeAll($blockName, array $before, $message = '')
1375
+ {
1376
+ $constaints = array();
1377
+ foreach ($before as $value) {
1378
+ $constaints[] = self::layoutBlock(
1379
+ $blockName, EcomDev_PHPUnit_Constraint_Layout_Block::TYPE_BEFORE, $value
1380
+ );
1381
+ }
1382
+
1383
+ $logicalAnd = new PHPUnit_Framework_Constraint_And();
1384
+ $logicalAnd->setConstraints($constaints);
1385
+ self::assertThatLayout($logicalAnd, $message);
1386
+ }
1387
+
1388
+
1389
+
1390
+ /**
1391
+ * Assert that layout block type is on the root rendering level
1392
+ *
1393
+ * @param string $blockName
1394
+ * @param string $message
1395
+ */
1396
+ public static function assertLayoutBlockRootLevel($blockName, $message = '')
1397
+ {
1398
+ self::assertThatLayout(
1399
+ self::layoutBlock(
1400
+ $blockName,
1401
+ EcomDev_PHPUnit_Constraint_Layout_Block::TYPE_ROOT_LEVEL
1402
+ ),
1403
+ $message
1404
+ );
1405
+ }
1406
+
1407
+ /**
1408
+ * Assert that layout block type is not on the root rendering level
1409
+ *
1410
+ * @param string $blockName
1411
+ * @param string $message
1412
+ */
1413
+ public static function assertLayoutBlockNotRootLevel($blockName, $message = '')
1414
+ {
1415
+ self::assertThatLayout(
1416
+ self::logicalNot(
1417
+ self::layoutBlock(
1418
+ $blockName,
1419
+ EcomDev_PHPUnit_Constraint_Layout_Block::TYPE_ROOT_LEVEL
1420
+ )
1421
+ ),
1422
+ $message
1423
+ );
1424
+ }
1425
+
1426
+ /**
1427
+ * Assert that layout block action was invoked
1428
+ *
1429
+ *
1430
+ * @param string $blockName
1431
+ * @param string $method
1432
+ * @param string $message
1433
+ * @param array|null $params
1434
+ * @param string $searchType
1435
+ */
1436
+ public static function assertLayoutBlockActionInvoked($blockName, $method, $message = '',
1437
+ array $arguments = null, $searchType = EcomDev_PHPUnit_Constraint_Layout_Block_Action::SEARCH_TYPE_AND)
1438
+ {
1439
+ self::assertThatLayout(
1440
+ self::layoutBlockAction(
1441
+ $blockName, $method,
1442
+ EcomDev_PHPUnit_Constraint_Layout_Block_Action::TYPE_INVOKED, null,
1443
+ $arguments, $searchType
1444
+ ),
1445
+ $message
1446
+ );
1447
+ }
1448
+
1449
+ /**
1450
+ * Assert that layout block action was not invoked
1451
+ *
1452
+ *
1453
+ * @param string $blockName
1454
+ * @param string $method
1455
+ * @param string $message
1456
+ * @param array|null $params
1457
+ * @param string $searchType
1458
+ */
1459
+ public static function assertLayoutBlockActionNotInvoked($blockName, $method, $message = '',
1460
+ array $arguments = null, $searchType = EcomDev_PHPUnit_Constraint_Layout_Block_Action::SEARCH_TYPE_AND)
1461
+ {
1462
+ self::assertThatLayout(
1463
+ self::logicalNot(
1464
+ self::layoutBlockAction(
1465
+ $blockName, $method,
1466
+ EcomDev_PHPUnit_Constraint_Layout_Block_Action::TYPE_INVOKED, null,
1467
+ $arguments, $searchType
1468
+ )
1469
+ ),
1470
+ $message
1471
+ );
1472
+ }
1473
+
1474
+ /**
1475
+ * Assert that layout block action was invoked at least expected number of times
1476
+ *
1477
+ *
1478
+ * @param string $blockName
1479
+ * @param string $method
1480
+ * @param string $message
1481
+ * @param array|null $params
1482
+ * @param string $searchType
1483
+ */
1484
+ public static function assertLayoutBlockActionInvokedAtLeast($blockName, $method, $invokationCount,
1485
+ $message = '', array $arguments = null,
1486
+ $searchType = EcomDev_PHPUnit_Constraint_Layout_Block_Action::SEARCH_TYPE_AND)
1487
+ {
1488
+ self::assertThatLayout(
1489
+ self::layoutBlockAction(
1490
+ $blockName, $method,
1491
+ EcomDev_PHPUnit_Constraint_Layout_Block_Action::TYPE_INVOKED_AT_LEAST, $invokationCount,
1492
+ $arguments, $searchType
1493
+ ),
1494
+ $message
1495
+ );
1496
+ }
1497
+
1498
+ /**
1499
+ * Assert that layout block action was invoked exactly expected number of times
1500
+ *
1501
+ *
1502
+ * @param string $blockName
1503
+ * @param string $method
1504
+ * @param string $message
1505
+ * @param array|null $params
1506
+ * @param string $searchType
1507
+ */
1508
+ public static function assertLayoutBlockActionInvokedExactly($blockName, $method, $invokationCount,
1509
+ $message = '', array $arguments = null,
1510
+ $searchType = EcomDev_PHPUnit_Constraint_Layout_Block_Action::SEARCH_TYPE_AND)
1511
+ {
1512
+ self::assertThatLayout(
1513
+ self::layoutBlockAction(
1514
+ $blockName, $method,
1515
+ EcomDev_PHPUnit_Constraint_Layout_Block_Action::TYPE_INVOKED_EXACTLY, $invokationCount,
1516
+ $arguments, $searchType
1517
+ ),
1518
+ $message
1519
+ );
1520
+ }
1521
+
1522
+ /**
1523
+ * Assert that layout block property is matched constraint conditions
1524
+ *
1525
+ * @param string $blockName
1526
+ * @param string $propertyName
1527
+ * @param PHPUnit_Framework_Constraint $constraint
1528
+ * @param string $message
1529
+ */
1530
+ public static function assertLayoutBlockProperty($blockName, $propertyName,
1531
+ PHPUnit_Framework_Constraint $constraint, $message = '')
1532
+ {
1533
+ self::assertThatLayout(
1534
+ self::layoutBlockProperty($blockName, $propertyName, $constraint),
1535
+ $message
1536
+ );
1537
+ }
1538
+
1539
+ /**
1540
+ * Assert that layout block property is not matched constraint conditions
1541
+ *
1542
+ * @param string $blockName
1543
+ * @param string $propertyName
1544
+ * @param PHPUnit_Framework_Constraint $constraint
1545
+ * @param string $message
1546
+ */
1547
+ public static function assertLayoutBlockPropertyNot($blockName, $propertyName,
1548
+ PHPUnit_Framework_Constraint $constraint, $message = '')
1549
+ {
1550
+ self::assertThatLayout(
1551
+ self::logicalNot(
1552
+ self::layoutBlockProperty($blockName, $propertyName, $constraint)
1553
+ ),
1554
+ $message
1555
+ );
1556
+ }
1557
+
1558
+ /**
1559
+ * Assert that layout block property is equal to expected value
1560
+ *
1561
+ * @param string $blockName
1562
+ * @param string $propertyName
1563
+ * @param mixed $expectedValue
1564
+ * @param string $message
1565
+ * @param float $delta
1566
+ * @param integer $maxDepth
1567
+ * @param boolean $canonicalize
1568
+ * @param boolean $ignoreCase
1569
+ */
1570
+ public static function assertLayoutBlockPropertyEquals($blockName, $propertyName,
1571
+ $expectedValue, $message = '', $delta = 0, $maxDepth = 10, $canonicalize = false,
1572
+ $ignoreCase = false)
1573
+ {
1574
+ self::assertLayoutBlockProperty(
1575
+ $blockName, $propertyName,
1576
+ self::equalTo($expectedValue, $delta, $maxDepth, $canonicalize, $ignoreCase),
1577
+ $message
1578
+ );
1579
+ }
1580
+
1581
+ /**
1582
+ * Assert that layout block property is not equal to expected value
1583
+ *
1584
+ * @param string $blockName
1585
+ * @param string $propertyName
1586
+ * @param mixed $expectedValue
1587
+ * @param string $message
1588
+ * @param float $delta
1589
+ * @param integer $maxDepth
1590
+ * @param boolean $canonicalize
1591
+ * @param boolean $ignoreCase
1592
+ */
1593
+ public static function assertLayoutBlockPropertyNotEquals($blockName, $propertyName,
1594
+ $expectedValue, $message = '', $delta = 0, $maxDepth = 10, $canonicalize = false,
1595
+ $ignoreCase = false)
1596
+ {
1597
+ self::assertLayoutBlockPropertyNot(
1598
+ $blockName, $propertyName,
1599
+ self::equalTo($expectedValue, $delta, $maxDepth, $canonicalize, $ignoreCase),
1600
+ $message
1601
+ );
1602
+ }
1603
+
1604
+
1605
+ /**
1606
+ * Assert that layout block property is the same as expected value
1607
+ *
1608
+ * @param string $blockName
1609
+ * @param string $propertyName
1610
+ * @param mixed $expectedValue
1611
+ * @param string $message
1612
+ */
1613
+ public static function assertLayoutBlockPropertySame($blockName, $propertyName,
1614
+ $expectedValue, $message = '')
1615
+ {
1616
+ self::assertLayoutBlockProperty(
1617
+ $blockName, $propertyName,
1618
+ self::identicalTo($expectedValue),
1619
+ $message
1620
+ );
1621
+ }
1622
+
1623
+ /**
1624
+ * Assert that layout block property is not the same as expected value
1625
+ *
1626
+ * @param string $blockName
1627
+ * @param string $propertyName
1628
+ * @param mixed $expectedValue
1629
+ * @param string $message
1630
+ */
1631
+ public static function assertLayoutBlockPropertyNotSame($blockName, $propertyName,
1632
+ $expectedValue, $message = '')
1633
+ {
1634
+ self::assertLayoutBlockPropertyNot(
1635
+ $blockName, $propertyName,
1636
+ self::identicalTo($expectedValue),
1637
+ $message
1638
+ );
1639
+ }
1640
+
1641
+ /**
1642
+ * Assert that layout block property is equal to expected php internal type
1643
+ *
1644
+ * @param string $blockName
1645
+ * @param string $propertyName
1646
+ * @param string $type
1647
+ * @param string $message
1648
+ */
1649
+ public static function assertLayoutBlockPropertyType($blockName, $propertyName,
1650
+ $type, $message = '')
1651
+ {
1652
+ self::assertLayoutBlockProperty(
1653
+ $blockName, $propertyName,
1654
+ self::isType($type),
1655
+ $message
1656
+ );
1657
+ }
1658
+
1659
+ /**
1660
+ * Assert that layout block property is not equal to expected php internal type
1661
+ *
1662
+ * @param string $blockName
1663
+ * @param string $propertyName
1664
+ * @param string $type
1665
+ * @param string $message
1666
+ */
1667
+ public static function assertLayoutBlockPropertyNotType($blockName, $propertyName,
1668
+ $type, $message = '')
1669
+ {
1670
+ self::assertLayoutBlockPropertyNot(
1671
+ $blockName, $propertyName,
1672
+ self::isType($type),
1673
+ $message
1674
+ );
1675
+ }
1676
+
1677
+
1678
+ /**
1679
+ * Assert that layout block property is an instance of expected class name
1680
+ *
1681
+ * @param string $blockName
1682
+ * @param string $propertyName
1683
+ * @param string $expectedClassName
1684
+ * @param string $message
1685
+ */
1686
+ public static function assertLayoutBlockPropertyInstanceOf($blockName, $propertyName,
1687
+ $expectedClassName, $message = '')
1688
+ {
1689
+ self::assertLayoutBlockProperty(
1690
+ $blockName, $propertyName,
1691
+ self::isInstanceOf($expectedClassName),
1692
+ $message
1693
+ );
1694
+ }
1695
+
1696
+ /**
1697
+ * Assert that layout block property is not an instance of expected class name
1698
+ *
1699
+ * @param string $blockName
1700
+ * @param string $propertyName
1701
+ * @param string $expectedClassName
1702
+ * @param string $message
1703
+ */
1704
+ public static function assertLayoutBlockPropertyNotInstanceOf($blockName, $propertyName,
1705
+ $expectedClassName, $message = '')
1706
+ {
1707
+ self::assertLayoutBlockPropertyNot(
1708
+ $blockName, $propertyName,
1709
+ self::isInstanceOf($expectedClassName),
1710
+ $message
1711
+ );
1712
+ }
1713
+
1714
+ /**
1715
+ * Assert that layout block property is empty
1716
+ *
1717
+ * @param string $blockName
1718
+ * @param string $propertyName
1719
+ * @param string $message
1720
+ */
1721
+ public static function assertLayoutBlockPropertyEmpty($blockName, $propertyName, $message = '')
1722
+ {
1723
+ self::assertLayoutBlockProperty(
1724
+ $blockName, $propertyName,
1725
+ self::isEmpty(),
1726
+ $message
1727
+ );
1728
+ }
1729
+
1730
+ /**
1731
+ * Assert that layout block property is not empty
1732
+ *
1733
+ * @param string $blockName
1734
+ * @param string $propertyName
1735
+ * @param string $message
1736
+ */
1737
+ public static function assertLayoutBlockPropertyNotEmpty($blockName, $propertyName, $message = '')
1738
+ {
1739
+ self::assertLayoutBlockPropertyNot(
1740
+ $blockName, $propertyName,
1741
+ self::isEmpty(),
1742
+ $message
1743
+ );
1744
+ }
1745
+
1746
+ /**
1747
+ * Assert that layout block property is null
1748
+ *
1749
+ * @param string $blockName
1750
+ * @param string $propertyName
1751
+ * @param string $message
1752
+ */
1753
+ public static function assertLayoutBlockPropertyNull($blockName, $propertyName, $message = '')
1754
+ {
1755
+ self::assertLayoutBlockProperty(
1756
+ $blockName, $propertyName,
1757
+ self::isNull(),
1758
+ $message
1759
+ );
1760
+ }
1761
+
1762
+ /**
1763
+ * Assert that layout block property is not null
1764
+ *
1765
+ * @param string $blockName
1766
+ * @param string $propertyName
1767
+ * @param string $message
1768
+ */
1769
+ public static function assertLayoutBlockPropertyNotNull($blockName, $propertyName, $message = '')
1770
+ {
1771
+ self::assertLayoutBlockPropertyNot(
1772
+ $blockName, $propertyName,
1773
+ self::isEmpty(),
1774
+ $message
1775
+ );
1776
+ }
1777
+
1778
+ /**
1779
+ * Set up controller params
1780
+ * (non-PHPdoc)
1781
+ * @see EcomDev_PHPUnit_Test_Case::setUp()
1782
+ */
1783
+ protected function setUp()
1784
+ {
1785
+ parent::setUp();
1786
+
1787
+ $this->reset();
1788
+ $this->registerCookieStub();
1789
+ $this->getCookies()->reset();
1790
+ $this->app()->getFrontController()->init();
1791
+ }
1792
+
1793
+ /**
1794
+ * Registers cookie stub
1795
+ *
1796
+ * @return EcomDev_PHPUnit_Test_Case_Controller
1797
+ */
1798
+ protected function registerCookieStub()
1799
+ {
1800
+ $cookie = $this->getModelMock('core/cookie', array('set', 'delete'));
1801
+
1802
+ $cookie->expects($this->any())
1803
+ ->method('set')
1804
+ ->will($this->returnCallback(
1805
+ array($this, 'setCookieCallback')
1806
+ ));
1807
+
1808
+ $cookie->expects($this->any())
1809
+ ->method('delete')
1810
+ ->will($this->returnCallback(
1811
+ array($this, 'deleteCookieCallback')
1812
+ ));
1813
+
1814
+ $this->replaceByMock('singleton', 'core/cookie', $cookie);
1815
+ return $this;
1816
+ }
1817
+
1818
+ /**
1819
+ * A callback that is invoked when a cookie is set
1820
+ * Emulates cookies processing by browser
1821
+ * Uses Zend_Http_CookieJar component
1822
+ *
1823
+ * @param string $name
1824
+ * @param string $value
1825
+ * @param int|boolean|null $period
1826
+ * @param string|null $path
1827
+ * @param string|null $domain
1828
+ * @param boolean|null $secure
1829
+ * @param boolean|null $httponly
1830
+ * @return EcomDev_PHPUnit_Test_Case_Controller
1831
+ */
1832
+ public function setCookieCallback($name, $value, $period = null, $path = null, $domain = null, $secure = null, $httponly = null)
1833
+ {
1834
+ /* @var $coookieStub Mage_Core_Model_Cookie */
1835
+ $cookieStub = Mage::getSingleton('core/cookie');
1836
+
1837
+ $cookie = urlencode($name) . '=' . urlencode($value);
1838
+
1839
+ if ($period === true) {
1840
+ $period = 3600;
1841
+ } elseif ($period === null) {
1842
+ $period = $cookieStub->getLifetime();
1843
+ }
1844
+
1845
+ if ($path === null) {
1846
+ $path = $cookieStub->getPath();
1847
+ }
1848
+
1849
+ if ($domain !== null) {
1850
+ $domain = $cookieStub->getDomain();
1851
+ }
1852
+
1853
+ if ($period === false) {
1854
+ $expire = 0;
1855
+ } elseif ($period === 0) {
1856
+ $expire = null;
1857
+ } else {
1858
+ $expire = time() + $period;
1859
+ }
1860
+
1861
+ if ($domain !== null) {
1862
+ $cookie .= '; Domain=.' . $domain;
1863
+ }
1864
+
1865
+ if ($path !== null) {
1866
+ $cookie .= '; Path=' . urlencode($path);
1867
+ }
1868
+
1869
+ if ($expire !== null) {
1870
+ $cookie .= '; Expires='. date('r', $expire);
1871
+ }
1872
+
1873
+ if ($secure || $cookieStub->isSecure()) {
1874
+ $cookie .= '; Secure';
1875
+ }
1876
+
1877
+ if ($httponly || $cookieStub->getHttponly()) {
1878
+ $cookie .= '; HttpOnly';
1879
+ }
1880
+
1881
+ self::getCookies()->addCookie($cookie);
1882
+
1883
+ return $this;
1884
+ }
1885
+
1886
+ /**
1887
+ * A callback that is invoked when a cookie is deleted
1888
+ *
1889
+ * @return EcomDev_PHPUnit_Test_Case_Controller
1890
+ */
1891
+ public function deleteCookieCallback($name, $path = null, $domain = null, $secure = null, $httponly = null)
1892
+ {
1893
+ $this->setCookieCallback($name, null, false, $path, $domain, $secure, $httponly);
1894
+ return $this;
1895
+ }
1896
+
1897
+ /**
1898
+ * Resets controller test case
1899
+ *
1900
+ * @return EcomDev_PHPUnit_Test_Case_Controller
1901
+ */
1902
+ protected function reset()
1903
+ {
1904
+ $_SESSION = array();
1905
+ $this->getRequest()->reset();
1906
+ $this->getResponse()->reset();
1907
+ $this->getLayout()->reset();
1908
+ return $this;
1909
+ }
1910
+
1911
+ /**
1912
+ * Dispatches controller action
1913
+ *
1914
+ *
1915
+ * @param string $route
1916
+ * @param array $params
1917
+ */
1918
+ public function dispatch($route = null, array $params = array())
1919
+ {
1920
+ if (!isset($params['_store'])) {
1921
+ if (strpos($route, EcomDev_PHPUnit_Model_App::AREA_ADMINHTML) !== false) {
1922
+ $params['_store'] = EcomDev_PHPUnit_Model_App::ADMIN_STORE_CODE;
1923
+ } else {
1924
+ $params['_store'] = $this->app()->getAnyStoreView()->getCode();
1925
+ }
1926
+ }
1927
+
1928
+ if ($params['_store'] !== EcomDev_PHPUnit_Model_App::ADMIN_STORE_CODE) {
1929
+ $this->setCurrentStore($params['_store']);
1930
+ $urlModel = Mage::getModel('core/url');
1931
+ } else {
1932
+ $urlModel = Mage::getModel('adminhtml/url');
1933
+ }
1934
+
1935
+ $this->app()->resetAreas();
1936
+
1937
+ $requestUri = $urlModel->getUrl($route, $params);
1938
+ $baseUrl = $urlModel->getBaseUrl($params);
1939
+
1940
+ $this->getRequest()->resetInternalProperties();
1941
+
1942
+ $this->getRequest()->setBaseUrl($baseUrl)
1943
+ ->setRequestUri($requestUri)
1944
+ ->setPathInfo();
1945
+
1946
+ $customCookies = $this->getRequest()->getCookie();
1947
+
1948
+ $autoCookies = $this->getCookies()->getMatchingCookies($requestUri);
1949
+
1950
+ /* @var $cookie Zend_Http_Cookie */
1951
+ foreach ($autoCookies as $cookie) {
1952
+ $this->getRequest()->setCookie(
1953
+ $cookie->getName(),
1954
+ $cookie->getValue()
1955
+ );
1956
+ }
1957
+
1958
+ if ($urlModel instanceof Mage_Adminhtml_Model_Url) {
1959
+ // Workaround for secret key in admin
1960
+ $this->getRequest()->setParam(
1961
+ Mage_Adminhtml_Model_Url::SECRET_KEY_PARAM_NAME,
1962
+ $urlModel->getSecretKey()
1963
+ );
1964
+ }
1965
+
1966
+ if (!$this->getRequest()->getMethod()) {
1967
+ $this->getRequest()->setMethod('GET');
1968
+ }
1969
+
1970
+ // Workaround for form key
1971
+ if ($this->getRequest()->isPost()) {
1972
+ $this->getRequest()->setPost('form_key', Mage::getSingleton('core/session')->getFromKey());
1973
+ }
1974
+
1975
+ $this->getLayout()->reset();
1976
+ $this->getResponse()->reset();
1977
+
1978
+ $this->app()->getFrontController()->dispatch();
1979
+
1980
+ // Unset changed cookies
1981
+ $this->getRequest()->resetCookies();
1982
+ $this->getRequest()->setCookies($customCookies);
1983
+ return $this;
1984
+ }
1985
+ }
app/code/community/EcomDev/PHPUnit/Test/Suite.php ADDED
@@ -0,0 +1,177 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PHP Unit test suite for Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ *
12
+ * @category EcomDev
13
+ * @package EcomDev_PHPUnit
14
+ * @copyright Copyright (c) 2011 Ecommerce Developers (http://www.ecomdev.org)
15
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
+ * @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
17
+ */
18
+
19
+
20
+ /**
21
+ * Test suite for Magento
22
+ *
23
+ * It discovers all test cases in modules
24
+ * if they were added to 'phpunit/suite/modules' configuration node
25
+ *
26
+ */
27
+ class EcomDev_PHPUnit_Test_Suite extends PHPUnit_Framework_TestSuite
28
+ {
29
+ // Configuration path constants
30
+ const XML_PATH_UNIT_TEST_GROUPS = 'phpunit/suite/groups';
31
+ const XML_PATH_UNIT_TEST_MODULES = 'phpunit/suite/modules';
32
+ const XML_PATH_UNIT_TEST_APP = 'phpunit/suite/app/class';
33
+ const XML_PATH_UNIT_TEST_SUITE = 'phpunit/suite/test_suite';
34
+ const CACHE_TAG = 'ECOMDEV_PHPUNIT';
35
+ const CACHE_TYPE = 'ecomdev_phpunit';
36
+
37
+ /**
38
+ * Setting up test scope for Magento
39
+ * (non-PHPdoc)
40
+ * @see PHPUnit_Framework_TestSuite::setUp()
41
+ */
42
+ protected function setUp()
43
+ {
44
+ $appClass = (string) Mage::getConfig()->getNode(self::XML_PATH_UNIT_TEST_APP);
45
+ $reflectionClass = EcomDev_Utils_Reflection::getRelflection($appClass);
46
+
47
+ if ($reflectionClass->hasMethod('applyTestScope')) {
48
+ $reflectionClass->getMethod('applyTestScope')->invoke(null);
49
+ }
50
+ }
51
+
52
+ /**
53
+ * Returning Magento to the state before suite was run
54
+ * (non-PHPdoc)
55
+ * @see PHPUnit_Framework_TestSuite::tearDown()
56
+ */
57
+ protected function tearDown()
58
+ {
59
+ $appClass = (string) Mage::getConfig()->getNode(self::XML_PATH_UNIT_TEST_APP);
60
+ $reflectionClass = EcomDev_Utils_Reflection::getRelflection($appClass);
61
+
62
+ if ($reflectionClass->hasMethod('discardTestScope')) {
63
+ $reflectionClass->getMethod('discardTestScope')->invoke(null);
64
+ }
65
+ }
66
+
67
+ /**
68
+ * This method loads all available test suites for PHPUnit
69
+ *
70
+ * @return PHPUnit_Framework_TestSuite
71
+ */
72
+ public static function suite()
73
+ {
74
+ $groups = Mage::getConfig()->getNode(self::XML_PATH_UNIT_TEST_GROUPS);
75
+ $modules = Mage::getConfig()->getNode(self::XML_PATH_UNIT_TEST_MODULES);
76
+ $testSuiteClass = EcomDev_Utils_Reflection::getRelflection((string) Mage::getConfig()->getNode(self::XML_PATH_UNIT_TEST_SUITE));
77
+
78
+ if (!$testSuiteClass->isSubclassOf('EcomDev_PHPUnit_Test_Suite_Group')) {
79
+ new RuntimeException('Test Suite class should be extended from EcomDev_PHPUnit_Test_Suite_Group');
80
+ }
81
+
82
+ $suite = new self('Magento Test Suite');
83
+
84
+ // Walk through different groups in modules for finding test cases
85
+ foreach ($groups->children() as $group) {
86
+ foreach ($modules->children() as $module) {
87
+ $realModule = Mage::getConfig()->getNode('modules/' . $module->getName());
88
+ if (!$realModule || !$realModule->is('active')) {
89
+ $suite->addTest(self::warning('There is no module with name: ' . $module->getName()));
90
+ continue;
91
+ }
92
+
93
+ $moduleCodeDir = Mage::getBaseDir('code') . DS . (string) $realModule->codePool;
94
+ $searchPath = Mage::getModuleDir('', $module->getName()) . DS . 'Test' . DS . (string) $group;
95
+
96
+ if (!is_dir($searchPath)) {
97
+ continue;
98
+ }
99
+
100
+ $currentGroups = array(
101
+ $group->getName(),
102
+ $module->getName()
103
+ );
104
+
105
+ $testCases = self::_loadTestCases($searchPath, $moduleCodeDir);
106
+
107
+ foreach ($testCases as $className) {
108
+ $suite->addTest($testSuiteClass->newInstance($className, $currentGroups));
109
+ }
110
+ }
111
+ }
112
+
113
+ if (!$suite->count()) {
114
+ $suite->addTest(self::warning('There were no test cases for the current run'));
115
+ }
116
+
117
+ return $suite;
118
+ }
119
+
120
+ /**
121
+ * Loads test cases from search path,
122
+ * Will return cached result
123
+ *
124
+ * @param string $searchPath path for searching files with tests
125
+ * @param string $moduleCodeDir path where the module files are placed (e.g. app/code/local),
126
+ * used for determining the class name
127
+ */
128
+ protected static function _loadTestCases($searchPath, $moduleCodeDir)
129
+ {
130
+ if (Mage::app()->useCache(self::CACHE_TYPE)) {
131
+ $cachedTestCases = Mage::app()->loadCache(
132
+ self::CACHE_TYPE . md5($searchPath)
133
+ );
134
+ if ($cachedTestCases) {
135
+ return unserialize($cachedTestCases);
136
+ }
137
+ }
138
+
139
+ $testCases = array();
140
+
141
+ $directoryIterator = new RecursiveIteratorIterator(
142
+ new RecursiveDirectoryIterator($searchPath)
143
+ );
144
+
145
+ foreach ($directoryIterator as $fileObject) {
146
+ /* @var $fileObject SplFileObject */
147
+ // Skip entry if it is not a php file
148
+ if (!$fileObject->isFile() || $fileObject->getBasename('.php') === $fileObject->getBasename()) {
149
+ continue;
150
+ }
151
+
152
+ $classPath = substr($fileObject->getPath() . DS . $fileObject->getBasename('.php'), strlen($moduleCodeDir));
153
+ $className = uc_words(ltrim($classPath, DS), '_', DS);
154
+
155
+ // Add unit test case only
156
+ // if it is a valid class extended from EcomDev_PHPUnit_Test_Case
157
+ if (class_exists($className, true)) {
158
+ $reflectionClass = EcomDev_Utils_Reflection::getRelflection($className);
159
+ if (!$reflectionClass->isSubclassOf('EcomDev_PHPUnit_Test_Case')
160
+ || $reflectionClass->isAbstract()) {
161
+ continue;
162
+ }
163
+ $testCases[] = $className;
164
+ }
165
+ }
166
+
167
+ if (Mage::app()->useCache(self::CACHE_TYPE)) {
168
+ Mage::app()->saveCache(
169
+ serialize($testCases),
170
+ self::CACHE_TYPE . md5($searchPath),
171
+ array(self::CACHE_TAG)
172
+ );
173
+ }
174
+
175
+ return $testCases;
176
+ }
177
+ }
app/code/community/EcomDev/PHPUnit/Test/Suite/Group.php ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PHP Unit test suite for Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ *
12
+ * @category EcomDev
13
+ * @package EcomDev_PHPUnit
14
+ * @copyright Copyright (c) 2011 Ecommerce Developers (http://www.ecomdev.org)
15
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
+ * @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
17
+ */
18
+
19
+
20
+ /**
21
+ * Test suite for a group of tests (e.g. tests from the same class)
22
+ *
23
+ */
24
+ class EcomDev_PHPUnit_Test_Suite_Group extends PHPUnit_Framework_TestSuite
25
+ {
26
+ const NO_GROUP_KEYWORD = '__nogroup__';
27
+
28
+ /**
29
+ * Contructor adds test groups defined on global level
30
+ * and adds additional logic for test names retrieval
31
+ *
32
+ * (non-PHPdoc)
33
+ * @see PHPUnit_Framework_TestSuite::__construct()
34
+ * @param array $groups
35
+ */
36
+ public function __construct($theClass = '', $groups = array())
37
+ {
38
+ if (!$theClass instanceof ReflectionClass) {
39
+ $theClass = EcomDev_Utils_Reflection::getRelflection($theClass);
40
+ }
41
+
42
+ // Check annotations for test case name
43
+ $annotations = PHPUnit_Util_Test::parseTestMethodAnnotations(
44
+ $theClass->getName()
45
+ );
46
+
47
+ if (isset($annotation['name'])) {
48
+ $name = $annotations['name'];
49
+ } else {
50
+ $name = sprintf('Test suite for %s', $theClass->getName());
51
+ }
52
+
53
+ // Creates all test instances
54
+ parent::__construct($theClass, $name);
55
+
56
+ // Just sort-out them by our internal groups
57
+ foreach ($groups as $group) {
58
+ $this->groups[$group] = $this->tests();
59
+ }
60
+
61
+ foreach ($this->tests() as $test) {
62
+ if ($test instanceof PHPUnit_Framework_TestSuite) {
63
+ /* @todo
64
+ * Post an issue into PHPUnit bugtracker for
65
+ * impossiblity for specifying group by parent test case
66
+ * Becuase it is a very dirty hack :(
67
+ **/
68
+ $testGroups = array();
69
+ foreach ($groups as $group) {
70
+ $testGroups[$group] = $test->tests();
71
+ }
72
+
73
+ EcomDev_Utils_Reflection::setRestrictedPropertyValue(
74
+ $test, 'groups', $testGroups
75
+ );
76
+ }
77
+ }
78
+
79
+ // Remove ungrouped tests group, if it exists
80
+ if (isset($this->groups[self::NO_GROUP_KEYWORD])) {
81
+ unset($this->groups[self::NO_GROUP_KEYWORD]);
82
+ }
83
+ }
84
+ }
app/code/community/EcomDev/PHPUnit/etc/config.xml ADDED
@@ -0,0 +1,125 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!--
3
+ /**
4
+ * PHP Unit test suite for Magento
5
+ *
6
+ * NOTICE OF LICENSE
7
+ *
8
+ * This source file is subject to the Open Software License (OSL 3.0)
9
+ * that is bundled with this package in the file LICENSE.txt.
10
+ * It is also available through the world-wide-web at this URL:
11
+ * http://opensource.org/licenses/osl-3.0.php
12
+ *
13
+ * @category EcomDev
14
+ * @package EcomDev_PHPUnit
15
+ * @copyright Copyright (c) 2011 Ecommerce Developers (http://www.ecomdev.org)
16
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
17
+ * @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
18
+ */
19
+ -->
20
+ <config>
21
+ <modules>
22
+ <EcomDev_PHPUnit>
23
+ <version>0.1.0</version>
24
+ </EcomDev_PHPUnit>
25
+ </modules>
26
+ <global>
27
+ <models>
28
+ <ecomdev_phpunit>
29
+ <class>EcomDev_PHPUnit_Model</class>
30
+ <resourceModel>ecomdev_phpunit_mysql4</resourceModel>
31
+ </ecomdev_phpunit>
32
+ <ecomdev_phpunit_mysql4>
33
+ <class>EcomDev_PHPUnit_Model_Mysql4</class>
34
+ </ecomdev_phpunit_mysql4>
35
+ </models>
36
+ <cache>
37
+ <types>
38
+ <ecomdev_phpunit>
39
+ <label>Unit Test Cases</label>
40
+ <description>Unit test case file paths cache.</description>
41
+ <tags>ECOMDEV_PHPUNIT</tags>
42
+ </ecomdev_phpunit>
43
+ </types>
44
+ </cache>
45
+ </global>
46
+ <phpunit>
47
+ <suite>
48
+ <!-- The names of directories inside Test for recognizion of tests per group -->
49
+ <groups>
50
+ <models>Model</models>
51
+ <helpers>Helper</helpers>
52
+ <blocks>Block</blocks>
53
+ <config>Config</config>
54
+ <controllers>Controller</controllers>
55
+ </groups>
56
+ <!-- Test suite that will be used for creation of each of the tests -->
57
+ <test_suite>EcomDev_PHPUnit_Test_Suite_Group</test_suite>
58
+ <layout>
59
+ <model>ecomdev_phpunit/layout</model>
60
+ </layout>
61
+ <design>
62
+ <package>
63
+ <model>ecomdev_phpunit/design_package</model>
64
+ </package>
65
+ </design>
66
+ <expectation>
67
+ <!-- Default model for loading of expectations -->
68
+ <model>ecomdev_phpunit/expectation</model>
69
+ </expectation>
70
+ <fixture>
71
+ <!-- Default model for loading of fixtures -->
72
+ <model>ecomdev_phpunit/fixture</model>
73
+ <eav>
74
+ <!-- Here goes the list of fixture loaders for EAV
75
+ If no fixture loader is specified for entity, then default will be used
76
+ -->
77
+ <default>ecomdev_phpunit/fixture_eav_default</default>
78
+ <catalog_product>ecomdev_phpunit/fixture_eav_catalog_product</catalog_product>
79
+ <catalog_category>ecomdev_phpunit/fixture_eav_catalog_category</catalog_category>
80
+ </eav>
81
+ </fixture>
82
+ <app>
83
+ <!-- Application class name for running tests -->
84
+ <class>EcomDev_PHPUnit_Model_App</class>
85
+ <area>
86
+ <!-- Application area class name for tests -->
87
+ <class>EcomDev_PHPUnit_Model_App_Area</class>
88
+ </area>
89
+ </app>
90
+ <!-- Configuration of controller for test cases -->
91
+ <controller>
92
+ <front>
93
+ <class>EcomDev_PHPUnit_Controller_Front</class>
94
+ </front>
95
+ <request>
96
+ <class>EcomDev_PHPUnit_Controller_Request_Http</class>
97
+ </request>
98
+ <response>
99
+ <class>EcomDev_PHPUnit_Controller_Response_Http</class>
100
+ </response>
101
+ </controller>
102
+
103
+ <modules>
104
+ <!-- Place your module name in your module config.xml
105
+ For adding it to test suite -->
106
+ <!-- Example:
107
+ <Namespace_MyModule />
108
+ -->
109
+ </modules>
110
+ </suite>
111
+ </phpunit>
112
+ <test>
113
+ <!-- Definition of event observers that will be used only for test environment -->
114
+ <events>
115
+ <core_block_abstract_to_html_after>
116
+ <observers>
117
+ <ecomdev_phpunit>
118
+ <class>core/layout</class>
119
+ <method>recordBlockRender</method>
120
+ </ecomdev_phpunit>
121
+ </observers>
122
+ </core_block_abstract_to_html_after>
123
+ </events>
124
+ </test>
125
+ </config>
app/code/local/Oink/MatrixrateIntegration/Model/Observer.php ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Description of Observer
5
+ *
6
+ * @author rterrani
7
+ */
8
+ class Oink_MatrixrateIntegration_Model_Observer
9
+ {
10
+ const MATRIXRATE_SHIPPING_METHOD_CODE="matrixrate";
11
+ const MATRIXRATE_SHIPPING_METHODS_CONFIG_PATH="oink/matrixrate/shipping_methods";
12
+
13
+ public function oinkAfterSetShippingMethod(Varien_Event_Observer $observer)
14
+ {
15
+ $shippingMethod = $observer->getShippingMethod();
16
+ $availableShippingMethods = $observer->getAvailableShippingMethods();
17
+ $shippingMethodCode=$shippingMethod->getCode();
18
+ $_shippingMethod=explode("_",$shippingMethodCode);
19
+ $carrier=array_shift($_shippingMethod);
20
+ if ($carrier == self::MATRIXRATE_SHIPPING_METHOD_CODE) {
21
+ $newShippingMethod = $this->_getAvailableMethod($availableShippingMethods,$shippingMethodCode);
22
+ $shippingMethod->setCode($newShippingMethod);
23
+ }
24
+ }
25
+
26
+ protected function _getAvailableMethod($availableShippingMethods)
27
+ {
28
+ $configuredShippingMethods = Mage::getStoreConfig(self::MATRIXRATE_SHIPPING_METHODS_CONFIG_PATH);
29
+ $matrixrateShippingRates=$availableShippingMethods[self::MATRIXRATE_SHIPPING_METHOD_CODE];
30
+ foreach ($configuredShippingMethods as $key => $shippingMethod) {
31
+ foreach ($matrixrateShippingRates as $matrixrateKey => $matrixrateShippingRate) {
32
+ if($matrixrateShippingRate->getMethodTitle()==$shippingMethod["method"]){
33
+ return $matrixrateShippingRate->getCode();
34
+ }
35
+ }
36
+ }
37
+ return $defaultShipmentMethod;
38
+ }
39
+
40
+ }
app/code/local/Oink/MatrixrateIntegration/etc/config.xml ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <modules>
4
+ <Oink_MatrixrateIntegration>
5
+ <version>1.0.0.0</version>
6
+ </Oink_MatrixrateIntegration>
7
+ </modules>
8
+ <global>
9
+ <models>
10
+ <oink_matrixrate_integration>
11
+ <class>Oink_MatrixrateIntegration_Model</class>
12
+ </oink_matrixrate_integration>
13
+ </models>
14
+ <events>
15
+ <oink_after_set_shipping_method>
16
+ <observers>
17
+ <oink_matrixrate_integration>
18
+ <class>oink_matrixrate_integration/observer</class>
19
+ <method>oinkAfterSetShippingMethod</method>
20
+ </oink_matrixrate_integration>
21
+ </observers>
22
+ </oink_after_set_shipping_method>
23
+ </events>
24
+ </global>
25
+ <frontend>
26
+ </frontend>
27
+ <default>
28
+ <oink>
29
+ <matrixrate>
30
+ <shipping_methods>
31
+ <expedited>
32
+ <method>FedEx Expedited (2-3 Day) (w/ Tracking)</method>
33
+ </expedited>
34
+ <ground>
35
+ <method>FedEx Ground (w/ Tracking)</method>
36
+ </ground>
37
+ <overnight>
38
+ <method>FedEx Overnight (w/ Tracking)</method>
39
+ </overnight>
40
+ <standard>
41
+ <method>Standard USPS (w/ Delivery Confirmation)</method>
42
+ </standard>
43
+ </shipping_methods>
44
+ </matrixrate>
45
+ </oink>
46
+ </default>
47
+ </config>
app/code/local/Oink/Oink/Block/Adminhtml/Sales/Order/View/Tab/Oink.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Oink_Oink_Block_Adminhtml_Sales_Order_View_Tab_Oink
4
+ extends Mage_Adminhtml_Block_Sales_Order_Abstract
5
+ implements Mage_Adminhtml_Block_Widget_Tab_Interface
6
+ {
7
+ /*
8
+ * @var $_order Oink_Oink_Model_Order
9
+ */
10
+ protected $_order;
11
+ /**
12
+ * ######################## TAB settings #################################
13
+ */
14
+ public function getTabLabel()
15
+ {
16
+ return Mage::helper('oink')->__('Oink');
17
+ }
18
+
19
+ public function getTabTitle()
20
+ {
21
+ return Mage::helper('oink')->__('Oink');
22
+ }
23
+
24
+ public function canShowTab()
25
+ {
26
+ return true;
27
+ }
28
+
29
+ public function isHidden()
30
+ {
31
+ $helper=Mage::helper("oink");
32
+ $order=$this->getOrder();
33
+ $vpOrder=Mage::helper("oink/checkout")->getOinkOrder($order->getId());
34
+ $this->_order=$vpOrder;
35
+ return !(bool)$vpOrder->getId();
36
+ }
37
+ }
app/code/local/Oink/Oink/Block/Adminhtml/System/Config/TestConnection.php ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Oink_Oink_Block_Adminhtml_System_Config_TestConnection
4
+ extends Mage_Adminhtml_Block_System_Config_Form_Field
5
+ {
6
+ protected function _getElementHtml(Varien_Data_Form_Element_Abstract $element)
7
+ {
8
+ $block=Mage::app()->getLayout()->createBlock("oink/adminhtml_system_config_testConnection_html");
9
+ return $block->_toHtml();
10
+ }
11
+ }
app/code/local/Oink/Oink/Block/Adminhtml/System/Config/TestConnection/Html.php ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Oink_Oink_Block_Adminhtml_System_Config_TestConnection_Html
4
+ extends Mage_Core_Block_Template
5
+ {
6
+ protected function _construct()
7
+ {
8
+ parent::_construct();
9
+ $this->setTemplate("oink/system/config/testConnection.phtml");
10
+ }
11
+
12
+ public function getAjaxUrl(){
13
+ $url=Mage::helper("adminhtml")->getUrl("*/oink/testConnection");
14
+ return $url;
15
+ }
16
+ }
app/code/local/Oink/Oink/Block/Adminhtml/System/Config/Version.php ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Oink_Oink_Block_Adminhtml_System_Config_Version
4
+ extends Mage_Adminhtml_Block_System_Config_Form_Field
5
+ {
6
+ protected function _getElementHtml(Varien_Data_Form_Element_Abstract $element)
7
+ {
8
+ $config=Mage::getConfig();
9
+ $version=(string)$config->getNode("modules/Oink_Oink/version");
10
+ return $version;
11
+ }
12
+ }
app/code/local/Oink/Oink/Block/Checkout/Button.php ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @category Oink
4
+ * @package Oink_Oink
5
+ */
6
+ class Oink_Oink_Block_Checkout_Button
7
+ extends Mage_Core_Block_Template
8
+ {
9
+
10
+ public function __construct()
11
+ {
12
+ parent::__construct();
13
+ if(Mage::helper("oink/checkout")->isEnabled()){
14
+ $this->setTemplate("oink/checkout/button.phtml");
15
+ }
16
+ }
17
+ /**
18
+ * Get checkout action url
19
+ *
20
+ * @return string
21
+ */
22
+ public function getCheckoutUrl()
23
+ {
24
+ return $this->getUrl("oink/checkout/index");
25
+ }
26
+ /**
27
+ * Get css class for button
28
+ *
29
+ * @return string
30
+ */
31
+ public function getCssClass()
32
+ {
33
+ return "oink-checkout-button";
34
+ }
35
+ /**
36
+ * Get button image url
37
+ *
38
+ * @return string
39
+ */
40
+ public function getQuickConnectImageUrl(){
41
+ return $this->getSkinUrl("images/oink/checkout/quick-connect.png");
42
+ }
43
+ /**
44
+ * Get button image url
45
+ *
46
+ * @return string
47
+ */
48
+ public function getImageUrl()
49
+ {
50
+ return "https://cdn.virtualpiggy.com/public/images/checkout-150x49.png";
51
+
52
+ }
53
+ /**
54
+ * Get login post url
55
+ *
56
+ * @return string
57
+ */
58
+ public function getLoginPostUrl(){
59
+ $secure = Mage::app()->getStore()->isCurrentlySecure();
60
+ return $this->getUrl("oink/checkout/loginPost",array("_secure"=>$secure));
61
+ }
62
+ /**
63
+ * Get login post url
64
+ *
65
+ * @return string
66
+ */
67
+ public function getQuickConnectPostUrl(){
68
+ return $this->getUrl("oink/checkout/quickconnect");
69
+ }
70
+
71
+ }
app/code/local/Oink/Oink/Block/Checkout/ParentConfirm.php ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @category Oink
4
+ * @package Oink_Oink
5
+ */
6
+ class Oink_Oink_Block_Checkout_ParentConfirm
7
+ extends Mage_Core_Block_Template
8
+ {
9
+ /**
10
+ *
11
+ * @return string
12
+ */
13
+ public function getFormActionUrl(){
14
+ return $this->getUrl("oink/checkout/processParentConfirm");
15
+ }
16
+
17
+ }
app/code/local/Oink/Oink/Block/Checkout/ParentConfirm/CSelect.php ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @category Oink
4
+ * @package Oink_Oink
5
+ */
6
+ class Oink_Oink_Block_Checkout_ParentConfirm_CSelect
7
+ extends Mage_Core_Block_Template
8
+ {
9
+ public function getChildrens(){
10
+ $helper=Mage::helper("oink");
11
+ $user=$helper->getUser();
12
+ $childrens=$user->getChildrens();
13
+ return $childrens;
14
+ }
15
+ }
app/code/local/Oink/Oink/Block/Checkout/ParentConfirm/Payment.php ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @category Oink
4
+ * @package Oink_Oink
5
+ */
6
+ class Oink_Oink_Block_Checkout_ParentConfirm_Payment
7
+ extends Mage_Core_Block_Template
8
+ {
9
+ public function getMethods(){
10
+ $helper=Mage::helper("oink");
11
+ $user=$helper->getUser();
12
+ $methods=$user->getPaymentMethods();
13
+ if (!empty($methods)){
14
+ foreach($methods as $method){
15
+ if($method->getToken() <> null){
16
+ return $methods;
17
+ }
18
+ }
19
+ }
20
+ throw new Exception("Parent has no payment accounts available/activated. Please refer to Oink's dashboard and configure/activate one.");
21
+ return;
22
+ }
23
+ }
app/code/local/Oink/Oink/Block/Checkout/Review.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @category Oink
4
+ * @package Oink_Oink
5
+ */
6
+ class Oink_Oink_Block_Checkout_Review extends Mage_Checkout_Block_Onepage_Abstract
7
+ {
8
+ protected function _construct()
9
+ {
10
+ $this->getCheckout()->setStepData('review', array(
11
+ 'label' => Mage::helper('checkout')->__('Order Review'),
12
+ 'is_show' => $this->isShow()
13
+ ));
14
+ parent::_construct();
15
+
16
+ $this->getQuote()->collectTotals()->save();
17
+ }
18
+ }
app/code/local/Oink/Oink/Block/Checkout/Review/Info.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @category Oink
4
+ * @package Oink_Oink
5
+ */
6
+ class Oink_Oink_Block_Checkout_Review_Info extends Mage_Sales_Block_Items_Abstract
7
+ {
8
+
9
+ public function __construct()
10
+ {
11
+ parent::__construct();
12
+ $this->_canEditQty=false;
13
+ }
14
+
15
+ /**
16
+ * Get array of all items what can be display directly
17
+ *
18
+ * @return array
19
+ */
20
+ public function getItems()
21
+ {
22
+ return Mage::getSingleton('checkout/session')->getQuote()->getAllVisibleItems();
23
+ }
24
+ /**
25
+ * Get all quote totals (sorted by priority)
26
+ * Method process quote states isVirtual and isMultiShipping
27
+ *
28
+ * @return array
29
+ */
30
+ public function getTotals()
31
+ {
32
+ return Mage::getSingleton('checkout/session')->getQuote()->getTotals();
33
+ }
34
+ }
app/code/local/Oink/Oink/Block/Payment/Form/Oink.php ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @category Oink
4
+ * @package Oink_Oink
5
+ */
6
+ class Oink_Oink_Block_Payment_Form_Oink
7
+ extends Mage_Payment_Block_Form
8
+ {
9
+
10
+ protected function _construct()
11
+ {
12
+ $this->setMethodLabelAfterHtml(Mage::helper("oink")->getCheckoutButtonHtml());
13
+ parent::_construct();
14
+ $this->setTemplate('oink/payment/form/oink.phtml');
15
+ }
16
+
17
+ }
app/code/local/Oink/Oink/Block/Payment/Info/Oink.php ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @category Oink
4
+ * @package Oink_Oink
5
+ */
6
+ class Oink_Oink_Block_Payment_Info_Oink
7
+ extends Mage_Payment_Block_Info
8
+ {
9
+
10
+ protected function _construct()
11
+ {
12
+ parent::_construct();
13
+ $this->setTemplate('oink/payment/info/oink.phtml');
14
+ }
15
+ /**
16
+ * Render as PDF
17
+ * @return string
18
+ */
19
+ public function toPdf()
20
+ {
21
+ $this->setTemplate('oink/payment/info/oink.phtml');
22
+ return $this->toHtml();
23
+ }
24
+
25
+ }
app/code/local/Oink/Oink/Block/Rewrite/Checkout/Onepage/Login.php ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @category Oink
4
+ * @package Oink_Oink
5
+ */
6
+ class Oink_Oink_Block_Rewrite_Checkout_Onepage_Login extends Mage_Checkout_Block_Onepage_Login
7
+ {
8
+
9
+ /**
10
+ * Render block HTML
11
+ *
12
+ * @return string
13
+ */
14
+ public function _toHtml()
15
+ {
16
+ Mage::getSingleton("customer/session")->unsParentConfirm();
17
+ $button=Mage::helper("oink")->getCheckoutButtonHtml(array("print_form"=>true));
18
+ return parent::_toHtml().$button;
19
+ }
20
+
21
+ }
app/code/local/Oink/Oink/Helper/Checkout.php ADDED
@@ -0,0 +1,528 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @category Oink
5
+ * @package Oink_Oink
6
+ */
7
+ class Oink_Oink_Helper_Checkout
8
+ extends Mage_Core_Helper_Abstract
9
+ {
10
+ /**
11
+ * Code of the payment method
12
+ *
13
+ * @var string
14
+ */
15
+ const PAYMENT_METHOD_CODE = "oink";
16
+ /**
17
+ * Approval pending code
18
+ *
19
+ * @var string
20
+ */
21
+ const APPROVAL_PENDING_CODE = "ApprovalPending";
22
+ /**
23
+ * Approval pending code
24
+ *
25
+ * @var string
26
+ */
27
+ const ADDITIONAL_DATA_INDEX = "oink_data";
28
+ /**
29
+ * Enabled code for All Users
30
+ *
31
+ * @var string
32
+ */
33
+ const ENABLE_CODE_ALL_USERS = "1";
34
+ /**
35
+ * Enabled code for All Registered Users
36
+ *
37
+ * @var string
38
+ */
39
+ const ENABLE_CODE_REGISTERED_USERS = "2";
40
+ /**
41
+ * Enabled code for All Guest Users
42
+ *
43
+ * @var string
44
+ */
45
+ const ENABLE_CODE_GUEST_USERS = "3";
46
+ /**
47
+ * Enabled code for All Registered Users
48
+ *
49
+ * @var string
50
+ */
51
+ const REGISTERED_USER_CHECKOUT_METHOD = "registered";
52
+
53
+ const ORDER_STATUS_APPROVAL_PENDING = 0;
54
+ const ORDER_STATUS_APPROVED = 1;
55
+ const ORDER_STATUS_REJECTED = -1;
56
+
57
+ protected $_order;
58
+ protected $_oinkOrder;
59
+
60
+ /**
61
+ * Check if customer have products in cart
62
+ * @return bool
63
+ */
64
+ public function customerHasProductsInCart()
65
+ {
66
+ $quote = $this->getQuote();
67
+ return (bool)$quote->getItemsCount();
68
+ }
69
+
70
+ /**
71
+ * @return bool
72
+ */
73
+ public function isCheckoutWithRegistered()
74
+ {
75
+ $quoteCheckoutMethod = $this->getQuote()->getCheckoutMethod();
76
+ return (
77
+ $quoteCheckoutMethod == Mage_Sales_Model_Quote::CHECKOUT_METHOD_REGISTER
78
+ ||
79
+ $quoteCheckoutMethod == Mage_Sales_Model_Quote::CHECKOUT_METHOD_LOGIN_IN
80
+ );
81
+ }
82
+
83
+ /**
84
+ * @return bool
85
+ */
86
+ public function isCheckoutWithGuest()
87
+ {
88
+ $quoteCheckoutMethod = $this->getQuote()->getCheckoutMethod();
89
+ return (
90
+ $quoteCheckoutMethod != Mage_Sales_Model_Quote::CHECKOUT_METHOD_REGISTER
91
+ &&
92
+ $quoteCheckoutMethod != Mage_Sales_Model_Quote::CHECKOUT_METHOD_LOGIN_IN
93
+ );
94
+ }
95
+
96
+
97
+ public function isEnabled()
98
+ {
99
+ $config = Mage::getStoreConfig("oink/checkoutbutton/show_payment_method");
100
+ $enabled = (
101
+ ($config == self::ENABLE_CODE_ALL_USERS)
102
+ ||
103
+ ($config == self::ENABLE_CODE_REGISTERED_USERS
104
+ && $this->isCheckoutWithRegistered()
105
+ ) || ($config == self::ENABLE_CODE_GUEST_USERS
106
+ && $this->isCheckoutWithGuest())
107
+ );
108
+
109
+ return $enabled;
110
+ }
111
+
112
+ public function isTwoStepsAuthorizationEnabled()
113
+ {
114
+ $configShow = Mage::getStoreConfig("oink/checkoutbutton/show_payment_method");
115
+ $configTwoSteps = Mage::getStoreConfig("oink/merchant_info/two_steps_authorization");
116
+
117
+ $enabled = (
118
+ (
119
+ ($configShow = self::ENABLE_CODE_ALL_USERS)
120
+ ||
121
+ ($configShow == self::ENABLE_CODE_REGISTERED_USERS)
122
+ ||
123
+ ($configShow == self::ENABLE_CODE_GUEST_USERS)
124
+ )
125
+ &&
126
+ ($configTwoSteps == 1)
127
+ );
128
+
129
+ return $enabled;
130
+ }
131
+
132
+
133
+ /**
134
+ * Populate the quote with addresses and totals
135
+ */
136
+ public function populateQuote()
137
+ {
138
+ $this->_createAddresses();
139
+ $this->getQuote()->collectTotals();
140
+ Mage::getSingleton('checkout/type_onepage')->savePayment(array(
141
+ "method" => self::PAYMENT_METHOD_CODE
142
+ ));
143
+ $this->getQuote()->save();
144
+ }
145
+
146
+ /**
147
+ * Get checkout quote instance by current session
148
+ *
149
+ * @return Mage_Sales_Model_Quote
150
+ */
151
+ public function getQuote()
152
+ {
153
+ return Mage::getSingleton('checkout/session')->getQuote();
154
+ }
155
+
156
+ /*
157
+ *
158
+ * @return Mage_Checkout_Model_Session
159
+ */
160
+
161
+ public function getCheckout()
162
+ {
163
+ return Mage::getSingleton("checkout/session");
164
+ }
165
+
166
+ /**
167
+ * Get Oink user
168
+ *
169
+ * @return Oink_Oink_Model_User
170
+ */
171
+ public function getUser()
172
+ {
173
+ return Mage::helper("oink")->getUser();
174
+ }
175
+
176
+ /**
177
+ * Get checkout quote instance by current session
178
+ *
179
+ * @return Mage_Sales_Model_Quote
180
+ */
181
+ public function getOrder()
182
+ {
183
+ if (is_null($this->_order)) {
184
+ $orderId = $this->getCheckout()->getLastOrderId();
185
+ $this->_order = Mage::getModel("sales/order")->load($orderId);
186
+ }
187
+ return $this->_order;
188
+ }
189
+
190
+ /**
191
+ * Create shipping and billing address from Oink user data and associate it with the quote
192
+ */
193
+ protected function _createAddresses()
194
+ {
195
+ $user = $this->getUser();
196
+ if ((bool)$user->getDeliverToChildren()) {
197
+ $oinkAddress = $user->getSelectedChildrenAddress();
198
+ } else {
199
+ $oinkAddress = $user->getAddress();
200
+ }
201
+ $quote = $this->getQuote();
202
+ $billingAddress = $quote->getBillingAddress();
203
+ $billingAddress->addData($oinkAddress->getData());
204
+ $billingAddress->setPaymentMethod(self::PAYMENT_METHOD_CODE);
205
+ $billingAddressCopy = clone $billingAddress;
206
+ $billingAddressCopy->unsAddressId()->unsAddressType();
207
+ $shippingAddress = $this->getQuote()->getShippingAddress();
208
+
209
+ $availableShippingMethods = $shippingAddress
210
+ ->addData($billingAddressCopy->getData())
211
+ ->setSameAsBilling(1)
212
+ ->setSaveInAddressBook(0)
213
+ ->setCollectShippingRates(true)
214
+ ->collectShippingRates()
215
+ ->save()
216
+ ->getGroupedAllShippingRates();
217
+
218
+ $defaultShippingMethodCode = Mage::getStoreConfig("oink/merchant_info/DefaultShipmentMethod");
219
+
220
+ $shippingMethod = new Varien_Object(array("code" => $defaultShippingMethodCode));
221
+ Mage::dispatchEvent("oink_after_set_shipping_method", array(
222
+ "shipping_method" => $shippingMethod,
223
+ "available_shipping_methods" => $availableShippingMethods,
224
+ ));
225
+
226
+ $shippingAddress
227
+ ->setShippingMethod($shippingMethod->getCode())
228
+ ->setCollectShippingRates(true);
229
+ }
230
+
231
+ /**
232
+ * Get Oink cart from the quote
233
+ * @return dtoCart
234
+ */
235
+ public function getOinkCart()
236
+ {
237
+ $quote = $this->getQuote();
238
+ $totals = $quote->getTotals();
239
+ $user = $this->getUser();
240
+ if (!isset ($totals["shipping"])) {
241
+ Mage::throwException(Mage::getStoreConfig("oink/messages/shipping_error"));
242
+ }
243
+ $cart = Mage::helper("oink")->getDtoCart();
244
+ if ((bool)$user->getDeliverToChildren()) {
245
+ $cart->ShipmentAddress = $user->getSelectedChildrenAddressDto();
246
+ } else {
247
+ $cart->ShipmentAddress = $user->getAddressDto();
248
+ }
249
+ $this->_fillCartWithItems($cart, $quote);
250
+ $cart->Currency = $quote->getBaseCurrencyCode();
251
+ $cart->Total = $quote->getGrandTotal();
252
+ $cart->ShippmentTotal = $quote->getGrandTotal();
253
+ if (isset ($totals["tax"])) {
254
+ $cart->Tax = $totals["tax"]->getValue();
255
+ } else {
256
+ $cart->Tax = 0;
257
+ }
258
+ if (isset($totals["shipping"])) {
259
+ $cart->Cost = $totals["shipping"]->getValue();
260
+ }
261
+ $cart->Discount = $quote->getBaseSubtotal() - $quote->getBaseSubtotalWithDiscount();
262
+ return $cart;
263
+ }
264
+
265
+ /**
266
+ * Get Oink cart from the quote
267
+ * @param dtoCart $cart
268
+ * @return dtoResultObject
269
+ */
270
+ public function sendCartToOink($cart)
271
+ {
272
+ $user = $this->getUser();
273
+ $order = $this->getOinkOrder();
274
+ $paymentService = Mage::helper("oink")->getOinkPaymentService();
275
+ if ($paymentService->nativeSoapExists()) {
276
+ $data = $cart->toXml();
277
+ } else {
278
+ $data = $cart->toEscapedXml();
279
+ }
280
+ Mage::helper("oink")->log($data, "cartXML");
281
+ $order->addAdditionalInformation("cartXML", $data);
282
+ /*
283
+ * $user-getToken() is saved in the database & tied to a transaction
284
+ *
285
+ */
286
+
287
+ if ($user->getData("selected_children")) {
288
+ $result = $paymentService->ProcessParentTransaction($user->getToken(), $data, "", $user->getData("selected_children"), $user->getSelectedPaymentAccount());
289
+ } else {
290
+ $result = $paymentService->ProcessTransaction($data, $user->getToken(), "");
291
+ }
292
+
293
+ $status = $paymentService->GetTransactionDetails($user->getToken(), $result->TransactionIdentifier);
294
+
295
+ $order->addAdditionalInformation("processTransactionResponse", $result->Xml);
296
+ return $result;
297
+ }
298
+
299
+ /*
300
+ *
301
+ * @param string The transaction identifier
302
+ */
303
+
304
+ public function checkTransaction($transactionId)
305
+ {
306
+ $paymentService = Mage::helper("oink")->getOinkPaymentService();
307
+ $user = $this->getUser();
308
+ $details = $paymentService->GetTransactionDetails($user->getToken(), $transactionId);
309
+ return $details;
310
+ }
311
+
312
+ /**
313
+ *
314
+ * @param int $orderId The id of the magento order
315
+ * @param string $field
316
+ * @return Oink_Oink_Model_Order
317
+ */
318
+
319
+ public function getOinkOrder($orderId = null, $field = "order_id")
320
+ {
321
+ if (is_null($this->_oinkOrder)) {
322
+ if (is_null($orderId)) {
323
+ $this->_oinkOrder = Mage::getModel("oink/order");
324
+ } else {
325
+ $this->_oinkOrder = Mage::getModel("oink/order")->load($orderId, $field);
326
+ }
327
+ }
328
+ return $this->_oinkOrder;
329
+ }
330
+
331
+ /*
332
+ *
333
+ * @param Oink_Oink_Model_Order $order
334
+ */
335
+
336
+ public function completeOrder($oinkOrder)
337
+ {
338
+ /**
339
+ * @var Mage_Sales_Model_Order_Invoice $invoice
340
+ */
341
+ $orderId = $oinkOrder->getOrderId();
342
+ $order = Mage::getModel("sales/order")->load($orderId);
343
+
344
+ try {
345
+ if (!$order->canInvoice()) {
346
+ Mage::throwException(Mage::helper('core')->__('Cannot create an invoice.'));
347
+ }
348
+
349
+ $invoice = Mage::getModel('sales/service_order', $order)->prepareInvoice();
350
+
351
+ if ($this->isTwoStepsAuthorizationEnabled()) {
352
+ $invoice->setRequestedCaptureCase(Mage_Sales_Model_Order_Invoice::NOT_CAPTURE);
353
+ if($invoice->getOrder()->getState() != Mage_Sales_Model_Order::STATE_CANCELED) {
354
+ $order->getPayment()->setIsTransactionPending(true);
355
+ }
356
+ } else {
357
+ $invoice->setRequestedCaptureCase(Mage_Sales_Model_Order_Invoice::CAPTURE_ONLINE);
358
+ }
359
+
360
+ $invoice->register();
361
+ if($invoice->getOrder()->getState() != Mage_Sales_Model_Order::STATE_CANCELED) {
362
+ $invoice->getOrder()->setIsInProcess(true);
363
+ }
364
+
365
+ $transactionSave = Mage::getModel('core/resource_transaction')
366
+ ->addObject($invoice)
367
+ ->addObject($invoice->getOrder());
368
+
369
+ $transactionSave->save();
370
+ $invoice->save();
371
+ } catch (Mage_Core_Exception $e) {
372
+ Mage::helper("oink")->log("OrderId: " . $orderId . " - " . $e->getMessage(), "errorCreatingInvoice");
373
+ }
374
+
375
+ if($order->getState() != Mage_Sales_Model_Order::STATE_CANCELED) {
376
+ $order->setStatus(Mage_Sales_Model_Order::STATE_PROCESSING);
377
+ $order->save();
378
+ }
379
+ }
380
+
381
+ /*
382
+ *
383
+ * @param Oink_Oink_Model_Order $order
384
+ */
385
+
386
+ public function cancelOrder($oinkOrder)
387
+ {
388
+ $order = Mage::getModel("sales/order")->load($oinkOrder->getOrderId());
389
+ $order->setStatus(Mage_Sales_Model_Order::STATE_CANCELED);
390
+ $order->save();
391
+ }
392
+
393
+ /**
394
+ *
395
+ */
396
+ public function cancelLastOrder()
397
+ {
398
+ $order = $this->getOrder();
399
+ $order->setStatus(Mage_Sales_Model_Order::STATE_CANCELED);
400
+ $order->save();
401
+ }
402
+
403
+ /**
404
+ * Fill Oink cart with items from the quote
405
+ * @param dtoCart $cart
406
+ * @param Mage_Sales_Model_Quote $quote
407
+ */
408
+ protected function _fillCartWithItems($cart, $quote)
409
+ {
410
+ $items = $quote->getItemsCollection();
411
+ foreach ($items as $key => $item) {
412
+ if ((bool)$item->getParentItem()) {
413
+ continue;
414
+ }
415
+ $vpItem = $this->_getCartItem($item);
416
+ $cart->AddItem($vpItem);
417
+ }
418
+ }
419
+
420
+ /**
421
+ * Fill Oink cart with items from the quote
422
+ * @param dtoCart $item
423
+ * @param Mage_Sales_Model_Quote_Item
424
+ */
425
+ protected function _getCartItem($item)
426
+ {
427
+ $product = Mage::getModel("catalog/product")->load($item->getProductId());
428
+ $itemDto = Mage::helper("oink")->getCartItemDto();
429
+ $itemDto->Total = $item->getBaseRowTotal();
430
+ $itemDto->Name = $item->getName();
431
+
432
+ // If description is null set description to name
433
+ $shortd = $product->getShortDescription();
434
+ if ($shortd == "") {
435
+ $itemDto->Description = $item->getName();
436
+ } else {
437
+ $itemDto->Description = $shortd;
438
+ }
439
+
440
+ $itemDto->Price = $item->getPrice();
441
+ $itemDto->Quantity = $item->getQty();
442
+ return $itemDto;
443
+ }
444
+
445
+ protected function _checkShippingMethod()
446
+ {
447
+
448
+ }
449
+
450
+ /**
451
+ * Get the checkout button as html
452
+ * @return string
453
+ */
454
+ public function getCheckoutButtonHtml()
455
+ {
456
+ return Mage::app()->getLayout()->createBlock("oink/checkout_button")->toHtml();
457
+ }
458
+
459
+ /**
460
+ * @param Mage_Sales_Model_Order_Invoice $invoice
461
+ * @param Mage_Sales_Model_Order_Item $item
462
+ * @return bool
463
+ */
464
+ protected function _isItemInInvoice($invoice, $item)
465
+ {
466
+ $collection = $invoice->getItemsCollection()->toArray();
467
+ $collection = isset($collection['items']) ? $collection['items'] : array();
468
+
469
+ /**
470
+ * @var array $orderItem
471
+ */
472
+ foreach ($collection as $orderItem) {
473
+ if ($orderItem['product_id'] == $item->getProductId()) {
474
+ return true;
475
+ }
476
+ }
477
+
478
+ return false;
479
+ }
480
+
481
+ /**
482
+ * Fill the empty invoice with the current cart items
483
+ *
484
+ * @param $invoice Mage_Sales_Model_Order_Invoice
485
+ * @param $order Mage_Sales_Model_Order
486
+ */
487
+ protected function _fillInvoiceWithItems($invoice, $order)
488
+ {
489
+ /**
490
+ * @var Mage_Sales_Model_Convert_Order $convertor
491
+ */
492
+ $convertor = Mage::getModel('sales/convert_order');
493
+ $savedQtys = array();
494
+
495
+ /**
496
+ * @var $orderItem Mage_Sales_Model_Order_Item
497
+ */
498
+ foreach ($order->getAllItems() as $orderItem) {
499
+
500
+ if (!$orderItem->isDummy() && !$orderItem->getQtyToInvoice() && $orderItem->getLockedDoInvoice()) {
501
+ continue;
502
+ }
503
+
504
+ if ($order->getForcedDoShipmentWithInvoice() && $orderItem->getLockedDoShip()) {
505
+ continue;
506
+ }
507
+
508
+ $item = $convertor->itemToInvoiceItem($orderItem);
509
+
510
+ if ($this->_isItemInInvoice($invoice, $item)) {
511
+ continue;
512
+ }
513
+
514
+ if (isset($savedQtys[$orderItem->getId()])) {
515
+ $qty = $savedQtys[$orderItem->getId()];
516
+ } else {
517
+ if ($orderItem->isDummy()) {
518
+ $qty = 1;
519
+ } else {
520
+ $qty = $orderItem->getQtyToInvoice();
521
+ }
522
+ }
523
+ $item->setQty($qty);
524
+ $invoice->addItem($item);
525
+ }
526
+ $invoice->collectTotals();
527
+ }
528
+ }
app/code/local/Oink/Oink/Helper/Data.php ADDED
@@ -0,0 +1,238 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @category Oink
5
+ * @package Oink_Oink
6
+ */
7
+ class Oink_Oink_Helper_Data
8
+ extends Mage_Core_Helper_Abstract
9
+ {
10
+ /**
11
+ *
12
+ * @var string
13
+ */
14
+ const VIRTUALPIGGY_CONFIGURATION_PATH="oink/merchant_info";
15
+
16
+ public function __construct()
17
+ {
18
+ Mage::helper("oink/libLoader")->loadOinkLib();
19
+ }
20
+
21
+ /**
22
+ * Authenticate child and get the the result
23
+ *
24
+ * @param string $user Oink account user
25
+ * @param string $password Oink account password
26
+ * @return bool|Oink_Oink_Model_Children
27
+ */
28
+ public function authenticateChild($user, $password)
29
+ {
30
+ /*
31
+ * magento requires a model for each entity
32
+ * all logic associated with this class in model
33
+ * Mage::getModel("oink/user_children") loads child model
34
+ * */
35
+ $children = Mage::getModel("oink/user_children");
36
+ Mage::getSingleton("customer/session")->setOinkUser($children);
37
+ return $children->login($user, $password);
38
+ }
39
+
40
+ /**
41
+ * Authenticate child and get the the result
42
+ *
43
+ * @param string $user Oink account user
44
+ * @param string $password Oink account password
45
+ * @return bool|Oink_Oink_Model_Children
46
+ */
47
+ public function authenticateUser($userName, $password)
48
+ {
49
+ $user = Mage::getModel("oink/user");
50
+ $user=$user->login($userName, $password);
51
+ Mage::getSingleton("customer/session")->setOinkUser($user);
52
+ return $user;
53
+ }
54
+
55
+ /**
56
+ * Check if the Oink user is logged
57
+ *
58
+ * @return bool
59
+ */
60
+ public function isUserLogged()
61
+ {
62
+ return (bool) $this->getUser();
63
+ }
64
+
65
+ /**
66
+ * Get Oink user
67
+ *
68
+ * @return Oink_Oink_Model_User
69
+ */
70
+ public function getUser()
71
+ {
72
+ return Mage::getSingleton("customer/session")->getOinkUser();
73
+ }
74
+
75
+ /**
76
+ * Get Oink user type
77
+ *
78
+ * @return string
79
+ */
80
+ public function getUserType()
81
+ {
82
+ $user=$this->getUser();
83
+ if($user instanceof Oink_Oink_Model_User_Children){
84
+ return Oink_Oink_Model_User::USER_CODE_TYPE_CHILDREN;
85
+ }elseif($user instanceof Oink_Oink_Model_User_Parent){
86
+ return Oink_Oink_Model_User::USER_CODE_TYPE_PARENT;
87
+ }
88
+ }
89
+
90
+ /**
91
+ * Get checkout quote instance by current session
92
+ *
93
+ * @return Mage_Sales_Model_Quote
94
+ */
95
+ public function getQuote()
96
+ {
97
+ return Mage::getSingleton('checkout/session')->getQuote();
98
+ }
99
+
100
+ /*
101
+ * Log to a specific oink log
102
+ *
103
+ * @param mixed Message, array or object to log
104
+ *
105
+ */
106
+
107
+ public function log($message, $title=null)
108
+ {
109
+ if (!is_null($title)) {
110
+ Mage::log($title, null, "oink.log", true);
111
+ }
112
+ Mage::log($message, null, "oink.log", true);
113
+ }
114
+
115
+ public function getExpiryTime()
116
+ {
117
+ $expiryTimeInDays = Mage::getStoreConfig("oink/merchant_info/order_expiration_time");
118
+ return $expiryTimeInDays * 24 * 60 * 60;
119
+ }
120
+
121
+ /**
122
+ * @param array $config Override saved config
123
+ * @return OinkPaymentService
124
+ */
125
+ public function getOinkPaymentService($config=array())
126
+ {
127
+ return new OinkPaymentService($this->getOinkConfig($config));
128
+ }
129
+
130
+ /**
131
+ * @return OinkParentService
132
+ */
133
+ public function getOinkParentService()
134
+ {
135
+ return new OinkParentService($this->getOinkConfig());
136
+ }
137
+
138
+ /**
139
+ * @return XmlSerializationService
140
+ */
141
+ public function getXmlSerializationService()
142
+ {
143
+ return new XmlSerializationService();
144
+ }
145
+
146
+ /**
147
+ * @return dtoCredentials
148
+ */
149
+ public function getDtoCredentials()
150
+ {
151
+ return new dtoCredentials();
152
+ }
153
+
154
+ /**
155
+ * @return dtoCart
156
+ */
157
+ public function getDtoCart()
158
+ {
159
+ return new dtoCart();
160
+ }
161
+
162
+ /**
163
+ * @return dtoCartItem
164
+ */
165
+ public function getCartItemDto()
166
+ {
167
+ return new dtoCartItem();
168
+ }
169
+
170
+ /**
171
+ * Get Oink payment gateway configuration filled with the
172
+ * configuration from magento
173
+ *
174
+ * @param array $override
175
+ * @return dtoPaymentGatewayConfiguration
176
+ */
177
+ public function getOinkConfig($override)
178
+ {
179
+ $mageConfig = Mage::getStoreConfig(self::VIRTUALPIGGY_CONFIGURATION_PATH);
180
+ $mageConfig["ParentServiceEndpointAddressWsdl"]=$mageConfig["ParentServiceEndpointAddress"]."?wsdl";
181
+ $mageConfig["TransactionServiceEndpointAddressWsdl"]=$mageConfig["TransactionServiceEndpointAddress"]."?wsdl";
182
+ $config = new dtoPaymentGatewayConfiguration();
183
+ foreach ($config as $key => $value) {
184
+ $config->$key = isset($override[$key]) ? $override[$key] : $mageConfig[$key];
185
+ }
186
+ return $config;
187
+ }
188
+
189
+ /**
190
+ * Get the checkout button as html
191
+ *
192
+ * @return string
193
+ */
194
+ public function getCheckoutButtonHtml($data=array())
195
+ {
196
+ return Mage::app()->getLayout()->createBlock("oink/checkout_button","",$data)->toHtml();
197
+ }
198
+
199
+ public function formatXmlString($xml)
200
+ {
201
+
202
+ // add marker linefeeds to aid the pretty-tokeniser (adds a linefeed between all tag-end boundaries)
203
+ $xml = preg_replace('/(>)(<)(\/*)/', "$1\n$2$3", $xml);
204
+
205
+ // now indent the tags
206
+ $token = strtok($xml, "\n");
207
+ $result = ''; // holds formatted version as it is built
208
+ $pad = 0; // initial indent
209
+ $matches = array(); // returns from preg_matches()
210
+ // scan each line and adjust indent based on opening/closing tags
211
+ while ($token !== false) :
212
+
213
+ // test for the various tag states
214
+ // 1. open and closing tags on same line - no change
215
+ if (preg_match('/.+<\/\w[^>]*>$/', $token, $matches)) :
216
+ $indent = 0;
217
+ // 2. closing tag - outdent now
218
+ elseif (preg_match('/^<\/\w/', $token, $matches)) :
219
+ $pad--;
220
+ // 3. opening tag - don't pad this one, only subsequent tags
221
+ elseif (preg_match('/^<\w[^>]*[^\/]>.*$/', $token, $matches)) :
222
+ $indent = 1;
223
+ // 4. no indentation needed
224
+ else :
225
+ $indent = 0;
226
+ endif;
227
+
228
+ // pad the line with the required number of leading spaces
229
+ $line = str_pad($token, strlen($token) + $pad, ' ', STR_PAD_LEFT);
230
+ $result .= $line . "\n"; // add to the cumulative result, with linefeed
231
+ $token = strtok("\n"); // get the next token
232
+ $pad += $indent; // update the pad size for subsequent lines
233
+ endwhile;
234
+
235
+ return $result;
236
+ }
237
+
238
+ }
app/code/local/Oink/Oink/Helper/LibLoader.php ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @category Oink
4
+ * @package Oink_Oink
5
+ */
6
+ class Oink_Oink_Helper_LibLoader
7
+ extends Mage_Core_Helper_Abstract
8
+ {
9
+ /**
10
+ *
11
+ * @var string
12
+ */
13
+ const VIRTUALPIGGY_LIB_FOLDER_NAME="Oink";
14
+
15
+ public function loadOinkLib(){
16
+ $this->loadDtos();
17
+ $this->loadInterfaces();
18
+ $this->loadImplementations();
19
+ }
20
+
21
+ public function loadDtos(){
22
+ /*
23
+ * VIRTUALPIGGY_LIB_FOLDER_NAME: constant relative to magento installation
24
+ * DS = directory separator (windows or linux sensitive), set in php.ini
25
+ * */
26
+ $path=Mage::getBaseDir("lib").DS;
27
+ $path.=self::VIRTUALPIGGY_LIB_FOLDER_NAME.DS."Data".DS."dtos.php";
28
+ require_once $path;
29
+ }
30
+
31
+ public function loadInterfaces(){
32
+ $path=Mage::getBaseDir("lib").DS;
33
+ $path.=self::VIRTUALPIGGY_LIB_FOLDER_NAME.DS."Services".DS."Interfaces".DS;
34
+ foreach (glob($path."*.php") as $key => $filename) {
35
+ require_once $filename;
36
+ }
37
+ }
38
+
39
+ public function loadImplementations(){
40
+ $path=Mage::getBaseDir("lib").DS;
41
+ $path.=self::VIRTUALPIGGY_LIB_FOLDER_NAME.DS."Services".DS."Implementations".DS;
42
+ foreach (glob($path."*.php") as $key => $filename) {
43
+ require_once $filename;
44
+ }
45
+ }
46
+
47
+ }
app/code/local/Oink/Oink/Model/Admin/Checkout.php ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Oink_Oink_Model_Admin_Checkout {
4
+ public function toOptionArray()
5
+ {
6
+ return array(
7
+ array('value'=>0, 'label'=>Mage::helper('oink')->__('Checkout Button and Radio Select')),
8
+ array('value'=>1, 'label'=>Mage::helper('oink')->__('Checkout Button Only')),
9
+ array('value'=>2, 'label'=>Mage::helper('oink')->__('Radio Select Only')),
10
+ );
11
+ }
12
+ }
app/code/local/Oink/Oink/Model/Admin/Enablestatus.php ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Oink_Oink_Model_Admin_Enablestatus {
4
+ public function toOptionArray()
5
+ {
6
+ return array(
7
+ array('value'=>0, 'label'=>Mage::helper('oink')->__('None')),
8
+ array('value'=>1, 'label'=>Mage::helper('oink')->__('All Users')),
9
+ array('value'=>2, 'label'=>Mage::helper('oink')->__('Only Registered Users')),
10
+ array('value'=>3, 'label'=>Mage::helper('oink')->__('Only Guest Users')),
11
+ );
12
+ }
13
+ }
app/code/local/Oink/Oink/Model/ErrorHandler.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @category Oink
5
+ * @package Oink_Oink
6
+ */
7
+ class Oink_Oink_Model_ErrorHandler
8
+ extends Mage_Core_Model_Abstract
9
+ {
10
+
11
+ protected $_errors = array(
12
+ "Merchant Application is not approved for your profile. Please add the merchant application to your profile." => array("type" => "config", "path" => "oink/messages/transaction_not_authorized"),
13
+ "The Transaction was denied because you do not have enough funds available." => array("type" => "config", "path" => "oink/messages/insufficient_funds"),
14
+ "Payment Account is disabled. Please contact your parent." => array("type" => "config", "path" => "oink/messages/parent_configuration"),
15
+ "parent_configuration" => array("type" => "config", "path" => "oink/messages/parent_configuration"),
16
+ "The payment type associated with your account is not accepted by this merchant." => array("type" => "config", "path" => "oink/messages/payment_not_accepted")
17
+ );
18
+
19
+ public function rewriteError($originalErrorMessage)
20
+ {
21
+ if($originalErrorMessage == ''){
22
+ return Mage::getStoreConfig("oink/messages/transaction_declined");
23
+ }
24
+ foreach ($this->_errors as $errorMessage => $errorConfig) {
25
+ if(strpos($originalErrorMessage, $errorMessage)!==false){
26
+ if($errorConfig["type"]=="config"){
27
+ return Mage::getStoreConfig($errorConfig["path"]);
28
+ }
29
+ }
30
+ }
31
+
32
+ return $originalErrorMessage;
33
+ }
34
+
35
+ }
app/code/local/Oink/Oink/Model/Mysql4/Order.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @category Oink
5
+ * @package Oink_Oink
6
+ */
7
+ class Oink_Oink_Model_Mysql4_Order
8
+ extends Mage_Core_Model_Mysql4_Abstract
9
+ {
10
+
11
+ /**
12
+ * Serializeable field: additional_information
13
+ *
14
+ * @var array
15
+ */
16
+ protected $_serializableFields = array(
17
+ 'additional_information' => array(null, array())
18
+ );
19
+ /**
20
+ * Initialize connection and define main table
21
+ *
22
+ */
23
+ protected function _construct()
24
+ {
25
+ $this->_init('oink/order', 'oink_order_id');
26
+ }
27
+
28
+ }
29
+
30
+ ?>
app/code/local/Oink/Oink/Model/Mysql4/Order/Collection.php ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @category Oink
5
+ * @package Oink_Oink
6
+ */
7
+ class Oink_Oink_Model_Mysql4_Order_Collection
8
+ extends Mage_Core_Model_Resource_Db_Collection_Abstract
9
+ {
10
+
11
+ /**
12
+ * Define resource model
13
+ *
14
+ */
15
+ protected function _construct()
16
+ {
17
+ $this->_init('oink/order');
18
+ }
19
+
20
+ }
21
+
22
+ ?>
app/code/local/Oink/Oink/Model/Observer.php ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @category Oink
4
+ * @package Oink_Oink
5
+ */
6
+ class Oink_Oink_Model_Observer
7
+ {
8
+ /**
9
+ *
10
+ * @param Varien_Event_Observer $observer
11
+ */
12
+ public function checkExpiredOrders($observer)
13
+ {
14
+ $now = Mage::getModel('core/date')->timestamp(time());
15
+ $expiredOrders = Mage::getModel("oink/order")->getCollection();
16
+ $expiredOrders->addFieldToFilter("expiry_date", array("lt" => $now));
17
+ foreach ($expiredOrders as $key => $order) {
18
+ Mage::helper("oink/checkout")->cancelOrder($order);
19
+ }
20
+ }
21
+
22
+ /**
23
+ *
24
+ * @param Varien_Event_Observer $observer
25
+ */
26
+ public function removeOinkPaymentMethod($observer)
27
+ {
28
+ $block = $observer->getBlock();
29
+ if ($block instanceof Mage_Checkout_Block_Onepage_Payment_Methods) {
30
+ $block->unsetChild("payment.method." . Oink_Oink_Helper_Checkout::PAYMENT_METHOD_CODE);
31
+ if (!Mage::helper("oink/checkout")->isEnabled()) {
32
+ $methods = $block->getMethods();
33
+ foreach ($methods as $key => $method) {
34
+ if ($method->getCode() == Oink_Oink_Helper_Checkout::PAYMENT_METHOD_CODE) {
35
+ unset($methods[$key]);
36
+ }
37
+ }
38
+ $block->setData('methods', $methods);
39
+ }
40
+ }
41
+ }
42
+
43
+ /**
44
+ * TODO change this to invoice PRE paid
45
+ *
46
+ * @param Varien_Event_Observer $observer
47
+ */
48
+ public function adminOrderStatusChange($observer)
49
+ {
50
+ $result = '';
51
+ $order = $observer->getEvent()->getOrder();
52
+ $state = $observer->getEvent()->getState();
53
+
54
+ if (Mage::helper("oink/checkout")->isTwoStepsAuthorizationEnabled()) {
55
+ $vpOrder = Mage::helper("oink/checkout")->getOinkOrder($order->getId());
56
+ $transactionIdentifier = $vpOrder->getTransactionIdentifier();
57
+
58
+ /**
59
+ * @var OinkPaymentService $paymentService
60
+ */
61
+ $paymentService = Mage::helper("oink")->getOinkPaymentService();
62
+
63
+ if ($transactionIdentifier) {
64
+ if ($state == Mage_Sales_Model_Order::STATE_CANCELED) {
65
+ $result = $paymentService->VoidCaptureTransactionByIdentifier($transactionIdentifier);
66
+ }
67
+
68
+ if ($result) {
69
+ Mage::helper("oink")->log($result, "resultOfProcessTwoSteps");
70
+ if (!(bool)$result->Status) {
71
+ $errorMessage = Mage::getSingleton("oink/errorHandler")->rewriteError($result->ErrorMessage);
72
+ Mage::getSingleton("core/session")->addError($errorMessage);
73
+ }
74
+ }
75
+ }
76
+ }
77
+ }
78
+
79
+ }
app/code/local/Oink/Oink/Model/Order.php ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @category Oink
5
+ * @package Oink_Oink
6
+ */
7
+ class Oink_Oink_Model_Order
8
+ extends Mage_Core_Model_Abstract
9
+ {
10
+
11
+ /**
12
+ * Initialize resource model
13
+ *
14
+ */
15
+ protected function _construct()
16
+ {
17
+ $this->_init('oink/order');
18
+ }
19
+
20
+
21
+
22
+ /*
23
+ *
24
+ * @param dtoResultObject
25
+ * @param Mage_Sales_Model_Order
26
+ */
27
+ public function addAdditionalInformation($key,$value){
28
+ $order=$this;
29
+ $data=$order->getAdditionalInformation();
30
+ $data[$key]=$value;
31
+ $order->setAdditionalInformation($data);
32
+ }
33
+
34
+
35
+
36
+
37
+ }
38
+
39
+ ?>
app/code/local/Oink/Oink/Model/Payment/Method/Oink.php ADDED
@@ -0,0 +1,164 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @category Oink
4
+ * @package Oink_Oink
5
+ */
6
+ class Oink_Oink_Model_Payment_Method_Oink
7
+ extends Mage_Payment_Model_Method_Abstract
8
+ {
9
+ /**
10
+ *
11
+ * @var string
12
+ */
13
+ protected $_code = 'oink';
14
+ protected $_canOrder = true;
15
+ protected $_formBlockType = 'oink/payment_form_oink';
16
+ protected $_infoBlockType = 'oink/payment_info_oink';
17
+ protected $_canCapture = true;
18
+
19
+ /**
20
+ * Assign data to info model instance
21
+ *
22
+ * @param mixed $data
23
+ * @return Mage_Payment_Model_Info
24
+ */
25
+ public function assignData($data)
26
+ {
27
+ Mage::log("Oink Payment info: \n" . print_r($data, true));
28
+
29
+ if (!($data instanceof Varien_Object)) {
30
+ $data = new Varien_Object($data);
31
+ }
32
+
33
+ Mage::log("Oink data: \n" . print_r($data, true));
34
+
35
+ if ($data->getBtToken()) {
36
+ $data->setPoNumber($data->getBtToken());
37
+ }
38
+ if ($data->getBtCustomerId()) {
39
+ $data->setCcOwner($data->getBtCustomerId());
40
+ }
41
+ if ($data->getPoNumber()) {
42
+ $data->setBtToken($data->getPoNumber());
43
+ }
44
+ if ($data->getCcOwner()) {
45
+ $data->setBtCustomerId($data->getCcOwner());
46
+ }
47
+
48
+ $this->getInfoInstance()->addData($data->getData());
49
+ return $this;
50
+ }
51
+
52
+ /**
53
+ * Order
54
+ *
55
+ * @param Varien_Object $orderPayment
56
+ * @return Mage_Payment_Model_Abstract
57
+ */
58
+ public function order(Varien_Object $payment, $amount)
59
+ {
60
+
61
+ $payment->setTransactionId(
62
+ $this->getInfoInstance()->getBtTransactionId()
63
+ );
64
+
65
+ return $this;
66
+ }
67
+
68
+ /**
69
+ * Capture payment abstract method
70
+ *
71
+ * @param Varien_Object $payment
72
+ * @param float $amount
73
+ *
74
+ * @return Mage_Payment_Model_Abstract|Oink_Oink_Model_Payment_Method_Oink
75
+ */
76
+ public function capture(Varien_Object $payment, $amount)
77
+ {
78
+ parent::capture($payment, $amount);
79
+
80
+ /**
81
+ * @var Oink_Oink_Helper_Checkout $vpHelper
82
+ */
83
+ $vpHelper = Mage::helper("oink/checkout");
84
+
85
+ if ($vpHelper->isTwoStepsAuthorizationEnabled()) {
86
+ $this->captureTwoStepOrder($payment, $amount);
87
+ return $this;
88
+ }
89
+
90
+
91
+ return $this;
92
+ }
93
+
94
+ /**
95
+ * @return bool
96
+ */
97
+ public function getIsTransactionPending()
98
+ {
99
+ /**
100
+ * @var Oink_Oink_Helper_Checkout $vpHelper
101
+ */
102
+ $vpHelper = Mage::helper("oink/checkout");
103
+
104
+ if ($vpHelper->isTwoStepsAuthorizationEnabled()) {
105
+ return true;
106
+ }
107
+
108
+ return parent::getIsTransactionPending();
109
+ }
110
+
111
+ /**
112
+ * Check capture availability
113
+ *
114
+ * @return bool
115
+ */
116
+ public function canCapture()
117
+ {
118
+ $order = $this->getInfoInstance()->getOrder();
119
+
120
+ if (!$this->_canCapture) {
121
+ return false;
122
+ }
123
+
124
+
125
+ if ($order) {
126
+ if ($order->getOinkStatus() == Oink_Oink_Helper_Checkout::ORDER_STATUS_APPROVED) {
127
+ return true;
128
+ } else {
129
+ //Mage::getSingleton('adminhtml/session')->addWarning('This order is not approved, so can not be captured');
130
+ return false;
131
+ }
132
+ }
133
+
134
+ return false;
135
+ }
136
+
137
+ private function captureTwoStepOrder(Varien_Object $payment, $amount)
138
+ {
139
+ /**
140
+ * @var OinkPaymentService $paymentService
141
+ */
142
+ $paymentService = Mage::helper("oink")->getOinkPaymentService();
143
+ $order = $payment->getOrder();
144
+
145
+ if (!$order) {
146
+ Mage::throwException(Mage::helper('paygate')->__('Error in capturing the payment.'));
147
+ }
148
+
149
+ $vpOrder = Mage::helper("oink/checkout")->getOinkOrder($order->getId());
150
+ $transactionIdentifier = $vpOrder->getTransactionIdentifier();
151
+
152
+ if (!$transactionIdentifier) {
153
+ Mage::throwException(Mage::helper('paygate')->__('Error in capturing the payment.'));
154
+ }
155
+
156
+ $result = $paymentService->CaptureTransactionByIdentifier($transactionIdentifier);
157
+
158
+ if (!$result->Status) {
159
+ Mage::throwException(Mage::helper('paygate')->__($result->ErrorMessage));
160
+ }
161
+
162
+ return $this;
163
+ }
164
+ }
app/code/local/Oink/Oink/Model/Sales/Order.php ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @category Oink
5
+ * @package Oink_Oink
6
+ */
7
+ class Oink_Oink_Model_Sales_Order
8
+ extends Mage_Sales_Model_Order
9
+ {
10
+ /**
11
+ * Overrides the base _setState but also dispatching a new Event
12
+ * @param string $state
13
+ * @param bool $status
14
+ * @param string $comment
15
+ * @param null $isCustomerNotified
16
+ * @return Mage_Sales_Model_Order
17
+ */
18
+
19
+ public function _setState($state, $status = false, $comment = '', $isCustomerNotified = null, $shouldProtectState = false)
20
+ {
21
+ Mage::dispatchEvent('sales_order_status_change', array('order' => $this, 'state' => $state, 'status' => $status, 'comment' => $comment, 'isCustomerNotified' => $isCustomerNotified));
22
+
23
+ return parent::_setState($state, $status, $comment, $isCustomerNotified);
24
+ }
25
+
26
+ }
app/code/local/Oink/Oink/Model/Sales/Order/Payment.php ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Created by PhpStorm.
4
+ * User: Matthew
5
+ * Date: 3/10/14
6
+ * Time: 10:53 AM
7
+ */
8
+
9
+
10
+ /**
11
+ * @category Oink
12
+ * @package Oink_Oink
13
+ */
14
+ class Oink_Oink_Model_Sales_Order_Payment
15
+ extends Mage_Sales_Model_Order_Payment {
16
+
17
+
18
+ /**
19
+ * Over-riding this function, so we can not set the payment status to processing when is two step
20
+ * @param float $amount
21
+ * @return $this|Mage_Sales_Model_Order_Payment
22
+ */
23
+ protected function _order($amount)
24
+ {
25
+ $instance = $this->getMethodInstance();
26
+ if($instance instanceof Oink_Oink_Model_Payment_Method_Oink) {
27
+ return $this;
28
+ }
29
+ else {
30
+ return parent::_order($amount);
31
+ }
32
+ }
33
+
34
+
35
+ public function place()
36
+ {
37
+ $instance = $this->getMethodInstance();
38
+ if($instance instanceof Oink_Oink_Model_Payment_Method_Oink) {
39
+ Mage::dispatchEvent('sales_order_payment_place_start', array('payment' => $this));
40
+
41
+ $order = $this->getOrder();
42
+
43
+ $this->setAmountOrdered($order->getTotalDue());
44
+ $this->setBaseAmountOrdered($order->getBaseTotalDue());
45
+ $this->setShippingAmount($order->getShippingAmount());
46
+ $this->setBaseShippingAmount($order->getBaseShippingAmount());
47
+
48
+ $methodInstance = $this->getMethodInstance();
49
+ $methodInstance->setStore($order->getStoreId());
50
+
51
+ $stateObject = new Varien_Object();
52
+
53
+ //Do order payment validation on payment method level
54
+
55
+ $methodInstance->validate();
56
+ $action = $methodInstance->getConfigPaymentAction();
57
+ if ($action) {
58
+ if ($methodInstance->isInitializeNeeded()) {
59
+ //For method initialization we have to use original config value for payment action
60
+ $methodInstance->initialize($methodInstance->getConfigData('payment_action'), $stateObject);
61
+ } else {
62
+ switch ($action) {
63
+ case Mage_Payment_Model_Method_Abstract::ACTION_ORDER:
64
+ $this->_order($order->getBaseTotalDue());
65
+ break;
66
+ case Mage_Payment_Model_Method_Abstract::ACTION_AUTHORIZE:
67
+ $this->_authorize(true, $order->getBaseTotalDue()); // base amount will be set inside
68
+ $this->setAmountAuthorized($order->getTotalDue());
69
+ break;
70
+ case Mage_Payment_Model_Method_Abstract::ACTION_AUTHORIZE_CAPTURE:
71
+ $this->setAmountAuthorized($order->getTotalDue());
72
+ $this->setBaseAmountAuthorized($order->getBaseTotalDue());
73
+ $this->capture(null);
74
+ break;
75
+ default:
76
+ break;
77
+ }
78
+ }
79
+ }
80
+
81
+ $this->_createBillingAgreement();
82
+
83
+ Mage::dispatchEvent('sales_order_payment_place_end', array('payment' => $this));
84
+ return $this;
85
+ }
86
+ else {
87
+ return parent::place();
88
+ }
89
+
90
+
91
+ }
92
+ }
app/code/local/Oink/Oink/Model/System/Config/Source/Shipping/Carriers.php ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @category Oink
4
+ * @package Oink_Oink
5
+ */
6
+ class Oink_Oink_Model_System_Config_Source_Shipping_Carriers
7
+ {
8
+ protected $_options;
9
+ /**
10
+ *
11
+ * @param bool $isMultiselect
12
+ * @return array
13
+ */
14
+ public function toOptionArray($isMultiselect)
15
+ {
16
+ if (!$this->_options) {
17
+ $this->_options = $this->getShippingOptions();
18
+ }
19
+ $options = $this->_options;
20
+ if(!$isMultiselect){
21
+ array_unshift($options, array('value'=>'', 'label'=>''));
22
+ }
23
+
24
+ return $options;
25
+ }
26
+ /**
27
+ * Get active shipping methods
28
+ *
29
+ * @return array
30
+ */
31
+ public function getShippingOptions(){
32
+ $carriersRaw = Mage::getSingleton('shipping/config')->getAllCarriers();
33
+ $config=Mage::getConfig();
34
+ $carriers=$config->getNode("default/carriers")->asArray();
35
+ $options=array();
36
+ foreach ($carriers as $carrierCode => $carrier) {
37
+ if(!(bool)$carrier["active"]){
38
+ continue;
39
+ }
40
+ if(isset($carrier["name"])){
41
+ $label=$carrier["name"];
42
+ }elseif(isset($carrier["title"])){
43
+ $label=$carrier["title"];
44
+ }else{
45
+ continue;
46
+ }
47
+ if(isset($carrier["allowed_methods"])){
48
+ $carrierAllowedMethods=$this->getCarrierAllowedMethods($carrier,$carrierCode);
49
+ $options[]=array("label"=>$label,"value"=>$carrierAllowedMethods);
50
+ }elseif($carrierCode == "tablerate"){
51
+ $options[]=array("label"=>$label,"value"=>$carrierCode."_".'bestway');
52
+ }else{
53
+ $options[]=array("label"=>$label,"value"=>$carrierCode."_".$carrierCode);
54
+ }
55
+ }
56
+ return $options;
57
+ }
58
+ /**
59
+ * Get active shipping methods from a carrier
60
+ *
61
+ * @param array $carrier Shipping method instance
62
+ * @param string $carrier Shipping method code
63
+ * @return array
64
+ */
65
+ public function getCarrierAllowedMethods($carrier,$carrierCode){
66
+ $carriersConfigGroup=Mage::getSingleton('adminhtml/config')->getSection("carriers")->groups;
67
+ $carrierAllowedMethodsCodes=explode(",",$carrier["allowed_methods"]);
68
+ $carrierMethodsModelName=(string)$carriersConfigGroup->$carrierCode->fields->allowed_methods->source_model;
69
+ $carrierMethodsModel=Mage::getModel($carrierMethodsModelName);
70
+ $carrierMethods=$carrierMethodsModel->toOptionArray();
71
+ $carrierAllowedMethods=array();
72
+ foreach ($carrierMethods as $method) {
73
+ if(in_array($method["value"], $carrierAllowedMethodsCodes)){
74
+ $method["value"]=$carrierCode."_".$method["value"];
75
+ $carrierAllowedMethods[]=$method;
76
+ }
77
+ }
78
+ return $carrierAllowedMethods;
79
+ }
80
+ }
app/code/local/Oink/Oink/Model/User.php ADDED
@@ -0,0 +1,141 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @category Oink
4
+ * @package Oink_Oink
5
+ */
6
+ class Oink_Oink_Model_User
7
+ extends Mage_Core_Model_Abstract
8
+ {
9
+
10
+ CONST USER_CODE_TYPE_CHILDREN="Child";
11
+ CONST USER_CODE_TYPE_PARENT="Parent";
12
+
13
+ protected $_token;
14
+ protected $_address;
15
+ /**
16
+ * Authenticate child and get the the result
17
+ *
18
+ * @param string $user Oink account user
19
+ * @param string $password Oink account password
20
+ * @return Oink_Oink_Model_User_Children|Oink_Oink_Model_User_Children
21
+ */
22
+ public function login($user, $password)
23
+ {
24
+ $paymentService = $this->_getHelper()->getOinkPaymentService();
25
+ $credentials = Mage::helper("oink")->getDtoCredentials();
26
+ $credentials->userName = $user;
27
+ $credentials->password = $password;
28
+ $auth = $paymentService->AuthenticateUser($credentials->userName, $credentials->password);
29
+ /*
30
+ * When casting a string to bool php will consider empty strings false.
31
+ *
32
+ */
33
+ if ((bool) $auth->Token) {
34
+ if($auth->UserType==self::USER_CODE_TYPE_CHILDREN){
35
+ $children=Mage::getModel("oink/user_children");
36
+ $children->setToken($auth->Token);
37
+ return $children;
38
+ }elseif($auth->UserType==self::USER_CODE_TYPE_PARENT){
39
+ $parent=Mage::getModel("oink/user_parent");
40
+ $parent->setToken($auth->Token);
41
+ return $parent;
42
+ }
43
+ }else{
44
+ Mage::log($auth, null, "", true);
45
+ Mage::throwException($auth->ErrorMessage);
46
+ }
47
+ }
48
+ /**
49
+ * Get address from Oink and change it to magento format
50
+ * @param dtoAddress
51
+ * @return Varien_Object
52
+ */
53
+ public function getAddress($oinkAddress=null)
54
+ {
55
+ if (is_null($this->_address)) {
56
+ if(is_null($oinkAddress)){
57
+ $oinkAddress = $this->getAddressDto();
58
+ }
59
+ $resource=Mage::getSingleton("core/resource");
60
+ $connection=$resource->getConnection("core_read");
61
+ $table=$resource->getTableName("directory_country_region");
62
+ $query = "SELECT default_name,region_id FROM {$table} WHERE country_id='{$oinkAddress->Country}' and code='{$oinkAddress->State}'";
63
+ $region = $connection->fetchRow($query);
64
+
65
+ $this->_address = new Varien_Object(array(
66
+ "street" => $oinkAddress->Address,
67
+ "city" => $oinkAddress->City,
68
+ "country_id" => $oinkAddress->Country,
69
+ "firstname" => $this->_getFirstname($oinkAddress->ParentName),
70
+ "lastname" => $this->_getLastname($oinkAddress->ParentName),
71
+ "telephone" => (bool)$oinkAddress->Phone ? $oinkAddress->Phone : "11111111",
72
+ "region" => $region["default_name"],
73
+ "region_id" => $region["region_id"],
74
+ "postcode" => $oinkAddress->Zip,
75
+ "email" => $oinkAddress->ParentEmail,
76
+ ));
77
+ }
78
+ return $this->_address;
79
+ }
80
+ /**
81
+ * @return Oink_Oink_Helper_Data
82
+ */
83
+ protected function _getHelper()
84
+ {
85
+ return Mage::helper("oink");
86
+ }
87
+ /**
88
+ * Get firstname from complete name
89
+ *
90
+ * @param string $name
91
+ * @return string
92
+ */
93
+ protected function _getFirstname($name)
94
+ {
95
+ if(is_null($name)){
96
+ return "sds";
97
+ }
98
+ $_name = explode(" ", $name);
99
+ return $_name[0];
100
+ }
101
+ /**
102
+ * Get lastname from complete name
103
+ *
104
+ * @param string $name
105
+ * @return string
106
+ */
107
+ protected function _getLastname($name)
108
+ {
109
+ if(is_null($name)){
110
+ return "sds";
111
+ }
112
+ $_name = explode(" ", $name);
113
+ unset($_name[0]);
114
+ return implode(" ", $_name);
115
+ }
116
+ /**
117
+ * @return string
118
+ */
119
+
120
+ public function getRandomMail()
121
+ {
122
+ return uniqid() . "@gmail.com";
123
+ }
124
+ /**
125
+ * @return string
126
+ */
127
+ public function getToken(){
128
+ return $this->_token;
129
+ }
130
+ /**
131
+ * @param $token string
132
+ */
133
+ public function setToken($token){
134
+ $this->_token=$token;
135
+ return $this;
136
+ }
137
+
138
+
139
+ }
140
+
141
+ ?>
app/code/local/Oink/Oink/Model/User/Children.php ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @category Oink
4
+ * @package Oink_Oink
5
+ */
6
+ class Oink_Oink_Model_User_Children
7
+ extends Oink_Oink_Model_User
8
+ {
9
+
10
+ protected $_token;
11
+ protected $_address;
12
+ /**
13
+ * Authenticate child and get the the result
14
+ *
15
+ * @param string $user Oink account user
16
+ * @param string $password Oink account password
17
+ * @return Oink_Oink_Model_Children
18
+ */
19
+ public function login($user, $password)
20
+ {
21
+ $paymentService = $this->_getHelper()->getOinkPaymentService();
22
+ $credentials = Mage::helper("oink")->getDtoCredentials();
23
+ $credentials->userName = $user;
24
+ $credentials->password = $password;
25
+ $auth = $paymentService->AuthenticateChild($credentials->userName, $credentials->password);
26
+ /*
27
+ * When casting a string to bool php will consider empty strings false.
28
+ * */
29
+ if ((bool) $auth->Token) {
30
+ $this->_token = $auth->Token;
31
+ return $this;
32
+ }else{
33
+ Mage::log($auth, null, "", true);
34
+ return null;
35
+ }
36
+ }
37
+ /**
38
+ * Get address from Oink
39
+ *
40
+ * @return dtoAddress
41
+ */
42
+ public function getAddressDto(){
43
+ $paymentService = $this->_getHelper()->getOinkPaymentService();
44
+ return $paymentService->GetChildAddress($this->_token);
45
+ }
46
+ }
47
+
48
+ ?>
app/code/local/Oink/Oink/Model/User/Parent.php ADDED
@@ -0,0 +1,113 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @category Oink
4
+ * @package Oink_Oink
5
+ */
6
+ class Oink_Oink_Model_User_Parent
7
+ extends Oink_Oink_Model_User
8
+ {
9
+
10
+ protected $_token;
11
+ protected $_address;
12
+ protected $_childrens;
13
+ protected $_paymentMethods;
14
+ protected $_selectedChildren;
15
+
16
+ /**
17
+ * Get address from Oink
18
+ *
19
+ * @return dtoAddress
20
+ */
21
+ public function getAddressDto(){
22
+ $paymentService = $this->_getHelper()->getOinkPaymentService();
23
+ return $paymentService->GetParentAddress($this->_token);
24
+ }
25
+ /*
26
+ * @return array
27
+ */
28
+ public function getChildrens(){
29
+ if(is_null($this->_childrens)){
30
+ $paymentService = Mage::helper("oink")->getOinkPaymentService();
31
+ $_childrens=$paymentService->GetAllChildren($this->getToken());
32
+ $childrens=array();
33
+ foreach ($_childrens as $_children) {
34
+ $children=Mage::getModel("oink/user_children");
35
+ $children->setChildrenIdentifier($_children->Token);
36
+ $children->setName($_children->Name);
37
+ $childrens[]=$children;
38
+ }
39
+ $this->_childrens=$childrens;
40
+ }
41
+ if(count($this->_childrens)<1){
42
+ Mage::throwException("parent_configuration");
43
+ }
44
+ return $this->_childrens;
45
+ }
46
+
47
+ /*
48
+ * @return Oink_Oink_Model_User_Children
49
+ */
50
+ public function getSelectedChildren(){
51
+ if(is_null($this->_selectedChildren)){
52
+ $selectedChildrenIdentifier=$this->getData("selected_children");
53
+ foreach ($this->getChildrens() as $children) {
54
+ if($children->getChildrenIdentifier()==$selectedChildrenIdentifier){
55
+ $this->_selectedChildren=$children;
56
+ break;
57
+ }
58
+ }
59
+ }
60
+ return $this->_selectedChildren;
61
+ }
62
+
63
+ /**
64
+ * Get address from Oink selected children and change it to magento format
65
+ *
66
+ * @return Varien_Object
67
+ */
68
+ public function getSelectedChildrenAddress(){
69
+ $addressDto=$this->getSelectedChildrenAddressDto();
70
+ return $this->getAddress($addressDto);
71
+ }
72
+
73
+ /**
74
+ * Get address from Oink selected children and change it to magento format
75
+ *
76
+ * @return dtoAddress
77
+ */
78
+ public function getSelectedChildrenAddressDto(){
79
+ $selectedChildren=$this->getSelectedChildren();
80
+ $paymentService = Mage::helper("oink")->getOinkPaymentService();
81
+ $addressDto=$paymentService->getParentChildAddress($this->getToken(),$selectedChildren->getChildrenIdentifier());
82
+ return $addressDto;
83
+ }
84
+
85
+
86
+ /*
87
+ * @return array
88
+ */
89
+ public function getPaymentMethods(){
90
+ if(is_null($this->_paymentMethods)){
91
+ $paymentService = Mage::helper("oink")->getOinkPaymentService();
92
+ $_paymentMethods=$paymentService->GetPaymentAccounts($this->getToken());
93
+ $paymentMethods=array();
94
+ foreach ($_paymentMethods as $_paymentMethod) {
95
+ $paymentMethod=new Varien_Object(array(
96
+ "token"=>$_paymentMethod->Token,
97
+ "name"=>$_paymentMethod->Name,
98
+ "url"=>$_paymentMethod->Url,
99
+ "type"=>$_paymentMethod->Type,
100
+ ));
101
+ $paymentMethods[]=$paymentMethod;
102
+ }
103
+ $this->_paymentMethods=$paymentMethods;
104
+ }
105
+ if(count($this->_paymentMethods)<1){
106
+ Mage::throwException("parent_configuration");
107
+ }
108
+ return $this->_paymentMethods;
109
+ }
110
+
111
+ }
112
+
113
+ ?>
app/code/local/Oink/Oink/Test/Controller2/CheckoutController.php ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Oink_Oink_Test_Controller_CheckoutController
4
+ extends EcomDev_PHPUnit_Test_Case_Controller
5
+ {
6
+
7
+ /**
8
+ *
9
+ * @param string $user
10
+ * @param string $password
11
+ * @test
12
+ * @dataProvider dataProvider
13
+ */
14
+ public function goodLogin($user,$password)
15
+ {
16
+ $this->getRequest()->setPost("user", $user);
17
+ $this->getRequest()->setPost("password", $password);
18
+ $this->dispatch("oink/checkout/loginPost");
19
+ $responseJson=$this->getResponse()->getOutputBody();
20
+ $response=json_decode($responseJson);
21
+ $this->assertTrue($response->response,"The user and password are correct. But something in the login failed.");
22
+ }
23
+
24
+ /**
25
+ *
26
+ * @param string $user
27
+ * @param string $password
28
+ * @test
29
+ * @dataProvider dataProvider
30
+ */
31
+ public function badLogin($user,$password)
32
+ {
33
+ $this->getRequest()->setPost("user", $user);
34
+ $this->getRequest()->setPost("password", $password);
35
+ $this->dispatch("oink/checkout/loginPost");
36
+ $responseJson=$this->getResponse()->getOutputBody();
37
+ $response=json_decode($responseJson);
38
+ $configMessage=Mage::getStoreConfig("oink/messages/error_login");
39
+ $this->assertTrue($response->response,"The user and password are incorrect. But the the login success.");
40
+ $this->assertEquals($configMessage,$response->errorMessage,"The login failed. But the message is not the configured in the admin.");
41
+ }
42
+
43
+ }
44
+
45
+ ?>
app/code/local/Oink/Oink/Test/Controller2/CheckoutController/providers/badLogin.yaml ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ -
2
+ - bad_user_name
3
+ - P@$$w0rd
app/code/local/Oink/Oink/Test/Controller2/CheckoutController/providers/goodLogin.yaml ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ -
2
+ - joaquincarranza
3
+ - P@$$w0rd
app/code/local/Oink/Oink/Test/Helper/Data.php ADDED
@@ -0,0 +1,111 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @category Oink
4
+ * @package Oink_Oink
5
+ */
6
+ class Oink_Oink_Test_Helper_Data extends EcomDev_PHPUnit_Test_Case
7
+ {
8
+ /*
9
+ * Oink helper
10
+ * @var Oink_Oink_Helper_Data
11
+ */
12
+ protected $_helper;
13
+
14
+ public function setUp()
15
+ {
16
+ $this->_helper=Mage::helper("oink");
17
+ parent::setUp();
18
+ }
19
+
20
+ /**
21
+ *
22
+ * @param string $user
23
+ * @param string $password
24
+ * @test
25
+ * @dataProvider dataProvider
26
+ */
27
+ public function goodLogin($user,$password)
28
+ {
29
+ $helper=$this->_helper;
30
+ $result = $helper->authenticateChild($user, $password);
31
+ $this->assertTrue((bool)$result,"The user and password are correct, but the login fails.");
32
+ }
33
+
34
+ /**
35
+ *
36
+ * @param string $user
37
+ * @param string $password
38
+ * @test
39
+ * @dataProvider dataProvider
40
+ */
41
+ public function badLogin($user,$password)
42
+ {
43
+ $helper=$this->_helper;
44
+ $result = $helper->authenticateChild($user, $password);
45
+ $this->assertFalse($result,"The user and password are incorrect, but the login success.");
46
+ }
47
+
48
+ /**
49
+ *
50
+ * @param string $user
51
+ * @param string $password
52
+ * @test
53
+ * @dataProvider dataProvider
54
+ */
55
+ public function badLoginMultipleTimes($user,$password)
56
+ {
57
+ $helper=$this->_helper;
58
+ for($i=0;$i<11;$i++){
59
+ $result = $helper->authenticateUser($user, $password);
60
+ }
61
+ $this->assertFalse($result,"The user and password are incorrect, but the login success.");
62
+ }
63
+
64
+ /**
65
+ *
66
+ * @param string $user
67
+ * @param string $password
68
+ * @test
69
+ * @dataProvider dataProvider
70
+ */
71
+ public function getUserAddress($user,$password)
72
+ {
73
+ $helper=$this->_helper;
74
+ $helper->authenticateChild($user, $password);
75
+ $children=Mage::helper("oink")->getUser();
76
+ $address=$children->getAddress();
77
+ $this->assertEquals("",(string)$address->ErrorMessage,"The user and password are correct, but the address have an error.");
78
+ }
79
+
80
+ /**
81
+ *
82
+ * @param string $user
83
+ * @param string $password
84
+ * @test
85
+ * @loadFixture
86
+ * @dataProvider dataProvider
87
+ */
88
+ public function processTransaction($user,$password){
89
+ /*
90
+ * Test not working
91
+ * Test not obtaining same result as in normal magento process
92
+ * Dispatch coupled to magento's framework
93
+ * Will fix this when last phase of project is complete
94
+ * */
95
+ $helper=$this->_helper;
96
+ $helper->authenticateChild($user, $password);
97
+ $quote=$helper->getQuote();
98
+ $product1=Mage::getModel("catalog/product")->load(1);
99
+ $product2=Mage::getModel("catalog/product")->load(2);
100
+ $quote->addProduct($product1);
101
+ $quote->addProduct($product2);
102
+ Mage::helper("oink/checkout")->populateQuote();
103
+ $cart=Mage::helper("oink/checkout")->getOinkCart();
104
+ $result=Mage::helper("oink/checkout")->sendCartToOink($cart);
105
+ var_dump($result);
106
+ // $controllerTestCase=new EcomDev_PHPUnit_Test_Case_Controller();
107
+ // $controllerTestCase->dispatch("oink/checkout/index");
108
+ }
109
+
110
+
111
+ }
app/code/local/Oink/Oink/Test/Helper/Data/fixtures/processTransaction.yaml ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ eav:
2
+ catalog_product:
3
+ - entity_id: 1
4
+ type_id: simple
5
+ sku: book
6
+ name: Book
7
+ short_description: Book
8
+ description: Book
9
+ url_key: book
10
+ stock:
11
+ qty: 100.00
12
+ is_in_stock: 1
13
+ website_ids:
14
+ - base
15
+ category_ids:
16
+ - 2
17
+ price: 12.99
18
+ tax_class_id: 2
19
+ status: 1
20
+ visibility: 4
21
+ - entity_id: 2
22
+ type_id: simple
23
+ sku: book2
24
+ name: Book2
25
+ short_description: Book2
26
+ description: Book2
27
+ url_key: book2
28
+ stock:
29
+ qty: 100.00
30
+ is_in_stock: 1
31
+ website_ids:
32
+ - base
33
+ category_ids:
34
+ - 2
35
+ price: 19.99
36
+ tax_class_id: 2
37
+ status: 1
38
+ visibility: 4
app/code/local/Oink/Oink/Test/Helper/Data/providers/badLogin.yaml ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ -
2
+ - bad_user_name
3
+ - P@$$w0rd
app/code/local/Oink/Oink/Test/Helper/Data/providers/badLoginMultipleTimes.yaml ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ -
2
+ - bad_user_name
3
+ - P@$$w0rd
app/code/local/Oink/Oink/Test/Helper/Data/providers/getChildProfiles.yaml ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ -
2
+ - alfredocarranza
3
+ - P@$$w0rd
app/code/local/Oink/Oink/Test/Helper/Data/providers/getUserAddress.yaml ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ -
2
+ - magentokid
3
+ - magento01
app/code/local/Oink/Oink/Test/Helper/Data/providers/goodLogin.yaml ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ -
2
+ - magentokid
3
+ - magento01
app/code/local/Oink/Oink/Test/Helper/Data/providers/processTransaction.yaml ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ -
2
+ - magentokid
3
+ - magento01
app/code/local/Oink/Oink/controllers/Adminhtml/OinkController.php ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @category Oink
5
+ * @package Oink_Oink
6
+ */
7
+ class Oink_Oink_Adminhtml_OinkController
8
+ extends Mage_Adminhtml_Controller_Action
9
+ {
10
+ public function testConnectionAction(){
11
+ $TransactionServiceEndpointAddress = $this->getRequest()->getParam("transactionServiceEndpointAddress");
12
+ $TransactionServiceEndpointAddressWsdl = $TransactionServiceEndpointAddress."?wsdl";
13
+ $config=array(
14
+ "TransactionServiceEndpointAddress" => $TransactionServiceEndpointAddress,
15
+ "TransactionServiceEndpointAddressWsdl" => $TransactionServiceEndpointAddressWsdl,
16
+ "MerchantIdentifier" => $this->getRequest()->getParam("merchantIdentifier"),
17
+ "APIkey" => $this->getRequest()->getParam("apiKey"),
18
+ );
19
+ $paymentService = Mage::helper("oink")->getOinkPaymentService($config);
20
+ $result=$paymentService->PingHeaders();
21
+ $this->getResponse()->setBody($result);
22
+ }
23
+
24
+
25
+ }
26
+
27
+ ?>
app/code/local/Oink/Oink/controllers/CheckoutController.php ADDED
@@ -0,0 +1,328 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @category Oink
5
+ * @package Oink_Oink
6
+ */
7
+ class Oink_Oink_CheckoutController
8
+ extends Mage_Core_Controller_Front_Action
9
+ {
10
+
11
+ /**
12
+ * Confirmation checkout page
13
+ */
14
+ public function indexAction()
15
+ {
16
+ if (!Mage::helper("oink/checkout")->customerHasProductsInCart()) {
17
+ Mage::getSingleton("core/session")->addError($this->__("You need to have products in your cart."));
18
+ $this->_redirect("checkout/cart/index");
19
+ } elseif (!Mage::helper("oink")->isUserLogged()) {
20
+ Mage::getSingleton("core/session")->addError($this->__("You need to be logged in Oink."));
21
+ $this->_redirect("checkout/cart/index");
22
+ } else {
23
+ if ($this->_isOrderReadyForConfirmation()) {
24
+ $this->_redirect("oink/checkout/parentConfirm");
25
+ } else {
26
+ Mage::helper("oink/checkout")->populateQuote();
27
+ $this->loadLayout()
28
+ ->renderLayout();
29
+ }
30
+ }
31
+ }
32
+
33
+ /**
34
+ * Parent Confirmation page
35
+ */
36
+ public function parentConfirmAction()
37
+ {
38
+ Mage::getSingleton("customer/session")->unsParentConfirm();
39
+ try {
40
+ $this->loadLayout()->renderLayout();
41
+ } catch (Exception $e) {
42
+ $errorMessage = Mage::getSingleton("oink/errorHandler")->rewriteError($e->getMessage());
43
+ Mage::getSingleton("core/session")->addError($errorMessage);
44
+ $this->_redirect("checkout/cart/index");
45
+ }
46
+ }
47
+
48
+ /**
49
+ * Login Oink user page
50
+ */
51
+ public function loginPostAction()
52
+ {
53
+ $user = $this->getRequest()->getPost("user");
54
+ $password = $this->getRequest()->getPost("password");
55
+ $loginResponse = array();
56
+ try {
57
+ $loginResponse["response"] = (bool)Mage::helper("oink")->authenticateUser($user, $password);
58
+
59
+ } catch (Exception $e) {
60
+ if (strpos($e->getMessage(), "temporarily disabled") !== false) {
61
+ $loginResponse["errorMessage"] = Mage::getStoreConfig("oink/messages/max_login_attemps");
62
+ } else {
63
+ $loginResponse["errorMessage"] = Mage::getStoreConfig("oink/messages/login_error");
64
+ }
65
+ }
66
+ /*
67
+ * Zend_Json_Encoder is required for magento to work. This will always be available in magento installations.
68
+ * */
69
+ $this->getResponse()->setBody(Zend_Json_Encoder::encode($loginResponse));
70
+ }
71
+
72
+ /**
73
+ * Process order page
74
+ */
75
+ public function placeOrderAction()
76
+ {
77
+
78
+ /**
79
+ * @var Oink_Oink_Helper_Checkout $vpCheckoutHelper
80
+ */
81
+ $vpCheckoutHelper = Mage::helper("oink/checkout");
82
+
83
+ try {
84
+ $cart = $vpCheckoutHelper->getOinkCart();
85
+ $result = $vpCheckoutHelper->sendCartToOink($cart);
86
+
87
+ Mage::helper("oink")->log($result, "resultOfProcessTransaction");
88
+ if ((bool)$result->Status) {
89
+ $this->_placeOrder();
90
+ $order = $vpCheckoutHelper->getOinkOrder();
91
+ $order->setOrderId($this->getCheckout()->getLastOrderId());
92
+ $createdAt = strtotime($vpCheckoutHelper->getOrder()->getCreatedAt());
93
+ $expiryDate = $createdAt + Mage::helper("oink")->getExpiryTime();
94
+
95
+ $order->setExpiryDate($expiryDate);
96
+ $order->setTransactionIdentifier($result->TransactionIdentifier);
97
+ $order->save();
98
+
99
+ $this->getCheckout()->clear();
100
+
101
+ $originalOrder = Mage::getModel('sales/order')->load($order->getOrderId());
102
+
103
+ if ($result->TransactionStatus == Oink_Oink_Helper_Checkout::APPROVAL_PENDING_CODE) {
104
+ $message = Mage::getStoreConfig("oink/messages/approval_required");
105
+ $originalOrder->setState(Mage_Sales_Model_Order::STATE_PENDING_PAYMENT, true, 'Awaiting parent approval - TXID: '.$result->TransactionIdentifier);
106
+
107
+ $originalOrder->setOinkStatus(
108
+ Oink_Oink_Helper_Checkout::ORDER_STATUS_APPROVAL_PENDING
109
+ );
110
+ } else {
111
+ $message = Mage::getStoreConfig("oink/messages/success_transaction");
112
+ $vpCheckoutHelper->completeOrder($order);
113
+ $originalOrder->sendNewOrderEmail();
114
+
115
+ $originalOrder->setOinkStatus(
116
+ Oink_Oink_Helper_Checkout::ORDER_STATUS_APPROVED
117
+ );
118
+
119
+ $originalOrder->setState(Mage_Sales_Model_Order::STATE_PROCESSING, true, 'TXID: '.$result->TransactionIdentifier);
120
+ }
121
+
122
+ $order->save();
123
+ $originalOrder->save();
124
+
125
+ Mage::getSingleton("core/session")->addSuccess($message);
126
+ $path = "*/*/success";
127
+ Mage::getSingleton("customer/session")->unsParentConfirm();
128
+ } else {
129
+ $errorMessage = Mage::getSingleton("oink/errorHandler")->rewriteError($result->ErrorMessage);
130
+ Mage::getSingleton("core/session")->addError($errorMessage);
131
+ $path = "*/*/index";
132
+ }
133
+ } catch (Exception $e) {
134
+ Mage::getSingleton("core/session")->addError($e->getMessage());
135
+ $path = "*/*/index";
136
+ }
137
+
138
+ $this->_redirect($path);
139
+ }
140
+
141
+ /*
142
+ * @return bool
143
+ */
144
+ protected function _isOrderReadyForConfirmation()
145
+ {
146
+ return Mage::helper("oink")->getUserType() == Oink_Oink_Model_User::USER_CODE_TYPE_PARENT
147
+ && !(bool)Mage::getSingleton("customer/session")->getParentConfirm();
148
+ }
149
+
150
+ protected function _placeOrder()
151
+ {
152
+ $quote = $this->_prepareGuestQuote();
153
+
154
+ $service = Mage::getModel('sales/service_quote', $quote);
155
+ $service->submitAll();
156
+
157
+ $checkoutSession = $this->getCheckout();
158
+
159
+ $checkoutSession->setLastQuoteId($quote->getId())
160
+ ->setLastSuccessQuoteId($quote->getId())
161
+ ->clearHelperData();
162
+
163
+ $order = $service->getOrder();
164
+ $redirectUrl = $this->getQuote()->getPayment()->getOrderPlaceRedirectUrl();
165
+
166
+ $checkoutSession->setLastOrderId($order->getId())
167
+ ->setRedirectUrl($redirectUrl)
168
+ ->setLastRealOrderId($order->getIncrementId());
169
+
170
+ $agreement = $order->getPayment()->getBillingAgreement();
171
+ if ($agreement) {
172
+ $checkoutSession->setLastBillingAgreementId($agreement->getId());
173
+ }
174
+
175
+ // add recurring profiles information to the session
176
+ $profiles = $service->getRecurringPaymentProfiles();
177
+ if ($profiles) {
178
+ $ids = array();
179
+ foreach ($profiles as $profile) {
180
+ $ids[] = $profile->getId();
181
+ }
182
+ $checkoutSession->setLastRecurringProfileIds($ids);
183
+ // TODO: send recurring profile emails
184
+ }
185
+
186
+ Mage::dispatchEvent(
187
+ 'checkout_submit_all_after', array('order' => $order, 'quote' => $this->getQuote(), 'recurring_profiles' => $profiles)
188
+ );
189
+ }
190
+
191
+ /**
192
+ * Callback page
193
+ */
194
+ public function callbackAction()
195
+ {
196
+ $params = $this->getRequest()->getParams();
197
+ $transactionId = $params["TransactionIdentifier"];
198
+ if(!isset($transactionId) && isset($params['id']))
199
+ $transactionId = $params['id'];
200
+ Mage::helper("oink")->log($params, "receivedCallbackMessage");
201
+ if ($transactionId) {
202
+ /**
203
+ * @var Oink_Oink_Helper_Checkout $checkoutHelper
204
+ */
205
+ $checkoutHelper = Mage::helper("oink/checkout");
206
+
207
+ $order = $checkoutHelper->getOinkOrder($transactionId, "transaction_identifier");
208
+ if ($order->getId()) {
209
+ $order->addAdditionalInformation("parentApproval", $params);
210
+
211
+ $originalOrder = Mage::getModel('sales/order')->load($order->getOrderId());
212
+
213
+ if(isset($params['Status']) && $params['Status'] == 'Rejected') {
214
+ $originalOrder->setData(
215
+ 'oink_status',
216
+ Oink_Oink_Helper_Checkout::ORDER_STATUS_REJECTED
217
+ );
218
+ $originalOrder->setState(Mage_Sales_Model_Order::STATE_CANCELED, Mage_Sales_Model_Order::STATE_CANCELED,
219
+ $this->__('This transaction was rejected by the parent'))->save();
220
+
221
+ if($originalOrder->canCancel()) {
222
+ $originalOrder->cancel()->save();
223
+ }
224
+ }
225
+ else if(isset($params['Status']) && $params['Status'] == 'Processed') {
226
+ $originalOrder->setData(
227
+ 'oink_status',
228
+ Oink_Oink_Helper_Checkout::ORDER_STATUS_APPROVED
229
+ );
230
+ $originalOrder->setState(Mage_Sales_Model_Order::STATE_PROCESSING, Mage_Sales_Model_Order::STATE_PROCESSING,
231
+ $this->__('This transaction was approved by the parent'))->save();
232
+ $originalOrder->sendNewOrderEmail();
233
+ }
234
+
235
+ $originalOrder->save();
236
+
237
+ $checkoutHelper->completeOrder($order);
238
+ }
239
+ }
240
+ }
241
+
242
+ /**
243
+ * Checkout success page
244
+ */
245
+ public function successAction()
246
+ {
247
+ $this->loadLayout()
248
+ ->renderLayout();
249
+ }
250
+
251
+ /*
252
+ * Quick Connect page
253
+ */
254
+ public function quickconnecetAction()
255
+ {
256
+
257
+ }
258
+
259
+ /**
260
+ * Process Parent Confirmation page
261
+ */
262
+ public function processParentConfirmAction()
263
+ {
264
+ $params = $this->getRequest()->getParams();
265
+ $errors = array();
266
+ if (!isset ($params["children"])) {
267
+ $errors[] = $this->__("You need to select one children");
268
+ }
269
+ if (!isset ($params["paymentAccount"])) {
270
+ $errors[] = $this->__("You need to select one payment account");
271
+ }
272
+ if ((bool)count($errors)) {
273
+ foreach ($errors as $error) {
274
+ Mage::getSingleton("core/session")->addError($error);
275
+ }
276
+ $this->_redirect("*/*/parentConfirm");
277
+ } else {
278
+ Mage::helper("oink")->getUser()->addData(array(
279
+ "selected_children" => $params["children"],
280
+ "selected_payment_account" => $params["paymentAccount"],
281
+ "deliver_to_children" => isset ($params["deliverToChildAddress"]),
282
+ "notify_children" => isset ($params["notifyChild"]),
283
+ ));
284
+ Mage::getSingleton("customer/session")->setParentConfirm(true);
285
+ $this->_redirect("*/*/index");
286
+ }
287
+ }
288
+
289
+ /**
290
+ * Prepare quote for guest checkout order submit
291
+ *
292
+ * @return Mage_Checkout_Model_Type_Onepage
293
+ */
294
+ protected function _prepareGuestQuote()
295
+ {
296
+ $quote = $this->getQuote();
297
+ $quote->setCustomerId(null)
298
+ ->setCustomerEmail($quote->getBillingAddress()->getEmail())
299
+ ->setCustomerIsGuest(true)
300
+ ->setCustomerGroupId(Mage_Customer_Model_Group::NOT_LOGGED_IN_ID);
301
+
302
+ $quote->setTotalsCollectedFlag(true);
303
+ ;
304
+
305
+ return $quote;
306
+ }
307
+
308
+ /*
309
+ *
310
+ * @return Mage_Checkout_Model_Session
311
+ */
312
+
313
+ public function getCheckout()
314
+ {
315
+ return Mage::getSingleton("checkout/session");
316
+ }
317
+
318
+ /*
319
+ *
320
+ * @return Mage_Sales_Model_Quote
321
+ */
322
+
323
+ public function getQuote()
324
+ {
325
+ return Mage::helper("oink/checkout")->getQuote();
326
+ }
327
+
328
+ }
app/code/local/Oink/Oink/etc/adminhtml.xml ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+
4
+ </config>
app/code/local/Oink/Oink/etc/config.xml ADDED
@@ -0,0 +1,210 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <modules>
4
+ <Oink_Oink>
5
+ <version>3.0.5</version>
6
+ </Oink_Oink>
7
+ </modules>
8
+ <global>
9
+ <helpers>
10
+ <oink>
11
+ <class>Oink_Oink_Helper</class>
12
+ </oink>
13
+ </helpers>
14
+ <models>
15
+ <oink>
16
+ <class>Oink_Oink_Model</class>
17
+ <resourceModel>oink_mysql4</resourceModel>
18
+ </oink>
19
+ <oink_mysql4>
20
+ <class>Oink_Oink_Model_Mysql4</class>
21
+ <entities>
22
+ <order>
23
+ <table>oink_order</table>
24
+ </order>
25
+ </entities>
26
+ </oink_mysql4>
27
+ <sales>
28
+ <rewrite>
29
+ <order>Oink_Oink_Model_Sales_Order</order>
30
+ <order_payment>Oink_Oink_Model_Sales_Order_Payment</order_payment>
31
+ </rewrite>
32
+ </sales>
33
+ </models>
34
+ <blocks>
35
+ <oink>
36
+ <class>Oink_Oink_Block</class>
37
+ </oink>
38
+ <checkout>
39
+ <rewrite>
40
+ <onepage_login>Oink_Oink_Block_Rewrite_Checkout_Onepage_Login</onepage_login>
41
+ </rewrite>
42
+ </checkout>
43
+ </blocks>
44
+ <resources>
45
+ <oink_setup>
46
+ <setup>
47
+ <module>Oink_Oink</module>
48
+ </setup>
49
+ </oink_setup>
50
+ </resources>
51
+ </global>
52
+
53
+ <admin>
54
+ <routers>
55
+ <adminhtml>
56
+ <args>
57
+ <modules>
58
+ <oink before="Mage_Adminhtml">Oink_Oink_Adminhtml</oink>
59
+ </modules>
60
+ </args>
61
+ </adminhtml>
62
+ </routers>
63
+ </admin>
64
+ <adminhtml>
65
+ <acl>
66
+ <resources>
67
+ <all>
68
+ <title>Allow Everything</title>
69
+ </all>
70
+ <admin>
71
+ <children>
72
+ <system>
73
+ <children>
74
+ <config>
75
+ <children>
76
+ <oink translate="title">
77
+ <title>Oink</title>
78
+ <sort_order>800</sort_order>
79
+ </oink>
80
+ </children>
81
+ </config>
82
+ </children>
83
+ </system>
84
+ </children>
85
+ </admin>
86
+ </resources>
87
+ </acl>
88
+ <layout>
89
+ <updates>
90
+ <oink>
91
+ <file>oink.xml</file>
92
+ </oink>
93
+ </updates>
94
+ </layout>
95
+ <events>
96
+ <!-- Added by Sebas! -->
97
+ <sales_order_status_change>
98
+ <observers>
99
+ <company_modulename_order_change>
100
+ <class>oink/observer</class>
101
+ <method>adminOrderStatusChange</method>
102
+ </company_modulename_order_change>
103
+ </observers>
104
+ </sales_order_status_change>
105
+ </events>
106
+ </adminhtml>
107
+ <frontend>
108
+ <routers>
109
+ <oink>
110
+ <use>standard</use>
111
+ <args>
112
+ <module>Oink_Oink</module>
113
+ <frontName>oink</frontName>
114
+ </args>
115
+ </oink>
116
+ </routers>
117
+ <layout>
118
+ <updates>
119
+ <oink>
120
+ <file>oink.xml</file>
121
+ </oink>
122
+ </updates>
123
+ </layout>
124
+ <translate>
125
+ <modules>
126
+ <Oink_Oink>
127
+ <files>
128
+ <default>Oink_Oink.csv</default>
129
+ </files>
130
+ </Oink_Oink>
131
+ </modules>
132
+ </translate>
133
+ <events>
134
+ <core_block_abstract_prepare_layout_after>
135
+ <observers>
136
+ <oink>
137
+ <class>oink/observer</class>
138
+ <method>removeOinkPaymentMethod</method>
139
+ </oink>
140
+ </observers>
141
+ </core_block_abstract_prepare_layout_after>
142
+ </events>
143
+ </frontend>
144
+ <phpunit>
145
+ <suite>
146
+ <modules>
147
+ <Oink_Oink />
148
+ </modules>
149
+ </suite>
150
+ </phpunit>
151
+ <crontab>
152
+ <jobs>
153
+ <check_oink_expired_orders>
154
+ <schedule>
155
+ <cron_expr>0 1 * * *</cron_expr>
156
+ </schedule>
157
+ <run>
158
+ <model>oink/observer::checkExpiredOrders</model>
159
+ </run>
160
+ </check_oink_expired_orders>
161
+ </jobs>
162
+ </crontab>
163
+ <default>
164
+ <oink>
165
+ <merchant_info>
166
+ <HeaderNamespace>vp</HeaderNamespace>
167
+ <propMerchantIdentifier>MerchantIdentifier</propMerchantIdentifier>
168
+ <propApiKey>APIkey</propApiKey>
169
+ <TransactionServiceEndpointAddress>https://development.oink.com/Services/TransactionService.svc</TransactionServiceEndpointAddress>
170
+ <TransactionServiceEndpointAddressWsdl>https://development.oink.com/services/TransactionService.svc?wsdl</TransactionServiceEndpointAddressWsdl>
171
+ <ParentServiceEndpointAddress>https://development.oink.com/services/JSON/ParentService.svc</ParentServiceEndpointAddress>
172
+ <ParentServiceEndpointAddressWsdl>https://development.oink.com/services/JSON/ParentService.svc?wsdl</ParentServiceEndpointAddressWsdl>
173
+ <MerchantIdentifier>a1d2e935-7f4d-4c70-8dfb-f0e6cace5774</MerchantIdentifier>
174
+ <APIkey>gadgetboom123</APIkey>
175
+ <two_steps_authorization>0</two_steps_authorization>
176
+ <Currency>USD</Currency>
177
+ <DefaultShipmentMethod>Delivery</DefaultShipmentMethod>
178
+ <order_expiration_time>5</order_expiration_time>
179
+ </merchant_info>
180
+ <checkoutbutton>
181
+ <show_payment_method>0</show_payment_method>
182
+ <button_image>Button_LG5.png</button_image>
183
+ <oink_cart_checkout_margin_top>5</oink_cart_checkout_margin_top>
184
+ </checkoutbutton>
185
+ <messages>
186
+ <login_error>Invalid username or password</login_error>
187
+ <max_login_attemps>Too many login attempts. Your account is locked for 10 minutes.</max_login_attemps>
188
+ <shipping_error>We are currently having trouble calculating your shipping. Please try again later.</shipping_error>
189
+ <approval_required>We are waiting to hear back from your parents. Thanks for using Oink.</approval_required>
190
+ <success_transaction>Your order was created successfully.</success_transaction>
191
+ <transaction_declined>We could not process your transaction. Please try again.</transaction_declined>
192
+ <insufficient_funds>The Transaction was denied because you do not have enough funds available.</insufficient_funds>
193
+ <transaction_not_authorized>You are not authorized to buy from this merchant. Please talk to your parents about letting you do this.</transaction_not_authorized>
194
+ <parent_configuration>Please make sure you configure your guest children and payment accounts in the Oink system</parent_configuration>
195
+ <payment_not_accepted>The payment type associated with your account is not accepted.</payment_not_accepted>
196
+ </messages>
197
+ </oink>
198
+ <payment>
199
+ <oink>
200
+ <active>1</active>
201
+ <payment_action>order</payment_action>
202
+ <model>oink/payment_method_oink</model>
203
+ <order_status>pending</order_status>
204
+ <title>Oink</title>
205
+ <allowspecific>0</allowspecific>
206
+ <group>offline</group>
207
+ </oink>
208
+ </payment>
209
+ </default>
210
+ </config>
app/code/local/Oink/Oink/etc/system.xml ADDED
@@ -0,0 +1,328 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <sections>
4
+ <oink translate="label" module="oink">
5
+ <label>Oink</label>
6
+ <tab>sales</tab>
7
+ <sort_order>800</sort_order>
8
+ <show_in_default>1</show_in_default>
9
+ <show_in_website>1</show_in_website>
10
+ <show_in_store>1</show_in_store>
11
+ <groups>
12
+ <extension_info>
13
+ <label>Extension Info</label>
14
+ <sort_order>50</sort_order>
15
+ <show_in_default>1</show_in_default>
16
+ <show_in_website>1</show_in_website>
17
+ <show_in_store>1</show_in_store>
18
+ <fields>
19
+ <version translate="label">
20
+ <label>Version</label>
21
+ <frontend_type>text</frontend_type>
22
+ <frontend_model>oink/adminhtml_system_config_version</frontend_model>
23
+ <sort_order>1</sort_order>
24
+ <show_in_default>1</show_in_default>
25
+ <show_in_website>1</show_in_website>
26
+ <show_in_store>1</show_in_store>
27
+ </version>
28
+ </fields>
29
+ </extension_info>
30
+ <merchant_info translate="label">
31
+ <label>Merchant Info</label>
32
+ <sort_order>100</sort_order>
33
+ <show_in_default>1</show_in_default>
34
+ <show_in_website>1</show_in_website>
35
+ <show_in_store>1</show_in_store>
36
+ <fields>
37
+ <TransactionServiceEndpointAddress>
38
+ <label>Transaction Service URL</label>
39
+ <frontend_type>text</frontend_type>
40
+ <sort_order>13</sort_order>
41
+ <show_in_default>1</show_in_default>
42
+ <show_in_website>1</show_in_website>
43
+ <show_in_store>1</show_in_store>
44
+ </TransactionServiceEndpointAddress>
45
+ <MerchantIdentifier translate="label">
46
+ <label>Merchant Identifier</label>
47
+ <frontend_type>text</frontend_type>
48
+ <sort_order>17</sort_order>
49
+ <show_in_default>1</show_in_default>
50
+ <show_in_website>1</show_in_website>
51
+ <show_in_store>1</show_in_store>
52
+ </MerchantIdentifier>
53
+ <APIkey translate="label">
54
+ <label>Api Key</label>
55
+ <frontend_type>text</frontend_type>
56
+ <sort_order>18</sort_order>
57
+ <show_in_default>1</show_in_default>
58
+ <show_in_website>1</show_in_website>
59
+ <show_in_store>1</show_in_store>
60
+ </APIkey>
61
+ <serviceStatus translate="label">
62
+ <frontend_type>text</frontend_type>
63
+ <frontend_model>oink/adminhtml_system_config_testConnection</frontend_model>
64
+ <sort_order>19</sort_order>
65
+ <show_in_default>1</show_in_default>
66
+ <show_in_website>1</show_in_website>
67
+ <show_in_store>1</show_in_store>
68
+ </serviceStatus>
69
+ <two_steps_authorization translate="label">
70
+ <label>Use two steps authorization</label>
71
+ <frontend_type>select</frontend_type>
72
+ <source_model>adminhtml/system_config_source_yesno</source_model>
73
+ <sort_order>20</sort_order>
74
+ <show_in_default>1</show_in_default>
75
+ <show_in_website>1</show_in_website>
76
+ <show_in_store>1</show_in_store>
77
+ </two_steps_authorization>
78
+ <Currency translate="label">
79
+ <label>Currency</label>
80
+ <frontend_type>text</frontend_type>
81
+ <sort_order>25</sort_order>
82
+ <show_in_default>1</show_in_default>
83
+ <show_in_website>1</show_in_website>
84
+ <show_in_store>1</show_in_store>
85
+ </Currency>
86
+ <DefaultShipmentMethod>
87
+ <label>Default Shipping Method</label>
88
+ <frontend_type>select</frontend_type>
89
+ <source_model>oink/system_config_source_shipping_carriers</source_model>
90
+ <sort_order>30</sort_order>
91
+ <show_in_default>1</show_in_default>
92
+ <show_in_website>1</show_in_website>
93
+ <show_in_store>1</show_in_store>
94
+ </DefaultShipmentMethod>
95
+ <order_expiration_time>
96
+ <label>Order Expiration time</label>
97
+ <sort_order>35</sort_order>
98
+ <show_in_default>1</show_in_default>
99
+ <show_in_website>1</show_in_website>
100
+ <show_in_store>1</show_in_store>
101
+ <comment>In days</comment>
102
+ </order_expiration_time>
103
+ </fields>
104
+ </merchant_info>
105
+ <checkoutbutton translate="label">
106
+ <label>Checkout Options</label>
107
+ <sort_order>125</sort_order>
108
+ <show_in_default>1</show_in_default>
109
+ <show_in_website>1</show_in_website>
110
+ <show_in_store>1</show_in_store>
111
+ <fields>
112
+ <show_payment_method translate="label">
113
+ <label>Show payment method for</label>
114
+ <frontend_type>select</frontend_type>
115
+ <source_model>oink/admin_enablestatus</source_model>
116
+ <sort_order>10</sort_order>
117
+ <show_in_default>1</show_in_default>
118
+ <show_in_website>1</show_in_website>
119
+ <show_in_store>1</show_in_store>
120
+ </show_payment_method>
121
+ <oink_radio translate="label">
122
+ <label>Checkout Type</label>
123
+ <frontend_type>select</frontend_type>
124
+ <source_model>oink/admin_checkout</source_model>
125
+ <sort_order>20</sort_order>
126
+ <show_in_default>1</show_in_default>
127
+ <show_in_website>1</show_in_website>
128
+ <show_in_store>1</show_in_store>
129
+ </oink_radio>
130
+ <oink_cart_checkout_margin_top>
131
+ <label>Oink Cart Checkout Button Top Margin</label>
132
+ <sort_order>30</sort_order>
133
+ <show_in_default>1</show_in_default>
134
+ <show_in_website>1</show_in_website>
135
+ <show_in_store>1</show_in_store>
136
+ <comment>In px</comment>
137
+ </oink_cart_checkout_margin_top>
138
+ </fields>
139
+ </checkoutbutton>
140
+ <messages>
141
+ <label>Messages</label>
142
+ <sort_order>150</sort_order>
143
+ <show_in_default>1</show_in_default>
144
+ <show_in_website>1</show_in_website>
145
+ <show_in_store>1</show_in_store>
146
+ <fields>
147
+ <login_error translate="label">
148
+ <label>Authentication error</label>
149
+ <frontend_type>textarea</frontend_type>
150
+ <sort_order>10</sort_order>
151
+ <show_in_default>1</show_in_default>
152
+ <show_in_website>1</show_in_website>
153
+ <show_in_store>1</show_in_store>
154
+ </login_error>
155
+ <max_login_attemps translate="label">
156
+ <label>Max. login attemps</label>
157
+ <frontend_type>textarea</frontend_type>
158
+ <sort_order>20</sort_order>
159
+ <show_in_default>1</show_in_default>
160
+ <show_in_website>1</show_in_website>
161
+ <show_in_store>1</show_in_store>
162
+ </max_login_attemps>
163
+ <shipping_error translate="label">
164
+ <label>Shipping calculation error</label>
165
+ <frontend_type>textarea</frontend_type>
166
+ <sort_order>40</sort_order>
167
+ <show_in_default>1</show_in_default>
168
+ <show_in_website>1</show_in_website>
169
+ <show_in_store>1</show_in_store>
170
+ </shipping_error>
171
+ <approval_required translate="label">
172
+ <label>Approval required</label>
173
+ <frontend_type>textarea</frontend_type>
174
+ <sort_order>50</sort_order>
175
+ <show_in_default>1</show_in_default>
176
+ <show_in_website>1</show_in_website>
177
+ <show_in_store>1</show_in_store>
178
+ </approval_required>
179
+ <success_transaction translate="label">
180
+ <label>Successful transaction</label>
181
+ <frontend_type>textarea</frontend_type>
182
+ <sort_order>55</sort_order>
183
+ <show_in_default>1</show_in_default>
184
+ <show_in_website>1</show_in_website>
185
+ <show_in_store>1</show_in_store>
186
+ </success_transaction>
187
+ <transaction_declined translate="label">
188
+ <label>* Default (catch-all) *</label>
189
+ <frontend_type>textarea</frontend_type>
190
+ <sort_order>60</sort_order>
191
+ <show_in_default>1</show_in_default>
192
+ <show_in_website>1</show_in_website>
193
+ <show_in_store>1</show_in_store>
194
+ </transaction_declined>
195
+ <insufficient_funds translate="label">
196
+ <label>Insufficient funds</label>
197
+ <frontend_type>textarea</frontend_type>
198
+ <sort_order>70</sort_order>
199
+ <show_in_default>1</show_in_default>
200
+ <show_in_website>1</show_in_website>
201
+ <show_in_store>1</show_in_store>
202
+ </insufficient_funds>
203
+ <transaction_not_authorized translate="label">
204
+ <label>Not approved for merchant</label>
205
+ <frontend_type>textarea</frontend_type>
206
+ <sort_order>80</sort_order>
207
+ <show_in_default>1</show_in_default>
208
+ <show_in_website>1</show_in_website>
209
+ <show_in_store>1</show_in_store>
210
+ </transaction_not_authorized>
211
+ <parent_configuration translate="label">
212
+ <label>No payment account / No children</label>
213
+ <frontend_type>textarea</frontend_type>
214
+ <sort_order>80</sort_order>
215
+ <show_in_default>1</show_in_default>
216
+ <show_in_website>1</show_in_website>
217
+ <show_in_store>1</show_in_store>
218
+ </parent_configuration>
219
+ <payment_not_accepted translate="label">
220
+ <label>Payment type not accepted</label>
221
+ <frontend_type>textarea</frontend_type>
222
+ <sort_order>90</sort_order>
223
+ <show_in_default>1</show_in_default>
224
+ <show_in_website>1</show_in_website>
225
+ <show_in_store>1</show_in_store>
226
+ </payment_not_accepted>
227
+ </fields>
228
+ </messages>
229
+ </groups>
230
+ </oink>
231
+ <payment>
232
+ <groups>
233
+ <oink translate="label" module="oink">
234
+ <label>Oink</label>
235
+ <frontend_type>text</frontend_type>
236
+ <sort_order>10</sort_order>
237
+ <show_in_default>1</show_in_default>
238
+ <show_in_website>1</show_in_website>
239
+ <show_in_store>1</show_in_store>
240
+ <fields>
241
+ <active translate="label">
242
+ <label>Enabled</label>
243
+ <frontend_type>select</frontend_type>
244
+ <source_model>adminhtml/system_config_source_yesno</source_model>
245
+ <sort_order>1</sort_order>
246
+ <show_in_default>1</show_in_default>
247
+ <show_in_website>1</show_in_website>
248
+ <show_in_store>0</show_in_store>
249
+ </active>
250
+ <order_status translate="label">
251
+ <label>New Order Status</label>
252
+ <frontend_type>select</frontend_type>
253
+ <source_model>adminhtml/system_config_source_order_status_new</source_model>
254
+ <sort_order>2</sort_order>
255
+ <show_in_default>1</show_in_default>
256
+ <show_in_website>1</show_in_website>
257
+ <show_in_store>0</show_in_store>
258
+ </order_status>
259
+ <title translate="label">
260
+ <label>Title</label>
261
+ <frontend_type>text</frontend_type>
262
+ <sort_order>1</sort_order>
263
+ <show_in_default>1</show_in_default>
264
+ <show_in_website>1</show_in_website>
265
+ <show_in_store>1</show_in_store>
266
+ </title>
267
+ <sort_order translate="label">
268
+ <label>Sort Order</label>
269
+ <frontend_type>text</frontend_type>
270
+ <sort_order>100</sort_order>
271
+ <show_in_default>1</show_in_default>
272
+ <show_in_website>1</show_in_website>
273
+ <show_in_store>0</show_in_store>
274
+ </sort_order>
275
+ <allowspecific translate="label">
276
+ <label>Payment from Applicable Countries</label>
277
+ <frontend_type>allowspecific</frontend_type>
278
+ <sort_order>50</sort_order>
279
+ <source_model>adminhtml/system_config_source_payment_allspecificcountries</source_model>
280
+ <show_in_default>1</show_in_default>
281
+ <show_in_website>1</show_in_website>
282
+ <show_in_store>0</show_in_store>
283
+ </allowspecific>
284
+ <specificcountry translate="label">
285
+ <label>Payment from Specific Countries</label>
286
+ <frontend_type>multiselect</frontend_type>
287
+ <sort_order>51</sort_order>
288
+ <source_model>adminhtml/system_config_source_country</source_model>
289
+ <show_in_default>1</show_in_default>
290
+ <show_in_website>1</show_in_website>
291
+ <show_in_store>0</show_in_store>
292
+ <can_be_empty>1</can_be_empty>
293
+ </specificcountry>
294
+ <min_order_total translate="label">
295
+ <label>Minimum Order Total</label>
296
+ <frontend_type>text</frontend_type>
297
+ <sort_order>98</sort_order>
298
+ <show_in_default>1</show_in_default>
299
+ <show_in_website>1</show_in_website>
300
+ <show_in_store>0</show_in_store>
301
+ </min_order_total>
302
+ <max_order_total translate="label">
303
+ <label>Maximum Order Total</label>
304
+ <frontend_type>text</frontend_type>
305
+ <sort_order>99</sort_order>
306
+ <show_in_default>1</show_in_default>
307
+ <show_in_website>1</show_in_website>
308
+ <show_in_store>0</show_in_store>
309
+ </max_order_total>
310
+ <!--
311
+ <payment_action translate="label">
312
+ <label>Automatically Invoice All Items</label>
313
+ <frontend_type>select</frontend_type>
314
+ <source_model>payment/source_invoice</source_model>
315
+ <sort_order>3</sort_order>
316
+ <show_in_default>1</show_in_default>
317
+ <show_in_website>1</show_in_website>
318
+ <show_in_store>0</show_in_store>
319
+ </payment_action>
320
+ -->
321
+ <model>
322
+ </model>
323
+ </fields>
324
+ </oink>
325
+ </groups>
326
+ </payment>
327
+ </sections>
328
+ </config>
app/code/local/Oink/Oink/sql/oink_setup/mysql4-install-1.0.0.0.php ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ $installer = $this;
4
+ /* @var $installer Mage_Core_Model_Resource_Setup */
5
+
6
+ $installer->startSetup();
7
+
8
+ $installer->run("
9
+ DROP TABLE IF EXISTS `{$this->getTable('oink_order')}`;
10
+ CREATE TABLE IF NOT EXISTS `{$this->getTable('oink_order')}` (
11
+ `oink_order_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
12
+ `order_id` int(10) unsigned NOT NULL,
13
+ `transaction_identifier` varchar(128) NOT NULL,
14
+ `expiry_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
15
+ `additional_information` text NOT NULL,
16
+ PRIMARY KEY (`oink_order_id`),
17
+ UNIQUE KEY `oink_order_sales_flat_order` (`order_id`)
18
+ ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
19
+
20
+ ALTER TABLE `{$this->getTable('oink_order')}`
21
+ ADD CONSTRAINT `oink_order_ibfk_1` FOREIGN KEY (`order_id`) REFERENCES `{$this->getTable('sales_flat_order')}` (`entity_id`) ON DELETE CASCADE ON UPDATE NO ACTION;
22
+ ");
23
+
24
+ $installer->endSetup();
app/code/local/Oink/Oink/sql/oink_setup/mysql4-upgrade-1.0.0.0-1.0.0.1.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ $installer = $this;
3
+
4
+ /* @var $installer Mage_Core_Model_Resource_Setup */
5
+ $installer->startSetup();
6
+
7
+ try {
8
+ $installer->getConnection()->addColumn(
9
+ $installer->getTable('sales/order'),
10
+ 'oink_status',
11
+ 'int(4)'
12
+ );
13
+
14
+ $installer->endSetup();
15
+ } catch (Exception $e){
16
+ $this->getConnection()->rollback();
17
+ Mage::logException($e);
18
+ }
19
+
20
+
app/code/local/Oink/Oink/sql/oink_setup/mysql5-install-1.0.0.0.php ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ $installer = $this;
4
+ /* @var $installer Mage_Core_Model_Resource_Setup */
5
+
6
+ $installer->startSetup();
7
+
8
+ $installer->run("
9
+ DROP TABLE IF EXISTS `{$this->getTable('oink_order')}`;
10
+ CREATE TABLE IF NOT EXISTS `{$this->getTable('oink_order')}` (
11
+ `oink_order_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
12
+ `order_id` int(10) unsigned NOT NULL,
13
+ `transaction_identifier` varchar(128) NOT NULL,
14
+ `expiry_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
15
+ `additional_information` text NOT NULL,
16
+ PRIMARY KEY (`oink_order_id`),
17
+ UNIQUE KEY `oink_order_sales_flat_order` (`order_id`)
18
+ ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
19
+
20
+ ALTER TABLE `{$this->getTable('oink_order')}`
21
+ ADD CONSTRAINT `oink_order_ibfk_1` FOREIGN KEY (`order_id`) REFERENCES `{$this->getTable('sales_flat_order')}` (`entity_id`) ON DELETE CASCADE ON UPDATE NO ACTION;
22
+ ");
23
+
24
+ $installer->endSetup();
app/code/local/Oink/Oink/sql/oink_setup/mysql5-upgrade-1.0.0.0-1.0.0.1.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ $installer = $this;
3
+
4
+ /* @var $installer Mage_Core_Model_Resource_Setup */
5
+ $installer->startSetup();
6
+
7
+ try {
8
+ $installer->getConnection()->addColumn(
9
+ $installer->getTable('sales/order'),
10
+ 'oink_status',
11
+ 'int(4)'
12
+ );
13
+
14
+ $installer->endSetup();
15
+ } catch (Exception $e){
16
+ $this->getConnection()->rollback();
17
+ Mage::logException($e);
18
+ }
19
+
20
+
app/design/adminhtml/base/default/layout/oink.xml ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <layout>
3
+ <adminhtml_sales_order_view>
4
+ <reference name="sales_order_tabs">
5
+ <block type="oink/adminhtml_sales_order_view_tab_oink" name="order_tab_oink" template="oink/sales/order/view/tab/oink.phtml" />
6
+ <action method="addTab">
7
+ <name>oink_data</name>
8
+ <block>order_tab_oink</block>
9
+ </action>
10
+ </reference>
11
+ </adminhtml_sales_order_view>
12
+ </layout>
app/design/adminhtml/base/default/template/oink/payment/form/oink.phtml ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php /* @var $this Oink_Oink_Block_Payment_Form_Oink */ ?>
2
+ <?php if ($this->getMethod()->getMailingAddress() || $this->getMethod()->getPayableTo()): ?>
3
+ <ul class="form-list checkmo-list" id="payment_form_<?php echo $this->getMethodCode() ?>" style="display:none;">
4
+ <?php if ($this->getMethod()->getPayableTo()): ?>
5
+ <li>
6
+ <label><?php echo $this->__('Make Check payable to:') ?></label>
7
+ <?php echo $this->escapeHtml($this->getMethod()->getPayableTo()) ?>
8
+ </li>
9
+ <?php endif; ?>
10
+ <?php if ($this->getMethod()->getMailingAddress()): ?>
11
+ <li>
12
+ <label><?php echo Mage::helper('payment')->__('Send Check to:') ?></label>
13
+ <address class="checkmo-mailing-address">
14
+ <?php echo nl2br($this->escapeHtml($this->getMethod()->getMailingAddress())) ?>
15
+ </address>
16
+ </li>
17
+ <?php endif; ?>
18
+ </ul>
19
+ <?php endif; ?>
app/design/adminhtml/base/default/template/oink/payment/info/oink.phtml ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <?php /* @var $this Oink_Oink_Block_Payment_Info_Oink */ ?>
2
+ <p><?php echo $this->__("This order was placed through Oink") ?></p>
app/design/adminhtml/base/default/template/oink/sales/order/view/tab/oink.phtml ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ $order = $this->_order;
3
+ $info = $order->getAdditionalInformation();
4
+ $helper=Mage::helper("oink");
5
+ ?>
6
+ <?php if (isset($info["cartXML"])): ?>
7
+ <div class="entry-edit">
8
+ <div class="entry-edit-head">
9
+ <h4 class="icon-head head-account"><?php echo Mage::helper('oink')->__('Cart XML') ?></h4>
10
+ </div>
11
+ <div class="fieldset" style="overflow:auto;">
12
+ <pre><?php echo htmlspecialchars ($info["cartXML"]) ?></pre>
13
+ </div>
14
+ </div>
15
+ <?php endif; ?>
16
+
17
+ <?php if (isset($info["processTransactionResponse"])): ?>
18
+ <div class="entry-edit">
19
+ <div class="entry-edit-head">
20
+ <h4 class="icon-head head-account"><?php echo Mage::helper('oink')->__('Transaction Response') ?></h4>
21
+ </div>
22
+ <div class="fieldset" style="overflow:auto;">
23
+ <pre><?php echo htmlspecialchars ($helper->formatXmlString($info["processTransactionResponse"])) ?></pre>
24
+ </div>
25
+ </div>
26
+ <?php endif; ?>
27
+
28
+ <?php if (isset($info["receivedCallbackMessage"])): ?>
29
+ <div class="entry-edit">
30
+ <div class="entry-edit-head">
31
+ <h4 class="icon-head head-account"><?php echo Mage::helper('oink')->__('Approval Callback') ?></h4>
32
+ </div>
33
+ <div class="fieldset" style="overflow:auto;">
34
+ <?php echo $info["receivedCallbackMessage"] ?>
35
+ </div>
36
+ </div>
37
+ <?php endif; ?>
app/design/adminhtml/base/default/template/oink/system/config/testConnection.phtml ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script type="text/javascript">
2
+ function testOinkConnection() {
3
+ var elem = $('oink_merchant_info_testConnection');
4
+
5
+ params = {
6
+ transactionServiceEndpointAddress: $('oink_merchant_info_TransactionServiceEndpointAddress').value,
7
+ merchantIdentifier: $('oink_merchant_info_MerchantIdentifier').value,
8
+ apiKey: $('oink_merchant_info_APIkey').value
9
+ };
10
+
11
+ new Ajax.Request('<?php echo $this->getAjaxUrl() ?>', {
12
+ parameters: params,
13
+ method: 'get',
14
+ onSuccess: function(response) {
15
+ result = 'Connection failed! Test again?';
16
+ try {
17
+ response = response.responseText;
18
+ if (response == 1) {
19
+ result = 'Successful! Test again?';
20
+ elem.removeClassName('delete').addClassName('success')
21
+ } else {
22
+ elem.removeClassName('success').addClassName('delete')
23
+ }
24
+ } catch (e) {
25
+ elem.removeClassName('success').addClassName('delete')
26
+ }
27
+ $('connection_test_result').update(result);
28
+ }
29
+ });
30
+ }
31
+ </script>
32
+ <button onclick="javascript:testOinkConnection(); return false;" class="scalable" type="button" id="oink_merchant_info_testConnection">
33
+ <span id="connection_test_result">Test Connection</span>
34
+ </button>
app/design/frontend/base/default/layout/oink.xml ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <layout version="0.1.0">
3
+ <oink_checkout_index>
4
+ <reference name="content">
5
+ <block type="oink/checkout_review" name="oink.checkout.review" as="review" template="oink/checkout/review.phtml">
6
+ <block type="oink/checkout_review_info" name="oink.checkout.review.info" as="info" template="oink/checkout/review/info.phtml" >
7
+ <action method="addItemRender">
8
+ <type>default</type>
9
+ <block>checkout/cart_item_renderer</block>
10
+ <template>checkout/onepage/review/item.phtml</template>
11
+ </action>
12
+ <action method="addItemRender">
13
+ <type>grouped</type>
14
+ <block>checkout/cart_item_renderer_grouped</block>
15
+ <template>checkout/onepage/review/item.phtml</template>
16
+ </action>
17
+ <action method="addItemRender">
18
+ <type>configurable</type>
19
+ <block>checkout/cart_item_renderer_configurable</block>
20
+ <template>checkout/onepage/review/item.phtml</template>
21
+ </action>
22
+ <block type="checkout/cart_totals" name="oink.checkout.review.info.totals" as="totals" template="checkout/onepage/review/totals.phtml"/>
23
+ <block type="core/text_list" name="oink.checkout.review.info.items.before" as="items_before" translate="label">
24
+ <label>Items Before</label>
25
+ </block>
26
+ <block type="checkout/agreements" name="oink.checkout.agreements" as="agreements" template="checkout/onepage/agreements.phtml"/>
27
+ <block type="core/template" name="oink.checkout.review.button" as="button" template="oink/checkout/review/button.phtml"/>
28
+ </block>
29
+ </block>
30
+ </reference>
31
+ </oink_checkout_index>
32
+
33
+ <oink_checkout_parentconfirm>
34
+ <reference name="content">
35
+ <block type="oink/checkout_parentConfirm" template="oink/checkout/parent_confirm.phtml" name="oink.checkout.parentConfirm" as="parentConfirm" >
36
+ <block type="oink/checkout_parentConfirm_CSelect" template="oink/checkout/parent_confirm/c_select.phtml" name="oink.checkout.parentConfirm.CSelect" as="CSelect" />
37
+ <block type="oink/checkout_parentConfirm_payment" template="oink/checkout/parent_confirm/payment.phtml" name="oink.checkout.parentConfirm.payment" as="payment" />
38
+ </block>
39
+ </reference>
40
+ </oink_checkout_parentconfirm>
41
+
42
+ <checkout_cart_index>
43
+ <reference name="checkout.cart.methods">
44
+ <block type="oink/checkout_button" template="oink/checkout/button/form.phtml" name="oink_login" />
45
+ <block type="oink/checkout_button" template="oink/checkout/cart/button.phtml" name="oink_checkoutbutton" before="checkout.cart.methods.multishipping" />
46
+ </reference>
47
+ </checkout_cart_index>
48
+
49
+ <checkout_onepage_index>
50
+ <reference name="content">
51
+ <block type="oink/checkout_button" template="oink/checkout/button/form.phtml" name="oink_login" />
52
+ </reference>
53
+ </checkout_onepage_index>
54
+ </layout>
app/design/frontend/base/default/template/oink/checkout/button.phtml ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php /* @var $this Oink_Oink_Block_Checkout_Button */ ?>
2
+ <?php $config = Mage::getStoreConfig('checkout/options'); ?>
3
+ <script type="text/javascript">
4
+ /* TODO: Get non-lossy image assets.
5
+ var oinkRadioImgs = new Array(
6
+ '68x8.png', '68x9.png', '68x10.png','68x11.png', '68x12.png', '68x13.png', '68x14.png',
7
+ '68x15.png', '68x16.png', '68x17.png', '68x18.png', '68x19.png', '68x20.png');
8
+ */
9
+
10
+ // 1. create "oinkRadio" element
11
+ // 2. save onepage-guest-register-button onclick method (prevents overiding core)
12
+ // 3. create vpCheckout method
13
+ // 4. only add Oink "radio" and replace "onepage" button (#2) if guest_checkout enabled.
14
+ // 5. in checkoutVP call onepage onclick method if Oink Radio not selected
15
+ // 6. use admin (config) for Oink image ->
16
+
17
+
18
+ var vp_onepageclick = null;
19
+ document.observe('dom:loaded', function(){
20
+
21
+ // 2. Save "Onepage Checkout(Magento)" onclick "function"
22
+ vp_onepageclick = $('onepage-guest-register-button').onclick;
23
+
24
+
25
+ // 4. If "Allow Guest Checkout" enabled, add Oink "radio" select and replace "onepage" guest with "oink"
26
+ var oinkCheckoutType = '<?php echo Mage::getStoreConfig("oink/checkoutbutton/oink_radio"); ?>';
27
+ var guestCheckoutEnabled = '<?php echo $config['guest_checkout']; ?>';
28
+ if(guestCheckoutEnabled == '1') {
29
+ // Merchant selected (0) "Checkout Button and Radio Select" OR
30
+ // Merchant selected (2) "Radio Select Only"
31
+ if(oinkCheckoutType == '1' || oinkCheckoutType == '0') {
32
+ var continueBtnHeight = $('onepage-guest-register-button').getHeight();
33
+ var oinkCheckoutBtn = '<a href="<?php echo $this->getCheckoutUrl() ?>" id="oink-checkout-button" onclick="return oinkLoginForm.toggleTooltip()" class="<?php echo $this->getCssClass() ?>"><img src="https://cdn.virtualpiggy.com/public/images/checkout-145x42.png" style="height: '+continueBtnHeight+'px" /></a>';
34
+ $('onepage-guest-register-button').up(0).insert(oinkCheckoutBtn);
35
+ }
36
+ if(oinkCheckoutType == '2' || oinkCheckoutType == '0') {
37
+ var radioOptionHeight = getRadioOptionHeight();
38
+ // 1. Oink Radio Button
39
+ var oinkRadio = '<li class="control"><input type="radio" name="checkout_method" id="lologin:oink" value="oink" class="radio"> <label for="login:oink"><img src="https://cdn.virtualpiggy.com/public/images/checkout-radio-68x20.png" height="'+radioOptionHeight+'px" style="vertical-align:middle;" /></label></li>';
40
+ $('login:register').up(0).insert({
41
+ before: oinkRadio
42
+ });
43
+ // 3. Create Oink onclick "function"
44
+ var vpContinue = '<button id="onepage-guest-register-button" type="button" class="button" onclick="checkoutVP();"><span><span>Continue</span></span></button>';
45
+ $('onepage-guest-register-button').replace(vpContinue);
46
+ }
47
+ }
48
+ });
49
+
50
+ function getRadioOptionHeight() {
51
+ var radioOptionLayout = $('login:register').up(0).getLayout();
52
+ var radioOptionHeight = radioOptionLayout.get('height')-radioOptionLayout.get('margin-top')-radioOptionLayout.get('margin-bottom');
53
+ if(radioOptionHeight < 8)
54
+ radioOptionHeight = 8;
55
+ if(radioOptionHeight > 20)
56
+ radioOptionHeight = 20;
57
+ return radioOptionHeight;
58
+ }
59
+
60
+ function checkoutVP() {
61
+ // 5. if Oink Radio selected display Oink Login else call "Onepage Checkout (Magento)"
62
+ if(document.getElementById('lologin:oink').checked) {
63
+ oinkLoginForm.toggleTooltip();
64
+ }
65
+ else {
66
+ vp_onepageclick();
67
+ }
68
+ }
69
+
70
+ </script>
app/design/frontend/base/default/template/oink/checkout/button/form.phtml ADDED
@@ -0,0 +1,207 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <style>
2
+ #oink-login-container{
3
+ position:relative;
4
+ }
5
+ input[type=text], input[type=password]
6
+ {
7
+ height:25px;
8
+ width:250px;
9
+ font-size:11pt;
10
+ color: #444;
11
+ padding-left: 10px;
12
+ text-decoration: none;
13
+ font-family: "helvetica neue regular";
14
+ }
15
+
16
+ #oink-cart-button {
17
+ display: inline-block;
18
+ margin-top: <?php echo Mage::getStoreConfig("oink/checkoutbutton/oink_cart_checkout_margin_top").'px;'; ?>
19
+ }
20
+
21
+ .opensans
22
+ {
23
+ font-family: "open sans condensed", sans-serif;
24
+ font-style:condensed;
25
+ font-size:16pt;
26
+ font-weight:bold;
27
+ color:#1E6FCA;
28
+ line-height: 15px;
29
+ }
30
+
31
+
32
+ #oink-checkout-button {
33
+ float: left;
34
+ }
35
+
36
+ .overlay_magento {
37
+ background-color: #000;
38
+ filter:alpha(opacity=60);
39
+ -moz-opacity: 0.6;
40
+ opacity: 0.6;
41
+ }
42
+
43
+ .dim
44
+ {
45
+ background-color: white;
46
+ filter:alpha(opacity=50); /* IE */
47
+ opacity: 0.5; /* Safari, Opera */
48
+ -moz-opacity:0.50; /* FireFox */
49
+ z-index: 20;
50
+ }
51
+
52
+
53
+ </style>
54
+
55
+ <?php $skinUrl = $this->getSkinUrl('images/oink/checkout/'); ?>
56
+ <?php $baseJsUrl = Mage::getBaseUrl('js'); ?>
57
+
58
+ <link rel="stylesheet" type="text/css" href="<?php echo $baseJsUrl ?>prototype/windows/themes/default.css"/>
59
+ <link href='//fonts.googleapis.com/css?family=Open+Sans+Condensed:bold&v1' rel='stylesheet' type='text/css'>
60
+
61
+ <script type="text/javascript" src="<?php echo $baseJsUrl ?>prototype/window.js"></script>
62
+ <div id="oink-login" align="center" style="display:none;">
63
+ <div align="left" style="width:600px;height:300px;border:1px solid #444;background-color:#fff;">
64
+
65
+ <!-- x //-->
66
+ <div style="float:right;padding:10px;"><a style="text-decoration:none;cursor:pointer;" onClick="return closePopup()"><img src="<?php echo $skinUrl; ?>x.png" /></a></div>
67
+ <div style="padding:30px;">
68
+
69
+ <!-- left col -->
70
+ <div id="loading" style="vertical-align:top;display:none;width:310px;height:200px;">
71
+ <div align="center">
72
+ <img src="https://cdn.virtualpiggy.com/public/images/checkout-logo-192x75.png" />
73
+ <div align="center" class="opensans" style="width:220px;padding-top:15px;"><span style="font-weight:bold;color:#999;"><?php echo Mage::helper('adminhtml')->__('Please wait while you are logged in...') ?></span></div>
74
+ <div align="center" style="padding-top:20px;"><img src="<?php echo $this->getSkinUrl('images/oink/login/loader.gif') ?>" alt="<?php echo Mage::helper('adminhtml')->__('Loading...') ?>"/></div>
75
+ </div>
76
+ </div>
77
+
78
+ <div id="login" style="vertical-align:top;display:inline-block;width:310px;height:200px;">
79
+ <div align="center">
80
+ <form id="oink-login">
81
+ <img src="https://cdn.virtualpiggy.com/public/images/checkout-logo-192x75.png" height="70"/>
82
+ <div class="opensans" style="font-size:16pt;font-weight:bold;color:#999;padding-top:15px;">Log In to Checkout</div>
83
+ <div align="center" style="padding-top:10px;">
84
+ <input class="textBox required-entry" onkeypress="bindOinkLoginPost(event)" id="oink-login-userid" name="UserName" tabindex="2" type="text" placeholder="Username" />
85
+ </div>
86
+ <div align="center" style="padding-top:5px;">
87
+ <input autocomplete="off" onkeypress="bindOinkLoginPost(event)" class="textBox required-entry" id="oink-login-password" name="Password" tabindex="3" type="password" placeholder="Password" />
88
+ <div class="opensans" style="font-size:10pt;color:#ff0000;" id="oink-errors-container">&nbsp;</div>
89
+ <div><a href="https://users.oink.com/login/forgotpassword" target="_blank" style="font-size:10pt;color:#999;font-family:"helvetica neue regular";">Forgot Password?</a></div>
90
+ </div>
91
+ </form>
92
+ </div>
93
+ </div>
94
+
95
+ <!-- separator -->
96
+ <div style="display:inline-block;height:210px;width:0px;border:1px solid #999;"></div>
97
+
98
+ <!-- right col -->
99
+ <div id="signup" style="vertical-align:top;display:inline-block;width:180px;height:200px;padding-left:15px;">
100
+ <div align="center" style="padding-top:30px;">
101
+ <div style=""><span class="opensans">Don't have an Oink account?</span></div>
102
+ <div style="padding-top:15px;"><span style="font-size:10pt;font-family:"helvetica neue regular";color:#444;line-height:10px;">Oink is the safe way for kids and teens to save, shop and give online.</span></div>
103
+ <div style="padding-top:35px;"><a href="http://www.oink.com/how-it-works" target="_blank" style="font-size:10pt;color:#999;font-family:"helvetica neue regular";">Learn More</a></div>
104
+ </div>
105
+ </div>
106
+
107
+ <!-- buttons -->
108
+ <div id="buttons">
109
+ <div id="button-login" align="center" style="display:inline-block;width:310px;"><a onclick="return oinkLoginForm.submit();" href="#"><img src="<?php echo $skinUrl; ?>login.png" /></a></div>
110
+ <div id="button-signup" align="center" style="display:inline-block;width:220px;"><a href="https://users.oink.com/registration" target="_blank" style="font-size:10pt;font-family:helvetica, neue, regular;color:#999;"><img src="<?php echo $skinUrl; ?>signup.png" /></a></div>
111
+ </div>
112
+ </div>
113
+ </div>
114
+ </div>
115
+
116
+ <input type="hidden" id="oink-checkout-url" value="<?php echo $this->getCheckoutUrl() ?>"/>
117
+ <script type="text/javascript">
118
+ //<![CDATA[
119
+ if ("payment" in window)
120
+ {
121
+ var oldSwitchMethod=payment.switchMethod;
122
+ payment.switchMethod=function(method){
123
+ if(method=="oink"){
124
+ oinkLoginForm.toggleTooltip()
125
+ }else{
126
+ oldSwitchMethod.apply(this,[method])
127
+ }
128
+ }
129
+ }
130
+ // if($('p_method_oink')){
131
+ // $('p_method_oink').onclick=function(){
132
+ // oinkLoginForm.submit();
133
+ // }
134
+ // }
135
+ function closePopup(){
136
+ if($('p_method_oink'))$('p_method_oink').checked=false;
137
+ Dialog.cancelCallback();
138
+ return false;
139
+ }
140
+ var oinkLoginForm = new VarienForm('oink-login', true);
141
+ function bindOinkLoginPost(evt){
142
+ if (evt.keyCode == Event.KEY_RETURN) {
143
+ oinkLoginForm.submit();
144
+ }
145
+ }
146
+ oinkLoginForm.toggleTooltip=function(){
147
+ if($$(".dialog").length){
148
+ return false;
149
+ }
150
+ if($('p_method_oink')){
151
+ $('p_method_oink').checked=1;
152
+ }
153
+ Dialog.info($('oink-login').innerHTML, {
154
+ className:"magento",
155
+ width:600,
156
+ height:300,
157
+ top: 175,
158
+ });
159
+ return false;
160
+ }
161
+
162
+ oinkLoginForm.submit=function(){
163
+ var user=$('oink-login-userid').value;
164
+ var password=$('oink-login-password').value;
165
+
166
+ if(this.validator && this.validator.validate()){
167
+ new Ajax.Request("<?php echo $this->getLoginPostUrl() ?>",{
168
+ method:"post",
169
+ parameters:{
170
+ "user" : user,
171
+ "password" : password
172
+ },
173
+
174
+ onCreate:function() {
175
+ $('loading').setStyle({ display: 'inline-block'});
176
+ $('login').setStyle({ display: 'none'});
177
+ $('signup').addClassName('dim');
178
+ $('button-login').innerHTML = '<img src="<?php echo $skinUrl; ?>login.png" />';
179
+ $('buttons').addClassName('dim');
180
+ },
181
+
182
+ onComplete:function(){},
183
+
184
+ onSuccess:function(transport) {
185
+ var json=eval('(' + transport.responseText + ')');
186
+
187
+ if(json.response) {
188
+ setLocation($("oink-checkout-url").value);
189
+ $('oink-errors-container').innerHTML = '';
190
+ } else
191
+ {
192
+ $('oink-errors-container').innerHTML = json.errorMessage;
193
+ $('loading').setStyle({ display: 'none'});
194
+ $('login').setStyle({ display: 'inline-block'});
195
+ $('signup').removeClassName('dim');
196
+ $('button-login').innerHTML = '<a onclick="return oinkLoginForm.submit();" href="#"><img src="<?php echo $skinUrl; ?>login.png" /></a>';
197
+ $('buttons').removeClassName('dim');
198
+ }
199
+ }
200
+ });
201
+ }
202
+
203
+ return false;
204
+ }
205
+
206
+ //]]>
207
+ </script>
app/design/frontend/base/default/template/oink/checkout/cart/button.phtml ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
1
+ <?php /* @var $this Oink_Oink_Block_Checkout_Button */ ?>
2
+ <?php
3
+ if(Mage::helper("oink/checkout")->isEnabled()) { ?>
4
+ <a href="<?php echo $this->getCheckoutUrl() ?>" id="oink-cart-button" onclick="return oinkLoginForm.toggleTooltip()" class="<?php echo $this->getCssClass() ?>"><img src="https://cdn.virtualpiggy.com/public/images/checkout-145x42.png" /></a>
5
+ <?php } ?>
app/design/frontend/base/default/template/oink/checkout/parent_confirm.phtml ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <style>
2
+ h1.page-title{
3
+ color:#1484c5;
4
+ text-decoration: underline;
5
+ }
6
+ #oinkParentConfirm select{
7
+ margin-left:10px;
8
+ }
9
+ #oinkParentConfirm{
10
+ font-size: 14px;
11
+ }
12
+ #paymentAccounts{
13
+ width:360px;
14
+ margin-bottom:15px;
15
+ }
16
+ #paymentAccounts th{
17
+ color:#fff;
18
+ font-weight: bold;
19
+ background-color: #1484c5;
20
+ }
21
+ #paymentAccounts td{
22
+ border:1px solid #676;
23
+ padding:5px;
24
+ }
25
+ </style>
26
+ <div class="page-title">
27
+ <h1><?php echo $this->__('Oink Guest Checkout'); ?></h1>
28
+ </div>
29
+ <ol class="opc">
30
+ <form method="POST" action="<?php echo $this->getFormActionUrl() ?>" id="oinkParentConfirm" >
31
+ <?php echo $this->getChildHtml("CSelect") ?>
32
+ <?php echo $this->getChildHtml("payment") ?>
33
+
34
+ <div class="buttons-set" id="billing-buttons-container">
35
+ <button type="submit" title="<?php echo $this->__('Finalize the Transaction'); ?>" class="button" ><span><span><?php echo $this->__('Finalize the Transaction') ?></span></span></button>
36
+ </div>
37
+
38
+ </form>
39
+ </ol>
40
+ <script type="text/javascript" >
41
+ //<![CDATA[
42
+ var oinkParentConfirm = new VarienForm('oinkParentConfirm', true);
43
+ //]]>
44
+ </script>
app/design/frontend/base/default/template/oink/checkout/parent_confirm/c_select.phtml ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /* @var $this Oink_Oink_Block_Checkout_ParentConfirm_CSelect */
3
+ $childrens = $this->getChildrens();
4
+ ?>
5
+
6
+
7
+
8
+
9
+ <li class="section allow active" id="opc-billing">
10
+ <div class="step-title">
11
+ <h2><?php echo $this->__("Child information") ?></h2>
12
+ </div>
13
+
14
+ <div id="checkout-step-billing" class="step a-item" style="">
15
+ <fieldset>
16
+ <ul class="form-list">
17
+ <li id="billing-new-address-form">
18
+ <fieldset>
19
+ <ul>
20
+ <li class="fields">
21
+ <div class="field">
22
+ <label for="children" class="required">This transaction is for</label>
23
+ <div class="input-box">
24
+ <select name="children" id="cSelect" class="required-entry">
25
+ <option value="" ></option>
26
+ <?php foreach ($childrens as $key => $children): ?>
27
+ <option value="<?php echo $children->getChildrenIdentifier() ?>"><?php echo $children->getName() ?></option>
28
+ <?php endforeach; ?>
29
+ </select>
30
+ </div>
31
+ </div>
32
+ </li>
33
+ </ul>
34
+ </fieldset>
35
+ </li>
36
+ <li class="control">
37
+ <!--input type="checkbox" id="notifyChild" name="notifyChild" value="1" /><label for="notifyChild" ><?php echo $this->__("Notify the child about this transaction") ?></label><br-->
38
+ <input type="checkbox" id="deliverToChildAddress" name="deliverToChildAddress" value="1" />
39
+ <label for="deliverToChildAddress" ><?php echo $this->__("Deliver to the child's address") ?></label>
40
+ </li>
41
+ </ul>
42
+
43
+ </fieldset>
44
+ </div>
45
+ </li>
app/design/frontend/base/default/template/oink/checkout/parent_confirm/payment.phtml ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ $methods = $this->getMethods();
3
+ ?>
4
+ <li class="section allow active" id="opc-billing">
5
+ <div class="step-title">
6
+ <h2>Payment information</h2>
7
+ </div>
8
+
9
+ <div id="checkout-step-billing" class="step a-item" style="">
10
+ <fieldset>
11
+ <ul class="form-list">
12
+ <li id="billing-new-address-form">
13
+ <fieldset>
14
+ <ul>
15
+ <li class="fields">
16
+ <div class="field">
17
+ <ul>
18
+ <?php foreach ($methods as $i => $method): ?>
19
+ <li class="control">
20
+ <input type="radio" value="<?php echo $method->getToken() ?>" name="paymentAccount" <?php if ($i == count($methods) - 1): ?>class="validate-one-required-by-name"<?php endif; if($method == $methods[0]) echo 'checked'; ?> />
21
+ <label for="deliverToChildAddress" ><img style="width:30px;" src="<?php echo $method->getUrl() ?>" /> <span><?php echo $method->getName() ?></span></label>
22
+ </li>
23
+ <?php endforeach; ?>
24
+ </ul>
25
+ </div>
26
+ </li>
27
+ </ul>
28
+ </fieldset>
29
+ </li>
30
+ </ul>
31
+ </fieldset>
32
+ </div>
33
+ </li>
app/design/frontend/base/default/template/oink/checkout/review.phtml ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Academic Free License (AFL 3.0)
8
+ * that is bundled with this package in the file LICENSE_AFL.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/afl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category design
22
+ * @package base_default
23
+ * @copyright Copyright (c) 2011 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
25
+ */
26
+ ?>
27
+ <div class="order-review" id="checkout-review-load">
28
+ <?php echo $this->getChildHtml('info') ?>
29
+ </div>
app/design/frontend/base/default/template/oink/checkout/review/button.phtml ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <?php /* @var $this Mage_Core_Block_Template */ ?>
2
+ <button type="submit" title="<?php echo $this->__('Place Order'); ?>" class="button btn-checkout" onclick="this.onclick=function(){return false;};setLocation('<?php echo $this->getUrl("*/*/placeOrder") ?>');return false;"><span><span><?php echo $this->__('Place Order') ?></span></span></button>
app/design/frontend/base/default/template/oink/checkout/review/info.phtml ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php echo $this->getChildHtml('items_before'); ?>
2
+ <div id="checkout-review-table-wrapper">
3
+ <table class="data-table" id="checkout-review-table">
4
+ <?php if ($this->helper('tax')->displayCartBothPrices()): $colspan = $rowspan = 2; else: $colspan = $rowspan = 1; endif; ?>
5
+ <col />
6
+ <col width="1" />
7
+ <col width="1" />
8
+ <col width="1" />
9
+ <?php if ($this->helper('tax')->displayCartBothPrices()): ?>
10
+ <col width="1" />
11
+ <col width="1" />
12
+ <?php endif; ?>
13
+ <thead>
14
+ <tr>
15
+ <th rowspan="<?php echo $rowspan ?>"><?php echo $this->__('Product Name') ?></th>
16
+ <th colspan="<?php echo $colspan ?>" class="a-center"><?php echo $this->__('Price') ?></th>
17
+ <th rowspan="<?php echo $rowspan ?>" class="a-center"><?php echo $this->__('Qty') ?></th>
18
+ <th colspan="<?php echo $colspan ?>" class="a-center"><?php echo $this->__('Subtotal') ?></th>
19
+ </tr>
20
+ <?php if ($this->helper('tax')->displayCartBothPrices()): ?>
21
+ <tr>
22
+ <th class="a-right"><?php echo $this->helper('tax')->getIncExcTaxLabel(false) ?></th>
23
+ <th><?php echo $this->helper('tax')->getIncExcTaxLabel(true) ?></th>
24
+ <th class="a-right"><?php echo $this->helper('tax')->getIncExcTaxLabel(false) ?></th>
25
+ <th><?php echo $this->helper('tax')->getIncExcTaxLabel(true) ?></th>
26
+ </tr>
27
+ <?php endif; ?>
28
+ </thead>
29
+ <?php echo $this->getChildHtml('totals'); ?>
30
+ <tbody>
31
+ <?php foreach($this->getItems() as $_item): ?>
32
+ <?php echo $this->getItemHtml($_item)?>
33
+ <?php endforeach ?>
34
+ </tbody>
35
+ </table>
36
+ </div>
37
+ <?php echo $this->getChildHtml('items_after'); ?>
38
+ <script type="text/javascript">
39
+ //<![CDATA[
40
+ decorateTable('checkout-review-table');
41
+ truncateOptions();
42
+ //]]>
43
+ </script>
44
+ <div id="checkout-review-submit">
45
+ <?php echo $this->getChildHtml('agreements') ?>
46
+ <div class="buttons-set" id="review-buttons-container">
47
+ <p class="f-left"><?php echo $this->__('Forgot an Item?') ?> <a href="<?php echo $this->getUrl('checkout/cart') ?>"><?php echo $this->__('Edit Your Cart') ?></a></p>
48
+ <?php echo $this->getChildHtml('button') ?>
49
+ <span class="please-wait" id="review-please-wait" style="display:none;">
50
+ <img src="<?php echo $this->getSkinUrl('images/opc-ajax-loader.gif') ?>" alt="<?php echo $this->__('Submitting order information...') ?>" title="<?php echo $this->__('Submitting order information...') ?>" class="v-middle" /> <?php echo $this->__('Submitting order information...') ?>
51
+ </span>
52
+ </div>
53
+ <script type="text/javascript">
54
+ //<![CDATA[
55
+ review = new Review('<?php echo $this->getUrl('checkout/onepage/saveOrder') ?>', '<?php echo $this->getUrl('checkout/onepage/success') ?>', $('checkout-agreements'));
56
+ //]]>
57
+ </script>
58
+ </div>
app/design/frontend/base/default/template/oink/payment/form/oink.phtml ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php /* @var $this Oink_Oink_Block_Payment_Form_Oink */ ?>
2
+ <?php if ($this->getMethod()->getMailingAddress() || $this->getMethod()->getPayableTo()): ?>
3
+ <ul class="form-list checkmo-list" id="payment_form_<?php echo $this->getMethodCode() ?>" style="display:none;">
4
+ <?php if ($this->getMethod()->getPayableTo()): ?>
5
+ <li>
6
+ <label><?php echo $this->__('Make Check payable to:') ?></label>
7
+ <?php echo $this->escapeHtml($this->getMethod()->getPayableTo()) ?>
8
+ </li>
9
+ <?php endif; ?>
10
+ <?php if ($this->getMethod()->getMailingAddress()): ?>
11
+ <li>
12
+ <label><?php echo Mage::helper('payment')->__('Send Check to:') ?></label>
13
+ <address class="checkmo-mailing-address">
14
+ <?php echo nl2br($this->escapeHtml($this->getMethod()->getMailingAddress())) ?>
15
+ </address>
16
+ </li>
17
+ <?php endif; ?>
18
+ </ul>
19
+ <?php endif; ?>
app/design/frontend/base/default/template/oink/payment/info/oink.phtml ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php /* @var $this Oink_Oink_Block_Payment_Info_Oink */ ?>
2
+ <p><?php echo $this->getMethod()->getTitle() ?></p>
3
+ <?php if($this->getInfo()->getAdditionalData()): ?>
4
+ <?php if($this->getPayableTo()): ?>
5
+ <p><strong><?php echo $this->__('Make Check payable to:') ?></strong> <?php echo $this->escapeHtml($this->getPayableTo()) ?></p>
6
+ <?php endif; ?>
7
+ <?php if($this->getMailingAddress()): ?>
8
+ <p><strong><?php echo Mage::helper('payment')->__('Send Check to:') ?></strong></p>
9
+ <address class="checkmo-mailing-address">
10
+ <?php echo nl2br($this->escapeHtml($this->getMailingAddress())) ?>
11
+ </address>
12
+ <?php endif; ?>
13
+ <?php endif; ?>
app/etc/local.xml.phpunit ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <global>
4
+ <resources>
5
+ <default_setup>
6
+ <connection>
7
+ <dbname><![CDATA[oink_test]]></dbname>
8
+ </connection>
9
+ </default_setup>
10
+ </resources>
11
+ </global>
12
+ <default>
13
+ <web>
14
+ <seo>
15
+ <use_rewrites>1</use_rewrites>
16
+ </seo>
17
+ <secure>
18
+ <base_url>http://oink.test.localhost.net/</base_url>
19
+ </secure>
20
+ <unsecure>
21
+ <base_url>http://oink.test.localhost.net/</base_url>
22
+ </unsecure>
23
+ </web>
24
+ </default>
25
+ </config>
app/etc/modules/EcomDev_PHPUnit.xml ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!--
3
+ /**
4
+ * PHP Unit test suite for Magento
5
+ *
6
+ * NOTICE OF LICENSE
7
+ *
8
+ * This source file is subject to the Open Software License (OSL 3.0)
9
+ * that is bundled with this package in the file LICENSE.txt.
10
+ * It is also available through the world-wide-web at this URL:
11
+ * http://opensource.org/licenses/osl-3.0.php
12
+ *
13
+ * @category EcomDev
14
+ * @package EcomDev_PHPUnit
15
+ * @copyright Copyright (c) 2010 Ecommerce Developers (http://www.ecomdev.org)
16
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
17
+ * @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
18
+ */
19
+ -->
20
+ <config>
21
+ <modules>
22
+ <EcomDev_PHPUnit>
23
+ <codePool>community</codePool>
24
+ <active>true</active>
25
+ </EcomDev_PHPUnit>
26
+ </modules>
27
+ </config>
app/etc/modules/Oink_MatrixrateIntegration.xml ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <modules>
4
+ <Oink_MatrixrateIntegration>
5
+ <active>false</active>
6
+ <codePool>local</codePool>
7
+ <depends>
8
+ <Oink_Oink />
9
+ <Auctionmaid_Matrixrate />
10
+ </depends>
11
+ </Oink_MatrixrateIntegration>
12
+ </modules>
13
+ </config>
app/etc/modules/Oink_Oink.xml ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <modules>
4
+ <Oink_Oink>
5
+ <active>true</active>
6
+ <codePool>local</codePool>
7
+ </Oink_Oink>
8
+ </modules>
9
+ </config>
app/locale/en_US/Oink_Oink.csv ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "Make Check payable to:","Make Check payable to:"
2
+ "This order was placed through Oink","This order was placed through Oink"
3
+ "Cart XML","Cart XML"
4
+ "Transaction Response","Transaction Response"
5
+ "Approval Callback","Approval Callback"
6
+ "This transaction was rejected by the parent","This transaction was rejected by the parent"
7
+ "This transaction was approved by the parent","This transaction was approved by the parent"
8
+ "Test Connection","Test Connection"
9
+ "Successful! Test again?","Successful! Test again?"
10
+ "Connection failed! Test again?","Connection failed! Test again?"
11
+ "Oink Guest Checkout","Oink Guest Checkout"
12
+ "Finalize the Transaction","Finalize the Transaction"
13
+ "Place Order","Place Order"
14
+ "Product Name","Product Name"
15
+ "Edit Your Cart","Edit Your Cart"
16
+ "Submitting order information...","Submitting order information..."
17
+ "Payment information","Payment information"
18
+ "User Id","User Id"
19
+ "* Required Fields","* Required Fields"
20
+ "Login","Login"
21
+ "Cancel","Cancel"
22
+ "Loading...","Loading..."
23
+ "Please wait...","Please wait..."
24
+ "You need to have products in your cart.","You need to have products in your cart."
25
+ "You need to be logged in Oink.","You need to be logged in Oink."
26
+ "You need to select one children","You need to select one children"
27
+ "You need to select one payment account","You need to select one payment account"
28
+ "",""
29
+ "",""
lib/EcomDev/PHPUnit/Constraint/Abstract.php ADDED
@@ -0,0 +1,217 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PHP Unit test suite for Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ *
12
+ * @category EcomDev
13
+ * @package EcomDev_PHPUnit
14
+ * @copyright Copyright (c) 2011 Ecommerce Developers (http://www.ecomdev.org)
15
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
+ * @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
17
+ */
18
+
19
+ /**
20
+ * Abstract constraint for EcomDev_PHPUnit constraints
21
+ * Contains flexible constaint types implementation
22
+ *
23
+ */
24
+ abstract class EcomDev_PHPUnit_Constraint_Abstract
25
+ extends PHPUnit_Framework_Constraint
26
+ {
27
+ /**
28
+ * List of valiadation rules for expected value
29
+ * It is an associative array with key as type and value
30
+ * as an array of rules.
31
+ *
32
+ * First item of the rule array is mandatory indicator,
33
+ * second is function name for checking the type,
34
+ * third one is the type that will be displayed in invalid argument expception
35
+ * each of them can be ommited or if it between other ones just by specifying null value
36
+ *
37
+ * @var array
38
+ */
39
+ protected $_expectedValueValidation = array();
40
+
41
+ /**
42
+ * List of types that will use diff for displaying fail result
43
+ *
44
+ * @var array
45
+ */
46
+ protected $_typesWithDiff = array();
47
+
48
+ /**
49
+ * Comparisment type defined in the constructor
50
+ *
51
+ * @var string
52
+ */
53
+ protected $_type = null;
54
+
55
+ /**
56
+ * Expected value defined in the constructor
57
+ *
58
+ * @var mixed
59
+ */
60
+ protected $_expectedValue = null;
61
+
62
+ /**
63
+ * Custom actual value
64
+ *
65
+ * @var mixed
66
+ */
67
+ protected $_actualValue = null;
68
+
69
+ /**
70
+ * Flag for using of actual value in failure description
71
+ *
72
+ * @var boolean
73
+ */
74
+ protected $_useActualValue = false;
75
+
76
+ /**
77
+ * Abstract cnstraint constructor,
78
+ * provides unified interface for working with multiple types of evalation
79
+ *
80
+ * @param string $type
81
+ * @param mixed $expectedValue
82
+ */
83
+ public function __construct($type, $expectedValue = null)
84
+ {
85
+ $reflection = EcomDev_Utils_Reflection::getRelflection(get_class($this));
86
+ $types = array();
87
+ foreach ($reflection->getConstants() as $name => $constant) {
88
+ if (strpos($name, 'TYPE_') === 0) {
89
+ $types[] = $constant;
90
+ }
91
+ }
92
+
93
+ if (empty($type) || !is_string($type) || !in_array($type, $types)) {
94
+ throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string', $type);
95
+ }
96
+
97
+
98
+ if (isset($this->_expectedValueValidation[$type])) {
99
+ $expectedValueType = (isset($this->_expectedValueValidation[$type][2]) ?
100
+ isset($this->_expectedValueValidation[$type][2]) :
101
+ '');
102
+
103
+ // Mandatory check
104
+ if (isset($this->_expectedValueValidation[$type][0])
105
+ && $this->_expectedValueValidation[$type][0]
106
+ && $expectedValue === null) {
107
+ throw PHPUnit_Util_InvalidArgumentHelper::factory(2, $expectedValueType, $expectedValue);
108
+ }
109
+
110
+ // Type check
111
+ if (isset($this->_expectedValueValidation[$type][1])
112
+ && !$this->_expectedValueValidation[$type][1]($expectedValue)) {
113
+ throw PHPUnit_Util_InvalidArgumentHelper::factory(2, $expectedValueType, $expectedValue);
114
+ }
115
+ }
116
+
117
+ $this->_type = $type;
118
+ $this->_expectedValue = $expectedValue;
119
+ }
120
+
121
+ /**
122
+ * Set actual value that will be used in the fail message
123
+ *
124
+ * @param mixed $actual
125
+ * @return EcomDev_PHPUnit_Constraint_Abstract
126
+ */
127
+ protected function setActualValue($actual)
128
+ {
129
+ $this->_useActualValue = true;
130
+ $this->_actualValue = $actual;
131
+ return $this;
132
+ }
133
+
134
+
135
+ /**
136
+ * Calls internal protected method by defined constraint type
137
+ * Also can be passed a single argument
138
+ *
139
+ * @param string $prefix
140
+ * @return mixed
141
+ */
142
+ protected function callProtectedByType($prefix, $argument = null)
143
+ {
144
+ $camelizedType = uc_words($this->_type, '');
145
+ $methodName = $prefix . $camelizedType;
146
+ return $this->$methodName($argument);
147
+ }
148
+
149
+ /**
150
+ * Evaluates value by type.
151
+ * (non-PHPdoc)
152
+ * @see PHPUnit_Framework_Constraint::evaluate()
153
+ */
154
+ public function evaluate($other)
155
+ {
156
+ return $this->callProtectedByType('evaluate', $other);
157
+ }
158
+
159
+ /**
160
+ * Generates a failure exception based on exception type
161
+ *
162
+ * (non-PHPdoc)
163
+ * @see PHPUnit_Framework_Constraint::fail()
164
+ */
165
+ public function fail($other, $description, $not = FALSE)
166
+ {
167
+ $failureDescription = $this->failureDescription($other, $description, $not);
168
+
169
+ if (in_array($this->_type, $this->_typesWithDiff)) {
170
+ throw new EcomDev_PHPUnit_Constraint_Exception(
171
+ $failureDescription,
172
+ PHPUnit_Util_Diff::diff($this->getExpectedValue(), $this->getActualValue($other)),
173
+ $description
174
+ );
175
+ } else {
176
+ throw new EcomDev_PHPUnit_Constraint_Exception(
177
+ $failureDescription, $this->getActualValue($other), $description
178
+ );
179
+ }
180
+ }
181
+
182
+ /**
183
+ * Returns a scalar representation of actual value,
184
+ * Returns $other if internal acutal value is not set
185
+ *
186
+ * @param Varien_Simplexml_Element $other
187
+ * @return scalar
188
+ */
189
+ protected function getActualValue($other = null)
190
+ {
191
+ if ($this->_useActualValue) {
192
+ return $this->_actualValue;
193
+ }
194
+
195
+ return $other;
196
+ }
197
+
198
+ /**
199
+ * Returns a scalar representation of expected value
200
+ *
201
+ * @return string
202
+ */
203
+ protected function getExpectedValue()
204
+ {
205
+ return $this->_expectedValue;
206
+ }
207
+
208
+ /**
209
+ * Text reperesentation of constraint
210
+ * (non-PHPdoc)
211
+ * @see PHPUnit_Framework_SelfDescribing::toString()
212
+ */
213
+ public function toString()
214
+ {
215
+ return $this->callProtectedByType('text');
216
+ }
217
+ }
lib/EcomDev/PHPUnit/Constraint/Config.php ADDED
@@ -0,0 +1,111 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PHP Unit test suite for Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ *
12
+ * @category EcomDev
13
+ * @package EcomDev_PHPUnit
14
+ * @copyright Copyright (c) 2011 Ecommerce Developers (http://www.ecomdev.org)
15
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
+ * @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
17
+ */
18
+
19
+ /**
20
+ * Constraint for testing the configuration values
21
+ *
22
+ *
23
+ */
24
+ class EcomDev_PHPUnit_Constraint_Config extends PHPUnit_Framework_Constraint
25
+ {
26
+ /**
27
+ * Configuration instance
28
+ *
29
+ * @var Varien_Simplexml_Config
30
+ */
31
+ protected $config = null;
32
+
33
+ /**
34
+ * Configuration constraint
35
+ *
36
+ * @var PHPUnit_Framework_Constraint
37
+ */
38
+ protected $constraint = null;
39
+
40
+ /**
41
+ * Creates configuration constraint for config object
42
+ *
43
+ * @param Varien_Simplexml_Config $config
44
+ */
45
+ public function __construct($constraint)
46
+ {
47
+ if (!$constraint instanceof EcomDev_PHPUnit_Constraint_Config_Interface) {
48
+ throw PHPUnit_Util_InvalidArgumentHelper::factory(
49
+ 1, 'EcomDev_PHPUnit_Constraint_Config_Interface'
50
+ );
51
+ }
52
+ $this->constraint = $constraint;
53
+ }
54
+
55
+ /**
56
+ *
57
+ * @param mixed $other
58
+ * @param string $description
59
+ * @param boolean $not
60
+ */
61
+ public function fail($other, $description, $not)
62
+ {
63
+ $nodeValue = $this->getNodeValue($other);
64
+
65
+ return $this->constraint->fail($nodeValue, $description, $not);
66
+ }
67
+
68
+ /**
69
+ * Retrives a node value from configuration by child constraint path
70
+ *
71
+ *
72
+ * @param Varien_Simplexml_Config $other
73
+ */
74
+ protected function getNodeValue($config)
75
+ {
76
+ $nodeValue = $config->getNode(
77
+ $this->constraint->getNodePath()
78
+ );
79
+
80
+ if ($nodeValue === false) {
81
+ throw new EcomDev_PHPUnit_Constraint_Exception(
82
+ sprintf('Invalid node path specified for evaluation %s', $this->constraint->getNodePath())
83
+ );
84
+ }
85
+
86
+ return $nodeValue;
87
+ }
88
+
89
+ /**
90
+ * Evalutes constraint that is passed in the parameter
91
+ *
92
+ * @param Varien_Simplexml_Config $config
93
+ * @see PHPUnit_Framework_Constraint::evaluate()
94
+ */
95
+ public function evaluate($config)
96
+ {
97
+ $nodeValue = $this->getNodeValue($config);
98
+
99
+ return $this->constraint->evaluate($nodeValue);
100
+ }
101
+
102
+ /**
103
+ * Returns a string representation of the constraint.
104
+ *
105
+ * @return string
106
+ */
107
+ public function toString()
108
+ {
109
+ return $this->constraint->toString();
110
+ }
111
+ }
lib/EcomDev/PHPUnit/Constraint/Config/Abstract.php ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PHP Unit test suite for Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ *
12
+ * @category EcomDev
13
+ * @package EcomDev_PHPUnit
14
+ * @copyright Copyright (c) 2011 Ecommerce Developers (http://www.ecomdev.org)
15
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
+ * @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
17
+ */
18
+
19
+ /**
20
+ * Abstract class for constraints based on configuration
21
+ *
22
+ */
23
+ abstract class EcomDev_PHPUnit_Constraint_Config_Abstract
24
+ extends EcomDev_PHPUnit_Constraint_Abstract
25
+ implements EcomDev_PHPUnit_Constraint_Config_Interface
26
+ {
27
+ /**
28
+ * Config node path defined in the constructor
29
+ *
30
+ * @var string
31
+ */
32
+ protected $_nodePath = null;
33
+
34
+ /**
35
+ * Constraint constructor
36
+ *
37
+ * @param string $nodePath
38
+ * @param string $type
39
+ * @param mixed $expectedValue
40
+ */
41
+ public function __construct($nodePath, $type, $expectedValue = null)
42
+ {
43
+ if (empty($nodePath) || !is_string($nodePath)) {
44
+ throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string', $type);
45
+ }
46
+
47
+ $this->_nodePath = $nodePath;
48
+ parent::__construct($type, $expectedValue);
49
+ }
50
+
51
+ /**
52
+ * Returns node path for checking
53
+ *
54
+ * (non-PHPdoc)
55
+ * @see EcomDev_PHPUnit_Constraint_Config_Interface::getNodePath()
56
+ */
57
+ public function getNodePath()
58
+ {
59
+ return $this->_nodePath;
60
+ }
61
+
62
+ /**
63
+ * Automatically evaluate to false if the node was not found
64
+ *
65
+ * (non-PHPdoc)
66
+ * @see EcomDev_PHPUnit_Constraint_Abstract::evaluate()
67
+ */
68
+ public function evaluate($other)
69
+ {
70
+ if ($other === false) {
71
+ // If node was not found, than evaluation fails
72
+ return false;
73
+ }
74
+
75
+ return parent::evaluate($other);
76
+ }
77
+
78
+
79
+ /**
80
+ * Returns a scalar representation of actual value,
81
+ * Returns $other if internal acutal value is not set
82
+ *
83
+ * @param Varien_Simplexml_Element $other
84
+ * @return scalar
85
+ */
86
+ protected function getActualValue($other = null)
87
+ {
88
+ if (!$this->_useActualValue && $other->hasChildren()) {
89
+ return $other->asNiceXml();
90
+ } elseif (!$this->_useActualValue) {
91
+ return (string) $other;
92
+ }
93
+
94
+ return parent::getActualValue($other);
95
+ }
96
+
97
+ /**
98
+ * Returns a scalar representation of expected value
99
+ *
100
+ * @return string
101
+ */
102
+ protected function getExpectedValue()
103
+ {
104
+ if ($this->_expectedValue instanceof Varien_Simplexml_Element) {
105
+ return $this->_expectedValue->asNiceXml();
106
+ }
107
+
108
+ return parent::getExpectedValue();
109
+ }
110
+ }
lib/EcomDev/PHPUnit/Constraint/Config/ClassAlias.php ADDED
@@ -0,0 +1,140 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class alias constraint
5
+ *
6
+ */
7
+ class EcomDev_PHPUnit_Constraint_Config_ClassAlias
8
+ extends EcomDev_PHPUnit_Constraint_Config_Abstract
9
+ {
10
+ const XML_PATH_CLASS_ALIAS = 'global/%s/%s';
11
+
12
+ const GROUP_BLOCK = 'blocks';
13
+ const GROUP_MODEL = 'models';
14
+ const GROUP_HELPER = 'helpers';
15
+
16
+ const TYPE_CLASS_ALIAS = 'class_alias';
17
+
18
+ /**
19
+ * Mapping of the text that represents
20
+ * class alias group in fail message
21
+ *
22
+ * @var array
23
+ */
24
+ protected $_textByGroup = array(
25
+ self::GROUP_BLOCK => 'block alias',
26
+ self::GROUP_MODEL => 'model alias',
27
+ self::GROUP_HELPER => 'helper alias'
28
+ );
29
+
30
+ /**
31
+ * Class alias name, e.g. the name of the model
32
+ *
33
+ * @var string
34
+ */
35
+ protected $_classAliasName = null;
36
+
37
+ /**
38
+ * Class alias prefix,
39
+ * e.g. the prefix for models of a particular module
40
+ *
41
+ * @var string
42
+ */
43
+ protected $_classAliasPrefix = null;
44
+
45
+ /**
46
+ * Class alias group
47
+ *
48
+ * @var string
49
+ */
50
+ protected $_group = null;
51
+
52
+ /**
53
+ * Constraint for evaluation of grouped class alias (block, model, helper)
54
+ *
55
+ * @param string $group
56
+ * @param string $classAlias
57
+ * @param string $expectedClassName
58
+ * @param string $type
59
+ */
60
+ public function __construct($group, $classAlias, $expectedClassName, $type = self::TYPE_CLASS_ALIAS)
61
+ {
62
+ if (!isset($this->_textByGroup[$group])) {
63
+ throw PHPUnit_Util_InvalidArgumentHelper::factory(
64
+ 1,
65
+ implode(
66
+ '|',
67
+ array_keys($this->_textByGroup)
68
+ ),
69
+ $group
70
+ );
71
+ }
72
+
73
+ $this->_group = $group;
74
+
75
+ if ($group === self::GROUP_HELPER && strpos($classAlias, '/') === false) {
76
+ $classAlias .= '/data';
77
+ }
78
+
79
+ if (!strpos($classAlias, '/')) {
80
+ throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'class/alias', $classAlias);
81
+ }
82
+
83
+ list($this->_classAliasPrefix, $this->_classAliasName) = explode('/', $classAlias, 2);
84
+
85
+ $nodePath = sprintf(self::XML_PATH_CLASS_ALIAS, $group, $this->_classAliasPrefix);
86
+
87
+ $this->_expectedValueValidation += array(
88
+ self::TYPE_CLASS_ALIAS => array(true, 'is_string', 'string')
89
+ );
90
+
91
+ $this->_typesWithDiff[] = self::TYPE_CLASS_ALIAS;
92
+
93
+ parent::__construct($nodePath, $type, $expectedClassName);
94
+ }
95
+
96
+ /**
97
+ * Evaluates class alias is mapped to expected class name
98
+ *
99
+ * @param Varien_Simplexml_Element $other
100
+ * @return boolean
101
+ */
102
+ protected function evaluateClassAlias($other)
103
+ {
104
+ $classPrefix = $other->class;
105
+
106
+ if (isset($other->rewrite->{$this->_classAliasName})) {
107
+ $className = (string)$other->rewrite->{$this->_classAliasName};
108
+ } else {
109
+ $className = $classPrefix . '_' . uc_words($this->_classAliasName);
110
+ }
111
+
112
+ $this->setActualValue($className);
113
+ return $this->_actualValue === $this->_expectedValue;
114
+ }
115
+
116
+ /**
117
+ * Text representation of class alias constaint
118
+ *
119
+ * @return string
120
+ */
121
+ protected function textClassAlias()
122
+ {
123
+ return 'is mapped to expected class name';
124
+ }
125
+
126
+ /**
127
+ * Custom failure description for showing config related errors
128
+ * (non-PHPdoc)
129
+ * @see PHPUnit_Framework_Constraint::customFailureDescription()
130
+ */
131
+ protected function customFailureDescription($other, $description, $not)
132
+ {
133
+ return sprintf(
134
+ 'Failed asserting that %s "%s/%s" %s.',
135
+ $this->_textByGroup[$this->_group],
136
+ $this->_classAliasPrefix, $this->_classAliasName,
137
+ $this->toString()
138
+ );
139
+ }
140
+ }
lib/EcomDev/PHPUnit/Constraint/Config/EventObserver.php ADDED
@@ -0,0 +1,178 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PHP Unit test suite for Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ *
12
+ * @category EcomDev
13
+ * @package EcomDev_PHPUnit
14
+ * @copyright Copyright (c) 2011 Ecommerce Developers (http://www.ecomdev.org)
15
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
+ * @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
17
+ */
18
+
19
+ /**
20
+ * Constraint for testing event observer definition
21
+ * in the configuration
22
+ *
23
+ */
24
+ class EcomDev_PHPUnit_Constraint_Config_EventObserver
25
+ extends EcomDev_PHPUnit_Constraint_Config_Abstract
26
+ {
27
+ const XML_PATH_EVENTS = '%s/events';
28
+
29
+ const TYPE_DEFINDED = 'defined';
30
+
31
+ const OBSERVER_TYPE_DISABLED = 'disabled';
32
+ const OBSERVER_TYPE_SINGLETON = 'singleton';
33
+ const OBSERVER_TYPE_MODEL = 'model';
34
+
35
+ /**
36
+ * Event area (frontend, adminhtml, global, cron)
37
+ *
38
+ * @var string
39
+ */
40
+ protected $_area = null;
41
+
42
+ /**
43
+ * Observer name for additional restriction
44
+ *
45
+ * @var string|null
46
+ */
47
+ protected $_observerName = null;
48
+
49
+ /**
50
+ * Observer class alias
51
+ *
52
+ * @var string
53
+ */
54
+ protected $_observerClassAlias = null;
55
+
56
+ /**
57
+ * Observer method
58
+ *
59
+ * @var string
60
+ */
61
+ protected $_observerMethod = null;
62
+
63
+ /**
64
+ * Name of the event that should be observed
65
+ *
66
+ * @var string
67
+ */
68
+ protected $_eventName = null;
69
+
70
+ /**
71
+ * Constraint for testing observer
72
+ * event definitions in configuration
73
+ *
74
+ * @param string $area
75
+ * @param string $eventName
76
+ * @param string $observerClassAlias
77
+ * @param string $observerMethod
78
+ * @param string|null $observerName
79
+ */
80
+ public function __construct($area, $eventName, $observerClassAlias, $observerMethod, $type = self::TYPE_DEFINDED, $observerName = null)
81
+ {
82
+ if (empty($area) || !is_string($area)) {
83
+ throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string', $area);
84
+ }
85
+
86
+ if (empty($eventName) || !is_string($eventName)) {
87
+ throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'string', $eventName);
88
+ }
89
+
90
+ if (empty($observerClassAlias) || !is_string($observerClassAlias)) {
91
+ throw PHPUnit_Util_InvalidArgumentHelper::factory(3, 'string', $observerClassAlias);
92
+ }
93
+
94
+ if (empty($observerMethod) || !is_string($observerMethod)) {
95
+ throw PHPUnit_Util_InvalidArgumentHelper::factory(4, 'string', $observerMethod);
96
+ }
97
+
98
+ if ($observerName !== null && !is_string($observerName)) {
99
+ throw PHPUnit_Util_InvalidArgumentHelper::factory(6, 'string', $observerName);
100
+ }
101
+
102
+ $this->_area = $area;
103
+ $this->_eventName = $eventName;
104
+
105
+ $this->_observerClassAlias = $observerClassAlias;
106
+ $this->_observerMethod = $observerMethod;
107
+ $this->_observerName = $observerName;
108
+
109
+ $expectedValue = $this->_observerClassAlias . '::' . $this->_observerMethod;
110
+ $nodePath = sprintf(self::XML_PATH_EVENTS, $this->_area, $this->_eventName);
111
+
112
+ parent::__construct($nodePath, $type, $expectedValue);
113
+ }
114
+
115
+ /**
116
+ * Evaluates that observer is defined and enabled
117
+ *
118
+ * @param Varien_Simplexml_Element $other
119
+ * @return boolean
120
+ */
121
+ protected function evaluateDefined($other)
122
+ {
123
+ $this->setActualValue(false);
124
+
125
+ if (!isset($other->{$this->_eventName}->observers)) {
126
+ return false;
127
+ }
128
+
129
+ $observers = $other->{$this->_eventName}->observers;
130
+ foreach ($observers->children() as $observer) {
131
+ if ((string)$observer->type === self::OBSERVER_TYPE_DISABLED ||
132
+ ($this->_observerName !== null && $this->_observerName !== $observer->getName())) {
133
+ continue;
134
+ }
135
+
136
+ $classAlias = (isset($observer->class) ? (string) $observer->class : $observer->getClassName());
137
+ $method = (string)$observer->method;
138
+
139
+ if ($classAlias === $this->_observerClassAlias && $method == $this->_observerMethod) {
140
+ $this->setActualValue($classAlias . '::' . $method);
141
+ return true;
142
+ }
143
+ }
144
+
145
+ return false;
146
+ }
147
+
148
+ /**
149
+ * Text representation of event observer definition evaluation
150
+ *
151
+ * @return string
152
+ */
153
+ protected function textDefined()
154
+ {
155
+ $text = 'is defined';
156
+ if ($this->_observerName !== null) {
157
+ $text .= sprintf(' as %s observer name', $this->_observerName);
158
+ }
159
+
160
+ return $text;
161
+ }
162
+
163
+
164
+ /**
165
+ * Custom failure description for showing config related errors
166
+ * (non-PHPdoc)
167
+ * @see PHPUnit_Framework_Constraint::customFailureDescription()
168
+ */
169
+ protected function customFailureDescription($other, $description, $not)
170
+ {
171
+ return sprintf(
172
+ 'Failed asserting that %s "%s" event observer %s.',
173
+ $this->_area,
174
+ $this->_expectedValue,
175
+ $this->toString()
176
+ );
177
+ }
178
+ }
lib/EcomDev/PHPUnit/Constraint/Config/Interface.php ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PHP Unit test suite for Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ *
12
+ * @category EcomDev
13
+ * @package EcomDev_PHPUnit
14
+ * @copyright Copyright (c) 2011 Ecommerce Developers (http://www.ecomdev.org)
15
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
+ * @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
17
+ */
18
+
19
+ /**
20
+ * Interface for configuration constraints
21
+ *
22
+ */
23
+ interface EcomDev_PHPUnit_Constraint_Config_Interface
24
+ {
25
+ public function getNodePath();
26
+ }
lib/EcomDev/PHPUnit/Constraint/Config/Layout.php ADDED
@@ -0,0 +1,192 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PHP Unit test suite for Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ *
12
+ * @category EcomDev
13
+ * @package EcomDev_PHPUnit
14
+ * @copyright Copyright (c) 2011 Ecommerce Developers (http://www.ecomdev.org)
15
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
+ * @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
17
+ */
18
+
19
+ /**
20
+ * Layout configuration constraint
21
+ *
22
+ */
23
+ class EcomDev_PHPUnit_Constraint_Config_Layout
24
+ extends EcomDev_PHPUnit_Constraint_Config_Abstract
25
+ {
26
+ const XML_PATH_LAYOUT = '%s/layout/updates';
27
+
28
+ const TYPE_LAYOUT_DEFINITION = 'layout_definition';
29
+ const TYPE_LAYOUT_FILE = 'layout_file';
30
+
31
+ /**
32
+ * Design area (frontend, adminhtml)
33
+ *
34
+ * @var string
35
+ */
36
+ protected $_area = null;
37
+
38
+ /**
39
+ * Name of layout update,
40
+ * if specified, constraint
41
+ * will be additionally checked by this parameter
42
+ *
43
+ * @var string
44
+ */
45
+ protected $_layoutUpdate = null;
46
+
47
+ /**
48
+ * Restriction by theme name
49
+ *
50
+ * @var string
51
+ */
52
+ protected $_theme = null;
53
+
54
+ /**
55
+ * Restriction by design package name
56
+ *
57
+ * @var string
58
+ */
59
+ protected $_designPackage = null;
60
+
61
+ /**
62
+ * Model for assertion of the data
63
+ *
64
+ * @var EcomDev_PHPUnit_Constraint_Config_Design_Package_Interface
65
+ */
66
+ protected static $_designPackageModel = null;
67
+
68
+ /**
69
+ * Configuration constraint for cheking the existance of
70
+ * layout file in configuration and a particular theme as well
71
+ *
72
+ * @param string $area design area (frontend|adminhtml)
73
+ * @param string $expectedFile layout file name that should be checked
74
+ * @param string $type type of assertion
75
+ * @param string|null $layoutUpdate additional check for layout update name for assertion of configuration
76
+ * @param string|null $theme additional check for layout file existance in a particular theme
77
+ * @param string|null $designPackage additional check for layout file existance in a particular theme
78
+ */
79
+ public function __construct($area, $expectedFile, $type, $layoutUpdate = null,
80
+ $theme = null, $designPackage = null)
81
+ {
82
+ $this->_area = $area;
83
+ $this->_layoutUpdate = $layoutUpdate;
84
+ $this->_designPackage = $designPackage;
85
+ $this->_theme = $theme;
86
+
87
+ $this->_expectedValueValidation += array(
88
+ self::TYPE_LAYOUT_FILE => array(true, 'is_string', 'string'),
89
+ self::TYPE_LAYOUT_DEFINITION => array(true, 'is_string', 'string')
90
+ );
91
+
92
+ $this->_typesWithDiff[] = self::TYPE_LAYOUT_FILE;
93
+
94
+ $nodePath = sprintf(self::XML_PATH_LAYOUT, $area);
95
+
96
+ parent::__construct($nodePath, $type, $expectedFile);
97
+ }
98
+
99
+ /**
100
+ * Sets design package model for assertions
101
+ *
102
+ * @param EcomDev_PHPUnit_Design_Package_Interface $model
103
+ */
104
+ public static function setDesignPackageModel(EcomDev_PHPUnit_Design_Package_Interface $model)
105
+ {
106
+ self::$_designPackageModel = $model;
107
+ }
108
+
109
+ /**
110
+ * Retrieves design package model that was set before
111
+ *
112
+ * @return EcomDev_PHPUnit_Design_Package_Interface
113
+ */
114
+ public static function getDesignPackageModel()
115
+ {
116
+ return self::$_designPackageModel;
117
+ }
118
+
119
+ /**
120
+ * Checks layout definititions for expected file defined in the configuration
121
+ *
122
+ * @param Varien_Simplexml_Element $other
123
+ * @return boolean
124
+ */
125
+ protected function evaluateLayoutDefinition($other)
126
+ {
127
+ foreach ($other->children() as $layoutUpdate) {
128
+ if ((string)$layoutUpdate->file === $this->_expectedValue
129
+ && ($this->_layoutUpdate === null || $this->_layoutUpdate === $layoutUpdate->getName())) {
130
+ return true;
131
+ }
132
+ }
133
+
134
+ return false;
135
+ }
136
+
137
+ /**
138
+ * Layout defition assertion text
139
+ *
140
+ * @return string
141
+ */
142
+ protected function textLayoutDefition()
143
+ {
144
+ $text = sprintf('file "%s" is defined in configuration for %s area', $this->_expectedValue, $this->_area);
145
+
146
+ if ($this->_layoutUpdate !== null) {
147
+ $text .= sprintf(' in "%s" layout update', $this->_layoutUpdate);
148
+ }
149
+
150
+ return $text;
151
+ }
152
+
153
+ /**
154
+ * Evaluates layout file existance
155
+ *
156
+ * @param Varien_Simplexml_Element $other
157
+ * @return boolean
158
+ */
159
+ protected function evaluateLayoutFile($other)
160
+ {
161
+ $assertion = self::getDesignPackageModel()
162
+ ->getLayoutFileAssertion($this->_expectedValue, $this->_area, $this->_designPackage, $this->_theme);
163
+
164
+ $this->setActualValue($assertion['actual']);
165
+ $this->_expectedValue = $assertion['expected'];
166
+
167
+ return $this->_actualValue !== $this->_expectedValue;
168
+ }
169
+
170
+ /**
171
+ * Text representation of layout file existance constraint
172
+ *
173
+ * @return string
174
+ */
175
+ protected function textLayoutFile()
176
+ {
177
+ return 'file is the same as expected and exists';
178
+ }
179
+
180
+ /**
181
+ * Custom failure description for showing config related errors
182
+ * (non-PHPdoc)
183
+ * @see PHPUnit_Framework_Constraint::customFailureDescription()
184
+ */
185
+ protected function customFailureDescription($other, $description, $not)
186
+ {
187
+ return sprintf(
188
+ 'Failed asserting that layout %s.',
189
+ $this->toString()
190
+ );
191
+ }
192
+ }
lib/EcomDev/PHPUnit/Constraint/Config/Module.php ADDED
@@ -0,0 +1,228 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PHP Unit test suite for Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ *
12
+ * @category EcomDev
13
+ * @package EcomDev_PHPUnit
14
+ * @copyright Copyright (c) 2011 Ecommerce Developers (http://www.ecomdev.org)
15
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
+ * @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
17
+ */
18
+
19
+ /**
20
+ * Module configuration constraint
21
+ *
22
+ */
23
+ class EcomDev_PHPUnit_Constraint_Config_Module
24
+ extends EcomDev_PHPUnit_Constraint_Config_Abstract
25
+ {
26
+ const XML_PATH_MODULE_NODE = 'modules/%s';
27
+
28
+ const TYPE_IS_ACTIVE = 'is_active';
29
+ const TYPE_CODE_POOL = 'code_pool';
30
+ const TYPE_DEPENDS = 'depends';
31
+ const TYPE_EQUALS_VERSION = 'version';
32
+ const TYPE_LESS_THAN_VERSION = 'version_less_than';
33
+ const TYPE_GREATER_THAN_VERSION = 'version_greater_than';
34
+
35
+ /**
36
+ * Name of the module for constraint
37
+ *
38
+ * @var string
39
+ */
40
+ protected $_moduleName = null;
41
+
42
+ /**
43
+ * Contraint for evaluation of module config node
44
+ *
45
+ * @param string $nodePath
46
+ * @param string $type
47
+ * @param mixed $expectedValue
48
+ */
49
+ public function __construct($moduleName, $type, $expectedValue)
50
+ {
51
+ $this->_expectedValueValidation += array(
52
+ self::TYPE_CODE_POOL => array(true, 'is_string', 'string'),
53
+ self::TYPE_DEPENDS => array(true, 'is_string', 'string'),
54
+ self::TYPE_EQUALS_VERSION => array(true, 'is_string', 'string'),
55
+ self::TYPE_LESS_THAN_VERSION => array(true, 'is_string', 'string'),
56
+ self::TYPE_GREATER_THAN_VERSION => array(true, 'is_string', 'string'),
57
+ );
58
+
59
+ $this->_typesWithDiff[] = self::TYPE_CODE_POOL;
60
+ $this->_typesWithDiff[] = self::TYPE_EQUALS_VERSION;
61
+ $this->_typesWithDiff[] = self::TYPE_LESS_THAN_VERSION;
62
+ $this->_typesWithDiff[] = self::TYPE_GREATER_THAN_VERSION;
63
+
64
+ parent::__construct(
65
+ sprintf(self::XML_PATH_MODULE_NODE, $moduleName),
66
+ $type,
67
+ $expectedValue
68
+ );
69
+
70
+ $this->_moduleName = $moduleName;
71
+ }
72
+
73
+ /**
74
+ * Evaluates module is active
75
+ *
76
+ * @param Varien_Simplexml_Element $other
77
+ * @return boolean
78
+ */
79
+ protected function evaluateIsActive($other)
80
+ {
81
+ return $other->is('active');
82
+ }
83
+
84
+ /**
85
+ * Text representation of module is active constraint
86
+ *
87
+ * @return string
88
+ */
89
+ protected function textIsActive()
90
+ {
91
+ return 'is active';
92
+ }
93
+
94
+ /**
95
+ * Evaluates module code pool
96
+ *
97
+ * @param Varien_Simplexml_Element $other
98
+ * @return boolean
99
+ */
100
+ protected function evaluateCodePool($other)
101
+ {
102
+ $this->setActualValue((string)$other->codePool);
103
+
104
+ return $this->_actualValue === $this->_expectedValue;
105
+ }
106
+
107
+ /**
108
+ * Text representation of module is active constraint
109
+ *
110
+ * @return string
111
+ */
112
+ protected function textCodePool()
113
+ {
114
+ return sprintf('is placed in %s code pool', $this->_expectedValue);
115
+ }
116
+
117
+ /**
118
+ * Evaluates module is dependent on expected one
119
+ *
120
+ * @param Varien_Simplexml_Element $other
121
+ * @return boolean
122
+ */
123
+ protected function evaluateDepends($other)
124
+ {
125
+ if (!isset($other->depends) || !$other->depends->hasChildren()) {
126
+ return false;
127
+ }
128
+
129
+ return isset($other->depends->{$this->_expectedValue});
130
+ }
131
+
132
+ /**
133
+ * Text representation of module dependance
134
+ *
135
+ * @return string
136
+ */
137
+ protected function textDepends()
138
+ {
139
+ return sprintf('is dependent on %s module', $this->_expectedValue);
140
+ }
141
+
142
+ /**
143
+ * Evaluates module version is equal to expected
144
+ *
145
+ * @param Varien_Simplexml_Element $other
146
+ * @return boolean
147
+ */
148
+ protected function evaluateVersion($other)
149
+ {
150
+ return $this->compareVersion($other, '=');
151
+ }
152
+
153
+ /**
154
+ * Text representation of module version check
155
+ *
156
+ * @return string
157
+ */
158
+ protected function textVersion()
159
+ {
160
+ return sprintf('version is equal to %s', $this->_expectedValue);
161
+ }
162
+
163
+ /**
164
+ * Evaluates module version is less than expected
165
+ *
166
+ * @param Varien_Simplexml_Element $other
167
+ * @return boolean
168
+ */
169
+ protected function evaluateVersionLessThan($other)
170
+ {
171
+ return $this->compareVersion($other, '<');
172
+ }
173
+
174
+ /**
175
+ * Text representation of module version check
176
+ *
177
+ * @return string
178
+ */
179
+ protected function textVersionLessThan()
180
+ {
181
+ return sprintf('version is less than %s', $this->_expectedValue);
182
+ }
183
+
184
+ /**
185
+ * Evaluates module version is greater than expected
186
+ *
187
+ * @param Varien_Simplexml_Element $other
188
+ * @return boolean
189
+ */
190
+ protected function evaluateVersionGreaterThan($other)
191
+ {
192
+ return $this->compareVersion($other, '>');
193
+ }
194
+
195
+ /**
196
+ * Text representation of module version check
197
+ *
198
+ * @return string
199
+ */
200
+ protected function textVersionGreaterThan()
201
+ {
202
+ return sprintf('version is greater than %s', $this->_expectedValue);
203
+ }
204
+
205
+ /**
206
+ * Internal comparisment of the module version
207
+ *
208
+ * @param Varien_Simplexml_Element $other
209
+ * @param string $operator
210
+ */
211
+ protected function compareVersion($other, $operator)
212
+ {
213
+ $this->setActualValue((string)$other->version);
214
+ return version_compare($this->_actualValue, $this->_expectedValue, $operator);
215
+ }
216
+
217
+ /**
218
+ * Custom failure description for showing config related errors
219
+ * (non-PHPdoc)
220
+ * @see PHPUnit_Framework_Constraint::customFailureDescription()
221
+ */
222
+ protected function customFailureDescription($other, $description, $not)
223
+ {
224
+ return sprintf(
225
+ 'Failed asserting that %s module %s.', $this->_moduleName, $this->toString()
226
+ );
227
+ }
228
+ }
lib/EcomDev/PHPUnit/Constraint/Config/Node.php ADDED
@@ -0,0 +1,306 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PHP Unit test suite for Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ *
12
+ * @category EcomDev
13
+ * @package EcomDev_PHPUnit
14
+ * @copyright Copyright (c) 2011 Ecommerce Developers (http://www.ecomdev.org)
15
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
+ * @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
17
+ */
18
+
19
+ /**
20
+ * Configuration node constaint
21
+ *
22
+ */
23
+ class EcomDev_PHPUnit_Constraint_Config_Node
24
+ extends EcomDev_PHPUnit_Constraint_Config_Abstract
25
+ {
26
+ const TYPE_EQUALS_STRING = 'equals_string';
27
+ const TYPE_EQUALS_BOOLEAN = 'equals_boolean';
28
+ const TYPE_EQUALS_XML = 'equals_xml';
29
+ const TYPE_EQUALS_NUMBER = 'equals_decimal';
30
+ const TYPE_LESS_THAN = 'less_than';
31
+ const TYPE_GREATER_THAN = 'greater_than';
32
+ const TYPE_CONTAIN_VALUE = 'contain_values';
33
+ const TYPE_HAS_CHILD = 'has_child';
34
+ const TYPE_HAS_CHILDREN = 'has_children';
35
+
36
+ /**
37
+ * Contraint for evaluation of config node
38
+ *
39
+ * @param string $moduleName
40
+ * @param string $type
41
+ * @param mixed $expectedValue
42
+ */
43
+ public function __construct($nodePath, $type, $expectedValue = null)
44
+ {
45
+ $this->_expectedValueValidation += array(
46
+ self::TYPE_EQUALS_STRING => array(true, 'is_string', 'string'),
47
+ self::TYPE_EQUALS_NUMBER => array(true, 'is_numeric', 'numeric'),
48
+ self::TYPE_LESS_THAN => array(true, 'is_numeric', 'numeric'),
49
+ self::TYPE_GREATER_THAN => array(true, 'is_numeric', 'numeric'),
50
+ self::TYPE_CONTAIN_VALUE => array(true, 'is_scalar', 'scalar'),
51
+ self::TYPE_HAS_CHILD => array(true, 'is_string', 'string')
52
+ );
53
+
54
+ $this->_typesWithDiff[] = self::TYPE_EQUALS_STRING;
55
+ $this->_typesWithDiff[] = self::TYPE_EQUALS_BOOLEAN;
56
+ $this->_typesWithDiff[] = self::TYPE_EQUALS_XML;
57
+ $this->_typesWithDiff[] = self::TYPE_EQUALS_NUMBER;
58
+ $this->_typesWithDiff[] = self::TYPE_LESS_THAN;
59
+ $this->_typesWithDiff[] = self::TYPE_GREATER_THAN;
60
+
61
+ parent::__construct($nodePath, $type, $expectedValue);
62
+ }
63
+
64
+ /**
65
+ * Check that node value is equal to string
66
+ *
67
+ * @param Varien_Simplexml_Element $other
68
+ */
69
+ protected function evaluateEqualsString($other)
70
+ {
71
+ return (string)$other === $this->_expectedValue;
72
+ }
73
+
74
+ /**
75
+ * Text representation of the assertion
76
+ *
77
+ * @return string
78
+ */
79
+ protected function textEqualsString()
80
+ {
81
+ return 'is equal to expected string';
82
+ }
83
+
84
+ /**
85
+ * Check that node value is equal to number
86
+ *
87
+ * @param Varien_Simplexml_Element $other
88
+ */
89
+ protected function evaluateEqualsNumber($other)
90
+ {
91
+ return (float)$other == $this->_expectedValue;
92
+ }
93
+
94
+ /**
95
+ * Text representation of the assertion
96
+ *
97
+ * @return string
98
+ */
99
+ protected function textEqualsNumber()
100
+ {
101
+ return 'is equal to expected number';
102
+ }
103
+
104
+ /**
105
+ * Check that node value is a string with such properties
106
+ *
107
+ * @param Varien_Simplexml_Element $other
108
+ */
109
+ protected function evaluateLessThan($other)
110
+ {
111
+ return (float)$other > (float)$this->_expectedValue;
112
+ }
113
+
114
+ /**
115
+ * Text representation of the assertion
116
+ *
117
+ * @return string
118
+ */
119
+ protected function textLessThan()
120
+ {
121
+ return sprintf('is less than %s', (float)$this->_expectedValue);
122
+ }
123
+
124
+ /**
125
+ * Check that node value is a string with such properties
126
+ *
127
+ * @param Varien_Simplexml_Element $other
128
+ */
129
+ protected function evaluateGreaterThan($other)
130
+ {
131
+ return (float)$other > (float)$this->_expectedValue;
132
+ }
133
+
134
+ /**
135
+ * Text representation of the assertion
136
+ *
137
+ * @return string
138
+ */
139
+ protected function textGreaterThan()
140
+ {
141
+ return sprintf('is greater than %s', (float)$this->_expectedValue);
142
+ }
143
+
144
+
145
+ /**
146
+ * Checks that string is not false value of a config flag
147
+ *
148
+ * @param Varien_Simplexml_Element $other
149
+ */
150
+ protected function evaluateEqualsBoolean($other)
151
+ {
152
+ $other = (string) $other;
153
+ return !empty($other) && $other !== 'false';
154
+ }
155
+
156
+ /**
157
+ * Returns text reperesentation of flag checking
158
+ *
159
+ * @return string
160
+ */
161
+ protected function textEqualsBoolean()
162
+ {
163
+ return 'is equals to boolean flag true';
164
+ }
165
+
166
+ /**
167
+ * Checks expected xml value with current configuration
168
+ *
169
+ * @param Varien_Simplexml_Element $other
170
+ * @throws RuntimeException if expected value is a valid xml object
171
+ */
172
+ protected function evaluateEqualsXml($other)
173
+ {
174
+ // Normalize expected XML for matching appropriate xml structure without
175
+ // whitespaces, etc
176
+ if (!$this->_expectedValue instanceof Varien_Simplexml_Element) {
177
+ try {
178
+ if ($other instanceof SimpleXMLElement) {
179
+ $other = $other->asXML();
180
+ }
181
+ $expectedXml = new Varien_Simplexml_Element($this->_expectedValue);
182
+ } catch (Exception $e) {
183
+ throw new RuntimeException(sprintf(
184
+ 'Expected value is not an xml string for node %s, passed expected value: %s, parsing error: %s',
185
+ $this->_nodePath,
186
+ PHPUnit_Util_Type::toString($this->_expectedValue),
187
+ $e->getMessage()
188
+ ));
189
+ }
190
+
191
+ $this->_expectedValue = $expectedXml;
192
+ }
193
+
194
+ return $this->_expectedValue->asNiceXml() == $other->asNiceXml();
195
+ }
196
+
197
+
198
+ /**
199
+ * Returns text representatation of xml comparisment
200
+ *
201
+ * @return string
202
+ */
203
+ protected function textEqualsXml()
204
+ {
205
+ return 'is the same as expected XML value';
206
+ }
207
+
208
+ /**
209
+ * Checks existance of a child with the expected value as the name
210
+ *
211
+ * @param Varien_Simplexml_Element $other
212
+ * @return boolean
213
+ */
214
+ protected function evaluateHasChild($other)
215
+ {
216
+ if (!$other->hasChildren()) {
217
+ return false;
218
+ }
219
+
220
+ if (!isset($other->{$this->_expectedValue})) {
221
+ return false;
222
+ }
223
+
224
+ return true;
225
+ }
226
+
227
+ /**
228
+ * Returns text represetnation of contain child assert
229
+ *
230
+ * @return string
231
+ */
232
+ protected function textHasChild()
233
+ {
234
+ return sprintf('has "%s" child node', $this->_expectedValue);
235
+ }
236
+
237
+ /**
238
+ * Checks that configuration node has children
239
+ *
240
+ * @param Varien_Simplexml_Element $other
241
+ * @return boolean
242
+ */
243
+ protected function evaluateHasChildren($other)
244
+ {
245
+ return $other->hasChildren();
246
+ }
247
+
248
+ /**
249
+ * Returns text representation of has children assert
250
+ *
251
+ * @return string
252
+ */
253
+ protected function textHasChildren()
254
+ {
255
+ return 'has children';
256
+ }
257
+
258
+ /**
259
+ * Checks multiple values nodes.
260
+ * Values are comma separated string
261
+ *
262
+ * @param Varien_Simplexml_Element $other
263
+ * @return boolean
264
+ */
265
+ protected function evaluateContainValue($other)
266
+ {
267
+ if ($other->hasChildren()) {
268
+ throw new RuntimeException(sprintf(
269
+ 'Config node "%s" is not a string of comma separated values, passed expected value: %s',
270
+ $this->_nodePath,
271
+ PHPUnit_Util_Type::toString($this->_expectedValue)
272
+ ));
273
+ }
274
+
275
+ $values = explode(',', (string)$other);
276
+
277
+ if (!in_array($this->_expectedValue, $values)) {
278
+ return true;
279
+ }
280
+
281
+ return false;
282
+ }
283
+
284
+ /**
285
+ * Returns text representation of contain value assert
286
+ *
287
+ * @return string
288
+ */
289
+ protected function textContainValue()
290
+ {
291
+ return sprintf('contains "%s" in comma separated value list',
292
+ PHPUnit_Util_Type::toString($this->_expectedValue));
293
+ }
294
+
295
+ /**
296
+ * Custom failure description for showing config related errors
297
+ * (non-PHPdoc)
298
+ * @see PHPUnit_Framework_Constraint::customFailureDescription()
299
+ */
300
+ protected function customFailureDescription($other, $description, $not)
301
+ {
302
+ return sprintf(
303
+ 'Failed asserting that configuration node "%s" %s.', $this->_nodePath, $this->toString()
304
+ );
305
+ }
306
+ }
lib/EcomDev/PHPUnit/Constraint/Config/Resource.php ADDED
@@ -0,0 +1,236 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PHP Unit test suite for Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ *
12
+ * @category EcomDev
13
+ * @package EcomDev_PHPUnit
14
+ * @copyright Copyright (c) 2012 EcomDev BV (http://www.ecomdev.org)
15
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
+ * @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
17
+ */
18
+
19
+ /**
20
+ * Setup resources configuration constraint
21
+ *
22
+ */
23
+ class EcomDev_PHPUnit_Constraint_Config_Resource
24
+ extends EcomDev_PHPUnit_Constraint_Config_Abstract
25
+ {
26
+ const XML_PATH_RESOURCES_NODE = 'global/resources';
27
+
28
+ const TYPE_SETUP_DEFINED = 'setup_defined';
29
+ const TYPE_SETUP_SCHEME_EXISTS = 'setup_scheme_exists';
30
+ const TYPE_SETUP_DATA_EXISTS = 'setup_data_exists';
31
+
32
+ /**
33
+ * Name of the module for constraint
34
+ *
35
+ * @var string
36
+ */
37
+ protected $_moduleName = null;
38
+
39
+ /**
40
+ * The module directory for constraint
41
+ *
42
+ * @var string
43
+ */
44
+ protected $_moduleDirectory = null;
45
+
46
+ /**
47
+ * Constraint for evaluation of module config node
48
+ *
49
+ * @param string $nodePath
50
+ * @param string $type
51
+ * @param string $moduleDirectory
52
+ * @param mixed $expectedValue
53
+ */
54
+ public function __construct($moduleName, $type, $moduleDirectory = null, $expectedValue = null)
55
+ {
56
+ $this->_expectedValueValidation += array(
57
+ self::TYPE_SETUP_DEFINED => array(false, 'is_string', 'string'),
58
+ self::TYPE_SETUP_SCHEME_EXISTS => array(false, 'is_string', 'string'),
59
+ self::TYPE_SETUP_DATA_EXISTS => array(false, 'is_string', 'string'),
60
+ );
61
+
62
+ $this->_typesWithDiff[] = self::TYPE_SETUP_DEFINED;
63
+ $this->_typesWithDiff[] = self::TYPE_SETUP_SCHEME_EXISTS;
64
+ $this->_typesWithDiff[] = self::TYPE_SETUP_DATA_EXISTS;
65
+
66
+ parent::__construct(
67
+ self::XML_PATH_RESOURCES_NODE,
68
+ $type,
69
+ $expectedValue
70
+ );
71
+
72
+ $this->_moduleName = $moduleName;
73
+ $this->_moduleDirectory = $moduleDirectory;
74
+
75
+ if (($this->_type === self::TYPE_SETUP_SCHEME_EXISTS || $this->_type === self::TYPE_SETUP_DATA_EXISTS)
76
+ && !is_dir($moduleDirectory)) {
77
+ throw PHPUnit_Util_InvalidArgumentHelper::factory(3, 'real directory', $moduleDirectory);
78
+ }
79
+ }
80
+
81
+ /**
82
+ * Returns list of module setup resources
83
+ *
84
+ * @param Varien_Simplexml_Element $xml
85
+ * @return array
86
+ */
87
+ protected function getModuleSetupResources(Varien_Simplexml_Element $xml)
88
+ {
89
+ $resourcesForModule = array();
90
+ foreach ($xml->children() as $resourceNode) {
91
+ if (isset($resourceNode->setup->module)
92
+ && (string)$resourceNode->setup->module === $this->_moduleName) {
93
+ $resourcesForModule[] = $resourceNode->getName();
94
+ }
95
+ }
96
+
97
+ return $resourcesForModule;
98
+ }
99
+
100
+ /**
101
+ * Checks definition of expected resource name
102
+ *
103
+ * @param Varien_Simplexml_Element $other
104
+ */
105
+ protected function evaluateSetupDefined($other)
106
+ {
107
+ $moduleResources = $this->getModuleSetupResources($other);
108
+
109
+ if ($this->_expectedValue === null) {
110
+ $this->_expectedValue = empty($moduleResources) ?
111
+ strtolower($this->_moduleName) . '_setup' :
112
+ current($moduleResources);
113
+ }
114
+
115
+ $this->setActualValue($moduleResources);
116
+
117
+ return in_array($this->_expectedValue, $this->_actualValue);
118
+ }
119
+
120
+ /**
121
+ * Represents constraint for definition of setup resources
122
+ *
123
+ * @return string
124
+ */
125
+ public function textSetupDefined()
126
+ {
127
+ return sprintf('contains resource definition for %s module with %s name',
128
+ $this->_moduleName, $this->_expectedValue);
129
+ }
130
+
131
+ /**
132
+ * Set actual value for comparison from module sql/data directories
133
+ *
134
+ * @param string $type
135
+ * @return EcomDev_PHPUnit_Constraint_Config_Resource
136
+ */
137
+ protected function setActualValueFromResourceDirectories($type = 'sql')
138
+ {
139
+ if (!is_dir($this->_moduleDirectory . DIRECTORY_SEPARATOR . $type)) {
140
+ $this->setActualValue(array());
141
+ return $this;
142
+ }
143
+
144
+ $dirIterator = new DirectoryIterator($this->_moduleDirectory . DIRECTORY_SEPARATOR . $type);
145
+
146
+ $resourceDirectories = array();
147
+
148
+ foreach ($dirIterator as $entry) {
149
+ /* @var $entry DirectoryIterator */
150
+ if ($entry->isDir() && !$entry->isDot()) {
151
+ $resourceDirectories[] = $entry->getBasename();
152
+ }
153
+ }
154
+
155
+ $this->setActualValue($resourceDirectories);
156
+
157
+ return $this;
158
+ }
159
+
160
+ /**
161
+ * Checks existence and definition of expected resource name schema directory
162
+ *
163
+ * @param Varien_Simplexml_Element $other
164
+ */
165
+ protected function evaluateSetupSchemeExists($other)
166
+ {
167
+ $moduleResources = $this->getModuleSetupResources($other);
168
+
169
+ if ($this->_expectedValue === null) {
170
+ $this->_expectedValue = empty($moduleResources) ?
171
+ strtolower($this->_moduleName) . '_setup' :
172
+ current($moduleResources);
173
+ }
174
+
175
+ $this->setActualValueFromResourceDirectories('sql');
176
+
177
+ return in_array($this->_expectedValue, $moduleResources)
178
+ && in_array($this->_expectedValue, $this->_actualValue);
179
+ }
180
+
181
+ /**
182
+ * Represents constraint for definition of setup resources
183
+ *
184
+ * @return string
185
+ */
186
+ public function textSetupSchemeExists()
187
+ {
188
+ return sprintf(' schema directory is created for %s module with %s name',
189
+ $this->_moduleName, $this->_expectedValue);
190
+ }
191
+
192
+ /**
193
+ * Checks existence and definition of expected resource name data directory
194
+ *
195
+ * @param Varien_Simplexml_Element $other
196
+ */
197
+ protected function evaluateSetupDataExists($other)
198
+ {
199
+ $moduleResources = $this->getModuleSetupResources($other);
200
+
201
+ if ($this->_expectedValue === null) {
202
+ $this->_expectedValue = empty($moduleResources) ?
203
+ strtolower($this->_moduleName) . '_setup' :
204
+ current($moduleResources);
205
+ }
206
+
207
+ $this->setActualValueFromResourceDirectories('data');
208
+
209
+ return in_array($this->_expectedValue, $moduleResources)
210
+ && in_array($this->_expectedValue, $this->_actualValue);
211
+ }
212
+
213
+ /**
214
+ * Represents constraint for definition of setup resources
215
+ *
216
+ * @return string
217
+ */
218
+ public function textSetupDataExists()
219
+ {
220
+ return sprintf(' data directory is created for %s module with %s name', $this->_moduleName, $this->_expectedValue);
221
+ }
222
+
223
+ /**
224
+ * Custom failure description for showing config related errors
225
+ * (non-PHPdoc)
226
+ * @see PHPUnit_Framework_Constraint::customFailureDescription()
227
+ */
228
+ protected function customFailureDescription($other, $description, $not)
229
+ {
230
+ return sprintf(
231
+ 'Failed asserting that setup resources %s.',
232
+ $this->toString()
233
+ );
234
+ }
235
+ }
236
+
lib/EcomDev/PHPUnit/Constraint/Config/Resource/Script.php ADDED
@@ -0,0 +1,365 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PHP Unit test suite for Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ *
12
+ * @category EcomDev
13
+ * @package EcomDev_PHPUnit
14
+ * @copyright Copyright (c) 2012 EcomDev BV (http://www.ecomdev.org)
15
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
+ * @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
17
+ */
18
+
19
+ /**
20
+ * Setup resources configuration constraint
21
+ *
22
+ */
23
+ class EcomDev_PHPUnit_Constraint_Config_Resource_Script
24
+ extends EcomDev_PHPUnit_Constraint_Config_Abstract
25
+ {
26
+ const XML_PATH_RESOURCES_NODE = 'global/resources';
27
+
28
+
29
+ const TYPE_SCRIPT_SCHEME = 'script_scheme';
30
+ const TYPE_SCRIPT_DATA = 'script_data';
31
+
32
+ const FILE_INSTALL_SCHEME = '/^(mysql4-install|install)-([\\d\\.]+)$/';
33
+ const FILE_UPGRADE_SCHEME = '/^(mysql4-upgrade|upgrade)-([\\d\\.]+)-([\\d\\.]+)$/';
34
+
35
+ const FILE_INSTALL_DATA = '/^(mysql4-data-install|data-install)-([\\d\\.]+)$/';
36
+ const FILE_UPGRADE_DATA = '/^(mysql4-data-upgrade|data-upgrade)-([\\d\\.]+)-([\\d\\.]+)$/';
37
+
38
+
39
+ /**
40
+ * Name of the module for constraint
41
+ *
42
+ * @var string
43
+ */
44
+ protected $_moduleName = null;
45
+
46
+ /**
47
+ * The module directory for constraint
48
+ *
49
+ * @var string
50
+ */
51
+ protected $_moduleDirectory = null;
52
+
53
+ /**
54
+ * Resource name where to look for scripts
55
+ *
56
+ * @var string
57
+ */
58
+ protected $_resourceName = null;
59
+
60
+ /**
61
+ * Contraint for evaluation of module config node
62
+ *
63
+ * @param string $nodePath
64
+ * @param string $type
65
+ * @param string $moduleDirectory
66
+ * @param mixed $expectedValue
67
+ */
68
+ public function __construct($moduleName, $type, $moduleDirectory, $resourceName = null, $expectedVersions = null)
69
+ {
70
+ $this->_typesWithDiff[] = self::TYPE_SCRIPT_SCHEME;
71
+ $this->_typesWithDiff[] = self::TYPE_SCRIPT_DATA;
72
+
73
+ parent::__construct(
74
+ self::XML_PATH_RESOURCES_NODE,
75
+ $type,
76
+ $expectedVersions
77
+ );
78
+
79
+ $this->_moduleName = $moduleName;
80
+ $this->_moduleDirectory = $moduleDirectory;
81
+ $this->_resourceName = $resourceName;
82
+
83
+ if (!is_dir($moduleDirectory)) {
84
+ throw PHPUnit_Util_InvalidArgumentHelper::factory(3, 'real directory', $moduleDirectory);
85
+ }
86
+ }
87
+
88
+ /**
89
+ * Returns setup resource for module setup scripts
90
+ *
91
+ * @param Varien_Simplexml_Element $xml
92
+ * @return string
93
+ */
94
+ protected function getResourceName(Varien_Simplexml_Element $xml)
95
+ {
96
+ foreach ($xml->children() as $resourceNode) {
97
+ if (isset($resourceNode->setup->module)
98
+ && (string)$resourceNode->setup->module === $this->_moduleName) {
99
+ return $resourceNode->getName();
100
+ }
101
+ }
102
+
103
+ return false;
104
+ }
105
+
106
+ /**
107
+ * Returns list of scripts that are presented in resource directory
108
+ *
109
+ * @param string|array $directory
110
+ * @param string $fromVersion
111
+ */
112
+ protected function parseVersions($directory)
113
+ {
114
+ if (is_array($directory)) {
115
+ // For multiple directories merge result together
116
+ $result = array();
117
+
118
+ foreach ($directory as $entry) {
119
+ $result = array_merge_recursive($result, $this->parseVersions($entry));
120
+ }
121
+
122
+ // Sort install scripts by version
123
+ usort($result['install'], array($this, 'compareVersions'));
124
+ // Sort upgrade scripts by version
125
+ usort($result['upgrade'], array($this, 'compareVersions'));
126
+ return $result;
127
+ }
128
+
129
+
130
+ $versions = array(
131
+ 'scheme' => array(
132
+ 'install' => array(),
133
+ 'upgrade' => array()
134
+ ),
135
+ 'data' => array(
136
+ 'install' => array(),
137
+ 'upgrade' => array()
138
+ )
139
+ );
140
+
141
+
142
+ if (!is_dir($directory)) {
143
+ return $versions;
144
+ }
145
+
146
+ $directoryIterator = new DirectoryIterator($directory);
147
+
148
+ $matchMap = array(
149
+ self::FILE_INSTALL_SCHEME => array('scheme', 'install'),
150
+ self::FILE_UPGRADE_SCHEME => array('scheme', 'upgrade'),
151
+ self::FILE_INSTALL_DATA => array('data', 'install'),
152
+ self::FILE_UPGRADE_DATA => array('data', 'upgrade')
153
+ );
154
+
155
+ foreach ($directoryIterator as $entry) {
156
+ /* @var $entry SplFileInfo */
157
+ // We do not support scheme upgrade scripts with .sql
158
+ // file extension, since it is not the best practice.
159
+ if ($entry->isFile() && substr($entry->getBasename(), -4) === '.php') {
160
+ foreach ($matchMap as $pattern => $target) {
161
+ // Fulfill versions array
162
+ if (preg_match($pattern, $entry->getBasename('.php'), $match)) {
163
+ $versions[$target[0]][$target[1]][] = array(
164
+ 'filename' => $entry->getBasename(),
165
+ 'prefix' => $match[1],
166
+ 'from' => $match[2],
167
+ 'to' => isset($match[3]) ? $match[3] : null
168
+ );
169
+ }
170
+ }
171
+ }
172
+ }
173
+
174
+ return $versions;
175
+ }
176
+
177
+ /**
178
+ * Compares two versions array
179
+ *
180
+ * @param array $first
181
+ * @param array $next
182
+ * @return int
183
+ */
184
+ protected function compareVersions($first, $next)
185
+ {
186
+ $result = version_compare($first['from'], $next['from']);
187
+
188
+ if ($result === 0) {
189
+ /* if file with type specified, it has more priority */
190
+ $result = (strpos($first['prefix'], 'mysql4') ? 1 : -1);
191
+ }
192
+
193
+ return $result;
194
+ }
195
+
196
+ /**
197
+ * Returns list of version scripts including expected and actual information
198
+ *
199
+ * @param array $versions
200
+ * @param string $from
201
+ * @param string $to
202
+ * @param string $scriptPrefix
203
+ * @return array with keys expected and actual
204
+ */
205
+ protected function getVersionScriptsDiff($versions, $from = null, $to = null, $scriptPrefix = '')
206
+ {
207
+ if ($from === null && end($versions['install'])) {
208
+ $version = end($versions['install']);
209
+ $from = $version['from'];
210
+ reset($versions['install']);
211
+ } elseif ($from === null && reset($versions['upgrade'])) {
212
+ $version = reset($versions['upgrade']);
213
+ $from = $version['from'];
214
+ }
215
+
216
+ if ($to === null && end($versions['upgrade'])) {
217
+ $version = end($versions['upgrade']);
218
+ $to = $version['to'];
219
+ } elseif ($to === null) {
220
+ $to = $from;
221
+ }
222
+
223
+ $actualVersions = array();
224
+ $expectedVersions = array();
225
+
226
+ $latestVersionFound = null;
227
+ if (empty($versions['install']) && $from !== null) {
228
+ $expectedVersions[] = sprintf('install-%s.php', $scriptPrefix, $from);
229
+ $latestVersionFound = $from;
230
+ } elseif ($from !== null) {
231
+ foreach ($versions['install'] as $index=>$version) {
232
+ if (version_compare($version['from'], $from) <= 0
233
+ && (!isset($versions['install'][$index+1]['from'])
234
+ || version_compare($versions['install'][$index+1]['from'], $from) > 0)) {
235
+ $latestVersionFound = $version['from'];
236
+ $actualVersions[] = $version['filename'];
237
+ $expectedVersions[] = $version['filename'];
238
+ break;
239
+ }
240
+ }
241
+ } elseif (!empty($versions['install'])) {
242
+ $version = current($versions['install']);
243
+ $latestVersionFound = $version['from'];
244
+ $actualVersions[] = $version['filename'];
245
+ $expectedVersions[] = $version['filename'];
246
+ } else {
247
+ $expectedVersions[] = sprintf('%sinstall-%s.php', $scriptPrefix, $to);
248
+ $latestVersionFound = $to;
249
+ }
250
+
251
+ foreach ($versions['upgrade'] as $version) {
252
+ $fromCompare = version_compare($version['from'], $latestVersionFound);
253
+ if ($fromCompare < 0) {
254
+ continue;
255
+ }
256
+
257
+ if ($fromCompare > 0) {
258
+ $expectedVersions[] = sprintf('%supgrade-%s-%s.php', $scriptPrefix, $latestVersionFound, $version['from']);
259
+ }
260
+
261
+ $actualVersions[] = $version['filename'];
262
+ $expectedVersions[] = $version['filename'];
263
+ $latestVersionFound = $version['to'];
264
+ }
265
+
266
+ if ($to !== null && version_compare($latestVersionFound, $to) === -1) {
267
+ $expectedVersions[] = sprintf('%supgrade-%s-%s.php', $scriptPrefix, $latestVersionFound, $to);
268
+ } elseif ($to !== null && version_compare($latestVersionFound, $to) === 1 && $expectedVersions) {
269
+ array_pop($expectedVersions);
270
+ }
271
+
272
+ return array(
273
+ 'actual' => $actualVersions,
274
+ 'expected' => $expectedVersions
275
+ );
276
+ }
277
+
278
+ /**
279
+ * Checks structure of the schme setup scripts for a module
280
+ *
281
+ * @param Varien_Simplexml_Element $other
282
+ * @return boolean
283
+ */
284
+ protected function evaluateScriptScheme($other)
285
+ {
286
+ if ($this->_resourceName === null) {
287
+ $this->_resourceName = $this->getResourceName($other);
288
+ }
289
+
290
+ $from = isset($this->_expectedValue[0]) ? $this->_expectedValue[0] : null;
291
+ $to = isset($this->_expectedValue[1]) ? $this->_expectedValue[1] : null;
292
+
293
+ $versions = $this->parseVersions(
294
+ $this->_moduleDirectory . DIRECTORY_SEPARATOR . 'sql' . DIRECTORY_SEPARATOR . $this->_resourceName
295
+ );
296
+
297
+ $diff = $this->getVersionScriptsDiff($versions['scheme'], $from, $to);
298
+
299
+ $this->setActualValue($diff['actual']);
300
+ $this->_expectedValue = $diff['expected'];
301
+ return $this->_actualValue == $this->_expectedValue;
302
+ }
303
+
304
+ /**
305
+ * Text represetnation of scheme setup scripts versions chain
306
+ *
307
+ * @return
308
+ */
309
+ public function textScriptScheme()
310
+ {
311
+ return 'scheme setup scripts are created in correct version chain order';
312
+ }
313
+
314
+ /**
315
+ * Checks structure of the data setup scripts for a module
316
+ *
317
+ * @param Varien_Simplexml_Element $other
318
+ * @return boolean
319
+ */
320
+ protected function evaluateScriptData($other)
321
+ {
322
+ if ($this->_resourceName === null) {
323
+ $this->_resourceName = $this->getResourceName($other);
324
+ }
325
+
326
+ $from = isset($this->_expectedValue[0]) ? $this->_expectedValue[0] : null;
327
+ $to = isset($this->_expectedValue[1]) ? $this->_expectedValue[1] : null;
328
+
329
+ $versions = $this->parseVersions(
330
+ array(
331
+ $this->_moduleDirectory . DIRECTORY_SEPARATOR . 'data' . DIRECTORY_SEPARATOR . $this->_resourceName,
332
+ $this->_moduleDirectory . DIRECTORY_SEPARATOR . 'sql' . DIRECTORY_SEPARATOR . $this->_resourceName
333
+ )
334
+ );
335
+
336
+ $diff = $this->getVersionScriptsDiff($versions['data'], $from, $to);
337
+
338
+ $this->setActualValue($diff['actual']);
339
+ $this->_expectedValue = $diff['expected'];
340
+ return $this->_actualValue == $this->_expectedValue;
341
+ }
342
+
343
+ /**
344
+ * Text represetnation of scheme setup scripts versions chain
345
+ *
346
+ * @return
347
+ */
348
+ public function textScriptData()
349
+ {
350
+ return 'data setup scripts are created in correct version chain order';
351
+ }
352
+
353
+ /**
354
+ * Custom failure description for showing config related errors
355
+ * (non-PHPdoc)
356
+ * @see PHPUnit_Framework_Constraint::customFailureDescription()
357
+ */
358
+ protected function customFailureDescription($other, $description, $not)
359
+ {
360
+ return sprintf(
361
+ 'Failed asserting that setup resources %s.',
362
+ $this->toString()
363
+ );
364
+ }
365
+ }
lib/EcomDev/PHPUnit/Constraint/Config/TableAlias.php ADDED
@@ -0,0 +1,105 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Table alias constraint
5
+ *
6
+ */
7
+ class EcomDev_PHPUnit_Constraint_Config_TableAlias
8
+ extends EcomDev_PHPUnit_Constraint_Config_Abstract
9
+ {
10
+ const XML_PATH_MODELS = 'global/models';
11
+
12
+ const TYPE_TABLE_ALIAS = 'table_alias';
13
+
14
+ /**
15
+ * Table alias name, e.g. the name of the table within resource
16
+ *
17
+ * @var string
18
+ */
19
+ protected $_tableAliasName = null;
20
+
21
+ /**
22
+ * Table alias prefix,
23
+ * e.g. the prefix for tables of a particular resource model
24
+ *
25
+ * @var string
26
+ */
27
+ protected $_tableAliasPrefix = null;
28
+
29
+ /**
30
+ * Constraint for evaluation of table alias
31
+ *
32
+ * @param string $tableAlias
33
+ * @param string $expectedTableName
34
+ * @param string $type
35
+ */
36
+ public function __construct($tableAlias, $expectedTableName, $type = self::TYPE_TABLE_ALIAS)
37
+ {
38
+ if (!strpos($tableAlias, '/')) {
39
+ throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'table alias', $tableAlias);
40
+ }
41
+
42
+ list($this->_tableAliasPrefix, $this->_tableAliasName) = explode('/', $tableAlias, 2);
43
+
44
+ $this->_expectedValueValidation += array(
45
+ self::TYPE_TABLE_ALIAS => array(true, 'is_string', 'string')
46
+ );
47
+
48
+ $this->_typesWithDiff[] = self::TYPE_TABLE_ALIAS;
49
+
50
+ parent::__construct(self::XML_PATH_MODELS, $type, $expectedTableName);
51
+ }
52
+
53
+ /**
54
+ * Evaluates table alias is mapped to expected table name
55
+ *
56
+ * @param Varien_Simplexml_Element $other
57
+ * @return boolean
58
+ */
59
+ protected function evaluateTableAlias($other)
60
+ {
61
+ if (!isset($other->{$this->_tableAliasPrefix})) {
62
+ $this->setActualValue(false);
63
+ return false;
64
+ }
65
+
66
+ $modelNode = $other->{$this->_tableAliasPrefix};
67
+
68
+ if (!isset($modelNode->entities) && isset($other->{(string)$modelNode->resourceModel})) {
69
+ $modelNode = $other->{(string)$modelNode->resourceModel};
70
+ }
71
+
72
+ if (isset($modelNode->entities->{$this->_tableAliasName}->table)) {
73
+ $tableName = (string)$modelNode->entities->{$this->_tableAliasName}->table;
74
+ } else {
75
+ $tableName = false;
76
+ }
77
+
78
+ $this->setActualValue($tableName);
79
+ return $this->_actualValue === $this->_expectedValue;
80
+ }
81
+
82
+ /**
83
+ * Text representation of table alias constaint
84
+ *
85
+ * @return string
86
+ */
87
+ protected function textTableAlias()
88
+ {
89
+ return 'is mapped to table name';
90
+ }
91
+
92
+ /**
93
+ * Custom failure description for showing config related errors
94
+ * (non-PHPdoc)
95
+ * @see PHPUnit_Framework_Constraint::customFailureDescription()
96
+ */
97
+ protected function customFailureDescription($other, $description, $not)
98
+ {
99
+ return sprintf(
100
+ 'Failed asserting that table alias "%s/%s" %s.',
101
+ $this->_tableAliasPrefix, $this->_tableAliasName,
102
+ $this->toString()
103
+ );
104
+ }
105
+ }
lib/EcomDev/PHPUnit/Constraint/Controller/Request.php ADDED
@@ -0,0 +1,308 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PHP Unit test suite for Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ *
12
+ * @category EcomDev
13
+ * @package EcomDev_PHPUnit
14
+ * @copyright Copyright (c) 2011 Ecommerce Developers (http://www.ecomdev.org)
15
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
+ * @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
17
+ */
18
+
19
+ /**
20
+ * Constraint for controller request assetions
21
+ *
22
+ */
23
+ class EcomDev_PHPUnit_Constraint_Controller_Request extends EcomDev_PHPUnit_Constraint_Abstract
24
+ {
25
+ const TYPE_ROUTE = 'route';
26
+ const TYPE_ROUTE_NAME = 'route_name';
27
+ const TYPE_CONTROLLER_NAME = 'controller_name';
28
+ const TYPE_CONTROLLER_MODULE = 'controller_module';
29
+ const TYPE_ACTION_NAME = 'action_name';
30
+ const TYPE_DISPATCHED = 'dispatched';
31
+ const TYPE_FORWARDED = 'forwarded';
32
+ const TYPE_BEFORE_FORWARD_ROUTE = 'before_forward_route';
33
+
34
+ /**
35
+ * Constraint for controller request assetions
36
+ *
37
+ *
38
+ * @param string $type
39
+ * @param string|null $expectedValue
40
+ */
41
+ public function __construct($type, $expectedValue = null)
42
+ {
43
+ $this->_expectedValueValidation += array(
44
+ self::TYPE_ROUTE => array(true, 'is_string', 'string'),
45
+ self::TYPE_ROUTE_NAME => array(true, 'is_string', 'string'),
46
+ self::TYPE_CONTROLLER_NAME => array(true, 'is_string', 'string'),
47
+ self::TYPE_CONTROLLER_MODULE => array(true, 'is_string', 'string'),
48
+ self::TYPE_ACTION_NAME => array(true, 'is_string', 'string'),
49
+ self::TYPE_BEFORE_FORWARD_ROUTE => array(true, 'is_string', 'string')
50
+ );
51
+
52
+ $this->_typesWithDiff[] = self::TYPE_ROUTE;
53
+ $this->_typesWithDiff[] = self::TYPE_ROUTE_NAME;
54
+ $this->_typesWithDiff[] = self::TYPE_CONTROLLER_NAME;
55
+ $this->_typesWithDiff[] = self::TYPE_CONTROLLER_MODULE;
56
+ $this->_typesWithDiff[] = self::TYPE_ACTION_NAME;
57
+ $this->_typesWithDiff[] = self::TYPE_BEFORE_FORWARD_ROUTE;
58
+
59
+ parent::__construct($type, $expectedValue);
60
+ }
61
+
62
+ /**
63
+ * Parses route to params
64
+ *
65
+ * @param string $route
66
+ * @return array
67
+ */
68
+ protected function parseRoute($route)
69
+ {
70
+ $routeParts = explode('/', $route, 3);
71
+ $routePartsCount = count($routeParts);
72
+ if ($routePartsCount < 3) {
73
+ array_pad($routeParts, 3-$routePartsCount, null);
74
+ }
75
+
76
+ $params = array();
77
+
78
+ if ($routeParts[0] !== '*') {
79
+ $params['route_name'] = !empty($routeParts[0]) ? $routeParts[0] : 'index';
80
+ }
81
+
82
+ if ($routeParts[1] !== '*') {
83
+ $params['controller_name'] = !empty($routeParts[1]) ? $routeParts[1] : 'index';
84
+ }
85
+
86
+ if ($routeParts[2] !== '*') {
87
+ $params['action_name'] = !empty($routeParts[2]) ? $routeParts[2] : 'index';
88
+ }
89
+ return $params;
90
+ }
91
+
92
+ /**
93
+ * Evaluates that current controller route is equal to expected
94
+ *
95
+ * @param EcomDev_PHPUnit_Controller_Request_Interface $other
96
+ * @return boolean
97
+ */
98
+ protected function evaluateRoute($other)
99
+ {
100
+ $params = $this->parseRoute($this->_expectedValue);
101
+ $this->setActualValue(
102
+ $other->getRouteName() . '/' . $other->getControllerName()
103
+ . '/' . $other->getActionName()
104
+ );
105
+ foreach ($params as $propertyName => $expectedValue) {
106
+ $methodName = 'get'.str_replace(' ', '',
107
+ ucwords(strtr($propertyName, '_', ' '))
108
+ );
109
+ if ($other->$methodName() !== $expectedValue) {
110
+ return false;
111
+ }
112
+ }
113
+
114
+ return true;
115
+ }
116
+
117
+ /**
118
+ * Text reperesentation of route path assertion
119
+ *
120
+ * @return string
121
+ */
122
+ protected function textRoute()
123
+ {
124
+ return 'route matches expected one';
125
+ }
126
+
127
+ /**
128
+ * Evaluates that before forwarding controller route is equal to expected
129
+ *
130
+ * @param EcomDev_PHPUnit_Controller_Request_Interface $other
131
+ * @return boolean
132
+ */
133
+ protected function evaluateBeforeForwardRoute($other)
134
+ {
135
+ if (!$other->getBeforeForwardInfo()) {
136
+ $this->setActualValue(false);
137
+ return false;
138
+ }
139
+
140
+ $params = $this->parseRoute($this->_expectedValue);
141
+ $this->setActualValue(
142
+ $other->getBeforeForwardInfo('route_name') . '/'
143
+ . $other->getBeforeForwardInfo('controller_name') . '/'
144
+ . $other->getBeforeForwardInfo('action_name')
145
+ );
146
+
147
+ foreach ($params as $propertyName => $expectedValue) {
148
+ if ($other->getBeforeForwardInfo($propertyName) !== $expectedValue) {
149
+ return false;
150
+ }
151
+ }
152
+
153
+ return true;
154
+ }
155
+
156
+ /**
157
+ * Text reperesentation of route path assertion
158
+ *
159
+ * @return string
160
+ */
161
+ protected function textBeforeForwardRoute()
162
+ {
163
+ return 'route before forwarding matches expected one';
164
+ }
165
+
166
+ /**
167
+ * Evaluates that request was forwarded
168
+ *
169
+ * @param EcomDev_PHPUnit_Controller_Request_Interface $other
170
+ * @return boolean
171
+ */
172
+ protected function evaluateForwarded($other)
173
+ {
174
+ return (bool)$other->getBeforeForwardInfo();
175
+ }
176
+
177
+ /**
178
+ * Text reperesentation of was forwaded request assertion
179
+ *
180
+ * @return string
181
+ */
182
+ protected function textForwarded()
183
+ {
184
+ return 'is forwarded';
185
+ }
186
+
187
+ /**
188
+ * Evaluates that request was forwarded
189
+ *
190
+ * @param EcomDev_PHPUnit_Controller_Request_Interface $other
191
+ * @return boolean
192
+ */
193
+ protected function evaluateDispatched($other)
194
+ {
195
+ return $other->isDispatched();
196
+ }
197
+
198
+ /**
199
+ * Text reperesentation of was forwaded request assertion
200
+ *
201
+ * @return string
202
+ */
203
+ protected function textDispatched()
204
+ {
205
+ return 'is dispatched';
206
+ }
207
+
208
+ /**
209
+ * Evaluates that request route name is equal to expected
210
+ *
211
+ * @param EcomDev_PHPUnit_Controller_Request_Interface $other
212
+ * @return boolean
213
+ */
214
+ protected function evaluateRouteName($other)
215
+ {
216
+ $this->setActualValue($other->getRouteName());
217
+ return $this->_actualValue === $this->_expectedValue;
218
+ }
219
+
220
+ /**
221
+ * Text reperesentation of route name assertion
222
+ *
223
+ * @return string
224
+ */
225
+ protected function textRouteName()
226
+ {
227
+ return 'route name is equal to expected';
228
+ }
229
+
230
+ /**
231
+ * Evaluates that request controller name is equal to expected
232
+ *
233
+ * @param EcomDev_PHPUnit_Controller_Request_Interface $other
234
+ * @return boolean
235
+ */
236
+ protected function evaluateControllerName($other)
237
+ {
238
+ $this->setActualValue($other->getControllerName());
239
+ return $this->_actualValue === $this->_expectedValue;
240
+ }
241
+
242
+ /**
243
+ * Text reperesentation of controller name assertion
244
+ *
245
+ * @return string
246
+ */
247
+ protected function textControllerName()
248
+ {
249
+ return 'controller name is equal to expected';
250
+ }
251
+
252
+ /**
253
+ * Evaluates that request controller module is equal to expected
254
+ *
255
+ * @param EcomDev_PHPUnit_Controller_Request_Interface $other
256
+ * @return boolean
257
+ */
258
+ protected function evaluateControllerModule($other)
259
+ {
260
+ $this->setActualValue($other->getControllerModule());
261
+ return $this->_actualValue === $this->_expectedValue;
262
+ }
263
+
264
+ /**
265
+ * Text reperesentation of controller module assertion
266
+ *
267
+ * @return string
268
+ */
269
+ protected function textControllerModule()
270
+ {
271
+ return 'controller module is equal to expected';
272
+ }
273
+
274
+ /**
275
+ * Evaluates that request action name is equal to expected
276
+ *
277
+ * @param EcomDev_PHPUnit_Controller_Request_Interface $other
278
+ * @return boolean
279
+ */
280
+ protected function evaluateActionName($other)
281
+ {
282
+ $this->setActualValue($other->getActionName());
283
+ return $this->_actualValue === $this->_expectedValue;
284
+ }
285
+
286
+ /**
287
+ * Text reperesentation of action name assertion
288
+ *
289
+ * @return string
290
+ */
291
+ protected function textActionName()
292
+ {
293
+ return 'action name is equal to expected';
294
+ }
295
+
296
+ /**
297
+ * Custom failure description for showing request related errors
298
+ * (non-PHPdoc)
299
+ * @see PHPUnit_Framework_Constraint::customFailureDescription()
300
+ */
301
+ protected function customFailureDescription($other, $description, $not)
302
+ {
303
+ return sprintf(
304
+ 'Failed asserting that request %s.',
305
+ $this->toString()
306
+ );
307
+ }
308
+ }
lib/EcomDev/PHPUnit/Constraint/Controller/Response/Abstract.php ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PHP Unit test suite for Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ *
12
+ * @category EcomDev
13
+ * @package EcomDev_PHPUnit
14
+ * @copyright Copyright (c) 2011 Ecommerce Developers (http://www.ecomdev.org)
15
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
+ * @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
17
+ */
18
+
19
+ /**
20
+ * Abstract constraint for controller response assetions
21
+ *
22
+ */
23
+ abstract class EcomDev_PHPUnit_Constraint_Controller_Response_Abstract
24
+ extends EcomDev_PHPUnit_Constraint_Abstract
25
+ {
26
+ /**
27
+ * Custom failure description for showing response related errors
28
+ * (non-PHPdoc)
29
+ * @see PHPUnit_Framework_Constraint::customFailureDescription()
30
+ */
31
+ protected function customFailureDescription($other, $description, $not)
32
+ {
33
+ return sprintf(
34
+ 'Failed asserting that request %s.',
35
+ $this->toString()
36
+ );
37
+ }
38
+ }
lib/EcomDev/PHPUnit/Constraint/Controller/Response/Body.php ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PHP Unit test suite for Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ *
12
+ * @category EcomDev
13
+ * @package EcomDev_PHPUnit
14
+ * @copyright Copyright (c) 2011 Ecommerce Developers (http://www.ecomdev.org)
15
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
+ * @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
17
+ */
18
+
19
+ /**
20
+ * Constraint for controller response body assertions
21
+ *
22
+ */
23
+ class EcomDev_PHPUnit_Constraint_Controller_Response_Body
24
+ extends EcomDev_PHPUnit_Constraint_Controller_Response_Abstract
25
+ {
26
+ const TYPE_CONSTRAINT = 'constraint';
27
+
28
+ /**
29
+ * Constraint for controller response body assertions
30
+ *
31
+ * @param PHPUnit_Framework_Constraint $constraint
32
+ * @param string $type
33
+ */
34
+ public function __construct(PHPUnit_Framework_Constraint $constraint = null, $type = self::TYPE_CONSTRAINT)
35
+ {
36
+ $this->_expectedValueValidation += array(
37
+ self::TYPE_CONSTRAINT => array(true, null, 'PHPUnit_Framework_Constraint')
38
+ );
39
+
40
+ parent::__construct($type, $constraint);
41
+ }
42
+
43
+ /**
44
+ * Evaluates controller response body is evaluated by constraint
45
+ *
46
+ *
47
+ * @param EcomDev_PHPUnit_Controller_Response_Interface $other
48
+ */
49
+ protected function evaluateConstraint($other)
50
+ {
51
+ $this->setActualValue($other->getOutputBody());
52
+ return $this->_expectedValue->evaluate($this->_actualValue);
53
+ }
54
+
55
+ /**
56
+ * Text representation of response body is evaluated by constraint assertion
57
+ *
58
+ * @return string
59
+ */
60
+ protected function textConstraint()
61
+ {
62
+ return sprintf('body %s', $this->_expectedValue->toString());
63
+ }
64
+ }
lib/EcomDev/PHPUnit/Constraint/Controller/Response/Header.php ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PHP Unit test suite for Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ *
12
+ * @category EcomDev
13
+ * @package EcomDev_PHPUnit
14
+ * @copyright Copyright (c) 2011 Ecommerce Developers (http://www.ecomdev.org)
15
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
+ * @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
17
+ */
18
+
19
+ /**
20
+ * Constraint for controller response header assertions
21
+ *
22
+ */
23
+ class EcomDev_PHPUnit_Constraint_Controller_Response_Header
24
+ extends EcomDev_PHPUnit_Constraint_Controller_Response_Abstract
25
+ {
26
+ const TYPE_CONSTRAINT = 'constraint';
27
+ const TYPE_SENT = 'sent';
28
+
29
+ /**
30
+ * The name of the header that will be asserted
31
+ *
32
+ * @var string
33
+ */
34
+ protected $_headerName = null;
35
+
36
+ /**
37
+ * Response header assertion
38
+ *
39
+ * @param string $headerName
40
+ * @param string $type
41
+ * @param PHPUnit_Framework_Constraint $constraint
42
+ */
43
+ public function __construct($headerName, $type, PHPUnit_Framework_Constraint $constraint = null)
44
+ {
45
+ if (empty($headerName) || !is_string($headerName)) {
46
+ throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string', $headerName);
47
+ }
48
+
49
+ $this->_expectedValueValidation += array(
50
+ self::TYPE_CONSTRAINT => array(true, null, 'PHPUnit_Framework_Constraint')
51
+ );
52
+
53
+ parent::__construct($type, $constraint);
54
+ $this->_headerName = $headerName;
55
+ }
56
+
57
+ /**
58
+ * Evaluates controller response header is sent
59
+ *
60
+ *
61
+ * @param EcomDev_PHPUnit_Controller_Response_Interface $other
62
+ */
63
+ protected function evaluateSent($other)
64
+ {
65
+ $this->setActualValue($other->getSentHeaders());
66
+ return $other->getSentHeader($this->_headerName) !== false;
67
+ }
68
+
69
+ /**
70
+ * Text representation of header is sent assertion
71
+ *
72
+ * @return string
73
+ */
74
+ protected function textSent()
75
+ {
76
+ return sprintf('header "%s" is sent', $this->_headerName);
77
+ }
78
+
79
+ /**
80
+ * Evaluates controller response header is evaluated by constraint
81
+ *
82
+ *
83
+ * @param EcomDev_PHPUnit_Controller_Response_Interface $other
84
+ */
85
+ protected function evaluateConstraint($other)
86
+ {
87
+ $this->setActualValue($other->getSentHeader($this->_headerName));
88
+ return $this->_expectedValue->evaluate($this->_actualValue);
89
+ }
90
+
91
+ /**
92
+ * Text representation of header is evaluated by constraint assertion
93
+ *
94
+ * @return string
95
+ */
96
+ protected function textConstraint()
97
+ {
98
+ return sprintf('header "%s" value %s', $this->_headerName, $this->_expectedValue->toString());
99
+ }
100
+ }
lib/EcomDev/PHPUnit/Constraint/Exception.php ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PHP Unit test suite for Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ *
12
+ * @category EcomDev
13
+ * @package EcomDev_PHPUnit
14
+ * @copyright Copyright (c) 2011 Ecommerce Developers (http://www.ecomdev.org)
15
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
+ * @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
17
+ */
18
+
19
+ /**
20
+ * Exception for failed constraints execution
21
+ *
22
+ *
23
+ */
24
+ class EcomDev_PHPUnit_Constraint_Exception extends PHPUnit_Framework_ExpectationFailedException
25
+ {
26
+ protected $diff = null;
27
+
28
+ public function __construct($description, $diff = '', $message = '')
29
+ {
30
+ if (!is_scalar($diff)) {
31
+ $diff = print_r($diff, true);
32
+ }
33
+
34
+ $this->diff = $diff;
35
+ parent::__construct($description, null, $message);
36
+ }
37
+
38
+ public function toString()
39
+ {
40
+ $result = parent::toString();
41
+
42
+ if (!empty($this->diff)) {
43
+ $result .= "\n" . $this->diff;
44
+ }
45
+
46
+ return $result;
47
+ }
48
+ }
lib/EcomDev/PHPUnit/Constraint/Json.php ADDED
@@ -0,0 +1,174 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PHP Unit test suite for Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ *
12
+ * @category EcomDev
13
+ * @package EcomDev_PHPUnit
14
+ * @copyright Copyright (c) 2011 Ecommerce Developers (http://www.ecomdev.org)
15
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
+ * @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
17
+ */
18
+
19
+ /**
20
+ * Constraint for checking JSON values
21
+ *
22
+ */
23
+ class EcomDev_PHPUnit_Constraint_Json extends EcomDev_PHPUnit_Constraint_Abstract
24
+ {
25
+ const TYPE_VALID = 'valid';
26
+ const TYPE_MATCH = 'match';
27
+
28
+ const MATCH_AND = 'and';
29
+ const MATCH_OR = 'or';
30
+ const MATCH_EXACT = 'exact';
31
+
32
+ /**
33
+ * Match type for evaluation
34
+ *
35
+ * @var string
36
+ */
37
+ protected $_matchType = self::MATCH_AND;
38
+
39
+ /**
40
+ * Constraint for checking JSON values
41
+ *
42
+ *
43
+ * @param string $type
44
+ * @param array $expectedValue expected json in array format
45
+ * @param string $matchType
46
+ */
47
+ public function __construct($type, $expectedValue = null, $matchType = self::MATCH_AND)
48
+ {
49
+ if ($expectedValue !== null && (empty($matchType) || !is_string($matchType))) {
50
+ PHPUnit_Util_InvalidArgumentHelper::factory(3, 'string', $matchType);
51
+ }
52
+
53
+ $this->_expectedValueValidation += array(
54
+ self::TYPE_MATCH => array(true, 'is_array', 'array')
55
+ );
56
+
57
+ $this->_typesWithDiff[] = self::TYPE_MATCH;
58
+
59
+ parent::__construct($type, $expectedValue);
60
+ $this->_matchType = $matchType;
61
+ }
62
+
63
+ /**
64
+ * Evaluate that string is valid JSON
65
+ *
66
+ * @param string $other
67
+ * @return boolean
68
+ */
69
+ protected function evaluateValid($other)
70
+ {
71
+ try {
72
+ $decodedJson = Zend_Json::decode($other);
73
+ $this->setActualValue($decodedJson);
74
+ } catch (Zend_Json_Exception $e) {
75
+ $this->setActualValue(
76
+ PHPUnit_Util_Type::shortenedString($other)
77
+ . "\n" . $e->__toString()
78
+ );
79
+ return false;
80
+ }
81
+
82
+ return true;
83
+ }
84
+
85
+ /**
86
+ * Text representation of JSON string is valid assertion
87
+ *
88
+ * @return string
89
+ */
90
+ protected function textValid()
91
+ {
92
+ return 'is valid JSON';
93
+ }
94
+
95
+ /**
96
+ * Evaluate that string is valid JSON
97
+ *
98
+ * @param string $other
99
+ * @return boolean
100
+ */
101
+ protected function evaluateMatch($other)
102
+ {
103
+ $decodedJson = Zend_Json::decode($other);
104
+ $this->setActualValue($decodedJson);
105
+
106
+ $intersection = array_intersect_assoc(
107
+ $this->_actualValue,
108
+ $this->_expectedValue
109
+ );
110
+
111
+ switch ($this->_matchType) {
112
+ case self::MATCH_OR:
113
+ $matched = !empty($intersection);
114
+ break;
115
+ case self::MATCH_EXACT:
116
+ $matched = count($intersection) === count($decodedJson);
117
+ break;
118
+ case self::MATCH_AND:
119
+ default:
120
+ $matched = count($intersection) === count($this->_expectedValue);
121
+ break;
122
+ }
123
+
124
+ return $matched;
125
+ }
126
+
127
+ /**
128
+ * Text representation of matching evaluation
129
+ *
130
+ * @return string
131
+ */
132
+ protected function textMatch()
133
+ {
134
+ $string = 'matches expected JSON structure ';
135
+
136
+ switch ($this->_matchType) {
137
+ case self::MATCH_OR:
138
+ $string .= 'at least in one element';
139
+ break;
140
+ case self::MATCH_EXACT:
141
+ $string .= 'exactly';
142
+ break;
143
+ case self::MATCH_AND:
144
+ default:
145
+ $string .= 'in all expected elements';
146
+ break;
147
+ }
148
+
149
+ return $string;
150
+ }
151
+
152
+ /**
153
+ * Text representation of JSON string is valid assertion
154
+ *
155
+ * @return string
156
+ */
157
+ protected function textValid()
158
+ {
159
+ return 'is valid JSON';
160
+ }
161
+
162
+ /**
163
+ * Custom failure description for showing json related errors
164
+ * (non-PHPdoc)
165
+ * @see PHPUnit_Framework_Constraint::customFailureDescription()
166
+ */
167
+ protected function customFailureDescription($other, $description, $not)
168
+ {
169
+ return sprintf(
170
+ 'Failed asserting that string value %s.',
171
+ $this->toString()
172
+ );
173
+ }
174
+ }
lib/EcomDev/PHPUnit/Constraint/Layout.php ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PHP Unit test suite for Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ *
12
+ * @category EcomDev
13
+ * @package EcomDev_PHPUnit
14
+ * @copyright Copyright (c) 2011 Ecommerce Developers (http://www.ecomdev.org)
15
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
+ * @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
17
+ */
18
+
19
+ /**
20
+ * Constraint for main layout functionality
21
+ *
22
+ */
23
+ class EcomDev_PHPUnit_Constraint_Layout extends EcomDev_PHPUnit_Constraint_Layout_Abstract
24
+ {
25
+ const TYPE_LOADED = 'loaded';
26
+ const TYPE_RENDERED = 'rendered';
27
+
28
+ const ACTION_RENDER = EcomDev_PHPUnit_Constraint_Layout_Logger_Interface::ACTION_RENDER;
29
+
30
+ /**
31
+ * Constraint for main layout functions
32
+ *
33
+ *
34
+ * @param string $type
35
+ */
36
+ public function __construct($type = self::TYPE_LOADED)
37
+ {
38
+ parent::__construct($type);
39
+ }
40
+
41
+ /**
42
+ * Evaluates that layout was loaded
43
+ *
44
+ *
45
+ * @param EcomDev_PHPUnit_Constraint_Layout_Logger_Interface $other
46
+ * @return boolean
47
+ */
48
+ protected function evaluateLoaded($other)
49
+ {
50
+ return $other->isLoaded();
51
+ }
52
+
53
+ /**
54
+ * Text representation of layout is loaded assertion
55
+ *
56
+ * @return string
57
+ */
58
+ protected function textLoaded()
59
+ {
60
+ return 'is loaded';
61
+ }
62
+
63
+ /**
64
+ * Evaluates that layout was rendered
65
+ *
66
+ *
67
+ * @param EcomDev_PHPUnit_Constraint_Layout_Logger_Interface $other
68
+ * @return boolean
69
+ */
70
+ protected function evaluateRendered($other)
71
+ {
72
+ return $other->findFirst(self::ACTION_RENDER, 'layout') !== false;
73
+ }
74
+
75
+ /**
76
+ * Text representation of layout is rendered assertion
77
+ *
78
+ * @return string
79
+ */
80
+ protected function textRendered()
81
+ {
82
+ return 'is rendered';
83
+ }
84
+ }
lib/EcomDev/PHPUnit/Constraint/Layout/Abstract.php ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PHP Unit test suite for Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ *
12
+ * @category EcomDev
13
+ * @package EcomDev_PHPUnit
14
+ * @copyright Copyright (c) 2011 Ecommerce Developers (http://www.ecomdev.org)
15
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
+ * @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
17
+ */
18
+
19
+ /**
20
+ * Base for all layout constraints
21
+ *
22
+ */
23
+ abstract class EcomDev_PHPUnit_Constraint_Layout_Abstract extends EcomDev_PHPUnit_Constraint_Abstract
24
+ {
25
+ /**
26
+ * Custom failure description for showing layout related errors
27
+ * (non-PHPdoc)
28
+ * @see PHPUnit_Framework_Constraint::customFailureDescription()
29
+ */
30
+ protected function customFailureDescription($other, $description, $not)
31
+ {
32
+ return sprintf(
33
+ 'Failed asserting that layout %s.',
34
+ $this->toString()
35
+ );
36
+ }
37
+
38
+ /**
39
+ * For layout, actual value should be always set
40
+ * (non-PHPdoc)
41
+ * @see EcomDev_PHPUnit_Constraint_Abstract::getActualValue()
42
+ */
43
+ protected function getActualValue($other)
44
+ {
45
+ if ($this->_useActualValue) {
46
+ if (is_array($this->_actualValue)) {
47
+ return PHPUnit_Util_Type::toString($this->_actualValue);
48
+ }
49
+
50
+ return parent::getActualValue($other);
51
+ }
52
+
53
+ return '';
54
+ }
55
+ }
lib/EcomDev/PHPUnit/Constraint/Layout/Block.php ADDED
@@ -0,0 +1,308 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PHP Unit test suite for Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ *
12
+ * @category EcomDev
13
+ * @package EcomDev_PHPUnit
14
+ * @copyright Copyright (c) 2011 Ecommerce Developers (http://www.ecomdev.org)
15
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
+ * @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
17
+ */
18
+
19
+ /**
20
+ * Constaint related to main layout block functionality
21
+ *
22
+ */
23
+ class EcomDev_PHPUnit_Constraint_Layout_Block extends EcomDev_PHPUnit_Constraint_Layout_Abstract
24
+ {
25
+ const TYPE_CREATED = 'created';
26
+ const TYPE_REMOVED = 'removed';
27
+ const TYPE_RENDERED = 'rendered';
28
+ const TYPE_RENDERED_CONTENT = 'rendered_content';
29
+ const TYPE_TYPE = 'type';
30
+ const TYPE_INSTANCE_OF = 'instance_of';
31
+ const TYPE_AFTER = 'after';
32
+ const TYPE_BEFORE = 'before';
33
+ const TYPE_PARENT_NAME = 'parent_name';
34
+ const TYPE_ROOT_LEVEL = 'root_level';
35
+
36
+ const ACTION_BLOCK_CREATED = EcomDev_PHPUnit_Constraint_Layout_Logger_Interface::ACTION_BLOCK_CREATED;
37
+ const ACTION_BLOCK_RENDERED = EcomDev_PHPUnit_Constraint_Layout_Logger_Interface::ACTION_BLOCK_RENDERED;
38
+ const ACTION_BLOCK_REMOVED = EcomDev_PHPUnit_Constraint_Layout_Logger_Interface::ACTION_BLOCK_REMOVED;
39
+
40
+ /**
41
+ * Block name for constraint
42
+ *
43
+ * @var string
44
+ */
45
+ protected $_blockName = null;
46
+
47
+ /**
48
+ * Constaint related to main layout block functionality
49
+ *
50
+ * @param string $blockName
51
+ * @param string $type
52
+ * @param string|null $expectedValue
53
+ */
54
+ public function __construct($blockName, $type, $expectedValue = null)
55
+ {
56
+ if (empty($blockName) || !is_string($blockName)) {
57
+ throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string', $blockName);
58
+ }
59
+
60
+ $this->_blockName = $blockName;
61
+
62
+ $this->_expectedValueValidation += array(
63
+ self::TYPE_TYPE => array(true, 'is_string', 'string'),
64
+ self::TYPE_INSTANCE_OF => array(true, 'is_string', 'string'),
65
+ self::TYPE_AFTER => array(true, 'is_string', 'string'),
66
+ self::TYPE_BEFORE => array(true, 'is_string', 'string'),
67
+ self::TYPE_PARENT_NAME => array(true, 'is_string', 'string'),
68
+ self::TYPE_RENDERED_CONTENT => array(true)
69
+ );
70
+
71
+ $this->_typesWithDiff[] = self::TYPE_TYPE;
72
+ $this->_typesWithDiff[] = self::TYPE_AFTER;
73
+ $this->_typesWithDiff[] = self::TYPE_BEFORE;
74
+ $this->_typesWithDiff[] = self::TYPE_PARENT_NAME;
75
+ parent::__construct($type, $expectedValue);
76
+ }
77
+
78
+ /**
79
+ * Evaluates that layout block was created
80
+ *
81
+ * @param EcomDev_PHPUnit_Constraint_Layout_Logger_Interface $other
82
+ * @return boolean
83
+ */
84
+ protected function evaluateCreated($other)
85
+ {
86
+ return $other->findFirst(self::ACTION_BLOCK_CREATED, $this->_blockName);
87
+ }
88
+
89
+ /**
90
+ * Text representation of block is created assertion
91
+ *
92
+ * @return string
93
+ */
94
+ protected function textCreated()
95
+ {
96
+ return sprintf('block "%s" is created', $this->_blockName);
97
+ }
98
+
99
+ /**
100
+ * Evaluates that layout block was rendered
101
+ *
102
+ * @param EcomDev_PHPUnit_Constraint_Layout_Logger_Interface $other
103
+ * @return boolean
104
+ */
105
+ protected function evaluateRendered($other)
106
+ {
107
+ return $other->findFirst(self::ACTION_BLOCK_RENDERED, $this->_blockName) !== false;
108
+ }
109
+
110
+ /**
111
+ * Text representation of block is rendered assertion
112
+ *
113
+ * @return string
114
+ */
115
+ protected function textRendered()
116
+ {
117
+ return sprintf('block "%s" is rendered', $this->_blockName);
118
+ }
119
+
120
+ /**
121
+ * Evaluates that layout block rendered is evaluated by expected constraint
122
+ *
123
+ * @param EcomDev_PHPUnit_Constraint_Layout_Logger_Interface $other
124
+ * @return boolean
125
+ */
126
+ protected function evaluateRenderedContent($other)
127
+ {
128
+ $renderInfo = $other->findFirst(self::ACTION_BLOCK_RENDERED, $this->_blockName);
129
+
130
+ if (!$renderInfo) {
131
+ $this->setActualValue(false);
132
+ return false;
133
+ }
134
+
135
+ $this->setActualValue($renderInfo['content']);
136
+ return $this->_expectedValue->evaluate($renderInfo['content']);
137
+ }
138
+
139
+ /**
140
+ * Text representation of block rendered is evaluated by expected constraint assertion
141
+ *
142
+ * @return string
143
+ */
144
+ protected function textRenderedContent()
145
+ {
146
+ return sprintf('block "%s" rendered content %s',
147
+ $this->_blockName, $this->_expectedValue->toString());
148
+ }
149
+
150
+ /**
151
+ * Evaluates that layout block was removed
152
+ *
153
+ * @param EcomDev_PHPUnit_Constraint_Layout_Logger_Interface $other
154
+ * @return boolean
155
+ */
156
+ protected function evaluateRemoved($other)
157
+ {
158
+ // Set possible block creation record for failure
159
+ $this->setActualValue(
160
+ $other->findFirst(self::ACTION_BLOCK_CREATED, $this->_blockName)
161
+ );
162
+
163
+ return $this->_actualValue === false
164
+ && $other->findFirst(self::ACTION_BLOCK_REMOVED, $this->_blockName) !== false;
165
+ }
166
+
167
+ /**
168
+ * Text representation of block is removed assertion
169
+ *
170
+ * @return string
171
+ */
172
+ protected function textRemoved()
173
+ {
174
+ return sprintf('block "%s" is removed', $this->_blockName);
175
+ }
176
+
177
+ /**
178
+ * Evaluates that layout block was placed after expected one
179
+ *
180
+ * @param EcomDev_PHPUnit_Constraint_Layout_Logger_Interface $other
181
+ * @return boolean
182
+ */
183
+ protected function evaluateAfter($other)
184
+ {
185
+ $positionInfo = $other->getBlockPosition($this->_blockName);
186
+ $this->setActualValue($positionInfo['after']);
187
+ return in_array($this->_expectedValue, $this->_actualValue);
188
+ }
189
+
190
+ /**
191
+ * Text representation of layout block is placed after another
192
+ *
193
+ * @return string
194
+ */
195
+ protected function textAfter()
196
+ {
197
+ return sprintf('block "%s" is placed after "%s"', $this->_blockName, $this->_expectedValue);
198
+ }
199
+
200
+ /**
201
+ * Evaluates that layout block was placed before expected one
202
+ *
203
+ * @param EcomDev_PHPUnit_Constraint_Layout_Logger_Interface $other
204
+ * @return boolean
205
+ */
206
+ protected function evaluateBefore($other)
207
+ {
208
+ $positionInfo = $other->getBlockPosition($this->_blockName);
209
+ $this->setActualValue($positionInfo['before']);
210
+ return in_array($this->_expectedValue, $this->_actualValue);
211
+ }
212
+
213
+ /**
214
+ * Text representation of layout block is placed before another
215
+ *
216
+ * @return string
217
+ */
218
+ protected function textBefore()
219
+ {
220
+ return sprintf('block "%s" is placed before "%s"', $this->_blockName, $this->_expectedValue);
221
+ }
222
+
223
+ /**
224
+ * Evaluates that layout block is a type of expected
225
+ *
226
+ * @param EcomDev_PHPUnit_Constraint_Layout_Logger_Interface $other
227
+ * @return boolean
228
+ */
229
+ protected function evaluateType($other)
230
+ {
231
+ $blockInfo = $other->findFirst(self::ACTION_BLOCK_CREATED, $this->_blockName);
232
+ if ($blockInfo === false) {
233
+ $this->setActualValue(false);
234
+ return false;
235
+ }
236
+
237
+ $this->setActualValue($blockInfo['type']);
238
+ return $blockInfo['type'] === $this->_expectedValue;
239
+ }
240
+
241
+ /**
242
+ * Text represetation of block type constraint
243
+ *
244
+ * @return string
245
+ */
246
+ protected function textType()
247
+ {
248
+ return sprintf('block "%s" is a type of "%s"', $this->_blockName, $this->_expectedValue);
249
+ }
250
+
251
+ /**
252
+ * Evaluates that layout block is an instance of expected class/interface
253
+ *
254
+ * @param EcomDev_PHPUnit_Constraint_Layout_Logger_Interface $other
255
+ * @return boolean
256
+ */
257
+ protected function evaluateInstanceOf($other)
258
+ {
259
+ $blockInfo = $other->findFirst(self::ACTION_BLOCK_CREATED, $this->_blockName);
260
+ if ($blockInfo === false) {
261
+ $this->setActualValue(false);
262
+ return false;
263
+ }
264
+
265
+ $this->setActualValue($blockInfo['class']);
266
+ $actualReflection = EcomDev_Utils_Reflection::getRelflection($this->_actualValue);
267
+ return $this->_actualValue === $this->_expectedValue
268
+ || $actualReflection->isSubclassOf($this->_expectedValue);
269
+ }
270
+
271
+ /**
272
+ * Text represetation of block instance of constraint
273
+ *
274
+ * @return string
275
+ */
276
+ protected function textInstanceOf()
277
+ {
278
+ return sprintf('block "%s" is an instance of %s', $this->_blockName, $this->_expectedValue);
279
+ }
280
+
281
+
282
+
283
+ /**
284
+ * Evaluates that layout block is a root level block
285
+ *
286
+ * @param EcomDev_PHPUnit_Constraint_Layout_Logger_Interface $other
287
+ * @return boolean
288
+ */
289
+ protected function evaluateRootLevel($other)
290
+ {
291
+ $blockInfo = $other->findFirst(self::ACTION_BLOCK_CREATED, $this->_blockName);
292
+ if ($blockInfo === false) {
293
+ return false;
294
+ }
295
+
296
+ return $blockInfo['root'] === true;
297
+ }
298
+
299
+ /**
300
+ * Text representation of a root level block assertion
301
+ *
302
+ * @return string
303
+ */
304
+ protected function textRootLevel()
305
+ {
306
+ return sprintf('block "%s" is a root level one', $this->_blockName);
307
+ }
308
+ }
lib/EcomDev/PHPUnit/Constraint/Layout/Block/Action.php ADDED
@@ -0,0 +1,202 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PHP Unit test suite for Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ *
12
+ * @category EcomDev
13
+ * @package EcomDev_PHPUnit
14
+ * @copyright Copyright (c) 2011 Ecommerce Developers (http://www.ecomdev.org)
15
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
+ * @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
17
+ */
18
+
19
+ /**
20
+ * Constaint related to main layout block action calls functionality
21
+ *
22
+ */
23
+ class EcomDev_PHPUnit_Constraint_Layout_Block_Action extends EcomDev_PHPUnit_Constraint_Layout_Abstract
24
+ {
25
+ const TYPE_INVOKED = 'invoked';
26
+ const TYPE_INVOKED_AT_LEAST = 'invoked_at_least';
27
+ const TYPE_INVOKED_EXACTLY = 'invoked_exactly';
28
+
29
+ const ACTION_BLOCK_ACTION = EcomDev_PHPUnit_Constraint_Layout_Logger_Interface::ACTION_BLOCK_ACTION;
30
+
31
+ const SEARCH_TYPE_OR = EcomDev_PHPUnit_Constraint_Layout_Logger_Interface::SEARCH_TYPE_OR;
32
+ const SEARCH_TYPE_EXACT = EcomDev_PHPUnit_Constraint_Layout_Logger_Interface::SEARCH_TYPE_EXACT;
33
+ const SEARCH_TYPE_AND = EcomDev_PHPUnit_Constraint_Layout_Logger_Interface::SEARCH_TYPE_AND;
34
+
35
+ /**
36
+ * Block name for the action
37
+ *
38
+ * @var string
39
+ */
40
+ protected $_blockName = null;
41
+
42
+ /**
43
+ * Block method name for the action
44
+ *
45
+ * @var string
46
+ */
47
+ protected $_method = null;
48
+
49
+ /**
50
+ * Target for searching in layout records
51
+ *
52
+ * @var string
53
+ */
54
+ protected $_target = null;
55
+
56
+ /**
57
+ * Block method arguments for search
58
+ *
59
+ * @var array
60
+ */
61
+ protected $_arguments = null;
62
+
63
+ /**
64
+ * Block method arguments search type
65
+ *
66
+ * @var unknown_type
67
+ */
68
+ protected $_searchType = self::SEARCH_TYPE_AND;
69
+
70
+ /**
71
+ * Constaint related to main layout block action calls functionality
72
+ *
73
+ * @param string $blockName
74
+ * @param string $method
75
+ * @param string $type
76
+ * @param int|null $invocationCount
77
+ * @param array|null $parameters
78
+ * @param string $searchType
79
+ */
80
+ public function __construct($blockName, $method, $type, $invocationCount = null,
81
+ array $arguments = null, $searchType = self::SEARCH_TYPE_AND)
82
+ {
83
+ if (empty($blockName) || !is_string($blockName)) {
84
+ PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string', $blockName);
85
+ }
86
+
87
+ if (empty($method) || !is_string($method)) {
88
+ throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'string', $method);
89
+ }
90
+
91
+ if (!is_string($searchType)) {
92
+ throw PHPUnit_Util_InvalidArgumentHelper::factory(6, 'string', $searchType);
93
+ }
94
+
95
+ $this->_expectedValueValidation += array(
96
+ self::TYPE_INVOKED_AT_LEAST => array(true, 'is_int', 'integer'),
97
+ self::TYPE_INVOKED_EXACTLY => array(true, 'is_int', 'integer')
98
+ );
99
+
100
+ parent::__construct($type, $invocationCount);
101
+
102
+ $this->_blockName = $blockName;
103
+ $this->_method = $method;
104
+ $this->_target = sprintf('%s::%s', $this->_blockName, $this->_method);
105
+ $this->_arguments = $arguments;
106
+ }
107
+
108
+ /**
109
+ * Finds records in layout logger history
110
+ *
111
+ * @param EcomDev_PHPUnit_Constraint_Layout_Logger_Interface $other
112
+ * @return array
113
+ */
114
+ protected function findRecords($other)
115
+ {
116
+ if ($this->_arguments !== null) {
117
+ $this->setActualValue($other->findAll(self::ACTION_BLOCK_ACTION, $this->_target));
118
+ return $other->findByParameters(
119
+ self::ACTION_BLOCK_ACTION, $this->_target,
120
+ $this->_arguments, $this->_searchType
121
+ );
122
+ }
123
+ $records = $other->findAll(self::ACTION_BLOCK_ACTION, $this->_target);
124
+ $this->setActualValue($records);
125
+ return $records;
126
+ }
127
+
128
+ /**
129
+ * Evaluates that method was invoked at least once
130
+ *
131
+ * @param EcomDev_PHPUnit_Constraint_Layout_Logger_Interface $other
132
+ * @return boolean
133
+ */
134
+ protected function evaluateInvoked($other)
135
+ {
136
+ $records = $this->findRecords($other);
137
+ return !empty($records);
138
+ }
139
+
140
+ /**
141
+ * Text representation of at least once invokation
142
+ *
143
+ * @return string
144
+ */
145
+ protected function textInvoked()
146
+ {
147
+ $withArguments = '';
148
+
149
+ if ($this->_arguments !== null) {
150
+ $withArguments = ' with expected arguments';
151
+ }
152
+
153
+ return sprintf('block "%s" action for method "%s" was invoked%s',
154
+ $this->_blockName, $this->_method, $withArguments);
155
+ }
156
+
157
+ /**
158
+ * Evaluates that method was invoked
159
+ * at least expected number of times
160
+ *
161
+ * @param EcomDev_PHPUnit_Constraint_Layout_Logger_Interface $other
162
+ * @return boolean
163
+ */
164
+ protected function evaluateInvokedAtLeast($other)
165
+ {
166
+ $records = $this->findRecords($other);
167
+ return count($records) >= $this->_expectedValue;
168
+ }
169
+
170
+ /**
171
+ * Text representation of at least expected times invokation
172
+ *
173
+ * @return string
174
+ */
175
+ protected function textInvokedAtLeast()
176
+ {
177
+ return $this->textInvoked() . sprintf(' at least %d times', $this->_expectedValue);
178
+ }
179
+
180
+ /**
181
+ * Evaluates that method was invoked
182
+ * exactly expected number of times
183
+ *
184
+ * @param EcomDev_PHPUnit_Constraint_Layout_Logger_Interface $other
185
+ * @return boolean
186
+ */
187
+ protected function evaluateInvokedExactly($other)
188
+ {
189
+ $records = $this->findRecords($other);
190
+ return count($records) === $this->_expectedValue;
191
+ }
192
+
193
+ /**
194
+ * Text representation of exactly times invokation
195
+ *
196
+ * @return string
197
+ */
198
+ protected function textInvokedExactly()
199
+ {
200
+ return $this->textInvoked() . sprintf(' exactly %d times', $this->_expectedValue);
201
+ }
202
+ }
lib/EcomDev/PHPUnit/Constraint/Layout/Block/Property.php ADDED
@@ -0,0 +1,121 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PHP Unit test suite for Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ *
12
+ * @category EcomDev
13
+ * @package EcomDev_PHPUnit
14
+ * @copyright Copyright (c) 2011 Ecommerce Developers (http://www.ecomdev.org)
15
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
+ * @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
17
+ */
18
+
19
+ /**
20
+ * Block property constraint
21
+ *
22
+ */
23
+ class EcomDev_PHPUnit_Constraint_Layout_Block_Property
24
+ extends EcomDev_PHPUnit_Constraint_Layout_Abstract
25
+ {
26
+ const TYPE_CONSTRAINT = 'constraint';
27
+
28
+ /**
29
+ * Block name for constraint
30
+ *
31
+ * @var string
32
+ */
33
+ protected $_blockName = null;
34
+
35
+ /**
36
+ * Block property for constraint
37
+ *
38
+ * @var string
39
+ */
40
+ protected $_propertyName = null;
41
+
42
+ /**
43
+ * Block property constraint
44
+ *
45
+ * @return boolean
46
+ */
47
+ public function __construct($blockName, $propertyName, PHPUnit_Framework_Constraint $constraint,
48
+ $type = self::TYPE_CONSTRAINT)
49
+ {
50
+ if (empty($blockName) || !is_string($blockName)) {
51
+ throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string', $blockName);
52
+ }
53
+
54
+ if (empty($propertyName) || !is_string($propertyName)) {
55
+ throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'string', $propertyName);
56
+ }
57
+
58
+ parent::__construct($type, $constraint);
59
+
60
+ $this->_blockName = $blockName;
61
+ $this->_propertyName = $propertyName;
62
+ }
63
+
64
+ /**
65
+ * Retuns number of constraint assertions
66
+ *
67
+ * (non-PHPdoc)
68
+ * @see PHPUnit_Framework_Constraint::count()
69
+ */
70
+ public function count()
71
+ {
72
+ return $this->_expectedValue->count();
73
+ }
74
+
75
+ /**
76
+ * Returning user friendly actual value
77
+ * (non-PHPdoc)
78
+ * @see EcomDev_PHPUnit_Constraint_Abstract::getActualValue()
79
+ */
80
+ protected function getActualValue($other)
81
+ {
82
+ if ($this->_useActualValue) {
83
+ if ($this->_actualValue instanceof Varien_Object) {
84
+ $value = $this->_actualValue->debug();
85
+ } else {
86
+ $value = $this->_actualValue;
87
+ }
88
+
89
+ return PHPUnit_Util_Type::toString($value);
90
+ }
91
+
92
+ return '';
93
+ }
94
+
95
+ /**
96
+ * Evaluates a property constraint
97
+ *
98
+ * @param EcomDev_PHPUnit_Constraint_Layout_Logger_Interface $other
99
+ * @return boolean
100
+ */
101
+ protected function evaluateConstraint($other)
102
+ {
103
+ $this->setActualValue(
104
+ $other->getBlockProperty($this->_blockName, $this->_propertyName)
105
+ );
106
+
107
+ return $this->_expectedValue->evaluate($this->_actualValue);
108
+ }
109
+
110
+ /**
111
+ * Text representation of block property constraint
112
+ *
113
+ * @return string
114
+ */
115
+ protected function textConstraint()
116
+ {
117
+ return sprintf('block "%s" property "%s" %s',
118
+ $this->_blockName, $this->_propertyName,
119
+ $this->_expectedValue->toString());
120
+ }
121
+ }
lib/EcomDev/PHPUnit/Constraint/Layout/Handle.php ADDED
@@ -0,0 +1,201 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PHP Unit test suite for Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ *
12
+ * @category EcomDev
13
+ * @package EcomDev_PHPUnit
14
+ * @copyright Copyright (c) 2011 Ecommerce Developers (http://www.ecomdev.org)
15
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
+ * @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
17
+ */
18
+
19
+ /**
20
+ * Constraint for testing layout handles load priority
21
+ *
22
+ */
23
+ class EcomDev_PHPUnit_Constraint_Layout_Handle extends EcomDev_PHPUnit_Constraint_Layout_Abstract
24
+ {
25
+ const TYPE_LOADED = 'loaded';
26
+ const TYPE_LOADED_AFTER = 'loaded_after';
27
+ const TYPE_LOADED_BEFORE = 'loaded_before';
28
+
29
+ const ACTION_HANDLE_LOADED = EcomDev_PHPUnit_Constraint_Layout_Logger_Interface::ACTION_HANDLE_LOADED;
30
+
31
+ /**
32
+ * Position element of layout handle,
33
+ * for instance another handle
34
+ *
35
+ * @var string|null
36
+ */
37
+ protected $_position = null;
38
+
39
+ /**
40
+ * Handle name
41
+ *
42
+ * @var string
43
+ */
44
+ protected $_handle = null;
45
+
46
+ /**
47
+ * Layout handle constraint
48
+ *
49
+ *
50
+ * @param string $handle layout handle name
51
+ * @param string $type
52
+ * @param string|null $position layout handle position
53
+ */
54
+ public function __construct($handle, $type, $position = null)
55
+ {
56
+ if ($position !== null && !is_string($position)) {
57
+ throw PHPUnit_Util_InvalidArgumentHelper::factory(3, 'string', $position);
58
+ }
59
+
60
+ $this->_position = $position;
61
+
62
+ $this->_handle = $handle;
63
+
64
+ $this->_expectedValueValidation += array(
65
+ self::TYPE_LOADED => array(true, 'is_string', 'string'),
66
+ self::TYPE_LOADED_AFTER => array(true, 'is_string', 'string'),
67
+ self::TYPE_LOADED_BEFORE => array(true, 'is_string', 'string')
68
+ );
69
+
70
+ $this->_typesWithDiff[] = self::TYPE_LOADED;
71
+ $this->_typesWithDiff[] = self::TYPE_LOADED_AFTER;
72
+ $this->_typesWithDiff[] = self::TYPE_LOADED_BEFORE;
73
+
74
+ parent::__construct($type, $this->_handle);
75
+ }
76
+
77
+ /**
78
+ * Evaluates that layout handle was loaded
79
+ *
80
+ *
81
+ * @param EcomDev_PHPUnit_Constraint_Layout_Logger_Interface $other
82
+ * @return boolean
83
+ */
84
+ protected function evaluateLoaded($other)
85
+ {
86
+ $this->setActualValue(
87
+ $other->findAllTargets(self::ACTION_HANDLE_LOADED)
88
+ );
89
+
90
+ $this->_expectedValue = $this->_actualValue;
91
+
92
+ $match = $other->findFirst(self::ACTION_HANDLE_LOADED, $this->_handle) !== false;
93
+
94
+ if (!$match) {
95
+ $this->_expectedValue[] = $this->_handle;
96
+ }
97
+
98
+ return $match;
99
+ }
100
+
101
+ /**
102
+ * Text representation of layout handle loaded assertion
103
+ *
104
+ * @return string
105
+ */
106
+ protected function textLoaded()
107
+ {
108
+ return sprintf('handle "%s" is loaded', $this->_handle);
109
+ }
110
+
111
+ /**
112
+ * Evaluates that layout handle was loaded after another
113
+ *
114
+ * @param EcomDev_PHPUnit_Constraint_Layout_Logger_Interface $other
115
+ * @return boolean
116
+ */
117
+ protected function evaluateLoadedAfter($other)
118
+ {
119
+ $handleInfo = $other->findFirst(self::ACTION_HANDLE_LOADED, $this->_handle);
120
+
121
+ if ($handleInfo === false) {
122
+ return false;
123
+ }
124
+
125
+ $match = in_array($this->_position, $handleInfo['after']);
126
+
127
+ $this->setActualValue(
128
+ $handleInfo['before']
129
+ );
130
+
131
+ $this->_actualValue[] = $this->_handle;
132
+ $this->_expectedValue = $this->_actualValue;
133
+
134
+ if (!$match) {
135
+ array_splice(
136
+ $this->_expectedValue,
137
+ array_search($this->_handle, $this->_expectedValue),
138
+ 0,
139
+ $this->_position
140
+ );
141
+ }
142
+
143
+ return $match;
144
+ }
145
+
146
+ /**
147
+ * Text representation of loaded after assertion
148
+ *
149
+ * @return string
150
+ */
151
+ protected function textLoadedAfter()
152
+ {
153
+ return sprintf('handle "%s" is loaded after "%s"', $this->_handle, $this->_position);
154
+ }
155
+
156
+ /**
157
+ * Evaluates that layout handle was loaded after another
158
+ *
159
+ * @param EcomDev_PHPUnit_Constraint_Layout_Logger_Interface $other
160
+ * @return boolean
161
+ */
162
+ protected function evaluateLoadedBefore($other)
163
+ {
164
+ $handleInfo = $other->findFirst(self::ACTION_HANDLE_LOADED, $this->_handle);
165
+
166
+ if ($handleInfo === false) {
167
+ return false;
168
+ }
169
+
170
+ $match = in_array($this->_position, $handleInfo['before']);
171
+
172
+
173
+ $this->setActualValue(
174
+ $handleInfo['before']
175
+ );
176
+
177
+ array_unshift($this->_actualValue, $this->_handle);
178
+ $this->_expectedValue = $this->_actualValue;
179
+
180
+ if (!$match) {
181
+ array_splice(
182
+ $this->_expectedValue,
183
+ array_search($this->_handle, $this->_expectedValue) + 1,
184
+ 0,
185
+ $this->_position
186
+ );
187
+ }
188
+
189
+ return $match;
190
+ }
191
+
192
+ /**
193
+ * Text representation of loaded after assertion
194
+ *
195
+ * @return string
196
+ */
197
+ protected function textLoadedBefore()
198
+ {
199
+ return sprintf('handle "%s" is loaded before "%s"', $this->_handle, $this->_position);
200
+ }
201
+ }
lib/EcomDev/PHPUnit/Constraint/Layout/Logger/Interface.php ADDED
@@ -0,0 +1,119 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PHP Unit test suite for Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ *
12
+ * @category EcomDev
13
+ * @package EcomDev_PHPUnit
14
+ * @copyright Copyright (c) 2011 Ecommerce Developers (http://www.ecomdev.org)
15
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
+ * @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
17
+ */
18
+
19
+ /**
20
+ * Interface that should be implemented in layout model for
21
+ * making possible asserting layout actions
22
+ *
23
+ */
24
+ interface EcomDev_PHPUnit_Constraint_Layout_Logger_Interface
25
+ {
26
+ const ACTION_HANDLE_LOADED = 'handle_loaded';
27
+ const ACTION_BLOCK_CREATED = 'block_created';
28
+ const ACTION_BLOCK_RENDERED = 'block_rendered';
29
+ const ACTION_BLOCK_REMOVED = 'block_removed';
30
+ const ACTION_BLOCK_ACTION = 'block_action';
31
+
32
+ const ACTION_RENDER = 'rendered';
33
+
34
+ const SEARCH_TYPE_OR = 'or';
35
+ const SEARCH_TYPE_AND = 'and';
36
+ const SEARCH_TYPE_EXACT = 'exact';
37
+
38
+ /**
39
+ * Records a particular target action
40
+ *
41
+ * @param string $action
42
+ * @param string $target
43
+ * @param array $parameters
44
+ * @return EcomDev_PHPUnit_Constraint_Layout_Logger_Interface
45
+ */
46
+ public function record($action, $target, array $parameters = array());
47
+
48
+ /**
49
+ * Returns all actions performed on the target
50
+ * or if target is null returns actions for all targets
51
+ *
52
+ * @param string $action
53
+ * @param string|null $target
54
+ * @return array
55
+ */
56
+ public function findAll($action, $target = null);
57
+
58
+ /**
59
+ * Returns all actions targets
60
+ *
61
+ * @param string $action
62
+ * @return array
63
+ */
64
+ public function findAllTargets($action);
65
+
66
+ /**
67
+ * Returns first action that was recorded for target
68
+ *
69
+ * @param string $action
70
+ * @param string $target
71
+ * @return array|false
72
+ */
73
+ public function findFirst($action, $target);
74
+
75
+ /**
76
+ * Returns target action records by specified parameters
77
+ *
78
+ *
79
+ * @param string $action
80
+ * @param string $target
81
+ * @param array $parameters
82
+ * @param string $searchType (or, and, exact)
83
+ * @return array|false
84
+ */
85
+ public function findByParameters($action, $target, array $parameters, $searchType = self::SEARCH_TYPE_AND);
86
+
87
+ /**
88
+ * Returns block position information in the parent subling.
89
+ * Returned array contains two keys "before" and "after"
90
+ * which are list of block names in this positions
91
+ *
92
+ * @param string $block
93
+ * @return array
94
+ */
95
+ public function getBlockPosition($block);
96
+
97
+ /**
98
+ * Returns block parent name
99
+ *
100
+ * @param string $block
101
+ * @return string|boolean
102
+ */
103
+ public function getBlockParent($block);
104
+
105
+ /**
106
+ * Returns block property, even by getter
107
+ *
108
+ * @param string $block
109
+ * @return mixed
110
+ */
111
+ public function getBlockProperty($block, $property);
112
+
113
+ /**
114
+ * Retuns a boolean flag for layout load status
115
+ *
116
+ * @return boolean
117
+ */
118
+ public function isLoaded();
119
+ }
lib/EcomDev/PHPUnit/Controller/Request/Interface.php ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PHP Unit test suite for Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ *
12
+ * @category EcomDev
13
+ * @package EcomDev_PHPUnit
14
+ * @copyright Copyright (c) 2011 Ecommerce Developers (http://www.ecomdev.org)
15
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
+ * @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
17
+ */
18
+
19
+ /**
20
+ * Interface for request object, that will be asserted
21
+ *
22
+ */
23
+ interface EcomDev_PHPUnit_Controller_Request_Interface
24
+ {
25
+ /**
26
+ * Returns current route name
27
+ *
28
+ * @return string
29
+ */
30
+ public function getRouteName();
31
+
32
+ /**
33
+ * Returns current controller name
34
+ *
35
+ * @return string
36
+ */
37
+ public function getControllerName();
38
+
39
+ /**
40
+ * Returns current controller module
41
+ *
42
+ * @return string
43
+ */
44
+ public function getControllerModule();
45
+
46
+ /**
47
+ * Returns current controller action name
48
+ *
49
+ * @return string
50
+ */
51
+ public function getActionName();
52
+
53
+ /**
54
+ * Retrieve property's value which was before forward call.
55
+ *
56
+ * @param string $name
57
+ * @return array|string|null
58
+ */
59
+ public function getBeforeForwardInfo($name = null);
60
+
61
+ /**
62
+ * Check whether request was dispatched
63
+ *
64
+ */
65
+ public function isDispatched();
66
+ }
lib/EcomDev/PHPUnit/Controller/Response/Interface.php ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PHP Unit test suite for Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ *
12
+ * @category EcomDev
13
+ * @package EcomDev_PHPUnit
14
+ * @copyright Copyright (c) 2011 Ecommerce Developers (http://www.ecomdev.org)
15
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
+ * @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
17
+ */
18
+
19
+ /**
20
+ * Interface for response object, that will be asserted
21
+ *
22
+ */
23
+ interface EcomDev_PHPUnit_Controller_Response_Interface
24
+ {
25
+ /**
26
+ * Returns rendered headers array that was sent,
27
+ * if headers was not sent, then returns null
28
+ *
29
+ * @return array|null
30
+ */
31
+ public function getSentHeaders();
32
+
33
+ /**
34
+ * Returns a particular header that was sent
35
+ *
36
+ * @param string $headerName
37
+ * @return string|false
38
+ */
39
+ public function getSentHeader($headerName);
40
+
41
+ /**
42
+ * Returns rendered response, if response was not sent,
43
+ * then it returns null
44
+ *
45
+ * @return string|null
46
+ */
47
+ public function getSentResponse();
48
+
49
+ /**
50
+ * Returns rendered body output
51
+ *
52
+ * @return string
53
+ */
54
+ public function getOutputBody();
55
+ }
lib/EcomDev/PHPUnit/Design/Package/Interface.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PHP Unit test suite for Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ *
12
+ * @category EcomDev
13
+ * @package EcomDev_PHPUnit
14
+ * @copyright Copyright (c) 2011 Ecommerce Developers (http://www.ecomdev.org)
15
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
+ * @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
17
+ */
18
+
19
+ /**
20
+ * Interface for assertions in layout configuration
21
+ *
22
+ */
23
+ interface EcomDev_PHPUnit_Design_Package_Interface
24
+ {
25
+ /**
26
+ * Asserts layout file existance in design packages,
27
+ * and returns actual and expected filenames as result
28
+ *
29
+ * @param string $fileName
30
+ * @param string $area
31
+ * @param string|null $designPackage if not specified any theme will be used
32
+ * @param string|null $theme if not specified any theme will be used
33
+ * @return array of 'expected' and 'actual' file names
34
+ */
35
+ public function getLayoutFileAssertion($fileName, $area, $designPackage = null, $theme = null);
36
+
37
+ }
lib/EcomDev/PHPUnit/Isolation/Interface.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PHP Unit test suite for Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ *
12
+ * @category EcomDev
13
+ * @package EcomDev_PHPUnit
14
+ * @copyright Copyright (c) 2011 Ecommerce Developers (http://www.ecomdev.org)
15
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
+ * @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
17
+ */
18
+
19
+ /**
20
+ * Isolation interface,
21
+ * should be implemented on resetable Magento entities,
22
+ * that should be isolated during the test
23
+ *
24
+ */
25
+ interface EcomDev_PHPUnit_Isolation_Interface
26
+ {
27
+ /**
28
+ * Unified method for reseting data
29
+ * in currently isolated object
30
+ *
31
+ */
32
+ public function reset();
33
+ }
lib/EcomDev/Utils/Reflection.php ADDED
@@ -0,0 +1,124 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PHP Unit test suite for Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ *
12
+ * @category EcomDev
13
+ * @package EcomDev_PHPUnit
14
+ * @copyright Copyright (c) 2011 Ecommerce Developers (http://www.ecomdev.org)
15
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
+ * @author Ivan Chepurnyi <ivan.chepurnyi@ecomdev.org>
17
+ */
18
+
19
+ class EcomDev_Utils_Reflection
20
+ {
21
+ /**
22
+ * Cache of reflection objects
23
+ *
24
+ * @var array
25
+ */
26
+ protected static $_reflectionCache = array();
27
+
28
+ /**
29
+ * Sets protected or private property value
30
+ *
31
+ * @param string|object $object class name
32
+ * @param string $property
33
+ * @param mixed $value
34
+ */
35
+ public static function setRestrictedPropertyValue($object, $property, $value)
36
+ {
37
+ if (version_compare(PHP_VERSION, '5.3.0', '<')) {
38
+ throw new RuntimeException('For setting of restricted properties via Reflection, PHP version should be 5.3.0 or later');
39
+ }
40
+
41
+ $reflectionObject = self::getRelflection($object);
42
+ $reflectionProperty = $reflectionObject->getProperty($property);
43
+ $reflectionProperty->setAccessible(true);
44
+ $reflectionProperty->setValue((is_string($object) ? null : $object), $value);
45
+ }
46
+
47
+ /**
48
+ * Gets protected or private property value
49
+ *
50
+ * @param string|object $object class name
51
+ * @param string $property
52
+ * @return mixed
53
+ */
54
+ public static function getRestrictedPropertyValue($object, $property)
55
+ {
56
+ if (version_compare(PHP_VERSION, '5.3.0', '<')) {
57
+ throw new RuntimeException('For getting of restricted properties via Reflection, PHP version should be 5.3.0 or later');
58
+ }
59
+
60
+ $reflectionObject = self::getRelflection($object);
61
+ $reflectionProperty = $reflectionObject->getProperty($property);
62
+ $reflectionProperty->setAccessible(true);
63
+ return $reflectionProperty->getValue((is_string($object) ? null : $object));
64
+ }
65
+
66
+
67
+ /**
68
+ * Calls private or protected method
69
+ *
70
+ * @param string|object $object
71
+ * @param string $method
72
+ * @param array $args
73
+ * @return mixed
74
+ */
75
+ public static function invokeRestrictedMethod($object, $method, $args = array())
76
+ {
77
+ if (version_compare(PHP_VERSION, '5.3.2', '<')) {
78
+ throw new RuntimeException('For invoking restricted methods via Reflection, PHP version should be 5.3.2 or later');
79
+ }
80
+
81
+ $reflectionObject = self::getRelflection($object);
82
+ $reflectionMethod = $reflectionObject->getMethod($method);
83
+ $reflectionMethod->setAccessible(true);
84
+
85
+ if (!empty($args)) {
86
+ return $reflectionMethod->invokeArgs((is_string($object) ? null : $object), $args);
87
+ }
88
+
89
+ return $reflectionMethod->invoke((is_string($object) ? null : $object));
90
+ }
91
+
92
+ /**
93
+ * Returns reflection object from instance or class name
94
+ *
95
+ * @param string|object $object
96
+ * @return ReflectionClass|ReflectionObject
97
+ */
98
+ public static function getRelflection($object)
99
+ {
100
+ // If object is a class name
101
+ if (is_string($object) && class_exists($object)) {
102
+ if (isset(self::$_reflectionCache[$object])) {
103
+ return self::$_reflectionCache[$object];
104
+ }
105
+ $reflection = new ReflectionClass($object);
106
+ self::$_reflectionCache[$object] = $reflection;
107
+ return $reflection;
108
+ }
109
+ // If object is an instance of a class
110
+ elseif (is_object($object)) {
111
+ $objectHash = spl_object_hash($object);
112
+ if (isset(self::$_reflectionCache[$objectHash])) {
113
+ return self::$_reflectionCache[$objectHash];
114
+ }
115
+ $reflection = new ReflectionObject($object);
116
+ self::$_reflectionCache[$objectHash] = $reflection;
117
+ return $reflection;
118
+ }
119
+ // In case of invalid argument
120
+ else {
121
+ throw new InvalidArgumentException('$object should be a valid class name or object instance');
122
+ }
123
+ }
124
+ }
lib/Oink/Data/dtos.php ADDED
@@ -0,0 +1,634 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Provides all Data Transfer Objects, DTOs, which can be used for
4
+ * moving data into & out of Oink services in a decoupled
5
+ * fashion
6
+ *
7
+ * @package Oink.Data.dtos
8
+ */
9
+
10
+ /**
11
+ * Result object used to transmit status of a web service call
12
+ */
13
+ class dtoResultObject
14
+ {
15
+ /**
16
+ * Describes any exceptions in the PHP client or errors in the webservice
17
+ * @var string
18
+ * @access public
19
+ */
20
+ var $ErrorMessage;
21
+ /**
22
+ * Indicates if the web method was executed properly
23
+ * @var bool
24
+ * @access public
25
+ */
26
+ var $Status;
27
+ /**
28
+ * An encrypted authentication key which needs to be used for all subsequent transactions
29
+ * @var guid
30
+ * @access public
31
+ */
32
+ var $Token;
33
+ /**
34
+ * @var string
35
+ * @access public
36
+ */
37
+ var $TransactionStatus;
38
+ /**
39
+ * Value that determines a transaction from system of origin
40
+ * @var string
41
+ * @access public
42
+ */
43
+ var $TransactionIdentifier;
44
+
45
+ /**
46
+ * Original XML response
47
+ * @var string
48
+ * @access public
49
+ */
50
+ var $Xml;
51
+
52
+ }
53
+ /**
54
+ * Oink user
55
+ */
56
+ class dtoUser extends dtoResultObject
57
+ {
58
+ var $UserType;
59
+ }
60
+ /**
61
+ * Oink children
62
+ */
63
+ class dtoChildren{
64
+ var $Name;
65
+ var $Token;
66
+ }
67
+ /**
68
+ * Oink payment account
69
+ */
70
+ class dtoPaymentAccount{
71
+ var $Type;
72
+ var $Name;
73
+ var $Token;
74
+ var $Url;
75
+ }
76
+ /**
77
+ * Oink specific configuration elements
78
+ */
79
+ class dtoPaymentGatewayConfiguration
80
+ {
81
+ /**
82
+ * Namespace for header properties
83
+ * @var string
84
+ * @access public
85
+ */
86
+ var $HeaderNamespace;
87
+ /**
88
+ * Header property for merchant identifier value
89
+ */
90
+ var $propMerchantIdentifier;
91
+ /**
92
+ * Header property for api key value
93
+ */
94
+ var $propApiKey;
95
+ /**
96
+ * URI for the Oink Transaction service
97
+ */
98
+ var $TransactionServiceEndpointAddress;
99
+ /**
100
+ * URI for the Oink Transaction service WSDL
101
+ */
102
+ var $TransactionServiceEndpointAddressWsdl;
103
+ /**
104
+ * URI for the Oink Parent service
105
+ */
106
+ var $ParentServiceEndpointAddress;
107
+ /**
108
+ * URI for the Oink Parent service WSDL
109
+ */
110
+ var $ParentServiceEndpointAddressWsdl;
111
+ /**
112
+ * Value required to be passed in all webservice calls for authentication.
113
+ * Will be provided to the merchant by Oink
114
+ */
115
+ var $MerchantIdentifier;
116
+ /**
117
+ * Value required to be passed in all webservice calls for authentication
118
+ * Will be provided to the merchant by Oink
119
+ */
120
+ var $APIkey;
121
+ /**
122
+ * The currency in which the transaction is being sent to Oink
123
+ */
124
+ var $Currency;
125
+ /**
126
+ * The desired default ship method that a merchant decides. There can only be
127
+ * one shipping method per merchant application.
128
+ */
129
+ var $DefaultShipmentMethod;
130
+
131
+ }
132
+ /**
133
+ * Used to pass authentication credential to Oink services
134
+ */
135
+ class dtoCredentials
136
+ {
137
+
138
+ var $userName;
139
+ var $password;
140
+ }
141
+ class dtoProfileInfo
142
+ {
143
+ var $Age;
144
+ var $Gender;
145
+ var $ErrorMessage;
146
+ }
147
+ class dtoAddressRequestFormConfiguration
148
+ {
149
+ var $PostAction;
150
+ var $MerchantIdentifier;
151
+ var $Url;
152
+ var $ButtonHtml;
153
+ }
154
+ class dtoCheckoutFormConfiguration extends dtoAddressRequestFormConfiguration
155
+ {
156
+ var $Description;
157
+ var $Data;
158
+ var $TransactionIdentifier;
159
+ var $Amount;
160
+ var $ExpiryDate;
161
+ var $ChildIdentifier;
162
+ var $ItemIdentifier;
163
+ var $Currency;
164
+ var $ErrorUrl;
165
+ var $ParentIdentifier;
166
+ var $GuestChildName;
167
+ var $NotifyChild;
168
+ var $DeliveryToChildAddress;
169
+ var $PaymentAccountIdentifier;
170
+ var $ExternalLoginFlag;
171
+ var $Token;
172
+ var $Value;
173
+ }
174
+ /**
175
+ * Obtained from forms integration address request
176
+ */
177
+ class dtoAddressRequest
178
+ {
179
+ var $State;
180
+ var $Zip;
181
+ var $Token;
182
+ var $MerchantIdentifier;
183
+ }
184
+ /**
185
+ * Used to pass address information from Oink
186
+ */
187
+ class dtoAddress
188
+ {
189
+
190
+ var $Status;
191
+ var $ErrorMessage;
192
+ var $Address;
193
+ var $City;
194
+ var $State;
195
+ var $Zip;
196
+ var $Country;
197
+ var $Phone;
198
+ var $ParentName;
199
+ var $ParentEmail;
200
+ var $ChildName;
201
+ /**
202
+ * Method to serialize an address to Oink specific XML
203
+ */
204
+ public function ToXml()
205
+ {
206
+
207
+ $doc = new DOMDocument();
208
+
209
+ $shipment = $this->getXmlElement($doc);
210
+
211
+ $doc->formatOutput = true;
212
+ return $doc->saveXML($shipment);
213
+ }
214
+
215
+ public function getXmlElement($doc){
216
+ $shipment = $doc->createElement('shipment-address');
217
+ $doc->appendChild($shipment);
218
+
219
+ $elements = $this->_getXmlElements();
220
+
221
+ foreach ($elements as $key => $content) {
222
+ $newElementCDATA = $doc->createCDATASection($content);
223
+ $newElement = $doc->createElement($key);
224
+ $newElement->appendChild($newElementCDATA);
225
+ $shipment->appendChild($newElement);
226
+ }
227
+
228
+ return $shipment;
229
+ }
230
+
231
+ protected function _getXmlElements()
232
+ {
233
+ return array(
234
+ 'address' => $this->Address,
235
+ 'zip' => $this->Zip,
236
+ 'city' => $this->City,
237
+ 'state' => $this->State,
238
+ 'country' => $this->Country,
239
+ 'phone' => $this->Phone,
240
+ 'name' => $this->ParentName,
241
+ 'attention-of' => $this->ChildName,
242
+ );
243
+ }
244
+
245
+ }
246
+ /**
247
+ * The cart contains credit card charge information and product purchase information
248
+ */
249
+ class dtoWishlist
250
+ {
251
+
252
+ public function AddItem(dtoWishlistItem $item)
253
+ {
254
+ array_push($this->Items, $item);
255
+ }
256
+
257
+ var $Items = array();
258
+
259
+ /**
260
+ * Used to serialize shopping cart elements to Oink specific XML
261
+ */
262
+ public function ToXml()
263
+ {
264
+ $doc = new DOMDocument();
265
+ $items = $doc->createElement('items');
266
+ $doc->appendChild($items);
267
+
268
+ foreach ($this->Items as $item) {
269
+ $items->appendChild($item->getXmlNode($doc));
270
+ }
271
+
272
+ $doc->formatOutput = true;
273
+ return $doc->saveXML($items);
274
+ }
275
+ }
276
+
277
+
278
+ /**
279
+ * The cart contains credit card charge information and product purchase information
280
+ */
281
+ class dtoCart
282
+ {
283
+
284
+ function __construct()
285
+ {
286
+ $this->ShipmentAddress = new dtoAddress();
287
+ }
288
+
289
+ public function AddItem(dtoCartItem $item)
290
+ {
291
+ array_push($this->Items, $item);
292
+ }
293
+
294
+ var $Currency;
295
+ var $Total;
296
+ var $ShippmentTotal;
297
+ /**
298
+ * This is the tax applied to a order. This is not a mandatory field
299
+ */
300
+ var $Tax;
301
+ var $Cost;
302
+ /**
303
+ * This is the discount amount applied to an order
304
+ */
305
+ var $Discount;
306
+ var $ShipmentAddress;
307
+ var $Items = array();
308
+
309
+ /**
310
+ * Used to serialize shopping cart elements to Oink specific XML
311
+ */
312
+ public function ToXml()
313
+ {
314
+ $doc = new DOMDocument();
315
+
316
+ $cart = $doc->createElement('cart');
317
+ $cart->setAttribute("currency", $this->Currency);
318
+ $cart->setAttribute("total",number_format($this->Total, 2, '.', ''));
319
+ $doc->appendChild($cart);
320
+
321
+ $cartShipment = $doc->createElement('cart-shipment');
322
+ $cartShipment->setAttribute("total",number_format($this->ShippmentTotal, 2, '.', ''));
323
+ $cart->appendChild($cartShipment);
324
+
325
+ $elements = $this->_getXmlElements();
326
+
327
+ foreach ($elements as $key => $total) {
328
+ $newElement = $doc->createElement($key);
329
+ $newElement->setAttribute("total", number_format($total, 2, '.', ''));
330
+ $cartShipment->appendChild($newElement);
331
+ }
332
+
333
+ $shipmentAddress = $this->ShipmentAddress->getXmlElement($doc);
334
+ $cartShipment->appendChild($shipmentAddress);
335
+
336
+ $items = $doc->createElement('items');
337
+ $cartShipment->appendChild($items);
338
+
339
+ foreach ($this->Items as $item) {
340
+ $items->appendChild($item->getXmlNode($doc));
341
+ }
342
+
343
+ $doc->formatOutput = true;
344
+ return '<?xml version="1.0" encoding="UTF-8"?>' . "\n" . $doc->saveXML($cart);
345
+ }
346
+
347
+ public function toEscapedXml()
348
+ {
349
+ return htmlspecialchars($this->ToXml(), ENT_QUOTES);
350
+ }
351
+
352
+ protected function _getXmlElements()
353
+ {
354
+ return array(
355
+ 'shipment-tax' => $this->Tax,
356
+ 'shipment-cost' => $this->Cost,
357
+ 'shipment-discount' => $this->Discount,
358
+ );
359
+ }
360
+ }
361
+
362
+
363
+ /**
364
+ * The subscription contains the subscription period information and subscription cost
365
+ */
366
+ class dtoSubscription
367
+ {
368
+ var $Currency;
369
+ var $Total;
370
+ /**
371
+ * This is the subscription expiration date
372
+ */
373
+ var $ExpirationDate;
374
+ /**
375
+ * This is the subscription period. An example could be "Monthly"
376
+ */
377
+ var $Period;
378
+
379
+ /**
380
+ * Used to serialize the subscription to Oink specific XML
381
+ * Example : <subscription period="Weekly"><initial-cost currency="USD" value="12" /><expiry date="2012-12-05" /></subscription>
382
+ */
383
+ public function ToXml()
384
+ {
385
+
386
+ $doc = new DOMDocument();
387
+
388
+ $subscription = $doc->createElement('subscription');
389
+ $subscription->setAttribute("period", $this->Period);
390
+ $doc->appendChild($subscription);
391
+
392
+ $initialCost = $doc->createElement('initial-cost');
393
+ $initialCost->setAttribute("currency", $this->Currency);
394
+ $initialCost->setAttribute("value", $this->Total);
395
+ $subscription->appendChild($initialCost);
396
+
397
+ $expiry = $doc->createElement('expiry');
398
+ $expiry->setAttribute("date", $this->ExpirationDate);
399
+ $subscription->appendChild($expiry);
400
+
401
+ $doc->formatOutput = true;
402
+ return $doc->saveXML($subscription);
403
+
404
+ }
405
+
406
+ public function toEscapedXml()
407
+ {
408
+ return htmlspecialchars($this->ToXml(), ENT_QUOTES);
409
+ }
410
+ }
411
+
412
+
413
+ /**
414
+ This are the line items of an order which contain specific information about the product purchased.
415
+ * "Items" are not mandatory and instances of an item can occur multiple times to represent multiple
416
+ * products being purchased.
417
+ */
418
+ class dtoCartItem
419
+ {
420
+ /**
421
+ *
422
+ * This is the name of a product. For example,
423
+ * ======================================================
424
+ * Lego Star Wars Plo Koon's Jedi Starfighter
425
+ */
426
+ var $Name;
427
+ /**
428
+ *
429
+ * This is a brief description of a product. For example,
430
+ * ======================================================
431
+ * LEGO Star Wars Plo Koon's Jedi Starfighter (8093). Lead the search for General Grievous with Jedi Master Plo Koon! Jedi Master Plo Koon, leader of a Clone Army taskforce, scours the spacelanes for General Grievous' new superweapon, Malevolence, as seen in Star Wars: The Clone Wars. If the mission proves too dangerous, Plo Koon can eject from his starfighter and live to fight the Separatists another day! Set includes Jedi Master Plo Koon minifigure, new R7-D4 astromech droid and Jedi starfighter with ejection seat in the cockpit.
432
+ * The LEGO Star Wars Plo Koon's Jedi Starfighter (8093) features:
433
+ * Set contains 175 pieces
434
+ * Includes Jedi Master Plo Koon minifigure and a new R7-D4 astromech droid
435
+ * Plo Koon's starfighter features cockpit ejection seat
436
+ * Plo Koon's Starfighter measures 10" (26 cm) long!
437
+ */
438
+ var $Description;
439
+ /**
440
+ * This is the unit price for a product.
441
+ */
442
+ var $Price;
443
+ /**
444
+ * These are the amount of units of a product which are being purchased.
445
+ */
446
+ var $Quantity;
447
+ /**
448
+ * This is the line item total. Equivalent to unit price multiplied by quantity.
449
+ */
450
+ var $Total;
451
+ /**
452
+ * Used to serialize line items to Oink specific XML
453
+ */
454
+ public function ToXml()
455
+ {
456
+
457
+ $doc = new DOMDocument();
458
+
459
+ $item= $this->getXmlNode($doc);
460
+ $doc->appendChild($item);
461
+
462
+ $doc->formatOutput = true;
463
+ return $doc->saveXML($total);
464
+ }
465
+
466
+ public function toEscapedXml()
467
+ {
468
+ return htmlspecialchars($this->ToXml(), ENT_QUOTES);
469
+ }
470
+
471
+ public function getXmlNode($doc){
472
+ $item = $doc->createElement('item');
473
+ $item->setAttribute("total", $this->Total);
474
+
475
+ $elements = $this->_getXmlElements();
476
+
477
+ foreach ($elements as $key => $content) {
478
+ $newElement = $doc->createElement($key);
479
+ if(!empty($content)){
480
+ $newElementCDATA = $doc->createCDATASection($content);
481
+ $newElement->appendChild($newElementCDATA);
482
+ }
483
+ $item->appendChild($newElement);
484
+ }
485
+ return $item;
486
+ }
487
+
488
+ protected function _getXmlElements()
489
+ {
490
+ return array(
491
+ 'item-name' => $this->Name,
492
+ 'item-description' => $this->Description,
493
+ 'item-price' => $this->Price,
494
+ 'item-quantity' => $this->Quantity,
495
+ );
496
+ }
497
+
498
+ }
499
+ class dtoWishlistStatus
500
+ {
501
+ var $Children;
502
+ var $ErrorMessage;
503
+ var $Status;
504
+ var $Token;
505
+ var $TransactionStatus;
506
+ }
507
+
508
+ class dtoWishlistItem
509
+ {
510
+ /**
511
+ * Item SKU
512
+ */
513
+ var $Identifier;
514
+ /**
515
+ * The URL of the product on the merchant's site
516
+ */
517
+ var $Url;
518
+ /**
519
+ * This is a brief description of a product. For example,
520
+ */
521
+ var $Description;
522
+
523
+ public function ToXml()
524
+ {
525
+
526
+ $doc = new DOMDocument();
527
+
528
+ $item= $this->getXmlNode($doc);
529
+ $doc->appendChild($item);
530
+
531
+ $doc->formatOutput = true;
532
+ return $doc->saveXML($total);
533
+ }
534
+
535
+ public function toEscapedXml()
536
+ {
537
+ return htmlspecialchars($this->ToXml(), ENT_QUOTES);
538
+ }
539
+
540
+ public function getXmlNode($doc){
541
+ $item = $doc->createElement('item');
542
+ $elements = $this->_getXmlElements();
543
+
544
+ foreach ($elements as $key => $content) {
545
+ $newElementCDATA = $doc->createTextNode($content);
546
+ $newElement = $doc->createElement($key);
547
+ $newElement->appendChild($newElementCDATA);
548
+ $item->appendChild($newElement);
549
+ }
550
+ return $item;
551
+ }
552
+
553
+ protected function _getXmlElements()
554
+ {
555
+ return array(
556
+ 'Identifier' => $this->Identifier,
557
+ 'Url' => $this->Url,
558
+ 'Description' => $this->Description
559
+ );
560
+ }
561
+ }
562
+ /**
563
+ * This object contains the information ralted to the status of a transaction which Oink
564
+ * sends after a transaction is approved.
565
+ */
566
+ class dtoTransactionStatus
567
+ {
568
+ /**
569
+ * The Oink id for this transaction
570
+ */
571
+ var $id;
572
+ /**
573
+ * The current status of a transaction. The possible values are:
574
+ * Processed: The transaction was processed, the payment was processed.
575
+ * ApprovalPending: The transaction requires parent approval as the parent has already been notified and it will not be processed until the parent approved it.
576
+ * LimitsExceeded: The transaction could not be processed if the child exceeded the limits set by their parents.
577
+ * Error: A general error prevented the transaction from being processed. A message will be shown in the UI for the reason.
578
+ */
579
+ var $Status;
580
+ /**
581
+ * The website url provided by the merchant
582
+ */
583
+ var $Url;
584
+ /**
585
+ * Any error messages related to this transaction
586
+ */
587
+ var $errorMessage;
588
+ /**
589
+ * The merchant identifier provided by Oink
590
+ */
591
+ var $MerchantIdentifier;
592
+ /**
593
+ * The transaction identifier provided by the merchant to identify a transaction in their ecommerce system
594
+ */
595
+ var $TransactionIdentifier;
596
+ /**
597
+ * The original description provided by the merchant
598
+ */
599
+ var $Description;
600
+ /**
601
+ * The transaction amount
602
+ */
603
+ var $Amount;
604
+ /**
605
+ * The transaction expiration date if provided by the merchant
606
+ */
607
+ var $ExpiryDate;
608
+ /**
609
+ * The XML document describing the transaction if provided by the merchant
610
+ */
611
+ var $Data;
612
+ /**
613
+ * Parent or guest address associated to the transaction
614
+ */
615
+ var $Address;
616
+ /**
617
+ * Parent or guest city associated to the transaction
618
+ */
619
+ var $City;
620
+ /**
621
+ * Parent or guest zip code associated to the transaction
622
+ */
623
+ var $Zip;
624
+ /**
625
+ * Parent or guest state associated to the transaction
626
+ */
627
+ var $State;
628
+ /**
629
+ * Parent or guest country associated to the transaction
630
+ */
631
+ var $Country;
632
+ }
633
+
634
+ ?>
lib/Oink/Schemas/cart.xml ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <vp:cart
3
+ xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
4
+ xmlns:vp='null'
5
+ xsi:schemaLocation='null https://development.oink.com/Schemas/Oink.xsd'>
6
+ <vp:cart-shipment total="5.00">
7
+ <vp:shipment-tax total="0.00"></vp:shipment-tax>
8
+ <vp:items>
9
+ <vp:item total="5.00">
10
+ <vp:item-name>Buzz lightyear</vp:item-name>
11
+ <vp:item-description>Toystory toy</vp:item-description>
12
+ <vp:item-price>5.00</vp:item-price>
13
+ <vp:item-quantity>1</vp:item-quantity>
14
+ </vp:item>
15
+ </vp:items>
16
+ </vp:cart-shipment>
17
+ </vp:cart>
lib/Oink/Schemas/cart_02.xml ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!--
3
+ To change this template, choose Tools | Templates
4
+ and open the template in the editor.
5
+ -->
6
+
7
+
8
+ <ns1:cart
9
+ xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
10
+ xmlns:ns1='null'
11
+ xsi:schemaLocation='null Oink.xsd'>
12
+ <ns1:cart-shipment total="5.00">
13
+ <ns1:shipment-tax total="0.00"></ns1:shipment-tax>
14
+ <ns1:shipment-cost total="0.00"></ns1:shipment-cost>
15
+ <ns1:shipment-discount total="0.00"></ns1:shipment-discount>
16
+ <ns1:reward-points total="0"></ns1:reward-points>
17
+ <ns1:shipment-address>
18
+ <ns1:address>1234 easy st</ns1:address>
19
+ <ns1:zip>91367</ns1:zip>
20
+ <ns1:city>woodland</ns1:city>
21
+ <ns1:state>ca</ns1:state>
22
+ <ns1:country>US</ns1:country>
23
+ <ns1:phone>555.555.5555</ns1:phone>
24
+ <ns1:name>parent</ns1:name>
25
+ <ns1:attention-of>kid</ns1:attention-of>
26
+ </ns1:shipment-address>
27
+ <ns1:items>
28
+ <ns1:item total="5.00">
29
+ <ns1:item-identifier>toy01</ns1:item-identifier>
30
+ <ns1:item-name>fun toy</ns1:item-name>
31
+ <ns1:item-description>a really cool toy</ns1:item-description>
32
+ <ns1:item-price>5.00</ns1:item-price>
33
+ <ns1:item-quantity>1</ns1:item-quantity>
34
+ </ns1:item>
35
+ </ns1:items>
36
+ </ns1:cart-shipment>
37
+
38
+ </ns1:cart>
lib/Oink/Schemas/cart_03.xml ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="utf-8" ?>
2
+ <cart currency="USD" total="57.168">
3
+ <cart-shipment total="57.168">
4
+ <shipment-tax total="2.2" />
5
+ <shipment-cost total="4.5" />
6
+ <shipment-discount total="1.5" />
7
+ <shipment-address>
8
+ <address>Gates Avenue</address>
9
+ <zip>12345</zip>
10
+ <city>New York</city>
11
+ <state>UTJR</state>
12
+ <country>US</country>
13
+ <phone>1234579</phone>
14
+ <name>Parent</name>
15
+ <attention-of>Child</attention-of>
16
+ </shipment-address>
17
+ <items>
18
+ <item total="12.234">
19
+ <item-name>The name</item-name>
20
+ <item-description>The description</item-description>
21
+ <item-price>12.234</item-price>
22
+ <item-quantity>1</item-quantity>
23
+ </item>
24
+ </items>
25
+ </cart-shipment>
26
+ </cart>
lib/Oink/Schemas/cart_04.xml ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="utf-8" ?>
2
+ <cart currency="USD" total="18.00">
3
+ <cart-shipment total="18.00">
4
+ <shipment-tax total="0.0" />
5
+ <shipment-cost total="0.0" />
6
+ <items>
7
+ <item total="18.00">
8
+ <item-name>Mega Bloks Halo Wars</item-name>
9
+ <item-description>Mega Bloks Halo Wars - UNSC Gremlin (96818)</item-description>
10
+ <item-price>18.00</item-price>
11
+ <item-quantity>1</item-quantity>
12
+ </item>
13
+ </items>
14
+ </cart-shipment>
15
+ </cart>
lib/Oink/Schemas/oink.xsd ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
3
+ <xs:element name="cart">
4
+ <xs:complexType>
5
+ <xs:sequence>
6
+ <xs:element name="cart-shipment">
7
+ <xs:complexType>
8
+ <xs:sequence>
9
+ <xs:element name="shipment-tax">
10
+ <xs:complexType>
11
+ <xs:attribute name="total" type="xs:decimal" use="required" />
12
+ </xs:complexType>
13
+ </xs:element>
14
+ <xs:element name="shipment-cost" minOccurs="0" maxOccurs="1">
15
+ <xs:complexType>
16
+ <xs:attribute name="total" type="xs:decimal" use="required" />
17
+ </xs:complexType>
18
+ </xs:element>
19
+ <xs:element name="shipment-discount" minOccurs="0" maxOccurs="1">
20
+ <xs:complexType>
21
+ <xs:attribute name="total" type="xs:decimal" use="required" />
22
+ </xs:complexType>
23
+ </xs:element>
24
+ <xs:element name="reward-points" minOccurs="0" maxOccurs="1" >
25
+ <xs:complexType>
26
+ <xs:attribute name="total" type="xs:decimal" use="required" />
27
+ </xs:complexType>
28
+ </xs:element>
29
+ <xs:element name="shipment-address" minOccurs="0" maxOccurs="1">
30
+ <xs:complexType>
31
+ <xs:sequence>
32
+ <xs:element name="address" />
33
+ <xs:element name="zip" />
34
+ <xs:element name="city" />
35
+ <xs:element name="state" />
36
+ <xs:element name="country" minOccurs="0" maxOccurs="1" />
37
+ <xs:element name="phone" minOccurs="0" maxOccurs="1" />
38
+ <xs:element name="name" minOccurs="0" maxOccurs="1" />
39
+ <xs:element name="attention-of" minOccurs="0" maxOccurs="1" />
40
+ </xs:sequence>
41
+ </xs:complexType>
42
+ </xs:element>
43
+ <xs:element name="items">
44
+ <xs:complexType>
45
+ <xs:sequence>
46
+ <xs:element minOccurs="1" maxOccurs="unbounded" name="item">
47
+ <xs:complexType>
48
+ <xs:sequence>
49
+ <xs:element name="item-identifier" type="xs:string" minOccurs="0" />
50
+ <xs:element name="item-name" type="xs:string" />
51
+ <xs:element name="item-description" type="xs:string" />
52
+ <xs:element name="item-price" type="xs:decimal" />
53
+ <xs:element name="item-quantity" type="xs:int" />
54
+ </xs:sequence>
55
+ <xs:attribute name="total" type="xs:decimal" use="required" />
56
+ </xs:complexType>
57
+ </xs:element>
58
+ </xs:sequence>
59
+ </xs:complexType>
60
+ </xs:element>
61
+ </xs:sequence>
62
+ <xs:attribute name="total" type="xs:decimal" use="required" />
63
+ </xs:complexType>
64
+ </xs:element>
65
+ </xs:sequence>
66
+ <xs:attribute name="currency" type="xs:string" use="optional" default="USD" />
67
+ <xs:attribute name="total" type="xs:decimal" use="required" />
68
+ </xs:complexType>
69
+ </xs:element>
70
+ </xs:schema>
lib/Oink/Services/Implementations/FormPaymentServiceConfiguration.php ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Oink.Services.Implementations
4
+ */
5
+ class FormPaymentServiceConfiguration implements IPaymentServiceConfiguration
6
+ {
7
+ public function GetServiceConfiguration()
8
+ {
9
+ $config = new dtoPaymentGatewayConfiguration();
10
+ return $config;
11
+
12
+ }
13
+ }
14
+ ?>
lib/Oink/Services/Implementations/MagentoPaymentServiceConfiguration.php ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Oink.Services.Implementations
4
+ */
5
+ class MagentoPaymentServiceConfiguration implements IPaymentServiceConfiguration
6
+ {
7
+ public function GetServiceConfiguration()
8
+ {
9
+ $config = new dtoPaymentGatewayConfiguration();
10
+ return $config;
11
+ }
12
+ }
13
+ ?>
lib/Oink/Services/Implementations/MerchantFormServiceConfiguration.php ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class MerchantFormServiceConfiguration implements IFormServiceConfiguration
4
+ {
5
+ public function GetAddressRequestFormConfiguration(){
6
+ $config = new dtoAddressRequestFormConfiguration();
7
+ $config->MerchantIdentifier = "be8d78b5-a156-4548-a00d-d3d4386f7426";
8
+ $config->PostAction = "https://localhost:8181/FormPost/Submit";
9
+ $config->Url = "http://localhost/vpintegration/trunk/PHP/Research/generic/checkout-forms-dynamicshipping.php";
10
+ $config->ButtonHtml = '<input type="submit" value="Calculate Shipping" class="magentobutton" />';
11
+ return $config;
12
+ }
13
+ public function GetPreAuthorizedCheckoutFormConfiguration(){
14
+ $config = new dtoCheckoutFormConfiguration();
15
+ $config->PostAction = "https://localhost:8181/FormPost/Submit";
16
+ $config->MerchantIdentifier = "be8d78b5-a156-4548-a00d-d3d4386f7426";
17
+ $config->Url = "http://localhost/vpintegration/trunk/PHP/Research/generic/checkout-forms-confirmation.htm";
18
+ $config->ButtonHtml = '<input type="submit" value="Place Order" class="magentobutton" />';
19
+ $config->Description = "testdesc";
20
+ $config->TransactionIdentifier = "ID:1234567";
21
+ $config->Amount = "13.13";
22
+ $config->Currency = "USD";
23
+ $config->ErrorUrl = "http://www.playdin.com";
24
+ return $config;
25
+ }
26
+ public function GetCheckoutFormConfiguration(){
27
+ $config = new dtoCheckoutFormConfiguration();
28
+ $config->PostAction = "https://localhost:8181/Checkout/Submit";
29
+ $config->MerchantIdentifier = "be8d78b5-a156-4548-a00d-d3d4386f7426";
30
+ $config->Url = "http://localhost/vpintegration/trunk/PHP/Research/generic/checkout-forms-confirmation.htm";
31
+ $config->ButtonHtml = '<input type="submit" value="Place Order" class="magentobutton" />';
32
+ $config->Description = "testdesc";
33
+ //$config->Data = "";
34
+ $config->TransactionIdentifier = "ID:1234567";
35
+ $config->Amount = "13.13";
36
+ //$config->ExpiryDate = "";
37
+ //$config->ChildIdentifier = "";
38
+ //$config->ItemIdentifier = "";
39
+ $config->Currency = "USD";
40
+ $config->ErrorUrl = "http://www.playdin.com";
41
+ //$config->ParentIdentifier = "";
42
+ //$config->GuestChildName = "";
43
+ //$config->NotifyChild = "";
44
+ //$config->DeliveryToChildAddress = "";
45
+ //$config->PaymentAccountIdentifier = "";
46
+ //$config->ExternalLoginFlag = "";
47
+ //$config->Token = "";
48
+ //$config->Value = "";
49
+ return $config;
50
+ }
51
+
52
+ }
53
+ ?>
lib/Oink/Services/Implementations/MerchantPaymentServiceConfiguration.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Oink.Services.Implementations
4
+ */
5
+ class MerchantPaymentServiceConfiguration implements IPaymentServiceConfiguration
6
+ {
7
+ public function GetServiceConfiguration()
8
+ {
9
+ $config = new dtoPaymentGatewayConfiguration();
10
+ /* ================================
11
+ Define all variables to be used for client soap call
12
+ ================================ */
13
+ $config->HeaderNamespace = "vp";
14
+ $config->propMerchantIdentifier = "MerchantIdentifier";
15
+ $config->propApiKey = "APIkey";
16
+ $config->TransactionServiceEndpointAddress = "https://development.oink.com/Services/TransactionService.svc";
17
+ $config->TransactionServiceEndpointAddressWsdl = "https://development.oink.com/services/TransactionService.svc?wsdl";
18
+ $config->ParentServiceEndpointAddress = "https://development.oink.com/services/JSON/ParentService.svc";
19
+ $config->ParentServiceEndpointAddressWsdl = "https://development.oink.com/services/JSON/ParentService.svc?wsdl";
20
+
21
+ $config->MerchantIdentifier = "03d081e1-2d57-4c98-8f1b-bbb83d4ab14a";
22
+ $config->APIkey = "gadgetboom123";
23
+ $config->Currency = "USD";
24
+ $config->DefaultShipmentMethod = "Delivery";
25
+ return $config;
26
+ }
27
+ }
28
+ ?>
lib/Oink/Services/Implementations/MockCartService.php ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Oink.Services.Implementations
4
+ */
5
+ class MockCartService implements ICartService{
6
+
7
+
8
+ public function GetCurrentCart(){
9
+
10
+ $cart = new dtoCart();
11
+ $cart->Currency = "USD";
12
+ $cart->Total = 10.00;
13
+ $cart->ShippmentTotal = 0;
14
+ $cart->Tax = 0;
15
+ $cart->Cost = 0;
16
+ $cart->Discount = 0;
17
+
18
+ $address = new dtoAddress();
19
+ $address->Address = "134 Easy st";
20
+ $address->Zip = "91367";
21
+ $address->State = "CA";
22
+ $address->City = "Woodland Hills";
23
+ $address->Country = "US";
24
+ $address->Phone = "555.555.5555";
25
+ $address->ParentName = "Alfredo Carranza";
26
+ $address->ChildName = "Joaquin Carranza";
27
+ $cart->ShipmentAddress = $address;
28
+
29
+ $item = new dtoCartItem();
30
+ $item->Total = 4.50;
31
+ $item->Name = "Mock item";
32
+ $item->Description = "Mock description";
33
+ $item->Price = 4.50;
34
+ $item->Quantity = 1;
35
+ $cart->AddItem(($item));
36
+
37
+ $item_2 = new dtoCartItem();
38
+ $item_2->Total = 5.50;
39
+ $item_2->Name = "Mock item number 2";
40
+ $item_2->Description = "Mock description number 2";
41
+ $item_2->Price = 5.50;
42
+ $item_2->Quantity = 1;
43
+ $cart->AddItem(($item_2));
44
+ return $cart;
45
+ }
46
+
47
+ public function GetCurrentSubscription(){
48
+
49
+ $subscription = new dtoSubscription();
50
+ $subscription->Currency = 'USD';
51
+ $subscription->ExpirationDate = '2012-12-05';
52
+ $subscription->Period = 'Weekly';
53
+ $subscription->Total = 12;
54
+ return $subscription;
55
+ }
56
+
57
+ public function GetCurrentWishlist(){
58
+ /*
59
+
60
+ <?xml version='1.0' encoding='utf-8' ?><items><item><Identifier>Mega Bloks Halo Wars - UNSC Gremlin (96818)</Identifier><Url>www.google.com</Url><Description>69F73096-F298-44BF-A32D-DE39493D2A09</Description></item></items>
61
+ */
62
+
63
+ $wishlist = new dtoWishlist();
64
+
65
+ $item = new dtoWishlistItem();
66
+ $item->Identifier = "123792359723";
67
+ $item->Description = "The Get Up Kids: Band Camp Pullover Hoodie";
68
+ $item->Url = "http://ecommercesite.com/product/hoodie-192.html";
69
+ $wishlist->AddItem(($item));
70
+
71
+ return $wishlist;
72
+ }
73
+
74
+
75
+ }
76
+
77
+
78
+ ?>
lib/Oink/Services/Implementations/OinkCallbackService.php ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @package Oink.Services.Implementations
5
+ */
6
+ class OinkCallbackService implements ICallbackService {
7
+
8
+ public function GetCallbackAddressInformation()
9
+ {
10
+ $address = new dtoAddressRequest();
11
+
12
+ if (isset($_POST['MerchantIdentifier']))
13
+ {
14
+ $address->MerchantIdentifier = $_POST['MerchantIdentifier'];
15
+ }
16
+ if (isset($_POST['Token']))
17
+ {
18
+ $address->Token = $_POST['Token'];
19
+ }
20
+ if (isset($_POST['Value']))
21
+ {
22
+ $location = $_POST['Value'];
23
+ $location_array = explode(";", $location);
24
+ $state;
25
+ $zip;
26
+ foreach ($location_array as $value){
27
+ if(strlen($value) == 2){
28
+ $address->State = $value;
29
+ }
30
+ else{
31
+ $address->Zip = $value;
32
+ }
33
+ }
34
+ }
35
+ return $address;
36
+ }
37
+
38
+ public function GetCallbackTransactionStatus() {
39
+ $status = new dtoTransactionStatus();
40
+ if (isset($_POST['id']))
41
+ $status->id = $_POST['id'];
42
+ if (isset($_POST['Status']))
43
+ $status->Status = $_POST['Status'];
44
+ if (isset($_POST['Url']))
45
+ $status->Url = $_POST['Url'];
46
+ if (isset($_POST['errorMessage']))
47
+ $status->errorMessage = $_POST['errorMessage'];
48
+ if (isset($_POST['MerchantIdentifier']))
49
+ $status->MerchantIdentifier = $_POST['MerchantIdentifier'];
50
+ if (isset($_POST['TransactionIdentifier']))
51
+ $status->TransactionIdentifier = $_POST['TransactionIdentifier'];
52
+ if (isset($_POST['Description']))
53
+ $status->Description = $_POST['Description'];
54
+ if (isset($_POST['Amount']))
55
+ $status->Amount = $_POST['Amount'];
56
+ if (isset($_POST['ExpiryDate']))
57
+ $status->ExpiryDate = $_POST['ExpiryDate'];
58
+ if (isset($_POST['Data']))
59
+ $status->Data = $_POST['Data'];
60
+ if (isset($_POST['Address']))
61
+ $status->Address = $_POST['Address'];
62
+ if (isset($_POST['City']))
63
+ $status->City = $_POST['City'];
64
+ if (isset($_POST['Zip']))
65
+ $status->Zip = $_POST['Zip'];
66
+ if (isset($_POST['State']))
67
+ $status->State = $_POST['State'];
68
+ if (isset($_POST['Country']))
69
+ $status->Country = $_POST['Country'];
70
+ return $status;
71
+ }
72
+
73
+ }
74
+
75
+ ?>
lib/Oink/Services/Implementations/OinkException.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class OinkException extends Exception{
3
+
4
+ public function __toString() {
5
+ return $this->getMessage();
6
+ }
7
+
8
+ }
9
+ ?>
lib/Oink/Services/Implementations/OinkFormService.php ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @package Oink.Services.Implementations
5
+ */
6
+ class OinkFormService implements IFormService {
7
+
8
+ private function _GenerateInputElement($name, $variable)
9
+ {
10
+ $input = "";
11
+ if(isset($variable)){
12
+ $value = $variable;
13
+ $input = '<input type="hidden" name="'.$name.'" value="'.$variable.'" />';
14
+ }
15
+ echo $input;
16
+ }
17
+
18
+ public function GenerateAddressRequestForm($config)
19
+ {
20
+ ?>
21
+ <form action="<?php echo $config->PostAction; ?>" method="post" id="login">
22
+ <input type="hidden" name="MerchantIdentifier" value="<?php echo $config->MerchantIdentifier; ?>" />
23
+ <input type="hidden" name="Url" value="<?php echo $config->Url; ?>" />
24
+ <input type="hidden" name="Lookup" value="State;Zip" />
25
+ <?php echo $config->ButtonHtml; ?>
26
+ </form>
27
+ <?php
28
+ }
29
+
30
+ public function GenerateCheckoutForm($config)
31
+ {
32
+ ?>
33
+ <form action="<?php echo $config->PostAction; ?>" method="post" id="login" name="login">
34
+ <?php
35
+ $this->_GenerateInputElement("MerchantIdentifier",$config->MerchantIdentifier);
36
+ $this->_GenerateInputElement("Url", $config->Url);
37
+ $this->_GenerateInputElement("Description", $config->Description);
38
+ $this->_GenerateInputElement("Data", $config->Data);
39
+ $this->_GenerateInputElement("TransactionIdentifier", $config->TransactionIdentifier);
40
+ $this->_GenerateInputElement("Amount", $config->Amount);
41
+ $this->_GenerateInputElement("Currency", $config->Currency);
42
+ $this->_GenerateInputElement("ErrorUrl", $config->ErrorUrl);
43
+ $this->_GenerateInputElement("ItemIdentifier", $config->ItemIdentifier);
44
+ $this->_GenerateInputElement("ExpiryDate", $config->ExpiryDate);
45
+ $this->_GenerateInputElement("ChildIdentifier", $config->ChildIdentifier);
46
+ $this->_GenerateInputElement("ParentIdentifier", $config->ParentIdentifier);
47
+ $this->_GenerateInputElement("GuestChildName", $config->GuestChildName);
48
+ $this->_GenerateInputElement("NotifyChild", $config->NotifyChild);
49
+ $this->_GenerateInputElement("DeliveryToChildAddress", $config->DeliveryToChildAddress);
50
+ $this->_GenerateInputElement("PaymentAccountIdentifier", $config->PaymentAccountIdentifier);
51
+ $this->_GenerateInputElement("ExternalLoginFlag", $config->ExternalLoginFlag);
52
+ $this->_GenerateInputElement("Token", $config->Token);
53
+ $this->_GenerateInputElement("Value", $config->Value);
54
+ echo $config->ButtonHtml;
55
+ ?>
56
+ </form>
57
+ <?php
58
+ }
59
+ }
60
+
61
+ ?>
lib/Oink/Services/Implementations/OinkLoggingService.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class OinkLoggingService implements ILoggingService
4
+ {
5
+ public function Log($result)
6
+ {
7
+ $logfile = $_SERVER['DOCUMENT_ROOT'].'/Oink.'.date("YmdHis").'.log';
8
+ // writing response to external file
9
+ $f = fopen($logfile, 'w');
10
+ ob_start();
11
+ print_r($result);
12
+ $return = ob_get_contents();
13
+ ob_end_clean();
14
+ fwrite($f, $return);
15
+ fclose($f);
16
+ }
17
+ }
18
+ ?>
lib/Oink/Services/Implementations/OinkParentService.php ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @package Oink.Services.Implementations
5
+ */
6
+ class OinkParentService implements IParentService{
7
+
8
+ var $config;
9
+
10
+ function __construct($config) {
11
+ $this->config = $config;
12
+ }
13
+
14
+ private function GetSoapClient()
15
+ {
16
+ $client = new SOAPClient($this->config->ParentServiceEndpointAddressWsdl);
17
+ $headers = array();
18
+
19
+ $headers[] = new SoapHeader($this->config->HeaderNamespace,
20
+ $this->config->propMerchantIdentifier,
21
+ $this->config->MerchantIdentifier);
22
+
23
+ $headers[] = new SoapHeader($this->config->HeaderNamespace,
24
+ $this->config->propApiKey,
25
+ $this->config->APIkey);
26
+ $client->__setSoapHeaders($headers);
27
+ return $client;
28
+ }
29
+
30
+ public function AuthenticateParent($username, $password){
31
+ $result_dto = new dtoResultObject();
32
+ $result_dto->ErrorMessage = "SOAP call not executed.";
33
+ $result_dto->Status = false;
34
+
35
+ try {
36
+ $client = $this->GetSoapClient();
37
+ $params = array(
38
+ 'userName' => $username,
39
+ 'password' => $password,
40
+ );
41
+ $result = $client->AuthenticateParent($params);
42
+
43
+ $result_dto->ErrorMessage = $result->AuthenticateParentResult->ErrorMessage;
44
+ $result_dto->Token = $result->AuthenticateParentResult->Token;
45
+ $result_dto->Status = $result->AuthenticateParentResult->Status;
46
+
47
+ } catch(Exception $e) {
48
+ $result_dto->ErrorMessage = "Exception occured: " . $e;
49
+ }
50
+ return $result_dto;
51
+ }
52
+
53
+
54
+ public function GetChildProfiles($token){
55
+
56
+
57
+ try {
58
+ $client = $this->GetSoapClient();
59
+ $params = array(
60
+ 'token'=> $token,
61
+ );
62
+ $result = $client->GetChildProfiles($params);
63
+ return $result;
64
+ } catch(Exception $e) {
65
+ echo "Exception occured: ".$e;
66
+ }
67
+ }
68
+ }
69
+
70
+ ?>
lib/Oink/Services/Implementations/OinkPaymentService.php ADDED
@@ -0,0 +1,585 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @package Oink.Services.Implementations
5
+ */
6
+ class OinkPaymentService implements IPaymentService {
7
+
8
+ var $config;
9
+
10
+ function __construct($config) {
11
+ $this->config = $config;
12
+ }
13
+ private function GetVPSoapClient(){
14
+ $client = new OinkSoapClient($this->config);
15
+ return $client;
16
+ }
17
+ /**
18
+ * Default method to generate soap client with WCF security headers
19
+ * set properly
20
+ */
21
+ private function GetNativeSoapClient() {
22
+ $client = new SOAPClient($this->config->TransactionServiceEndpointAddressWsdl, array("trace" => 1));
23
+ $headers = array();
24
+
25
+ $headers[] = new SoapHeader($this->config->HeaderNamespace,
26
+ $this->config->propMerchantIdentifier,
27
+ $this->config->MerchantIdentifier);
28
+
29
+ $headers[] = new SoapHeader($this->config->HeaderNamespace,
30
+ $this->config->propApiKey,
31
+ $this->config->APIkey);
32
+ $client->__setSoapHeaders($headers);
33
+
34
+ return $client;
35
+ }
36
+
37
+ private function GetSoapClient(){
38
+ if($this->nativeSoapExists()){
39
+ return $this->GetNativeSoapClient();
40
+ }else{
41
+ return $this->GetVPSoapClient();
42
+ }
43
+ }
44
+
45
+ public function nativeSoapExists(){
46
+ return class_exists('SOAPClient');
47
+ }
48
+
49
+ public function AddItemToMerchantExclusionList() {
50
+
51
+ }
52
+
53
+ /**
54
+ * Authenticates a child based on username & password.
55
+ * @return dtoResultObject The result object contains information for
56
+ * the webservice call to AuthenticateChild
57
+ */
58
+ public function AuthenticateChild($name, $password) {
59
+ $result_dto = new dtoResultObject();
60
+ $result_dto->ErrorMessage = "SOAP call not executed.";
61
+ $result_dto->Status = false;
62
+
63
+ try {
64
+ $client = $this->GetSoapClient();
65
+ $params = array(
66
+ 'userName' => $name,
67
+ 'password' => $password,
68
+ );
69
+ $result = $client->AuthenticateChild($params);
70
+ $result_dto->ErrorMessage = $result->AuthenticateChildResult->ErrorMessage;
71
+ $result_dto->Token = $result->AuthenticateChildResult->Token;
72
+ $result_dto->Status = $result->AuthenticateChildResult->Status;
73
+
74
+ } catch (Exception $e) {
75
+ $result_dto->ErrorMessage = "Exception occured: " . $e;
76
+ }
77
+ return $result_dto;
78
+ }
79
+
80
+ /**
81
+ * Method to authenticate parnet or child and returns a token to use in subsequent calls
82
+ * @return Object containing information about call status, the user type and the token
83
+ */
84
+ public function AuthenticateUser($name, $password) {
85
+ $result_dto = new dtoResultObject();
86
+ $result_dto->ErrorMessage = "SOAP call not executed.";
87
+ $result_dto->Status = false;
88
+
89
+ try {
90
+ $client = $this->GetSoapClient();
91
+ $params = array(
92
+ 'userName' => $name,
93
+ 'password' => $password,
94
+ );
95
+ $result = $client->AuthenticateUser($params);
96
+ $result_dto->ErrorMessage = $result->AuthenticateUserResult->ErrorMessage;
97
+ $result_dto->Token = $result->AuthenticateUserResult->Token;
98
+ $result_dto->Status = $result->AuthenticateUserResult->Status;
99
+ $result_dto->UserType = $result->AuthenticateUserResult->UserType;
100
+ } catch (Exception $e) {
101
+ $result_dto->ErrorMessage = "Exception occured: " . $e;
102
+ }
103
+ return $result_dto;
104
+ }
105
+
106
+ public function GetChildProfile($token) {
107
+ $profile = new dtoProfileInfo();
108
+ $profile->ErrorMessage = "SOAP call not executed.";
109
+ try {
110
+ $client = $this->GetSoapClient();
111
+ $params = array(
112
+ 'token' => $token,
113
+ );
114
+ $result = $client->GetChildGenderAge($params);
115
+
116
+ $profile->Age = $result->GetChildGenderAgeResult->Age;
117
+ $profile->Gender = $result->GetChildGenderAgeResult->Gender;
118
+ $profile->ErrorMessage = $result->GetChildGenderAgeResult->ErrorMessage;
119
+ } catch (Exception $e) {
120
+ $profile->ErrorMessage = "Exception occured: " . $e;
121
+ }
122
+ return $profile;
123
+ }
124
+
125
+ /**
126
+ * Gets child address data based on token obtained from AuthenticateChild method
127
+ * @return dtoAddress The address object contains child data returned from
128
+ * the webservice call to GetChildAddress
129
+ */
130
+ public function GetChildAddress($token) {
131
+ $result_dto = new dtoAddress();
132
+ $result_dto->Status = false;
133
+ $result_dto->ErrorMessage = "SOAP call not executed.";
134
+ try {
135
+ $client = $this->GetSoapClient();
136
+ $params = array(
137
+ 'token' => $token,
138
+ );
139
+ $result = $client->GetChildAddress($params);
140
+ $result_dto->Address = $result->GetChildAddressResult->Address;
141
+ $result_dto->City = $result->GetChildAddressResult->City;
142
+ $result_dto->Country = $result->GetChildAddressResult->Country;
143
+ $result_dto->ErrorMessage = $result->GetChildAddressResult->ErrorMessage;
144
+ $result_dto->State = $result->GetChildAddressResult->State;
145
+ $result_dto->Status = $result->GetChildAddressResult->Status;
146
+ $result_dto->Zip = $result->GetChildAddressResult->Zip;
147
+ $result_dto->Phone = $result->GetChildAddressResult->ParentPhone;
148
+ $result_dto->ParentEmail = $result->GetChildAddressResult->ParentEmail;
149
+ $result_dto->ParentName = $result->GetChildAddressResult->Name;
150
+ $result_dto->ChildName = $result->GetChildAddressResult->AttentionOf;
151
+ } catch (Exception $e) {
152
+ $result_dto->ErrorMessage = "Exception occured: " . $e;
153
+ }
154
+ return $result_dto;
155
+ }
156
+
157
+ /**
158
+ * Gets parent address data based on token obtained from AuthenticateUser method
159
+ * @return dtoAddress The address object contains child data returned from
160
+ * the webservice call to GetParentAddress
161
+ */
162
+ public function GetParentAddress($token) {
163
+ $result_dto = new dtoAddress();
164
+ $result_dto->Status = false;
165
+ $result_dto->ErrorMessage = "SOAP call not executed.";
166
+ try {
167
+ $client = $this->GetSoapClient();
168
+ $params = array(
169
+ 'token' => $token,
170
+ );
171
+ $result = $client->GetParentAddress($params);
172
+ $result_dto->Address = $result->GetParentAddressResult->Address;
173
+ $result_dto->City = $result->GetParentAddressResult->City;
174
+ $result_dto->Country = $result->GetParentAddressResult->Country;
175
+ $result_dto->ErrorMessage = $result->GetParentAddressResult->ErrorMessage;
176
+ $result_dto->State = $result->GetParentAddressResult->State;
177
+ $result_dto->Status = $result->GetParentAddressResult->Status;
178
+ $result_dto->Zip = $result->GetParentAddressResult->Zip;
179
+ $result_dto->Phone = $result->GetParentAddressResult->ParentPhone;
180
+ $result_dto->ParentEmail = $result->GetParentAddressResult->ParentEmail;
181
+ $result_dto->ParentName = $result->GetParentAddressResult->Name;
182
+ } catch (Exception $e) {
183
+ $result_dto->ErrorMessage = "Exception occured: " . $e;
184
+ }
185
+ return $result_dto;
186
+ }
187
+
188
+ /**
189
+ * Method to return a Parent child's address details
190
+ * <param name="token">Parent Security Token</param>
191
+ * @return Address Result object
192
+ */
193
+ public function GetParentChildAddress($token, $childIdentifier) {
194
+ $result_dto = new dtoAddress();
195
+ $result_dto->Status = false;
196
+ $result_dto->ErrorMessage = "SOAP call not executed.";
197
+ try {
198
+ $client = $this->GetSoapClient();
199
+ $params = array(
200
+ 'token' => $token,
201
+ "childIdentifier" => $childIdentifier
202
+ );
203
+ $result = $client->GetParentChildAddress($params);
204
+ $result_dto->Address = $result->GetParentChildAddressResult->Address;
205
+ $result_dto->City = $result->GetParentChildAddressResult->City;
206
+ $result_dto->Country = $result->GetParentChildAddressResult->Country;
207
+ $result_dto->ErrorMessage = $result->GetParentChildAddressResult->ErrorMessage;
208
+ $result_dto->State = $result->GetParentChildAddressResult->State;
209
+ $result_dto->Status = $result->GetParentChildAddressResult->Status;
210
+ $result_dto->Zip = $result->GetParentChildAddressResult->Zip;
211
+ $result_dto->Phone = $result->GetParentChildAddressResult->ParentPhone;
212
+ $result_dto->ParentEmail = $result->GetParentChildAddressResult->ParentEmail;
213
+ $result_dto->ParentName = $result->GetParentChildAddressResult->Name;
214
+ } catch (Exception $e) {
215
+ $result_dto->ErrorMessage = "Exception occured: " . $e;
216
+ }
217
+ return $result_dto;
218
+ }
219
+
220
+ /**
221
+ * Method to return a Parent's list of children he can purchase items for
222
+ * <param name="token">Parent Security Token</param>
223
+ * @return Array of entities
224
+ */
225
+ public function GetAllChildren($token) {
226
+ $result_dto = new dtoResultObject();
227
+ $result_dto->ErrorMessage = "SOAP call not executed.";
228
+ $result_dto->Status = false;
229
+
230
+ try {
231
+ $client = $this->GetSoapClient();
232
+ $params = array(
233
+ 'token' => $token,
234
+ );
235
+ $result = $client->GetAllChildren($params);
236
+ $childrens = array();
237
+ if (!is_array($result->GetAllChildrenResult->EntityResult)) {
238
+ $result->GetAllChildrenResult->EntityResult = array($result->GetAllChildrenResult->EntityResult);
239
+ }
240
+ foreach ($result->GetAllChildrenResult->EntityResult as $key => $_children) {
241
+ $_children=(object)$_children;
242
+ $children = new dtoChildren();
243
+ $children->Name = $_children->Name;
244
+ $children->Token = $_children->Identifier;
245
+ $childrens[] = $children;
246
+ }
247
+ } catch (Exception $e) {
248
+ $result_dto->ErrorMessage = "Exception occured: " . $e;
249
+ return $result_dto;
250
+ }
251
+ return $childrens;
252
+ }
253
+
254
+ /**
255
+ * Method to return a Parent's list of children he can purchase items for
256
+ * <param name="token">Parent Security Token</param>
257
+ * @return array
258
+ */
259
+ public function GetPaymentAccounts($token) {
260
+ $result_dto = new dtoResultObject();
261
+ $result_dto->ErrorMessage = "SOAP call not executed.";
262
+ $result_dto->Status = false;
263
+
264
+ try {
265
+ $client = $this->GetSoapClient();
266
+ $params = array(
267
+ 'token' => $token,
268
+ );
269
+ $result = $client->GetPaymentAccounts($params);
270
+ if (!is_array($result->GetPaymentAccountsResult->PaymentAccountResult)) {
271
+ $result->GetPaymentAccountsResult->PaymentAccountResult = array($result->GetPaymentAccountsResult->PaymentAccountResult);
272
+ }
273
+ $paymentAccounts = array();
274
+ foreach ($result->GetPaymentAccountsResult->PaymentAccountResult as $key => $_paymentAccount) {
275
+ $_paymentAccount = (object) $_paymentAccount;
276
+ $paymentAccount = new dtoPaymentAccount();
277
+ $paymentAccount->Name = $_paymentAccount->Name;
278
+ $paymentAccount->Type = $_paymentAccount->Type;
279
+ $paymentAccount->Token = $_paymentAccount->Identifier;
280
+ $paymentAccount->Url = $_paymentAccount->Url;
281
+ $paymentAccounts[] = $paymentAccount;
282
+ }
283
+ } catch (Exception $e) {
284
+ $result_dto->ErrorMessage = "Exception occured: " . $e;
285
+ return $result_dto;
286
+ }
287
+ return $paymentAccounts;
288
+ }
289
+
290
+ public function GetLoyaltyBalance($token) {
291
+
292
+ }
293
+
294
+ /**
295
+ * Gets specific transaction data based on token obtained from AuthenticateChild method
296
+ * & transaction identifier obtained from ProcessTransaction method
297
+ */
298
+ public function GetTransactionDetails($token, $transactionIdentifier) {
299
+
300
+ try {
301
+ $client = $this->GetSoapClient();
302
+ $params = array(
303
+ 'token' => $token,
304
+ 'transactionIdentifier' => $transactionIdentifier,
305
+ );
306
+ /*
307
+ * TODO: Need to create dtoTransactionDetails
308
+ * Need to map to dto so integration developers will understand
309
+ * what data is comming out of service.
310
+ */
311
+ $return = $client->GetTransactionDetails($params);
312
+ } catch (Exception $e) {
313
+ /*
314
+ * TODO: Need to add exception message to dtoTransactionDetails DTO
315
+ */
316
+ return $e;
317
+ }
318
+ return $return;
319
+ }
320
+
321
+ public function GetTransactions($token, $start_date, $end_date) {
322
+
323
+ try {
324
+ $client = $this->GetSoapClient();
325
+
326
+ $params = array(
327
+ 'token' => $token,
328
+ 'startDate' => $start_date,
329
+ 'endDate' => $end_date,
330
+ );
331
+ $return = $client->GetTransactions($params);
332
+ } catch (Exception $e) {
333
+ echo "Exception occured: " . $e;
334
+ }
335
+ }
336
+
337
+ public function ProcessTransaction($checkOutData, $token, $transactionDescription) {
338
+ $result_dto = new dtoResultObject();
339
+ $result_dto->Status = false;
340
+ $result_dto->ErrorMessage = "SOAP call not executed.";
341
+ try {
342
+ $client = $this->GetSoapClient();
343
+ $params = array(
344
+ 'checkOutData' => $checkOutData,
345
+ 'token' => $token,
346
+ 'transactionDescription' => $transactionDescription,
347
+ );
348
+ $result = $client->ProcessTransaction($params);
349
+ if ((string)$result->ProcessTransactionResult->Status == 'false'){
350
+ $result->ProcessTransactionResult->Status = false;
351
+ }
352
+ $result_dto->Xml = $client->__getLastResponse();
353
+ $result_dto->ErrorMessage = $result->ProcessTransactionResult->ErrorMessage;
354
+ $result_dto->Status = $result->ProcessTransactionResult->Status;
355
+ $result_dto->TransactionStatus = $result->ProcessTransactionResult->TransactionStatus;
356
+ $result_dto->TransactionIdentifier = $result->ProcessTransactionResult->TransactionIdentifier;
357
+ } catch (Exception $e) {
358
+ $result_dto->ErrorMessage = "Exception occured: " . $e;
359
+ }
360
+ return $result_dto;
361
+ }
362
+
363
+ public function ProcessParentTransaction($token, $checkOutData, $transactionDescription, $childIdentifier, $paymentAccountIdentifier) {
364
+ $result_dto = new dtoResultObject();
365
+ $result_dto->Status = false;
366
+ $result_dto->ErrorMessage = "SOAP call not executed.";
367
+ try {
368
+ $client = $this->GetSoapClient();
369
+ $params = array(
370
+ 'token' => $token,
371
+ 'checkOutData' => $checkOutData,
372
+ 'transactionDescription' => $transactionDescription,
373
+ 'childIdentifier' => $childIdentifier,
374
+ 'paymentAccountIdentifier' => $paymentAccountIdentifier,
375
+ );
376
+ $result = $client->ProcessParentTransaction($params);
377
+ if ((string)$result->ProcessParentTransactionResult->Status == 'false'){
378
+ $result->ProcessParentTransactionResult->Status = false;
379
+ }
380
+ $result_dto->Xml = $client->__getLastResponse();
381
+ $result_dto->ErrorMessage = $result->ProcessParentTransactionResult->ErrorMessage;
382
+ $result_dto->Status = $result->ProcessParentTransactionResult->Status;
383
+ $result_dto->TransactionStatus = $result->ProcessParentTransactionResult->TransactionStatus;
384
+ $result_dto->TransactionIdentifier = $result->ProcessParentTransactionResult->TransactionIdentifier;
385
+ } catch (Exception $e) {
386
+ $result_dto->ErrorMessage = "Exception occured: " . $e;
387
+ }
388
+ return $result_dto;
389
+ }
390
+
391
+ public function ProcessSubscription($token, $subscriptionData, $checkOutData, $description) {
392
+ $result_dto = new dtoResultObject();
393
+ $result_dto->Status = false;
394
+ $result_dto->ErrorMessage = "SOAP call not executed.";
395
+ try {
396
+ $client = $this->GetSoapClient();
397
+ $params = array(
398
+ 'token' => $token,
399
+ 'subscriptionData' => $subscriptionData,
400
+ 'checkOutData' => $checkOutData,
401
+ 'transactionDescription' => $description,
402
+ );
403
+ $result = $client->ProcessSubscription($params);
404
+ $result_dto->Xml = $client->__getLastResponse();
405
+ $result_dto->Identifier = $result->ProcessSubscriptionResult->Identifier;
406
+ $result_dto->Name = $result->ProcessSubscriptionResult->Name;
407
+ $result_dto->Type = $result->ProcessSubscriptionResult->Type;
408
+ } catch (Exception $e) {
409
+ $result_dto->ErrorMessage = "Exception occured: " . $e;
410
+ }
411
+ return $result;
412
+ }
413
+
414
+ public function ApproveSubscription($token, $subscriptionIdentifier, $paymentAccountIdentifier, $endDate, $maxCount, $approved) {
415
+ $result_dto = new dtoResultObject();
416
+ $result_dto->Status = false;
417
+ $result_dto->ErrorMessage = "SOAP call not executed.";
418
+ try {
419
+ $client = $this->GetSoapClient();
420
+ $params = array(
421
+ 'token' => $token,
422
+ 'subscriptionIdentifier' => $subscriptionIdentifier,
423
+ 'paymentAccountIdentifier' => $paymentAccountIdentifier,
424
+ 'endDate' => $endDate,
425
+ 'maxCount' => $maxCount,
426
+ 'approved' => $approved,
427
+ );
428
+ $result = $client->ApproveSubscription($params);
429
+ } catch (Exception $e) {
430
+ $result_dto->ErrorMessage = "Exception occured: " . $e;
431
+ return $result_dto;
432
+ }
433
+ return $result;
434
+ }
435
+
436
+ public function MerchantCancelSubscription($Identifier){
437
+ $result_dto = new dtoResultObject();
438
+ $result_dto->Status = false;
439
+ $result_dto->ErrorMessage = "SOAP call not executed.";
440
+ try {
441
+ $client = $this->GetSoapClient();
442
+ $params = array(
443
+ 'Identifier' => $Identifier,
444
+ );
445
+ $result = $client->ApproveSubscription($params);
446
+ } catch (Exception $e) {
447
+ $result_dto->ErrorMessage = "Exception occured: " . $e;
448
+ return $result_dto;
449
+ }
450
+ return $result;
451
+ }
452
+
453
+ public function MerchantCancelSubscriptionByExternalRef($ExternalRefIdentifier){
454
+ $result_dto = new dtoResultObject();
455
+ $result_dto->Status = false;
456
+ $result_dto->ErrorMessage = "SOAP call not executed.";
457
+ try {
458
+ $client = $this->GetSoapClient();
459
+ $params = array(
460
+ 'ExternalRefIdentifier' => $ExternalRefIdentifier,
461
+ );
462
+ $result = $client->ApproveSubscription($params);
463
+ } catch (Exception $e) {
464
+ $result_dto->ErrorMessage = "Exception occured: " . $e;
465
+ return $result_dto;
466
+ }
467
+ return $result;
468
+ }
469
+
470
+ public function GetSubscriptionTransactions($subscriptionIdentifier){
471
+ $result_dto = new dtoResultObject();
472
+ $result_dto->Status = false;
473
+ $result_dto->ErrorMessage = "SOAP call not executed.";
474
+ try {
475
+ $client = $this->GetSoapClient();
476
+ $params = array(
477
+ 'subscriptionIdentifier' => $subscriptionIdentifier,
478
+ );
479
+ $result = $client->ApproveSubscription($params);
480
+ } catch (Exception $e) {
481
+ $result_dto->ErrorMessage = "Exception occured: " . $e;
482
+ return $result_dto;
483
+ }
484
+ return $result;
485
+ }
486
+
487
+ public function GetSubscriptionTransactionsByRef($externalIdentifier){
488
+ $result_dto = new dtoResultObject();
489
+ $result_dto->Status = false;
490
+ $result_dto->ErrorMessage = "SOAP call not executed.";
491
+ try {
492
+ $client = $this->GetSoapClient();
493
+ $params = array(
494
+ 'ExternalRefIdentifier' => $externalIdentifier,
495
+ );
496
+ $result = $client->ApproveSubscription($params);
497
+ } catch (Exception $e) {
498
+ $result_dto->ErrorMessage = "Exception occured: " . $e;
499
+ return $result_dto;
500
+ }
501
+ return $result;
502
+ }
503
+
504
+ public function RemoveItemFromMerchantExclusionList() {
505
+
506
+ }
507
+
508
+ public function SaveWishList($token, $xml) {
509
+
510
+ try {
511
+ $client = $this->GetSoapClient();
512
+ $params = array(
513
+ 'token' => $token,
514
+ 'wishListXml' => $xml,
515
+ );
516
+ $result = $client->SaveWishList($params);
517
+ } catch (Exception $e) {
518
+ echo "Exception occured: " . $e;
519
+ }
520
+ $status = new dtoWishlistStatus();
521
+ $status->Children = $result->SaveWishListResult->Children;
522
+ $status->ErrorMessage = $result->SaveWishListResult->ErrorMessage;
523
+ $status->Status = $result->SaveWishListResult->Status;
524
+ $status->Token = $result->SaveWishListResult->Token;
525
+ $status->TransactionStatus = $result->SaveWishListResult->TransactionStatus;
526
+ return $status;
527
+ }
528
+
529
+ public function PingHeaders() {
530
+ try {
531
+ $client = $this->GetSoapClient();
532
+ $result = $client->PingHeaders();
533
+ } catch (Exception $e) {
534
+ return false;
535
+ }
536
+ if(isset($result->PingHeadersResult->scalar)){
537
+ return ($result->PingHeadersResult->scalar == 'true')?1:0;
538
+ }
539
+ return $result->PingHeadersResult;
540
+ }
541
+
542
+ public function CaptureTransactionByIdentifier($transactionIdentifier){
543
+ $result_dto = new dtoResultObject();
544
+ $result_dto->Status = false;
545
+ $result_dto->ErrorMessage = "SOAP call not executed.";
546
+ try {
547
+ $client = $this->GetSoapClient();
548
+ $params = array(
549
+ 'transactionIdentifier' => $transactionIdentifier,
550
+ 'capture' => true,
551
+ );
552
+
553
+ $result = $client->CaptureTransactionByIdentifier($params);
554
+ $result_dto->ErrorMessage = $result->CaptureTransactionByIdentifierResult->ErrorMessage;
555
+ $result_dto->Status = $result->CaptureTransactionByIdentifierResult->Status;
556
+ } catch (Exception $e) {
557
+
558
+ $result_dto->ErrorMessage = "Exception occured: " . $e;
559
+ }
560
+ return $result_dto;
561
+ }
562
+
563
+ public function VoidCaptureTransactionByIdentifier($transactionIdentifier){
564
+ $result_dto = new dtoResultObject();
565
+ $result_dto->Status = false;
566
+ $result_dto->ErrorMessage = "SOAP call not executed.";
567
+ try {
568
+ $client = $this->GetSoapClient();
569
+ $params = array(
570
+ 'transactionIdentifier' => $transactionIdentifier,
571
+ 'capture' => 0,
572
+ );
573
+
574
+ $result = $client->CaptureTransactionByIdentifier($params);
575
+ $result_dto->ErrorMessage = $result->CaptureTransactionByIdentifierResult->ErrorMessage;
576
+ $result_dto->Status = $result->CaptureTransactionByIdentifierResult->Status;
577
+ } catch (Exception $e) {
578
+ $result_dto->ErrorMessage = "Exception occured: " . $e;
579
+ }
580
+ return $result_dto;
581
+ }
582
+
583
+ }
584
+
585
+ ?>
lib/Oink/Services/Implementations/OinkSoapClient.php ADDED
@@ -0,0 +1,320 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class OinkSoapClient{
3
+ var $config;
4
+ var $lastResponse;
5
+
6
+ function __construct($config) {
7
+ $this->config = $config;
8
+ }
9
+
10
+ public function AuthenticateChild($params){
11
+ $method = "AuthenticateChild";
12
+ $response = $this->MakeGenericSoapCall($method,$params);
13
+ $result = new stdClass();
14
+ $result->AuthenticateChildResult = new stdClass();
15
+ $result->AuthenticateChildResult = $response;
16
+ return $result;
17
+ }
18
+
19
+ public function AuthenticateUser($params){
20
+ $method = "AuthenticateUser";
21
+ $response = $this->MakeGenericSoapCall($method,$params);
22
+ $result = new stdClass();
23
+ $result->AuthenticateUserResult = new stdClass();
24
+ $result->AuthenticateUserResult = $response;
25
+ return $result;
26
+ }
27
+
28
+ public function GetChildGenderAge($params){
29
+ $method = "GetChildGenderAge";
30
+ $response = $this->MakeGenericSoapCall($method,$params);
31
+ $result = new stdClass();
32
+ $result->GetChildGenderAgeResult = new stdClass();
33
+ $result->GetChildGenderAgeResult = $response;
34
+ return $result;
35
+ }
36
+
37
+ public function GetChildAddress($params){
38
+ $method = "GetChildAddress";
39
+ $response = $this->MakeGenericSoapCall($method,$params);
40
+
41
+ $result = new stdClass();
42
+ $result->GetChildAddressResult = new stdClass();
43
+ $result->GetChildAddressResult = $response;
44
+ return $result;
45
+ }
46
+
47
+ public function GetParentAddress($params){
48
+ $method = "GetParentAddress";
49
+ $response = $this->MakeGenericSoapCall($method,$params);
50
+
51
+ $result = new stdClass();
52
+ $result->GetParentAddressResult = new stdClass();
53
+ $result->GetParentAddressResult = $response;
54
+ return $result;
55
+ }
56
+
57
+ public function GetParentChildAddress($params){
58
+ $method = "GetParentChildAddress";
59
+ $response = $this->MakeGenericSoapCall($method,$params);
60
+ $result = new stdClass();
61
+ $result->GetParentChildAddressResult = new stdClass();
62
+ $result->GetParentChildAddressResult = $response;
63
+ return $result;
64
+ }
65
+
66
+ public function GetAllChildren($params){
67
+ $method = "GetAllChildren";
68
+ $response = $this->MakeGenericSoapCall($method,$params);
69
+ $result = new stdClass();
70
+ $result->GetAllChildrenResult = new stdClass();
71
+ $result->GetAllChildrenResult = $response;
72
+ return $result;
73
+ }
74
+
75
+ public function GetPaymentAccounts($params){
76
+ $method = "GetPaymentAccounts";
77
+ $response = $this->MakeGenericSoapCall($method,$params);
78
+ $result = new stdClass();
79
+ $result->GetPaymentAccountsResult = new stdClass();
80
+ $result->GetPaymentAccountsResult = $response;
81
+ return $result;
82
+ }
83
+
84
+ public function GetLoyaltyBalance($params){
85
+ $method = "GetLoyaltyBalance";
86
+ $response = $this->MakeGenericSoapCall($method,$params);
87
+ $result = new stdClass();
88
+ $result->GetLoyaltyBalanceResult = new stdClass();
89
+ $result->GetLoyaltyBalanceResult = $response;
90
+ return $result;
91
+ }
92
+
93
+ public function GetTransactionDetails($params){
94
+ $method = "GetTransactionDetails";
95
+ $response = $this->MakeGenericSoapCall($method,$params);
96
+ $result = new stdClass();
97
+ $result->GetTransactionDetailsResult = new stdClass();
98
+ $result->GetTransactionDetailsResult = $response;
99
+ return $result;
100
+ }
101
+
102
+ public function GetTransactions($params){
103
+ $method = "GetTransactions";
104
+ $response = $this->MakeGenericSoapCall($method,$params);
105
+ $result = new stdClass();
106
+ $result->GetTransactionsResult = new stdClass();
107
+ $result->GetTransactionsResult = $response;
108
+ return $result;
109
+ }
110
+
111
+ public function ProcessTransaction($params){
112
+ $method = "ProcessTransaction";
113
+ $response = $this->MakeGenericSoapCall($method,$params);
114
+ $result = new stdClass();
115
+ $result->ProcessTransactionResult = new stdClass();
116
+ $result->ProcessTransactionResult = $response;
117
+ return $result;
118
+ }
119
+
120
+ public function ProcessParentTransaction($params){
121
+ $method = "ProcessParentTransaction";
122
+ $response = $this->MakeGenericSoapCall($method,$params);
123
+ $result = new stdClass();
124
+ $result->ProcessParentTransactionResult = new stdClass();
125
+ $result->ProcessParentTransactionResult = $response;
126
+ return $result;
127
+ }
128
+
129
+ public function ProcessSubscription($params){
130
+ $method = "ProcessSubscription";
131
+ $response = $this->MakeGenericSoapCall($method,$params);
132
+ $result = new stdClass();
133
+ $result->ProcessSubscriptionResult = new stdClass();
134
+ $result->ProcessSubscriptionResult = $response;
135
+ return $result;
136
+ }
137
+
138
+ public function ApproveSubscription($params) {
139
+ $method = "ApproveSubscription";
140
+ $response = $this->MakeGenericSoapCall($method,$params);
141
+ $result = new stdClass();
142
+ $result->ApproveSubscriptionResult = new stdClass();
143
+ $result->ApproveSubscriptionResult = $response;
144
+ return $result;
145
+ }
146
+
147
+ public function MerchantCancelSubscription($params){
148
+ $method = "MerchantCancelSubscription";
149
+ $response = $this->MakeGenericSoapCall($method,$params);
150
+ $result = new stdClass();
151
+ $result->MerchantCancelSubscriptionResult = new stdClass();
152
+ $result->MerchantCancelSubscriptionResult = $response;
153
+ return $result;
154
+ }
155
+
156
+ public function MerchantCancelSubscriptionByExternalRef($params){
157
+ $method = "MerchantCancelSubscriptionByExternalRef";
158
+ $response = $this->MakeGenericSoapCall($method,$params);
159
+ $result = new stdClass();
160
+ $result->MerchantCancelSubscriptionByExternalRefResult = new stdClass();
161
+ $result->MerchantCancelSubscriptionByExternalRefResult = $response;
162
+ return $result;
163
+ }
164
+
165
+ public function GetSubscriptionTransactions($params){
166
+ $method = "GetSubscriptionTransactions";
167
+ $response = $this->MakeGenericSoapCall($method,$params);
168
+ $result = new stdClass();
169
+ $result->GetSubscriptionTransactionsResult = new stdClass();
170
+ $result->GetSubscriptionTransactionsResult = $response;
171
+ return $result;
172
+ }
173
+
174
+ public function GetSubscriptionTransactionsByRef($params){
175
+ $method = "GetSubscriptionTransactionsByRef";
176
+ $response = $this->MakeGenericSoapCall($method,$params);
177
+ $result = new stdClass();
178
+ $result->GetSubscriptionTransactionsByRefResult = new stdClass();
179
+ $result->GetSubscriptionTransactionsByRefResult = $response;
180
+ return $result;
181
+ }
182
+
183
+ public function SaveWishList($params){
184
+ $method = "SaveWishList";
185
+ $response = $this->MakeGenericSoapCall($method,$params);
186
+ $result = new stdClass();
187
+ $result->SaveWishListResult = new stdClass();
188
+ $result->SaveWishListResult = $response;
189
+ return $result;
190
+ }
191
+
192
+ public function CaptureTransactionByIdentifier($params){
193
+ $method = "CaptureTransactionByIdentifier";
194
+ $response = $this->MakeGenericSoapCall($method,$params);
195
+ $result = new stdClass();
196
+ $result->CaptureTransactionByIdentifierResult = new stdClass();
197
+ $result->CaptureTransactionByIdentifierResult = $response;
198
+ return $result;
199
+ }
200
+
201
+ public function PingHeaders(){
202
+ $method = "PingHeaders";
203
+ $response = $this->MakeGenericSoapCall($method,NULL);
204
+ $result = new stdClass();
205
+ $result->PingHeadersResult = new stdClass();
206
+ $result->PingHeadersResult = $response;
207
+ return $result;
208
+ }
209
+
210
+ public function __getLastResponse(){
211
+ return $this->lastResponse;
212
+ }
213
+
214
+ /*==============================================
215
+ * Soap Infrastructure
216
+ ==============================================*/
217
+ private function MakeGenericSoapCall($method, $params){
218
+ $soap_envelope = $this->GenerateSoapEnvelope($method, $params);
219
+ $url = $this->config->TransactionServiceEndpointAddress."?".$method;
220
+ $SOAPAction = 'http://tempuri.org/ITransactionService/'.$method;
221
+
222
+ $headers = array(
223
+ 'Content-Type: text/xml; charset=utf-8',
224
+ 'Content-Length: '.strlen($soap_envelope),
225
+ 'SOAPAction: '.$SOAPAction
226
+ );
227
+
228
+ $ch = curl_init();
229
+ curl_setopt($ch, CURLOPT_URL, $url);
230
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
231
+ curl_setopt($ch, CURLOPT_POST, TRUE);
232
+ curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
233
+ curl_setopt($ch, CURLOPT_POSTFIELDS, $soap_envelope);
234
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
235
+
236
+ $result = curl_exec($ch);
237
+ $this->lastResponse = $result;
238
+ curl_close($ch);
239
+
240
+ $response = $this->ConvertSoapXmlToResponseObject($method, $result);
241
+ $this->CheckResponse($response);
242
+ return $response;
243
+ }
244
+ private function GenerateSoapEnvelope($method, $params){
245
+
246
+ $body = "<ns1:".$method.">";
247
+ if (isset ($params)) {
248
+ foreach ($params as $key => $value) {
249
+ $p = '<ns1:' . $key . '>' . $value . '</ns1:' . $key . '>';
250
+ $body .= $p;
251
+ }
252
+ }
253
+ $body .="</ns1:".$method.">";
254
+
255
+ $envelope = '
256
+ <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://tempuri.org/" xmlns:ns2="vp">
257
+ <SOAP-ENV:Header>
258
+ <ns2:MerchantIdentifier>'.$this->config->MerchantIdentifier.'</ns2:MerchantIdentifier>
259
+ <ns2:APIkey>'.$this->config->APIkey.'</ns2:APIkey>
260
+ </SOAP-ENV:Header>
261
+ <SOAP-ENV:Body>
262
+ '.$body.'
263
+ </SOAP-ENV:Body>
264
+ </SOAP-ENV:Envelope>';
265
+ return $envelope;
266
+ }
267
+ private function ConvertSoapXmlToResponseObject($method, $xml){
268
+ $exception_key = "<s:Fault>";
269
+ $is_exception = strpos($xml, $exception_key);
270
+
271
+ $method_response = $method."Response";
272
+ $method_result = $method."Result";
273
+ $soap_envelope = "Envelope";
274
+ $soap_body = "Body";
275
+
276
+ $xml = $this->CleanXmlResponse($xml);
277
+ $xmlObj = new XmlToArray($xml);
278
+ $obj_array = $xmlObj->createArray();
279
+
280
+ if($is_exception){
281
+ $fault = "Fault";
282
+ $xml_body = $obj_array[$soap_envelope][$soap_body][0];
283
+ $response = (object)$xml_body[$fault][0];
284
+ }else{
285
+ $xml_body = $obj_array[$soap_envelope][$soap_body][0];
286
+ if(is_array($xml_body[$method_response][0][$method_result][0]))
287
+ $response = (object)$xml_body[$method_response][0][$method_result][0];
288
+ else
289
+ $response = (object)$xml_body[$method_response][0][$method_result];
290
+ }
291
+
292
+ return $response;
293
+ }
294
+ private function CleanXmlResponse($xml){
295
+ $clean = $xml;
296
+ $clean = str_replace(' xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"', '', $clean);
297
+ $clean = str_replace(' xmlns="http://tempuri.org/"', '', $clean);
298
+ $clean = str_replace(' xmlns:a="http://schemas.datacontract.org/2004/07/Oink.Services.Model" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"', '', $clean);
299
+ $clean = str_replace(' i:nil="true"', '', $clean);
300
+ $clean = str_replace('<s:', '<', $clean);
301
+ $clean = str_replace('</s:', '</', $clean);
302
+ $clean = str_replace('<a:', '<', $clean);
303
+ $clean = str_replace('</a:', '</', $clean);
304
+ $clean = str_replace(' xmlns:a="http://schemas.microsoft.com/net/2005/12/windowscommunicationfoundation/dispatcher"', '', $clean);
305
+ $clean = str_replace(' xml:lang="en-US"', '', $clean);
306
+ $clean = str_replace(' xmlns="http://schemas.datacontract.org/2004/07/System.ServiceModel" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"', '', $clean);
307
+ return $clean;
308
+ }
309
+ /**
310
+ *
311
+ * @param stdClass $result
312
+ * @throws Exception
313
+ */
314
+ private function CheckResponse($result){
315
+ if(isset($result->faultcode)){
316
+ throw new OinkException($result->faultstring);
317
+ }
318
+ }
319
+ }
320
+ ?>
lib/Oink/Services/Implementations/XmlSerializationService.php ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Oink.Services.Implementations
4
+ */
5
+
6
+ class XmlSerializationService implements ISerializationService
7
+ {
8
+ var $xmlResult;
9
+
10
+ function __construct(){
11
+ $rootNode = "vp";
12
+ $this->xmlResult = new SimpleXMLElement("<$rootNode></$rootNode>");
13
+ }
14
+
15
+ private function iteratechildren($object,$xml){
16
+ foreach ($object as $name=>$value) {
17
+ if (is_string($value) || is_numeric($value)) {
18
+ $xml->$name=$value;
19
+ } else {
20
+ $xml->$name=null;
21
+ $this->iteratechildren($value,$xml->$name);
22
+ }
23
+ }
24
+ }
25
+
26
+ private function SerializeCart(dtoCart $cart,$schemaPath){
27
+ /*
28
+ * This is just for testing. We are now using dto.ToXml() in magento application
29
+ * */
30
+ $xml = file_get_contents($schemaPath, true);
31
+ return trim($xml, " ");
32
+ /*
33
+ $x = '<?xml version="1.0" encoding="utf-8" ?>';
34
+ $x .= $cart->ToXml();
35
+ return $x;
36
+ *
37
+ */
38
+ }
39
+ private function SerializeGeneric($object){
40
+ $this->iteratechildren($object,$this->xmlResult);
41
+ return $this->xmlResult->asXML();
42
+ }
43
+ public function SerializeObject($object,$schemaPath){
44
+ if(is_a($object, 'dtoCart')){
45
+ return $this->SerializeCart($object,$schemaPath);
46
+ }else{
47
+ return $this->SerializeGeneric($object);
48
+ }
49
+ }
50
+
51
+ public function DeserializeObject($serialized){
52
+
53
+ }
54
+
55
+ }
56
+ ?>
lib/Oink/Services/Implementations/XmlToArray.php ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class XmlToArray {
4
+
5
+ var $xml = '';
6
+
7
+ function XmlToArray($xml) {
8
+ $this->xml = $xml;
9
+ }
10
+
11
+ function _struct_to_array($values, &$i) {
12
+ $child = array();
13
+ if (isset($values[$i]['value']))
14
+ array_push($child, $values[$i]['value']);
15
+
16
+ while ($i++ < count($values)) {
17
+ switch ($values[$i]['type']) {
18
+ case 'cdata':
19
+ array_push($child, $values[$i]['value']);
20
+ break;
21
+
22
+ case 'complete':
23
+ $name = $values[$i]['tag'];
24
+ if (!empty($name)) {
25
+ $child[$name] = isset($values[$i]['value']) ? ($values[$i]['value']) : '';
26
+ if (isset($values[$i]['attributes'])) {
27
+ $child[$name] = $values[$i]['attributes'];
28
+ }
29
+ }
30
+ break;
31
+
32
+ case 'open':
33
+ $name = $values[$i]['tag'];
34
+ $size = isset($child[$name]) ? sizeof($child[$name]) : 0;
35
+ $child[$name][$size] = $this->_struct_to_array($values, $i);
36
+ break;
37
+
38
+ case 'close':
39
+ return $child;
40
+ break;
41
+ }
42
+ }
43
+ return $child;
44
+ }
45
+
46
+ //_struct_to_array
47
+
48
+ function createArray() {
49
+ $xml = $this->xml;
50
+ $values = array();
51
+ $index = array();
52
+ $array = array();
53
+ $parser = xml_parser_create();
54
+ xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
55
+ xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
56
+ xml_parse_into_struct($parser, $xml, $values, $index);
57
+ xml_parser_free($parser);
58
+ $i = 0;
59
+ if (!is_null($values[$i])) {
60
+ $name = $values[$i]['tag'];
61
+ $array[$name] = isset($values[$i]['attributes']) ? $values[$i]['attributes'] : '';
62
+ $array[$name] = $this->_struct_to_array($values, $i);
63
+ }
64
+
65
+ return $array;
66
+ }
67
+
68
+ //createArray
69
+ }
70
+
71
+ //XmlToArray
72
+ ?>
lib/Oink/Services/Interfaces/ICallbackService.php ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Oink.Services.Interfaces
4
+ */
5
+ interface ICallbackService {
6
+ /**
7
+ * Method to authenticate parnet or child and returns a token to use in subsequent calls
8
+ * @return Object containing information about call status, the user type and the token
9
+ */
10
+ public function GetCallbackTransactionStatus();
11
+ /**
12
+ * Method to authenticate parnet or child and returns a token to use in subsequent calls
13
+ * @return Object containing information about call status, the user type and the token
14
+ */
15
+ public function GetCallbackAddressInformation();
16
+ }
17
+ ?>
lib/Oink/Services/Interfaces/ICartService.php ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Oink.Services.Interfaces
4
+ */
5
+ interface ICartService
6
+ {
7
+ public function GetCurrentCart();
8
+ public function GetCurrentWishlist();
9
+ }
10
+ ?>
lib/Oink/Services/Interfaces/IFormService.php ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Oink.Services.Interfaces
4
+ */
5
+ interface IFormService {
6
+ /**
7
+ * Method to authenticate parnet or child and returns a token to use in subsequent calls
8
+ * @return Object containing information about call status, the user type and the token
9
+ */
10
+ public function GenerateAddressRequestForm($config);
11
+ /**
12
+ * Method to authenticate parnet or child and returns a token to use in subsequent calls
13
+ * @return Object containing information about call status, the user type and the token
14
+ */
15
+ public function GenerateCheckoutForm($config);
16
+ }
17
+ ?>
lib/Oink/Services/Interfaces/IFormServiceConfiguration.php ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Oink.Services.Interfaces
4
+ */
5
+ interface IFormServiceConfiguration
6
+ {
7
+ public function GetAddressRequestFormConfiguration();
8
+ public function GetCheckoutFormConfiguration();
9
+ public function GetPreAuthorizedCheckoutFormConfiguration();
10
+ }
11
+ ?>
lib/Oink/Services/Interfaces/ILoggingService.php ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * To change this template, choose Tools | Templates
5
+ * and open the template in the editor.
6
+ */
7
+
8
+ /**
9
+ *
10
+ * @author Administrator
11
+ */
12
+ interface ILoggingService
13
+ {
14
+ public function Log($result);
15
+ }
16
+
17
+ ?>
lib/Oink/Services/Interfaces/IParentService.php ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Oink.Services.Interfaces
4
+ */
5
+ interface IParentService
6
+ {
7
+ public function AuthenticateParent($username, $password);
8
+ public function GetChildProfiles($token);
9
+ }
10
+ ?>
lib/Oink/Services/Interfaces/IPaymentService.php ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Oink.Services.Interfaces
4
+ */
5
+ interface IPaymentService {
6
+
7
+ public function AddItemToMerchantExclusionList();
8
+ public function AuthenticateChild($name, $password);
9
+ public function GetChildProfile($token);
10
+ public function GetChildAddress($token);
11
+ public function GetLoyaltyBalance($token);
12
+ public function GetTransactionDetails($token, $transactionIdentifier);
13
+ public function GetTransactions($token, $start_date, $end_date);
14
+ public function ProcessParentTransaction($token, $checkOutData, $transactionDescription, $childIdentifier, $paymentAccountIdentifier);
15
+ public function ProcessTransaction($checkOutData, $token, $transactionDescription);
16
+ public function RemoveItemFromMerchantExclusionList();
17
+ public function SaveWishList($token, $xml);
18
+ /*
19
+ * TODO: Need to implement PingHeaders prior to Guest checkout
20
+ * Will work on this when other tasks in 1st phase are complete.
21
+ * */
22
+ /**
23
+ * Used to verify connectivity to the web service
24
+ * and verifies validity for the header values vp.MerchantIdentifier and vp.APIkey
25
+ */
26
+ public function PingHeaders();
27
+ /*
28
+ * ============================================================================
29
+ * TODO: Will be implemented after 1st phase of project is considered complete.
30
+ * ============================================================================
31
+ * */
32
+ /**
33
+ * Method to authenticate parnet or child and returns a token to use in subsequent calls
34
+ * @return Object containing information about call status, the user type and the token
35
+ */
36
+ public function AuthenticateUser($name, $password);
37
+ /**
38
+ * Method to return parent address details
39
+ * <param name="token">Parent Security Token</param>
40
+ * @return Transaction Result object
41
+ */
42
+ //public function GetParentAddress($token);
43
+ /**
44
+ * Method to return a Parent's address details
45
+ * <param name="token">Parent Security Token</param>
46
+ * @return Address Result object
47
+ */
48
+ public function GetParentAddress($token);
49
+ //public function GetParentChildAddress($token, $childIdentifier);
50
+ /**
51
+ * Method to return a Parent child's address details
52
+ * <param name="token">Parent Security Token</param>
53
+ * @return Address Result object
54
+ */
55
+ public function GetParentChildAddress($token,$childIdentifier);
56
+ /**
57
+ * Method to return a Parent's payment accounts compatible with merchant application
58
+ * <param name="token">Parent Security Token</param>
59
+ * @return Array of entities
60
+ */
61
+ public function GetPaymentAccounts($token);
62
+ /**
63
+ * Method to return a Parent's list of children he can purchase items for
64
+ * <param name="token">Parent Security Token</param>
65
+ * @return Array of entities
66
+ */
67
+ public function GetAllChildren($token);
68
+ }
69
+ ?>
lib/Oink/Services/Interfaces/IPaymentServiceConfiguration.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Oink.Services.Interfaces
4
+ */
5
+ interface IPaymentServiceConfiguration
6
+ {
7
+ public function GetServiceConfiguration();
8
+ }
9
+ ?>
lib/Oink/Services/Interfaces/ISerializationService.php ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Oink.Services.Interfaces
4
+ */
5
+ interface ISerializationService {
6
+ /*
7
+ * Only used for testing.
8
+ * */
9
+ public function SerializeObject($object,$schemaPath);
10
+ public function DeserializeObject($serialized);
11
+ }
12
+ ?>
lib/Spyc/spyc.php ADDED
@@ -0,0 +1,1024 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Spyc -- A Simple PHP YAML Class
4
+ * @version 0.4.5
5
+ * @author Vlad Andersen <vlad.andersen@gmail.com>
6
+ * @author Chris Wanstrath <chris@ozmm.org>
7
+ * @link http://code.google.com/p/spyc/
8
+ * @copyright Copyright 2005-2006 Chris Wanstrath, 2006-2009 Vlad Andersen
9
+ * @license http://www.opensource.org/licenses/mit-license.php MIT License
10
+ * @package Spyc
11
+ */
12
+
13
+ if (!function_exists('spyc_load')) {
14
+ /**
15
+ * Parses YAML to array.
16
+ * @param string $string YAML string.
17
+ * @return array
18
+ */
19
+ function spyc_load ($string) {
20
+ return Spyc::YAMLLoadString($string);
21
+ }
22
+ }
23
+
24
+ if (!function_exists('spyc_load_file')) {
25
+ /**
26
+ * Parses YAML to array.
27
+ * @param string $file Path to YAML file.
28
+ * @return array
29
+ */
30
+ function spyc_load_file ($file) {
31
+ return Spyc::YAMLLoad($file);
32
+ }
33
+ }
34
+
35
+ /**
36
+ * The Simple PHP YAML Class.
37
+ *
38
+ * This class can be used to read a YAML file and convert its contents
39
+ * into a PHP array. It currently supports a very limited subsection of
40
+ * the YAML spec.
41
+ *
42
+ * Usage:
43
+ * <code>
44
+ * $Spyc = new Spyc;
45
+ * $array = $Spyc->load($file);
46
+ * </code>
47
+ * or:
48
+ * <code>
49
+ * $array = Spyc::YAMLLoad($file);
50
+ * </code>
51
+ * or:
52
+ * <code>
53
+ * $array = spyc_load_file($file);
54
+ * </code>
55
+ * @package Spyc
56
+ */
57
+ class Spyc {
58
+
59
+ // SETTINGS
60
+
61
+ /**
62
+ * Setting this to true will force YAMLDump to enclose any string value in
63
+ * quotes. False by default.
64
+ *
65
+ * @var bool
66
+ */
67
+ public $setting_dump_force_quotes = false;
68
+
69
+ /**
70
+ * Setting this to true will forse YAMLLoad to use syck_load function when
71
+ * possible. False by default.
72
+ * @var bool
73
+ */
74
+ public $setting_use_syck_is_possible = false;
75
+
76
+
77
+
78
+ /**#@+
79
+ * @access private
80
+ * @var mixed
81
+ */
82
+ private $_dumpIndent;
83
+ private $_dumpWordWrap;
84
+ private $_containsGroupAnchor = false;
85
+ private $_containsGroupAlias = false;
86
+ private $path;
87
+ private $result;
88
+ private $LiteralPlaceHolder = '___YAML_Literal_Block___';
89
+ private $SavedGroups = array();
90
+ private $indent;
91
+ /**
92
+ * Path modifier that should be applied after adding current element.
93
+ * @var array
94
+ */
95
+ private $delayedPath = array();
96
+
97
+ /**#@+
98
+ * @access public
99
+ * @var mixed
100
+ */
101
+ public $_nodeId;
102
+
103
+ /**
104
+ * Load a valid YAML string to Spyc.
105
+ * @param string $input
106
+ * @return array
107
+ */
108
+ public function load ($input) {
109
+ return $this->__loadString($input);
110
+ }
111
+
112
+ /**
113
+ * Load a valid YAML file to Spyc.
114
+ * @param string $file
115
+ * @return array
116
+ */
117
+ public function loadFile ($file) {
118
+ return $this->__load($file);
119
+ }
120
+
121
+ /**
122
+ * Load YAML into a PHP array statically
123
+ *
124
+ * The load method, when supplied with a YAML stream (string or file),
125
+ * will do its best to convert YAML in a file into a PHP array. Pretty
126
+ * simple.
127
+ * Usage:
128
+ * <code>
129
+ * $array = Spyc::YAMLLoad('lucky.yaml');
130
+ * print_r($array);
131
+ * </code>
132
+ * @access public
133
+ * @return array
134
+ * @param string $input Path of YAML file or string containing YAML
135
+ */
136
+ public static function YAMLLoad($input) {
137
+ $Spyc = new Spyc;
138
+ return $Spyc->__load($input);
139
+ }
140
+
141
+ /**
142
+ * Load a string of YAML into a PHP array statically
143
+ *
144
+ * The load method, when supplied with a YAML string, will do its best
145
+ * to convert YAML in a string into a PHP array. Pretty simple.
146
+ *
147
+ * Note: use this function if you don't want files from the file system
148
+ * loaded and processed as YAML. This is of interest to people concerned
149
+ * about security whose input is from a string.
150
+ *
151
+ * Usage:
152
+ * <code>
153
+ * $array = Spyc::YAMLLoadString("---\n0: hello world\n");
154
+ * print_r($array);
155
+ * </code>
156
+ * @access public
157
+ * @return array
158
+ * @param string $input String containing YAML
159
+ */
160
+ public static function YAMLLoadString($input) {
161
+ $Spyc = new Spyc;
162
+ return $Spyc->__loadString($input);
163
+ }
164
+
165
+ /**
166
+ * Dump YAML from PHP array statically
167
+ *
168
+ * The dump method, when supplied with an array, will do its best
169
+ * to convert the array into friendly YAML. Pretty simple. Feel free to
170
+ * save the returned string as nothing.yaml and pass it around.
171
+ *
172
+ * Oh, and you can decide how big the indent is and what the wordwrap
173
+ * for folding is. Pretty cool -- just pass in 'false' for either if
174
+ * you want to use the default.
175
+ *
176
+ * Indent's default is 2 spaces, wordwrap's default is 40 characters. And
177
+ * you can turn off wordwrap by passing in 0.
178
+ *
179
+ * @access public
180
+ * @return string
181
+ * @param array $array PHP array
182
+ * @param int $indent Pass in false to use the default, which is 2
183
+ * @param int $wordwrap Pass in 0 for no wordwrap, false for default (40)
184
+ */
185
+ public static function YAMLDump($array,$indent = false,$wordwrap = false) {
186
+ $spyc = new Spyc;
187
+ return $spyc->dump($array,$indent,$wordwrap);
188
+ }
189
+
190
+
191
+ /**
192
+ * Dump PHP array to YAML
193
+ *
194
+ * The dump method, when supplied with an array, will do its best
195
+ * to convert the array into friendly YAML. Pretty simple. Feel free to
196
+ * save the returned string as tasteful.yaml and pass it around.
197
+ *
198
+ * Oh, and you can decide how big the indent is and what the wordwrap
199
+ * for folding is. Pretty cool -- just pass in 'false' for either if
200
+ * you want to use the default.
201
+ *
202
+ * Indent's default is 2 spaces, wordwrap's default is 40 characters. And
203
+ * you can turn off wordwrap by passing in 0.
204
+ *
205
+ * @access public
206
+ * @return string
207
+ * @param array $array PHP array
208
+ * @param int $indent Pass in false to use the default, which is 2
209
+ * @param int $wordwrap Pass in 0 for no wordwrap, false for default (40)
210
+ */
211
+ public function dump($array,$indent = false,$wordwrap = false) {
212
+ // Dumps to some very clean YAML. We'll have to add some more features
213
+ // and options soon. And better support for folding.
214
+
215
+ // New features and options.
216
+ if ($indent === false or !is_numeric($indent)) {
217
+ $this->_dumpIndent = 2;
218
+ } else {
219
+ $this->_dumpIndent = $indent;
220
+ }
221
+
222
+ if ($wordwrap === false or !is_numeric($wordwrap)) {
223
+ $this->_dumpWordWrap = 40;
224
+ } else {
225
+ $this->_dumpWordWrap = $wordwrap;
226
+ }
227
+
228
+ // New YAML document
229
+ $string = "---\n";
230
+
231
+ // Start at the base of the array and move through it.
232
+ if ($array) {
233
+ $array = (array)$array;
234
+ $first_key = key($array);
235
+
236
+ $previous_key = -1;
237
+ foreach ($array as $key => $value) {
238
+ $string .= $this->_yamlize($key,$value,0,$previous_key, $first_key);
239
+ $previous_key = $key;
240
+ }
241
+ }
242
+ return $string;
243
+ }
244
+
245
+ /**
246
+ * Attempts to convert a key / value array item to YAML
247
+ * @access private
248
+ * @return string
249
+ * @param $key The name of the key
250
+ * @param $value The value of the item
251
+ * @param $indent The indent of the current node
252
+ */
253
+ private function _yamlize($key,$value,$indent, $previous_key = -1, $first_key = 0) {
254
+ if (is_array($value)) {
255
+ if (empty ($value))
256
+ return $this->_dumpNode($key, array(), $indent, $previous_key, $first_key);
257
+ // It has children. What to do?
258
+ // Make it the right kind of item
259
+ $string = $this->_dumpNode($key, NULL, $indent, $previous_key, $first_key);
260
+ // Add the indent
261
+ $indent += $this->_dumpIndent;
262
+ // Yamlize the array
263
+ $string .= $this->_yamlizeArray($value,$indent);
264
+ } elseif (!is_array($value)) {
265
+ // It doesn't have children. Yip.
266
+ $string = $this->_dumpNode($key, $value, $indent, $previous_key, $first_key);
267
+ }
268
+ return $string;
269
+ }
270
+
271
+ /**
272
+ * Attempts to convert an array to YAML
273
+ * @access private
274
+ * @return string
275
+ * @param $array The array you want to convert
276
+ * @param $indent The indent of the current level
277
+ */
278
+ private function _yamlizeArray($array,$indent) {
279
+ if (is_array($array)) {
280
+ $string = '';
281
+ $previous_key = -1;
282
+ $first_key = key($array);
283
+ foreach ($array as $key => $value) {
284
+ $string .= $this->_yamlize($key, $value, $indent, $previous_key, $first_key);
285
+ $previous_key = $key;
286
+ }
287
+ return $string;
288
+ } else {
289
+ return false;
290
+ }
291
+ }
292
+
293
+ /**
294
+ * Returns YAML from a key and a value
295
+ * @access private
296
+ * @return string
297
+ * @param $key The name of the key
298
+ * @param $value The value of the item
299
+ * @param $indent The indent of the current node
300
+ */
301
+ private function _dumpNode($key, $value, $indent, $previous_key = -1, $first_key = 0) {
302
+ // do some folding here, for blocks
303
+ if (is_string ($value) && ((strpos($value,"\n") !== false || strpos($value,": ") !== false || strpos($value,"- ") !== false ||
304
+ strpos($value,"*") !== false || strpos($value,"#") !== false || strpos($value,"<") !== false || strpos($value,">") !== false ||
305
+ strpos($value,"[") !== false || strpos($value,"]") !== false || strpos($value,"{") !== false || strpos($value,"}") !== false) || substr ($value, -1, 1) == ':')) {
306
+ $value = $this->_doLiteralBlock($value,$indent);
307
+ } else {
308
+ $value = $this->_doFolding($value,$indent);
309
+ if (is_bool($value)) {
310
+ $value = ($value) ? "true" : "false";
311
+ }
312
+ }
313
+
314
+ if ($value === array()) $value = '[ ]';
315
+
316
+ $spaces = str_repeat(' ',$indent);
317
+
318
+ if (is_int($key) && $key - 1 == $previous_key && $first_key===0) {
319
+ // It's a sequence
320
+ $string = $spaces.'- '.$value."\n";
321
+ } else {
322
+ if ($first_key===0) throw new Exception('Keys are all screwy. The first one was zero, now it\'s "'. $key .'"');
323
+ // It's mapped
324
+ if (strpos($key, ":") !== false) { $key = '"' . $key . '"'; }
325
+ $string = $spaces.$key.': '.$value."\n";
326
+ }
327
+ return $string;
328
+ }
329
+
330
+ /**
331
+ * Creates a literal block for dumping
332
+ * @access private
333
+ * @return string
334
+ * @param $value
335
+ * @param $indent int The value of the indent
336
+ */
337
+ private function _doLiteralBlock($value,$indent) {
338
+ if (strpos($value, "\n") === false && strpos($value, "'") === false) {
339
+ return sprintf ("'%s'", $value);
340
+ }
341
+ if (strpos($value, "\n") === false && strpos($value, '"') === false) {
342
+ return sprintf ('"%s"', $value);
343
+ }
344
+ $exploded = explode("\n",$value);
345
+ $newValue = '|';
346
+ $indent += $this->_dumpIndent;
347
+ $spaces = str_repeat(' ',$indent);
348
+ foreach ($exploded as $line) {
349
+ $newValue .= "\n" . $spaces . trim($line);
350
+ }
351
+ return $newValue;
352
+ }
353
+
354
+ /**
355
+ * Folds a string of text, if necessary
356
+ * @access private
357
+ * @return string
358
+ * @param $value The string you wish to fold
359
+ */
360
+ private function _doFolding($value,$indent) {
361
+ // Don't do anything if wordwrap is set to 0
362
+
363
+ if ($this->_dumpWordWrap !== 0 && is_string ($value) && strlen($value) > $this->_dumpWordWrap) {
364
+ $indent += $this->_dumpIndent;
365
+ $indent = str_repeat(' ',$indent);
366
+ $wrapped = wordwrap($value,$this->_dumpWordWrap,"\n$indent");
367
+ $value = ">\n".$indent.$wrapped;
368
+ } else {
369
+ if ($this->setting_dump_force_quotes && is_string ($value))
370
+ $value = '"' . $value . '"';
371
+ }
372
+
373
+
374
+ return $value;
375
+ }
376
+
377
+ // LOADING FUNCTIONS
378
+
379
+ private function __load($input) {
380
+ $Source = $this->loadFromSource($input);
381
+ return $this->loadWithSource($Source);
382
+ }
383
+
384
+ private function __loadString($input) {
385
+ $Source = $this->loadFromString($input);
386
+ return $this->loadWithSource($Source);
387
+ }
388
+
389
+ private function loadWithSource($Source) {
390
+ if (empty ($Source)) return array();
391
+ if ($this->setting_use_syck_is_possible && function_exists ('syck_load')) {
392
+ $array = syck_load (implode ('', $Source));
393
+ return is_array($array) ? $array : array();
394
+ }
395
+
396
+ $this->path = array();
397
+ $this->result = array();
398
+
399
+ $cnt = count($Source);
400
+ for ($i = 0; $i < $cnt; $i++) {
401
+ $line = $Source[$i];
402
+
403
+ $this->indent = strlen($line) - strlen(ltrim($line));
404
+ $tempPath = $this->getParentPathByIndent($this->indent);
405
+ $line = self::stripIndent($line, $this->indent);
406
+ if (self::isComment($line)) continue;
407
+ if (self::isEmpty($line)) continue;
408
+ $this->path = $tempPath;
409
+
410
+ $literalBlockStyle = self::startsLiteralBlock($line);
411
+ if ($literalBlockStyle) {
412
+ $line = rtrim ($line, $literalBlockStyle . " \n");
413
+ $literalBlock = '';
414
+ $line .= $this->LiteralPlaceHolder;
415
+
416
+ while (++$i < $cnt && $this->literalBlockContinues($Source[$i], $this->indent)) {
417
+ $literalBlock = $this->addLiteralLine($literalBlock, $Source[$i], $literalBlockStyle);
418
+ }
419
+ $i--;
420
+ }
421
+
422
+ while (++$i < $cnt && self::greedilyNeedNextLine($line)) {
423
+ $line = rtrim ($line, " \n\t\r") . ' ' . ltrim ($Source[$i], " \t");
424
+ }
425
+ $i--;
426
+
427
+
428
+
429
+ if (strpos ($line, '#')) {
430
+ if (strpos ($line, '"') === false && strpos ($line, "'") === false)
431
+ $line = preg_replace('/\s+#(.+)$/','',$line);
432
+ }
433
+
434
+ $lineArray = $this->_parseLine($line);
435
+
436
+ if ($literalBlockStyle)
437
+ $lineArray = $this->revertLiteralPlaceHolder ($lineArray, $literalBlock);
438
+
439
+ $this->addArray($lineArray, $this->indent);
440
+
441
+ foreach ($this->delayedPath as $indent => $delayedPath)
442
+ $this->path[$indent] = $delayedPath;
443
+
444
+ $this->delayedPath = array();
445
+
446
+ }
447
+ return $this->result;
448
+ }
449
+
450
+ private function loadFromSource ($input) {
451
+ if (!empty($input) && strpos($input, "\n") === false && file_exists($input))
452
+ return file($input);
453
+
454
+ return $this->loadFromString($input);
455
+ }
456
+
457
+ private function loadFromString ($input) {
458
+ $lines = explode("\n",$input);
459
+ foreach ($lines as $k => $_) {
460
+ $lines[$k] = rtrim ($_, "\r");
461
+ }
462
+ return $lines;
463
+ }
464
+
465
+ /**
466
+ * Parses YAML code and returns an array for a node
467
+ * @access private
468
+ * @return array
469
+ * @param string $line A line from the YAML file
470
+ */
471
+ private function _parseLine($line) {
472
+ if (!$line) return array();
473
+ $line = trim($line);
474
+
475
+ if (!$line) return array();
476
+ $array = array();
477
+
478
+ $group = $this->nodeContainsGroup($line);
479
+ if ($group) {
480
+ $this->addGroup($line, $group);
481
+ $line = $this->stripGroup ($line, $group);
482
+ }
483
+
484
+ if ($this->startsMappedSequence($line))
485
+ return $this->returnMappedSequence($line);
486
+
487
+ if ($this->startsMappedValue($line))
488
+ return $this->returnMappedValue($line);
489
+
490
+ if ($this->isArrayElement($line))
491
+ return $this->returnArrayElement($line);
492
+
493
+ if ($this->isPlainArray($line))
494
+ return $this->returnPlainArray($line);
495
+
496
+
497
+ return $this->returnKeyValuePair($line);
498
+
499
+ }
500
+
501
+ /**
502
+ * Finds the type of the passed value, returns the value as the new type.
503
+ * @access private
504
+ * @param string $value
505
+ * @return mixed
506
+ */
507
+ private function _toType($value) {
508
+ if ($value === '') return null;
509
+ $first_character = $value[0];
510
+ $last_character = substr($value, -1, 1);
511
+
512
+ $is_quoted = false;
513
+ do {
514
+ if (!$value) break;
515
+ if ($first_character != '"' && $first_character != "'") break;
516
+ if ($last_character != '"' && $last_character != "'") break;
517
+ $is_quoted = true;
518
+ } while (0);
519
+
520
+ if ($is_quoted)
521
+ return strtr(substr ($value, 1, -1), array ('\\"' => '"', '\'\'' => '\'', '\\\'' => '\''));
522
+
523
+ if (strpos($value, ' #') !== false)
524
+ $value = preg_replace('/\s+#(.+)$/','',$value);
525
+
526
+ if ($first_character == '[' && $last_character == ']') {
527
+ // Take out strings sequences and mappings
528
+ $innerValue = trim(substr ($value, 1, -1));
529
+ if ($innerValue === '') return array();
530
+ $explode = $this->_inlineEscape($innerValue);
531
+ // Propagate value array
532
+ $value = array();
533
+ foreach ($explode as $v) {
534
+ $value[] = $this->_toType($v);
535
+ }
536
+ return $value;
537
+ }
538
+
539
+ if (strpos($value,': ')!==false && $first_character != '{') {
540
+ $array = explode(': ',$value);
541
+ $key = trim($array[0]);
542
+ array_shift($array);
543
+ $value = trim(implode(': ',$array));
544
+ $value = $this->_toType($value);
545
+ return array($key => $value);
546
+ }
547
+
548
+ if ($first_character == '{' && $last_character == '}') {
549
+ $innerValue = trim(substr ($value, 1, -1));
550
+ if ($innerValue === '') return array();
551
+ // Inline Mapping
552
+ // Take out strings sequences and mappings
553
+ $explode = $this->_inlineEscape($innerValue);
554
+ // Propagate value array
555
+ $array = array();
556
+ foreach ($explode as $v) {
557
+ $SubArr = $this->_toType($v);
558
+ if (empty($SubArr)) continue;
559
+ if (is_array ($SubArr)) {
560
+ $array[key($SubArr)] = $SubArr[key($SubArr)]; continue;
561
+ }
562
+ $array[] = $SubArr;
563
+ }
564
+ return $array;
565
+ }
566
+
567
+ if ($value == 'null' || $value == 'NULL' || $value == 'Null' || $value == '' || $value == '~') {
568
+ return null;
569
+ }
570
+
571
+ if (intval($first_character) > 0 && preg_match ('/^[1-9]+[0-9]*$/', $value)) {
572
+ $intvalue = (int)$value;
573
+ if ($intvalue != PHP_INT_MAX)
574
+ $value = $intvalue;
575
+ return $value;
576
+ }
577
+
578
+ if (in_array($value,
579
+ array('true', 'on', '+', 'yes', 'y', 'True', 'TRUE', 'On', 'ON', 'YES', 'Yes', 'Y'))) {
580
+ return true;
581
+ }
582
+
583
+ if (in_array(strtolower($value),
584
+ array('false', 'off', '-', 'no', 'n'))) {
585
+ return false;
586
+ }
587
+
588
+ if (is_numeric($value)) {
589
+ if ($value === '0') return 0;
590
+ if (trim ($value, 0) === $value)
591
+ $value = (float)$value;
592
+ return $value;
593
+ }
594
+
595
+ return $value;
596
+ }
597
+
598
+ /**
599
+ * Used in inlines to check for more inlines or quoted strings
600
+ * @access private
601
+ * @return array
602
+ */
603
+ private function _inlineEscape($inline) {
604
+ // There's gotta be a cleaner way to do this...
605
+ // While pure sequences seem to be nesting just fine,
606
+ // pure mappings and mappings with sequences inside can't go very
607
+ // deep. This needs to be fixed.
608
+
609
+ $seqs = array();
610
+ $maps = array();
611
+ $saved_strings = array();
612
+
613
+ // Check for strings
614
+ $regex = '/(?:(")|(?:\'))((?(1)[^"]+|[^\']+))(?(1)"|\')/';
615
+ if (preg_match_all($regex,$inline,$strings)) {
616
+ $saved_strings = $strings[0];
617
+ $inline = preg_replace($regex,'YAMLString',$inline);
618
+ }
619
+ unset($regex);
620
+
621
+ $i = 0;
622
+ do {
623
+
624
+ // Check for sequences
625
+ while (preg_match('/\[([^{}\[\]]+)\]/U',$inline,$matchseqs)) {
626
+ $seqs[] = $matchseqs[0];
627
+ $inline = preg_replace('/\[([^{}\[\]]+)\]/U', ('YAMLSeq' . (count($seqs) - 1) . 's'), $inline, 1);
628
+ }
629
+
630
+ // Check for mappings
631
+ while (preg_match('/{([^\[\]{}]+)}/U',$inline,$matchmaps)) {
632
+ $maps[] = $matchmaps[0];
633
+ $inline = preg_replace('/{([^\[\]{}]+)}/U', ('YAMLMap' . (count($maps) - 1) . 's'), $inline, 1);
634
+ }
635
+
636
+ if ($i++ >= 10) break;
637
+
638
+ } while (strpos ($inline, '[') !== false || strpos ($inline, '{') !== false);
639
+
640
+ $explode = explode(', ',$inline);
641
+ $stringi = 0; $i = 0;
642
+
643
+ while (1) {
644
+
645
+ // Re-add the sequences
646
+ if (!empty($seqs)) {
647
+ foreach ($explode as $key => $value) {
648
+ if (strpos($value,'YAMLSeq') !== false) {
649
+ foreach ($seqs as $seqk => $seq) {
650
+ $explode[$key] = str_replace(('YAMLSeq'.$seqk.'s'),$seq,$value);
651
+ $value = $explode[$key];
652
+ }
653
+ }
654
+ }
655
+ }
656
+
657
+ // Re-add the mappings
658
+ if (!empty($maps)) {
659
+ foreach ($explode as $key => $value) {
660
+ if (strpos($value,'YAMLMap') !== false) {
661
+ foreach ($maps as $mapk => $map) {
662
+ $explode[$key] = str_replace(('YAMLMap'.$mapk.'s'), $map, $value);
663
+ $value = $explode[$key];
664
+ }
665
+ }
666
+ }
667
+ }
668
+
669
+
670
+ // Re-add the strings
671
+ if (!empty($saved_strings)) {
672
+ foreach ($explode as $key => $value) {
673
+ while (strpos($value,'YAMLString') !== false) {
674
+ $explode[$key] = preg_replace('/YAMLString/',$saved_strings[$stringi],$value, 1);
675
+ unset($saved_strings[$stringi]);
676
+ ++$stringi;
677
+ $value = $explode[$key];
678
+ }
679
+ }
680
+ }
681
+
682
+ $finished = true;
683
+ foreach ($explode as $key => $value) {
684
+ if (strpos($value,'YAMLSeq') !== false) {
685
+ $finished = false; break;
686
+ }
687
+ if (strpos($value,'YAMLMap') !== false) {
688
+ $finished = false; break;
689
+ }
690
+ if (strpos($value,'YAMLString') !== false) {
691
+ $finished = false; break;
692
+ }
693
+ }
694
+ if ($finished) break;
695
+
696
+ $i++;
697
+ if ($i > 10)
698
+ break; // Prevent infinite loops.
699
+ }
700
+
701
+ return $explode;
702
+ }
703
+
704
+ private function literalBlockContinues ($line, $lineIndent) {
705
+ if (!trim($line)) return true;
706
+ if (strlen($line) - strlen(ltrim($line)) > $lineIndent) return true;
707
+ return false;
708
+ }
709
+
710
+ private function referenceContentsByAlias ($alias) {
711
+ do {
712
+ if (!isset($this->SavedGroups[$alias])) { echo "Bad group name: $alias."; break; }
713
+ $groupPath = $this->SavedGroups[$alias];
714
+ $value = $this->result;
715
+ foreach ($groupPath as $k) {
716
+ $value = $value[$k];
717
+ }
718
+ } while (false);
719
+ return $value;
720
+ }
721
+
722
+ private function addArrayInline ($array, $indent) {
723
+ $CommonGroupPath = $this->path;
724
+ if (empty ($array)) return false;
725
+
726
+ foreach ($array as $k => $_) {
727
+ $this->addArray(array($k => $_), $indent);
728
+ $this->path = $CommonGroupPath;
729
+ }
730
+ return true;
731
+ }
732
+
733
+ private function addArray ($incoming_data, $incoming_indent) {
734
+
735
+ // print_r ($incoming_data);
736
+
737
+ if (count ($incoming_data) > 1)
738
+ return $this->addArrayInline ($incoming_data, $incoming_indent);
739
+
740
+ $key = key ($incoming_data);
741
+ $value = isset($incoming_data[$key]) ? $incoming_data[$key] : null;
742
+ if ($key === '__!YAMLZero') $key = '0';
743
+
744
+ if ($incoming_indent == 0 && !$this->_containsGroupAlias && !$this->_containsGroupAnchor) { // Shortcut for root-level values.
745
+ if ($key || $key === '' || $key === '0') {
746
+ $this->result[$key] = $value;
747
+ } else {
748
+ $this->result[] = $value; end ($this->result); $key = key ($this->result);
749
+ }
750
+ $this->path[$incoming_indent] = $key;
751
+ return;
752
+ }
753
+
754
+
755
+
756
+ $history = array();
757
+ // Unfolding inner array tree.
758
+ $history[] = $_arr = $this->result;
759
+ foreach ($this->path as $k) {
760
+ $history[] = $_arr = $_arr[$k];
761
+ }
762
+
763
+ if ($this->_containsGroupAlias) {
764
+ $value = $this->referenceContentsByAlias($this->_containsGroupAlias);
765
+ $this->_containsGroupAlias = false;
766
+ }
767
+
768
+
769
+ // Adding string or numeric key to the innermost level or $this->arr.
770
+ if (is_string($key) && $key == '<<') {
771
+ if (!is_array ($_arr)) { $_arr = array (); }
772
+
773
+ $_arr = array_merge ($_arr, $value);
774
+ } else if ($key || $key === '' || $key === '0') {
775
+ $_arr[$key] = $value;
776
+ } else {
777
+ if (!is_array ($_arr)) { $_arr = array ($value); $key = 0; }
778
+ else { $_arr[] = $value; end ($_arr); $key = key ($_arr); }
779
+ }
780
+
781
+ $reverse_path = array_reverse($this->path);
782
+ $reverse_history = array_reverse ($history);
783
+ $reverse_history[0] = $_arr;
784
+ $cnt = count($reverse_history) - 1;
785
+ for ($i = 0; $i < $cnt; $i++) {
786
+ $reverse_history[$i+1][$reverse_path[$i]] = $reverse_history[$i];
787
+ }
788
+ $this->result = $reverse_history[$cnt];
789
+
790
+ $this->path[$incoming_indent] = $key;
791
+
792
+ if ($this->_containsGroupAnchor) {
793
+ $this->SavedGroups[$this->_containsGroupAnchor] = $this->path;
794
+ if (is_array ($value)) {
795
+ $k = key ($value);
796
+ if (!is_int ($k)) {
797
+ $this->SavedGroups[$this->_containsGroupAnchor][$incoming_indent + 2] = $k;
798
+ }
799
+ }
800
+ $this->_containsGroupAnchor = false;
801
+ }
802
+
803
+ }
804
+
805
+ private static function startsLiteralBlock ($line) {
806
+ $lastChar = substr (trim($line), -1);
807
+ if ($lastChar != '>' && $lastChar != '|') return false;
808
+ if ($lastChar == '|') return $lastChar;
809
+ // HTML tags should not be counted as literal blocks.
810
+ if (preg_match ('#<.*?>$#', $line)) return false;
811
+ return $lastChar;
812
+ }
813
+
814
+ private static function greedilyNeedNextLine($line) {
815
+ $line = trim ($line);
816
+ if (!strlen($line)) return false;
817
+ if (substr ($line, -1, 1) == ']') return false;
818
+ if ($line[0] == '[') return true;
819
+ if (preg_match ('#^[^:]+?:\s*\[#', $line)) return true;
820
+ return false;
821
+ }
822
+
823
+ private function addLiteralLine ($literalBlock, $line, $literalBlockStyle) {
824
+ $line = self::stripIndent($line);
825
+ $line = rtrim ($line, "\r\n\t ") . "\n";
826
+ if ($literalBlockStyle == '|') {
827
+ return $literalBlock . $line;
828
+ }
829
+ if (strlen($line) == 0)
830
+ return rtrim($literalBlock, ' ') . "\n";
831
+ if ($line == "\n" && $literalBlockStyle == '>') {
832
+ return rtrim ($literalBlock, " \t") . "\n";
833
+ }
834
+ if ($line != "\n")
835
+ $line = trim ($line, "\r\n ") . " ";
836
+ return $literalBlock . $line;
837
+ }
838
+
839
+ function revertLiteralPlaceHolder ($lineArray, $literalBlock) {
840
+ foreach ($lineArray as $k => $_) {
841
+ if (is_array($_))
842
+ $lineArray[$k] = $this->revertLiteralPlaceHolder ($_, $literalBlock);
843
+ else if (substr($_, -1 * strlen ($this->LiteralPlaceHolder)) == $this->LiteralPlaceHolder)
844
+ $lineArray[$k] = rtrim ($literalBlock, " \r\n");
845
+ }
846
+ return $lineArray;
847
+ }
848
+
849
+ private static function stripIndent ($line, $indent = -1) {
850
+ if ($indent == -1) $indent = strlen($line) - strlen(ltrim($line));
851
+ return substr ($line, $indent);
852
+ }
853
+
854
+ private function getParentPathByIndent ($indent) {
855
+ if ($indent == 0) return array();
856
+ $linePath = $this->path;
857
+ do {
858
+ end($linePath); $lastIndentInParentPath = key($linePath);
859
+ if ($indent <= $lastIndentInParentPath) array_pop ($linePath);
860
+ } while ($indent <= $lastIndentInParentPath);
861
+ return $linePath;
862
+ }
863
+
864
+
865
+ private function clearBiggerPathValues ($indent) {
866
+
867
+
868
+ if ($indent == 0) $this->path = array();
869
+ if (empty ($this->path)) return true;
870
+
871
+ foreach ($this->path as $k => $_) {
872
+ if ($k > $indent) unset ($this->path[$k]);
873
+ }
874
+
875
+ return true;
876
+ }
877
+
878
+
879
+ private static function isComment ($line) {
880
+ if (!$line) return false;
881
+ if ($line[0] == '#') return true;
882
+ if (trim($line, " \r\n\t") == '---') return true;
883
+ return false;
884
+ }
885
+
886
+ private static function isEmpty ($line) {
887
+ return (trim ($line) === '');
888
+ }
889
+
890
+
891
+ private function isArrayElement ($line) {
892
+ if (!$line) return false;
893
+ if ($line[0] != '-') return false;
894
+ if (strlen ($line) > 3)
895
+ if (substr($line,0,3) == '---') return false;
896
+
897
+ return true;
898
+ }
899
+
900
+ private function isHashElement ($line) {
901
+ return strpos($line, ':');
902
+ }
903
+
904
+ private function isLiteral ($line) {
905
+ if ($this->isArrayElement($line)) return false;
906
+ if ($this->isHashElement($line)) return false;
907
+ return true;
908
+ }
909
+
910
+
911
+ private static function unquote ($value) {
912
+ if (!$value) return $value;
913
+ if (!is_string($value)) return $value;
914
+ if ($value[0] == '\'') return trim ($value, '\'');
915
+ if ($value[0] == '"') return trim ($value, '"');
916
+ return $value;
917
+ }
918
+
919
+ private function startsMappedSequence ($line) {
920
+ return ($line[0] == '-' && substr ($line, -1, 1) == ':');
921
+ }
922
+
923
+ private function returnMappedSequence ($line) {
924
+ $array = array();
925
+ $key = self::unquote(trim(substr($line,1,-1)));
926
+ $array[$key] = array();
927
+ $this->delayedPath = array(strpos ($line, $key) + $this->indent => $key);
928
+ return array($array);
929
+ }
930
+
931
+ private function returnMappedValue ($line) {
932
+ $array = array();
933
+ $key = self::unquote (trim(substr($line,0,-1)));
934
+ $array[$key] = '';
935
+ return $array;
936
+ }
937
+
938
+ private function startsMappedValue ($line) {
939
+ return (substr ($line, -1, 1) == ':');
940
+ }
941
+
942
+ private function isPlainArray ($line) {
943
+ return ($line[0] == '[' && substr ($line, -1, 1) == ']');
944
+ }
945
+
946
+ private function returnPlainArray ($line) {
947
+ return $this->_toType($line);
948
+ }
949
+
950
+ private function returnKeyValuePair ($line) {
951
+ $array = array();
952
+ $key = '';
953
+ if (strpos ($line, ':')) {
954
+ // It's a key/value pair most likely
955
+ // If the key is in double quotes pull it out
956
+ if (($line[0] == '"' || $line[0] == "'") && preg_match('/^(["\'](.*)["\'](\s)*:)/',$line,$matches)) {
957
+ $value = trim(str_replace($matches[1],'',$line));
958
+ $key = $matches[2];
959
+ } else {
960
+ // Do some guesswork as to the key and the value
961
+ $explode = explode(':',$line);
962
+ $key = trim($explode[0]);
963
+ array_shift($explode);
964
+ $value = trim(implode(':',$explode));
965
+ }
966
+ // Set the type of the value. Int, string, etc
967
+ $value = $this->_toType($value);
968
+ if ($key === '0') $key = '__!YAMLZero';
969
+ $array[$key] = $value;
970
+ } else {
971
+ $array = array ($line);
972
+ }
973
+ return $array;
974
+
975
+ }
976
+
977
+
978
+ private function returnArrayElement ($line) {
979
+ if (strlen($line) <= 1) return array(array()); // Weird %)
980
+ $array = array();
981
+ $value = trim(substr($line,1));
982
+ $value = $this->_toType($value);
983
+ $array[] = $value;
984
+ return $array;
985
+ }
986
+
987
+
988
+ private function nodeContainsGroup ($line) {
989
+ $symbolsForReference = 'A-z0-9_\-';
990
+ if (strpos($line, '&') === false && strpos($line, '*') === false) return false; // Please die fast ;-)
991
+ if ($line[0] == '&' && preg_match('/^(&['.$symbolsForReference.']+)/', $line, $matches)) return $matches[1];
992
+ if ($line[0] == '*' && preg_match('/^(\*['.$symbolsForReference.']+)/', $line, $matches)) return $matches[1];
993
+ if (preg_match('/(&['.$symbolsForReference.']+)$/', $line, $matches)) return $matches[1];
994
+ if (preg_match('/(\*['.$symbolsForReference.']+$)/', $line, $matches)) return $matches[1];
995
+ if (preg_match ('#^\s*<<\s*:\s*(\*[^\s]+).*$#', $line, $matches)) return $matches[1];
996
+ return false;
997
+
998
+ }
999
+
1000
+ private function addGroup ($line, $group) {
1001
+ if ($group[0] == '&') $this->_containsGroupAnchor = substr ($group, 1);
1002
+ if ($group[0] == '*') $this->_containsGroupAlias = substr ($group, 1);
1003
+ //print_r ($this->path);
1004
+ }
1005
+
1006
+ private function stripGroup ($line, $group) {
1007
+ $line = trim(str_replace($group, '', $line));
1008
+ return $line;
1009
+ }
1010
+ }
1011
+
1012
+ // Enable use of Spyc from command line
1013
+ // The syntax is the following: php spyc.php spyc.yaml
1014
+
1015
+ define ('SPYC_FROM_COMMAND_LINE', false);
1016
+
1017
+ do {
1018
+ if (!SPYC_FROM_COMMAND_LINE) break;
1019
+ if (empty ($_SERVER['argc']) || $_SERVER['argc'] < 2) break;
1020
+ if (empty ($_SERVER['PHP_SELF']) || $_SERVER['PHP_SELF'] != 'spyc.php') break;
1021
+ $file = $argv[1];
1022
+ printf ("Spyc loading file: %s\n", $file);
1023
+ print_r (spyc_load_file ($file));
1024
+ } while (0);
package.xml ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <package>
3
+ <name>Oink</name>
4
+ <version>3.0.1</version>
5
+ <stability>stable</stability>
6
+ <license>LGPL</license>
7
+ <channel>community</channel>
8
+ <extends/>
9
+ <summary>Oink is a module for eCommerce storefronts that allows children to safely make online purchases.</summary>
10
+ <description>Oink gives young customers the ability to safely make COPPA (Child Online Privacy Protection Act) compliant purchases online, without providing any personal information. Parents can control all aspects of the child account, including monthly allowance and approved merchants. Best of all, it&#x2019;s free for families to use and easy to set up.</description>
11
+ <notes>Bug fixes</notes>
12
+ <authors><author><name>Dane De Forest</name><user>danevp</user><email>dane@virtualpiggy.com</email></author></authors>
13
+ <date>2014-05-27</date>
14
+ <time>21:01:07</time>
15
+ <contents><target name="magelocal"><dir name="Oink"><dir name="MatrixrateIntegration"><dir name="Model"><file name="Observer.php" hash="1ad95c4d1d9814e22145d4a452d62f15"/></dir><dir name="etc"><file name="config.xml" hash="df4259c1073f399c8da554669fd08e3d"/></dir></dir><dir name="Oink"><dir name="Block"><dir name="Adminhtml"><dir name="Sales"><dir name="Order"><dir name="View"><dir name="Tab"><file name="Oink.php" hash="88f2869eb2f9a61b9d5c1d0c58da4ccb"/></dir></dir></dir></dir><dir name="System"><dir name="Config"><dir name="TestConnection"><file name="Html.php" hash="4493dc6d68b1054ad107aaccd90f8849"/></dir><file name="TestConnection.php" hash="7c5ed95a15a3795d08a03e70edac8e38"/><file name="Version.php" hash="567ce2916cfce5874be4b23a231b856f"/></dir></dir></dir><dir name="Checkout"><file name="Button.php" hash="1b25bcf121c5fd2e1b044c88bdabba43"/><dir name="ParentConfirm"><file name="CSelect.php" hash="07a1c5eb4583eda741cb3f9074f2efc5"/><file name="Payment.php" hash="1fdf2136a5abf8cc6d676baade20eae2"/></dir><file name="ParentConfirm.php" hash="c07914c6f913342cb7d86f662a55ac94"/><dir name="Review"><file name="Info.php" hash="1052609c22610e092f8974d7b02543bb"/></dir><file name="Review.php" hash="7a0710ba02a395036ae5e419c314bac8"/></dir><dir name="Payment"><dir name="Form"><file name="Oink.php" hash="0cc55a3f273512cb0ea408d0f3443b4a"/></dir><dir name="Info"><file name="Oink.php" hash="513559d214b08926dbb6d2fe4914ee63"/></dir></dir><dir name="Rewrite"><dir name="Checkout"><dir name="Onepage"><file name="Login.php" hash="0d7751b75dbb856550f36cd2aae83c16"/></dir></dir></dir></dir><dir name="Helper"><file name="Checkout.php" hash="270f4a273c6ffcf68c5f2293387cb7d2"/><file name="Data.php" hash="ba01d2f1f3be4488772188218f405228"/><file name="LibLoader.php" hash="a9a8b826b02106a9865c74244ff69415"/></dir><dir name="Model"><dir name="Admin"><file name="Checkout.php" hash="ce7a86912e7f07e65beefa9099f99a59"/><file name="Enablestatus.php" hash="f4e118ffafcc36f2d180383ee2a3d4a6"/></dir><file name="ErrorHandler.php" hash="38fa82bff169fb6eaad8d350e930e348"/><dir name="Mysql4"><dir name="Order"><file name="Collection.php" hash="943f3891c5965f8dc0b2db13e3ad403d"/></dir><file name="Order.php" hash="657eb776a8ca0487e76b27f53d59463b"/></dir><file name="Observer.php" hash="04aa15210ca430746892405985f3e12d"/><file name="Order.php" hash="774ea4ac5437025bb91c776ea9b14f42"/><dir name="Payment"><dir name="Method"><file name="Oink.php" hash="43e8e89139029c1918e45b7128ccb5ae"/></dir></dir><dir name="Sales"><dir name="Order"><file name="Payment.php" hash="8dfe63c381d86fd75d3093e6d7e129f8"/></dir><file name="Order.php" hash="31fd730faace9a0d15385cb7f2343d2d"/></dir><dir name="System"><dir name="Config"><dir name="Source"><dir name="Shipping"><file name="Carriers.php" hash="3c502ed259db8d94f1e71daf2a919b5f"/></dir></dir></dir></dir><dir name="User"><file name="Children.php" hash="348f3626d64519a58858ac4828593e6b"/><file name="Parent.php" hash="5096b9fb24f350d78fa4d9b9a4bbb9b2"/></dir><file name="User.php" hash="85fed8cfeeb166554edc9bcaec0f8421"/></dir><dir name="Test"><dir name="Controller2"><dir name="CheckoutController"><dir name="providers"><file name="badLogin.yaml" hash="da49958359c3ba92baa96095b4ce7394"/><file name="goodLogin.yaml" hash="918e2f1ff926a2562252db8547bb7d8e"/></dir></dir><file name="CheckoutController.php" hash="12be796256378f01e575d8474294b482"/></dir><dir name="Helper"><dir name="Data"><dir name="fixtures"><file name="processTransaction.yaml" hash="4dbdae37f7d24221f47f121fd5579f2c"/></dir><dir name="providers"><file name="badLogin.yaml" hash="da49958359c3ba92baa96095b4ce7394"/><file name="badLoginMultipleTimes.yaml" hash="da49958359c3ba92baa96095b4ce7394"/><file name="getChildProfiles.yaml" hash="8c7facf752f16c5921f78b0267188b1c"/><file name="getUserAddress.yaml" hash="eb6310661106ddccaffc4f539efe9768"/><file name="goodLogin.yaml" hash="eb6310661106ddccaffc4f539efe9768"/><file name="processTransaction.yaml" hash="eb6310661106ddccaffc4f539efe9768"/></dir></dir><file name="Data.php" hash="bd2e177e88cd65d9ae7a06ac24eaf9d8"/></dir></dir><dir name="controllers"><dir name="Adminhtml"><file name="OinkController.php" hash="578a3cc0b4914e65adf6db4eaaaa9b23"/></dir><file name="CheckoutController.php" hash="015dc835725096d3af8088a1902e4b92"/></dir><dir name="etc"><file name="adminhtml.xml" hash="22ed149a3393086bc9e73ab2222183cb"/><file name="config.xml" hash="8516f5f4382d982089e9d58ff71919fd"/><file name="system.xml" hash="592d333a57b3cd859b631f00801f161b"/></dir><dir name="sql"><dir name="oink_setup"><file name="mysql4-install-1.0.0.0.php" hash="257a26eb67e2dc24448864d2e6f516ad"/><file name="mysql4-upgrade-1.0.0.0-1.0.0.1.php" hash="6aab451785809dbd3f3e91b7894a7c02"/><file name="mysql5-install-1.0.0.0.php" hash="257a26eb67e2dc24448864d2e6f516ad"/><file name="mysql5-upgrade-1.0.0.0-1.0.0.1.php" hash="6aab451785809dbd3f3e91b7894a7c02"/></dir></dir></dir></dir></target><target name="magecommunity"><dir name="EcomDev"><dir name="PHPUnit"><dir name="Controller"><file name="Front.php" hash="847d7e34b3cc72e3591d7ee803975cdb"/><dir name="Request"><file name="Http.php" hash="af4f28d44299e7ca0e4209690ecac69d"/></dir><dir name="Response"><file name="Http.php" hash="55d39daa2cc52d60579bcfae46c2a24a"/></dir></dir><dir name="Model"><dir name="App"><file name="Area.php" hash="d353d58095f14771057727dfd01aa961"/></dir><file name="App.php" hash="8dd3da0b8f12450a43ceee5dc7b508f0"/><file name="Config.php" hash="945b372ba1f8a3cc70da85dd00a846e7"/><dir name="Design"><file name="Package.php" hash="333c87bb0ff447934b1b0a71dec86079"/></dir><dir name="Expectation"><file name="Interface.php" hash="7b5e6b3a77b7be93a7e2a85aa6a339cb"/><file name="Object.php" hash="83576bc1b93a9708f9b43fcbf762c92b"/></dir><file name="Expectation.php" hash="a04bc23970c4037fe1eaa14743ed8e22"/><dir name="Fixture"><file name="Interface.php" hash="09aec5a338453baf0ac7dedf5d9452c7"/></dir><file name="Fixture.php" hash="47302c3144158393d5dda38bd3e4c620"/><file name="Layout.php" hash="81f4ecabaa4840a66404e659af70b69d"/><dir name="Mysql4"><dir name="Fixture"><dir name="Eav"><file name="Abstract.php" hash="e25701a2ea6869e868adb28cb7718e43"/><dir name="Catalog"><file name="Abstract.php" hash="f5798499ff5d8380442b9bb271f254f2"/><file name="Category.php" hash="93041bbc6f90ddd2ff1f7e29b58023d3"/><file name="Product.php" hash="58b6cf6cbd0aed217b6e4b6410010885"/></dir><file name="Default.php" hash="245bf00ecfb2e1efe96a3ed5d6dad589"/></dir><file name="Exception.php" hash="d1ce5cae98766f796a79f23304097ab8"/></dir><file name="Fixture.php" hash="1c5e85062bcf7a139080270e4c42b99f"/></dir><dir name="Test"><dir name="Loadable"><file name="Interface.php" hash="40be3317c5179b4fdca6c2696a15176f"/></dir></dir></dir><dir name="Test"><dir name="Case"><file name="Config.php" hash="709eeb9bca9006ed1d04860f29d7495b"/><file name="Controller.php" hash="104f85831d77910e650bd7296661472d"/></dir><file name="Case.php" hash="21489664fa9588ea3a97c35ce5066733"/><dir name="Suite"><file name="Group.php" hash="064eab1bf03faa1e1fb71b78846f0429"/></dir><file name="Suite.php" hash="3b6f8b22f20cb42c2094d03f28d20492"/></dir><dir name="etc"><file name="config.xml" hash="14e63b0adbcce9a375919da1aa15227a"/></dir></dir></dir></target><target name="magedesign"><dir name="adminhtml"><dir name="base"><dir name="default"><dir><dir name="layout"><file name="oink.xml" hash="d28ffcf3f7c0bbe99faac00169bef4ce"/></dir><dir name="template"><dir name="oink"><dir name="payment"><dir name="form"><file name="oink.phtml" hash="413f04e9914686ee5d3708f3780bb9d3"/></dir><dir name="info"><file name="oink.phtml" hash="06998a01415a9e09cfaa3806633f4249"/></dir></dir><dir name="sales"><dir name="order"><dir name="view"><dir name="tab"><file name="oink.phtml" hash="fc9e1fd549cd1fd8e4b10d3eca7346f2"/></dir></dir></dir></dir><dir name="system"><dir name="config"><file name="testConnection.phtml" hash="c4895dfa22df790854e1912b5ae161a0"/></dir></dir></dir></dir></dir></dir></dir></dir><dir name="frontend"><dir name="base"><dir name="default"><dir name="template"><dir name="oink"><dir name="checkout"><dir name="button"><file name="form.phtml" hash="b129fa59dd71f39e6e3c7fb71122d5c0"/></dir><file name="button.phtml" hash="828c9fdd0f77f1b457ad4a76574ebe57"/><dir name="cart"><file name="button.phtml" hash="a0af805290eb9487a1ee170d131c7805"/></dir><dir name="parent_confirm"><file name="c_select.phtml" hash="aa477ffaf12b7d6a24c24b5269508472"/><file name="payment.phtml" hash="7dd2bf9a8255f989f9a499a2cfff854d"/></dir><file name="parent_confirm.phtml" hash="0922a7fdaa3cb4ee4dc8ebfd35b01e4d"/><dir name="review"><file name="button.phtml" hash="3d94f2ce6ae20835e94f847705328d64"/><file name="info.phtml" hash="c888c9a46f943681856d8bd5ea45af75"/></dir><file name="review.phtml" hash="f4fad1be808013dc001e1bc725ed5038"/></dir><dir name="payment"><dir name="form"><file name="oink.phtml" hash="413f04e9914686ee5d3708f3780bb9d3"/></dir><dir name="info"><file name="oink.phtml" hash="c6d80262e171f080ced20a1d96222087"/></dir></dir></dir></dir><dir name="layout"><file name="oink.xml" hash="74a257a386b1103a9f3b9e6b3e7fd797"/></dir></dir></dir></dir></target><target name="mageetc"><dir name="."><file name="local.xml.phpunit" hash="155b3dacacad449828d3b46d9a4ff54c"/></dir><dir name="modules"><file name="EcomDev_PHPUnit.xml" hash="2c01f6939a92696235097c3911d8da95"/><file name="Oink_MatrixrateIntegration.xml" hash="38413b446bc64321a7ac213239b8d8f3"/><file name="Oink_Oink.xml" hash="55524a00acf6d5cf5c12dda5a54dc08e"/></dir></target><target name="magelocale"><dir name="en_US"><file name="Oink_Oink.csv" hash="d2a4ee9cfc8fc86777b582dd60b6a938"/></dir></target><target name="magelib"><dir name="EcomDev"><dir name="PHPUnit"><dir name="Constraint"><file name="Abstract.php" hash="8367e95443051a1a3edc03bf6a0f818e"/><dir name="Config"><file name="Abstract.php" hash="284de496c6258eed0ea7830e9c628ef5"/><file name="ClassAlias.php" hash="a177fa3fa44f87c06a4b176e3cf4eb48"/><file name="EventObserver.php" hash="af42156827ae7c63f46abff1d56acf1c"/><file name="Interface.php" hash="c14f03486e21aad667bf2a0e832f04ce"/><file name="Layout.php" hash="f1ac1c04212b04fbdb1c94a0d975189e"/><file name="Module.php" hash="cd9ec3c31e291e2162843968c527d839"/><file name="Node.php" hash="988f9cd2e06102150612d0397de8a4b9"/><dir name="Resource"><file name="Script.php" hash="2babb4ca27b94bf74f7d8c47e916e0a6"/></dir><file name="Resource.php" hash="1eeee84158a53e7dc375f5fb1161bdb5"/><file name="TableAlias.php" hash="36aa17df9ec2ea600bda9d67f273c7b6"/></dir><file name="Config.php" hash="86a33da791eea8c7ad487663913a1d47"/><dir name="Controller"><file name="Request.php" hash="4f85a7c4fd6cad201d22f3db9154d557"/><dir name="Response"><file name="Abstract.php" hash="0f15f98a34c9d8282c45b618e07fe4c5"/><file name="Body.php" hash="07fad650d0df7872e44233a4cfe8ada5"/><file name="Header.php" hash="360d8bcf11b7b9ecffd702e2e7291fec"/></dir></dir><file name="Exception.php" hash="dbc6ae2eaa64f9f38b0b43f2c98a7c99"/><file name="Json.php" hash="137b118bc053f106645f8edee8bf3966"/><dir name="Layout"><file name="Abstract.php" hash="fbe141eef4f9d64e2a5ea0eb18fae94c"/><dir name="Block"><file name="Action.php" hash="3b524c284c332348e956f42d939a0a9e"/><file name="Property.php" hash="edbb3dfdb07215c2010fa86e472cd620"/></dir><file name="Block.php" hash="3711d6d8c134f72ef41ab93da89b2f45"/><file name="Handle.php" hash="aa17b9dbbb19e8b1b701ddaf75b5fc59"/><dir name="Logger"><file name="Interface.php" hash="1b669104ba95fe085aa66ae460271424"/></dir></dir><file name="Layout.php" hash="6387afaef7588092b4931f3be60e0638"/></dir><dir name="Controller"><dir name="Request"><file name="Interface.php" hash="e7a6a4526b8c97541e14a30dd1db3b11"/></dir><dir name="Response"><file name="Interface.php" hash="7d12c9687c37ca2241d1978a13ed4553"/></dir></dir><dir name="Design"><dir name="Package"><file name="Interface.php" hash="09caa9abec26253ec318c9cb97186844"/></dir></dir><dir name="Isolation"><file name="Interface.php" hash="3d1cfc661c1178212f7b2e3e54e5d8cf"/></dir></dir><dir name="Utils"><file name="Reflection.php" hash="433a0fe545498cd25d355ac397bda5e9"/></dir></dir><dir name="Oink"><dir name="Data"><file name="dtos.php" hash="531fc293eeb0bcd7e7b8b33c671ad233"/></dir><dir name="Schemas"><file name="cart.xml" hash="67e1d6e0bb80c0807d1209a0a63b5de9"/><file name="cart_02.xml" hash="a0cc5b00e7758fc021c05de105d96e7c"/><file name="cart_03.xml" hash="c2cf1d01b25033bac8dd058ca9ef8091"/><file name="cart_04.xml" hash="608065c7c7e490ac11e7767aa2cbd8ac"/><file name="oink.xsd" hash="6cd3f6703fdcb9edcd1c5c744df3d79d"/></dir><dir name="Services"><dir name="Implementations"><file name="FormPaymentServiceConfiguration.php" hash="0ca8abd64fd6c55943acbcc0c790fb93"/><file name="MagentoPaymentServiceConfiguration.php" hash="2a8a40a32e32070ff2403f85d7f14588"/><file name="MerchantFormServiceConfiguration.php" hash="9348b07cf422ce5a8f383bc8816dc2f6"/><file name="MerchantPaymentServiceConfiguration.php" hash="787d626749fa5f148c2302297a4643e6"/><file name="MockCartService.php" hash="e405a565156c2c654794f2498eb704d3"/><file name="OinkCallbackService.php" hash="d2e5d9b31531af56bff71925fe38a729"/><file name="OinkException.php" hash="7ec08618ff5bc6229e2798e159740cee"/><file name="OinkFormService.php" hash="87db0953c68684efa7145b1efaecf4ac"/><file name="OinkLoggingService.php" hash="442ff23c4cf96bf112b2e1b17c58fc8b"/><file name="OinkParentService.php" hash="fb80f2a2d887acd8f3b40775367cc635"/><file name="OinkPaymentService.php" hash="c7b45e54a418725ce5128d75c20531c4"/><file name="OinkSoapClient.php" hash="a285e5afb4b54470a3ede09e17ac9a31"/><file name="XmlSerializationService.php" hash="b3df52384ddcb22c36dd777a4b0c6e37"/><file name="XmlToArray.php" hash="bec873ee5a71cc56b90e1901e9dad448"/></dir><dir name="Interfaces"><file name="ICallbackService.php" hash="36249ed2ebbab470140e546e57a45eeb"/><file name="ICartService.php" hash="757fe16fd63e3643e1c1f721503062d6"/><file name="IFormService.php" hash="54ff55760a104205ab2ebdf3e2eba710"/><file name="IFormServiceConfiguration.php" hash="ab08a9b7e0a453919397a1f3d33e4374"/><file name="ILoggingService.php" hash="540baa761603b9821ce56268bbe3b4a3"/><file name="IParentService.php" hash="15cc1ad75b20f8b59add2aecb6cc805b"/><file name="IPaymentService.php" hash="cf3748640cf606e5e2b2b8b6a5a094ff"/><file name="IPaymentServiceConfiguration.php" hash="6394875c724bddb0594591615c627956"/><file name="ISerializationService.php" hash="08917f2e64ff4425a5b1261d262a357b"/></dir></dir></dir><dir name="Spyc"><file name="spyc.php" hash="a83c6d2c9f8cba7f195bce001b6d3965"/></dir></target></contents>
16
+ <compatible/>
17
+ <dependencies><required><php><min>5.2.0</min><max>5.6.0</max></php></required></dependencies>
18
+ </package>