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

Standard::createContainer()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 68
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 8
nc 2
nop 0
dl 0
loc 68
rs 10
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\Sitemap;
12
13
14
/**
15
 * Job controller for product sitemap.
16
 *
17
 * @package Controller
18
 * @subpackage Jobs
19
 */
20
class Standard
21
	extends \Aimeos\Controller\Jobs\Product\Export\Standard
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 site map' );
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', 'Creates a product site map for search engines' );
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
55
		$files = $this->export( $container );
56
		$this->createSitemapIndex( $container, $files );
57
58
		$container->close();
59
	}
60
61
62
	/**
63
	 * Adds the given products to the content object for the site map file
64
	 *
65
	 * @param \Aimeos\MW\Container\Content\Iface $content File content object
66
	 * @param \Aimeos\MShop\Product\Item\Iface[] $items List of product items
67
	 */
68
	protected function addItems( \Aimeos\MW\Container\Content\Iface $content, array $items )
69
	{
70
		$config = $this->getContext()->getConfig();
71
72
		/** controller/jobs/product/export/sitemap/changefreq
73
		 * Change frequency of the products
74
		 *
75
		 * Depending on how often the product content changes (e.g. price updates)
76
		 * and the site map files are generated you can give search engines a
77
		 * hint how often they should reindex your site. The site map schema
78
		 * allows a few pre-defined strings for the change frequency:
79
		 * * always
80
		 * * hourly
81
		 * * daily
82
		 * * weekly
83
		 * * monthly
84
		 * * yearly
85
		 * * never
86
		 *
87
		 * More information can be found at
88
		 * {@link http://www.sitemaps.org/protocol.html#xmlTagDefinitions sitemap.org}
89
		 *
90
		 * @param string One of the pre-defined strings (see description)
91
		 * @since 2015.01
92
		 * @category User
93
		 * @category Developer
94
		 * @see controller/jobs/product/export/sitemap/container/options
95
		 * @see controller/jobs/product/export/sitemap/location
96
		 * @see controller/jobs/product/export/sitemap/max-items
97
		 * @see controller/jobs/product/export/sitemap/max-query
98
		 */
99
		$changefreq = $config->get( 'controller/jobs/product/export/sitemap/changefreq', 'daily' );
100
101
		/** controller/jobs/product/export/sitemap/standard/template-items
102
		 * Relative path to the XML items template of the product site map job controller.
103
		 *
104
		 * The template file contains the XML code and processing instructions
105
		 * to generate the site map files. The configuration string is the path
106
		 * to the template file relative to the templates directory (usually in
107
		 * controller/jobs/templates).
108
		 *
109
		 * You can overwrite the template file configuration in extensions and
110
		 * provide alternative templates. These alternative templates should be
111
		 * named like the default one but with the string "standard" replaced by
112
		 * an unique name. You may use the name of your project for this. If
113
		 * you've implemented an alternative client class as well, "standard"
114
		 * should be replaced by the name of the new class.
115
		 *
116
		 * @param string Relative path to the template creating XML code for the site map items
117
		 * @since 2015.01
118
		 * @category Developer
119
		 * @see controller/jobs/product/export/sitemap/standard/template-header
120
		 * @see controller/jobs/product/export/sitemap/standard/template-footer
121
		 * @see controller/jobs/product/export/sitemap/standard/template-index
122
		 */
123
		$tplconf = 'controller/jobs/product/export/sitemap/standard/template-items';
124
		$default = 'product/export/sitemap-items-body-standard';
125
126
		$context = $this->getContext();
127
		$view = $context->getView();
128
129
		$view->siteItems = $items;
130
		$view->siteFreq = $changefreq;
131
132
		$content->add( $view->render( $context->getConfig()->get( $tplconf, $default ) ) );
133
	}
134
135
136
	/**
137
	 * Creates a new container for the site map file
138
	 *
139
	 * @return \Aimeos\MW\Container\Iface Container object
140
	 */
141
	protected function createContainer()
142
	{
143
		$config = $this->getContext()->getConfig();
144
145
		/** controller/jobs/product/export/sitemap/location
146
		 * Directory where the generated site maps should be placed into
147
		 *
148
		 * The site maps must be publically available for download by the search
149
		 * engines. Therefore, you have to configure a directory for the site
150
		 * maps in your web space that is writeable by the process generating
151
		 * the files, e.g.
152
		 *
153
		 * /var/www/yourshop/your/sitemap/path
154
		 *
155
		 * The location of the site map index file should then be
156
		 * added to the robots.txt in the document root of your domain:
157
		 *
158
		 * Sitemap: https://www.yourshop.com/your/sitemap/path/aimeos-sitemap-index.xml
159
		 *
160
		 * The "sitemapindex-aimeos.xml" file is the site map index file that
161
		 * references the real site map files which contains the links to the
162
		 * products. Please make sure that the protocol and domain
163
		 * (https://www.yourshop.com/) is the same as the ones used in the
164
		 * product links!
165
		 *
166
		 * More details about site maps can be found at
167
		 * {@link http://www.sitemaps.org/protocol.html sitemaps.org}
168
		 *
169
		 * @param string Absolute directory to store the site maps into
170
		 * @since 2015.01
171
		 * @category Developer
172
		 * @category User
173
		 * @see controller/jobs/product/export/sitemap/container/options
174
		 * @see controller/jobs/product/export/sitemap/max-items
175
		 * @see controller/jobs/product/export/sitemap/max-query
176
		 * @see controller/jobs/product/export/sitemap/changefreq
177
		 */
178
		$location = $config->get( 'controller/jobs/product/export/sitemap/location' );
179
180
		/** controller/jobs/product/export/sitemap/container/options
181
		 * List of file container options for the site map files
182
		 *
183
		 * The directory and the generated site map files are stored using
184
		 * container/content objects from the core, namely the "Directory"
185
		 * container and the "Binary" content classes. Both implementations
186
		 * support some options:
187
		 * * dir-perm (default: 0755): Permissions if the directory must be created
188
		 * * gzip-level (default: 5): GZip compression level from 0 to 9 (0 = fast, 9 = best)
189
		 * * gzip-mode (default: "wb"): Overwrite existing files in binary mode
190
		 *
191
		 * @param array Associative list of option name/value pairs
192
		 * @since 2015.01
193
		 * @category Developer
194
		 * @see controller/jobs/product/export/sitemap/location
195
		 * @see controller/jobs/product/export/sitemap/max-items
196
		 * @see controller/jobs/product/export/sitemap/max-query
197
		 * @see controller/jobs/product/export/sitemap/changefreq
198
		 */
199
		$default = array( 'gzip-mode' => 'wb' );
200
		$options = $config->get( 'controller/jobs/product/export/sitemap/container/options', $default );
201
202
		if( $location === null )
203
		{
204
			$msg = sprintf( 'Required configuration for "%1$s" is missing', 'controller/jobs/product/export/sitemap/location' );
205
			throw new \Aimeos\Controller\Jobs\Exception( $msg );
206
		}
207
208
		return \Aimeos\MW\Container\Factory::getContainer( $location, 'Directory', 'Gzip', $options );
209
	}
210
211
212
	/**
213
	 * Creates a new site map content object
214
	 *
215
	 * @param \Aimeos\MW\Container\Iface $container Container object
216
	 * @param integer $filenum New file number
217
	 * @return \Aimeos\MW\Container\Content\Iface New content object
218
	 */
219
	protected function createContent( \Aimeos\MW\Container\Iface $container, $filenum )
220
	{
221
		/** controller/jobs/product/export/sitemap/standard/template-header
222
		 * Relative path to the XML site map header template of the product site map job controller.
223
		 *
224
		 * The template file contains the XML code and processing instructions
225
		 * to generate the site map header. The configuration string is the path
226
		 * to the template file relative to the templates directory (usually in
227
		 * controller/jobs/templates).
228
		 *
229
		 * You can overwrite the template file configuration in extensions and
230
		 * provide alternative templates. These alternative templates should be
231
		 * named like the default one but with the string "standard" replaced by
232
		 * an unique name. You may use the name of your project for this. If
233
		 * you've implemented an alternative client class as well, "standard"
234
		 * should be replaced by the name of the new class.
235
		 *
236
		 * @param string Relative path to the template creating XML code for the site map header
237
		 * @since 2015.01
238
		 * @category Developer
239
		 * @see controller/jobs/product/export/sitemap/standard/template-items
240
		 * @see controller/jobs/product/export/sitemap/standard/template-footer
241
		 * @see controller/jobs/product/export/sitemap/standard/template-index
242
		 */
243
		$tplconf = 'controller/jobs/product/export/sitemap/standard/template-header';
244
		$default = 'product/export/sitemap-items-header-standard';
245
246
		$context = $this->getContext();
247
		$view = $context->getView();
248
249
		$content = $container->create( $this->getFilename( $filenum ) );
250
		$content->add( $view->render( $context->getConfig()->get( $tplconf, $default ) ) );
251
		$container->add( $content );
252
253
		return $content;
254
	}
255
256
257
	/**
258
	 * Closes the site map content object
259
	 *
260
	 * @param \Aimeos\MW\Container\Content\Iface $content
261
	 */
262
	protected function closeContent( \Aimeos\MW\Container\Content\Iface $content )
263
	{
264
		/** controller/jobs/product/export/sitemap/standard/template-footer
265
		 * Relative path to the XML site map footer template of the product site map job controller.
266
		 *
267
		 * The template file contains the XML code and processing instructions
268
		 * to generate the site map footer. The configuration string is the path
269
		 * to the template file relative to the templates directory (usually in
270
		 * controller/jobs/templates).
271
		 *
272
		 * You can overwrite the template file configuration in extensions and
273
		 * provide alternative templates. These alternative templates should be
274
		 * named like the default one but with the string "standard" replaced by
275
		 * an unique name. You may use the name of your project for this. If
276
		 * you've implemented an alternative client class as well, "standard"
277
		 * should be replaced by the name of the new class.
278
		 *
279
		 * @param string Relative path to the template creating XML code for the site map footer
280
		 * @since 2015.01
281
		 * @category Developer
282
		 * @see controller/jobs/product/export/sitemap/standard/template-header
283
		 * @see controller/jobs/product/export/sitemap/standard/template-items
284
		 * @see controller/jobs/product/export/sitemap/standard/template-index
285
		 */
286
		$tplconf = 'controller/jobs/product/export/sitemap/standard/template-footer';
287
		$default = 'product/export/sitemap-items-footer-standard';
288
289
		$context = $this->getContext();
290
		$view = $context->getView();
291
292
		$content->add( $view->render( $context->getConfig()->get( $tplconf, $default ) ) );
293
	}
294
295
296
	/**
297
	 * Adds the content for the site map index file
298
	 *
299
	 * @param \Aimeos\MW\Container\Iface $container File container object
300
	 * @param array $files List of generated site map file names
301
	 */
302
	protected function createSitemapIndex( \Aimeos\MW\Container\Iface $container, array $files )
303
	{
304
		/** controller/jobs/product/export/sitemap/standard/template-index
305
		 * Relative path to the XML site map index template of the product site map job controller.
306
		 *
307
		 * The template file contains the XML code and processing instructions
308
		 * to generate the site map index files. The configuration string is the path
309
		 * to the template file relative to the templates directory (usually in
310
		 * controller/jobs/templates).
311
		 *
312
		 * You can overwrite the template file configuration in extensions and
313
		 * provide alternative templates. These alternative templates should be
314
		 * named like the default one but with the string "standard" replaced by
315
		 * an unique name. You may use the name of your project for this. If
316
		 * you've implemented an alternative client class as well, "standard"
317
		 * should be replaced by the name of the new class.
318
		 *
319
		 * @param string Relative path to the template creating XML code for the site map index
320
		 * @since 2015.01
321
		 * @category Developer
322
		 * @see controller/jobs/product/export/sitemap/standard/template-header
323
		 * @see controller/jobs/product/export/sitemap/standard/template-items
324
		 * @see controller/jobs/product/export/sitemap/standard/template-footer
325
		 */
326
		$tplconf = 'controller/jobs/product/export/sitemap/standard/template-index';
327
		$default = 'product/export/sitemap-index-standard';
328
329
		$context = $this->getContext();
330
		$view = $context->getView();
331
332
		$view->siteFiles = $files;
333
334
		$content = $container->create( 'aimeos-sitemap-index.xml' );
335
		$content->add( $view->render( $context->getConfig()->get( $tplconf, $default ) ) );
336
		$container->add( $content );
337
	}
338
339
340
	/**
341
	 * Exports the products into the given container
342
	 *
343
	 * @param \Aimeos\MW\Container\Iface $container Container object
344
	 * @param boolean $default True to filter exported products by default criteria
345
	 * @return array List of content (file) names
346
	 */
347
	protected function export( \Aimeos\MW\Container\Iface $container, $default = true )
348
	{
349
		$domains = $this->getConfig( 'domains', [] );
350
		$maxItems = $this->getConfig( 'max-items', 10000 );
351
		$maxQuery = $this->getConfig( 'max-query', 1000 );
352
353
		$start = 0; $filenum = 1;
354
		$names = [];
355
356
		$manager = \Aimeos\MShop::create( $this->getContext(), 'index' );
357
358
		$search = $manager->createSearch( $default );
359
		$search->setConditions( $search->compare( '!=', 'index.catalog.id', null ) );
360
		$search->setSortations( array( $search->sort( '+', 'product.id' ) ) );
361
		$search->setSlice( 0, $maxQuery );
362
363
		$content = $this->createContent( $container, $filenum );
364
		$names[] = $content->getResource();
365
366
		do
367
		{
368
			$items = $manager->searchItems( $search, $domains );
369
			$this->addItems( $content, $items );
370
371
			$count = count( $items );
372
			$start += $count;
373
			$search->setSlice( $start, $maxQuery );
374
375
			if( $start + $maxQuery > $maxItems * $filenum )
376
			{
377
				$this->closeContent( $content );
378
				$content = $this->createContent( $container, ++$filenum );
379
				$names[] = $content->getResource();
380
			}
381
		}
382
		while( $count >= $search->getSliceSize() );
383
384
		$this->closeContent( $content );
385
386
		return $names;
387
	}
388
389
390
	/**
391
	 * Returns the configuration value for the given name
392
	 *
393
	 * @param string $name One of "domain", "max-items" or "max-query"
394
	 * @param mixed $default Default value if name is unknown
395
	 * @return mixed Configuration value
396
	 */
397
	protected function getConfig( $name, $default = null )
398
	{
399
		$config = $this->getContext()->getConfig();
400
401
		switch( $name )
402
		{
403
			case 'domains':
404
				/** controller/jobs/product/export/sitemap/domains
405
				 * List of associated items from other domains that should be fetched for the sitemap
406
				 *
407
				 * Products consist not only of the base data but also of texts, media
408
				 * files, prices, attrbutes and other details. Those information is
409
				 * associated to the products via their lists. Using the "domains" option
410
				 * you can make more or less associated items available in the template.
411
				 *
412
				 * @param array List of domain names
413
				 * @since 2018.07
414
				 * @category Developer
415
				 * @category User
416
				 * @see controller/jobs/product/export/sitemap/container/options
417
				 * @see controller/jobs/product/export/sitemap/location
418
				 * @see controller/jobs/product/export/sitemap/max-items
419
				 * @see controller/jobs/product/export/sitemap/max-query
420
				 * @see controller/jobs/product/export/sitemap/changefreq
421
				 */
422
				return $config->get( 'controller/jobs/product/export/sitemap/domains', $default );
423
424
			case 'max-items':
425
				/** controller/jobs/product/export/sitemap/max-items
426
				 * Maximum number of products per site map
427
				 *
428
				 * Each site map file must not contain more than 50,000 links and it's
429
				 * size must be less than 10MB. If your product URLs are rather long
430
				 * and one of your site map files is bigger than 10MB, you should set
431
				 * the number of products per file to a smaller value until each file
432
				 * is less than 10MB.
433
				 *
434
				 * More details about site maps can be found at
435
				 * {@link http://www.sitemaps.org/protocol.html sitemaps.org}
436
				 *
437
				 * @param integer Number of products per file
438
				 * @since 2015.01
439
				 * @category Developer
440
				 * @category User
441
				 * @see controller/jobs/product/export/sitemap/container/options
442
				 * @see controller/jobs/product/export/sitemap/location
443
				 * @see controller/jobs/product/export/sitemap/max-query
444
				 * @see controller/jobs/product/export/sitemap/changefreq
445
				 * @see controller/jobs/product/export/sitemap/domains
446
				 */
447
				return $config->get( 'controller/jobs/product/export/sitemap/max-items', 50000 );
448
449
			case 'max-query':
450
				/** controller/jobs/product/export/sitemap/max-query
451
				 * Maximum number of products per query
452
				 *
453
				 * The products are fetched from the database in bunches for efficient
454
				 * retrieval. The higher the value, the lower the total time the database
455
				 * is busy finding the records. Higher values also means that record
456
				 * updates in the tables need to wait longer and the memory consumption
457
				 * of the PHP process is higher.
458
				 *
459
				 * @param integer Number of products per query
460
				 * @since 2015.01
461
				 * @category Developer
462
				 * @see controller/jobs/product/export/sitemap/container/options
463
				 * @see controller/jobs/product/export/sitemap/location
464
				 * @see controller/jobs/product/export/sitemap/max-items
465
				 * @see controller/jobs/product/export/sitemap/changefreq
466
				 * @see controller/jobs/product/export/sitemap/domains
467
				 */
468
				return $config->get( 'controller/jobs/product/export/sitemap/max-query', 1000 );
469
		}
470
471
		return $default;
472
	}
473
474
475
	/**
476
	 * Returns the file name for the new content file
477
	 *
478
	 * @param integer $number Current file number
479
	 * @return string New file name
480
	 */
481
	protected function getFilename( $number )
482
	{
483
		return sprintf( 'aimeos-sitemap-%d.xml', $number );
484
	}
485
}
486