Completed
Branch master (c3c77b)
by Aimeos
03:13
created

Standard::createContainer()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 80
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 9
nc 2
nop 0
dl 0
loc 80
rs 9.9666
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * @license LGPLv3, http://opensource.org/licenses/LGPL-3.0
5
 * @copyright Aimeos (aimeos.org), 2015-2018
6
 * @package Controller
7
 * @subpackage Jobs
8
 */
9
10
11
namespace Aimeos\Controller\Jobs\Product\Export;
12
13
14
/**
15
 * Job controller for product exports.
16
 *
17
 * @package Controller
18
 * @subpackage Jobs
19
 */
20
class Standard
21
	extends \Aimeos\Controller\Jobs\Base
22
	implements \Aimeos\Controller\Jobs\Iface
23
{
24
	/**
25
	 * Returns the localized name of the job.
26
	 *
27
	 * @return string Name of the job
28
	 */
29
	public function getName()
30
	{
31
		return $this->getContext()->getI18n()->dt( 'controller/jobs', 'Product export' );
32
	}
33
34
35
	/**
36
	 * Returns the localized description of the job.
37
	 *
38
	 * @return string Description of the job
39
	 */
40
	public function getDescription()
41
	{
42
		return $this->getContext()->getI18n()->dt( 'controller/jobs', 'Exports all available products' );
43
	}
44
45
46
	/**
47
	 * Executes the job.
48
	 *
49
	 * @throws \Aimeos\Controller\Jobs\Exception If an error occurs
50
	 */
51
	public function run()
52
	{
53
		$container = $this->createContainer();
54
		$this->export( $container, false );
55
		$container->close();
56
	}
57
58
59
	/**
60
	 * Adds the given products to the content object for the site map file
61
	 *
62
	 * @param \Aimeos\MW\Container\Content\Iface $content File content object
63
	 * @param \Aimeos\MShop\Product\Item\Iface[] $items List of product items
64
	 */
65
	protected function addItems( \Aimeos\MW\Container\Content\Iface $content, array $items )
66
	{
67
		/** controller/jobs/product/export/standard/template-items
68
		 * Relative path to the XML items template of the product site map job controller.
69
		 *
70
		 * The template file contains the XML code and processing instructions
71
		 * to generate the site map files. The configuration string is the path
72
		 * to the template file relative to the templates directory (usually in
73
		 * controller/jobs/templates).
74
		 *
75
		 * You can overwrite the template file configuration in extensions and
76
		 * provide alternative templates. These alternative templates should be
77
		 * named like the default one but with the string "standard" replaced by
78
		 * an unique name. You may use the name of your project for this. If
79
		 * you've implemented an alternative client class as well, "standard"
80
		 * should be replaced by the name of the new class.
81
		 *
82
		 * @param string Relative path to the template creating XML code for the site map items
83
		 * @since 2015.01
84
		 * @category Developer
85
		 * @see client/html/account/favorite/standard/template-header
86
		 * @see controller/jobs/product/export/standard/template-footer
87
		 * @see controller/jobs/product/export/standard/template-index
88
		 */
89
		$tplconf = 'controller/jobs/product/export/standard/template-items';
90
		$default = 'product/export/items-body-standard';
91
92
		$context = $this->getContext();
93
		$view = $context->getView();
94
95
		$view->exportItems = $items;
96
97
		$content->add( $view->render( $context->getConfig()->get( $tplconf, $default ) ) );
98
	}
99
100
101
	/**
102
	 * Creates a new container for the site map file
103
	 *
104
	 * @return \Aimeos\MW\Container\Iface Container object
105
	 */
106
	protected function createContainer()
107
	{
108
		$config = $this->getContext()->getConfig();
109
110
		/** controller/jobs/product/export/location
111
		 * Directory where the generated site maps should be placed into
112
		 *
113
		 * You have to configure a directory for the generated files on your
114
		 * server that is writeable by the process generating the files, e.g.
115
		 *
116
		 * /var/www/your/export/path
117
		 *
118
		 * @param string Absolute directory to store the exported files into
119
		 * @since 2015.01
120
		 * @category Developer
121
		 * @category User
122
		 * @see controller/jobs/product/export/standard/container/options
123
		 * @see controller/jobs/product/export/max-items
124
		 * @see controller/jobs/product/export/max-query
125
		 */
126
		$location = $config->get( 'controller/jobs/product/export/location' );
127
128
		/** controller/jobs/product/export/standard/container/type
129
		 * List of file container options for the export files
130
		 *
131
		 * The generated files are stored using container/content objects from
132
		 * the core.
133
		 *
134
		 * @param string Container name
135
		 * @since 2015.01
136
		 * @category Developer
137
		 * @see controller/jobs/product/export/standard/container/content
138
		 * @see controller/jobs/product/export/standard/container/options
139
		 * @see controller/jobs/product/export/location
140
		 * @see controller/jobs/product/export/max-items
141
		 * @see controller/jobs/product/export/max-query
142
		 */
143
		$container = $config->get( 'controller/jobs/product/export/standard/container/type', 'Directory' );
144
145
		/** controller/jobs/product/export/standard/container/content
146
		 * List of file container options for the export files
147
		 *
148
		 * The generated files are stored using container/content objects from
149
		 * the core.
150
		 *
151
		 * @param array Associative list of option name/value pairs
152
		 * @since 2015.01
153
		 * @category Developer
154
		 * @see controller/jobs/product/export/standard/container/type
155
		 * @see controller/jobs/product/export/standard/container/options
156
		 * @see controller/jobs/product/export/location
157
		 * @see controller/jobs/product/export/max-items
158
		 * @see controller/jobs/product/export/max-query
159
		 */
160
		$content = $config->get( 'controller/jobs/product/export/standard/container/content', 'Binary' );
161
162
		/** controller/jobs/product/export/standard/container/options
163
		 * List of file container options for the export files
164
		 *
165
		 * The generated files are stored using container/content objects from
166
		 * the core.
167
		 *
168
		 * @param array Associative list of option name/value pairs
169
		 * @since 2015.01
170
		 * @category Developer
171
		 * @see controller/jobs/product/export/standard/container/type
172
		 * @see controller/jobs/product/export/standard/container/content
173
		 * @see controller/jobs/product/export/location
174
		 * @see controller/jobs/product/export/max-items
175
		 * @see controller/jobs/product/export/max-query
176
		 */
177
		$options = $config->get( 'controller/jobs/product/export/standard/container/options', [] );
178
179
		if( $location === null )
180
		{
181
			$msg = sprintf( 'Required configuration for "%1$s" is missing', 'controller/jobs/product/export/location' );
182
			throw new \Aimeos\Controller\Jobs\Exception( $msg );
183
		}
184
185
		return \Aimeos\MW\Container\Factory::getContainer( $location, $container, $content, $options );
186
	}
187
188
189
	/**
190
	 * Creates a new site map content object
191
	 *
192
	 * @param \Aimeos\MW\Container\Iface $container Container object
193
	 * @param integer $filenum New file number
194
	 * @return \Aimeos\MW\Container\Content\Iface New content object
195
	 */
196
	protected function createContent( \Aimeos\MW\Container\Iface $container, $filenum )
197
	{
198
		/** controller/jobs/product/export/standard/template-header
199
		 * Relative path to the XML site map header template of the product site map job controller.
200
		 *
201
		 * The template file contains the XML code and processing instructions
202
		 * to generate the site map header. The configuration string is the path
203
		 * to the template file relative to the templates directory (usually in
204
		 * controller/jobs/templates).
205
		 *
206
		 * You can overwrite the template file configuration in extensions and
207
		 * provide alternative templates. These alternative templates should be
208
		 * named like the default one but with the string "standard" replaced by
209
		 * an unique name. You may use the name of your project for this. If
210
		 * you've implemented an alternative client class as well, "standard"
211
		 * should be replaced by the name of the new class.
212
		 *
213
		 * @param string Relative path to the template creating XML code for the site map header
214
		 * @since 2015.01
215
		 * @category Developer
216
		 * @see controller/jobs/product/export/standard/template-items
217
		 * @see controller/jobs/product/export/standard/template-footer
218
		 * @see controller/jobs/product/export/standard/template-index
219
		 */
220
		$tplconf = 'controller/jobs/product/export/standard/template-header';
221
		$default = 'product/export/items-header-standard';
222
223
		$context = $this->getContext();
224
		$view = $context->getView();
225
226
		$content = $container->create( $this->getFilename( $filenum ) );
227
		$content->add( $view->render( $context->getConfig()->get( $tplconf, $default ) ) );
228
		$container->add( $content );
229
230
		return $content;
231
	}
232
233
234
	/**
235
	 * Closes the site map content object
236
	 *
237
	 * @param \Aimeos\MW\Container\Content\Iface $content
238
	 */
239
	protected function closeContent( \Aimeos\MW\Container\Content\Iface $content )
240
	{
241
		/** controller/jobs/product/export/standard/template-footer
242
		 * Relative path to the XML site map footer template of the product site map job controller.
243
		 *
244
		 * The template file contains the XML code and processing instructions
245
		 * to generate the site map footer. The configuration string is the path
246
		 * to the template file relative to the templates directory (usually in
247
		 * controller/jobs/templates).
248
		 *
249
		 * You can overwrite the template file configuration in extensions and
250
		 * provide alternative templates. These alternative templates should be
251
		 * named like the default one but with the string "standard" replaced by
252
		 * an unique name. You may use the name of your project for this. If
253
		 * you've implemented an alternative client class as well, "standard"
254
		 * should be replaced by the name of the new class.
255
		 *
256
		 * @param string Relative path to the template creating XML code for the site map footer
257
		 * @since 2015.01
258
		 * @category Developer
259
		 * @see controller/jobs/product/export/standard/template-header
260
		 * @see controller/jobs/product/export/standard/template-items
261
		 * @see controller/jobs/product/export/standard/template-index
262
		 */
263
		$tplconf = 'controller/jobs/product/export/standard/template-footer';
264
		$default = 'product/export/items-footer-standard';
265
266
		$context = $this->getContext();
267
		$view = $context->getView();
268
269
		$content->add( $view->render( $context->getConfig()->get( $tplconf, $default ) ) );
270
	}
271
272
273
	/**
274
	 * Exports the products into the given container
275
	 *
276
	 * @param \Aimeos\MW\Container\Iface $container Container object
277
	 * @param boolean $default True to filter exported products by default criteria
278
	 * @return array List of content (file) names
279
	 */
280
	protected function export( \Aimeos\MW\Container\Iface $container, $default = true )
281
	{
282
		$domains = array( 'attribute', 'media', 'price', 'product', 'text' );
283
284
		$domains = $this->getConfig( 'domains', $domains );
285
		$maxItems = $this->getConfig( 'max-items', 10000 );
286
		$maxQuery = $this->getConfig( 'max-query', 1000 );
287
288
		$start = 0; $filenum = 1;
289
		$names = [];
290
291
		$productManager = \Aimeos\MShop::create( $this->getContext(), 'product' );
292
293
		$search = $productManager->createSearch( $default );
294
		$search->setSortations( array( $search->sort( '+', 'product.id' ) ) );
295
		$search->setSlice( 0, $maxQuery );
296
297
		$content = $this->createContent( $container, $filenum );
298
		$names[] = $content->getResource();
299
300
		do
301
		{
302
			$items = $productManager->searchItems( $search, $domains );
303
			$this->addItems( $content, $items );
304
305
			$count = count( $items );
306
			$start += $count;
307
			$search->setSlice( $start, $maxQuery );
308
309
			if( $start + $maxQuery > $maxItems * $filenum )
310
			{
311
				$this->closeContent( $content );
312
				$content = $this->createContent( $container, ++$filenum );
313
				$names[] = $content->getResource();
314
			}
315
		}
316
		while( $count >= $search->getSliceSize() );
317
318
		$this->closeContent( $content );
319
320
		return $names;
321
	}
322
323
324
	/**
325
	 * Returns the configuration value for the given name
326
	 *
327
	 * @param string $name One of "domain", "max-items" or "max-query"
328
	 * @param mixed $default Default value if name is unknown
329
	 * @return mixed Configuration value
330
	 */
331
	protected function getConfig( $name, $default = null )
332
	{
333
		$config = $this->getContext()->getConfig();
334
335
		switch( $name )
336
		{
337
			case 'domain':
338
				/** controller/jobs/product/export/domains
339
				 * List of associated items from other domains that should be exported too
340
				 *
341
				 * Products consist not only of the base data but also of texts, media
342
				 * files, prices, attrbutes and other details. Those information is
343
				 * associated to the products via their lists. Using the "domains" option
344
				 * you can make more or less associated items available in the template.
345
				 *
346
				 * @param array List of domain names
347
				 * @since 2015.01
348
				 * @category Developer
349
				 * @category User
350
				 * @see controller/jobs/product/export/standard/container/type
351
				 * @see controller/jobs/product/export/standard/container/content
352
				 * @see controller/jobs/product/export/standard/container/options
353
				 * @see controller/jobs/product/export/filename
354
				 * @see controller/jobs/product/export/location
355
				 * @see controller/jobs/product/export/max-items
356
				 * @see controller/jobs/product/export/max-query
357
				 */
358
				return $config->get( 'controller/jobs/product/export/domains', $default );
359
360
			case 'max-items':
361
				/** controller/jobs/product/export/max-items
362
				 * Maximum number of exported products per file
363
				 *
364
				 * Limits the number of exported products per file as the memory
365
				 * consumption of processing big files is rather high. Splitting
366
				 * the data into several files that can also be processed in
367
				 * parallel is able to speed up importing the files again.
368
				 *
369
				 * @param integer Number of products entries per file
370
				 * @since 2015.01
371
				 * @category Developer
372
				 * @category User
373
				 * @see controller/jobs/product/export/standard/container/type
374
				 * @see controller/jobs/product/export/standard/container/content
375
				 * @see controller/jobs/product/export/standard/container/options
376
				 * @see controller/jobs/product/export/filename
377
				 * @see controller/jobs/product/export/location
378
				 * @see controller/jobs/product/export/max-query
379
				 * @see controller/jobs/product/export/domains
380
				 */
381
				return $config->get( 'controller/jobs/product/export/max-items', $default );
382
383
			case 'max-query':
384
				/** controller/jobs/product/export/max-query
385
				 * Maximum number of products per query
386
				 *
387
				 * The products are fetched from the database in bunches for efficient
388
				 * retrieval. The higher the value, the lower the total time the database
389
				 * is busy finding the records. Higher values also means that record
390
				 * updates in the tables need to wait longer and the memory consumption
391
				 * of the PHP process is higher.
392
				 *
393
				 * @param integer Number of products per query
394
				 * @since 2015.01
395
				 * @category Developer
396
				 * @see controller/jobs/product/export/standard/container/type
397
				 * @see controller/jobs/product/export/standard/container/content
398
				 * @see controller/jobs/product/export/standard/container/options
399
				 * @see controller/jobs/product/export/filename
400
				 * @see controller/jobs/product/export/location
401
				 * @see controller/jobs/product/export/max-items
402
				 * @see controller/jobs/product/export/domains
403
				 */
404
				return $config->get( 'controller/jobs/product/export/max-query', $default );
405
406
			case 'filename':
407
				/** controller/jobs/product/export/filename
408
				 * Template for the generated file names
409
				 *
410
				 * The generated export files will be named according to the given
411
				 * string which can contain two place holders: The number of the
412
				 * exported product and the ISO date/time when the file was created.
413
				 *
414
				 * @param string File name template
415
				 * @since 2018.04
416
				 * @category Developer
417
				 * @see controller/jobs/product/export/standard/container/type
418
				 * @see controller/jobs/product/export/standard/container/content
419
				 * @see controller/jobs/product/export/standard/container/options
420
				 * @see controller/jobs/product/export/location
421
				 * @see controller/jobs/product/export/max-items
422
				 * @see controller/jobs/product/export/max-query
423
				 * @see controller/jobs/product/export/domains
424
				 */
425
				return $config->get( 'controller/jobs/product/export/filename', $default );
426
		}
427
428
		return $default;
429
	}
430
431
432
	/**
433
	 * Returns the file name for the new content file
434
	 *
435
	 * @param integer $number Current file number
436
	 * @return string New file name
437
	 */
438
	protected function getFilename( $number )
439
	{
440
		return sprintf( $this->getConfig( 'filename', 'aimeos-products-%1$d_%2$s.xml' ), $number, date( 'Y-m-d_H:i:s' ) );
441
	}
442
}
443