Completed
Push — master ( b4d1c4...5b98ac )
by Aimeos
05:50
created
client/html/src/Client/Html/Checkout/Standard/Delivery/Standard.php 1 patch
Indentation   +340 added lines, -340 removed lines patch added patch discarded remove patch
@@ -23,345 +23,345 @@
 block discarded – undo
23 23
  * @subpackage Html
24 24
  */
25 25
 class Standard
26
-	extends \Aimeos\Client\Html\Common\Client\Factory\Base
27
-	implements \Aimeos\Client\Html\Common\Client\Factory\Iface
26
+    extends \Aimeos\Client\Html\Common\Client\Factory\Base
27
+    implements \Aimeos\Client\Html\Common\Client\Factory\Iface
28 28
 {
29
-	/** client/html/checkout/standard/delivery/standard/subparts
30
-	 * List of HTML sub-clients rendered within the checkout standard delivery section
31
-	 *
32
-	 * The output of the frontend is composed of the code generated by the HTML
33
-	 * clients. Each HTML client can consist of serveral (or none) sub-clients
34
-	 * that are responsible for rendering certain sub-parts of the output. The
35
-	 * sub-clients can contain HTML clients themselves and therefore a
36
-	 * hierarchical tree of HTML clients is composed. Each HTML client creates
37
-	 * the output that is placed inside the container of its parent.
38
-	 *
39
-	 * At first, always the HTML code generated by the parent is printed, then
40
-	 * the HTML code of its sub-clients. The order of the HTML sub-clients
41
-	 * determines the order of the output of these sub-clients inside the parent
42
-	 * container. If the configured list of clients is
43
-	 *
44
-	 *  array( "subclient1", "subclient2" )
45
-	 *
46
-	 * you can easily change the order of the output by reordering the subparts:
47
-	 *
48
-	 *  client/html/<clients>/subparts = array( "subclient1", "subclient2" )
49
-	 *
50
-	 * You can also remove one or more parts if they shouldn't be rendered:
51
-	 *
52
-	 *  client/html/<clients>/subparts = array( "subclient1" )
53
-	 *
54
-	 * As the clients only generates structural HTML, the layout defined via CSS
55
-	 * should support adding, removing or reordering content by a fluid like
56
-	 * design.
57
-	 *
58
-	 * @param array List of sub-client names
59
-	 * @since 2014.03
60
-	 * @category Developer
61
-	 */
62
-	private $subPartPath = 'client/html/checkout/standard/delivery/standard/subparts';
63
-	private $subPartNames = array();
64
-	private $cache;
65
-
66
-
67
-	/**
68
-	 * Returns the HTML code for insertion into the body.
69
-	 *
70
-	 * @param string $uid Unique identifier for the output if the content is placed more than once on the same page
71
-	 * @param array &$tags Result array for the list of tags that are associated to the output
72
-	 * @param string|null &$expire Result variable for the expiration date of the output (null for no expiry)
73
-	 * @return string HTML code
74
-	 */
75
-	public function getBody( $uid = '', array &$tags = array(), &$expire = null )
76
-	{
77
-		$view = $this->getView();
78
-		$step = $view->get( 'standardStepActive' );
79
-		$onepage = $view->config( 'client/html/checkout/standard/onepage', array() );
80
-
81
-		if( $step != 'delivery' && !( in_array( 'delivery', $onepage ) && in_array( $step, $onepage ) ) ) {
82
-			return '';
83
-		}
84
-
85
-		$view = $this->setViewParams( $view, $tags, $expire );
86
-
87
-		$html = '';
88
-		foreach( $this->getSubClients() as $subclient ) {
89
-			$html .= $subclient->setView( $view )->getBody( $uid, $tags, $expire );
90
-		}
91
-		$view->deliveryBody = $html;
92
-
93
-		/** client/html/checkout/standard/delivery/standard/template-body
94
-		 * Relative path to the HTML body template of the checkout standard delivery client.
95
-		 *
96
-		 * The template file contains the HTML code and processing instructions
97
-		 * to generate the result shown in the body of the frontend. The
98
-		 * configuration string is the path to the template file relative
99
-		 * to the templates directory (usually in client/html/templates).
100
-		 *
101
-		 * You can overwrite the template file configuration in extensions and
102
-		 * provide alternative templates. These alternative templates should be
103
-		 * named like the default one but with the string "standard" replaced by
104
-		 * an unique name. You may use the name of your project for this. If
105
-		 * you've implemented an alternative client class as well, "standard"
106
-		 * should be replaced by the name of the new class.
107
-		 *
108
-		 * @param string Relative path to the template creating code for the HTML page body
109
-		 * @since 2014.03
110
-		 * @category Developer
111
-		 * @see client/html/checkout/standard/delivery/standard/template-header
112
-		 */
113
-		$tplconf = 'client/html/checkout/standard/delivery/standard/template-body';
114
-		$default = 'checkout/standard/delivery-body-default.php';
115
-
116
-		return $view->render( $view->config( $tplconf, $default ) );
117
-	}
118
-
119
-
120
-	/**
121
-	 * Returns the HTML string for insertion into the header.
122
-	 *
123
-	 * @param string $uid Unique identifier for the output if the content is placed more than once on the same page
124
-	 * @param array &$tags Result array for the list of tags that are associated to the output
125
-	 * @param string|null &$expire Result variable for the expiration date of the output (null for no expiry)
126
-	 * @return string|null String including HTML tags for the header on error
127
-	 */
128
-	public function getHeader( $uid = '', array &$tags = array(), &$expire = null )
129
-	{
130
-		$view = $this->getView();
131
-		$step = $view->get( 'standardStepActive' );
132
-		$onepage = $view->config( 'client/html/checkout/standard/onepage', array() );
133
-
134
-		if( $step != 'delivery' && !( in_array( 'delivery', $onepage ) && in_array( $step, $onepage ) ) ) {
135
-			return '';
136
-		}
137
-
138
-		$view = $this->setViewParams( $view, $tags, $expire );
139
-
140
-		$html = '';
141
-		foreach( $this->getSubClients() as $subclient ) {
142
-			$html .= $subclient->setView( $view )->getHeader( $uid, $tags, $expire );
143
-		}
144
-		$view->deliveryHeader = $html;
145
-
146
-		/** client/html/checkout/standard/delivery/standard/template-header
147
-		 * Relative path to the HTML header template of the checkout standard delivery client.
148
-		 *
149
-		 * The template file contains the HTML code and processing instructions
150
-		 * to generate the HTML code that is inserted into the HTML page header
151
-		 * of the rendered page in the frontend. The configuration string is the
152
-		 * path to the template file relative to the templates directory (usually
153
-		 * in client/html/templates).
154
-		 *
155
-		 * You can overwrite the template file configuration in extensions and
156
-		 * provide alternative templates. These alternative templates should be
157
-		 * named like the default one but with the string "standard" replaced by
158
-		 * an unique name. You may use the name of your project for this. If
159
-		 * you've implemented an alternative client class as well, "standard"
160
-		 * should be replaced by the name of the new class.
161
-		 *
162
-		 * @param string Relative path to the template creating code for the HTML page head
163
-		 * @since 2014.03
164
-		 * @category Developer
165
-		 * @see client/html/checkout/standard/delivery/standard/template-body
166
-		 */
167
-		$tplconf = 'client/html/checkout/standard/delivery/standard/template-header';
168
-		$default = 'checkout/standard/delivery-header-default.php';
169
-
170
-		return $view->render( $view->config( $tplconf, $default ) );
171
-	}
172
-
173
-
174
-	/**
175
-	 * Returns the sub-client given by its name.
176
-	 *
177
-	 * @param string $type Name of the client type
178
-	 * @param string|null $name Name of the sub-client (Default if null)
179
-	 * @return \Aimeos\Client\Html\Iface Sub-client object
180
-	 */
181
-	public function getSubClient( $type, $name = null )
182
-	{
183
-		/** client/html/checkout/standard/delivery/decorators/excludes
184
-		 * Excludes decorators added by the "common" option from the checkout standard delivery html client
185
-		 *
186
-		 * Decorators extend the functionality of a class by adding new aspects
187
-		 * (e.g. log what is currently done), executing the methods of the underlying
188
-		 * class only in certain conditions (e.g. only for logged in users) or
189
-		 * modify what is returned to the caller.
190
-		 *
191
-		 * This option allows you to remove a decorator added via
192
-		 * "client/html/common/decorators/default" before they are wrapped
193
-		 * around the html client.
194
-		 *
195
-		 *  client/html/checkout/standard/delivery/decorators/excludes = array( 'decorator1' )
196
-		 *
197
-		 * This would remove the decorator named "decorator1" from the list of
198
-		 * common decorators ("\Aimeos\Client\Html\Common\Decorator\*") added via
199
-		 * "client/html/common/decorators/default" to the html client.
200
-		 *
201
-		 * @param array List of decorator names
202
-		 * @since 2015.08
203
-		 * @category Developer
204
-		 * @see client/html/common/decorators/default
205
-		 * @see client/html/checkout/standard/delivery/decorators/global
206
-		 * @see client/html/checkout/standard/delivery/decorators/local
207
-		 */
208
-
209
-		/** client/html/checkout/standard/delivery/decorators/global
210
-		 * Adds a list of globally available decorators only to the checkout standard delivery html client
211
-		 *
212
-		 * Decorators extend the functionality of a class by adding new aspects
213
-		 * (e.g. log what is currently done), executing the methods of the underlying
214
-		 * class only in certain conditions (e.g. only for logged in users) or
215
-		 * modify what is returned to the caller.
216
-		 *
217
-		 * This option allows you to wrap global decorators
218
-		 * ("\Aimeos\Client\Html\Common\Decorator\*") around the html client.
219
-		 *
220
-		 *  client/html/checkout/standard/delivery/decorators/global = array( 'decorator1' )
221
-		 *
222
-		 * This would add the decorator named "decorator1" defined by
223
-		 * "\Aimeos\Client\Html\Common\Decorator\Decorator1" only to the html client.
224
-		 *
225
-		 * @param array List of decorator names
226
-		 * @since 2015.08
227
-		 * @category Developer
228
-		 * @see client/html/common/decorators/default
229
-		 * @see client/html/checkout/standard/delivery/decorators/excludes
230
-		 * @see client/html/checkout/standard/delivery/decorators/local
231
-		 */
232
-
233
-		/** client/html/checkout/standard/delivery/decorators/local
234
-		 * Adds a list of local decorators only to the checkout standard delivery html client
235
-		 *
236
-		 * Decorators extend the functionality of a class by adding new aspects
237
-		 * (e.g. log what is currently done), executing the methods of the underlying
238
-		 * class only in certain conditions (e.g. only for logged in users) or
239
-		 * modify what is returned to the caller.
240
-		 *
241
-		 * This option allows you to wrap local decorators
242
-		 * ("\Aimeos\Client\Html\Checkout\Decorator\*") around the html client.
243
-		 *
244
-		 *  client/html/checkout/standard/delivery/decorators/local = array( 'decorator2' )
245
-		 *
246
-		 * This would add the decorator named "decorator2" defined by
247
-		 * "\Aimeos\Client\Html\Checkout\Decorator\Decorator2" only to the html client.
248
-		 *
249
-		 * @param array List of decorator names
250
-		 * @since 2015.08
251
-		 * @category Developer
252
-		 * @see client/html/common/decorators/default
253
-		 * @see client/html/checkout/standard/delivery/decorators/excludes
254
-		 * @see client/html/checkout/standard/delivery/decorators/global
255
-		 */
256
-
257
-		return $this->createSubClient( 'checkout/standard/delivery/' . $type, $name );
258
-	}
259
-
260
-
261
-	/**
262
-	 * Processes the input, e.g. store given values.
263
-	 * A view must be available and this method doesn't generate any output
264
-	 * besides setting view variables.
265
-	 */
266
-	public function process()
267
-	{
268
-		$view = $this->getView();
269
-
270
-		try
271
-		{
272
-			$context = $this->getContext();
273
-			$basketCtrl = \Aimeos\Controller\Frontend\Factory::createController( $context, 'basket' );
274
-
275
-			// only start if there's something to do
276
-			if( ( $serviceId = $view->param( 'c_deliveryoption', null ) ) !== null )
277
-			{
278
-				$serviceCtrl = \Aimeos\Controller\Frontend\Factory::createController( $context, 'service' );
279
-
280
-				$attributes = $view->param( 'c_delivery/' . $serviceId, array() );
281
-				$errors = $serviceCtrl->checkServiceAttributes( 'delivery', $serviceId, $attributes );
282
-
283
-				foreach( $errors as $key => $msg )
284
-				{
285
-					if( $msg === null ) {
286
-						unset( $errors[$key] );
287
-					}
288
-				}
289
-
290
-				if( count( $errors ) === 0 ) {
291
-					$basketCtrl->setService( 'delivery', $serviceId, $attributes );
292
-				} else {
293
-					$view->standardStepActive = 'delivery';
294
-				}
295
-
296
-				$view->deliveryError = $errors;
297
-			}
298
-
299
-
300
-			parent::process();
301
-
302
-
303
-			// Test if delivery service is available
304
-			$services = $basketCtrl->get()->getServices();
305
-			if( !isset( $view->standardStepActive ) && !array_key_exists( 'delivery', $services ) )
306
-			{
307
-				$view->standardStepActive = 'delivery';
308
-				return false;
309
-			}
310
-		}
311
-		catch( \Exception $e )
312
-		{
313
-			$view->standardStepActive = 'delivery';
314
-			throw $e;
315
-		}
316
-	}
317
-
318
-
319
-	/**
320
-	 * Returns the list of sub-client names configured for the client.
321
-	 *
322
-	 * @return array List of HTML client names
323
-	 */
324
-	protected function getSubClientNames()
325
-	{
326
-		return $this->getContext()->getConfig()->get( $this->subPartPath, $this->subPartNames );
327
-	}
328
-
329
-
330
-	/**
331
-	 * Sets the necessary parameter values in the view.
332
-	 *
333
-	 * @param \Aimeos\MW\View\Iface $view The view object which generates the HTML output
334
-	 * @param array &$tags Result array for the list of tags that are associated to the output
335
-	 * @param string|null &$expire Result variable for the expiration date of the output (null for no expiry)
336
-	 * @return \Aimeos\MW\View\Iface Modified view object
337
-	 */
338
-	protected function setViewParams( \Aimeos\MW\View\Iface $view, array &$tags = array(), &$expire = null )
339
-	{
340
-		if( !isset( $this->cache ) )
341
-		{
342
-			$context = $this->getContext();
343
-
344
-			$basketCntl = \Aimeos\Controller\Frontend\Factory::createController( $context, 'basket' );
345
-			$serviceCntl = \Aimeos\Controller\Frontend\Factory::createController( $context, 'service' );
346
-
347
-			$basket = $basketCntl->get();
348
-
349
-			$services = $serviceCntl->getServices( 'delivery', $basket );
350
-			$serviceAttributes = $servicePrices = array();
351
-
352
-			foreach( $services as $id => $service )
353
-			{
354
-				$serviceAttributes[$id] = $serviceCntl->getServiceAttributes( 'delivery', $id, $basket );
355
-				$servicePrices[$id] = $serviceCntl->getServicePrice( 'delivery', $id, $basket );
356
-			}
357
-
358
-			$view->deliveryServices = $services;
359
-			$view->deliveryServiceAttributes = $serviceAttributes;
360
-			$view->deliveryServicePrices = $servicePrices;
361
-
362
-			$this->cache = $view;
363
-		}
364
-
365
-		return $this->cache;
366
-	}
29
+    /** client/html/checkout/standard/delivery/standard/subparts
30
+     * List of HTML sub-clients rendered within the checkout standard delivery section
31
+     *
32
+     * The output of the frontend is composed of the code generated by the HTML
33
+     * clients. Each HTML client can consist of serveral (or none) sub-clients
34
+     * that are responsible for rendering certain sub-parts of the output. The
35
+     * sub-clients can contain HTML clients themselves and therefore a
36
+     * hierarchical tree of HTML clients is composed. Each HTML client creates
37
+     * the output that is placed inside the container of its parent.
38
+     *
39
+     * At first, always the HTML code generated by the parent is printed, then
40
+     * the HTML code of its sub-clients. The order of the HTML sub-clients
41
+     * determines the order of the output of these sub-clients inside the parent
42
+     * container. If the configured list of clients is
43
+     *
44
+     *  array( "subclient1", "subclient2" )
45
+     *
46
+     * you can easily change the order of the output by reordering the subparts:
47
+     *
48
+     *  client/html/<clients>/subparts = array( "subclient1", "subclient2" )
49
+     *
50
+     * You can also remove one or more parts if they shouldn't be rendered:
51
+     *
52
+     *  client/html/<clients>/subparts = array( "subclient1" )
53
+     *
54
+     * As the clients only generates structural HTML, the layout defined via CSS
55
+     * should support adding, removing or reordering content by a fluid like
56
+     * design.
57
+     *
58
+     * @param array List of sub-client names
59
+     * @since 2014.03
60
+     * @category Developer
61
+     */
62
+    private $subPartPath = 'client/html/checkout/standard/delivery/standard/subparts';
63
+    private $subPartNames = array();
64
+    private $cache;
65
+
66
+
67
+    /**
68
+     * Returns the HTML code for insertion into the body.
69
+     *
70
+     * @param string $uid Unique identifier for the output if the content is placed more than once on the same page
71
+     * @param array &$tags Result array for the list of tags that are associated to the output
72
+     * @param string|null &$expire Result variable for the expiration date of the output (null for no expiry)
73
+     * @return string HTML code
74
+     */
75
+    public function getBody( $uid = '', array &$tags = array(), &$expire = null )
76
+    {
77
+        $view = $this->getView();
78
+        $step = $view->get( 'standardStepActive' );
79
+        $onepage = $view->config( 'client/html/checkout/standard/onepage', array() );
80
+
81
+        if( $step != 'delivery' && !( in_array( 'delivery', $onepage ) && in_array( $step, $onepage ) ) ) {
82
+            return '';
83
+        }
84
+
85
+        $view = $this->setViewParams( $view, $tags, $expire );
86
+
87
+        $html = '';
88
+        foreach( $this->getSubClients() as $subclient ) {
89
+            $html .= $subclient->setView( $view )->getBody( $uid, $tags, $expire );
90
+        }
91
+        $view->deliveryBody = $html;
92
+
93
+        /** client/html/checkout/standard/delivery/standard/template-body
94
+         * Relative path to the HTML body template of the checkout standard delivery client.
95
+         *
96
+         * The template file contains the HTML code and processing instructions
97
+         * to generate the result shown in the body of the frontend. The
98
+         * configuration string is the path to the template file relative
99
+         * to the templates directory (usually in client/html/templates).
100
+         *
101
+         * You can overwrite the template file configuration in extensions and
102
+         * provide alternative templates. These alternative templates should be
103
+         * named like the default one but with the string "standard" replaced by
104
+         * an unique name. You may use the name of your project for this. If
105
+         * you've implemented an alternative client class as well, "standard"
106
+         * should be replaced by the name of the new class.
107
+         *
108
+         * @param string Relative path to the template creating code for the HTML page body
109
+         * @since 2014.03
110
+         * @category Developer
111
+         * @see client/html/checkout/standard/delivery/standard/template-header
112
+         */
113
+        $tplconf = 'client/html/checkout/standard/delivery/standard/template-body';
114
+        $default = 'checkout/standard/delivery-body-default.php';
115
+
116
+        return $view->render( $view->config( $tplconf, $default ) );
117
+    }
118
+
119
+
120
+    /**
121
+     * Returns the HTML string for insertion into the header.
122
+     *
123
+     * @param string $uid Unique identifier for the output if the content is placed more than once on the same page
124
+     * @param array &$tags Result array for the list of tags that are associated to the output
125
+     * @param string|null &$expire Result variable for the expiration date of the output (null for no expiry)
126
+     * @return string|null String including HTML tags for the header on error
127
+     */
128
+    public function getHeader( $uid = '', array &$tags = array(), &$expire = null )
129
+    {
130
+        $view = $this->getView();
131
+        $step = $view->get( 'standardStepActive' );
132
+        $onepage = $view->config( 'client/html/checkout/standard/onepage', array() );
133
+
134
+        if( $step != 'delivery' && !( in_array( 'delivery', $onepage ) && in_array( $step, $onepage ) ) ) {
135
+            return '';
136
+        }
137
+
138
+        $view = $this->setViewParams( $view, $tags, $expire );
139
+
140
+        $html = '';
141
+        foreach( $this->getSubClients() as $subclient ) {
142
+            $html .= $subclient->setView( $view )->getHeader( $uid, $tags, $expire );
143
+        }
144
+        $view->deliveryHeader = $html;
145
+
146
+        /** client/html/checkout/standard/delivery/standard/template-header
147
+         * Relative path to the HTML header template of the checkout standard delivery client.
148
+         *
149
+         * The template file contains the HTML code and processing instructions
150
+         * to generate the HTML code that is inserted into the HTML page header
151
+         * of the rendered page in the frontend. The configuration string is the
152
+         * path to the template file relative to the templates directory (usually
153
+         * in client/html/templates).
154
+         *
155
+         * You can overwrite the template file configuration in extensions and
156
+         * provide alternative templates. These alternative templates should be
157
+         * named like the default one but with the string "standard" replaced by
158
+         * an unique name. You may use the name of your project for this. If
159
+         * you've implemented an alternative client class as well, "standard"
160
+         * should be replaced by the name of the new class.
161
+         *
162
+         * @param string Relative path to the template creating code for the HTML page head
163
+         * @since 2014.03
164
+         * @category Developer
165
+         * @see client/html/checkout/standard/delivery/standard/template-body
166
+         */
167
+        $tplconf = 'client/html/checkout/standard/delivery/standard/template-header';
168
+        $default = 'checkout/standard/delivery-header-default.php';
169
+
170
+        return $view->render( $view->config( $tplconf, $default ) );
171
+    }
172
+
173
+
174
+    /**
175
+     * Returns the sub-client given by its name.
176
+     *
177
+     * @param string $type Name of the client type
178
+     * @param string|null $name Name of the sub-client (Default if null)
179
+     * @return \Aimeos\Client\Html\Iface Sub-client object
180
+     */
181
+    public function getSubClient( $type, $name = null )
182
+    {
183
+        /** client/html/checkout/standard/delivery/decorators/excludes
184
+         * Excludes decorators added by the "common" option from the checkout standard delivery html client
185
+         *
186
+         * Decorators extend the functionality of a class by adding new aspects
187
+         * (e.g. log what is currently done), executing the methods of the underlying
188
+         * class only in certain conditions (e.g. only for logged in users) or
189
+         * modify what is returned to the caller.
190
+         *
191
+         * This option allows you to remove a decorator added via
192
+         * "client/html/common/decorators/default" before they are wrapped
193
+         * around the html client.
194
+         *
195
+         *  client/html/checkout/standard/delivery/decorators/excludes = array( 'decorator1' )
196
+         *
197
+         * This would remove the decorator named "decorator1" from the list of
198
+         * common decorators ("\Aimeos\Client\Html\Common\Decorator\*") added via
199
+         * "client/html/common/decorators/default" to the html client.
200
+         *
201
+         * @param array List of decorator names
202
+         * @since 2015.08
203
+         * @category Developer
204
+         * @see client/html/common/decorators/default
205
+         * @see client/html/checkout/standard/delivery/decorators/global
206
+         * @see client/html/checkout/standard/delivery/decorators/local
207
+         */
208
+
209
+        /** client/html/checkout/standard/delivery/decorators/global
210
+         * Adds a list of globally available decorators only to the checkout standard delivery html client
211
+         *
212
+         * Decorators extend the functionality of a class by adding new aspects
213
+         * (e.g. log what is currently done), executing the methods of the underlying
214
+         * class only in certain conditions (e.g. only for logged in users) or
215
+         * modify what is returned to the caller.
216
+         *
217
+         * This option allows you to wrap global decorators
218
+         * ("\Aimeos\Client\Html\Common\Decorator\*") around the html client.
219
+         *
220
+         *  client/html/checkout/standard/delivery/decorators/global = array( 'decorator1' )
221
+         *
222
+         * This would add the decorator named "decorator1" defined by
223
+         * "\Aimeos\Client\Html\Common\Decorator\Decorator1" only to the html client.
224
+         *
225
+         * @param array List of decorator names
226
+         * @since 2015.08
227
+         * @category Developer
228
+         * @see client/html/common/decorators/default
229
+         * @see client/html/checkout/standard/delivery/decorators/excludes
230
+         * @see client/html/checkout/standard/delivery/decorators/local
231
+         */
232
+
233
+        /** client/html/checkout/standard/delivery/decorators/local
234
+         * Adds a list of local decorators only to the checkout standard delivery html client
235
+         *
236
+         * Decorators extend the functionality of a class by adding new aspects
237
+         * (e.g. log what is currently done), executing the methods of the underlying
238
+         * class only in certain conditions (e.g. only for logged in users) or
239
+         * modify what is returned to the caller.
240
+         *
241
+         * This option allows you to wrap local decorators
242
+         * ("\Aimeos\Client\Html\Checkout\Decorator\*") around the html client.
243
+         *
244
+         *  client/html/checkout/standard/delivery/decorators/local = array( 'decorator2' )
245
+         *
246
+         * This would add the decorator named "decorator2" defined by
247
+         * "\Aimeos\Client\Html\Checkout\Decorator\Decorator2" only to the html client.
248
+         *
249
+         * @param array List of decorator names
250
+         * @since 2015.08
251
+         * @category Developer
252
+         * @see client/html/common/decorators/default
253
+         * @see client/html/checkout/standard/delivery/decorators/excludes
254
+         * @see client/html/checkout/standard/delivery/decorators/global
255
+         */
256
+
257
+        return $this->createSubClient( 'checkout/standard/delivery/' . $type, $name );
258
+    }
259
+
260
+
261
+    /**
262
+     * Processes the input, e.g. store given values.
263
+     * A view must be available and this method doesn't generate any output
264
+     * besides setting view variables.
265
+     */
266
+    public function process()
267
+    {
268
+        $view = $this->getView();
269
+
270
+        try
271
+        {
272
+            $context = $this->getContext();
273
+            $basketCtrl = \Aimeos\Controller\Frontend\Factory::createController( $context, 'basket' );
274
+
275
+            // only start if there's something to do
276
+            if( ( $serviceId = $view->param( 'c_deliveryoption', null ) ) !== null )
277
+            {
278
+                $serviceCtrl = \Aimeos\Controller\Frontend\Factory::createController( $context, 'service' );
279
+
280
+                $attributes = $view->param( 'c_delivery/' . $serviceId, array() );
281
+                $errors = $serviceCtrl->checkServiceAttributes( 'delivery', $serviceId, $attributes );
282
+
283
+                foreach( $errors as $key => $msg )
284
+                {
285
+                    if( $msg === null ) {
286
+                        unset( $errors[$key] );
287
+                    }
288
+                }
289
+
290
+                if( count( $errors ) === 0 ) {
291
+                    $basketCtrl->setService( 'delivery', $serviceId, $attributes );
292
+                } else {
293
+                    $view->standardStepActive = 'delivery';
294
+                }
295
+
296
+                $view->deliveryError = $errors;
297
+            }
298
+
299
+
300
+            parent::process();
301
+
302
+
303
+            // Test if delivery service is available
304
+            $services = $basketCtrl->get()->getServices();
305
+            if( !isset( $view->standardStepActive ) && !array_key_exists( 'delivery', $services ) )
306
+            {
307
+                $view->standardStepActive = 'delivery';
308
+                return false;
309
+            }
310
+        }
311
+        catch( \Exception $e )
312
+        {
313
+            $view->standardStepActive = 'delivery';
314
+            throw $e;
315
+        }
316
+    }
317
+
318
+
319
+    /**
320
+     * Returns the list of sub-client names configured for the client.
321
+     *
322
+     * @return array List of HTML client names
323
+     */
324
+    protected function getSubClientNames()
325
+    {
326
+        return $this->getContext()->getConfig()->get( $this->subPartPath, $this->subPartNames );
327
+    }
328
+
329
+
330
+    /**
331
+     * Sets the necessary parameter values in the view.
332
+     *
333
+     * @param \Aimeos\MW\View\Iface $view The view object which generates the HTML output
334
+     * @param array &$tags Result array for the list of tags that are associated to the output
335
+     * @param string|null &$expire Result variable for the expiration date of the output (null for no expiry)
336
+     * @return \Aimeos\MW\View\Iface Modified view object
337
+     */
338
+    protected function setViewParams( \Aimeos\MW\View\Iface $view, array &$tags = array(), &$expire = null )
339
+    {
340
+        if( !isset( $this->cache ) )
341
+        {
342
+            $context = $this->getContext();
343
+
344
+            $basketCntl = \Aimeos\Controller\Frontend\Factory::createController( $context, 'basket' );
345
+            $serviceCntl = \Aimeos\Controller\Frontend\Factory::createController( $context, 'service' );
346
+
347
+            $basket = $basketCntl->get();
348
+
349
+            $services = $serviceCntl->getServices( 'delivery', $basket );
350
+            $serviceAttributes = $servicePrices = array();
351
+
352
+            foreach( $services as $id => $service )
353
+            {
354
+                $serviceAttributes[$id] = $serviceCntl->getServiceAttributes( 'delivery', $id, $basket );
355
+                $servicePrices[$id] = $serviceCntl->getServicePrice( 'delivery', $id, $basket );
356
+            }
357
+
358
+            $view->deliveryServices = $services;
359
+            $view->deliveryServiceAttributes = $serviceAttributes;
360
+            $view->deliveryServicePrices = $servicePrices;
361
+
362
+            $this->cache = $view;
363
+        }
364
+
365
+        return $this->cache;
366
+    }
367 367
 }
368 368
\ No newline at end of file
Please login to merge, or discard this patch.
client/html/src/Client/Html/Checkout/Standard/Payment/Standard.php 1 patch
Indentation   +340 added lines, -340 removed lines patch added patch discarded remove patch
@@ -23,345 +23,345 @@
 block discarded – undo
23 23
  * @subpackage Html
24 24
  */
25 25
 class Standard
26
-	extends \Aimeos\Client\Html\Common\Client\Factory\Base
27
-	implements \Aimeos\Client\Html\Common\Client\Factory\Iface
26
+    extends \Aimeos\Client\Html\Common\Client\Factory\Base
27
+    implements \Aimeos\Client\Html\Common\Client\Factory\Iface
28 28
 {
29
-	/** client/html/checkout/standard/payment/standard/subparts
30
-	 * List of HTML sub-clients rendered within the checkout standard payment section
31
-	 *
32
-	 * The output of the frontend is composed of the code generated by the HTML
33
-	 * clients. Each HTML client can consist of serveral (or none) sub-clients
34
-	 * that are responsible for rendering certain sub-parts of the output. The
35
-	 * sub-clients can contain HTML clients themselves and therefore a
36
-	 * hierarchical tree of HTML clients is composed. Each HTML client creates
37
-	 * the output that is placed inside the container of its parent.
38
-	 *
39
-	 * At first, always the HTML code generated by the parent is printed, then
40
-	 * the HTML code of its sub-clients. The order of the HTML sub-clients
41
-	 * determines the order of the output of these sub-clients inside the parent
42
-	 * container. If the configured list of clients is
43
-	 *
44
-	 *  array( "subclient1", "subclient2" )
45
-	 *
46
-	 * you can easily change the order of the output by reordering the subparts:
47
-	 *
48
-	 *  client/html/<clients>/subparts = array( "subclient1", "subclient2" )
49
-	 *
50
-	 * You can also remove one or more parts if they shouldn't be rendered:
51
-	 *
52
-	 *  client/html/<clients>/subparts = array( "subclient1" )
53
-	 *
54
-	 * As the clients only generates structural HTML, the layout defined via CSS
55
-	 * should support adding, removing or reordering content by a fluid like
56
-	 * design.
57
-	 *
58
-	 * @param array List of sub-client names
59
-	 * @since 2014.03
60
-	 * @category Developer
61
-	 */
62
-	private $subPartPath = 'client/html/checkout/standard/payment/standard/subparts';
63
-	private $subPartNames = array();
64
-	private $cache;
65
-
66
-
67
-	/**
68
-	 * Returns the HTML code for insertion into the body.
69
-	 *
70
-	 * @param string $uid Unique identifier for the output if the content is placed more than once on the same page
71
-	 * @param array &$tags Result array for the list of tags that are associated to the output
72
-	 * @param string|null &$expire Result variable for the expiration date of the output (null for no expiry)
73
-	 * @return string HTML code
74
-	 */
75
-	public function getBody( $uid = '', array &$tags = array(), &$expire = null )
76
-	{
77
-		$view = $this->getView();
78
-		$step = $view->get( 'standardStepActive' );
79
-		$onepage = $view->config( 'client/html/checkout/standard/onepage', array() );
80
-
81
-		if( $step != 'payment' && !( in_array( 'payment', $onepage ) && in_array( $step, $onepage ) ) ) {
82
-			return '';
83
-		}
84
-
85
-		$view = $this->setViewParams( $view, $tags, $expire );
86
-
87
-		$html = '';
88
-		foreach( $this->getSubClients() as $subclient ) {
89
-			$html .= $subclient->setView( $view )->getBody( $uid, $tags, $expire );
90
-		}
91
-		$view->paymentBody = $html;
92
-
93
-		/** client/html/checkout/standard/payment/standard/template-body
94
-		 * Relative path to the HTML body template of the checkout standard payment client.
95
-		 *
96
-		 * The template file contains the HTML code and processing instructions
97
-		 * to generate the result shown in the body of the frontend. The
98
-		 * configuration string is the path to the template file relative
99
-		 * to the templates directory (usually in client/html/templates).
100
-		 *
101
-		 * You can overwrite the template file configuration in extensions and
102
-		 * provide alternative templates. These alternative templates should be
103
-		 * named like the default one but with the string "standard" replaced by
104
-		 * an unique name. You may use the name of your project for this. If
105
-		 * you've implemented an alternative client class as well, "standard"
106
-		 * should be replaced by the name of the new class.
107
-		 *
108
-		 * @param string Relative path to the template creating code for the HTML page body
109
-		 * @since 2014.03
110
-		 * @category Developer
111
-		 * @see client/html/checkout/standard/payment/standard/template-header
112
-		 */
113
-		$tplconf = 'client/html/checkout/standard/payment/standard/template-body';
114
-		$default = 'checkout/standard/payment-body-default.php';
115
-
116
-		return $view->render( $view->config( $tplconf, $default ) );
117
-	}
118
-
119
-
120
-	/**
121
-	 * Returns the HTML string for insertion into the header.
122
-	 *
123
-	 * @param string $uid Unique identifier for the output if the content is placed more than once on the same page
124
-	 * @param array &$tags Result array for the list of tags that are associated to the output
125
-	 * @param string|null &$expire Result variable for the expiration date of the output (null for no expiry)
126
-	 * @return string|null String including HTML tags for the header on error
127
-	 */
128
-	public function getHeader( $uid = '', array &$tags = array(), &$expire = null )
129
-	{
130
-		$view = $this->getView();
131
-		$step = $view->get( 'standardStepActive' );
132
-		$onepage = $view->config( 'client/html/checkout/standard/onepage', array() );
133
-
134
-		if( $step != 'payment' && !( in_array( 'payment', $onepage ) && in_array( $step, $onepage ) ) ) {
135
-			return '';
136
-		}
137
-
138
-		$view = $this->setViewParams( $view, $tags, $expire );
139
-
140
-		$html = '';
141
-		foreach( $this->getSubClients() as $subclient ) {
142
-			$html .= $subclient->setView( $view )->getHeader( $uid, $tags, $expire );
143
-		}
144
-		$view->paymentHeader = $html;
145
-
146
-		/** client/html/checkout/standard/payment/standard/template-header
147
-		 * Relative path to the HTML header template of the checkout standard payment client.
148
-		 *
149
-		 * The template file contains the HTML code and processing instructions
150
-		 * to generate the HTML code that is inserted into the HTML page header
151
-		 * of the rendered page in the frontend. The configuration string is the
152
-		 * path to the template file relative to the templates directory (usually
153
-		 * in client/html/templates).
154
-		 *
155
-		 * You can overwrite the template file configuration in extensions and
156
-		 * provide alternative templates. These alternative templates should be
157
-		 * named like the default one but with the string "standard" replaced by
158
-		 * an unique name. You may use the name of your project for this. If
159
-		 * you've implemented an alternative client class as well, "standard"
160
-		 * should be replaced by the name of the new class.
161
-		 *
162
-		 * @param string Relative path to the template creating code for the HTML page head
163
-		 * @since 2014.03
164
-		 * @category Developer
165
-		 * @see client/html/checkout/standard/payment/standard/template-body
166
-		 */
167
-		$tplconf = 'client/html/checkout/standard/payment/standard/template-header';
168
-		$default = 'checkout/standard/payment-header-default.php';
169
-
170
-		return $view->render( $view->config( $tplconf, $default ) );
171
-	}
172
-
173
-
174
-	/**
175
-	 * Returns the sub-client given by its name.
176
-	 *
177
-	 * @param string $type Name of the client type
178
-	 * @param string|null $name Name of the sub-client (Default if null)
179
-	 * @return \Aimeos\Client\Html\Iface Sub-client object
180
-	 */
181
-	public function getSubClient( $type, $name = null )
182
-	{
183
-		/** client/html/checkout/standard/payment/decorators/excludes
184
-		 * Excludes decorators added by the "common" option from the checkout standard payment html client
185
-		 *
186
-		 * Decorators extend the functionality of a class by adding new aspects
187
-		 * (e.g. log what is currently done), executing the methods of the underlying
188
-		 * class only in certain conditions (e.g. only for logged in users) or
189
-		 * modify what is returned to the caller.
190
-		 *
191
-		 * This option allows you to remove a decorator added via
192
-		 * "client/html/common/decorators/default" before they are wrapped
193
-		 * around the html client.
194
-		 *
195
-		 *  client/html/checkout/standard/payment/decorators/excludes = array( 'decorator1' )
196
-		 *
197
-		 * This would remove the decorator named "decorator1" from the list of
198
-		 * common decorators ("\Aimeos\Client\Html\Common\Decorator\*") added via
199
-		 * "client/html/common/decorators/default" to the html client.
200
-		 *
201
-		 * @param array List of decorator names
202
-		 * @since 2015.08
203
-		 * @category Developer
204
-		 * @see client/html/common/decorators/default
205
-		 * @see client/html/checkout/standard/payment/decorators/global
206
-		 * @see client/html/checkout/standard/payment/decorators/local
207
-		 */
208
-
209
-		/** client/html/checkout/standard/payment/decorators/global
210
-		 * Adds a list of globally available decorators only to the checkout standard payment html client
211
-		 *
212
-		 * Decorators extend the functionality of a class by adding new aspects
213
-		 * (e.g. log what is currently done), executing the methods of the underlying
214
-		 * class only in certain conditions (e.g. only for logged in users) or
215
-		 * modify what is returned to the caller.
216
-		 *
217
-		 * This option allows you to wrap global decorators
218
-		 * ("\Aimeos\Client\Html\Common\Decorator\*") around the html client.
219
-		 *
220
-		 *  client/html/checkout/standard/payment/decorators/global = array( 'decorator1' )
221
-		 *
222
-		 * This would add the decorator named "decorator1" defined by
223
-		 * "\Aimeos\Client\Html\Common\Decorator\Decorator1" only to the html client.
224
-		 *
225
-		 * @param array List of decorator names
226
-		 * @since 2015.08
227
-		 * @category Developer
228
-		 * @see client/html/common/decorators/default
229
-		 * @see client/html/checkout/standard/payment/decorators/excludes
230
-		 * @see client/html/checkout/standard/payment/decorators/local
231
-		 */
232
-
233
-		/** client/html/checkout/standard/payment/decorators/local
234
-		 * Adds a list of local decorators only to the checkout standard payment html client
235
-		 *
236
-		 * Decorators extend the functionality of a class by adding new aspects
237
-		 * (e.g. log what is currently done), executing the methods of the underlying
238
-		 * class only in certain conditions (e.g. only for logged in users) or
239
-		 * modify what is returned to the caller.
240
-		 *
241
-		 * This option allows you to wrap local decorators
242
-		 * ("\Aimeos\Client\Html\Checkout\Decorator\*") around the html client.
243
-		 *
244
-		 *  client/html/checkout/standard/payment/decorators/local = array( 'decorator2' )
245
-		 *
246
-		 * This would add the decorator named "decorator2" defined by
247
-		 * "\Aimeos\Client\Html\Checkout\Decorator\Decorator2" only to the html client.
248
-		 *
249
-		 * @param array List of decorator names
250
-		 * @since 2015.08
251
-		 * @category Developer
252
-		 * @see client/html/common/decorators/default
253
-		 * @see client/html/checkout/standard/payment/decorators/excludes
254
-		 * @see client/html/checkout/standard/payment/decorators/global
255
-		 */
256
-
257
-		return $this->createSubClient( 'checkout/standard/payment/' . $type, $name );
258
-	}
259
-
260
-
261
-	/**
262
-	 * Processes the input, e.g. store given values.
263
-	 * A view must be available and this method doesn't generate any output
264
-	 * besides setting view variables.
265
-	 */
266
-	public function process()
267
-	{
268
-		$view = $this->getView();
269
-
270
-		try
271
-		{
272
-			$context = $this->getContext();
273
-			$basketCtrl = \Aimeos\Controller\Frontend\Factory::createController( $context, 'basket' );
274
-
275
-			// only start if there's something to do
276
-			if( ( $serviceId = $view->param( 'c_paymentoption', null ) ) !== null )
277
-			{
278
-				$serviceCtrl = \Aimeos\Controller\Frontend\Factory::createController( $context, 'service' );
279
-
280
-				$attributes = $view->param( 'c_payment/' . $serviceId, array() );
281
-				$errors = $serviceCtrl->checkServiceAttributes( 'payment', $serviceId, $attributes );
282
-
283
-				foreach( $errors as $key => $msg )
284
-				{
285
-					if( $msg === null ) {
286
-						unset( $errors[$key] );
287
-					}
288
-				}
289
-
290
-				if( count( $errors ) === 0 ) {
291
-					$basketCtrl->setService( 'payment', $serviceId, $attributes );
292
-				} else {
293
-					$view->standardStepActive = 'payment';
294
-				}
295
-
296
-				$view->paymentError = $errors;
297
-			}
298
-
299
-
300
-			parent::process();
301
-
302
-
303
-			// Test if payment service is available
304
-			$services = $basketCtrl->get()->getServices();
305
-			if( !isset( $view->standardStepActive ) && !array_key_exists( 'payment', $services ) )
306
-			{
307
-				$view->standardStepActive = 'payment';
308
-				return false;
309
-			}
310
-		}
311
-		catch( \Exception $e )
312
-		{
313
-			$view->standardStepActive = 'payment';
314
-			throw $e;
315
-		}
316
-	}
317
-
318
-
319
-	/**
320
-	 * Returns the list of sub-client names configured for the client.
321
-	 *
322
-	 * @return array List of HTML client names
323
-	 */
324
-	protected function getSubClientNames()
325
-	{
326
-		return $this->getContext()->getConfig()->get( $this->subPartPath, $this->subPartNames );
327
-	}
328
-
329
-
330
-	/**
331
-	 * Sets the necessary parameter values in the view.
332
-	 *
333
-	 * @param \Aimeos\MW\View\Iface $view The view object which generates the HTML output
334
-	 * @param array &$tags Result array for the list of tags that are associated to the output
335
-	 * @param string|null &$expire Result variable for the expiration date of the output (null for no expiry)
336
-	 * @return \Aimeos\MW\View\Iface Modified view object
337
-	 */
338
-	protected function setViewParams( \Aimeos\MW\View\Iface $view, array &$tags = array(), &$expire = null )
339
-	{
340
-		if( !isset( $this->cache ) )
341
-		{
342
-			$context = $this->getContext();
343
-
344
-			$basketCntl = \Aimeos\Controller\Frontend\Factory::createController( $context, 'basket' );
345
-			$serviceCntl = \Aimeos\Controller\Frontend\Factory::createController( $context, 'service' );
346
-
347
-			$basket = $basketCntl->get();
348
-
349
-			$services = $serviceCntl->getServices( 'payment', $basket );
350
-			$serviceAttributes = $servicePrices = array();
351
-
352
-			foreach( $services as $id => $service )
353
-			{
354
-				$serviceAttributes[$id] = $serviceCntl->getServiceAttributes( 'payment', $id, $basket );
355
-				$servicePrices[$id] = $serviceCntl->getServicePrice( 'payment', $id, $basket );
356
-			}
357
-
358
-			$view->paymentServices = $services;
359
-			$view->paymentServiceAttributes = $serviceAttributes;
360
-			$view->paymentServicePrices = $servicePrices;
361
-
362
-			$this->cache = $view;
363
-		}
364
-
365
-		return $this->cache;
366
-	}
29
+    /** client/html/checkout/standard/payment/standard/subparts
30
+     * List of HTML sub-clients rendered within the checkout standard payment section
31
+     *
32
+     * The output of the frontend is composed of the code generated by the HTML
33
+     * clients. Each HTML client can consist of serveral (or none) sub-clients
34
+     * that are responsible for rendering certain sub-parts of the output. The
35
+     * sub-clients can contain HTML clients themselves and therefore a
36
+     * hierarchical tree of HTML clients is composed. Each HTML client creates
37
+     * the output that is placed inside the container of its parent.
38
+     *
39
+     * At first, always the HTML code generated by the parent is printed, then
40
+     * the HTML code of its sub-clients. The order of the HTML sub-clients
41
+     * determines the order of the output of these sub-clients inside the parent
42
+     * container. If the configured list of clients is
43
+     *
44
+     *  array( "subclient1", "subclient2" )
45
+     *
46
+     * you can easily change the order of the output by reordering the subparts:
47
+     *
48
+     *  client/html/<clients>/subparts = array( "subclient1", "subclient2" )
49
+     *
50
+     * You can also remove one or more parts if they shouldn't be rendered:
51
+     *
52
+     *  client/html/<clients>/subparts = array( "subclient1" )
53
+     *
54
+     * As the clients only generates structural HTML, the layout defined via CSS
55
+     * should support adding, removing or reordering content by a fluid like
56
+     * design.
57
+     *
58
+     * @param array List of sub-client names
59
+     * @since 2014.03
60
+     * @category Developer
61
+     */
62
+    private $subPartPath = 'client/html/checkout/standard/payment/standard/subparts';
63
+    private $subPartNames = array();
64
+    private $cache;
65
+
66
+
67
+    /**
68
+     * Returns the HTML code for insertion into the body.
69
+     *
70
+     * @param string $uid Unique identifier for the output if the content is placed more than once on the same page
71
+     * @param array &$tags Result array for the list of tags that are associated to the output
72
+     * @param string|null &$expire Result variable for the expiration date of the output (null for no expiry)
73
+     * @return string HTML code
74
+     */
75
+    public function getBody( $uid = '', array &$tags = array(), &$expire = null )
76
+    {
77
+        $view = $this->getView();
78
+        $step = $view->get( 'standardStepActive' );
79
+        $onepage = $view->config( 'client/html/checkout/standard/onepage', array() );
80
+
81
+        if( $step != 'payment' && !( in_array( 'payment', $onepage ) && in_array( $step, $onepage ) ) ) {
82
+            return '';
83
+        }
84
+
85
+        $view = $this->setViewParams( $view, $tags, $expire );
86
+
87
+        $html = '';
88
+        foreach( $this->getSubClients() as $subclient ) {
89
+            $html .= $subclient->setView( $view )->getBody( $uid, $tags, $expire );
90
+        }
91
+        $view->paymentBody = $html;
92
+
93
+        /** client/html/checkout/standard/payment/standard/template-body
94
+         * Relative path to the HTML body template of the checkout standard payment client.
95
+         *
96
+         * The template file contains the HTML code and processing instructions
97
+         * to generate the result shown in the body of the frontend. The
98
+         * configuration string is the path to the template file relative
99
+         * to the templates directory (usually in client/html/templates).
100
+         *
101
+         * You can overwrite the template file configuration in extensions and
102
+         * provide alternative templates. These alternative templates should be
103
+         * named like the default one but with the string "standard" replaced by
104
+         * an unique name. You may use the name of your project for this. If
105
+         * you've implemented an alternative client class as well, "standard"
106
+         * should be replaced by the name of the new class.
107
+         *
108
+         * @param string Relative path to the template creating code for the HTML page body
109
+         * @since 2014.03
110
+         * @category Developer
111
+         * @see client/html/checkout/standard/payment/standard/template-header
112
+         */
113
+        $tplconf = 'client/html/checkout/standard/payment/standard/template-body';
114
+        $default = 'checkout/standard/payment-body-default.php';
115
+
116
+        return $view->render( $view->config( $tplconf, $default ) );
117
+    }
118
+
119
+
120
+    /**
121
+     * Returns the HTML string for insertion into the header.
122
+     *
123
+     * @param string $uid Unique identifier for the output if the content is placed more than once on the same page
124
+     * @param array &$tags Result array for the list of tags that are associated to the output
125
+     * @param string|null &$expire Result variable for the expiration date of the output (null for no expiry)
126
+     * @return string|null String including HTML tags for the header on error
127
+     */
128
+    public function getHeader( $uid = '', array &$tags = array(), &$expire = null )
129
+    {
130
+        $view = $this->getView();
131
+        $step = $view->get( 'standardStepActive' );
132
+        $onepage = $view->config( 'client/html/checkout/standard/onepage', array() );
133
+
134
+        if( $step != 'payment' && !( in_array( 'payment', $onepage ) && in_array( $step, $onepage ) ) ) {
135
+            return '';
136
+        }
137
+
138
+        $view = $this->setViewParams( $view, $tags, $expire );
139
+
140
+        $html = '';
141
+        foreach( $this->getSubClients() as $subclient ) {
142
+            $html .= $subclient->setView( $view )->getHeader( $uid, $tags, $expire );
143
+        }
144
+        $view->paymentHeader = $html;
145
+
146
+        /** client/html/checkout/standard/payment/standard/template-header
147
+         * Relative path to the HTML header template of the checkout standard payment client.
148
+         *
149
+         * The template file contains the HTML code and processing instructions
150
+         * to generate the HTML code that is inserted into the HTML page header
151
+         * of the rendered page in the frontend. The configuration string is the
152
+         * path to the template file relative to the templates directory (usually
153
+         * in client/html/templates).
154
+         *
155
+         * You can overwrite the template file configuration in extensions and
156
+         * provide alternative templates. These alternative templates should be
157
+         * named like the default one but with the string "standard" replaced by
158
+         * an unique name. You may use the name of your project for this. If
159
+         * you've implemented an alternative client class as well, "standard"
160
+         * should be replaced by the name of the new class.
161
+         *
162
+         * @param string Relative path to the template creating code for the HTML page head
163
+         * @since 2014.03
164
+         * @category Developer
165
+         * @see client/html/checkout/standard/payment/standard/template-body
166
+         */
167
+        $tplconf = 'client/html/checkout/standard/payment/standard/template-header';
168
+        $default = 'checkout/standard/payment-header-default.php';
169
+
170
+        return $view->render( $view->config( $tplconf, $default ) );
171
+    }
172
+
173
+
174
+    /**
175
+     * Returns the sub-client given by its name.
176
+     *
177
+     * @param string $type Name of the client type
178
+     * @param string|null $name Name of the sub-client (Default if null)
179
+     * @return \Aimeos\Client\Html\Iface Sub-client object
180
+     */
181
+    public function getSubClient( $type, $name = null )
182
+    {
183
+        /** client/html/checkout/standard/payment/decorators/excludes
184
+         * Excludes decorators added by the "common" option from the checkout standard payment html client
185
+         *
186
+         * Decorators extend the functionality of a class by adding new aspects
187
+         * (e.g. log what is currently done), executing the methods of the underlying
188
+         * class only in certain conditions (e.g. only for logged in users) or
189
+         * modify what is returned to the caller.
190
+         *
191
+         * This option allows you to remove a decorator added via
192
+         * "client/html/common/decorators/default" before they are wrapped
193
+         * around the html client.
194
+         *
195
+         *  client/html/checkout/standard/payment/decorators/excludes = array( 'decorator1' )
196
+         *
197
+         * This would remove the decorator named "decorator1" from the list of
198
+         * common decorators ("\Aimeos\Client\Html\Common\Decorator\*") added via
199
+         * "client/html/common/decorators/default" to the html client.
200
+         *
201
+         * @param array List of decorator names
202
+         * @since 2015.08
203
+         * @category Developer
204
+         * @see client/html/common/decorators/default
205
+         * @see client/html/checkout/standard/payment/decorators/global
206
+         * @see client/html/checkout/standard/payment/decorators/local
207
+         */
208
+
209
+        /** client/html/checkout/standard/payment/decorators/global
210
+         * Adds a list of globally available decorators only to the checkout standard payment html client
211
+         *
212
+         * Decorators extend the functionality of a class by adding new aspects
213
+         * (e.g. log what is currently done), executing the methods of the underlying
214
+         * class only in certain conditions (e.g. only for logged in users) or
215
+         * modify what is returned to the caller.
216
+         *
217
+         * This option allows you to wrap global decorators
218
+         * ("\Aimeos\Client\Html\Common\Decorator\*") around the html client.
219
+         *
220
+         *  client/html/checkout/standard/payment/decorators/global = array( 'decorator1' )
221
+         *
222
+         * This would add the decorator named "decorator1" defined by
223
+         * "\Aimeos\Client\Html\Common\Decorator\Decorator1" only to the html client.
224
+         *
225
+         * @param array List of decorator names
226
+         * @since 2015.08
227
+         * @category Developer
228
+         * @see client/html/common/decorators/default
229
+         * @see client/html/checkout/standard/payment/decorators/excludes
230
+         * @see client/html/checkout/standard/payment/decorators/local
231
+         */
232
+
233
+        /** client/html/checkout/standard/payment/decorators/local
234
+         * Adds a list of local decorators only to the checkout standard payment html client
235
+         *
236
+         * Decorators extend the functionality of a class by adding new aspects
237
+         * (e.g. log what is currently done), executing the methods of the underlying
238
+         * class only in certain conditions (e.g. only for logged in users) or
239
+         * modify what is returned to the caller.
240
+         *
241
+         * This option allows you to wrap local decorators
242
+         * ("\Aimeos\Client\Html\Checkout\Decorator\*") around the html client.
243
+         *
244
+         *  client/html/checkout/standard/payment/decorators/local = array( 'decorator2' )
245
+         *
246
+         * This would add the decorator named "decorator2" defined by
247
+         * "\Aimeos\Client\Html\Checkout\Decorator\Decorator2" only to the html client.
248
+         *
249
+         * @param array List of decorator names
250
+         * @since 2015.08
251
+         * @category Developer
252
+         * @see client/html/common/decorators/default
253
+         * @see client/html/checkout/standard/payment/decorators/excludes
254
+         * @see client/html/checkout/standard/payment/decorators/global
255
+         */
256
+
257
+        return $this->createSubClient( 'checkout/standard/payment/' . $type, $name );
258
+    }
259
+
260
+
261
+    /**
262
+     * Processes the input, e.g. store given values.
263
+     * A view must be available and this method doesn't generate any output
264
+     * besides setting view variables.
265
+     */
266
+    public function process()
267
+    {
268
+        $view = $this->getView();
269
+
270
+        try
271
+        {
272
+            $context = $this->getContext();
273
+            $basketCtrl = \Aimeos\Controller\Frontend\Factory::createController( $context, 'basket' );
274
+
275
+            // only start if there's something to do
276
+            if( ( $serviceId = $view->param( 'c_paymentoption', null ) ) !== null )
277
+            {
278
+                $serviceCtrl = \Aimeos\Controller\Frontend\Factory::createController( $context, 'service' );
279
+
280
+                $attributes = $view->param( 'c_payment/' . $serviceId, array() );
281
+                $errors = $serviceCtrl->checkServiceAttributes( 'payment', $serviceId, $attributes );
282
+
283
+                foreach( $errors as $key => $msg )
284
+                {
285
+                    if( $msg === null ) {
286
+                        unset( $errors[$key] );
287
+                    }
288
+                }
289
+
290
+                if( count( $errors ) === 0 ) {
291
+                    $basketCtrl->setService( 'payment', $serviceId, $attributes );
292
+                } else {
293
+                    $view->standardStepActive = 'payment';
294
+                }
295
+
296
+                $view->paymentError = $errors;
297
+            }
298
+
299
+
300
+            parent::process();
301
+
302
+
303
+            // Test if payment service is available
304
+            $services = $basketCtrl->get()->getServices();
305
+            if( !isset( $view->standardStepActive ) && !array_key_exists( 'payment', $services ) )
306
+            {
307
+                $view->standardStepActive = 'payment';
308
+                return false;
309
+            }
310
+        }
311
+        catch( \Exception $e )
312
+        {
313
+            $view->standardStepActive = 'payment';
314
+            throw $e;
315
+        }
316
+    }
317
+
318
+
319
+    /**
320
+     * Returns the list of sub-client names configured for the client.
321
+     *
322
+     * @return array List of HTML client names
323
+     */
324
+    protected function getSubClientNames()
325
+    {
326
+        return $this->getContext()->getConfig()->get( $this->subPartPath, $this->subPartNames );
327
+    }
328
+
329
+
330
+    /**
331
+     * Sets the necessary parameter values in the view.
332
+     *
333
+     * @param \Aimeos\MW\View\Iface $view The view object which generates the HTML output
334
+     * @param array &$tags Result array for the list of tags that are associated to the output
335
+     * @param string|null &$expire Result variable for the expiration date of the output (null for no expiry)
336
+     * @return \Aimeos\MW\View\Iface Modified view object
337
+     */
338
+    protected function setViewParams( \Aimeos\MW\View\Iface $view, array &$tags = array(), &$expire = null )
339
+    {
340
+        if( !isset( $this->cache ) )
341
+        {
342
+            $context = $this->getContext();
343
+
344
+            $basketCntl = \Aimeos\Controller\Frontend\Factory::createController( $context, 'basket' );
345
+            $serviceCntl = \Aimeos\Controller\Frontend\Factory::createController( $context, 'service' );
346
+
347
+            $basket = $basketCntl->get();
348
+
349
+            $services = $serviceCntl->getServices( 'payment', $basket );
350
+            $serviceAttributes = $servicePrices = array();
351
+
352
+            foreach( $services as $id => $service )
353
+            {
354
+                $serviceAttributes[$id] = $serviceCntl->getServiceAttributes( 'payment', $id, $basket );
355
+                $servicePrices[$id] = $serviceCntl->getServicePrice( 'payment', $id, $basket );
356
+            }
357
+
358
+            $view->paymentServices = $services;
359
+            $view->paymentServiceAttributes = $serviceAttributes;
360
+            $view->paymentServicePrices = $servicePrices;
361
+
362
+            $this->cache = $view;
363
+        }
364
+
365
+        return $this->cache;
366
+    }
367 367
 }
368 368
\ No newline at end of file
Please login to merge, or discard this patch.
client/html/src/Client/Html/Checkout/Standard/Address/Billing/Standard.php 1 patch
Indentation   +760 added lines, -760 removed lines patch added patch discarded remove patch
@@ -19,765 +19,765 @@
 block discarded – undo
19 19
  * @subpackage Html
20 20
  */
21 21
 class Standard
22
-	extends \Aimeos\Client\Html\Common\Client\Factory\Base
23
-	implements \Aimeos\Client\Html\Common\Client\Factory\Iface
22
+    extends \Aimeos\Client\Html\Common\Client\Factory\Base
23
+    implements \Aimeos\Client\Html\Common\Client\Factory\Iface
24 24
 {
25
-	/** client/html/checkout/standard/address/billing/standard/subparts
26
-	 * List of HTML sub-clients rendered within the checkout standard address billing section
27
-	 *
28
-	 * The output of the frontend is composed of the code generated by the HTML
29
-	 * clients. Each HTML client can consist of serveral (or none) sub-clients
30
-	 * that are responsible for rendering certain sub-parts of the output. The
31
-	 * sub-clients can contain HTML clients themselves and therefore a
32
-	 * hierarchical tree of HTML clients is composed. Each HTML client creates
33
-	 * the output that is placed inside the container of its parent.
34
-	 *
35
-	 * At first, always the HTML code generated by the parent is printed, then
36
-	 * the HTML code of its sub-clients. The order of the HTML sub-clients
37
-	 * determines the order of the output of these sub-clients inside the parent
38
-	 * container. If the configured list of clients is
39
-	 *
40
-	 *  array( "subclient1", "subclient2" )
41
-	 *
42
-	 * you can easily change the order of the output by reordering the subparts:
43
-	 *
44
-	 *  client/html/<clients>/subparts = array( "subclient1", "subclient2" )
45
-	 *
46
-	 * You can also remove one or more parts if they shouldn't be rendered:
47
-	 *
48
-	 *  client/html/<clients>/subparts = array( "subclient1" )
49
-	 *
50
-	 * As the clients only generates structural HTML, the layout defined via CSS
51
-	 * should support adding, removing or reordering content by a fluid like
52
-	 * design.
53
-	 *
54
-	 * @param array List of sub-client names
55
-	 * @since 2014.03
56
-	 * @category Developer
57
-	 */
58
-	private $subPartPath = 'client/html/checkout/standard/address/billing/standard/subparts';
59
-	private $subPartNames = array();
60
-	private $cache;
61
-
62
-	private $mandatory = array(
63
-		'order.base.address.salutation',
64
-		'order.base.address.firstname',
65
-		'order.base.address.lastname',
66
-		'order.base.address.address1',
67
-		'order.base.address.postal',
68
-		'order.base.address.city',
69
-		'order.base.address.languageid',
70
-		'order.base.address.email'
71
-	);
72
-
73
-	private $optional = array(
74
-		'order.base.address.company',
75
-		'order.base.address.vatid',
76
-		'order.base.address.address2',
77
-		'order.base.address.countryid',
78
-		'order.base.address.state',
79
-	);
80
-
81
-
82
-	/**
83
-	 * Returns the HTML code for insertion into the body.
84
-	 *
85
-	 * @param string $uid Unique identifier for the output if the content is placed more than once on the same page
86
-	 * @param array &$tags Result array for the list of tags that are associated to the output
87
-	 * @param string|null &$expire Result variable for the expiration date of the output (null for no expiry)
88
-	 * @return string HTML code
89
-	 */
90
-	public function getBody( $uid = '', array &$tags = array(), &$expire = null )
91
-	{
92
-		$view = $this->setViewParams( $this->getView(), $tags, $expire );
93
-
94
-		$html = '';
95
-		foreach( $this->getSubClients() as $subclient ) {
96
-			$html .= $subclient->setView( $view )->getBody( $uid, $tags, $expire );
97
-		}
98
-		$view->billingBody = $html;
99
-
100
-		/** client/html/checkout/standard/address/billing/standard/template-body
101
-		 * Relative path to the HTML body template of the checkout standard address billing client.
102
-		 *
103
-		 * The template file contains the HTML code and processing instructions
104
-		 * to generate the result shown in the body of the frontend. The
105
-		 * configuration string is the path to the template file relative
106
-		 * to the templates directory (usually in client/html/templates).
107
-		 *
108
-		 * You can overwrite the template file configuration in extensions and
109
-		 * provide alternative templates. These alternative templates should be
110
-		 * named like the default one but with the string "standard" replaced by
111
-		 * an unique name. You may use the name of your project for this. If
112
-		 * you've implemented an alternative client class as well, "standard"
113
-		 * should be replaced by the name of the new class.
114
-		 *
115
-		 * @param string Relative path to the template creating code for the HTML page body
116
-		 * @since 2014.03
117
-		 * @category Developer
118
-		 * @see client/html/checkout/standard/address/billing/standard/template-header
119
-		 */
120
-		$tplconf = 'client/html/checkout/standard/address/billing/standard/template-body';
121
-		$default = 'checkout/standard/address-billing-body-default.php';
122
-
123
-		return $view->render( $view->config( $tplconf, $default ) );
124
-	}
125
-
126
-
127
-	/**
128
-	 * Returns the HTML string for insertion into the header.
129
-	 *
130
-	 * @param string $uid Unique identifier for the output if the content is placed more than once on the same page
131
-	 * @param array &$tags Result array for the list of tags that are associated to the output
132
-	 * @param string|null &$expire Result variable for the expiration date of the output (null for no expiry)
133
-	 * @return string|null String including HTML tags for the header on error
134
-	 */
135
-	public function getHeader( $uid = '', array &$tags = array(), &$expire = null )
136
-	{
137
-		$view = $this->setViewParams( $this->getView(), $tags, $expire );
138
-
139
-		$html = '';
140
-		foreach( $this->getSubClients() as $subclient ) {
141
-			$html .= $subclient->setView( $view )->getHeader( $uid, $tags, $expire );
142
-		}
143
-		$view->billingHeader = $html;
144
-
145
-		/** client/html/checkout/standard/address/billing/standard/template-header
146
-		 * Relative path to the HTML header template of the checkout standard address billing client.
147
-		 *
148
-		 * The template file contains the HTML code and processing instructions
149
-		 * to generate the HTML code that is inserted into the HTML page header
150
-		 * of the rendered page in the frontend. The configuration string is the
151
-		 * path to the template file relative to the templates directory (usually
152
-		 * in client/html/templates).
153
-		 *
154
-		 * You can overwrite the template file configuration in extensions and
155
-		 * provide alternative templates. These alternative templates should be
156
-		 * named like the default one but with the string "standard" replaced by
157
-		 * an unique name. You may use the name of your project for this. If
158
-		 * you've implemented an alternative client class as well, "standard"
159
-		 * should be replaced by the name of the new class.
160
-		 *
161
-		 * @param string Relative path to the template creating code for the HTML page head
162
-		 * @since 2014.03
163
-		 * @category Developer
164
-		 * @see client/html/checkout/standard/address/billing/standard/template-body
165
-		 */
166
-		$tplconf = 'client/html/checkout/standard/address/billing/standard/template-header';
167
-		$default = 'checkout/standard/address-billing-header-default.php';
168
-
169
-		return $view->render( $view->config( $tplconf, $default ) );
170
-	}
171
-
172
-
173
-	/**
174
-	 * Returns the sub-client given by its name.
175
-	 *
176
-	 * @param string $type Name of the client type
177
-	 * @param string|null $name Name of the sub-client (Default if null)
178
-	 * @return \Aimeos\Client\Html\Iface Sub-client object
179
-	 */
180
-	public function getSubClient( $type, $name = null )
181
-	{
182
-		/** client/html/checkout/standard/address/billing/decorators/excludes
183
-		 * Excludes decorators added by the "common" option from the checkout standard address billing html client
184
-		 *
185
-		 * Decorators extend the functionality of a class by adding new aspects
186
-		 * (e.g. log what is currently done), executing the methods of the underlying
187
-		 * class only in certain conditions (e.g. only for logged in users) or
188
-		 * modify what is returned to the caller.
189
-		 *
190
-		 * This option allows you to remove a decorator added via
191
-		 * "client/html/common/decorators/default" before they are wrapped
192
-		 * around the html client.
193
-		 *
194
-		 *  client/html/checkout/standard/address/billing/decorators/excludes = array( 'decorator1' )
195
-		 *
196
-		 * This would remove the decorator named "decorator1" from the list of
197
-		 * common decorators ("\Aimeos\Client\Html\Common\Decorator\*") added via
198
-		 * "client/html/common/decorators/default" to the html client.
199
-		 *
200
-		 * @param array List of decorator names
201
-		 * @since 2015.08
202
-		 * @category Developer
203
-		 * @see client/html/common/decorators/default
204
-		 * @see client/html/checkout/standard/address/billing/decorators/global
205
-		 * @see client/html/checkout/standard/address/billing/decorators/local
206
-		 */
207
-
208
-		/** client/html/checkout/standard/address/billing/decorators/global
209
-		 * Adds a list of globally available decorators only to the checkout standard address billing html client
210
-		 *
211
-		 * Decorators extend the functionality of a class by adding new aspects
212
-		 * (e.g. log what is currently done), executing the methods of the underlying
213
-		 * class only in certain conditions (e.g. only for logged in users) or
214
-		 * modify what is returned to the caller.
215
-		 *
216
-		 * This option allows you to wrap global decorators
217
-		 * ("\Aimeos\Client\Html\Common\Decorator\*") around the html client.
218
-		 *
219
-		 *  client/html/checkout/standard/address/billing/decorators/global = array( 'decorator1' )
220
-		 *
221
-		 * This would add the decorator named "decorator1" defined by
222
-		 * "\Aimeos\Client\Html\Common\Decorator\Decorator1" only to the html client.
223
-		 *
224
-		 * @param array List of decorator names
225
-		 * @since 2015.08
226
-		 * @category Developer
227
-		 * @see client/html/common/decorators/default
228
-		 * @see client/html/checkout/standard/address/billing/decorators/excludes
229
-		 * @see client/html/checkout/standard/address/billing/decorators/local
230
-		 */
231
-
232
-		/** client/html/checkout/standard/address/billing/decorators/local
233
-		 * Adds a list of local decorators only to the checkout standard address billing html client
234
-		 *
235
-		 * Decorators extend the functionality of a class by adding new aspects
236
-		 * (e.g. log what is currently done), executing the methods of the underlying
237
-		 * class only in certain conditions (e.g. only for logged in users) or
238
-		 * modify what is returned to the caller.
239
-		 *
240
-		 * This option allows you to wrap local decorators
241
-		 * ("\Aimeos\Client\Html\Checkout\Decorator\*") around the html client.
242
-		 *
243
-		 *  client/html/checkout/standard/address/billing/decorators/local = array( 'decorator2' )
244
-		 *
245
-		 * This would add the decorator named "decorator2" defined by
246
-		 * "\Aimeos\Client\Html\Checkout\Decorator\Decorator2" only to the html client.
247
-		 *
248
-		 * @param array List of decorator names
249
-		 * @since 2015.08
250
-		 * @category Developer
251
-		 * @see client/html/common/decorators/default
252
-		 * @see client/html/checkout/standard/address/billing/decorators/excludes
253
-		 * @see client/html/checkout/standard/address/billing/decorators/global
254
-		 */
255
-
256
-		return $this->createSubClient( 'checkout/standard/address/billing/' . $type, $name );
257
-	}
258
-
259
-
260
-	/**
261
-	 * Stores the given or fetched billing address in the basket.
262
-	 */
263
-	public function process()
264
-	{
265
-		$view = $this->getView();
266
-
267
-		try
268
-		{
269
-			// only start if there's something to do
270
-			if( $view->param( 'ca_billingoption', null ) === null ) {
271
-				return;
272
-			}
273
-
274
-			$context = $this->getContext();
275
-			$basketCtrl = \Aimeos\Controller\Frontend\Factory::createController( $context, 'basket' );
276
-
277
-
278
-			/** client/html/checkout/standard/address/billing/disable-new
279
-			 * Disables the option to enter a new billing address for an order
280
-			 *
281
-			 * Besides the main billing address, customers can usually enter a new
282
-			 * billing address as well. To suppress displaying the form fields for
283
-			 * a billing address, you can set this configuration option to "1".
284
-			 *
285
-			 * Until 2015-02, the configuration option was available as
286
-			 * "client/html/common/address/billing/disable-new" starting from 2014-03.
287
-			 *
288
-			 * @param boolean A value of "1" to disable, "0" enables the billing address form
289
-			 * @since 2015.02
290
-			 * @category User
291
-			 * @category Developer
292
-			 * @see client/html/checkout/standard/address/billing/salutations
293
-			 * @see client/html/checkout/standard/address/billing/mandatory
294
-			 * @see client/html/checkout/standard/address/billing/optional
295
-			 * @see client/html/checkout/standard/address/billing/hidden
296
-			 */
297
-			$disable = $view->config( 'client/html/checkout/standard/address/billing/disable-new', false );
298
-			$type = \Aimeos\MShop\Order\Item\Base\Address\Base::TYPE_PAYMENT;
299
-
300
-			if( ( $option = $view->param( 'ca_billingoption', 'null' ) ) === 'null' && $disable === false ) // new address
301
-			{
302
-				$params = $view->param( 'ca_billing', array() );
303
-				$invalid = $this->checkFields( $params );
304
-
305
-				if( count( $invalid ) > 0 )
306
-				{
307
-					$view->billingError = $invalid;
308
-					throw new \Aimeos\Client\Html\Exception( sprintf( 'At least one billing address part is missing or invalid' ) );
309
-				}
310
-
311
-				$basketCtrl->setAddress( $type, $params );
312
-			}
313
-			else // existing address
314
-			{
315
-				$customerManager = \Aimeos\MShop\Factory::createManager( $context, 'customer' );
316
-
317
-				$search = $customerManager->createSearch( true );
318
-				$expr = array(
319
-					$search->compare( '==', 'customer.id', $option ),
320
-					$search->getConditions(),
321
-				);
322
-				$search->setConditions( $search->combine( '&&', $expr ) );
323
-
324
-				$items = $customerManager->searchItems( $search );
325
-
326
-				if( ( $item = reset( $items ) ) === false || $option != $context->getUserId() ) {
327
-					throw new \Aimeos\Client\Html\Exception( sprintf( 'Customer with ID "%1$s" not found', $option ) );
328
-				}
329
-
330
-				$invalid = array();
331
-				$addr = $item->getPaymentAddress();
332
-				$params = $view->param( 'ca_billing_' . $option, array() );
333
-
334
-				if( !empty( $params ) )
335
-				{
336
-					$list = array();
337
-					$invalid = $this->checkFields( $params );
338
-
339
-					foreach( $params as $key => $value ) {
340
-						$list[str_replace( 'order.base', 'customer', $key )] = $value;
341
-					}
342
-
343
-					$addr->fromArray( $list );
344
-					$item->setPaymentAddress( $addr );
345
-
346
-					$customerManager->saveItem( $item );
347
-				}
348
-
349
-				if( count( $invalid ) > 0 )
350
-				{
351
-					$view->billingError = $invalid;
352
-					throw new \Aimeos\Client\Html\Exception( sprintf( 'At least one billing address part is missing or invalid' ) );
353
-				}
354
-
355
-				$basketCtrl->setAddress( $type, $addr );
356
-			}
357
-
358
-			parent::process();
359
-		}
360
-		catch( \Aimeos\Controller\Frontend\Exception $e )
361
-		{
362
-			$view->billingError = $e->getErrorList();
363
-			throw $e;
364
-		}
365
-	}
366
-
367
-
368
-	/**
369
-	 * Checks the address fields for missing data and sanitizes the given parameter list.
370
-	 *
371
-	 * @param array &$params Associative list of address keys (order.base.address.* or customer.address.*) and their values
372
-	 * @return array List of missing field names
373
-	 */
374
-	protected function checkFields( array &$params )
375
-	{
376
-		$view = $this->getView();
377
-
378
-		/** client/html/checkout/standard/address/billing/mandatory
379
-		 * List of billing address input fields that are required
380
-		 *
381
-		 * You can configure the list of billing address fields that are
382
-		 * necessary and must be filled by the customer before he can
383
-		 * continue the checkout process. Available field keys are:
384
-		 * * order.base.address.company
385
-		 * * order.base.address.vatid
386
-		 * * order.base.address.salutation
387
-		 * * order.base.address.firstname
388
-		 * * order.base.address.lastname
389
-		 * * order.base.address.address1
390
-		 * * order.base.address.address2
391
-		 * * order.base.address.address3
392
-		 * * order.base.address.postal
393
-		 * * order.base.address.city
394
-		 * * order.base.address.state
395
-		 * * order.base.address.languageid
396
-		 * * order.base.address.countryid
397
-		 * * order.base.address.telephone
398
-		 * * order.base.address.telefax
399
-		 * * order.base.address.email
400
-		 * * order.base.address.website
401
-		 *
402
-		 * Until 2015-02, the configuration option was available as
403
-		 * "client/html/common/address/billing/mandatory" starting from 2014-03.
404
-		 *
405
-		 * @param array List of field keys
406
-		 * @since 2015.02
407
-		 * @category User
408
-		 * @category Developer
409
-		 * @see client/html/checkout/standard/address/billing/disable-new
410
-		 * @see client/html/checkout/standard/address/billing/salutations
411
-		 * @see client/html/checkout/standard/address/billing/optional
412
-		 * @see client/html/checkout/standard/address/billing/hidden
413
-		 * @see client/html/checkout/standard/address/countries
414
-		 * @see client/html/checkout/standard/address/validate
415
-		 */
416
-		$mandatory = $view->config( 'client/html/checkout/standard/address/billing/mandatory', $this->mandatory );
417
-
418
-		/** client/html/checkout/standard/address/billing/optional
419
-		 * List of billing address input fields that are optional
420
-		 *
421
-		 * You can configure the list of billing address fields that
422
-		 * customers can fill but don't have to before they can
423
-		 * continue the checkout process. Available field keys are:
424
-		 * * order.base.address.company
425
-		 * * order.base.address.vatid
426
-		 * * order.base.address.salutation
427
-		 * * order.base.address.firstname
428
-		 * * order.base.address.lastname
429
-		 * * order.base.address.address1
430
-		 * * order.base.address.address2
431
-		 * * order.base.address.address3
432
-		 * * order.base.address.postal
433
-		 * * order.base.address.city
434
-		 * * order.base.address.state
435
-		 * * order.base.address.languageid
436
-		 * * order.base.address.countryid
437
-		 * * order.base.address.telephone
438
-		 * * order.base.address.telefax
439
-		 * * order.base.address.email
440
-		 * * order.base.address.website
441
-		 *
442
-		 * Until 2015-02, the configuration option was available as
443
-		 * "client/html/common/address/billing/optional" starting from 2014-03.
444
-		 *
445
-		 * @param array List of field keys
446
-		 * @since 2015.02
447
-		 * @category User
448
-		 * @category Developer
449
-		 * @see client/html/checkout/standard/address/billing/disable-new
450
-		 * @see client/html/checkout/standard/address/billing/salutations
451
-		 * @see client/html/checkout/standard/address/billing/mandatory
452
-		 * @see client/html/checkout/standard/address/billing/hidden
453
-		 * @see client/html/checkout/standard/address/countries
454
-		 * @see client/html/checkout/standard/address/validate
455
-		 */
456
-		$optional = $view->config( 'client/html/checkout/standard/address/billing/optional', $this->optional );
457
-
458
-		/** client/html/checkout/standard/address/validate
459
-		 * List of regular expressions to validate the data of the address fields
460
-		 *
461
-		 * To validate the address input data of the customer, an individual
462
-		 * {@link http://php.net/manual/en/pcre.pattern.php Perl compatible regular expression}
463
-		 * can be applied to each field. Available fields are:
464
-		 * * company
465
-		 * * vatid
466
-		 * * salutation
467
-		 * * firstname
468
-		 * * lastname
469
-		 * * address1
470
-		 * * address2
471
-		 * * address3
472
-		 * * postal
473
-		 * * city
474
-		 * * state
475
-		 * * languageid
476
-		 * * countryid
477
-		 * * telephone
478
-		 * * telefax
479
-		 * * email
480
-		 * * website
481
-		 *
482
-		 * Some fields are validated automatically because they are not
483
-		 * dependent on a country specific rule. These fields are:
484
-		 * * salutation
485
-		 * * email
486
-		 * * website
487
-		 *
488
-		 * To validate e.g the postal/zip code, you can define a regular
489
-		 * expression like this if you want to allow only digits:
490
-		 *
491
-		 *  client/html/checkout/standard/address/validate/postal = '^[0-9]+$'
492
-		 *
493
-		 * Several regular expressions can be defined line this:
494
-		 *
495
-		 *  client/html/checkout/standard/address/validate = array(
496
-		 *      'postal' = '^[0-9]+$',
497
-		 *      'vatid' = '^[A-Z]{2}[0-9]{8}$',
498
-		 *  )
499
-		 *
500
-		 * Don't add any delimiting characters like slashes (/) to the beginning
501
-		 * or the end of the regular expression. They will be added automatically.
502
-		 * Any slashes inside the expression must be escaped by backlashes,
503
-		 * i.e. "\/".
504
-		 *
505
-		 * Until 2015-02, the configuration option was available as
506
-		 * "client/html/common/address/billing/validate" starting from 2014-09.
507
-		 *
508
-		 * @param array Associative list of field names and regular expressions
509
-		 * @since 2014.09
510
-		 * @category Developer
511
-		 * @see client/html/checkout/standard/address/billing/mandatory
512
-		 * @see client/html/checkout/standard/address/billing/optional
513
-		 */
514
-
515
-		/** client/html/checkout/standard/address/validate/company
516
-		 * Regular expression to check the "company" address value
517
-		 *
518
-		 * @see client/html/checkout/standard/address/validate
519
-		 */
520
-
521
-		/** client/html/checkout/standard/address/validate/vatid
522
-		 * Regular expression to check the "vatid" address value
523
-		 *
524
-		 * @see client/html/checkout/standard/address/validate
525
-		 */
526
-
527
-		/** client/html/checkout/standard/address/validate/salutation
528
-		 * Regular expression to check the "salutation" address value
529
-		 *
530
-		 * @see client/html/checkout/standard/address/validate
531
-		 */
532
-
533
-		/** client/html/checkout/standard/address/validate/firstname
534
-		 * Regular expression to check the "firstname" address value
535
-		 *
536
-		 * @see client/html/checkout/standard/address/validate
537
-		 */
538
-
539
-		/** client/html/checkout/standard/address/validate/lastname
540
-		 * Regular expression to check the "lastname" address value
541
-		 *
542
-		 * @see client/html/checkout/standard/address/validate
543
-		 */
544
-
545
-		/** client/html/checkout/standard/address/validate/address1
546
-		 * Regular expression to check the "address1" address value
547
-		 *
548
-		 * @see client/html/checkout/standard/address/validate
549
-		 */
550
-
551
-		/** client/html/checkout/standard/address/validate/address2
552
-		 * Regular expression to check the "address2" address value
553
-		 *
554
-		 * @see client/html/checkout/standard/address/validate
555
-		 */
556
-
557
-		/** client/html/checkout/standard/address/validate/address3
558
-		 * Regular expression to check the "address3" address value
559
-		 *
560
-		 * @see client/html/checkout/standard/address/validate
561
-		 */
562
-
563
-		/** client/html/checkout/standard/address/validate/postal
564
-		 * Regular expression to check the "postal" address value
565
-		 *
566
-		 * @see client/html/checkout/standard/address/validate
567
-		 */
568
-
569
-		/** client/html/checkout/standard/address/validate/city
570
-		 * Regular expression to check the "city" address value
571
-		 *
572
-		 * @see client/html/checkout/standard/address/validate
573
-		 */
574
-
575
-		/** client/html/checkout/standard/address/validate/state
576
-		 * Regular expression to check the "state" address value
577
-		 *
578
-		 * @see client/html/checkout/standard/address/validate
579
-		 */
580
-
581
-		/** client/html/checkout/standard/address/validate/languageid
582
-		 * Regular expression to check the "languageid" address value
583
-		 *
584
-		 * @see client/html/checkout/standard/address/validate
585
-		 */
586
-
587
-		/** client/html/checkout/standard/address/validate/countryid
588
-		 * Regular expression to check the "countryid" address value
589
-		 *
590
-		 * @see client/html/checkout/standard/address/validate
591
-		 */
592
-
593
-		/** client/html/checkout/standard/address/validate/telephone
594
-		 * Regular expression to check the "telephone" address value
595
-		 *
596
-		 * @see client/html/checkout/standard/address/validate
597
-		 */
598
-
599
-		/** client/html/checkout/standard/address/validate/telefax
600
-		 * Regular expression to check the "telefax" address value
601
-		 *
602
-		 * @see client/html/checkout/standard/address/validate
603
-		 */
604
-
605
-		/** client/html/checkout/standard/address/validate/email
606
-		 * Regular expression to check the "email" address value
607
-		 *
608
-		 * @see client/html/checkout/standard/address/validate
609
-		 */
610
-
611
-		/** client/html/checkout/standard/address/validate/website
612
-		 * Regular expression to check the "website" address value
613
-		 *
614
-		 * @see client/html/checkout/standard/address/validate
615
-		 */
616
-
617
-		$invalid = array();
618
-		$allFields = array_flip( array_merge( $mandatory, $optional ) );
619
-
620
-		foreach( $params as $key => $value )
621
-		{
622
-			if( isset( $allFields[$key] ) )
623
-			{
624
-				$name = substr( $key, 19 );
625
-				$regex = $view->config( 'client/html/checkout/standard/address/validate/' . $name );
626
-
627
-				if( $regex && preg_match( '/' . $regex . '/', $value ) !== 1 )
628
-				{
629
-					$msg = $view->translate( 'client', 'Billing address part "%1$s" is invalid' );
630
-					$invalid[$key] = sprintf( $msg, $name );
631
-					unset( $params[$key] );
632
-				}
633
-			}
634
-			else
635
-			{
636
-				unset( $params[$key] );
637
-			}
638
-		}
639
-
640
-
641
-		if( isset( $params['order.base.address.salutation'] )
642
-			&& $params['order.base.address.salutation'] === \Aimeos\MShop\Common\Item\Address\Base::SALUTATION_COMPANY
643
-			&& in_array( 'order.base.address.company', $mandatory ) === false
644
-		) {
645
-			$mandatory[] = 'order.base.address.company';
646
-		} else {
647
-			$params['order.base.address.company'] = $params['order.base.address.vatid'] = '';
648
-		}
649
-
650
-		foreach( $mandatory as $key )
651
-		{
652
-			if( !isset( $params[$key] ) || $params[$key] == '' )
653
-			{
654
-				$msg = $view->translate( 'client', 'Billing address part "%1$s" is missing' );
655
-				$invalid[$key] = sprintf( $msg, substr( $key, 19 ) );
656
-				unset( $params[$key] );
657
-			}
658
-		}
659
-
660
-		return $invalid;
661
-	}
662
-
663
-
664
-	/**
665
-	 * Returns the list of sub-client names configured for the client.
666
-	 *
667
-	 * @return array List of HTML client names
668
-	 */
669
-	protected function getSubClientNames()
670
-	{
671
-		return $this->getContext()->getConfig()->get( $this->subPartPath, $this->subPartNames );
672
-	}
673
-
674
-
675
-	/**
676
-	 * Sets the necessary parameter values in the view.
677
-	 *
678
-	 * @param \Aimeos\MW\View\Iface $view The view object which generates the HTML output
679
-	 * @param array &$tags Result array for the list of tags that are associated to the output
680
-	 * @param string|null &$expire Result variable for the expiration date of the output (null for no expiry)
681
-	 * @return \Aimeos\MW\View\Iface Modified view object
682
-	 */
683
-	protected function setViewParams( \Aimeos\MW\View\Iface $view, array &$tags = array(), &$expire = null )
684
-	{
685
-		if( !isset( $this->cache ) )
686
-		{
687
-			$context = $this->getContext();
688
-			$basketCntl = \Aimeos\Controller\Frontend\Factory::createController( $context, 'basket' );
689
-
690
-			try {
691
-				$langid = $basketCntl->get()->getAddress( 'payment' )->getLanguageId();
692
-			} catch( \Exception $e ) {
693
-				$langid = $view->param( 'ca_billing/order.base.address.languageid', $context->getLocale()->getLanguageId() );
694
-			}
695
-			$view->billingLanguage = $langid;
696
-
697
-			/** client/html/checkout/standard/address/billing/hidden
698
-			 * List of billing address input fields that are optional and should be hidden
699
-			 *
700
-			 * You can configure the list of billing address fields that
701
-			 * are hidden when a customer enters his new billing address.
702
-			 * Available field keys are:
703
-			 * * order.base.address.company
704
-			 * * order.base.address.vatid
705
-			 * * order.base.address.salutation
706
-			 * * order.base.address.firstname
707
-			 * * order.base.address.lastname
708
-			 * * order.base.address.address1
709
-			 * * order.base.address.address2
710
-			 * * order.base.address.address3
711
-			 * * order.base.address.postal
712
-			 * * order.base.address.city
713
-			 * * order.base.address.state
714
-			 * * order.base.address.languageid
715
-			 * * order.base.address.countryid
716
-			 * * order.base.address.telephone
717
-			 * * order.base.address.telefax
718
-			 * * order.base.address.email
719
-			 * * order.base.address.website
720
-			 *
721
-			 * Caution: Only hide fields that don't require any input
722
-			 *
723
-			 * Until 2015-02, the configuration option was available as
724
-			 * "client/html/common/address/billing/hidden" starting from 2014-03.
725
-			 *
726
-			 * @param array List of field keys
727
-			 * @since 2015.02
728
-			 * @category User
729
-			 * @category Developer
730
-			 * @see client/html/checkout/standard/address/billing/disable-new
731
-			 * @see client/html/checkout/standard/address/billing/salutations
732
-			 * @see client/html/checkout/standard/address/billing/mandatory
733
-			 * @see client/html/checkout/standard/address/billing/optional
734
-			 * @see client/html/checkout/standard/address/countries
735
-			 */
736
-			$hidden = $view->config( 'client/html/checkout/standard/address/billing/hidden', array() );
737
-
738
-			if( count( $view->get( 'addressLanguages', array() ) ) === 1 ) {
739
-				$hidden[] = 'order.base.address.languageid';
740
-			}
741
-
742
-			$salutations = array( 'company', 'mr', 'mrs' );
743
-
744
-			/** client/html/checkout/standard/address/billing/salutations
745
-			 * List of salutions the customer can select from for the billing address
746
-			 *
747
-			 * The following salutations are available:
748
-			 * * empty string for "unknown"
749
-			 * * company
750
-			 * * mr
751
-			 * * mrs
752
-			 * * miss
753
-			 *
754
-			 * You can modify the list of salutation codes and remove the ones
755
-			 * which shouldn't be used. Adding new salutations is a little bit
756
-			 * more difficult because you have to adapt a few areas in the source
757
-			 * code.
758
-			 *
759
-			 * Until 2015-02, the configuration option was available as
760
-			 * "client/html/common/address/billing/salutations" starting from 2014-03.
761
-			 *
762
-			 * @param array List of available salutation codes
763
-			 * @since 2015.02
764
-			 * @category User
765
-			 * @category Developer
766
-			 * @see client/html/checkout/standard/address/billing/disable-new
767
-			 * @see client/html/checkout/standard/address/billing/mandatory
768
-			 * @see client/html/checkout/standard/address/billing/optional
769
-			 * @see client/html/checkout/standard/address/billing/hidden
770
-			 * @see client/html/checkout/standard/address/countries
771
-			 */
772
-			$view->billingSalutations = $view->config( 'client/html/checkout/standard/address/billing/salutations', $salutations );
773
-
774
-			$view->billingMandatory = $view->config( 'client/html/checkout/standard/address/billing/mandatory', $this->mandatory );
775
-			$view->billingOptional = $view->config( 'client/html/checkout/standard/address/billing/optional', $this->optional );
776
-			$view->billingHidden = $hidden;
777
-
778
-			$this->cache = $view;
779
-		}
780
-
781
-		return $this->cache;
782
-	}
25
+    /** client/html/checkout/standard/address/billing/standard/subparts
26
+     * List of HTML sub-clients rendered within the checkout standard address billing section
27
+     *
28
+     * The output of the frontend is composed of the code generated by the HTML
29
+     * clients. Each HTML client can consist of serveral (or none) sub-clients
30
+     * that are responsible for rendering certain sub-parts of the output. The
31
+     * sub-clients can contain HTML clients themselves and therefore a
32
+     * hierarchical tree of HTML clients is composed. Each HTML client creates
33
+     * the output that is placed inside the container of its parent.
34
+     *
35
+     * At first, always the HTML code generated by the parent is printed, then
36
+     * the HTML code of its sub-clients. The order of the HTML sub-clients
37
+     * determines the order of the output of these sub-clients inside the parent
38
+     * container. If the configured list of clients is
39
+     *
40
+     *  array( "subclient1", "subclient2" )
41
+     *
42
+     * you can easily change the order of the output by reordering the subparts:
43
+     *
44
+     *  client/html/<clients>/subparts = array( "subclient1", "subclient2" )
45
+     *
46
+     * You can also remove one or more parts if they shouldn't be rendered:
47
+     *
48
+     *  client/html/<clients>/subparts = array( "subclient1" )
49
+     *
50
+     * As the clients only generates structural HTML, the layout defined via CSS
51
+     * should support adding, removing or reordering content by a fluid like
52
+     * design.
53
+     *
54
+     * @param array List of sub-client names
55
+     * @since 2014.03
56
+     * @category Developer
57
+     */
58
+    private $subPartPath = 'client/html/checkout/standard/address/billing/standard/subparts';
59
+    private $subPartNames = array();
60
+    private $cache;
61
+
62
+    private $mandatory = array(
63
+        'order.base.address.salutation',
64
+        'order.base.address.firstname',
65
+        'order.base.address.lastname',
66
+        'order.base.address.address1',
67
+        'order.base.address.postal',
68
+        'order.base.address.city',
69
+        'order.base.address.languageid',
70
+        'order.base.address.email'
71
+    );
72
+
73
+    private $optional = array(
74
+        'order.base.address.company',
75
+        'order.base.address.vatid',
76
+        'order.base.address.address2',
77
+        'order.base.address.countryid',
78
+        'order.base.address.state',
79
+    );
80
+
81
+
82
+    /**
83
+     * Returns the HTML code for insertion into the body.
84
+     *
85
+     * @param string $uid Unique identifier for the output if the content is placed more than once on the same page
86
+     * @param array &$tags Result array for the list of tags that are associated to the output
87
+     * @param string|null &$expire Result variable for the expiration date of the output (null for no expiry)
88
+     * @return string HTML code
89
+     */
90
+    public function getBody( $uid = '', array &$tags = array(), &$expire = null )
91
+    {
92
+        $view = $this->setViewParams( $this->getView(), $tags, $expire );
93
+
94
+        $html = '';
95
+        foreach( $this->getSubClients() as $subclient ) {
96
+            $html .= $subclient->setView( $view )->getBody( $uid, $tags, $expire );
97
+        }
98
+        $view->billingBody = $html;
99
+
100
+        /** client/html/checkout/standard/address/billing/standard/template-body
101
+         * Relative path to the HTML body template of the checkout standard address billing client.
102
+         *
103
+         * The template file contains the HTML code and processing instructions
104
+         * to generate the result shown in the body of the frontend. The
105
+         * configuration string is the path to the template file relative
106
+         * to the templates directory (usually in client/html/templates).
107
+         *
108
+         * You can overwrite the template file configuration in extensions and
109
+         * provide alternative templates. These alternative templates should be
110
+         * named like the default one but with the string "standard" replaced by
111
+         * an unique name. You may use the name of your project for this. If
112
+         * you've implemented an alternative client class as well, "standard"
113
+         * should be replaced by the name of the new class.
114
+         *
115
+         * @param string Relative path to the template creating code for the HTML page body
116
+         * @since 2014.03
117
+         * @category Developer
118
+         * @see client/html/checkout/standard/address/billing/standard/template-header
119
+         */
120
+        $tplconf = 'client/html/checkout/standard/address/billing/standard/template-body';
121
+        $default = 'checkout/standard/address-billing-body-default.php';
122
+
123
+        return $view->render( $view->config( $tplconf, $default ) );
124
+    }
125
+
126
+
127
+    /**
128
+     * Returns the HTML string for insertion into the header.
129
+     *
130
+     * @param string $uid Unique identifier for the output if the content is placed more than once on the same page
131
+     * @param array &$tags Result array for the list of tags that are associated to the output
132
+     * @param string|null &$expire Result variable for the expiration date of the output (null for no expiry)
133
+     * @return string|null String including HTML tags for the header on error
134
+     */
135
+    public function getHeader( $uid = '', array &$tags = array(), &$expire = null )
136
+    {
137
+        $view = $this->setViewParams( $this->getView(), $tags, $expire );
138
+
139
+        $html = '';
140
+        foreach( $this->getSubClients() as $subclient ) {
141
+            $html .= $subclient->setView( $view )->getHeader( $uid, $tags, $expire );
142
+        }
143
+        $view->billingHeader = $html;
144
+
145
+        /** client/html/checkout/standard/address/billing/standard/template-header
146
+         * Relative path to the HTML header template of the checkout standard address billing client.
147
+         *
148
+         * The template file contains the HTML code and processing instructions
149
+         * to generate the HTML code that is inserted into the HTML page header
150
+         * of the rendered page in the frontend. The configuration string is the
151
+         * path to the template file relative to the templates directory (usually
152
+         * in client/html/templates).
153
+         *
154
+         * You can overwrite the template file configuration in extensions and
155
+         * provide alternative templates. These alternative templates should be
156
+         * named like the default one but with the string "standard" replaced by
157
+         * an unique name. You may use the name of your project for this. If
158
+         * you've implemented an alternative client class as well, "standard"
159
+         * should be replaced by the name of the new class.
160
+         *
161
+         * @param string Relative path to the template creating code for the HTML page head
162
+         * @since 2014.03
163
+         * @category Developer
164
+         * @see client/html/checkout/standard/address/billing/standard/template-body
165
+         */
166
+        $tplconf = 'client/html/checkout/standard/address/billing/standard/template-header';
167
+        $default = 'checkout/standard/address-billing-header-default.php';
168
+
169
+        return $view->render( $view->config( $tplconf, $default ) );
170
+    }
171
+
172
+
173
+    /**
174
+     * Returns the sub-client given by its name.
175
+     *
176
+     * @param string $type Name of the client type
177
+     * @param string|null $name Name of the sub-client (Default if null)
178
+     * @return \Aimeos\Client\Html\Iface Sub-client object
179
+     */
180
+    public function getSubClient( $type, $name = null )
181
+    {
182
+        /** client/html/checkout/standard/address/billing/decorators/excludes
183
+         * Excludes decorators added by the "common" option from the checkout standard address billing html client
184
+         *
185
+         * Decorators extend the functionality of a class by adding new aspects
186
+         * (e.g. log what is currently done), executing the methods of the underlying
187
+         * class only in certain conditions (e.g. only for logged in users) or
188
+         * modify what is returned to the caller.
189
+         *
190
+         * This option allows you to remove a decorator added via
191
+         * "client/html/common/decorators/default" before they are wrapped
192
+         * around the html client.
193
+         *
194
+         *  client/html/checkout/standard/address/billing/decorators/excludes = array( 'decorator1' )
195
+         *
196
+         * This would remove the decorator named "decorator1" from the list of
197
+         * common decorators ("\Aimeos\Client\Html\Common\Decorator\*") added via
198
+         * "client/html/common/decorators/default" to the html client.
199
+         *
200
+         * @param array List of decorator names
201
+         * @since 2015.08
202
+         * @category Developer
203
+         * @see client/html/common/decorators/default
204
+         * @see client/html/checkout/standard/address/billing/decorators/global
205
+         * @see client/html/checkout/standard/address/billing/decorators/local
206
+         */
207
+
208
+        /** client/html/checkout/standard/address/billing/decorators/global
209
+         * Adds a list of globally available decorators only to the checkout standard address billing html client
210
+         *
211
+         * Decorators extend the functionality of a class by adding new aspects
212
+         * (e.g. log what is currently done), executing the methods of the underlying
213
+         * class only in certain conditions (e.g. only for logged in users) or
214
+         * modify what is returned to the caller.
215
+         *
216
+         * This option allows you to wrap global decorators
217
+         * ("\Aimeos\Client\Html\Common\Decorator\*") around the html client.
218
+         *
219
+         *  client/html/checkout/standard/address/billing/decorators/global = array( 'decorator1' )
220
+         *
221
+         * This would add the decorator named "decorator1" defined by
222
+         * "\Aimeos\Client\Html\Common\Decorator\Decorator1" only to the html client.
223
+         *
224
+         * @param array List of decorator names
225
+         * @since 2015.08
226
+         * @category Developer
227
+         * @see client/html/common/decorators/default
228
+         * @see client/html/checkout/standard/address/billing/decorators/excludes
229
+         * @see client/html/checkout/standard/address/billing/decorators/local
230
+         */
231
+
232
+        /** client/html/checkout/standard/address/billing/decorators/local
233
+         * Adds a list of local decorators only to the checkout standard address billing html client
234
+         *
235
+         * Decorators extend the functionality of a class by adding new aspects
236
+         * (e.g. log what is currently done), executing the methods of the underlying
237
+         * class only in certain conditions (e.g. only for logged in users) or
238
+         * modify what is returned to the caller.
239
+         *
240
+         * This option allows you to wrap local decorators
241
+         * ("\Aimeos\Client\Html\Checkout\Decorator\*") around the html client.
242
+         *
243
+         *  client/html/checkout/standard/address/billing/decorators/local = array( 'decorator2' )
244
+         *
245
+         * This would add the decorator named "decorator2" defined by
246
+         * "\Aimeos\Client\Html\Checkout\Decorator\Decorator2" only to the html client.
247
+         *
248
+         * @param array List of decorator names
249
+         * @since 2015.08
250
+         * @category Developer
251
+         * @see client/html/common/decorators/default
252
+         * @see client/html/checkout/standard/address/billing/decorators/excludes
253
+         * @see client/html/checkout/standard/address/billing/decorators/global
254
+         */
255
+
256
+        return $this->createSubClient( 'checkout/standard/address/billing/' . $type, $name );
257
+    }
258
+
259
+
260
+    /**
261
+     * Stores the given or fetched billing address in the basket.
262
+     */
263
+    public function process()
264
+    {
265
+        $view = $this->getView();
266
+
267
+        try
268
+        {
269
+            // only start if there's something to do
270
+            if( $view->param( 'ca_billingoption', null ) === null ) {
271
+                return;
272
+            }
273
+
274
+            $context = $this->getContext();
275
+            $basketCtrl = \Aimeos\Controller\Frontend\Factory::createController( $context, 'basket' );
276
+
277
+
278
+            /** client/html/checkout/standard/address/billing/disable-new
279
+             * Disables the option to enter a new billing address for an order
280
+             *
281
+             * Besides the main billing address, customers can usually enter a new
282
+             * billing address as well. To suppress displaying the form fields for
283
+             * a billing address, you can set this configuration option to "1".
284
+             *
285
+             * Until 2015-02, the configuration option was available as
286
+             * "client/html/common/address/billing/disable-new" starting from 2014-03.
287
+             *
288
+             * @param boolean A value of "1" to disable, "0" enables the billing address form
289
+             * @since 2015.02
290
+             * @category User
291
+             * @category Developer
292
+             * @see client/html/checkout/standard/address/billing/salutations
293
+             * @see client/html/checkout/standard/address/billing/mandatory
294
+             * @see client/html/checkout/standard/address/billing/optional
295
+             * @see client/html/checkout/standard/address/billing/hidden
296
+             */
297
+            $disable = $view->config( 'client/html/checkout/standard/address/billing/disable-new', false );
298
+            $type = \Aimeos\MShop\Order\Item\Base\Address\Base::TYPE_PAYMENT;
299
+
300
+            if( ( $option = $view->param( 'ca_billingoption', 'null' ) ) === 'null' && $disable === false ) // new address
301
+            {
302
+                $params = $view->param( 'ca_billing', array() );
303
+                $invalid = $this->checkFields( $params );
304
+
305
+                if( count( $invalid ) > 0 )
306
+                {
307
+                    $view->billingError = $invalid;
308
+                    throw new \Aimeos\Client\Html\Exception( sprintf( 'At least one billing address part is missing or invalid' ) );
309
+                }
310
+
311
+                $basketCtrl->setAddress( $type, $params );
312
+            }
313
+            else // existing address
314
+            {
315
+                $customerManager = \Aimeos\MShop\Factory::createManager( $context, 'customer' );
316
+
317
+                $search = $customerManager->createSearch( true );
318
+                $expr = array(
319
+                    $search->compare( '==', 'customer.id', $option ),
320
+                    $search->getConditions(),
321
+                );
322
+                $search->setConditions( $search->combine( '&&', $expr ) );
323
+
324
+                $items = $customerManager->searchItems( $search );
325
+
326
+                if( ( $item = reset( $items ) ) === false || $option != $context->getUserId() ) {
327
+                    throw new \Aimeos\Client\Html\Exception( sprintf( 'Customer with ID "%1$s" not found', $option ) );
328
+                }
329
+
330
+                $invalid = array();
331
+                $addr = $item->getPaymentAddress();
332
+                $params = $view->param( 'ca_billing_' . $option, array() );
333
+
334
+                if( !empty( $params ) )
335
+                {
336
+                    $list = array();
337
+                    $invalid = $this->checkFields( $params );
338
+
339
+                    foreach( $params as $key => $value ) {
340
+                        $list[str_replace( 'order.base', 'customer', $key )] = $value;
341
+                    }
342
+
343
+                    $addr->fromArray( $list );
344
+                    $item->setPaymentAddress( $addr );
345
+
346
+                    $customerManager->saveItem( $item );
347
+                }
348
+
349
+                if( count( $invalid ) > 0 )
350
+                {
351
+                    $view->billingError = $invalid;
352
+                    throw new \Aimeos\Client\Html\Exception( sprintf( 'At least one billing address part is missing or invalid' ) );
353
+                }
354
+
355
+                $basketCtrl->setAddress( $type, $addr );
356
+            }
357
+
358
+            parent::process();
359
+        }
360
+        catch( \Aimeos\Controller\Frontend\Exception $e )
361
+        {
362
+            $view->billingError = $e->getErrorList();
363
+            throw $e;
364
+        }
365
+    }
366
+
367
+
368
+    /**
369
+     * Checks the address fields for missing data and sanitizes the given parameter list.
370
+     *
371
+     * @param array &$params Associative list of address keys (order.base.address.* or customer.address.*) and their values
372
+     * @return array List of missing field names
373
+     */
374
+    protected function checkFields( array &$params )
375
+    {
376
+        $view = $this->getView();
377
+
378
+        /** client/html/checkout/standard/address/billing/mandatory
379
+         * List of billing address input fields that are required
380
+         *
381
+         * You can configure the list of billing address fields that are
382
+         * necessary and must be filled by the customer before he can
383
+         * continue the checkout process. Available field keys are:
384
+         * * order.base.address.company
385
+         * * order.base.address.vatid
386
+         * * order.base.address.salutation
387
+         * * order.base.address.firstname
388
+         * * order.base.address.lastname
389
+         * * order.base.address.address1
390
+         * * order.base.address.address2
391
+         * * order.base.address.address3
392
+         * * order.base.address.postal
393
+         * * order.base.address.city
394
+         * * order.base.address.state
395
+         * * order.base.address.languageid
396
+         * * order.base.address.countryid
397
+         * * order.base.address.telephone
398
+         * * order.base.address.telefax
399
+         * * order.base.address.email
400
+         * * order.base.address.website
401
+         *
402
+         * Until 2015-02, the configuration option was available as
403
+         * "client/html/common/address/billing/mandatory" starting from 2014-03.
404
+         *
405
+         * @param array List of field keys
406
+         * @since 2015.02
407
+         * @category User
408
+         * @category Developer
409
+         * @see client/html/checkout/standard/address/billing/disable-new
410
+         * @see client/html/checkout/standard/address/billing/salutations
411
+         * @see client/html/checkout/standard/address/billing/optional
412
+         * @see client/html/checkout/standard/address/billing/hidden
413
+         * @see client/html/checkout/standard/address/countries
414
+         * @see client/html/checkout/standard/address/validate
415
+         */
416
+        $mandatory = $view->config( 'client/html/checkout/standard/address/billing/mandatory', $this->mandatory );
417
+
418
+        /** client/html/checkout/standard/address/billing/optional
419
+         * List of billing address input fields that are optional
420
+         *
421
+         * You can configure the list of billing address fields that
422
+         * customers can fill but don't have to before they can
423
+         * continue the checkout process. Available field keys are:
424
+         * * order.base.address.company
425
+         * * order.base.address.vatid
426
+         * * order.base.address.salutation
427
+         * * order.base.address.firstname
428
+         * * order.base.address.lastname
429
+         * * order.base.address.address1
430
+         * * order.base.address.address2
431
+         * * order.base.address.address3
432
+         * * order.base.address.postal
433
+         * * order.base.address.city
434
+         * * order.base.address.state
435
+         * * order.base.address.languageid
436
+         * * order.base.address.countryid
437
+         * * order.base.address.telephone
438
+         * * order.base.address.telefax
439
+         * * order.base.address.email
440
+         * * order.base.address.website
441
+         *
442
+         * Until 2015-02, the configuration option was available as
443
+         * "client/html/common/address/billing/optional" starting from 2014-03.
444
+         *
445
+         * @param array List of field keys
446
+         * @since 2015.02
447
+         * @category User
448
+         * @category Developer
449
+         * @see client/html/checkout/standard/address/billing/disable-new
450
+         * @see client/html/checkout/standard/address/billing/salutations
451
+         * @see client/html/checkout/standard/address/billing/mandatory
452
+         * @see client/html/checkout/standard/address/billing/hidden
453
+         * @see client/html/checkout/standard/address/countries
454
+         * @see client/html/checkout/standard/address/validate
455
+         */
456
+        $optional = $view->config( 'client/html/checkout/standard/address/billing/optional', $this->optional );
457
+
458
+        /** client/html/checkout/standard/address/validate
459
+         * List of regular expressions to validate the data of the address fields
460
+         *
461
+         * To validate the address input data of the customer, an individual
462
+         * {@link http://php.net/manual/en/pcre.pattern.php Perl compatible regular expression}
463
+         * can be applied to each field. Available fields are:
464
+         * * company
465
+         * * vatid
466
+         * * salutation
467
+         * * firstname
468
+         * * lastname
469
+         * * address1
470
+         * * address2
471
+         * * address3
472
+         * * postal
473
+         * * city
474
+         * * state
475
+         * * languageid
476
+         * * countryid
477
+         * * telephone
478
+         * * telefax
479
+         * * email
480
+         * * website
481
+         *
482
+         * Some fields are validated automatically because they are not
483
+         * dependent on a country specific rule. These fields are:
484
+         * * salutation
485
+         * * email
486
+         * * website
487
+         *
488
+         * To validate e.g the postal/zip code, you can define a regular
489
+         * expression like this if you want to allow only digits:
490
+         *
491
+         *  client/html/checkout/standard/address/validate/postal = '^[0-9]+$'
492
+         *
493
+         * Several regular expressions can be defined line this:
494
+         *
495
+         *  client/html/checkout/standard/address/validate = array(
496
+         *      'postal' = '^[0-9]+$',
497
+         *      'vatid' = '^[A-Z]{2}[0-9]{8}$',
498
+         *  )
499
+         *
500
+         * Don't add any delimiting characters like slashes (/) to the beginning
501
+         * or the end of the regular expression. They will be added automatically.
502
+         * Any slashes inside the expression must be escaped by backlashes,
503
+         * i.e. "\/".
504
+         *
505
+         * Until 2015-02, the configuration option was available as
506
+         * "client/html/common/address/billing/validate" starting from 2014-09.
507
+         *
508
+         * @param array Associative list of field names and regular expressions
509
+         * @since 2014.09
510
+         * @category Developer
511
+         * @see client/html/checkout/standard/address/billing/mandatory
512
+         * @see client/html/checkout/standard/address/billing/optional
513
+         */
514
+
515
+        /** client/html/checkout/standard/address/validate/company
516
+         * Regular expression to check the "company" address value
517
+         *
518
+         * @see client/html/checkout/standard/address/validate
519
+         */
520
+
521
+        /** client/html/checkout/standard/address/validate/vatid
522
+         * Regular expression to check the "vatid" address value
523
+         *
524
+         * @see client/html/checkout/standard/address/validate
525
+         */
526
+
527
+        /** client/html/checkout/standard/address/validate/salutation
528
+         * Regular expression to check the "salutation" address value
529
+         *
530
+         * @see client/html/checkout/standard/address/validate
531
+         */
532
+
533
+        /** client/html/checkout/standard/address/validate/firstname
534
+         * Regular expression to check the "firstname" address value
535
+         *
536
+         * @see client/html/checkout/standard/address/validate
537
+         */
538
+
539
+        /** client/html/checkout/standard/address/validate/lastname
540
+         * Regular expression to check the "lastname" address value
541
+         *
542
+         * @see client/html/checkout/standard/address/validate
543
+         */
544
+
545
+        /** client/html/checkout/standard/address/validate/address1
546
+         * Regular expression to check the "address1" address value
547
+         *
548
+         * @see client/html/checkout/standard/address/validate
549
+         */
550
+
551
+        /** client/html/checkout/standard/address/validate/address2
552
+         * Regular expression to check the "address2" address value
553
+         *
554
+         * @see client/html/checkout/standard/address/validate
555
+         */
556
+
557
+        /** client/html/checkout/standard/address/validate/address3
558
+         * Regular expression to check the "address3" address value
559
+         *
560
+         * @see client/html/checkout/standard/address/validate
561
+         */
562
+
563
+        /** client/html/checkout/standard/address/validate/postal
564
+         * Regular expression to check the "postal" address value
565
+         *
566
+         * @see client/html/checkout/standard/address/validate
567
+         */
568
+
569
+        /** client/html/checkout/standard/address/validate/city
570
+         * Regular expression to check the "city" address value
571
+         *
572
+         * @see client/html/checkout/standard/address/validate
573
+         */
574
+
575
+        /** client/html/checkout/standard/address/validate/state
576
+         * Regular expression to check the "state" address value
577
+         *
578
+         * @see client/html/checkout/standard/address/validate
579
+         */
580
+
581
+        /** client/html/checkout/standard/address/validate/languageid
582
+         * Regular expression to check the "languageid" address value
583
+         *
584
+         * @see client/html/checkout/standard/address/validate
585
+         */
586
+
587
+        /** client/html/checkout/standard/address/validate/countryid
588
+         * Regular expression to check the "countryid" address value
589
+         *
590
+         * @see client/html/checkout/standard/address/validate
591
+         */
592
+
593
+        /** client/html/checkout/standard/address/validate/telephone
594
+         * Regular expression to check the "telephone" address value
595
+         *
596
+         * @see client/html/checkout/standard/address/validate
597
+         */
598
+
599
+        /** client/html/checkout/standard/address/validate/telefax
600
+         * Regular expression to check the "telefax" address value
601
+         *
602
+         * @see client/html/checkout/standard/address/validate
603
+         */
604
+
605
+        /** client/html/checkout/standard/address/validate/email
606
+         * Regular expression to check the "email" address value
607
+         *
608
+         * @see client/html/checkout/standard/address/validate
609
+         */
610
+
611
+        /** client/html/checkout/standard/address/validate/website
612
+         * Regular expression to check the "website" address value
613
+         *
614
+         * @see client/html/checkout/standard/address/validate
615
+         */
616
+
617
+        $invalid = array();
618
+        $allFields = array_flip( array_merge( $mandatory, $optional ) );
619
+
620
+        foreach( $params as $key => $value )
621
+        {
622
+            if( isset( $allFields[$key] ) )
623
+            {
624
+                $name = substr( $key, 19 );
625
+                $regex = $view->config( 'client/html/checkout/standard/address/validate/' . $name );
626
+
627
+                if( $regex && preg_match( '/' . $regex . '/', $value ) !== 1 )
628
+                {
629
+                    $msg = $view->translate( 'client', 'Billing address part "%1$s" is invalid' );
630
+                    $invalid[$key] = sprintf( $msg, $name );
631
+                    unset( $params[$key] );
632
+                }
633
+            }
634
+            else
635
+            {
636
+                unset( $params[$key] );
637
+            }
638
+        }
639
+
640
+
641
+        if( isset( $params['order.base.address.salutation'] )
642
+            && $params['order.base.address.salutation'] === \Aimeos\MShop\Common\Item\Address\Base::SALUTATION_COMPANY
643
+            && in_array( 'order.base.address.company', $mandatory ) === false
644
+        ) {
645
+            $mandatory[] = 'order.base.address.company';
646
+        } else {
647
+            $params['order.base.address.company'] = $params['order.base.address.vatid'] = '';
648
+        }
649
+
650
+        foreach( $mandatory as $key )
651
+        {
652
+            if( !isset( $params[$key] ) || $params[$key] == '' )
653
+            {
654
+                $msg = $view->translate( 'client', 'Billing address part "%1$s" is missing' );
655
+                $invalid[$key] = sprintf( $msg, substr( $key, 19 ) );
656
+                unset( $params[$key] );
657
+            }
658
+        }
659
+
660
+        return $invalid;
661
+    }
662
+
663
+
664
+    /**
665
+     * Returns the list of sub-client names configured for the client.
666
+     *
667
+     * @return array List of HTML client names
668
+     */
669
+    protected function getSubClientNames()
670
+    {
671
+        return $this->getContext()->getConfig()->get( $this->subPartPath, $this->subPartNames );
672
+    }
673
+
674
+
675
+    /**
676
+     * Sets the necessary parameter values in the view.
677
+     *
678
+     * @param \Aimeos\MW\View\Iface $view The view object which generates the HTML output
679
+     * @param array &$tags Result array for the list of tags that are associated to the output
680
+     * @param string|null &$expire Result variable for the expiration date of the output (null for no expiry)
681
+     * @return \Aimeos\MW\View\Iface Modified view object
682
+     */
683
+    protected function setViewParams( \Aimeos\MW\View\Iface $view, array &$tags = array(), &$expire = null )
684
+    {
685
+        if( !isset( $this->cache ) )
686
+        {
687
+            $context = $this->getContext();
688
+            $basketCntl = \Aimeos\Controller\Frontend\Factory::createController( $context, 'basket' );
689
+
690
+            try {
691
+                $langid = $basketCntl->get()->getAddress( 'payment' )->getLanguageId();
692
+            } catch( \Exception $e ) {
693
+                $langid = $view->param( 'ca_billing/order.base.address.languageid', $context->getLocale()->getLanguageId() );
694
+            }
695
+            $view->billingLanguage = $langid;
696
+
697
+            /** client/html/checkout/standard/address/billing/hidden
698
+             * List of billing address input fields that are optional and should be hidden
699
+             *
700
+             * You can configure the list of billing address fields that
701
+             * are hidden when a customer enters his new billing address.
702
+             * Available field keys are:
703
+             * * order.base.address.company
704
+             * * order.base.address.vatid
705
+             * * order.base.address.salutation
706
+             * * order.base.address.firstname
707
+             * * order.base.address.lastname
708
+             * * order.base.address.address1
709
+             * * order.base.address.address2
710
+             * * order.base.address.address3
711
+             * * order.base.address.postal
712
+             * * order.base.address.city
713
+             * * order.base.address.state
714
+             * * order.base.address.languageid
715
+             * * order.base.address.countryid
716
+             * * order.base.address.telephone
717
+             * * order.base.address.telefax
718
+             * * order.base.address.email
719
+             * * order.base.address.website
720
+             *
721
+             * Caution: Only hide fields that don't require any input
722
+             *
723
+             * Until 2015-02, the configuration option was available as
724
+             * "client/html/common/address/billing/hidden" starting from 2014-03.
725
+             *
726
+             * @param array List of field keys
727
+             * @since 2015.02
728
+             * @category User
729
+             * @category Developer
730
+             * @see client/html/checkout/standard/address/billing/disable-new
731
+             * @see client/html/checkout/standard/address/billing/salutations
732
+             * @see client/html/checkout/standard/address/billing/mandatory
733
+             * @see client/html/checkout/standard/address/billing/optional
734
+             * @see client/html/checkout/standard/address/countries
735
+             */
736
+            $hidden = $view->config( 'client/html/checkout/standard/address/billing/hidden', array() );
737
+
738
+            if( count( $view->get( 'addressLanguages', array() ) ) === 1 ) {
739
+                $hidden[] = 'order.base.address.languageid';
740
+            }
741
+
742
+            $salutations = array( 'company', 'mr', 'mrs' );
743
+
744
+            /** client/html/checkout/standard/address/billing/salutations
745
+             * List of salutions the customer can select from for the billing address
746
+             *
747
+             * The following salutations are available:
748
+             * * empty string for "unknown"
749
+             * * company
750
+             * * mr
751
+             * * mrs
752
+             * * miss
753
+             *
754
+             * You can modify the list of salutation codes and remove the ones
755
+             * which shouldn't be used. Adding new salutations is a little bit
756
+             * more difficult because you have to adapt a few areas in the source
757
+             * code.
758
+             *
759
+             * Until 2015-02, the configuration option was available as
760
+             * "client/html/common/address/billing/salutations" starting from 2014-03.
761
+             *
762
+             * @param array List of available salutation codes
763
+             * @since 2015.02
764
+             * @category User
765
+             * @category Developer
766
+             * @see client/html/checkout/standard/address/billing/disable-new
767
+             * @see client/html/checkout/standard/address/billing/mandatory
768
+             * @see client/html/checkout/standard/address/billing/optional
769
+             * @see client/html/checkout/standard/address/billing/hidden
770
+             * @see client/html/checkout/standard/address/countries
771
+             */
772
+            $view->billingSalutations = $view->config( 'client/html/checkout/standard/address/billing/salutations', $salutations );
773
+
774
+            $view->billingMandatory = $view->config( 'client/html/checkout/standard/address/billing/mandatory', $this->mandatory );
775
+            $view->billingOptional = $view->config( 'client/html/checkout/standard/address/billing/optional', $this->optional );
776
+            $view->billingHidden = $hidden;
777
+
778
+            $this->cache = $view;
779
+        }
780
+
781
+        return $this->cache;
782
+    }
783 783
 }
784 784
\ No newline at end of file
Please login to merge, or discard this patch.
client/html/src/Client/Html/Checkout/Standard/Address/Standard.php 1 patch
Indentation   +449 added lines, -449 removed lines patch added patch discarded remove patch
@@ -23,454 +23,454 @@
 block discarded – undo
23 23
  * @subpackage Html
24 24
  */
25 25
 class Standard
26
-	extends \Aimeos\Client\Html\Common\Client\Factory\Base
27
-	implements \Aimeos\Client\Html\Common\Client\Factory\Iface
26
+    extends \Aimeos\Client\Html\Common\Client\Factory\Base
27
+    implements \Aimeos\Client\Html\Common\Client\Factory\Iface
28 28
 {
29
-	/** client/html/checkout/standard/address/standard/subparts
30
-	 * List of HTML sub-clients rendered within the checkout standard address section
31
-	 *
32
-	 * The output of the frontend is composed of the code generated by the HTML
33
-	 * clients. Each HTML client can consist of serveral (or none) sub-clients
34
-	 * that are responsible for rendering certain sub-parts of the output. The
35
-	 * sub-clients can contain HTML clients themselves and therefore a
36
-	 * hierarchical tree of HTML clients is composed. Each HTML client creates
37
-	 * the output that is placed inside the container of its parent.
38
-	 *
39
-	 * At first, always the HTML code generated by the parent is printed, then
40
-	 * the HTML code of its sub-clients. The order of the HTML sub-clients
41
-	 * determines the order of the output of these sub-clients inside the parent
42
-	 * container. If the configured list of clients is
43
-	 *
44
-	 *  array( "subclient1", "subclient2" )
45
-	 *
46
-	 * you can easily change the order of the output by reordering the subparts:
47
-	 *
48
-	 *  client/html/<clients>/subparts = array( "subclient1", "subclient2" )
49
-	 *
50
-	 * You can also remove one or more parts if they shouldn't be rendered:
51
-	 *
52
-	 *  client/html/<clients>/subparts = array( "subclient1" )
53
-	 *
54
-	 * As the clients only generates structural HTML, the layout defined via CSS
55
-	 * should support adding, removing or reordering content by a fluid like
56
-	 * design.
57
-	 *
58
-	 * @param array List of sub-client names
59
-	 * @since 2014.03
60
-	 * @category Developer
61
-	 */
62
-	private $subPartPath = 'client/html/checkout/standard/address/standard/subparts';
63
-
64
-	/** client/html/checkout/standard/address/billing/name
65
-	 * Name of the billing part used by the checkout standard address client implementation
66
-	 *
67
-	 * Use "Myname" if your class is named "\Aimeos\Client\Checkout\Standard\Address\Billing\Myname".
68
-	 * The name is case-sensitive and you should avoid camel case names like "MyName".
69
-	 *
70
-	 * @param string Last part of the client class name
71
-	 * @since 2014.03
72
-	 * @category Developer
73
-	 */
74
-
75
-	/** client/html/checkout/standard/address/delivery/name
76
-	 * Name of the delivery part used by the checkout standard address client implementation
77
-	 *
78
-	 * Use "Myname" if your class is named "\Aimeos\Client\Checkout\Standard\Address\Delivery\Myname".
79
-	 * The name is case-sensitive and you should avoid camel case names like "MyName".
80
-	 *
81
-	 * @param string Last part of the client class name
82
-	 * @since 2014.03
83
-	 * @category Developer
84
-	 */
85
-	private $subPartNames = array( 'billing', 'delivery' );
86
-
87
-	private $cache;
88
-
89
-
90
-	/**
91
-	 * Returns the HTML code for insertion into the body.
92
-	 *
93
-	 * @param string $uid Unique identifier for the output if the content is placed more than once on the same page
94
-	 * @param array &$tags Result array for the list of tags that are associated to the output
95
-	 * @param string|null &$expire Result variable for the expiration date of the output (null for no expiry)
96
-	 * @return string HTML code
97
-	 */
98
-	public function getBody( $uid = '', array &$tags = array(), &$expire = null )
99
-	{
100
-		$view = $this->getView();
101
-		$step = $view->get( 'standardStepActive', 'address' );
102
-		$onepage = $view->config( 'client/html/checkout/standard/onepage', array() );
103
-
104
-		if( $step != 'address' && !( in_array( 'address', $onepage ) && in_array( $step, $onepage ) ) ) {
105
-			return '';
106
-		}
107
-
108
-		$view = $this->setViewParams( $view, $tags, $expire );
109
-
110
-		$html = '';
111
-		foreach( $this->getSubClients() as $subclient ) {
112
-			$html .= $subclient->setView( $view )->getBody( $uid, $tags, $expire );
113
-		}
114
-		$view->addressBody = $html;
115
-
116
-		/** client/html/checkout/standard/address/standard/template-body
117
-		 * Relative path to the HTML body template of the checkout standard address client.
118
-		 *
119
-		 * The template file contains the HTML code and processing instructions
120
-		 * to generate the result shown in the body of the frontend. The
121
-		 * configuration string is the path to the template file relative
122
-		 * to the templates directory (usually in client/html/templates).
123
-		 *
124
-		 * You can overwrite the template file configuration in extensions and
125
-		 * provide alternative templates. These alternative templates should be
126
-		 * named like the default one but with the string "standard" replaced by
127
-		 * an unique name. You may use the name of your project for this. If
128
-		 * you've implemented an alternative client class as well, "standard"
129
-		 * should be replaced by the name of the new class.
130
-		 *
131
-		 * @param string Relative path to the template creating code for the HTML page body
132
-		 * @since 2014.03
133
-		 * @category Developer
134
-		 * @see client/html/checkout/standard/address/standard/template-header
135
-		 */
136
-		$tplconf = 'client/html/checkout/standard/address/standard/template-body';
137
-		$default = 'checkout/standard/address-body-default.php';
138
-
139
-		return $view->render( $view->config( $tplconf, $default ) );
140
-	}
141
-
142
-
143
-	/**
144
-	 * Returns the HTML string for insertion into the header.
145
-	 *
146
-	 * @param string $uid Unique identifier for the output if the content is placed more than once on the same page
147
-	 * @param array &$tags Result array for the list of tags that are associated to the output
148
-	 * @param string|null &$expire Result variable for the expiration date of the output (null for no expiry)
149
-	 * @return string|null String including HTML tags for the header on error
150
-	 */
151
-	public function getHeader( $uid = '', array &$tags = array(), &$expire = null )
152
-	{
153
-		$view = $this->getView();
154
-		$step = $view->get( 'standardStepActive' );
155
-		$onepage = $view->config( 'client/html/checkout/standard/onepage', array() );
156
-
157
-		if( $step != 'address' && !( in_array( 'address', $onepage ) && in_array( $step, $onepage ) ) ) {
158
-			return '';
159
-		}
160
-
161
-		$view = $this->setViewParams( $view, $tags, $expire );
162
-
163
-		$html = '';
164
-		foreach( $this->getSubClients() as $subclient ) {
165
-			$html .= $subclient->setView( $view )->getHeader( $uid, $tags, $expire );
166
-		}
167
-		$view->addressHeader = $html;
168
-
169
-		/** client/html/checkout/standard/address/standard/template-header
170
-		 * Relative path to the HTML header template of the checkout standard address client.
171
-		 *
172
-		 * The template file contains the HTML code and processing instructions
173
-		 * to generate the HTML code that is inserted into the HTML page header
174
-		 * of the rendered page in the frontend. The configuration string is the
175
-		 * path to the template file relative to the templates directory (usually
176
-		 * in client/html/templates).
177
-		 *
178
-		 * You can overwrite the template file configuration in extensions and
179
-		 * provide alternative templates. These alternative templates should be
180
-		 * named like the default one but with the string "standard" replaced by
181
-		 * an unique name. You may use the name of your project for this. If
182
-		 * you've implemented an alternative client class as well, "standard"
183
-		 * should be replaced by the name of the new class.
184
-		 *
185
-		 * @param string Relative path to the template creating code for the HTML page head
186
-		 * @since 2014.03
187
-		 * @category Developer
188
-		 * @see client/html/checkout/standard/address/standard/template-body
189
-		 */
190
-		$tplconf = 'client/html/checkout/standard/address/standard/template-header';
191
-		$default = 'checkout/standard/address-header-default.php';
192
-
193
-		return $view->render( $view->config( $tplconf, $default ) );
194
-	}
195
-
196
-
197
-	/**
198
-	 * Returns the sub-client given by its name.
199
-	 *
200
-	 * @param string $type Name of the client type
201
-	 * @param string|null $name Name of the sub-client (Default if null)
202
-	 * @return \Aimeos\Client\Html\Iface Sub-client object
203
-	 */
204
-	public function getSubClient( $type, $name = null )
205
-	{
206
-		/** client/html/checkout/standard/address/decorators/excludes
207
-		 * Excludes decorators added by the "common" option from the checkout standard address html client
208
-		 *
209
-		 * Decorators extend the functionality of a class by adding new aspects
210
-		 * (e.g. log what is currently done), executing the methods of the underlying
211
-		 * class only in certain conditions (e.g. only for logged in users) or
212
-		 * modify what is returned to the caller.
213
-		 *
214
-		 * This option allows you to remove a decorator added via
215
-		 * "client/html/common/decorators/default" before they are wrapped
216
-		 * around the html client.
217
-		 *
218
-		 *  client/html/checkout/standard/address/decorators/excludes = array( 'decorator1' )
219
-		 *
220
-		 * This would remove the decorator named "decorator1" from the list of
221
-		 * common decorators ("\Aimeos\Client\Html\Common\Decorator\*") added via
222
-		 * "client/html/common/decorators/default" to the html client.
223
-		 *
224
-		 * @param array List of decorator names
225
-		 * @since 2015.08
226
-		 * @category Developer
227
-		 * @see client/html/common/decorators/default
228
-		 * @see client/html/checkout/standard/address/decorators/global
229
-		 * @see client/html/checkout/standard/address/decorators/local
230
-		 */
231
-
232
-		/** client/html/checkout/standard/address/decorators/global
233
-		 * Adds a list of globally available decorators only to the checkout standard address html client
234
-		 *
235
-		 * Decorators extend the functionality of a class by adding new aspects
236
-		 * (e.g. log what is currently done), executing the methods of the underlying
237
-		 * class only in certain conditions (e.g. only for logged in users) or
238
-		 * modify what is returned to the caller.
239
-		 *
240
-		 * This option allows you to wrap global decorators
241
-		 * ("\Aimeos\Client\Html\Common\Decorator\*") around the html client.
242
-		 *
243
-		 *  client/html/checkout/standard/address/decorators/global = array( 'decorator1' )
244
-		 *
245
-		 * This would add the decorator named "decorator1" defined by
246
-		 * "\Aimeos\Client\Html\Common\Decorator\Decorator1" only to the html client.
247
-		 *
248
-		 * @param array List of decorator names
249
-		 * @since 2015.08
250
-		 * @category Developer
251
-		 * @see client/html/common/decorators/default
252
-		 * @see client/html/checkout/standard/address/decorators/excludes
253
-		 * @see client/html/checkout/standard/address/decorators/local
254
-		 */
255
-
256
-		/** client/html/checkout/standard/address/decorators/local
257
-		 * Adds a list of local decorators only to the checkout standard address html client
258
-		 *
259
-		 * Decorators extend the functionality of a class by adding new aspects
260
-		 * (e.g. log what is currently done), executing the methods of the underlying
261
-		 * class only in certain conditions (e.g. only for logged in users) or
262
-		 * modify what is returned to the caller.
263
-		 *
264
-		 * This option allows you to wrap local decorators
265
-		 * ("\Aimeos\Client\Html\Checkout\Decorator\*") around the html client.
266
-		 *
267
-		 *  client/html/checkout/standard/address/decorators/local = array( 'decorator2' )
268
-		 *
269
-		 * This would add the decorator named "decorator2" defined by
270
-		 * "\Aimeos\Client\Html\Checkout\Decorator\Decorator2" only to the html client.
271
-		 *
272
-		 * @param array List of decorator names
273
-		 * @since 2015.08
274
-		 * @category Developer
275
-		 * @see client/html/common/decorators/default
276
-		 * @see client/html/checkout/standard/address/decorators/excludes
277
-		 * @see client/html/checkout/standard/address/decorators/global
278
-		 */
279
-
280
-		return $this->createSubClient( 'checkout/standard/address/' . $type, $name );
281
-	}
282
-
283
-
284
-	/**
285
-	 * Processes the input, e.g. store given values.
286
-	 * A view must be available and this method doesn't generate any output
287
-	 * besides setting view variables.
288
-	 */
289
-	public function process()
290
-	{
291
-		$view = $this->getView();
292
-
293
-		try
294
-		{
295
-			parent::process();
296
-
297
-			$basketCntl = \Aimeos\Controller\Frontend\Factory::createController( $this->getContext(), 'basket' );
298
-
299
-			// Test if addresses are available
300
-			$addresses = $basketCntl->get()->getAddresses();
301
-			if( !isset( $view->standardStepActive ) && count( $addresses ) === 0 )
302
-			{
303
-				$view->standardStepActive = 'address';
304
-				return false;
305
-			}
306
-		}
307
-		catch( \Exception $e )
308
-		{
309
-			$this->getView()->standardStepActive = 'address';
310
-			throw $e;
311
-		}
312
-
313
-	}
314
-
315
-
316
-	/**
317
-	 * Returns the list of sub-client names configured for the client.
318
-	 *
319
-	 * @return array List of HTML client names
320
-	 */
321
-	protected function getSubClientNames()
322
-	{
323
-		return $this->getContext()->getConfig()->get( $this->subPartPath, $this->subPartNames );
324
-	}
325
-
326
-
327
-	/**
328
-	 * Sets the necessary parameter values in the view.
329
-	 *
330
-	 * @param \Aimeos\MW\View\Iface $view The view object which generates the HTML output
331
-	 * @param array &$tags Result array for the list of tags that are associated to the output
332
-	 * @param string|null &$expire Result variable for the expiration date of the output (null for no expiry)
333
-	 * @return \Aimeos\MW\View\Iface Modified view object
334
-	 */
335
-	protected function setViewParams( \Aimeos\MW\View\Iface $view, array &$tags = array(), &$expire = null )
336
-	{
337
-		if( !isset( $this->cache ) )
338
-		{
339
-			$context = $this->getContext();
340
-
341
-
342
-			$customerManager = \Aimeos\MShop\Factory::createManager( $context, 'customer' );
343
-
344
-			$search = $customerManager->createSearch( true );
345
-			$expr = array(
346
-				$search->compare( '==', 'customer.id', $context->getUserId() ),
347
-				$search->getConditions(),
348
-			);
349
-			$search->setConditions( $search->combine( '&&', $expr ) );
350
-
351
-			$items = $customerManager->searchItems( $search );
352
-
353
-			if( ( $item = reset( $items ) ) !== false )
354
-			{
355
-				$deliveryAddressItems = array();
356
-
357
-				$orderAddressManager = \Aimeos\MShop\Factory::createManager( $context, 'order/base/address' );
358
-				$customerAddressManager = \Aimeos\MShop\Factory::createManager( $context, 'customer/address' );
359
-
360
-				$search = $customerAddressManager->createSearch();
361
-				$search->setConditions( $search->compare( '==', 'customer.address.parentid', $item->getId() ) );
362
-
363
-				foreach( $customerAddressManager->searchItems( $search ) as $id => $address )
364
-				{
365
-					$deliveryAddressItem = $orderAddressManager->createItem();
366
-					$deliveryAddressItem->copyFrom( $address );
367
-
368
-					$deliveryAddressItems[$id] = $deliveryAddressItem;
369
-				}
370
-
371
-				$paymentAddressItem = $orderAddressManager->createItem();
372
-				$paymentAddressItem->copyFrom( $item->getPaymentAddress() );
373
-
374
-				$view->addressCustomerItem = $item;
375
-				$view->addressPaymentItem = $paymentAddressItem;
376
-				$view->addressDeliveryItems = $deliveryAddressItems;
377
-			}
378
-
379
-
380
-			$localeManager = \Aimeos\MShop\Factory::createManager( $context, 'locale' );
381
-			$locales = $localeManager->searchItems( $localeManager->createSearch( true ) );
382
-
383
-			$languages = array();
384
-			foreach( $locales as $locale ) {
385
-				$languages[$locale->getLanguageId()] = $locale->getLanguageId();
386
-			}
387
-
388
-			$view->addressLanguages = $languages;
389
-
390
-			/** client/html/checkout/standard/address/countries
391
-			 * List of available countries that that users can select from in the front-end
392
-			 *
393
-			 * This configration option is used whenever a list of countries is
394
-			 * shown in the front-end users can select from. It's used e.g.
395
-			 * if the customer should select the country he is living in the
396
-			 * checkout process. In case that the list is empty, no country
397
-			 * selection is shown.
398
-			 *
399
-			 * Each list entry must be a two letter ISO country code that is then
400
-			 * translated into its name. The codes have to be upper case
401
-			 * characters like "DE" for Germany or "GB" for Great Britain, e.g.
402
-			 *
403
-			 *  array( 'DE', 'GB', ... )
404
-			 *
405
-			 * To display the country selection, you have to add the key for the
406
-			 * country ID (order.base.address.languageid) to the "mandatory" or
407
-			 * "optional" configuration option for billing and delivery addresses.
408
-			 *
409
-			 * Until 2015-02, the configuration option was available as
410
-			 * "client/html/common/address/countries" starting from 2014-03.
411
-			 *
412
-			 * @param array List of two letter ISO country codes
413
-			 * @since 2015.02
414
-			 * @category User
415
-			 * @category Developer
416
-			 * @see client/html/checkout/standard/address/billing/mandatory
417
-			 * @see client/html/checkout/standard/address/billing/optional
418
-			 * @see client/html/checkout/standard/address/delivery/mandatory
419
-			 * @see client/html/checkout/standard/address/delivery/optional
420
-			 */
421
-			$view->addressCountries = $view->config( 'client/html/checkout/standard/address/countries', array() );
422
-
423
-			/** client/html/checkout/standard/address/states
424
-			 * List of available states that that users can select from in the front-end
425
-			 *
426
-			 * This configration option is used whenever a list of states is
427
-			 * shown in the front-end users can select from. It's used e.g.
428
-			 * if the customer should select the state he is living in the
429
-			 * checkout process. In case that the list is empty, no state
430
-			 * selection is shown.
431
-			 *
432
-			 * A two letter ISO country code must be the key for the list of
433
-			 * states that belong to this country. The list of states must then
434
-			 * contain the state code as key and its name as values, e.g.
435
-			 *
436
-			 *  array(
437
-			 *      'US' => array(
438
-			 *          'CA' => 'California',
439
-			 *          'NY' => 'New York',
440
-			 *          ...
441
-			 *      ),
442
-			 *      ...
443
-			 *  );
444
-			 *
445
-			 * The codes have to be upper case characters like "US" for the
446
-			 * United States or "DE" for Germany. The order of the country and
447
-			 * state codes determine the order of the states in the frontend and
448
-			 * the state codes are later used for per state tax calculation.
449
-			 *
450
-			 * To display the country selection, you have to add the key for the
451
-			 * state (order.base.address.state) to the "mandatory" or
452
-			 * "optional" configuration option for billing and delivery addresses.
453
-			 * You also need to add order.base.address.countryid as well because
454
-			 * it is required to display the states that belong to this country.
455
-			 *
456
-			 * Until 2015-02, the configuration option was available as
457
-			 * "client/html/common/address/states" starting from 2014-09.
458
-			 *
459
-			 * @param array Multi-dimensional list ISO country codes and state codes/names
460
-			 * @since 2015.02
461
-			 * @category User
462
-			 * @category Developer
463
-			 * @see client/html/checkout/standard/address/billing/mandatory
464
-			 * @see client/html/checkout/standard/address/billing/optional
465
-			 * @see client/html/checkout/standard/address/delivery/mandatory
466
-			 * @see client/html/checkout/standard/address/delivery/optional
467
-			 */
468
-			$view->addressStates = $view->config( 'client/html/checkout/standard/address/states', array() );
469
-
470
-
471
-			$this->cache = $view;
472
-		}
473
-
474
-		return $this->cache;
475
-	}
29
+    /** client/html/checkout/standard/address/standard/subparts
30
+     * List of HTML sub-clients rendered within the checkout standard address section
31
+     *
32
+     * The output of the frontend is composed of the code generated by the HTML
33
+     * clients. Each HTML client can consist of serveral (or none) sub-clients
34
+     * that are responsible for rendering certain sub-parts of the output. The
35
+     * sub-clients can contain HTML clients themselves and therefore a
36
+     * hierarchical tree of HTML clients is composed. Each HTML client creates
37
+     * the output that is placed inside the container of its parent.
38
+     *
39
+     * At first, always the HTML code generated by the parent is printed, then
40
+     * the HTML code of its sub-clients. The order of the HTML sub-clients
41
+     * determines the order of the output of these sub-clients inside the parent
42
+     * container. If the configured list of clients is
43
+     *
44
+     *  array( "subclient1", "subclient2" )
45
+     *
46
+     * you can easily change the order of the output by reordering the subparts:
47
+     *
48
+     *  client/html/<clients>/subparts = array( "subclient1", "subclient2" )
49
+     *
50
+     * You can also remove one or more parts if they shouldn't be rendered:
51
+     *
52
+     *  client/html/<clients>/subparts = array( "subclient1" )
53
+     *
54
+     * As the clients only generates structural HTML, the layout defined via CSS
55
+     * should support adding, removing or reordering content by a fluid like
56
+     * design.
57
+     *
58
+     * @param array List of sub-client names
59
+     * @since 2014.03
60
+     * @category Developer
61
+     */
62
+    private $subPartPath = 'client/html/checkout/standard/address/standard/subparts';
63
+
64
+    /** client/html/checkout/standard/address/billing/name
65
+     * Name of the billing part used by the checkout standard address client implementation
66
+     *
67
+     * Use "Myname" if your class is named "\Aimeos\Client\Checkout\Standard\Address\Billing\Myname".
68
+     * The name is case-sensitive and you should avoid camel case names like "MyName".
69
+     *
70
+     * @param string Last part of the client class name
71
+     * @since 2014.03
72
+     * @category Developer
73
+     */
74
+
75
+    /** client/html/checkout/standard/address/delivery/name
76
+     * Name of the delivery part used by the checkout standard address client implementation
77
+     *
78
+     * Use "Myname" if your class is named "\Aimeos\Client\Checkout\Standard\Address\Delivery\Myname".
79
+     * The name is case-sensitive and you should avoid camel case names like "MyName".
80
+     *
81
+     * @param string Last part of the client class name
82
+     * @since 2014.03
83
+     * @category Developer
84
+     */
85
+    private $subPartNames = array( 'billing', 'delivery' );
86
+
87
+    private $cache;
88
+
89
+
90
+    /**
91
+     * Returns the HTML code for insertion into the body.
92
+     *
93
+     * @param string $uid Unique identifier for the output if the content is placed more than once on the same page
94
+     * @param array &$tags Result array for the list of tags that are associated to the output
95
+     * @param string|null &$expire Result variable for the expiration date of the output (null for no expiry)
96
+     * @return string HTML code
97
+     */
98
+    public function getBody( $uid = '', array &$tags = array(), &$expire = null )
99
+    {
100
+        $view = $this->getView();
101
+        $step = $view->get( 'standardStepActive', 'address' );
102
+        $onepage = $view->config( 'client/html/checkout/standard/onepage', array() );
103
+
104
+        if( $step != 'address' && !( in_array( 'address', $onepage ) && in_array( $step, $onepage ) ) ) {
105
+            return '';
106
+        }
107
+
108
+        $view = $this->setViewParams( $view, $tags, $expire );
109
+
110
+        $html = '';
111
+        foreach( $this->getSubClients() as $subclient ) {
112
+            $html .= $subclient->setView( $view )->getBody( $uid, $tags, $expire );
113
+        }
114
+        $view->addressBody = $html;
115
+
116
+        /** client/html/checkout/standard/address/standard/template-body
117
+         * Relative path to the HTML body template of the checkout standard address client.
118
+         *
119
+         * The template file contains the HTML code and processing instructions
120
+         * to generate the result shown in the body of the frontend. The
121
+         * configuration string is the path to the template file relative
122
+         * to the templates directory (usually in client/html/templates).
123
+         *
124
+         * You can overwrite the template file configuration in extensions and
125
+         * provide alternative templates. These alternative templates should be
126
+         * named like the default one but with the string "standard" replaced by
127
+         * an unique name. You may use the name of your project for this. If
128
+         * you've implemented an alternative client class as well, "standard"
129
+         * should be replaced by the name of the new class.
130
+         *
131
+         * @param string Relative path to the template creating code for the HTML page body
132
+         * @since 2014.03
133
+         * @category Developer
134
+         * @see client/html/checkout/standard/address/standard/template-header
135
+         */
136
+        $tplconf = 'client/html/checkout/standard/address/standard/template-body';
137
+        $default = 'checkout/standard/address-body-default.php';
138
+
139
+        return $view->render( $view->config( $tplconf, $default ) );
140
+    }
141
+
142
+
143
+    /**
144
+     * Returns the HTML string for insertion into the header.
145
+     *
146
+     * @param string $uid Unique identifier for the output if the content is placed more than once on the same page
147
+     * @param array &$tags Result array for the list of tags that are associated to the output
148
+     * @param string|null &$expire Result variable for the expiration date of the output (null for no expiry)
149
+     * @return string|null String including HTML tags for the header on error
150
+     */
151
+    public function getHeader( $uid = '', array &$tags = array(), &$expire = null )
152
+    {
153
+        $view = $this->getView();
154
+        $step = $view->get( 'standardStepActive' );
155
+        $onepage = $view->config( 'client/html/checkout/standard/onepage', array() );
156
+
157
+        if( $step != 'address' && !( in_array( 'address', $onepage ) && in_array( $step, $onepage ) ) ) {
158
+            return '';
159
+        }
160
+
161
+        $view = $this->setViewParams( $view, $tags, $expire );
162
+
163
+        $html = '';
164
+        foreach( $this->getSubClients() as $subclient ) {
165
+            $html .= $subclient->setView( $view )->getHeader( $uid, $tags, $expire );
166
+        }
167
+        $view->addressHeader = $html;
168
+
169
+        /** client/html/checkout/standard/address/standard/template-header
170
+         * Relative path to the HTML header template of the checkout standard address client.
171
+         *
172
+         * The template file contains the HTML code and processing instructions
173
+         * to generate the HTML code that is inserted into the HTML page header
174
+         * of the rendered page in the frontend. The configuration string is the
175
+         * path to the template file relative to the templates directory (usually
176
+         * in client/html/templates).
177
+         *
178
+         * You can overwrite the template file configuration in extensions and
179
+         * provide alternative templates. These alternative templates should be
180
+         * named like the default one but with the string "standard" replaced by
181
+         * an unique name. You may use the name of your project for this. If
182
+         * you've implemented an alternative client class as well, "standard"
183
+         * should be replaced by the name of the new class.
184
+         *
185
+         * @param string Relative path to the template creating code for the HTML page head
186
+         * @since 2014.03
187
+         * @category Developer
188
+         * @see client/html/checkout/standard/address/standard/template-body
189
+         */
190
+        $tplconf = 'client/html/checkout/standard/address/standard/template-header';
191
+        $default = 'checkout/standard/address-header-default.php';
192
+
193
+        return $view->render( $view->config( $tplconf, $default ) );
194
+    }
195
+
196
+
197
+    /**
198
+     * Returns the sub-client given by its name.
199
+     *
200
+     * @param string $type Name of the client type
201
+     * @param string|null $name Name of the sub-client (Default if null)
202
+     * @return \Aimeos\Client\Html\Iface Sub-client object
203
+     */
204
+    public function getSubClient( $type, $name = null )
205
+    {
206
+        /** client/html/checkout/standard/address/decorators/excludes
207
+         * Excludes decorators added by the "common" option from the checkout standard address html client
208
+         *
209
+         * Decorators extend the functionality of a class by adding new aspects
210
+         * (e.g. log what is currently done), executing the methods of the underlying
211
+         * class only in certain conditions (e.g. only for logged in users) or
212
+         * modify what is returned to the caller.
213
+         *
214
+         * This option allows you to remove a decorator added via
215
+         * "client/html/common/decorators/default" before they are wrapped
216
+         * around the html client.
217
+         *
218
+         *  client/html/checkout/standard/address/decorators/excludes = array( 'decorator1' )
219
+         *
220
+         * This would remove the decorator named "decorator1" from the list of
221
+         * common decorators ("\Aimeos\Client\Html\Common\Decorator\*") added via
222
+         * "client/html/common/decorators/default" to the html client.
223
+         *
224
+         * @param array List of decorator names
225
+         * @since 2015.08
226
+         * @category Developer
227
+         * @see client/html/common/decorators/default
228
+         * @see client/html/checkout/standard/address/decorators/global
229
+         * @see client/html/checkout/standard/address/decorators/local
230
+         */
231
+
232
+        /** client/html/checkout/standard/address/decorators/global
233
+         * Adds a list of globally available decorators only to the checkout standard address html client
234
+         *
235
+         * Decorators extend the functionality of a class by adding new aspects
236
+         * (e.g. log what is currently done), executing the methods of the underlying
237
+         * class only in certain conditions (e.g. only for logged in users) or
238
+         * modify what is returned to the caller.
239
+         *
240
+         * This option allows you to wrap global decorators
241
+         * ("\Aimeos\Client\Html\Common\Decorator\*") around the html client.
242
+         *
243
+         *  client/html/checkout/standard/address/decorators/global = array( 'decorator1' )
244
+         *
245
+         * This would add the decorator named "decorator1" defined by
246
+         * "\Aimeos\Client\Html\Common\Decorator\Decorator1" only to the html client.
247
+         *
248
+         * @param array List of decorator names
249
+         * @since 2015.08
250
+         * @category Developer
251
+         * @see client/html/common/decorators/default
252
+         * @see client/html/checkout/standard/address/decorators/excludes
253
+         * @see client/html/checkout/standard/address/decorators/local
254
+         */
255
+
256
+        /** client/html/checkout/standard/address/decorators/local
257
+         * Adds a list of local decorators only to the checkout standard address html client
258
+         *
259
+         * Decorators extend the functionality of a class by adding new aspects
260
+         * (e.g. log what is currently done), executing the methods of the underlying
261
+         * class only in certain conditions (e.g. only for logged in users) or
262
+         * modify what is returned to the caller.
263
+         *
264
+         * This option allows you to wrap local decorators
265
+         * ("\Aimeos\Client\Html\Checkout\Decorator\*") around the html client.
266
+         *
267
+         *  client/html/checkout/standard/address/decorators/local = array( 'decorator2' )
268
+         *
269
+         * This would add the decorator named "decorator2" defined by
270
+         * "\Aimeos\Client\Html\Checkout\Decorator\Decorator2" only to the html client.
271
+         *
272
+         * @param array List of decorator names
273
+         * @since 2015.08
274
+         * @category Developer
275
+         * @see client/html/common/decorators/default
276
+         * @see client/html/checkout/standard/address/decorators/excludes
277
+         * @see client/html/checkout/standard/address/decorators/global
278
+         */
279
+
280
+        return $this->createSubClient( 'checkout/standard/address/' . $type, $name );
281
+    }
282
+
283
+
284
+    /**
285
+     * Processes the input, e.g. store given values.
286
+     * A view must be available and this method doesn't generate any output
287
+     * besides setting view variables.
288
+     */
289
+    public function process()
290
+    {
291
+        $view = $this->getView();
292
+
293
+        try
294
+        {
295
+            parent::process();
296
+
297
+            $basketCntl = \Aimeos\Controller\Frontend\Factory::createController( $this->getContext(), 'basket' );
298
+
299
+            // Test if addresses are available
300
+            $addresses = $basketCntl->get()->getAddresses();
301
+            if( !isset( $view->standardStepActive ) && count( $addresses ) === 0 )
302
+            {
303
+                $view->standardStepActive = 'address';
304
+                return false;
305
+            }
306
+        }
307
+        catch( \Exception $e )
308
+        {
309
+            $this->getView()->standardStepActive = 'address';
310
+            throw $e;
311
+        }
312
+
313
+    }
314
+
315
+
316
+    /**
317
+     * Returns the list of sub-client names configured for the client.
318
+     *
319
+     * @return array List of HTML client names
320
+     */
321
+    protected function getSubClientNames()
322
+    {
323
+        return $this->getContext()->getConfig()->get( $this->subPartPath, $this->subPartNames );
324
+    }
325
+
326
+
327
+    /**
328
+     * Sets the necessary parameter values in the view.
329
+     *
330
+     * @param \Aimeos\MW\View\Iface $view The view object which generates the HTML output
331
+     * @param array &$tags Result array for the list of tags that are associated to the output
332
+     * @param string|null &$expire Result variable for the expiration date of the output (null for no expiry)
333
+     * @return \Aimeos\MW\View\Iface Modified view object
334
+     */
335
+    protected function setViewParams( \Aimeos\MW\View\Iface $view, array &$tags = array(), &$expire = null )
336
+    {
337
+        if( !isset( $this->cache ) )
338
+        {
339
+            $context = $this->getContext();
340
+
341
+
342
+            $customerManager = \Aimeos\MShop\Factory::createManager( $context, 'customer' );
343
+
344
+            $search = $customerManager->createSearch( true );
345
+            $expr = array(
346
+                $search->compare( '==', 'customer.id', $context->getUserId() ),
347
+                $search->getConditions(),
348
+            );
349
+            $search->setConditions( $search->combine( '&&', $expr ) );
350
+
351
+            $items = $customerManager->searchItems( $search );
352
+
353
+            if( ( $item = reset( $items ) ) !== false )
354
+            {
355
+                $deliveryAddressItems = array();
356
+
357
+                $orderAddressManager = \Aimeos\MShop\Factory::createManager( $context, 'order/base/address' );
358
+                $customerAddressManager = \Aimeos\MShop\Factory::createManager( $context, 'customer/address' );
359
+
360
+                $search = $customerAddressManager->createSearch();
361
+                $search->setConditions( $search->compare( '==', 'customer.address.parentid', $item->getId() ) );
362
+
363
+                foreach( $customerAddressManager->searchItems( $search ) as $id => $address )
364
+                {
365
+                    $deliveryAddressItem = $orderAddressManager->createItem();
366
+                    $deliveryAddressItem->copyFrom( $address );
367
+
368
+                    $deliveryAddressItems[$id] = $deliveryAddressItem;
369
+                }
370
+
371
+                $paymentAddressItem = $orderAddressManager->createItem();
372
+                $paymentAddressItem->copyFrom( $item->getPaymentAddress() );
373
+
374
+                $view->addressCustomerItem = $item;
375
+                $view->addressPaymentItem = $paymentAddressItem;
376
+                $view->addressDeliveryItems = $deliveryAddressItems;
377
+            }
378
+
379
+
380
+            $localeManager = \Aimeos\MShop\Factory::createManager( $context, 'locale' );
381
+            $locales = $localeManager->searchItems( $localeManager->createSearch( true ) );
382
+
383
+            $languages = array();
384
+            foreach( $locales as $locale ) {
385
+                $languages[$locale->getLanguageId()] = $locale->getLanguageId();
386
+            }
387
+
388
+            $view->addressLanguages = $languages;
389
+
390
+            /** client/html/checkout/standard/address/countries
391
+             * List of available countries that that users can select from in the front-end
392
+             *
393
+             * This configration option is used whenever a list of countries is
394
+             * shown in the front-end users can select from. It's used e.g.
395
+             * if the customer should select the country he is living in the
396
+             * checkout process. In case that the list is empty, no country
397
+             * selection is shown.
398
+             *
399
+             * Each list entry must be a two letter ISO country code that is then
400
+             * translated into its name. The codes have to be upper case
401
+             * characters like "DE" for Germany or "GB" for Great Britain, e.g.
402
+             *
403
+             *  array( 'DE', 'GB', ... )
404
+             *
405
+             * To display the country selection, you have to add the key for the
406
+             * country ID (order.base.address.languageid) to the "mandatory" or
407
+             * "optional" configuration option for billing and delivery addresses.
408
+             *
409
+             * Until 2015-02, the configuration option was available as
410
+             * "client/html/common/address/countries" starting from 2014-03.
411
+             *
412
+             * @param array List of two letter ISO country codes
413
+             * @since 2015.02
414
+             * @category User
415
+             * @category Developer
416
+             * @see client/html/checkout/standard/address/billing/mandatory
417
+             * @see client/html/checkout/standard/address/billing/optional
418
+             * @see client/html/checkout/standard/address/delivery/mandatory
419
+             * @see client/html/checkout/standard/address/delivery/optional
420
+             */
421
+            $view->addressCountries = $view->config( 'client/html/checkout/standard/address/countries', array() );
422
+
423
+            /** client/html/checkout/standard/address/states
424
+             * List of available states that that users can select from in the front-end
425
+             *
426
+             * This configration option is used whenever a list of states is
427
+             * shown in the front-end users can select from. It's used e.g.
428
+             * if the customer should select the state he is living in the
429
+             * checkout process. In case that the list is empty, no state
430
+             * selection is shown.
431
+             *
432
+             * A two letter ISO country code must be the key for the list of
433
+             * states that belong to this country. The list of states must then
434
+             * contain the state code as key and its name as values, e.g.
435
+             *
436
+             *  array(
437
+             *      'US' => array(
438
+             *          'CA' => 'California',
439
+             *          'NY' => 'New York',
440
+             *          ...
441
+             *      ),
442
+             *      ...
443
+             *  );
444
+             *
445
+             * The codes have to be upper case characters like "US" for the
446
+             * United States or "DE" for Germany. The order of the country and
447
+             * state codes determine the order of the states in the frontend and
448
+             * the state codes are later used for per state tax calculation.
449
+             *
450
+             * To display the country selection, you have to add the key for the
451
+             * state (order.base.address.state) to the "mandatory" or
452
+             * "optional" configuration option for billing and delivery addresses.
453
+             * You also need to add order.base.address.countryid as well because
454
+             * it is required to display the states that belong to this country.
455
+             *
456
+             * Until 2015-02, the configuration option was available as
457
+             * "client/html/common/address/states" starting from 2014-09.
458
+             *
459
+             * @param array Multi-dimensional list ISO country codes and state codes/names
460
+             * @since 2015.02
461
+             * @category User
462
+             * @category Developer
463
+             * @see client/html/checkout/standard/address/billing/mandatory
464
+             * @see client/html/checkout/standard/address/billing/optional
465
+             * @see client/html/checkout/standard/address/delivery/mandatory
466
+             * @see client/html/checkout/standard/address/delivery/optional
467
+             */
468
+            $view->addressStates = $view->config( 'client/html/checkout/standard/address/states', array() );
469
+
470
+
471
+            $this->cache = $view;
472
+        }
473
+
474
+        return $this->cache;
475
+    }
476 476
 }
477 477
\ No newline at end of file
Please login to merge, or discard this patch.
client/html/src/Client/Html/Checkout/Standard/Address/Delivery/Standard.php 1 patch
Indentation   +612 added lines, -612 removed lines patch added patch discarded remove patch
@@ -19,617 +19,617 @@
 block discarded – undo
19 19
  * @subpackage Html
20 20
  */
21 21
 class Standard
22
-	extends \Aimeos\Client\Html\Common\Client\Factory\Base
23
-	implements \Aimeos\Client\Html\Common\Client\Factory\Iface
22
+    extends \Aimeos\Client\Html\Common\Client\Factory\Base
23
+    implements \Aimeos\Client\Html\Common\Client\Factory\Iface
24 24
 {
25
-	/** client/html/checkout/standard/address/delivery/standard/subparts
26
-	 * List of HTML sub-clients rendered within the checkout standard address delivery section
27
-	 *
28
-	 * The output of the frontend is composed of the code generated by the HTML
29
-	 * clients. Each HTML client can consist of serveral (or none) sub-clients
30
-	 * that are responsible for rendering certain sub-parts of the output. The
31
-	 * sub-clients can contain HTML clients themselves and therefore a
32
-	 * hierarchical tree of HTML clients is composed. Each HTML client creates
33
-	 * the output that is placed inside the container of its parent.
34
-	 *
35
-	 * At first, always the HTML code generated by the parent is printed, then
36
-	 * the HTML code of its sub-clients. The order of the HTML sub-clients
37
-	 * determines the order of the output of these sub-clients inside the parent
38
-	 * container. If the configured list of clients is
39
-	 *
40
-	 *  array( "subclient1", "subclient2" )
41
-	 *
42
-	 * you can easily change the order of the output by reordering the subparts:
43
-	 *
44
-	 *  client/html/<clients>/subparts = array( "subclient1", "subclient2" )
45
-	 *
46
-	 * You can also remove one or more parts if they shouldn't be rendered:
47
-	 *
48
-	 *  client/html/<clients>/subparts = array( "subclient1" )
49
-	 *
50
-	 * As the clients only generates structural HTML, the layout defined via CSS
51
-	 * should support adding, removing or reordering content by a fluid like
52
-	 * design.
53
-	 *
54
-	 * @param array List of sub-client names
55
-	 * @since 2014.03
56
-	 * @category Developer
57
-	 */
58
-	private $subPartPath = 'client/html/checkout/standard/address/delivery/standard/subparts';
59
-	private $subPartNames = array();
60
-	private $cache;
61
-
62
-	private $mandatory = array(
63
-		'order.base.address.salutation',
64
-		'order.base.address.firstname',
65
-		'order.base.address.lastname',
66
-		'order.base.address.address1',
67
-		'order.base.address.postal',
68
-		'order.base.address.city',
69
-		'order.base.address.languageid',
70
-	);
71
-
72
-	private $optional = array(
73
-		'order.base.address.company',
74
-		'order.base.address.vatid',
75
-		'order.base.address.address2',
76
-		'order.base.address.countryid',
77
-		'order.base.address.state',
78
-	);
79
-
80
-
81
-	/**
82
-	 * Returns the HTML code for insertion into the body.
83
-	 *
84
-	 * @param string $uid Unique identifier for the output if the content is placed more than once on the same page
85
-	 * @param array &$tags Result array for the list of tags that are associated to the output
86
-	 * @param string|null &$expire Result variable for the expiration date of the output (null for no expiry)
87
-	 * @return string HTML code
88
-	 */
89
-	public function getBody( $uid = '', array &$tags = array(), &$expire = null )
90
-	{
91
-		$view = $this->setViewParams( $this->getView(), $tags, $expire );
92
-
93
-		$html = '';
94
-		foreach( $this->getSubClients() as $subclient ) {
95
-			$html .= $subclient->setView( $view )->getBody( $uid, $tags, $expire );
96
-		}
97
-		$view->deliveryBody = $html;
98
-
99
-		/** client/html/checkout/standard/address/delivery/standard/template-body
100
-		 * Relative path to the HTML body template of the checkout standard address delivery client.
101
-		 *
102
-		 * The template file contains the HTML code and processing instructions
103
-		 * to generate the result shown in the body of the frontend. The
104
-		 * configuration string is the path to the template file relative
105
-		 * to the templates directory (usually in client/html/templates).
106
-		 *
107
-		 * You can overwrite the template file configuration in extensions and
108
-		 * provide alternative templates. These alternative templates should be
109
-		 * named like the default one but with the string "standard" replaced by
110
-		 * an unique name. You may use the name of your project for this. If
111
-		 * you've implemented an alternative client class as well, "standard"
112
-		 * should be replaced by the name of the new class.
113
-		 *
114
-		 * @param string Relative path to the template creating code for the HTML page body
115
-		 * @since 2014.03
116
-		 * @category Developer
117
-		 * @see client/html/checkout/standard/address/delivery/standard/template-header
118
-		 */
119
-		$tplconf = 'client/html/checkout/standard/address/delivery/standard/template-body';
120
-		$default = 'checkout/standard/address-delivery-body-default.php';
121
-
122
-		return $view->render( $view->config( $tplconf, $default ) );
123
-	}
124
-
125
-
126
-	/**
127
-	 * Returns the HTML string for insertion into the header.
128
-	 *
129
-	 * @param string $uid Unique identifier for the output if the content is placed more than once on the same page
130
-	 * @param array &$tags Result array for the list of tags that are associated to the output
131
-	 * @param string|null &$expire Result variable for the expiration date of the output (null for no expiry)
132
-	 * @return string|null String including HTML tags for the header on error
133
-	 */
134
-	public function getHeader( $uid = '', array &$tags = array(), &$expire = null )
135
-	{
136
-		$view = $this->setViewParams( $this->getView(), $tags, $expire );
137
-
138
-		$html = '';
139
-		foreach( $this->getSubClients() as $subclient ) {
140
-			$html .= $subclient->setView( $view )->getHeader( $uid, $tags, $expire );
141
-		}
142
-		$view->deliveryHeader = $html;
143
-
144
-		/** client/html/checkout/standard/address/delivery/standard/template-header
145
-		 * Relative path to the HTML header template of the checkout standard address delivery client.
146
-		 *
147
-		 * The template file contains the HTML code and processing instructions
148
-		 * to generate the HTML code that is inserted into the HTML page header
149
-		 * of the rendered page in the frontend. The configuration string is the
150
-		 * path to the template file relative to the templates directory (usually
151
-		 * in client/html/templates).
152
-		 *
153
-		 * You can overwrite the template file configuration in extensions and
154
-		 * provide alternative templates. These alternative templates should be
155
-		 * named like the default one but with the string "standard" replaced by
156
-		 * an unique name. You may use the name of your project for this. If
157
-		 * you've implemented an alternative client class as well, "standard"
158
-		 * should be replaced by the name of the new class.
159
-		 *
160
-		 * @param string Relative path to the template creating code for the HTML page head
161
-		 * @since 2014.03
162
-		 * @category Developer
163
-		 * @see client/html/checkout/standard/address/delivery/standard/template-body
164
-		 */
165
-		$tplconf = 'client/html/checkout/standard/address/delivery/standard/template-header';
166
-		$default = 'checkout/standard/address-delivery-header-default.php';
167
-
168
-		return $view->render( $view->config( $tplconf, $default ) );
169
-	}
170
-
171
-
172
-	/**
173
-	 * Returns the sub-client given by its name.
174
-	 *
175
-	 * @param string $type Name of the client type
176
-	 * @param string|null $name Name of the sub-client (Default if null)
177
-	 * @return \Aimeos\Client\Html\Iface Sub-client object
178
-	 */
179
-	public function getSubClient( $type, $name = null )
180
-	{
181
-		/** client/html/checkout/standard/address/delivery/decorators/excludes
182
-		 * Excludes decorators added by the "common" option from the checkout standard address delivery html client
183
-		 *
184
-		 * Decorators extend the functionality of a class by adding new aspects
185
-		 * (e.g. log what is currently done), executing the methods of the underlying
186
-		 * class only in certain conditions (e.g. only for logged in users) or
187
-		 * modify what is returned to the caller.
188
-		 *
189
-		 * This option allows you to remove a decorator added via
190
-		 * "client/html/common/decorators/default" before they are wrapped
191
-		 * around the html client.
192
-		 *
193
-		 *  client/html/checkout/standard/address/delivery/decorators/excludes = array( 'decorator1' )
194
-		 *
195
-		 * This would remove the decorator named "decorator1" from the list of
196
-		 * common decorators ("\Aimeos\Client\Html\Common\Decorator\*") added via
197
-		 * "client/html/common/decorators/default" to the html client.
198
-		 *
199
-		 * @param array List of decorator names
200
-		 * @since 2015.08
201
-		 * @category Developer
202
-		 * @see client/html/common/decorators/default
203
-		 * @see client/html/checkout/standard/address/delivery/decorators/global
204
-		 * @see client/html/checkout/standard/address/delivery/decorators/local
205
-		 */
206
-
207
-		/** client/html/checkout/standard/address/delivery/decorators/global
208
-		 * Adds a list of globally available decorators only to the checkout standard address delivery html client
209
-		 *
210
-		 * Decorators extend the functionality of a class by adding new aspects
211
-		 * (e.g. log what is currently done), executing the methods of the underlying
212
-		 * class only in certain conditions (e.g. only for logged in users) or
213
-		 * modify what is returned to the caller.
214
-		 *
215
-		 * This option allows you to wrap global decorators
216
-		 * ("\Aimeos\Client\Html\Common\Decorator\*") around the html client.
217
-		 *
218
-		 *  client/html/checkout/standard/address/delivery/decorators/global = array( 'decorator1' )
219
-		 *
220
-		 * This would add the decorator named "decorator1" defined by
221
-		 * "\Aimeos\Client\Html\Common\Decorator\Decorator1" only to the html client.
222
-		 *
223
-		 * @param array List of decorator names
224
-		 * @since 2015.08
225
-		 * @category Developer
226
-		 * @see client/html/common/decorators/default
227
-		 * @see client/html/checkout/standard/address/delivery/decorators/excludes
228
-		 * @see client/html/checkout/standard/address/delivery/decorators/local
229
-		 */
230
-
231
-		/** client/html/checkout/standard/address/delivery/decorators/local
232
-		 * Adds a list of local decorators only to the checkout standard address delivery html client
233
-		 *
234
-		 * Decorators extend the functionality of a class by adding new aspects
235
-		 * (e.g. log what is currently done), executing the methods of the underlying
236
-		 * class only in certain conditions (e.g. only for logged in users) or
237
-		 * modify what is returned to the caller.
238
-		 *
239
-		 * This option allows you to wrap local decorators
240
-		 * ("\Aimeos\Client\Html\Checkout\Decorator\*") around the html client.
241
-		 *
242
-		 *  client/html/checkout/standard/address/delivery/decorators/local = array( 'decorator2' )
243
-		 *
244
-		 * This would add the decorator named "decorator2" defined by
245
-		 * "\Aimeos\Client\Html\Checkout\Decorator\Decorator2" only to the html client.
246
-		 *
247
-		 * @param array List of decorator names
248
-		 * @since 2015.08
249
-		 * @category Developer
250
-		 * @see client/html/common/decorators/default
251
-		 * @see client/html/checkout/standard/address/delivery/decorators/excludes
252
-		 * @see client/html/checkout/standard/address/delivery/decorators/global
253
-		 */
254
-
255
-		return $this->createSubClient( 'checkout/standard/address/delivery/' . $type, $name );
256
-	}
257
-
258
-
259
-	/**
260
-	 * Stores the given or fetched billing address in the basket.
261
-	 */
262
-	public function process()
263
-	{
264
-		$context = $this->getContext();
265
-		$view = $this->getView();
266
-
267
-		try
268
-		{
269
-			if( ( $id = $view->param( 'ca_delivery_delete', null ) ) !== null )
270
-			{
271
-				$customerAddressManager = \Aimeos\MShop\Factory::createManager( $context, 'customer/address' );
272
-				$address = $customerAddressManager->getItem( $id );
273
-
274
-				if( $address->getParentId() != $context->getUserId() ) {
275
-					throw new \Aimeos\Client\Html\Exception( sprintf( 'Address with ID "%1$s" not found', $id ) );
276
-				}
277
-
278
-				$customerAddressManager->deleteItem( $id );
279
-			}
280
-
281
-			// only start if there's something to do
282
-			if( $view->param( 'ca_deliveryoption', null ) === null ) {
283
-				return;
284
-			}
285
-
286
-			$basketCtrl = \Aimeos\Controller\Frontend\Factory::createController( $context, 'basket' );
287
-
288
-			/** client/html/checkout/standard/address/delivery/disable-new
289
-			 * Disables the option to enter a different delivery address for an order
290
-			 *
291
-			 * Besides the billing address, customers can usually enter a different
292
-			 * delivery address as well. To suppress displaying the form fields for
293
-			 * a delivery address, you can set this configuration option to "1".
294
-			 *
295
-			 * Until 2015-02, the configuration option was available as
296
-			 * "client/html/common/address/delivery/disable-new" starting from 2014-03.
297
-			 *
298
-			 * @param boolean A value of "1" to disable, "0" enables the delivery address form
299
-			 * @since 2015.02
300
-			 * @category User
301
-			 * @category Developer
302
-			 * @see client/html/checkout/standard/address/delivery/salutations
303
-			 * @see client/html/checkout/standard/address/delivery/mandatory
304
-			 * @see client/html/checkout/standard/address/delivery/optional
305
-			 * @see client/html/checkout/standard/address/delivery/hidden
306
-			 */
307
-			$disable = $view->config( 'client/html/checkout/standard/address/delivery/disable-new', false );
308
-			$type = \Aimeos\MShop\Order\Item\Base\Address\Base::TYPE_DELIVERY;
309
-
310
-			if( ( $option = $view->param( 'ca_deliveryoption', 'null' ) ) === 'null' && $disable === false ) // new address
311
-			{
312
-				$params = $view->param( 'ca_delivery', array() );
313
-				$invalid = $this->checkFields( $params );
314
-
315
-				if( count( $invalid ) > 0 )
316
-				{
317
-					$view->deliveryError = $invalid;
318
-					throw new \Aimeos\Client\Html\Exception( sprintf( 'At least one delivery address part is missing or invalid' ) );
319
-				}
320
-
321
-				$basketCtrl->setAddress( $type, $params );
322
-			}
323
-			else if( ( $option = $view->param( 'ca_deliveryoption', 'null' ) ) !== '-1' ) // existing address
324
-			{
325
-				$customerAddressManager = \Aimeos\MShop\Factory::createManager( $context, 'customer/address' );
326
-				$address = $customerAddressManager->getItem( $option );
327
-
328
-				if( $address->getParentId() != $context->getUserId() ) {
329
-					throw new \Aimeos\Client\Html\Exception( sprintf( 'Address with ID "%1$s" not found', $option ) );
330
-				}
331
-
332
-				$invalid = array();
333
-				$params = $view->param( 'ca_delivery_' . $option, array() );
334
-
335
-				if( !empty( $params ) )
336
-				{
337
-					$list = array();
338
-					$invalid = $this->checkFields( $params );
339
-
340
-					foreach( $params as $key => $value ) {
341
-						$list[str_replace( 'order.base', 'customer', $key )] = $value;
342
-					}
343
-
344
-					$address->fromArray( $list );
345
-					$customerAddressManager->saveItem( $address );
346
-				}
347
-
348
-				if( count( $invalid ) > 0 )
349
-				{
350
-					$view->deliveryError = $invalid;
351
-					throw new \Aimeos\Client\Html\Exception( sprintf( 'At least one delivery address part is missing or invalid' ) );
352
-				}
353
-
354
-				$basketCtrl->setAddress( $type, $address );
355
-			}
356
-			else
357
-			{
358
-				$basketCtrl->setAddress( $type, null );
359
-			}
360
-
361
-			parent::process();
362
-		}
363
-		catch( \Aimeos\Controller\Frontend\Exception $e )
364
-		{
365
-			$view->deliveryError = $e->getErrorList();
366
-			throw $e;
367
-		}
368
-	}
369
-
370
-
371
-	/**
372
-	 * Checks the address fields for missing data and sanitizes the given parameter list.
373
-	 *
374
-	 * @param array &$params Associative list of address keys (order.base.address.* or customer.address.*) and their values
375
-	 * @return array List of missing field names
376
-	 */
377
-	protected function checkFields( array &$params )
378
-	{
379
-		$view = $this->getView();
380
-
381
-		/** client/html/checkout/standard/address/delivery/mandatory
382
-		 * List of delivery address input fields that are required
383
-		 *
384
-		 * You can configure the list of delivery address fields that are
385
-		 * necessary and must be filled by the customer before he can
386
-		 * continue the checkout process. Available field keys are:
387
-		 * * order.base.address.company
388
-		 * * order.base.address.vatid
389
-		 * * order.base.address.salutation
390
-		 * * order.base.address.firstname
391
-		 * * order.base.address.lastname
392
-		 * * order.base.address.address1
393
-		 * * order.base.address.address2
394
-		 * * order.base.address.address3
395
-		 * * order.base.address.postal
396
-		 * * order.base.address.city
397
-		 * * order.base.address.state
398
-		 * * order.base.address.languageid
399
-		 * * order.base.address.countryid
400
-		 * * order.base.address.telephone
401
-		 * * order.base.address.telefax
402
-		 * * order.base.address.email
403
-		 * * order.base.address.website
404
-		 *
405
-		 * Until 2015-02, the configuration option was available as
406
-		 * "client/html/common/address/delivery/mandatory" starting from 2014-03.
407
-		 *
408
-		 * @param array List of field keys
409
-		 * @since 2015.02
410
-		 * @category User
411
-		 * @category Developer
412
-		 * @see client/html/checkout/standard/address/delivery/disable-new
413
-		 * @see client/html/checkout/standard/address/delivery/salutations
414
-		 * @see client/html/checkout/standard/address/delivery/optional
415
-		 * @see client/html/checkout/standard/address/delivery/hidden
416
-		 * @see client/html/checkout/standard/address/countries
417
-		 * @see client/html/checkout/standard/address/validate
418
-		 */
419
-		$mandatory = $view->config( 'client/html/checkout/standard/address/delivery/mandatory', $this->mandatory );
420
-
421
-		/** client/html/checkout/standard/address/delivery/optional
422
-		 * List of delivery address input fields that are optional
423
-		 *
424
-		 * You can configure the list of delivery address fields that
425
-		 * customers can fill but don't have to before they can
426
-		 * continue the checkout process. Available field keys are:
427
-		 * * order.base.address.company
428
-		 * * order.base.address.vatid
429
-		 * * order.base.address.salutation
430
-		 * * order.base.address.firstname
431
-		 * * order.base.address.lastname
432
-		 * * order.base.address.address1
433
-		 * * order.base.address.address2
434
-		 * * order.base.address.address3
435
-		 * * order.base.address.postal
436
-		 * * order.base.address.city
437
-		 * * order.base.address.state
438
-		 * * order.base.address.languageid
439
-		 * * order.base.address.countryid
440
-		 * * order.base.address.telephone
441
-		 * * order.base.address.telefax
442
-		 * * order.base.address.email
443
-		 * * order.base.address.website
444
-		 *
445
-		 * Until 2015-02, the configuration option was available as
446
-		 * "client/html/common/address/delivery/optional" starting from 2014-03.
447
-		 *
448
-		 * @param array List of field keys
449
-		 * @since 2015.02
450
-		 * @category User
451
-		 * @category Developer
452
-		 * @see client/html/checkout/standard/address/delivery/disable-new
453
-		 * @see client/html/checkout/standard/address/delivery/salutations
454
-		 * @see client/html/checkout/standard/address/delivery/mandatory
455
-		 * @see client/html/checkout/standard/address/delivery/hidden
456
-		 * @see client/html/checkout/standard/address/countries
457
-		 * @see client/html/checkout/standard/address/validate
458
-		 */
459
-		$optional = $view->config( 'client/html/checkout/standard/address/delivery/optional', $this->optional );
460
-
461
-		/** client/html/checkout/standard/address/validate
462
-		 *
463
-		 * @see client/html/checkout/standard/address/delivery/mandatory
464
-		 * @see client/html/checkout/standard/address/delivery/optional
465
-		 */
466
-
467
-		$invalid = array();
468
-		$allFields = array_flip( array_merge( $mandatory, $optional ) );
469
-
470
-		foreach( $params as $key => $value )
471
-		{
472
-			if( isset( $allFields[$key] ) )
473
-			{
474
-				$name = substr( $key, 19 );
475
-				$regex = $view->config( 'client/html/checkout/standard/address/validate/' . $name );
476
-
477
-				if( $regex && preg_match( '/' . $regex . '/', $value ) !== 1 )
478
-				{
479
-					$msg = $view->translate( 'client', 'Delivery address part "%1$s" is invalid' );
480
-					$invalid[$key] = sprintf( $msg, $name );
481
-					unset( $params[$key] );
482
-				}
483
-			}
484
-			else
485
-			{
486
-				unset( $params[$key] );
487
-			}
488
-		}
489
-
490
-
491
-		if( isset( $params['order.base.address.salutation'] )
492
-			&& $params['order.base.address.salutation'] === \Aimeos\MShop\Common\Item\Address\Base::SALUTATION_COMPANY
493
-			&& in_array( 'order.base.address.company', $mandatory ) === false
494
-		) {
495
-			$mandatory[] = 'order.base.address.company';
496
-		} else {
497
-			$params['order.base.address.company'] = $params['order.base.address.vatid'] = '';
498
-		}
499
-
500
-
501
-		foreach( $mandatory as $key )
502
-		{
503
-			if( !isset( $params[$key] ) || $params[$key] == '' )
504
-			{
505
-				$msg = $view->translate( 'client', 'Delivery address part "%1$s" is missing' );
506
-				$invalid[$key] = sprintf( $msg, substr( $key, 19 ) );
507
-				unset( $params[$key] );
508
-			}
509
-		}
510
-
511
-		return $invalid;
512
-	}
513
-
514
-
515
-	/**
516
-	 * Returns the list of sub-client names configured for the client.
517
-	 *
518
-	 * @return array List of HTML client names
519
-	 */
520
-	protected function getSubClientNames()
521
-	{
522
-		return $this->getContext()->getConfig()->get( $this->subPartPath, $this->subPartNames );
523
-	}
524
-
525
-
526
-	/**
527
-	 * Sets the necessary parameter values in the view.
528
-	 *
529
-	 * @param \Aimeos\MW\View\Iface $view The view object which generates the HTML output
530
-	 * @param array &$tags Result array for the list of tags that are associated to the output
531
-	 * @param string|null &$expire Result variable for the expiration date of the output (null for no expiry)
532
-	 * @return \Aimeos\MW\View\Iface Modified view object
533
-	 */
534
-	protected function setViewParams( \Aimeos\MW\View\Iface $view, array &$tags = array(), &$expire = null )
535
-	{
536
-		if( !isset( $this->cache ) )
537
-		{
538
-			$context = $this->getContext();
539
-			$basketCntl = \Aimeos\Controller\Frontend\Factory::createController( $context, 'basket' );
540
-
541
-			try {
542
-				$langid = $basketCntl->get()->getAddress( 'delivery' )->getLanguageId();
543
-			} catch( \Exception $e ) {
544
-				$langid = $view->param( 'ca_delivery/order.base.address.languageid', $context->getLocale()->getLanguageId() );
545
-			}
546
-			$view->deliveryLanguage = $langid;
547
-
548
-			/** client/html/checkout/standard/address/delivery/hidden
549
-			 * List of delivery address input fields that are optional
550
-			 *
551
-			 * You can configure the list of delivery address fields that
552
-			 * are hidden when a customer enters his delivery address.
553
-			 * Available field keys are:
554
-			 * * order.base.address.company
555
-			 * * order.base.address.vatid
556
-			 * * order.base.address.salutation
557
-			 * * order.base.address.firstname
558
-			 * * order.base.address.lastname
559
-			 * * order.base.address.address1
560
-			 * * order.base.address.address2
561
-			 * * order.base.address.address3
562
-			 * * order.base.address.postal
563
-			 * * order.base.address.city
564
-			 * * order.base.address.state
565
-			 * * order.base.address.languageid
566
-			 * * order.base.address.countryid
567
-			 * * order.base.address.telephone
568
-			 * * order.base.address.telefax
569
-			 * * order.base.address.email
570
-			 * * order.base.address.website
571
-			 *
572
-			 * Caution: Only hide fields that don't require any input
573
-			 *
574
-			 * Until 2015-02, the configuration option was available as
575
-			 * "client/html/common/address/delivery/hidden" starting from 2014-03.
576
-			 *
577
-			 * @param array List of field keys
578
-			 * @since 2015.02
579
-			 * @category User
580
-			 * @category Developer
581
-			 * @see client/html/checkout/standard/address/delivery/disable-new
582
-			 * @see client/html/checkout/standard/address/delivery/salutations
583
-			 * @see client/html/checkout/standard/address/delivery/mandatory
584
-			 * @see client/html/checkout/standard/address/delivery/optional
585
-			 * @see client/html/checkout/standard/address/countries
586
-			 */
587
-			$hidden = $view->config( 'client/html/checkout/standard/address/delivery/hidden', array() );
588
-
589
-			if( count( $view->get( 'addressLanguages', array() ) ) === 1 ) {
590
-				$hidden[] = 'order.base.address.languageid';
591
-			}
592
-
593
-			$salutations = array( 'company', 'mr', 'mrs' );
594
-
595
-			/** client/html/checkout/standard/address/delivery/salutations
596
-			 * List of salutions the customer can select from for the delivery address
597
-			 *
598
-			 * The following salutations are available:
599
-			 * * empty string for "unknown"
600
-			 * * company
601
-			 * * mr
602
-			 * * mrs
603
-			 * * miss
604
-			 *
605
-			 * You can modify the list of salutation codes and remove the ones
606
-			 * which shouldn't be used. Adding new salutations is a little bit
607
-			 * more difficult because you have to adapt a few areas in the source
608
-			 * code.
609
-			 *
610
-			 * Until 2015-02, the configuration option was available as
611
-			 * "client/html/common/address/delivery/salutations" starting from 2014-03.
612
-			 *
613
-			 * @param array List of available salutation codes
614
-			 * @since 2015.02
615
-			 * @category User
616
-			 * @category Developer
617
-			 * @see client/html/checkout/standard/address/delivery/disable-new
618
-			 * @see client/html/checkout/standard/address/delivery/mandatory
619
-			 * @see client/html/checkout/standard/address/delivery/optional
620
-			 * @see client/html/checkout/standard/address/delivery/hidden
621
-			 * @see client/html/checkout/standard/address/countries
622
-			 */
623
-			$view->deliverySalutations = $view->config( 'client/html/checkout/standard/address/delivery/salutations', $salutations );
624
-
625
-			$view->deliveryMandatory = $view->config( 'client/html/checkout/standard/address/delivery/mandatory', $this->mandatory );
626
-			$view->deliveryOptional = $view->config( 'client/html/checkout/standard/address/delivery/optional', $this->optional );
627
-			$view->deliveryHidden = $hidden;
628
-
629
-
630
-			$this->cache = $view;
631
-		}
632
-
633
-		return $this->cache;
634
-	}
25
+    /** client/html/checkout/standard/address/delivery/standard/subparts
26
+     * List of HTML sub-clients rendered within the checkout standard address delivery section
27
+     *
28
+     * The output of the frontend is composed of the code generated by the HTML
29
+     * clients. Each HTML client can consist of serveral (or none) sub-clients
30
+     * that are responsible for rendering certain sub-parts of the output. The
31
+     * sub-clients can contain HTML clients themselves and therefore a
32
+     * hierarchical tree of HTML clients is composed. Each HTML client creates
33
+     * the output that is placed inside the container of its parent.
34
+     *
35
+     * At first, always the HTML code generated by the parent is printed, then
36
+     * the HTML code of its sub-clients. The order of the HTML sub-clients
37
+     * determines the order of the output of these sub-clients inside the parent
38
+     * container. If the configured list of clients is
39
+     *
40
+     *  array( "subclient1", "subclient2" )
41
+     *
42
+     * you can easily change the order of the output by reordering the subparts:
43
+     *
44
+     *  client/html/<clients>/subparts = array( "subclient1", "subclient2" )
45
+     *
46
+     * You can also remove one or more parts if they shouldn't be rendered:
47
+     *
48
+     *  client/html/<clients>/subparts = array( "subclient1" )
49
+     *
50
+     * As the clients only generates structural HTML, the layout defined via CSS
51
+     * should support adding, removing or reordering content by a fluid like
52
+     * design.
53
+     *
54
+     * @param array List of sub-client names
55
+     * @since 2014.03
56
+     * @category Developer
57
+     */
58
+    private $subPartPath = 'client/html/checkout/standard/address/delivery/standard/subparts';
59
+    private $subPartNames = array();
60
+    private $cache;
61
+
62
+    private $mandatory = array(
63
+        'order.base.address.salutation',
64
+        'order.base.address.firstname',
65
+        'order.base.address.lastname',
66
+        'order.base.address.address1',
67
+        'order.base.address.postal',
68
+        'order.base.address.city',
69
+        'order.base.address.languageid',
70
+    );
71
+
72
+    private $optional = array(
73
+        'order.base.address.company',
74
+        'order.base.address.vatid',
75
+        'order.base.address.address2',
76
+        'order.base.address.countryid',
77
+        'order.base.address.state',
78
+    );
79
+
80
+
81
+    /**
82
+     * Returns the HTML code for insertion into the body.
83
+     *
84
+     * @param string $uid Unique identifier for the output if the content is placed more than once on the same page
85
+     * @param array &$tags Result array for the list of tags that are associated to the output
86
+     * @param string|null &$expire Result variable for the expiration date of the output (null for no expiry)
87
+     * @return string HTML code
88
+     */
89
+    public function getBody( $uid = '', array &$tags = array(), &$expire = null )
90
+    {
91
+        $view = $this->setViewParams( $this->getView(), $tags, $expire );
92
+
93
+        $html = '';
94
+        foreach( $this->getSubClients() as $subclient ) {
95
+            $html .= $subclient->setView( $view )->getBody( $uid, $tags, $expire );
96
+        }
97
+        $view->deliveryBody = $html;
98
+
99
+        /** client/html/checkout/standard/address/delivery/standard/template-body
100
+         * Relative path to the HTML body template of the checkout standard address delivery client.
101
+         *
102
+         * The template file contains the HTML code and processing instructions
103
+         * to generate the result shown in the body of the frontend. The
104
+         * configuration string is the path to the template file relative
105
+         * to the templates directory (usually in client/html/templates).
106
+         *
107
+         * You can overwrite the template file configuration in extensions and
108
+         * provide alternative templates. These alternative templates should be
109
+         * named like the default one but with the string "standard" replaced by
110
+         * an unique name. You may use the name of your project for this. If
111
+         * you've implemented an alternative client class as well, "standard"
112
+         * should be replaced by the name of the new class.
113
+         *
114
+         * @param string Relative path to the template creating code for the HTML page body
115
+         * @since 2014.03
116
+         * @category Developer
117
+         * @see client/html/checkout/standard/address/delivery/standard/template-header
118
+         */
119
+        $tplconf = 'client/html/checkout/standard/address/delivery/standard/template-body';
120
+        $default = 'checkout/standard/address-delivery-body-default.php';
121
+
122
+        return $view->render( $view->config( $tplconf, $default ) );
123
+    }
124
+
125
+
126
+    /**
127
+     * Returns the HTML string for insertion into the header.
128
+     *
129
+     * @param string $uid Unique identifier for the output if the content is placed more than once on the same page
130
+     * @param array &$tags Result array for the list of tags that are associated to the output
131
+     * @param string|null &$expire Result variable for the expiration date of the output (null for no expiry)
132
+     * @return string|null String including HTML tags for the header on error
133
+     */
134
+    public function getHeader( $uid = '', array &$tags = array(), &$expire = null )
135
+    {
136
+        $view = $this->setViewParams( $this->getView(), $tags, $expire );
137
+
138
+        $html = '';
139
+        foreach( $this->getSubClients() as $subclient ) {
140
+            $html .= $subclient->setView( $view )->getHeader( $uid, $tags, $expire );
141
+        }
142
+        $view->deliveryHeader = $html;
143
+
144
+        /** client/html/checkout/standard/address/delivery/standard/template-header
145
+         * Relative path to the HTML header template of the checkout standard address delivery client.
146
+         *
147
+         * The template file contains the HTML code and processing instructions
148
+         * to generate the HTML code that is inserted into the HTML page header
149
+         * of the rendered page in the frontend. The configuration string is the
150
+         * path to the template file relative to the templates directory (usually
151
+         * in client/html/templates).
152
+         *
153
+         * You can overwrite the template file configuration in extensions and
154
+         * provide alternative templates. These alternative templates should be
155
+         * named like the default one but with the string "standard" replaced by
156
+         * an unique name. You may use the name of your project for this. If
157
+         * you've implemented an alternative client class as well, "standard"
158
+         * should be replaced by the name of the new class.
159
+         *
160
+         * @param string Relative path to the template creating code for the HTML page head
161
+         * @since 2014.03
162
+         * @category Developer
163
+         * @see client/html/checkout/standard/address/delivery/standard/template-body
164
+         */
165
+        $tplconf = 'client/html/checkout/standard/address/delivery/standard/template-header';
166
+        $default = 'checkout/standard/address-delivery-header-default.php';
167
+
168
+        return $view->render( $view->config( $tplconf, $default ) );
169
+    }
170
+
171
+
172
+    /**
173
+     * Returns the sub-client given by its name.
174
+     *
175
+     * @param string $type Name of the client type
176
+     * @param string|null $name Name of the sub-client (Default if null)
177
+     * @return \Aimeos\Client\Html\Iface Sub-client object
178
+     */
179
+    public function getSubClient( $type, $name = null )
180
+    {
181
+        /** client/html/checkout/standard/address/delivery/decorators/excludes
182
+         * Excludes decorators added by the "common" option from the checkout standard address delivery html client
183
+         *
184
+         * Decorators extend the functionality of a class by adding new aspects
185
+         * (e.g. log what is currently done), executing the methods of the underlying
186
+         * class only in certain conditions (e.g. only for logged in users) or
187
+         * modify what is returned to the caller.
188
+         *
189
+         * This option allows you to remove a decorator added via
190
+         * "client/html/common/decorators/default" before they are wrapped
191
+         * around the html client.
192
+         *
193
+         *  client/html/checkout/standard/address/delivery/decorators/excludes = array( 'decorator1' )
194
+         *
195
+         * This would remove the decorator named "decorator1" from the list of
196
+         * common decorators ("\Aimeos\Client\Html\Common\Decorator\*") added via
197
+         * "client/html/common/decorators/default" to the html client.
198
+         *
199
+         * @param array List of decorator names
200
+         * @since 2015.08
201
+         * @category Developer
202
+         * @see client/html/common/decorators/default
203
+         * @see client/html/checkout/standard/address/delivery/decorators/global
204
+         * @see client/html/checkout/standard/address/delivery/decorators/local
205
+         */
206
+
207
+        /** client/html/checkout/standard/address/delivery/decorators/global
208
+         * Adds a list of globally available decorators only to the checkout standard address delivery html client
209
+         *
210
+         * Decorators extend the functionality of a class by adding new aspects
211
+         * (e.g. log what is currently done), executing the methods of the underlying
212
+         * class only in certain conditions (e.g. only for logged in users) or
213
+         * modify what is returned to the caller.
214
+         *
215
+         * This option allows you to wrap global decorators
216
+         * ("\Aimeos\Client\Html\Common\Decorator\*") around the html client.
217
+         *
218
+         *  client/html/checkout/standard/address/delivery/decorators/global = array( 'decorator1' )
219
+         *
220
+         * This would add the decorator named "decorator1" defined by
221
+         * "\Aimeos\Client\Html\Common\Decorator\Decorator1" only to the html client.
222
+         *
223
+         * @param array List of decorator names
224
+         * @since 2015.08
225
+         * @category Developer
226
+         * @see client/html/common/decorators/default
227
+         * @see client/html/checkout/standard/address/delivery/decorators/excludes
228
+         * @see client/html/checkout/standard/address/delivery/decorators/local
229
+         */
230
+
231
+        /** client/html/checkout/standard/address/delivery/decorators/local
232
+         * Adds a list of local decorators only to the checkout standard address delivery html client
233
+         *
234
+         * Decorators extend the functionality of a class by adding new aspects
235
+         * (e.g. log what is currently done), executing the methods of the underlying
236
+         * class only in certain conditions (e.g. only for logged in users) or
237
+         * modify what is returned to the caller.
238
+         *
239
+         * This option allows you to wrap local decorators
240
+         * ("\Aimeos\Client\Html\Checkout\Decorator\*") around the html client.
241
+         *
242
+         *  client/html/checkout/standard/address/delivery/decorators/local = array( 'decorator2' )
243
+         *
244
+         * This would add the decorator named "decorator2" defined by
245
+         * "\Aimeos\Client\Html\Checkout\Decorator\Decorator2" only to the html client.
246
+         *
247
+         * @param array List of decorator names
248
+         * @since 2015.08
249
+         * @category Developer
250
+         * @see client/html/common/decorators/default
251
+         * @see client/html/checkout/standard/address/delivery/decorators/excludes
252
+         * @see client/html/checkout/standard/address/delivery/decorators/global
253
+         */
254
+
255
+        return $this->createSubClient( 'checkout/standard/address/delivery/' . $type, $name );
256
+    }
257
+
258
+
259
+    /**
260
+     * Stores the given or fetched billing address in the basket.
261
+     */
262
+    public function process()
263
+    {
264
+        $context = $this->getContext();
265
+        $view = $this->getView();
266
+
267
+        try
268
+        {
269
+            if( ( $id = $view->param( 'ca_delivery_delete', null ) ) !== null )
270
+            {
271
+                $customerAddressManager = \Aimeos\MShop\Factory::createManager( $context, 'customer/address' );
272
+                $address = $customerAddressManager->getItem( $id );
273
+
274
+                if( $address->getParentId() != $context->getUserId() ) {
275
+                    throw new \Aimeos\Client\Html\Exception( sprintf( 'Address with ID "%1$s" not found', $id ) );
276
+                }
277
+
278
+                $customerAddressManager->deleteItem( $id );
279
+            }
280
+
281
+            // only start if there's something to do
282
+            if( $view->param( 'ca_deliveryoption', null ) === null ) {
283
+                return;
284
+            }
285
+
286
+            $basketCtrl = \Aimeos\Controller\Frontend\Factory::createController( $context, 'basket' );
287
+
288
+            /** client/html/checkout/standard/address/delivery/disable-new
289
+             * Disables the option to enter a different delivery address for an order
290
+             *
291
+             * Besides the billing address, customers can usually enter a different
292
+             * delivery address as well. To suppress displaying the form fields for
293
+             * a delivery address, you can set this configuration option to "1".
294
+             *
295
+             * Until 2015-02, the configuration option was available as
296
+             * "client/html/common/address/delivery/disable-new" starting from 2014-03.
297
+             *
298
+             * @param boolean A value of "1" to disable, "0" enables the delivery address form
299
+             * @since 2015.02
300
+             * @category User
301
+             * @category Developer
302
+             * @see client/html/checkout/standard/address/delivery/salutations
303
+             * @see client/html/checkout/standard/address/delivery/mandatory
304
+             * @see client/html/checkout/standard/address/delivery/optional
305
+             * @see client/html/checkout/standard/address/delivery/hidden
306
+             */
307
+            $disable = $view->config( 'client/html/checkout/standard/address/delivery/disable-new', false );
308
+            $type = \Aimeos\MShop\Order\Item\Base\Address\Base::TYPE_DELIVERY;
309
+
310
+            if( ( $option = $view->param( 'ca_deliveryoption', 'null' ) ) === 'null' && $disable === false ) // new address
311
+            {
312
+                $params = $view->param( 'ca_delivery', array() );
313
+                $invalid = $this->checkFields( $params );
314
+
315
+                if( count( $invalid ) > 0 )
316
+                {
317
+                    $view->deliveryError = $invalid;
318
+                    throw new \Aimeos\Client\Html\Exception( sprintf( 'At least one delivery address part is missing or invalid' ) );
319
+                }
320
+
321
+                $basketCtrl->setAddress( $type, $params );
322
+            }
323
+            else if( ( $option = $view->param( 'ca_deliveryoption', 'null' ) ) !== '-1' ) // existing address
324
+            {
325
+                $customerAddressManager = \Aimeos\MShop\Factory::createManager( $context, 'customer/address' );
326
+                $address = $customerAddressManager->getItem( $option );
327
+
328
+                if( $address->getParentId() != $context->getUserId() ) {
329
+                    throw new \Aimeos\Client\Html\Exception( sprintf( 'Address with ID "%1$s" not found', $option ) );
330
+                }
331
+
332
+                $invalid = array();
333
+                $params = $view->param( 'ca_delivery_' . $option, array() );
334
+
335
+                if( !empty( $params ) )
336
+                {
337
+                    $list = array();
338
+                    $invalid = $this->checkFields( $params );
339
+
340
+                    foreach( $params as $key => $value ) {
341
+                        $list[str_replace( 'order.base', 'customer', $key )] = $value;
342
+                    }
343
+
344
+                    $address->fromArray( $list );
345
+                    $customerAddressManager->saveItem( $address );
346
+                }
347
+
348
+                if( count( $invalid ) > 0 )
349
+                {
350
+                    $view->deliveryError = $invalid;
351
+                    throw new \Aimeos\Client\Html\Exception( sprintf( 'At least one delivery address part is missing or invalid' ) );
352
+                }
353
+
354
+                $basketCtrl->setAddress( $type, $address );
355
+            }
356
+            else
357
+            {
358
+                $basketCtrl->setAddress( $type, null );
359
+            }
360
+
361
+            parent::process();
362
+        }
363
+        catch( \Aimeos\Controller\Frontend\Exception $e )
364
+        {
365
+            $view->deliveryError = $e->getErrorList();
366
+            throw $e;
367
+        }
368
+    }
369
+
370
+
371
+    /**
372
+     * Checks the address fields for missing data and sanitizes the given parameter list.
373
+     *
374
+     * @param array &$params Associative list of address keys (order.base.address.* or customer.address.*) and their values
375
+     * @return array List of missing field names
376
+     */
377
+    protected function checkFields( array &$params )
378
+    {
379
+        $view = $this->getView();
380
+
381
+        /** client/html/checkout/standard/address/delivery/mandatory
382
+         * List of delivery address input fields that are required
383
+         *
384
+         * You can configure the list of delivery address fields that are
385
+         * necessary and must be filled by the customer before he can
386
+         * continue the checkout process. Available field keys are:
387
+         * * order.base.address.company
388
+         * * order.base.address.vatid
389
+         * * order.base.address.salutation
390
+         * * order.base.address.firstname
391
+         * * order.base.address.lastname
392
+         * * order.base.address.address1
393
+         * * order.base.address.address2
394
+         * * order.base.address.address3
395
+         * * order.base.address.postal
396
+         * * order.base.address.city
397
+         * * order.base.address.state
398
+         * * order.base.address.languageid
399
+         * * order.base.address.countryid
400
+         * * order.base.address.telephone
401
+         * * order.base.address.telefax
402
+         * * order.base.address.email
403
+         * * order.base.address.website
404
+         *
405
+         * Until 2015-02, the configuration option was available as
406
+         * "client/html/common/address/delivery/mandatory" starting from 2014-03.
407
+         *
408
+         * @param array List of field keys
409
+         * @since 2015.02
410
+         * @category User
411
+         * @category Developer
412
+         * @see client/html/checkout/standard/address/delivery/disable-new
413
+         * @see client/html/checkout/standard/address/delivery/salutations
414
+         * @see client/html/checkout/standard/address/delivery/optional
415
+         * @see client/html/checkout/standard/address/delivery/hidden
416
+         * @see client/html/checkout/standard/address/countries
417
+         * @see client/html/checkout/standard/address/validate
418
+         */
419
+        $mandatory = $view->config( 'client/html/checkout/standard/address/delivery/mandatory', $this->mandatory );
420
+
421
+        /** client/html/checkout/standard/address/delivery/optional
422
+         * List of delivery address input fields that are optional
423
+         *
424
+         * You can configure the list of delivery address fields that
425
+         * customers can fill but don't have to before they can
426
+         * continue the checkout process. Available field keys are:
427
+         * * order.base.address.company
428
+         * * order.base.address.vatid
429
+         * * order.base.address.salutation
430
+         * * order.base.address.firstname
431
+         * * order.base.address.lastname
432
+         * * order.base.address.address1
433
+         * * order.base.address.address2
434
+         * * order.base.address.address3
435
+         * * order.base.address.postal
436
+         * * order.base.address.city
437
+         * * order.base.address.state
438
+         * * order.base.address.languageid
439
+         * * order.base.address.countryid
440
+         * * order.base.address.telephone
441
+         * * order.base.address.telefax
442
+         * * order.base.address.email
443
+         * * order.base.address.website
444
+         *
445
+         * Until 2015-02, the configuration option was available as
446
+         * "client/html/common/address/delivery/optional" starting from 2014-03.
447
+         *
448
+         * @param array List of field keys
449
+         * @since 2015.02
450
+         * @category User
451
+         * @category Developer
452
+         * @see client/html/checkout/standard/address/delivery/disable-new
453
+         * @see client/html/checkout/standard/address/delivery/salutations
454
+         * @see client/html/checkout/standard/address/delivery/mandatory
455
+         * @see client/html/checkout/standard/address/delivery/hidden
456
+         * @see client/html/checkout/standard/address/countries
457
+         * @see client/html/checkout/standard/address/validate
458
+         */
459
+        $optional = $view->config( 'client/html/checkout/standard/address/delivery/optional', $this->optional );
460
+
461
+        /** client/html/checkout/standard/address/validate
462
+         *
463
+         * @see client/html/checkout/standard/address/delivery/mandatory
464
+         * @see client/html/checkout/standard/address/delivery/optional
465
+         */
466
+
467
+        $invalid = array();
468
+        $allFields = array_flip( array_merge( $mandatory, $optional ) );
469
+
470
+        foreach( $params as $key => $value )
471
+        {
472
+            if( isset( $allFields[$key] ) )
473
+            {
474
+                $name = substr( $key, 19 );
475
+                $regex = $view->config( 'client/html/checkout/standard/address/validate/' . $name );
476
+
477
+                if( $regex && preg_match( '/' . $regex . '/', $value ) !== 1 )
478
+                {
479
+                    $msg = $view->translate( 'client', 'Delivery address part "%1$s" is invalid' );
480
+                    $invalid[$key] = sprintf( $msg, $name );
481
+                    unset( $params[$key] );
482
+                }
483
+            }
484
+            else
485
+            {
486
+                unset( $params[$key] );
487
+            }
488
+        }
489
+
490
+
491
+        if( isset( $params['order.base.address.salutation'] )
492
+            && $params['order.base.address.salutation'] === \Aimeos\MShop\Common\Item\Address\Base::SALUTATION_COMPANY
493
+            && in_array( 'order.base.address.company', $mandatory ) === false
494
+        ) {
495
+            $mandatory[] = 'order.base.address.company';
496
+        } else {
497
+            $params['order.base.address.company'] = $params['order.base.address.vatid'] = '';
498
+        }
499
+
500
+
501
+        foreach( $mandatory as $key )
502
+        {
503
+            if( !isset( $params[$key] ) || $params[$key] == '' )
504
+            {
505
+                $msg = $view->translate( 'client', 'Delivery address part "%1$s" is missing' );
506
+                $invalid[$key] = sprintf( $msg, substr( $key, 19 ) );
507
+                unset( $params[$key] );
508
+            }
509
+        }
510
+
511
+        return $invalid;
512
+    }
513
+
514
+
515
+    /**
516
+     * Returns the list of sub-client names configured for the client.
517
+     *
518
+     * @return array List of HTML client names
519
+     */
520
+    protected function getSubClientNames()
521
+    {
522
+        return $this->getContext()->getConfig()->get( $this->subPartPath, $this->subPartNames );
523
+    }
524
+
525
+
526
+    /**
527
+     * Sets the necessary parameter values in the view.
528
+     *
529
+     * @param \Aimeos\MW\View\Iface $view The view object which generates the HTML output
530
+     * @param array &$tags Result array for the list of tags that are associated to the output
531
+     * @param string|null &$expire Result variable for the expiration date of the output (null for no expiry)
532
+     * @return \Aimeos\MW\View\Iface Modified view object
533
+     */
534
+    protected function setViewParams( \Aimeos\MW\View\Iface $view, array &$tags = array(), &$expire = null )
535
+    {
536
+        if( !isset( $this->cache ) )
537
+        {
538
+            $context = $this->getContext();
539
+            $basketCntl = \Aimeos\Controller\Frontend\Factory::createController( $context, 'basket' );
540
+
541
+            try {
542
+                $langid = $basketCntl->get()->getAddress( 'delivery' )->getLanguageId();
543
+            } catch( \Exception $e ) {
544
+                $langid = $view->param( 'ca_delivery/order.base.address.languageid', $context->getLocale()->getLanguageId() );
545
+            }
546
+            $view->deliveryLanguage = $langid;
547
+
548
+            /** client/html/checkout/standard/address/delivery/hidden
549
+             * List of delivery address input fields that are optional
550
+             *
551
+             * You can configure the list of delivery address fields that
552
+             * are hidden when a customer enters his delivery address.
553
+             * Available field keys are:
554
+             * * order.base.address.company
555
+             * * order.base.address.vatid
556
+             * * order.base.address.salutation
557
+             * * order.base.address.firstname
558
+             * * order.base.address.lastname
559
+             * * order.base.address.address1
560
+             * * order.base.address.address2
561
+             * * order.base.address.address3
562
+             * * order.base.address.postal
563
+             * * order.base.address.city
564
+             * * order.base.address.state
565
+             * * order.base.address.languageid
566
+             * * order.base.address.countryid
567
+             * * order.base.address.telephone
568
+             * * order.base.address.telefax
569
+             * * order.base.address.email
570
+             * * order.base.address.website
571
+             *
572
+             * Caution: Only hide fields that don't require any input
573
+             *
574
+             * Until 2015-02, the configuration option was available as
575
+             * "client/html/common/address/delivery/hidden" starting from 2014-03.
576
+             *
577
+             * @param array List of field keys
578
+             * @since 2015.02
579
+             * @category User
580
+             * @category Developer
581
+             * @see client/html/checkout/standard/address/delivery/disable-new
582
+             * @see client/html/checkout/standard/address/delivery/salutations
583
+             * @see client/html/checkout/standard/address/delivery/mandatory
584
+             * @see client/html/checkout/standard/address/delivery/optional
585
+             * @see client/html/checkout/standard/address/countries
586
+             */
587
+            $hidden = $view->config( 'client/html/checkout/standard/address/delivery/hidden', array() );
588
+
589
+            if( count( $view->get( 'addressLanguages', array() ) ) === 1 ) {
590
+                $hidden[] = 'order.base.address.languageid';
591
+            }
592
+
593
+            $salutations = array( 'company', 'mr', 'mrs' );
594
+
595
+            /** client/html/checkout/standard/address/delivery/salutations
596
+             * List of salutions the customer can select from for the delivery address
597
+             *
598
+             * The following salutations are available:
599
+             * * empty string for "unknown"
600
+             * * company
601
+             * * mr
602
+             * * mrs
603
+             * * miss
604
+             *
605
+             * You can modify the list of salutation codes and remove the ones
606
+             * which shouldn't be used. Adding new salutations is a little bit
607
+             * more difficult because you have to adapt a few areas in the source
608
+             * code.
609
+             *
610
+             * Until 2015-02, the configuration option was available as
611
+             * "client/html/common/address/delivery/salutations" starting from 2014-03.
612
+             *
613
+             * @param array List of available salutation codes
614
+             * @since 2015.02
615
+             * @category User
616
+             * @category Developer
617
+             * @see client/html/checkout/standard/address/delivery/disable-new
618
+             * @see client/html/checkout/standard/address/delivery/mandatory
619
+             * @see client/html/checkout/standard/address/delivery/optional
620
+             * @see client/html/checkout/standard/address/delivery/hidden
621
+             * @see client/html/checkout/standard/address/countries
622
+             */
623
+            $view->deliverySalutations = $view->config( 'client/html/checkout/standard/address/delivery/salutations', $salutations );
624
+
625
+            $view->deliveryMandatory = $view->config( 'client/html/checkout/standard/address/delivery/mandatory', $this->mandatory );
626
+            $view->deliveryOptional = $view->config( 'client/html/checkout/standard/address/delivery/optional', $this->optional );
627
+            $view->deliveryHidden = $hidden;
628
+
629
+
630
+            $this->cache = $view;
631
+        }
632
+
633
+        return $this->cache;
634
+    }
635 635
 }
636 636
\ No newline at end of file
Please login to merge, or discard this patch.
client/html/src/Client/Html/Checkout/Update/Factory.php 1 patch
Indentation   +59 added lines, -59 removed lines patch added patch discarded remove patch
@@ -19,69 +19,69 @@
 block discarded – undo
19 19
  * @subpackage Html
20 20
  */
21 21
 class Factory
22
-	extends \Aimeos\Client\Html\Common\Factory\Base
23
-	implements \Aimeos\Client\Html\Common\Factory\Iface
22
+    extends \Aimeos\Client\Html\Common\Factory\Base
23
+    implements \Aimeos\Client\Html\Common\Factory\Iface
24 24
 {
25
-	/**
26
-	 * Creates a update checkout client object.
27
-	 *
28
-	 * @param \Aimeos\MShop\Context\Item\Iface $context Shop context instance with necessary objects
29
-	 * @param array $templatePaths List of file system paths where the templates are stored
30
-	 * @param string|null $name Client name (default: "Standard")
31
-	 * @return \Aimeos\Client\Html\Iface Filter part implementing \Aimeos\Client\Html\Iface
32
-	 * @throws \Aimeos\Client\Html\Exception If requested client implementation couldn't be found or initialisation fails
33
-	 */
34
-	public static function createClient( \Aimeos\MShop\Context\Item\Iface $context, array $templatePaths, $name = null )
35
-	{
36
-		/** client/html/checkout/update/name
37
-		 * Class name of the used checkout update client implementation
38
-		 *
39
-		 * Each default HTML client can be replace by an alternative imlementation.
40
-		 * To use this implementation, you have to set the last part of the class
41
-		 * name as configuration value so the client factory knows which class it
42
-		 * has to instantiate.
43
-		 *
44
-		 * For example, if the name of the default class is
45
-		 *
46
-		 *  \Aimeos\Client\Html\Checkout\Update\Standard
47
-		 *
48
-		 * and you want to replace it with your own version named
49
-		 *
50
-		 *  \Aimeos\Client\Html\Checkout\Update\Myupdate
51
-		 *
52
-		 * then you have to set the this configuration option:
53
-		 *
54
-		 *  client/html/checkout/update/name = Myupdate
55
-		 *
56
-		 * The value is the last part of your own class name and it's case sensitive,
57
-		 * so take care that the configuration value is exactly named like the last
58
-		 * part of the class name.
59
-		 *
60
-		 * The allowed characters of the class name are A-Z, a-z and 0-9. No other
61
-		 * characters are possible! You should always start the last part of the class
62
-		 * name with an upper case character and continue only with lower case characters
63
-		 * or numbers. Avoid chamel case names like "MyUpdate"!
64
-		 *
65
-		 * @param string Last part of the class name
66
-		 * @since 2014.03
67
-		 * @category Developer
68
-		 */
69
-		if( $name === null ) {
70
-			$name = $context->getConfig()->get( 'client/html/checkout/update/name', 'Standard' );
71
-		}
25
+    /**
26
+     * Creates a update checkout client object.
27
+     *
28
+     * @param \Aimeos\MShop\Context\Item\Iface $context Shop context instance with necessary objects
29
+     * @param array $templatePaths List of file system paths where the templates are stored
30
+     * @param string|null $name Client name (default: "Standard")
31
+     * @return \Aimeos\Client\Html\Iface Filter part implementing \Aimeos\Client\Html\Iface
32
+     * @throws \Aimeos\Client\Html\Exception If requested client implementation couldn't be found or initialisation fails
33
+     */
34
+    public static function createClient( \Aimeos\MShop\Context\Item\Iface $context, array $templatePaths, $name = null )
35
+    {
36
+        /** client/html/checkout/update/name
37
+         * Class name of the used checkout update client implementation
38
+         *
39
+         * Each default HTML client can be replace by an alternative imlementation.
40
+         * To use this implementation, you have to set the last part of the class
41
+         * name as configuration value so the client factory knows which class it
42
+         * has to instantiate.
43
+         *
44
+         * For example, if the name of the default class is
45
+         *
46
+         *  \Aimeos\Client\Html\Checkout\Update\Standard
47
+         *
48
+         * and you want to replace it with your own version named
49
+         *
50
+         *  \Aimeos\Client\Html\Checkout\Update\Myupdate
51
+         *
52
+         * then you have to set the this configuration option:
53
+         *
54
+         *  client/html/checkout/update/name = Myupdate
55
+         *
56
+         * The value is the last part of your own class name and it's case sensitive,
57
+         * so take care that the configuration value is exactly named like the last
58
+         * part of the class name.
59
+         *
60
+         * The allowed characters of the class name are A-Z, a-z and 0-9. No other
61
+         * characters are possible! You should always start the last part of the class
62
+         * name with an upper case character and continue only with lower case characters
63
+         * or numbers. Avoid chamel case names like "MyUpdate"!
64
+         *
65
+         * @param string Last part of the class name
66
+         * @since 2014.03
67
+         * @category Developer
68
+         */
69
+        if( $name === null ) {
70
+            $name = $context->getConfig()->get( 'client/html/checkout/update/name', 'Standard' );
71
+        }
72 72
 
73
-		if( ctype_alnum( $name ) === false )
74
-		{
75
-			$classname = is_string( $name ) ? '\\Aimeos\\Client\\Html\\Checkout\\Update\\' . $name : '<not a string>';
76
-			throw new \Aimeos\Client\Html\Exception( sprintf( 'Invalid characters in class name "%1$s"', $classname ) );
77
-		}
73
+        if( ctype_alnum( $name ) === false )
74
+        {
75
+            $classname = is_string( $name ) ? '\\Aimeos\\Client\\Html\\Checkout\\Update\\' . $name : '<not a string>';
76
+            throw new \Aimeos\Client\Html\Exception( sprintf( 'Invalid characters in class name "%1$s"', $classname ) );
77
+        }
78 78
 
79
-		$iface = '\\Aimeos\\Client\\Html\\Iface';
80
-		$classname = '\\Aimeos\\Client\\Html\\Checkout\\Update\\' . $name;
79
+        $iface = '\\Aimeos\\Client\\Html\\Iface';
80
+        $classname = '\\Aimeos\\Client\\Html\\Checkout\\Update\\' . $name;
81 81
 
82
-		$client = self::createClientBase( $context, $classname, $iface, $templatePaths );
82
+        $client = self::createClientBase( $context, $classname, $iface, $templatePaths );
83 83
 
84
-		return self::addClientDecorators( $context, $client, $templatePaths, 'checkout/update' );
85
-	}
84
+        return self::addClientDecorators( $context, $client, $templatePaths, 'checkout/update' );
85
+    }
86 86
 }
87 87
 
Please login to merge, or discard this patch.
client/html/src/Client/Html/Checkout/Update/Standard.php 1 patch
Indentation   +401 added lines, -401 removed lines patch added patch discarded remove patch
@@ -19,406 +19,406 @@
 block discarded – undo
19 19
  * @subpackage Html
20 20
  */
21 21
 class Standard
22
-	extends \Aimeos\Client\Html\Common\Client\Factory\Base
23
-	implements \Aimeos\Client\Html\Common\Client\Factory\Iface
22
+    extends \Aimeos\Client\Html\Common\Client\Factory\Base
23
+    implements \Aimeos\Client\Html\Common\Client\Factory\Iface
24 24
 {
25
-	/** client/html/checkout/update/standard/subparts
26
-	 * List of HTML sub-clients rendered within the checkout update section
27
-	 *
28
-	 * The output of the frontend is composed of the code generated by the HTML
29
-	 * clients. Each HTML client can consist of serveral (or none) sub-clients
30
-	 * that are responsible for rendering certain sub-parts of the output. The
31
-	 * sub-clients can contain HTML clients themselves and therefore a
32
-	 * hierarchical tree of HTML clients is composed. Each HTML client creates
33
-	 * the output that is placed inside the container of its parent.
34
-	 *
35
-	 * At first, always the HTML code generated by the parent is printed, then
36
-	 * the HTML code of its sub-clients. The order of the HTML sub-clients
37
-	 * determines the order of the output of these sub-clients inside the parent
38
-	 * container. If the configured list of clients is
39
-	 *
40
-	 *  array( "subclient1", "subclient2" )
41
-	 *
42
-	 * you can easily change the order of the output by reordering the subparts:
43
-	 *
44
-	 *  client/html/<clients>/subparts = array( "subclient1", "subclient2" )
45
-	 *
46
-	 * You can also remove one or more parts if they shouldn't be rendered:
47
-	 *
48
-	 *  client/html/<clients>/subparts = array( "subclient1" )
49
-	 *
50
-	 * As the clients only generates structural HTML, the layout defined via CSS
51
-	 * should support adding, removing or reordering content by a fluid like
52
-	 * design.
53
-	 *
54
-	 * @param array List of sub-client names
55
-	 * @since 2014.03
56
-	 * @category Developer
57
-	 */
58
-	private $subPartPath = 'client/html/checkout/update/standard/subparts';
59
-	private $subPartNames = array();
60
-
61
-
62
-	/**
63
-	 * Returns the HTML code for insertion into the body.
64
-	 *
65
-	 * @param string $uid Unique identifier for the output if the content is placed more than once on the same page
66
-	 * @param array &$tags Result array for the list of tags that are associated to the output
67
-	 * @param string|null &$expire Result variable for the expiration date of the output (null for no expiry)
68
-	 * @return string HTML code
69
-	 */
70
-	public function getBody( $uid = '', array &$tags = array(), &$expire = null )
71
-	{
72
-		$context = $this->getContext();
73
-		$view = $this->getView();
74
-
75
-		try
76
-		{
77
-			$view = $this->setViewParams( $view, $tags, $expire );
78
-
79
-			$html = '';
80
-			foreach( $this->getSubClients() as $subclient ) {
81
-				$html .= $subclient->setView( $view )->getBody( $uid, $tags, $expire );
82
-			}
83
-			$view->updateBody = $html;
84
-		}
85
-		catch( \Aimeos\Client\Html\Exception $e )
86
-		{
87
-			$error = array( $this->getContext()->getI18n()->dt( 'client', $e->getMessage() ) );
88
-			$view->updateErrorList = $view->get( 'updateErrorList', array() ) + $error;
89
-		}
90
-		catch( \Aimeos\Controller\Frontend\Exception $e )
91
-		{
92
-			$error = array( $this->getContext()->getI18n()->dt( 'controller/frontend', $e->getMessage() ) );
93
-			$view->updateErrorList = $view->get( 'updateErrorList', array() ) + $error;
94
-		}
95
-		catch( \Aimeos\MShop\Exception $e )
96
-		{
97
-			$error = array( $this->getContext()->getI18n()->dt( 'mshop', $e->getMessage() ) );
98
-			$view->updateErrorList = $view->get( 'updateErrorList', array() ) + $error;
99
-		}
100
-		catch( \Exception $e )
101
-		{
102
-			$context->getLogger()->log( $e->getMessage() . PHP_EOL . $e->getTraceAsString() );
103
-
104
-			$error = array( $context->getI18n()->dt( 'client', 'A non-recoverable error occured' ) );
105
-			$view->updateErrorList = $view->get( 'updateErrorList', array() ) + $error;
106
-		}
107
-
108
-		/** client/html/checkout/update/standard/template-body
109
-		 * Relative path to the HTML body template of the checkout update client.
110
-		 *
111
-		 * The template file contains the HTML code and processing instructions
112
-		 * to generate the result shown in the body of the frontend. The
113
-		 * configuration string is the path to the template file relative
114
-		 * to the templates directory (usually in client/html/templates).
115
-		 *
116
-		 * You can overwrite the template file configuration in extensions and
117
-		 * provide alternative templates. These alternative templates should be
118
-		 * named like the default one but with the string "standard" replaced by
119
-		 * an unique name. You may use the name of your project for this. If
120
-		 * you've implemented an alternative client class as well, "standard"
121
-		 * should be replaced by the name of the new class.
122
-		 *
123
-		 * @param string Relative path to the template creating code for the HTML page body
124
-		 * @since 2014.03
125
-		 * @category Developer
126
-		 * @see client/html/checkout/update/standard/template-header
127
-		 */
128
-		$tplconf = 'client/html/checkout/update/standard/template-body';
129
-		$default = 'checkout/update/body-default.php';
130
-
131
-		return $view->render( $view->config( $tplconf, $default ) );
132
-	}
133
-
134
-
135
-	/**
136
-	 * Returns the HTML string for insertion into the header.
137
-	 *
138
-	 * @param string $uid Unique identifier for the output if the content is placed more than once on the same page
139
-	 * @param array &$tags Result array for the list of tags that are associated to the output
140
-	 * @param string|null &$expire Result variable for the expiration date of the output (null for no expiry)
141
-	 * @return string|null String including HTML tags for the header on error
142
-	 */
143
-	public function getHeader( $uid = '', array &$tags = array(), &$expire = null )
144
-	{
145
-		try
146
-		{
147
-			$view = $this->setViewParams( $this->getView(), $tags, $expire );
148
-
149
-			$html = '';
150
-			foreach( $this->getSubClients() as $subclient ) {
151
-				$html .= $subclient->setView( $view )->getHeader( $uid, $tags, $expire );
152
-			}
153
-			$view->updateHeader = $html;
154
-
155
-			/** client/html/checkout/update/standard/template-header
156
-			 * Relative path to the HTML header template of the checkout update client.
157
-			 *
158
-			 * The template file contains the HTML code and processing instructions
159
-			 * to generate the HTML code that is inserted into the HTML page header
160
-			 * of the rendered page in the frontend. The configuration string is the
161
-			 * path to the template file relative to the templates directory (usually
162
-			 * in client/html/templates).
163
-			 *
164
-			 * You can overwrite the template file configuration in extensions and
165
-			 * provide alternative templates. These alternative templates should be
166
-			 * named like the default one but with the string "standard" replaced by
167
-			 * an unique name. You may use the name of your project for this. If
168
-			 * you've implemented an alternative client class as well, "standard"
169
-			 * should be replaced by the name of the new class.
170
-			 *
171
-			 * @param string Relative path to the template creating code for the HTML page head
172
-			 * @since 2014.03
173
-			 * @category Developer
174
-			 * @see client/html/checkout/update/standard/template-body
175
-			 */
176
-			$tplconf = 'client/html/checkout/update/standard/template-header';
177
-			$default = 'checkout/update/header-default.php';
178
-
179
-			return $view->render( $view->config( $tplconf, $default ) );
180
-		}
181
-		catch( \Exception $e )
182
-		{
183
-			$this->getContext()->getLogger()->log( $e->getMessage() . PHP_EOL . $e->getTraceAsString() );
184
-		}
185
-	}
186
-
187
-
188
-	/**
189
-	 * Returns the sub-client given by its name.
190
-	 *
191
-	 * @param string $type Name of the client type
192
-	 * @param string|null $name Name of the sub-client (Default if null)
193
-	 * @return \Aimeos\Client\Html\Iface Sub-client object
194
-	 */
195
-	public function getSubClient( $type, $name = null )
196
-	{
197
-		/** client/html/checkout/update/decorators/excludes
198
-		 * Excludes decorators added by the "common" option from the checkout update html client
199
-		 *
200
-		 * Decorators extend the functionality of a class by adding new aspects
201
-		 * (e.g. log what is currently done), executing the methods of the underlying
202
-		 * class only in certain conditions (e.g. only for logged in users) or
203
-		 * modify what is returned to the caller.
204
-		 *
205
-		 * This option allows you to remove a decorator added via
206
-		 * "client/html/common/decorators/default" before they are wrapped
207
-		 * around the html client.
208
-		 *
209
-		 *  client/html/checkout/update/decorators/excludes = array( 'decorator1' )
210
-		 *
211
-		 * This would remove the decorator named "decorator1" from the list of
212
-		 * common decorators ("\Aimeos\Client\Html\Common\Decorator\*") added via
213
-		 * "client/html/common/decorators/default" to the html client.
214
-		 *
215
-		 * @param array List of decorator names
216
-		 * @since 2014.05
217
-		 * @category Developer
218
-		 * @see client/html/common/decorators/default
219
-		 * @see client/html/checkout/update/decorators/global
220
-		 * @see client/html/checkout/update/decorators/local
221
-		 */
222
-
223
-		/** client/html/checkout/update/decorators/global
224
-		 * Adds a list of globally available decorators only to the checkout update html client
225
-		 *
226
-		 * Decorators extend the functionality of a class by adding new aspects
227
-		 * (e.g. log what is currently done), executing the methods of the underlying
228
-		 * class only in certain conditions (e.g. only for logged in users) or
229
-		 * modify what is returned to the caller.
230
-		 *
231
-		 * This option allows you to wrap global decorators
232
-		 * ("\Aimeos\Client\Html\Common\Decorator\*") around the html client.
233
-		 *
234
-		 *  client/html/checkout/update/decorators/global = array( 'decorator1' )
235
-		 *
236
-		 * This would add the decorator named "decorator1" defined by
237
-		 * "\Aimeos\Client\Html\Common\Decorator\Decorator1" only to the html client.
238
-		 *
239
-		 * @param array List of decorator names
240
-		 * @since 2014.05
241
-		 * @category Developer
242
-		 * @see client/html/common/decorators/default
243
-		 * @see client/html/checkout/update/decorators/excludes
244
-		 * @see client/html/checkout/update/decorators/local
245
-		 */
246
-
247
-		/** client/html/checkout/update/decorators/local
248
-		 * Adds a list of local decorators only to the checkout update html client
249
-		 *
250
-		 * Decorators extend the functionality of a class by adding new aspects
251
-		 * (e.g. log what is currently done), executing the methods of the underlying
252
-		 * class only in certain conditions (e.g. only for logged in users) or
253
-		 * modify what is returned to the caller.
254
-		 *
255
-		 * This option allows you to wrap local decorators
256
-		 * ("\Aimeos\Client\Html\Checkout\Decorator\*") around the html client.
257
-		 *
258
-		 *  client/html/checkout/update/decorators/local = array( 'decorator2' )
259
-		 *
260
-		 * This would add the decorator named "decorator2" defined by
261
-		 * "\Aimeos\Client\Html\Checkout\Decorator\Decorator2" only to the html client.
262
-		 *
263
-		 * @param array List of decorator names
264
-		 * @since 2014.05
265
-		 * @category Developer
266
-		 * @see client/html/common/decorators/default
267
-		 * @see client/html/checkout/update/decorators/excludes
268
-		 * @see client/html/checkout/update/decorators/global
269
-		 */
270
-
271
-		return $this->createSubClient( 'checkout/update/' . $type, $name );
272
-	}
273
-
274
-
275
-	/**
276
-	 * Processes the input, e.g. store given values.
277
-	 * A view must be available and this method doesn't generate any output
278
-	 * besides setting view variables.
279
-	 */
280
-	public function process()
281
-	{
282
-		$view = $this->getView();
283
-		$context = $this->getContext();
284
-
285
-		try
286
-		{
287
-			$provider = $this->getServiceProvider( $view->param( 'code' ) );
288
-
289
-			$config = array( 'absoluteUri' => true, 'namespace' => false );
290
-			$params = array( 'code' => $view->param( 'code' ), 'orderid' => $view->param( 'orderid' ) );
291
-			$urls = array(
292
-				'payment.url-success' => $this->getUrlConfirm( $view, $params, $config ),
293
-				'payment.url-update' => $this->getUrlUpdate( $view, $params, $config ),
294
-			);
295
-			$urls['payment.url-self'] = $urls['payment.url-update'];
296
-			$provider->injectGlobalConfigBE( $urls );
297
-
298
-			$response = null;
299
-			$headers = array();
300
-
301
-			try
302
-			{
303
-				$body = $view->request()->getBody();
304
-
305
-				if( ( $orderItem = $provider->updateSync( $view->param(), $body, $response, $headers ) ) !== null ) {
306
-					\Aimeos\Controller\Frontend\Factory::createController( $context, 'order' )->update( $orderItem ); // stock, coupons
307
-				}
308
-
309
-				$view->updateMessage = $response;
310
-			}
311
-			catch( \Aimeos\MShop\Service\Exception $e )
312
-			{
313
-				$view->updateMessage = $e->getMessage();
314
-			}
315
-
316
-			if( !empty( $headers ) ) {
317
-				$view->updateHttpHeaders = $headers;
318
-			}
319
-
320
-			parent::process();
321
-		}
322
-		catch( \Exception $e )
323
-		{
324
-			/** client/html/checkout/standard/update/http-error
325
-			 * HTTP header sent for failed attempts to update the order status
326
-			 *
327
-			 * This HTTP header is returned to the remote system if the status
328
-			 * update failed due to an error in the application. This header is
329
-			 * not sent if e.g. a payment was refused by the payment gateway!
330
-			 * It should be one of the 5xx HTTP headers.
331
-			 *
332
-			 * @param array List of valid HTTP headers
333
-			 * @since 2015.07
334
-			 * @category Developer
335
-			 * @see client/html/checkout/standard/update/http-success
336
-			 */
337
-			$default = array( 'HTTP/1.1 500 Error updating order status' );
338
-			$headerList = $context->getConfig()->get( 'client/html/checkout/standard/update/http-error', $default );
339
-
340
-			$view->updateHttpHeaders = $headerList;
341
-			$view->updateMessage = $e->getMessage();
342
-
343
-			$body = $view->request()->getBody();
344
-			$params = print_r( $view->param(), true );
345
-			$msg = "Updating order status failed: %1\$s\n%2\$s\n%3\$s";
346
-			$context->getLogger()->log( sprintf( $msg, $e->getMessage(), $params, $body ) );
347
-		}
348
-	}
349
-
350
-
351
-	/**
352
-	 * Returns the service provider for the given code
353
-	 *
354
-	 * @param string $code Unique service code
355
-	 * @throws \Aimeos\Client\Html\Exception If no service item could be found
356
-	 * @return \Aimeos\MShop\Service\Provider\Iface Service provider object
357
-	 */
358
-	protected function getServiceProvider( $code )
359
-	{
360
-		$serviceManager = \Aimeos\MShop\Factory::createManager( $this->getContext(), 'service' );
361
-
362
-		$search = $serviceManager->createSearch();
363
-		$search->setConditions( $search->compare( '==', 'service.code', $code ) );
364
-
365
-		$result = $serviceManager->searchItems( $search );
366
-
367
-		if( ( $serviceItem = reset( $result ) ) === false )
368
-		{
369
-			$msg = sprintf( 'No service for code "%1$s" found', $code );
370
-			throw new \Aimeos\Client\Html\Exception( $msg );
371
-		}
372
-
373
-		return $serviceManager->getProvider( $serviceItem );
374
-	}
375
-
376
-
377
-	/**
378
-	 * Returns the list of sub-client names configured for the client.
379
-	 *
380
-	 * @return array List of HTML client names
381
-	 */
382
-	protected function getSubClientNames()
383
-	{
384
-		return $this->getContext()->getConfig()->get( $this->subPartPath, $this->subPartNames );
385
-	}
386
-
387
-
388
-	/**
389
-	 * Returns the URL to the confirm page.
390
-	 *
391
-	 * @param \Aimeos\MW\View\Iface $view View object
392
-	 * @param array $params Parameters that should be part of the URL
393
-	 * @param array $config Default URL configuration
394
-	 * @return string URL string
395
-	 */
396
-	protected function getUrlConfirm( \Aimeos\MW\View\Iface $view, array $params, array $config )
397
-	{
398
-		$target = $view->config( 'client/html/checkout/confirm/url/target' );
399
-		$cntl = $view->config( 'client/html/checkout/confirm/url/controller', 'checkout' );
400
-		$action = $view->config( 'client/html/checkout/confirm/url/action', 'confirm' );
401
-		$config = $view->config( 'client/html/checkout/confirm/url/config', $config );
402
-
403
-		return $view->url( $target, $cntl, $action, $params, array(), $config );
404
-	}
405
-
406
-
407
-	/**
408
-	 * Returns the URL to the update page.
409
-	 *
410
-	 * @param \Aimeos\MW\View\Iface $view View object
411
-	 * @param array $params Parameters that should be part of the URL
412
-	 * @param array $config Default URL configuration
413
-	 * @return string URL string
414
-	 */
415
-	protected function getUrlUpdate( \Aimeos\MW\View\Iface $view, array $params, array $config )
416
-	{
417
-		$target = $view->config( 'client/html/checkout/update/url/target' );
418
-		$cntl = $view->config( 'client/html/checkout/update/url/controller', 'checkout' );
419
-		$action = $view->config( 'client/html/checkout/update/url/action', 'update' );
420
-		$config = $view->config( 'client/html/checkout/update/url/config', $config );
421
-
422
-		return $view->url( $target, $cntl, $action, $params, array(), $config );
423
-	}
25
+    /** client/html/checkout/update/standard/subparts
26
+     * List of HTML sub-clients rendered within the checkout update section
27
+     *
28
+     * The output of the frontend is composed of the code generated by the HTML
29
+     * clients. Each HTML client can consist of serveral (or none) sub-clients
30
+     * that are responsible for rendering certain sub-parts of the output. The
31
+     * sub-clients can contain HTML clients themselves and therefore a
32
+     * hierarchical tree of HTML clients is composed. Each HTML client creates
33
+     * the output that is placed inside the container of its parent.
34
+     *
35
+     * At first, always the HTML code generated by the parent is printed, then
36
+     * the HTML code of its sub-clients. The order of the HTML sub-clients
37
+     * determines the order of the output of these sub-clients inside the parent
38
+     * container. If the configured list of clients is
39
+     *
40
+     *  array( "subclient1", "subclient2" )
41
+     *
42
+     * you can easily change the order of the output by reordering the subparts:
43
+     *
44
+     *  client/html/<clients>/subparts = array( "subclient1", "subclient2" )
45
+     *
46
+     * You can also remove one or more parts if they shouldn't be rendered:
47
+     *
48
+     *  client/html/<clients>/subparts = array( "subclient1" )
49
+     *
50
+     * As the clients only generates structural HTML, the layout defined via CSS
51
+     * should support adding, removing or reordering content by a fluid like
52
+     * design.
53
+     *
54
+     * @param array List of sub-client names
55
+     * @since 2014.03
56
+     * @category Developer
57
+     */
58
+    private $subPartPath = 'client/html/checkout/update/standard/subparts';
59
+    private $subPartNames = array();
60
+
61
+
62
+    /**
63
+     * Returns the HTML code for insertion into the body.
64
+     *
65
+     * @param string $uid Unique identifier for the output if the content is placed more than once on the same page
66
+     * @param array &$tags Result array for the list of tags that are associated to the output
67
+     * @param string|null &$expire Result variable for the expiration date of the output (null for no expiry)
68
+     * @return string HTML code
69
+     */
70
+    public function getBody( $uid = '', array &$tags = array(), &$expire = null )
71
+    {
72
+        $context = $this->getContext();
73
+        $view = $this->getView();
74
+
75
+        try
76
+        {
77
+            $view = $this->setViewParams( $view, $tags, $expire );
78
+
79
+            $html = '';
80
+            foreach( $this->getSubClients() as $subclient ) {
81
+                $html .= $subclient->setView( $view )->getBody( $uid, $tags, $expire );
82
+            }
83
+            $view->updateBody = $html;
84
+        }
85
+        catch( \Aimeos\Client\Html\Exception $e )
86
+        {
87
+            $error = array( $this->getContext()->getI18n()->dt( 'client', $e->getMessage() ) );
88
+            $view->updateErrorList = $view->get( 'updateErrorList', array() ) + $error;
89
+        }
90
+        catch( \Aimeos\Controller\Frontend\Exception $e )
91
+        {
92
+            $error = array( $this->getContext()->getI18n()->dt( 'controller/frontend', $e->getMessage() ) );
93
+            $view->updateErrorList = $view->get( 'updateErrorList', array() ) + $error;
94
+        }
95
+        catch( \Aimeos\MShop\Exception $e )
96
+        {
97
+            $error = array( $this->getContext()->getI18n()->dt( 'mshop', $e->getMessage() ) );
98
+            $view->updateErrorList = $view->get( 'updateErrorList', array() ) + $error;
99
+        }
100
+        catch( \Exception $e )
101
+        {
102
+            $context->getLogger()->log( $e->getMessage() . PHP_EOL . $e->getTraceAsString() );
103
+
104
+            $error = array( $context->getI18n()->dt( 'client', 'A non-recoverable error occured' ) );
105
+            $view->updateErrorList = $view->get( 'updateErrorList', array() ) + $error;
106
+        }
107
+
108
+        /** client/html/checkout/update/standard/template-body
109
+         * Relative path to the HTML body template of the checkout update client.
110
+         *
111
+         * The template file contains the HTML code and processing instructions
112
+         * to generate the result shown in the body of the frontend. The
113
+         * configuration string is the path to the template file relative
114
+         * to the templates directory (usually in client/html/templates).
115
+         *
116
+         * You can overwrite the template file configuration in extensions and
117
+         * provide alternative templates. These alternative templates should be
118
+         * named like the default one but with the string "standard" replaced by
119
+         * an unique name. You may use the name of your project for this. If
120
+         * you've implemented an alternative client class as well, "standard"
121
+         * should be replaced by the name of the new class.
122
+         *
123
+         * @param string Relative path to the template creating code for the HTML page body
124
+         * @since 2014.03
125
+         * @category Developer
126
+         * @see client/html/checkout/update/standard/template-header
127
+         */
128
+        $tplconf = 'client/html/checkout/update/standard/template-body';
129
+        $default = 'checkout/update/body-default.php';
130
+
131
+        return $view->render( $view->config( $tplconf, $default ) );
132
+    }
133
+
134
+
135
+    /**
136
+     * Returns the HTML string for insertion into the header.
137
+     *
138
+     * @param string $uid Unique identifier for the output if the content is placed more than once on the same page
139
+     * @param array &$tags Result array for the list of tags that are associated to the output
140
+     * @param string|null &$expire Result variable for the expiration date of the output (null for no expiry)
141
+     * @return string|null String including HTML tags for the header on error
142
+     */
143
+    public function getHeader( $uid = '', array &$tags = array(), &$expire = null )
144
+    {
145
+        try
146
+        {
147
+            $view = $this->setViewParams( $this->getView(), $tags, $expire );
148
+
149
+            $html = '';
150
+            foreach( $this->getSubClients() as $subclient ) {
151
+                $html .= $subclient->setView( $view )->getHeader( $uid, $tags, $expire );
152
+            }
153
+            $view->updateHeader = $html;
154
+
155
+            /** client/html/checkout/update/standard/template-header
156
+             * Relative path to the HTML header template of the checkout update client.
157
+             *
158
+             * The template file contains the HTML code and processing instructions
159
+             * to generate the HTML code that is inserted into the HTML page header
160
+             * of the rendered page in the frontend. The configuration string is the
161
+             * path to the template file relative to the templates directory (usually
162
+             * in client/html/templates).
163
+             *
164
+             * You can overwrite the template file configuration in extensions and
165
+             * provide alternative templates. These alternative templates should be
166
+             * named like the default one but with the string "standard" replaced by
167
+             * an unique name. You may use the name of your project for this. If
168
+             * you've implemented an alternative client class as well, "standard"
169
+             * should be replaced by the name of the new class.
170
+             *
171
+             * @param string Relative path to the template creating code for the HTML page head
172
+             * @since 2014.03
173
+             * @category Developer
174
+             * @see client/html/checkout/update/standard/template-body
175
+             */
176
+            $tplconf = 'client/html/checkout/update/standard/template-header';
177
+            $default = 'checkout/update/header-default.php';
178
+
179
+            return $view->render( $view->config( $tplconf, $default ) );
180
+        }
181
+        catch( \Exception $e )
182
+        {
183
+            $this->getContext()->getLogger()->log( $e->getMessage() . PHP_EOL . $e->getTraceAsString() );
184
+        }
185
+    }
186
+
187
+
188
+    /**
189
+     * Returns the sub-client given by its name.
190
+     *
191
+     * @param string $type Name of the client type
192
+     * @param string|null $name Name of the sub-client (Default if null)
193
+     * @return \Aimeos\Client\Html\Iface Sub-client object
194
+     */
195
+    public function getSubClient( $type, $name = null )
196
+    {
197
+        /** client/html/checkout/update/decorators/excludes
198
+         * Excludes decorators added by the "common" option from the checkout update html client
199
+         *
200
+         * Decorators extend the functionality of a class by adding new aspects
201
+         * (e.g. log what is currently done), executing the methods of the underlying
202
+         * class only in certain conditions (e.g. only for logged in users) or
203
+         * modify what is returned to the caller.
204
+         *
205
+         * This option allows you to remove a decorator added via
206
+         * "client/html/common/decorators/default" before they are wrapped
207
+         * around the html client.
208
+         *
209
+         *  client/html/checkout/update/decorators/excludes = array( 'decorator1' )
210
+         *
211
+         * This would remove the decorator named "decorator1" from the list of
212
+         * common decorators ("\Aimeos\Client\Html\Common\Decorator\*") added via
213
+         * "client/html/common/decorators/default" to the html client.
214
+         *
215
+         * @param array List of decorator names
216
+         * @since 2014.05
217
+         * @category Developer
218
+         * @see client/html/common/decorators/default
219
+         * @see client/html/checkout/update/decorators/global
220
+         * @see client/html/checkout/update/decorators/local
221
+         */
222
+
223
+        /** client/html/checkout/update/decorators/global
224
+         * Adds a list of globally available decorators only to the checkout update html client
225
+         *
226
+         * Decorators extend the functionality of a class by adding new aspects
227
+         * (e.g. log what is currently done), executing the methods of the underlying
228
+         * class only in certain conditions (e.g. only for logged in users) or
229
+         * modify what is returned to the caller.
230
+         *
231
+         * This option allows you to wrap global decorators
232
+         * ("\Aimeos\Client\Html\Common\Decorator\*") around the html client.
233
+         *
234
+         *  client/html/checkout/update/decorators/global = array( 'decorator1' )
235
+         *
236
+         * This would add the decorator named "decorator1" defined by
237
+         * "\Aimeos\Client\Html\Common\Decorator\Decorator1" only to the html client.
238
+         *
239
+         * @param array List of decorator names
240
+         * @since 2014.05
241
+         * @category Developer
242
+         * @see client/html/common/decorators/default
243
+         * @see client/html/checkout/update/decorators/excludes
244
+         * @see client/html/checkout/update/decorators/local
245
+         */
246
+
247
+        /** client/html/checkout/update/decorators/local
248
+         * Adds a list of local decorators only to the checkout update html client
249
+         *
250
+         * Decorators extend the functionality of a class by adding new aspects
251
+         * (e.g. log what is currently done), executing the methods of the underlying
252
+         * class only in certain conditions (e.g. only for logged in users) or
253
+         * modify what is returned to the caller.
254
+         *
255
+         * This option allows you to wrap local decorators
256
+         * ("\Aimeos\Client\Html\Checkout\Decorator\*") around the html client.
257
+         *
258
+         *  client/html/checkout/update/decorators/local = array( 'decorator2' )
259
+         *
260
+         * This would add the decorator named "decorator2" defined by
261
+         * "\Aimeos\Client\Html\Checkout\Decorator\Decorator2" only to the html client.
262
+         *
263
+         * @param array List of decorator names
264
+         * @since 2014.05
265
+         * @category Developer
266
+         * @see client/html/common/decorators/default
267
+         * @see client/html/checkout/update/decorators/excludes
268
+         * @see client/html/checkout/update/decorators/global
269
+         */
270
+
271
+        return $this->createSubClient( 'checkout/update/' . $type, $name );
272
+    }
273
+
274
+
275
+    /**
276
+     * Processes the input, e.g. store given values.
277
+     * A view must be available and this method doesn't generate any output
278
+     * besides setting view variables.
279
+     */
280
+    public function process()
281
+    {
282
+        $view = $this->getView();
283
+        $context = $this->getContext();
284
+
285
+        try
286
+        {
287
+            $provider = $this->getServiceProvider( $view->param( 'code' ) );
288
+
289
+            $config = array( 'absoluteUri' => true, 'namespace' => false );
290
+            $params = array( 'code' => $view->param( 'code' ), 'orderid' => $view->param( 'orderid' ) );
291
+            $urls = array(
292
+                'payment.url-success' => $this->getUrlConfirm( $view, $params, $config ),
293
+                'payment.url-update' => $this->getUrlUpdate( $view, $params, $config ),
294
+            );
295
+            $urls['payment.url-self'] = $urls['payment.url-update'];
296
+            $provider->injectGlobalConfigBE( $urls );
297
+
298
+            $response = null;
299
+            $headers = array();
300
+
301
+            try
302
+            {
303
+                $body = $view->request()->getBody();
304
+
305
+                if( ( $orderItem = $provider->updateSync( $view->param(), $body, $response, $headers ) ) !== null ) {
306
+                    \Aimeos\Controller\Frontend\Factory::createController( $context, 'order' )->update( $orderItem ); // stock, coupons
307
+                }
308
+
309
+                $view->updateMessage = $response;
310
+            }
311
+            catch( \Aimeos\MShop\Service\Exception $e )
312
+            {
313
+                $view->updateMessage = $e->getMessage();
314
+            }
315
+
316
+            if( !empty( $headers ) ) {
317
+                $view->updateHttpHeaders = $headers;
318
+            }
319
+
320
+            parent::process();
321
+        }
322
+        catch( \Exception $e )
323
+        {
324
+            /** client/html/checkout/standard/update/http-error
325
+             * HTTP header sent for failed attempts to update the order status
326
+             *
327
+             * This HTTP header is returned to the remote system if the status
328
+             * update failed due to an error in the application. This header is
329
+             * not sent if e.g. a payment was refused by the payment gateway!
330
+             * It should be one of the 5xx HTTP headers.
331
+             *
332
+             * @param array List of valid HTTP headers
333
+             * @since 2015.07
334
+             * @category Developer
335
+             * @see client/html/checkout/standard/update/http-success
336
+             */
337
+            $default = array( 'HTTP/1.1 500 Error updating order status' );
338
+            $headerList = $context->getConfig()->get( 'client/html/checkout/standard/update/http-error', $default );
339
+
340
+            $view->updateHttpHeaders = $headerList;
341
+            $view->updateMessage = $e->getMessage();
342
+
343
+            $body = $view->request()->getBody();
344
+            $params = print_r( $view->param(), true );
345
+            $msg = "Updating order status failed: %1\$s\n%2\$s\n%3\$s";
346
+            $context->getLogger()->log( sprintf( $msg, $e->getMessage(), $params, $body ) );
347
+        }
348
+    }
349
+
350
+
351
+    /**
352
+     * Returns the service provider for the given code
353
+     *
354
+     * @param string $code Unique service code
355
+     * @throws \Aimeos\Client\Html\Exception If no service item could be found
356
+     * @return \Aimeos\MShop\Service\Provider\Iface Service provider object
357
+     */
358
+    protected function getServiceProvider( $code )
359
+    {
360
+        $serviceManager = \Aimeos\MShop\Factory::createManager( $this->getContext(), 'service' );
361
+
362
+        $search = $serviceManager->createSearch();
363
+        $search->setConditions( $search->compare( '==', 'service.code', $code ) );
364
+
365
+        $result = $serviceManager->searchItems( $search );
366
+
367
+        if( ( $serviceItem = reset( $result ) ) === false )
368
+        {
369
+            $msg = sprintf( 'No service for code "%1$s" found', $code );
370
+            throw new \Aimeos\Client\Html\Exception( $msg );
371
+        }
372
+
373
+        return $serviceManager->getProvider( $serviceItem );
374
+    }
375
+
376
+
377
+    /**
378
+     * Returns the list of sub-client names configured for the client.
379
+     *
380
+     * @return array List of HTML client names
381
+     */
382
+    protected function getSubClientNames()
383
+    {
384
+        return $this->getContext()->getConfig()->get( $this->subPartPath, $this->subPartNames );
385
+    }
386
+
387
+
388
+    /**
389
+     * Returns the URL to the confirm page.
390
+     *
391
+     * @param \Aimeos\MW\View\Iface $view View object
392
+     * @param array $params Parameters that should be part of the URL
393
+     * @param array $config Default URL configuration
394
+     * @return string URL string
395
+     */
396
+    protected function getUrlConfirm( \Aimeos\MW\View\Iface $view, array $params, array $config )
397
+    {
398
+        $target = $view->config( 'client/html/checkout/confirm/url/target' );
399
+        $cntl = $view->config( 'client/html/checkout/confirm/url/controller', 'checkout' );
400
+        $action = $view->config( 'client/html/checkout/confirm/url/action', 'confirm' );
401
+        $config = $view->config( 'client/html/checkout/confirm/url/config', $config );
402
+
403
+        return $view->url( $target, $cntl, $action, $params, array(), $config );
404
+    }
405
+
406
+
407
+    /**
408
+     * Returns the URL to the update page.
409
+     *
410
+     * @param \Aimeos\MW\View\Iface $view View object
411
+     * @param array $params Parameters that should be part of the URL
412
+     * @param array $config Default URL configuration
413
+     * @return string URL string
414
+     */
415
+    protected function getUrlUpdate( \Aimeos\MW\View\Iface $view, array $params, array $config )
416
+    {
417
+        $target = $view->config( 'client/html/checkout/update/url/target' );
418
+        $cntl = $view->config( 'client/html/checkout/update/url/controller', 'checkout' );
419
+        $action = $view->config( 'client/html/checkout/update/url/action', 'update' );
420
+        $config = $view->config( 'client/html/checkout/update/url/config', $config );
421
+
422
+        return $view->url( $target, $cntl, $action, $params, array(), $config );
423
+    }
424 424
 }
Please login to merge, or discard this patch.
client/html/src/Client/Html/Account/Favorite/Factory.php 1 patch
Indentation   +59 added lines, -59 removed lines patch added patch discarded remove patch
@@ -19,69 +19,69 @@
 block discarded – undo
19 19
  * @subpackage Html
20 20
  */
21 21
 class Factory
22
-	extends \Aimeos\Client\Html\Common\Factory\Base
23
-	implements \Aimeos\Client\Html\Common\Factory\Iface
22
+    extends \Aimeos\Client\Html\Common\Factory\Base
23
+    implements \Aimeos\Client\Html\Common\Factory\Iface
24 24
 {
25
-	/**
26
-	 * Creates a account favorite client object.
27
-	 *
28
-	 * @param \Aimeos\MShop\Context\Item\Iface $context Shop context instance with necessary objects
29
-	 * @param array $templatePaths List of file system paths where the templates are stored
30
-	 * @param string|null $name Client name (default: "Standard")
31
-	 * @return \Aimeos\Client\Html\Iface Filter part implementing \Aimeos\Client\Html\Iface
32
-	 * @throws \Aimeos\Client\Html\Exception If requested client implementation couldn't be found or initialisation fails
33
-	 */
34
-	public static function createClient( \Aimeos\MShop\Context\Item\Iface $context, array $templatePaths, $name = null )
35
-	{
36
-		/** client/html/account/favorite/name
37
-		 * Class name of the used account favorite client implementation
38
-		 *
39
-		 * Each default HTML client can be replace by an alternative imlementation.
40
-		 * To use this implementation, you have to set the last part of the class
41
-		 * name as configuration value so the client factory knows which class it
42
-		 * has to instantiate.
43
-		 *
44
-		 * For example, if the name of the default class is
45
-		 *
46
-		 *  \Aimeos\Client\Html\Account\Favorite\Standard
47
-		 *
48
-		 * and you want to replace it with your own version named
49
-		 *
50
-		 *  \Aimeos\Client\Html\Account\Favorite\Myfavorite
51
-		 *
52
-		 * then you have to set the this configuration option:
53
-		 *
54
-		 *  client/html/account/favorite/name = Myfavorite
55
-		 *
56
-		 * The value is the last part of your own class name and it's case sensitive,
57
-		 * so take care that the configuration value is exactly named like the last
58
-		 * part of the class name.
59
-		 *
60
-		 * The allowed characters of the class name are A-Z, a-z and 0-9. No other
61
-		 * characters are possible! You should always start the last part of the class
62
-		 * name with an upper case character and continue only with lower case characters
63
-		 * or numbers. Avoid chamel case names like "MyFavorite"!
64
-		 *
65
-		 * @param string Last part of the class name
66
-		 * @since 2014.03
67
-		 * @category Developer
68
-		 */
69
-		if( $name === null ) {
70
-			$name = $context->getConfig()->get( 'client/html/account/favorite/name', 'Standard' );
71
-		}
25
+    /**
26
+     * Creates a account favorite client object.
27
+     *
28
+     * @param \Aimeos\MShop\Context\Item\Iface $context Shop context instance with necessary objects
29
+     * @param array $templatePaths List of file system paths where the templates are stored
30
+     * @param string|null $name Client name (default: "Standard")
31
+     * @return \Aimeos\Client\Html\Iface Filter part implementing \Aimeos\Client\Html\Iface
32
+     * @throws \Aimeos\Client\Html\Exception If requested client implementation couldn't be found or initialisation fails
33
+     */
34
+    public static function createClient( \Aimeos\MShop\Context\Item\Iface $context, array $templatePaths, $name = null )
35
+    {
36
+        /** client/html/account/favorite/name
37
+         * Class name of the used account favorite client implementation
38
+         *
39
+         * Each default HTML client can be replace by an alternative imlementation.
40
+         * To use this implementation, you have to set the last part of the class
41
+         * name as configuration value so the client factory knows which class it
42
+         * has to instantiate.
43
+         *
44
+         * For example, if the name of the default class is
45
+         *
46
+         *  \Aimeos\Client\Html\Account\Favorite\Standard
47
+         *
48
+         * and you want to replace it with your own version named
49
+         *
50
+         *  \Aimeos\Client\Html\Account\Favorite\Myfavorite
51
+         *
52
+         * then you have to set the this configuration option:
53
+         *
54
+         *  client/html/account/favorite/name = Myfavorite
55
+         *
56
+         * The value is the last part of your own class name and it's case sensitive,
57
+         * so take care that the configuration value is exactly named like the last
58
+         * part of the class name.
59
+         *
60
+         * The allowed characters of the class name are A-Z, a-z and 0-9. No other
61
+         * characters are possible! You should always start the last part of the class
62
+         * name with an upper case character and continue only with lower case characters
63
+         * or numbers. Avoid chamel case names like "MyFavorite"!
64
+         *
65
+         * @param string Last part of the class name
66
+         * @since 2014.03
67
+         * @category Developer
68
+         */
69
+        if( $name === null ) {
70
+            $name = $context->getConfig()->get( 'client/html/account/favorite/name', 'Standard' );
71
+        }
72 72
 
73
-		if( ctype_alnum( $name ) === false )
74
-		{
75
-			$classname = is_string( $name ) ? '\\Aimeos\\Client\\Html\\Account\\Favorite\\' . $name : '<not a string>';
76
-			throw new \Aimeos\Client\Html\Exception( sprintf( 'Invalid characters in class name "%1$s"', $classname ) );
77
-		}
73
+        if( ctype_alnum( $name ) === false )
74
+        {
75
+            $classname = is_string( $name ) ? '\\Aimeos\\Client\\Html\\Account\\Favorite\\' . $name : '<not a string>';
76
+            throw new \Aimeos\Client\Html\Exception( sprintf( 'Invalid characters in class name "%1$s"', $classname ) );
77
+        }
78 78
 
79
-		$iface = '\\Aimeos\\Client\\Html\\Iface';
80
-		$classname = '\\Aimeos\\Client\\Html\\Account\\Favorite\\' . $name;
79
+        $iface = '\\Aimeos\\Client\\Html\\Iface';
80
+        $classname = '\\Aimeos\\Client\\Html\\Account\\Favorite\\' . $name;
81 81
 
82
-		$client = self::createClientBase( $context, $classname, $iface, $templatePaths );
82
+        $client = self::createClientBase( $context, $classname, $iface, $templatePaths );
83 83
 
84
-		return self::addClientDecorators( $context, $client, $templatePaths, 'account/favorite' );
85
-	}
84
+        return self::addClientDecorators( $context, $client, $templatePaths, 'account/favorite' );
85
+    }
86 86
 
87 87
 }
88 88
\ No newline at end of file
Please login to merge, or discard this patch.
client/html/src/Client/Html/Account/Favorite/Standard.php 1 patch
Indentation   +460 added lines, -460 removed lines patch added patch discarded remove patch
@@ -19,465 +19,465 @@
 block discarded – undo
19 19
  * @subpackage Html
20 20
  */
21 21
 class Standard
22
-	extends \Aimeos\Client\Html\Common\Client\Factory\Base
23
-	implements \Aimeos\Client\Html\Common\Client\Factory\Iface
22
+    extends \Aimeos\Client\Html\Common\Client\Factory\Base
23
+    implements \Aimeos\Client\Html\Common\Client\Factory\Iface
24 24
 {
25
-	/** client/html/account/favorite/standard/subparts
26
-	 * List of HTML sub-clients rendered within the account favorite section
27
-	 *
28
-	 * The output of the frontend is composed of the code generated by the HTML
29
-	 * clients. Each HTML client can consist of serveral (or none) sub-clients
30
-	 * that are responsible for rendering certain sub-parts of the output. The
31
-	 * sub-clients can contain HTML clients themselves and therefore a
32
-	 * hierarchical tree of HTML clients is composed. Each HTML client creates
33
-	 * the output that is placed inside the container of its parent.
34
-	 *
35
-	 * At first, always the HTML code generated by the parent is printed, then
36
-	 * the HTML code of its sub-clients. The order of the HTML sub-clients
37
-	 * determines the order of the output of these sub-clients inside the parent
38
-	 * container. If the configured list of clients is
39
-	 *
40
-	 *  array( "subclient1", "subclient2" )
41
-	 *
42
-	 * you can easily change the order of the output by reordering the subparts:
43
-	 *
44
-	 *  client/html/<clients>/subparts = array( "subclient1", "subclient2" )
45
-	 *
46
-	 * You can also remove one or more parts if they shouldn't be rendered:
47
-	 *
48
-	 *  client/html/<clients>/subparts = array( "subclient1" )
49
-	 *
50
-	 * As the clients only generates structural HTML, the layout defined via CSS
51
-	 * should support adding, removing or reordering content by a fluid like
52
-	 * design.
53
-	 *
54
-	 * @param array List of sub-client names
55
-	 * @since 2014.03
56
-	 * @category Developer
57
-	 */
58
-	private $subPartPath = 'client/html/account/favorite/standard/subparts';
59
-	private $subPartNames = array();
60
-	private $cache;
61
-
62
-
63
-	/**
64
-	 * Returns the HTML code for insertion into the body.
65
-	 *
66
-	 * @param string $uid Unique identifier for the output if the content is placed more than once on the same page
67
-	 * @param array &$tags Result array for the list of tags that are associated to the output
68
-	 * @param string|null &$expire Result variable for the expiration date of the output (null for no expiry)
69
-	 * @return string HTML code
70
-	 */
71
-	public function getBody( $uid = '', array &$tags = array(), &$expire = null )
72
-	{
73
-		$context = $this->getContext();
74
-		$view = $this->getView();
75
-
76
-		try
77
-		{
78
-			$view = $this->setViewParams( $view, $tags, $expire );
79
-
80
-			$html = '';
81
-			foreach( $this->getSubClients() as $subclient ) {
82
-				$html .= $subclient->setView( $view )->getBody( $uid, $tags, $expire );
83
-			}
84
-			$view->favoriteBody = $html;
85
-		}
86
-		catch( \Aimeos\Client\Html\Exception $e )
87
-		{
88
-			$error = array( $this->getContext()->getI18n()->dt( 'client', $e->getMessage() ) );
89
-			$view->favoriteErrorList = $view->get( 'favoriteErrorList', array() ) + $error;
90
-		}
91
-		catch( \Aimeos\Controller\Frontend\Exception $e )
92
-		{
93
-			$error = array( $this->getContext()->getI18n()->dt( 'controller/frontend', $e->getMessage() ) );
94
-			$view->favoriteErrorList = $view->get( 'favoriteErrorList', array() ) + $error;
95
-		}
96
-		catch( \Aimeos\MShop\Exception $e )
97
-		{
98
-			$error = array( $this->getContext()->getI18n()->dt( 'mshop', $e->getMessage() ) );
99
-			$view->favoriteErrorList = $view->get( 'favoriteErrorList', array() ) + $error;
100
-		}
101
-		catch( \Exception $e )
102
-		{
103
-			$context->getLogger()->log( $e->getMessage() . PHP_EOL . $e->getTraceAsString() );
104
-
105
-			$error = array( $context->getI18n()->dt( 'client', 'A non-recoverable error occured' ) );
106
-			$view->favoriteErrorList = $view->get( 'favoriteErrorList', array() ) + $error;
107
-		}
108
-
109
-		/** client/html/account/favorite/standard/template-body
110
-		 * Relative path to the HTML body template of the account favorite client.
111
-		 *
112
-		 * The template file contains the HTML code and processing instructions
113
-		 * to generate the result shown in the body of the frontend. The
114
-		 * configuration string is the path to the template file relative
115
-		 * to the templates directory (usually in client/html/templates).
116
-		 *
117
-		 * You can overwrite the template file configuration in extensions and
118
-		 * provide alternative templates. These alternative templates should be
119
-		 * named like the default one but with the string "standard" replaced by
120
-		 * an unique name. You may use the name of your project for this. If
121
-		 * you've implemented an alternative client class as well, "standard"
122
-		 * should be replaced by the name of the new class.
123
-		 *
124
-		 * @param string Relative path to the template creating code for the HTML page body
125
-		 * @since 2014.03
126
-		 * @category Developer
127
-		 * @see client/html/account/favorite/standard/template-header
128
-		 */
129
-		$tplconf = 'client/html/account/favorite/standard/template-body';
130
-		$default = 'account/favorite/body-default.php';
131
-
132
-		return $view->render( $view->config( $tplconf, $default ) );
133
-	}
134
-
135
-
136
-	/**
137
-	 * Returns the HTML string for insertion into the header.
138
-	 *
139
-	 * @param string $uid Unique identifier for the output if the content is placed more than once on the same page
140
-	 * @param array &$tags Result array for the list of tags that are associated to the output
141
-	 * @param string|null &$expire Result variable for the expiration date of the output (null for no expiry)
142
-	 * @return string|null String including HTML tags for the header on error
143
-	 */
144
-	public function getHeader( $uid = '', array &$tags = array(), &$expire = null )
145
-	{
146
-		try
147
-		{
148
-			$view = $this->setViewParams( $this->getView(), $tags, $expire );
149
-
150
-			$html = '';
151
-			foreach( $this->getSubClients() as $subclient ) {
152
-				$html .= $subclient->setView( $view )->getHeader( $uid, $tags, $expire );
153
-			}
154
-			$view->favoriteHeader = $html;
155
-
156
-			/** client/html/account/favorite/standard/template-header
157
-			 * Relative path to the HTML header template of the account favorite client.
158
-			 *
159
-			 * The template file contains the HTML code and processing instructions
160
-			 * to generate the HTML code that is inserted into the HTML page header
161
-			 * of the rendered page in the frontend. The configuration string is the
162
-			 * path to the template file relative to the templates directory (usually
163
-			 * in client/html/templates).
164
-			 *
165
-			 * You can overwrite the template file configuration in extensions and
166
-			 * provide alternative templates. These alternative templates should be
167
-			 * named like the default one but with the string "standard" replaced by
168
-			 * an unique name. You may use the name of your project for this. If
169
-			 * you've implemented an alternative client class as well, "standard"
170
-			 * should be replaced by the name of the new class.
171
-			 *
172
-			 * @param string Relative path to the template creating code for the HTML page head
173
-			 * @since 2014.03
174
-			 * @category Developer
175
-			 * @see client/html/account/favorite/standard/template-body
176
-			 */
177
-			$tplconf = 'client/html/account/favorite/standard/template-header';
178
-			$default = 'account/favorite/header-default.php';
179
-
180
-			return $view->render( $view->config( $tplconf, $default ) );
181
-		}
182
-		catch( \Exception $e )
183
-		{
184
-			$this->getContext()->getLogger()->log( $e->getMessage() . PHP_EOL . $e->getTraceAsString() );
185
-		}
186
-	}
187
-
188
-
189
-	/**
190
-	 * Returns the sub-client given by its name.
191
-	 *
192
-	 * @param string $type Name of the client type
193
-	 * @param string|null $name Name of the sub-client (Default if null)
194
-	 * @return \Aimeos\Client\Html\Iface Sub-client object
195
-	 */
196
-	public function getSubClient( $type, $name = null )
197
-	{
198
-		/** client/html/account/favorite/decorators/excludes
199
-		 * Excludes decorators added by the "common" option from the account favorite html client
200
-		 *
201
-		 * Decorators extend the functionality of a class by adding new aspects
202
-		 * (e.g. log what is currently done), executing the methods of the underlying
203
-		 * class only in certain conditions (e.g. only for logged in users) or
204
-		 * modify what is returned to the caller.
205
-		 *
206
-		 * This option allows you to remove a decorator added via
207
-		 * "client/html/common/decorators/default" before they are wrapped
208
-		 * around the html client.
209
-		 *
210
-		 *  client/html/account/favorite/decorators/excludes = array( 'decorator1' )
211
-		 *
212
-		 * This would remove the decorator named "decorator1" from the list of
213
-		 * common decorators ("\Aimeos\Client\Html\Common\Decorator\*") added via
214
-		 * "client/html/common/decorators/default" to the html client.
215
-		 *
216
-		 * @param array List of decorator names
217
-		 * @since 2014.05
218
-		 * @category Developer
219
-		 * @see client/html/common/decorators/default
220
-		 * @see client/html/account/favorite/decorators/global
221
-		 * @see client/html/account/favorite/decorators/local
222
-		 */
223
-
224
-		/** client/html/account/favorite/decorators/global
225
-		 * Adds a list of globally available decorators only to the account favorite html client
226
-		 *
227
-		 * Decorators extend the functionality of a class by adding new aspects
228
-		 * (e.g. log what is currently done), executing the methods of the underlying
229
-		 * class only in certain conditions (e.g. only for logged in users) or
230
-		 * modify what is returned to the caller.
231
-		 *
232
-		 * This option allows you to wrap global decorators
233
-		 * ("\Aimeos\Client\Html\Common\Decorator\*") around the html client.
234
-		 *
235
-		 *  client/html/account/favorite/decorators/global = array( 'decorator1' )
236
-		 *
237
-		 * This would add the decorator named "decorator1" defined by
238
-		 * "\Aimeos\Client\Html\Common\Decorator\Decorator1" only to the html client.
239
-		 *
240
-		 * @param array List of decorator names
241
-		 * @since 2014.05
242
-		 * @category Developer
243
-		 * @see client/html/common/decorators/default
244
-		 * @see client/html/account/favorite/decorators/excludes
245
-		 * @see client/html/account/favorite/decorators/local
246
-		 */
247
-
248
-		/** client/html/account/favorite/decorators/local
249
-		 * Adds a list of local decorators only to the account favorite html client
250
-		 *
251
-		 * Decorators extend the functionality of a class by adding new aspects
252
-		 * (e.g. log what is currently done), executing the methods of the underlying
253
-		 * class only in certain conditions (e.g. only for logged in users) or
254
-		 * modify what is returned to the caller.
255
-		 *
256
-		 * This option allows you to wrap local decorators
257
-		 * ("\Aimeos\Client\Html\Account\Decorator\*") around the html client.
258
-		 *
259
-		 *  client/html/account/favorite/decorators/local = array( 'decorator2' )
260
-		 *
261
-		 * This would add the decorator named "decorator2" defined by
262
-		 * "\Aimeos\Client\Html\Account\Decorator\Decorator2" only to the html client.
263
-		 *
264
-		 * @param array List of decorator names
265
-		 * @since 2014.05
266
-		 * @category Developer
267
-		 * @see client/html/common/decorators/default
268
-		 * @see client/html/account/favorite/decorators/excludes
269
-		 * @see client/html/account/favorite/decorators/global
270
-		 */
271
-		return $this->createSubClient( 'account/favorite/' . $type, $name );
272
-	}
273
-
274
-
275
-	/**
276
-	 * Processes the input, e.g. store given values.
277
-	 * A view must be available and this method doesn't generate any output
278
-	 * besides setting view variables.
279
-	 */
280
-	public function process()
281
-	{
282
-		$view = $this->getView();
283
-		$context = $this->getContext();
284
-		$ids = $view->param( 'fav_id', array() );
285
-
286
-
287
-		if( $context->getUserId() != null && !empty( $ids ) )
288
-		{
289
-			$typeItem = $this->getTypeItem( 'customer/lists/type', 'product', 'favorite' );
290
-			$manager = \Aimeos\MShop\Factory::createManager( $context, 'customer/lists' );
291
-
292
-			$search = $manager->createSearch();
293
-			$expr = array(
294
-				$search->compare( '==', 'customer.lists.parentid', $context->getUserId() ),
295
-				$search->compare( '==', 'customer.lists.refid', $ids ),
296
-				$search->compare( '==', 'customer.lists.domain', 'product' ),
297
-				$search->compare( '==', 'customer.lists.typeid', $typeItem->getId() ),
298
-			);
299
-			$search->setConditions( $search->combine( '&&', $expr ) );
300
-
301
-			$items = array();
302
-			foreach( $manager->searchItems( $search ) as $item ) {
303
-				$items[$item->getRefId()] = $item;
304
-			}
305
-
306
-
307
-			switch( $view->param( 'fav_action' ) )
308
-			{
309
-				case 'add':
310
-
311
-					$item = $manager->createItem();
312
-					$item->setParentId( $context->getUserId() );
313
-					$item->setTypeId( $typeItem->getId() );
314
-					$item->setDomain( 'product' );
315
-					$item->setStatus( 1 );
316
-
317
-					foreach( (array) $view->param( 'fav_id', array() ) as $id )
318
-					{
319
-						if( !isset( $items[$id] ) )
320
-						{
321
-							$item->setId( null );
322
-							$item->setRefId( $id );
323
-
324
-							$manager->saveItem( $item );
325
-							$manager->moveItem( $item->getId() );
326
-						}
327
-					}
328
-
329
-					break;
330
-
331
-				case 'delete':
332
-
333
-					$listIds = array();
334
-
335
-					foreach( (array) $view->param( 'fav_id', array() ) as $id )
336
-					{
337
-						if( isset( $items[$id] ) ) {
338
-							$listIds[] = $items[$id]->getId();
339
-						}
340
-					}
341
-
342
-					$manager->deleteItems( $listIds );
343
-					break;
344
-			}
345
-		}
346
-
347
-		parent::process();
348
-	}
349
-
350
-
351
-	/**
352
-	 * Returns the list of sub-client names configured for the client.
353
-	 *
354
-	 * @return array List of HTML client names
355
-	 */
356
-	protected function getSubClientNames()
357
-	{
358
-		return $this->getContext()->getConfig()->get( $this->subPartPath, $this->subPartNames );
359
-	}
360
-
361
-
362
-	/**
363
-	 * Returns the sanitized page from the parameters for the product list.
364
-	 *
365
-	 * @param \Aimeos\MW\View\Iface $view View instance with helper for retrieving the required parameters
366
-	 * @return integer Page number starting from 1
367
-	 */
368
-	protected function getProductListPage( \Aimeos\MW\View\Iface $view )
369
-	{
370
-		$page = (int) $view->param( 'fav_page', 1 );
371
-		return ( $page < 1 ? 1 : $page );
372
-	}
373
-
374
-
375
-	/**
376
-	 * Returns the sanitized page size from the parameters for the product list.
377
-	 *
378
-	 * @param \Aimeos\MW\View\Iface $view View instance with helper for retrieving the required parameters
379
-	 * @return integer Page size
380
-	 */
381
-	protected function getProductListSize( \Aimeos\MW\View\Iface $view )
382
-	{
383
-		/** client/html/account/favorite/size
384
-		 * The number of products shown in a list page for favorite products
385
-		 *
386
-		 * Limits the number of products that is shown in the list pages to the
387
-		 * given value. If more products are available, the products are split
388
-		 * into bunches which will be shown on their own list page. The user is
389
-		 * able to move to the next page (or previous one if it's not the first)
390
-		 * to display the next (or previous) products.
391
-		 *
392
-		 * The value must be an integer number from 1 to 100. Negative values as
393
-		 * well as values above 100 are not allowed. The value can be overwritten
394
-		 * per request if the "l_size" parameter is part of the URL.
395
-		 *
396
-		 * @param integer Number of products
397
-		 * @since 2014.09
398
-		 * @category User
399
-		 * @category Developer
400
-		 * @see client/html/catalog/lists/size
401
-		 */
402
-		$defaultSize = $this->getContext()->getConfig()->get( 'client/html/account/favorite/size', 48 );
403
-
404
-		$size = (int) $view->param( 'fav-size', $defaultSize );
405
-		return ( $size < 1 || $size > 100 ? $defaultSize : $size );
406
-	}
407
-
408
-
409
-	/**
410
-	 * Sets the necessary parameter values in the view.
411
-	 *
412
-	 * @param \Aimeos\MW\View\Iface $view The view object which generates the HTML output
413
-	 * @param array &$tags Result array for the list of tags that are associated to the output
414
-	 * @param string|null &$expire Result variable for the expiration date of the output (null for no expiry)
415
-	 * @return \Aimeos\MW\View\Iface Modified view object
416
-	 */
417
-	protected function setViewParams( \Aimeos\MW\View\Iface $view, array &$tags = array(), &$expire = null )
418
-	{
419
-		if( !isset( $this->cache ) )
420
-		{
421
-			$total = 0;
422
-			$productIds = array();
423
-			$context = $this->getContext();
424
-			$typeItem = $this->getTypeItem( 'customer/lists/type', 'product', 'favorite' );
425
-
426
-			$size = $this->getProductListSize( $view );
427
-			$current = $this->getProductListPage( $view );
428
-			$last = ( $total != 0 ? ceil( $total / $size ) : 1 );
429
-
430
-
431
-			$manager = \Aimeos\MShop\Factory::createManager( $context, 'customer/lists' );
432
-
433
-			$search = $manager->createSearch();
434
-			$expr = array(
435
-				$search->compare( '==', 'customer.lists.parentid', $context->getUserId() ),
436
-				$search->compare( '==', 'customer.lists.typeid', $typeItem->getId() ),
437
-				$search->compare( '==', 'customer.lists.domain', 'product' ),
438
-			);
439
-			$search->setConditions( $search->combine( '&&', $expr ) );
440
-			$search->setSortations( array( $search->sort( '-', 'customer.lists.position' ) ) );
441
-			$search->setSlice( ( $current - 1 ) * $size, $size );
442
-
443
-			$view->favoriteListItems = $manager->searchItems( $search, array(), $total );
444
-
445
-
446
-			/** client/html/account/favorite/domains
447
-			 * A list of domain names whose items should be available in the account favorite view template
448
-			 *
449
-			 * The templates rendering product details usually add the images,
450
-			 * prices and texts associated to the product item. If you want to
451
-			 * display additional or less content, you can configure your own
452
-			 * list of domains (attribute, media, price, product, text, etc. are
453
-			 * domains) whose items are fetched from the storage. Please keep
454
-			 * in mind that the more domains you add to the configuration, the
455
-			 * more time is required for fetching the content!
456
-			 *
457
-			 * @param array List of domain names
458
-			 * @since 2014.09
459
-			 * @category Developer
460
-			 * @see client/html/catalog/domains
461
-			 */
462
-			$default = array( 'text', 'price', 'media' );
463
-			$domains = $context->getConfig()->get( 'client/html/account/favorite/domains', $default );
464
-
465
-			foreach( $view->favoriteListItems as $listItem ) {
466
-				$productIds[] = $listItem->getRefId();
467
-			}
468
-
469
-			$controller = \Aimeos\Controller\Frontend\Factory::createController( $context, 'catalog' );
470
-
471
-			$view->favoriteProductItems = $controller->getProductItems( $productIds, $domains );
472
-			$view->favoritePageFirst = 1;
473
-			$view->favoritePagePrev = ( $current > 1 ? $current - 1 : 1 );
474
-			$view->favoritePageNext = ( $current < $last ? $current + 1 : $last );
475
-			$view->favoritePageLast = $last;
476
-			$view->favoritePageCurr = $current;
477
-
478
-			$this->cache = $view;
479
-		}
480
-
481
-		return $this->cache;
482
-	}
25
+    /** client/html/account/favorite/standard/subparts
26
+     * List of HTML sub-clients rendered within the account favorite section
27
+     *
28
+     * The output of the frontend is composed of the code generated by the HTML
29
+     * clients. Each HTML client can consist of serveral (or none) sub-clients
30
+     * that are responsible for rendering certain sub-parts of the output. The
31
+     * sub-clients can contain HTML clients themselves and therefore a
32
+     * hierarchical tree of HTML clients is composed. Each HTML client creates
33
+     * the output that is placed inside the container of its parent.
34
+     *
35
+     * At first, always the HTML code generated by the parent is printed, then
36
+     * the HTML code of its sub-clients. The order of the HTML sub-clients
37
+     * determines the order of the output of these sub-clients inside the parent
38
+     * container. If the configured list of clients is
39
+     *
40
+     *  array( "subclient1", "subclient2" )
41
+     *
42
+     * you can easily change the order of the output by reordering the subparts:
43
+     *
44
+     *  client/html/<clients>/subparts = array( "subclient1", "subclient2" )
45
+     *
46
+     * You can also remove one or more parts if they shouldn't be rendered:
47
+     *
48
+     *  client/html/<clients>/subparts = array( "subclient1" )
49
+     *
50
+     * As the clients only generates structural HTML, the layout defined via CSS
51
+     * should support adding, removing or reordering content by a fluid like
52
+     * design.
53
+     *
54
+     * @param array List of sub-client names
55
+     * @since 2014.03
56
+     * @category Developer
57
+     */
58
+    private $subPartPath = 'client/html/account/favorite/standard/subparts';
59
+    private $subPartNames = array();
60
+    private $cache;
61
+
62
+
63
+    /**
64
+     * Returns the HTML code for insertion into the body.
65
+     *
66
+     * @param string $uid Unique identifier for the output if the content is placed more than once on the same page
67
+     * @param array &$tags Result array for the list of tags that are associated to the output
68
+     * @param string|null &$expire Result variable for the expiration date of the output (null for no expiry)
69
+     * @return string HTML code
70
+     */
71
+    public function getBody( $uid = '', array &$tags = array(), &$expire = null )
72
+    {
73
+        $context = $this->getContext();
74
+        $view = $this->getView();
75
+
76
+        try
77
+        {
78
+            $view = $this->setViewParams( $view, $tags, $expire );
79
+
80
+            $html = '';
81
+            foreach( $this->getSubClients() as $subclient ) {
82
+                $html .= $subclient->setView( $view )->getBody( $uid, $tags, $expire );
83
+            }
84
+            $view->favoriteBody = $html;
85
+        }
86
+        catch( \Aimeos\Client\Html\Exception $e )
87
+        {
88
+            $error = array( $this->getContext()->getI18n()->dt( 'client', $e->getMessage() ) );
89
+            $view->favoriteErrorList = $view->get( 'favoriteErrorList', array() ) + $error;
90
+        }
91
+        catch( \Aimeos\Controller\Frontend\Exception $e )
92
+        {
93
+            $error = array( $this->getContext()->getI18n()->dt( 'controller/frontend', $e->getMessage() ) );
94
+            $view->favoriteErrorList = $view->get( 'favoriteErrorList', array() ) + $error;
95
+        }
96
+        catch( \Aimeos\MShop\Exception $e )
97
+        {
98
+            $error = array( $this->getContext()->getI18n()->dt( 'mshop', $e->getMessage() ) );
99
+            $view->favoriteErrorList = $view->get( 'favoriteErrorList', array() ) + $error;
100
+        }
101
+        catch( \Exception $e )
102
+        {
103
+            $context->getLogger()->log( $e->getMessage() . PHP_EOL . $e->getTraceAsString() );
104
+
105
+            $error = array( $context->getI18n()->dt( 'client', 'A non-recoverable error occured' ) );
106
+            $view->favoriteErrorList = $view->get( 'favoriteErrorList', array() ) + $error;
107
+        }
108
+
109
+        /** client/html/account/favorite/standard/template-body
110
+         * Relative path to the HTML body template of the account favorite client.
111
+         *
112
+         * The template file contains the HTML code and processing instructions
113
+         * to generate the result shown in the body of the frontend. The
114
+         * configuration string is the path to the template file relative
115
+         * to the templates directory (usually in client/html/templates).
116
+         *
117
+         * You can overwrite the template file configuration in extensions and
118
+         * provide alternative templates. These alternative templates should be
119
+         * named like the default one but with the string "standard" replaced by
120
+         * an unique name. You may use the name of your project for this. If
121
+         * you've implemented an alternative client class as well, "standard"
122
+         * should be replaced by the name of the new class.
123
+         *
124
+         * @param string Relative path to the template creating code for the HTML page body
125
+         * @since 2014.03
126
+         * @category Developer
127
+         * @see client/html/account/favorite/standard/template-header
128
+         */
129
+        $tplconf = 'client/html/account/favorite/standard/template-body';
130
+        $default = 'account/favorite/body-default.php';
131
+
132
+        return $view->render( $view->config( $tplconf, $default ) );
133
+    }
134
+
135
+
136
+    /**
137
+     * Returns the HTML string for insertion into the header.
138
+     *
139
+     * @param string $uid Unique identifier for the output if the content is placed more than once on the same page
140
+     * @param array &$tags Result array for the list of tags that are associated to the output
141
+     * @param string|null &$expire Result variable for the expiration date of the output (null for no expiry)
142
+     * @return string|null String including HTML tags for the header on error
143
+     */
144
+    public function getHeader( $uid = '', array &$tags = array(), &$expire = null )
145
+    {
146
+        try
147
+        {
148
+            $view = $this->setViewParams( $this->getView(), $tags, $expire );
149
+
150
+            $html = '';
151
+            foreach( $this->getSubClients() as $subclient ) {
152
+                $html .= $subclient->setView( $view )->getHeader( $uid, $tags, $expire );
153
+            }
154
+            $view->favoriteHeader = $html;
155
+
156
+            /** client/html/account/favorite/standard/template-header
157
+             * Relative path to the HTML header template of the account favorite client.
158
+             *
159
+             * The template file contains the HTML code and processing instructions
160
+             * to generate the HTML code that is inserted into the HTML page header
161
+             * of the rendered page in the frontend. The configuration string is the
162
+             * path to the template file relative to the templates directory (usually
163
+             * in client/html/templates).
164
+             *
165
+             * You can overwrite the template file configuration in extensions and
166
+             * provide alternative templates. These alternative templates should be
167
+             * named like the default one but with the string "standard" replaced by
168
+             * an unique name. You may use the name of your project for this. If
169
+             * you've implemented an alternative client class as well, "standard"
170
+             * should be replaced by the name of the new class.
171
+             *
172
+             * @param string Relative path to the template creating code for the HTML page head
173
+             * @since 2014.03
174
+             * @category Developer
175
+             * @see client/html/account/favorite/standard/template-body
176
+             */
177
+            $tplconf = 'client/html/account/favorite/standard/template-header';
178
+            $default = 'account/favorite/header-default.php';
179
+
180
+            return $view->render( $view->config( $tplconf, $default ) );
181
+        }
182
+        catch( \Exception $e )
183
+        {
184
+            $this->getContext()->getLogger()->log( $e->getMessage() . PHP_EOL . $e->getTraceAsString() );
185
+        }
186
+    }
187
+
188
+
189
+    /**
190
+     * Returns the sub-client given by its name.
191
+     *
192
+     * @param string $type Name of the client type
193
+     * @param string|null $name Name of the sub-client (Default if null)
194
+     * @return \Aimeos\Client\Html\Iface Sub-client object
195
+     */
196
+    public function getSubClient( $type, $name = null )
197
+    {
198
+        /** client/html/account/favorite/decorators/excludes
199
+         * Excludes decorators added by the "common" option from the account favorite html client
200
+         *
201
+         * Decorators extend the functionality of a class by adding new aspects
202
+         * (e.g. log what is currently done), executing the methods of the underlying
203
+         * class only in certain conditions (e.g. only for logged in users) or
204
+         * modify what is returned to the caller.
205
+         *
206
+         * This option allows you to remove a decorator added via
207
+         * "client/html/common/decorators/default" before they are wrapped
208
+         * around the html client.
209
+         *
210
+         *  client/html/account/favorite/decorators/excludes = array( 'decorator1' )
211
+         *
212
+         * This would remove the decorator named "decorator1" from the list of
213
+         * common decorators ("\Aimeos\Client\Html\Common\Decorator\*") added via
214
+         * "client/html/common/decorators/default" to the html client.
215
+         *
216
+         * @param array List of decorator names
217
+         * @since 2014.05
218
+         * @category Developer
219
+         * @see client/html/common/decorators/default
220
+         * @see client/html/account/favorite/decorators/global
221
+         * @see client/html/account/favorite/decorators/local
222
+         */
223
+
224
+        /** client/html/account/favorite/decorators/global
225
+         * Adds a list of globally available decorators only to the account favorite html client
226
+         *
227
+         * Decorators extend the functionality of a class by adding new aspects
228
+         * (e.g. log what is currently done), executing the methods of the underlying
229
+         * class only in certain conditions (e.g. only for logged in users) or
230
+         * modify what is returned to the caller.
231
+         *
232
+         * This option allows you to wrap global decorators
233
+         * ("\Aimeos\Client\Html\Common\Decorator\*") around the html client.
234
+         *
235
+         *  client/html/account/favorite/decorators/global = array( 'decorator1' )
236
+         *
237
+         * This would add the decorator named "decorator1" defined by
238
+         * "\Aimeos\Client\Html\Common\Decorator\Decorator1" only to the html client.
239
+         *
240
+         * @param array List of decorator names
241
+         * @since 2014.05
242
+         * @category Developer
243
+         * @see client/html/common/decorators/default
244
+         * @see client/html/account/favorite/decorators/excludes
245
+         * @see client/html/account/favorite/decorators/local
246
+         */
247
+
248
+        /** client/html/account/favorite/decorators/local
249
+         * Adds a list of local decorators only to the account favorite html client
250
+         *
251
+         * Decorators extend the functionality of a class by adding new aspects
252
+         * (e.g. log what is currently done), executing the methods of the underlying
253
+         * class only in certain conditions (e.g. only for logged in users) or
254
+         * modify what is returned to the caller.
255
+         *
256
+         * This option allows you to wrap local decorators
257
+         * ("\Aimeos\Client\Html\Account\Decorator\*") around the html client.
258
+         *
259
+         *  client/html/account/favorite/decorators/local = array( 'decorator2' )
260
+         *
261
+         * This would add the decorator named "decorator2" defined by
262
+         * "\Aimeos\Client\Html\Account\Decorator\Decorator2" only to the html client.
263
+         *
264
+         * @param array List of decorator names
265
+         * @since 2014.05
266
+         * @category Developer
267
+         * @see client/html/common/decorators/default
268
+         * @see client/html/account/favorite/decorators/excludes
269
+         * @see client/html/account/favorite/decorators/global
270
+         */
271
+        return $this->createSubClient( 'account/favorite/' . $type, $name );
272
+    }
273
+
274
+
275
+    /**
276
+     * Processes the input, e.g. store given values.
277
+     * A view must be available and this method doesn't generate any output
278
+     * besides setting view variables.
279
+     */
280
+    public function process()
281
+    {
282
+        $view = $this->getView();
283
+        $context = $this->getContext();
284
+        $ids = $view->param( 'fav_id', array() );
285
+
286
+
287
+        if( $context->getUserId() != null && !empty( $ids ) )
288
+        {
289
+            $typeItem = $this->getTypeItem( 'customer/lists/type', 'product', 'favorite' );
290
+            $manager = \Aimeos\MShop\Factory::createManager( $context, 'customer/lists' );
291
+
292
+            $search = $manager->createSearch();
293
+            $expr = array(
294
+                $search->compare( '==', 'customer.lists.parentid', $context->getUserId() ),
295
+                $search->compare( '==', 'customer.lists.refid', $ids ),
296
+                $search->compare( '==', 'customer.lists.domain', 'product' ),
297
+                $search->compare( '==', 'customer.lists.typeid', $typeItem->getId() ),
298
+            );
299
+            $search->setConditions( $search->combine( '&&', $expr ) );
300
+
301
+            $items = array();
302
+            foreach( $manager->searchItems( $search ) as $item ) {
303
+                $items[$item->getRefId()] = $item;
304
+            }
305
+
306
+
307
+            switch( $view->param( 'fav_action' ) )
308
+            {
309
+                case 'add':
310
+
311
+                    $item = $manager->createItem();
312
+                    $item->setParentId( $context->getUserId() );
313
+                    $item->setTypeId( $typeItem->getId() );
314
+                    $item->setDomain( 'product' );
315
+                    $item->setStatus( 1 );
316
+
317
+                    foreach( (array) $view->param( 'fav_id', array() ) as $id )
318
+                    {
319
+                        if( !isset( $items[$id] ) )
320
+                        {
321
+                            $item->setId( null );
322
+                            $item->setRefId( $id );
323
+
324
+                            $manager->saveItem( $item );
325
+                            $manager->moveItem( $item->getId() );
326
+                        }
327
+                    }
328
+
329
+                    break;
330
+
331
+                case 'delete':
332
+
333
+                    $listIds = array();
334
+
335
+                    foreach( (array) $view->param( 'fav_id', array() ) as $id )
336
+                    {
337
+                        if( isset( $items[$id] ) ) {
338
+                            $listIds[] = $items[$id]->getId();
339
+                        }
340
+                    }
341
+
342
+                    $manager->deleteItems( $listIds );
343
+                    break;
344
+            }
345
+        }
346
+
347
+        parent::process();
348
+    }
349
+
350
+
351
+    /**
352
+     * Returns the list of sub-client names configured for the client.
353
+     *
354
+     * @return array List of HTML client names
355
+     */
356
+    protected function getSubClientNames()
357
+    {
358
+        return $this->getContext()->getConfig()->get( $this->subPartPath, $this->subPartNames );
359
+    }
360
+
361
+
362
+    /**
363
+     * Returns the sanitized page from the parameters for the product list.
364
+     *
365
+     * @param \Aimeos\MW\View\Iface $view View instance with helper for retrieving the required parameters
366
+     * @return integer Page number starting from 1
367
+     */
368
+    protected function getProductListPage( \Aimeos\MW\View\Iface $view )
369
+    {
370
+        $page = (int) $view->param( 'fav_page', 1 );
371
+        return ( $page < 1 ? 1 : $page );
372
+    }
373
+
374
+
375
+    /**
376
+     * Returns the sanitized page size from the parameters for the product list.
377
+     *
378
+     * @param \Aimeos\MW\View\Iface $view View instance with helper for retrieving the required parameters
379
+     * @return integer Page size
380
+     */
381
+    protected function getProductListSize( \Aimeos\MW\View\Iface $view )
382
+    {
383
+        /** client/html/account/favorite/size
384
+         * The number of products shown in a list page for favorite products
385
+         *
386
+         * Limits the number of products that is shown in the list pages to the
387
+         * given value. If more products are available, the products are split
388
+         * into bunches which will be shown on their own list page. The user is
389
+         * able to move to the next page (or previous one if it's not the first)
390
+         * to display the next (or previous) products.
391
+         *
392
+         * The value must be an integer number from 1 to 100. Negative values as
393
+         * well as values above 100 are not allowed. The value can be overwritten
394
+         * per request if the "l_size" parameter is part of the URL.
395
+         *
396
+         * @param integer Number of products
397
+         * @since 2014.09
398
+         * @category User
399
+         * @category Developer
400
+         * @see client/html/catalog/lists/size
401
+         */
402
+        $defaultSize = $this->getContext()->getConfig()->get( 'client/html/account/favorite/size', 48 );
403
+
404
+        $size = (int) $view->param( 'fav-size', $defaultSize );
405
+        return ( $size < 1 || $size > 100 ? $defaultSize : $size );
406
+    }
407
+
408
+
409
+    /**
410
+     * Sets the necessary parameter values in the view.
411
+     *
412
+     * @param \Aimeos\MW\View\Iface $view The view object which generates the HTML output
413
+     * @param array &$tags Result array for the list of tags that are associated to the output
414
+     * @param string|null &$expire Result variable for the expiration date of the output (null for no expiry)
415
+     * @return \Aimeos\MW\View\Iface Modified view object
416
+     */
417
+    protected function setViewParams( \Aimeos\MW\View\Iface $view, array &$tags = array(), &$expire = null )
418
+    {
419
+        if( !isset( $this->cache ) )
420
+        {
421
+            $total = 0;
422
+            $productIds = array();
423
+            $context = $this->getContext();
424
+            $typeItem = $this->getTypeItem( 'customer/lists/type', 'product', 'favorite' );
425
+
426
+            $size = $this->getProductListSize( $view );
427
+            $current = $this->getProductListPage( $view );
428
+            $last = ( $total != 0 ? ceil( $total / $size ) : 1 );
429
+
430
+
431
+            $manager = \Aimeos\MShop\Factory::createManager( $context, 'customer/lists' );
432
+
433
+            $search = $manager->createSearch();
434
+            $expr = array(
435
+                $search->compare( '==', 'customer.lists.parentid', $context->getUserId() ),
436
+                $search->compare( '==', 'customer.lists.typeid', $typeItem->getId() ),
437
+                $search->compare( '==', 'customer.lists.domain', 'product' ),
438
+            );
439
+            $search->setConditions( $search->combine( '&&', $expr ) );
440
+            $search->setSortations( array( $search->sort( '-', 'customer.lists.position' ) ) );
441
+            $search->setSlice( ( $current - 1 ) * $size, $size );
442
+
443
+            $view->favoriteListItems = $manager->searchItems( $search, array(), $total );
444
+
445
+
446
+            /** client/html/account/favorite/domains
447
+             * A list of domain names whose items should be available in the account favorite view template
448
+             *
449
+             * The templates rendering product details usually add the images,
450
+             * prices and texts associated to the product item. If you want to
451
+             * display additional or less content, you can configure your own
452
+             * list of domains (attribute, media, price, product, text, etc. are
453
+             * domains) whose items are fetched from the storage. Please keep
454
+             * in mind that the more domains you add to the configuration, the
455
+             * more time is required for fetching the content!
456
+             *
457
+             * @param array List of domain names
458
+             * @since 2014.09
459
+             * @category Developer
460
+             * @see client/html/catalog/domains
461
+             */
462
+            $default = array( 'text', 'price', 'media' );
463
+            $domains = $context->getConfig()->get( 'client/html/account/favorite/domains', $default );
464
+
465
+            foreach( $view->favoriteListItems as $listItem ) {
466
+                $productIds[] = $listItem->getRefId();
467
+            }
468
+
469
+            $controller = \Aimeos\Controller\Frontend\Factory::createController( $context, 'catalog' );
470
+
471
+            $view->favoriteProductItems = $controller->getProductItems( $productIds, $domains );
472
+            $view->favoritePageFirst = 1;
473
+            $view->favoritePagePrev = ( $current > 1 ? $current - 1 : 1 );
474
+            $view->favoritePageNext = ( $current < $last ? $current + 1 : $last );
475
+            $view->favoritePageLast = $last;
476
+            $view->favoritePageCurr = $current;
477
+
478
+            $this->cache = $view;
479
+        }
480
+
481
+        return $this->cache;
482
+    }
483 483
 }
484 484
\ No newline at end of file
Please login to merge, or discard this patch.