Completed
Pull Request — master (#12)
by
unknown
02:44
created

Standard   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 461
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 12

Importance

Changes 0
Metric Value
wmc 17
lcom 1
cbo 12
dl 0
loc 461
rs 10
c 0
b 0
f 0

11 Methods

Rating   Name   Duplication   Size   Complexity  
A getName() 0 4 1
A getDescription() 0 4 1
A run() 0 9 1
B addItems() 0 66 1
B createContainer() 0 68 2
A createContent() 0 36 1
A closeContent() 0 32 1
A createSitemapIndex() 0 36 1
A export() 0 38 3
B getConfig() 0 75 4
A getFilename() 0 4 1
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\Catalog\Export\Sitemap;
12
13
14
/**
15
 * Job controller for catalog sitemap.
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', 'Catalog 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 catalog 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 catalogs 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\Catalog\Item\Iface[] $items List of catalog items
67
	 */
68
	protected function addItems( \Aimeos\MW\Container\Content\Iface $content, array $items )
69
	{
70
		$config = $this->getContext()->getConfig();
71
72
		/** controller/jobs/catalog/export/sitemap/changefreq
73
		 * Change frequency of the catalog
74
		 *
75
		 * Depending on how often the catalog content changes
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 2018.11
92
		 * @category User
93
		 * @category Developer
94
		 * @see controller/jobs/catalog/export/sitemap/container/options
95
		 * @see controller/jobs/catalog/export/sitemap/location
96
		 * @see controller/jobs/catalog/export/sitemap/max-items
97
		 * @see controller/jobs/catalog/export/sitemap/max-query
98
		 */
99
		$changefreq = $config->get( 'controller/jobs/catalog/export/sitemap/changefreq', 'daily' );
100
101
		/** controller/jobs/catalog/export/sitemap/standard/template-items
102
		 * Relative path to the XML items template of the catalog 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 2018.11
118
		 * @category Developer
119
		 * @see controller/jobs/catalog/export/sitemap/standard/template-header
120
		 * @see controller/jobs/catalog/export/sitemap/standard/template-footer
121
		 * @see controller/jobs/catalog/export/sitemap/standard/template-index
122
		 */
123
		$tplconf = 'controller/jobs/catalog/export/sitemap/standard/template-items';
124
		$default = 'catalog/export/sitemap-items-body-standard.xml';
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/catalog/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
		 * catalogs. Please make sure that the protocol and domain
163
		 * (https://www.yourshop.com/) is the same as the ones used in the
164
		 * catalog 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 2018.11
171
		 * @category Developer
172
		 * @category User
173
		 * @see controller/jobs/catalog/export/sitemap/container/options
174
		 * @see controller/jobs/catalog/export/sitemap/max-items
175
		 * @see controller/jobs/catalog/export/sitemap/max-query
176
		 * @see controller/jobs/catalog/export/sitemap/changefreq
177
		 */
178
		$location = $config->get( 'controller/jobs/catalog/export/sitemap/location' );
179
180
		/** controller/jobs/catalog/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 2018.11
193
		 * @category Developer
194
		 * @see controller/jobs/catalog/export/sitemap/location
195
		 * @see controller/jobs/catalog/export/sitemap/max-items
196
		 * @see controller/jobs/catalog/export/sitemap/max-query
197
		 * @see controller/jobs/catalog/export/sitemap/changefreq
198
		 */
199
		$default = array('gzip-mode' => 'wb');
200
		$options = $config->get( 'controller/jobs/catalog/export/sitemap/container/options', $default );
201
202
		if ( $location === null ) {
203
			$msg = sprintf( 'Required configuration for "%1$s" is missing', 'controller/jobs/catalog/export/sitemap/location' );
204
			throw new \Aimeos\Controller\Jobs\Exception( $msg );
205
		}
206
207
		return \Aimeos\MW\Container\Factory::getContainer( $location, 'Directory', 'Gzip', $options );
208
	}
209
210
211
	/**
212
	 * Creates a new site map content object
213
	 *
214
	 * @param \Aimeos\MW\Container\Iface $container Container object
215
	 * @param integer $filenum New file number
216
	 * @return \Aimeos\MW\Container\Content\Iface New content object
217
	 */
218
	protected function createContent( \Aimeos\MW\Container\Iface $container, $filenum )
219
	{
220
		/** controller/jobs/catalog/export/sitemap/standard/template-header
221
		 * Relative path to the XML site map header template of the catalog site map job controller.
222
		 *
223
		 * The template file contains the XML code and processing instructions
224
		 * to generate the site map header. The configuration string is the path
225
		 * to the template file relative to the templates directory (usually in
226
		 * controller/jobs/templates).
227
		 *
228
		 * You can overwrite the template file configuration in extensions and
229
		 * provide alternative templates. These alternative templates should be
230
		 * named like the default one but with the string "standard" replaced by
231
		 * an unique name. You may use the name of your project for this. If
232
		 * you've implemented an alternative client class as well, "standard"
233
		 * should be replaced by the name of the new class.
234
		 *
235
		 * @param string Relative path to the template creating XML code for the site map header
236
		 * @since 2018.11
237
		 * @category Developer
238
		 * @see controller/jobs/catalog/export/sitemap/standard/template-items
239
		 * @see controller/jobs/catalog/export/sitemap/standard/template-footer
240
		 * @see controller/jobs/catalog/export/sitemap/standard/template-index
241
		 */
242
		$tplconf = 'controller/jobs/catalog/export/sitemap/standard/template-header';
243
		$default = 'catalog/export/sitemap-items-header-standard.xml';
244
245
		$context = $this->getContext();
246
		$view = $context->getView();
247
248
		$content = $container->create( $this->getFilename( $filenum ) );
249
		$content->add( $view->render( $context->getConfig()->get( $tplconf, $default ) ) );
250
		$container->add( $content );
251
252
		return $content;
253
	}
254
255
256
	/**
257
	 * Closes the site map content object
258
	 *
259
	 * @param \Aimeos\MW\Container\Content\Iface $content
260
	 */
261
	protected function closeContent( \Aimeos\MW\Container\Content\Iface $content )
262
	{
263
		/** controller/jobs/catalog/export/sitemap/standard/template-footer
264
		 * Relative path to the XML site map footer template of the catalog site map job controller.
265
		 *
266
		 * The template file contains the XML code and processing instructions
267
		 * to generate the site map footer. The configuration string is the path
268
		 * to the template file relative to the templates directory (usually in
269
		 * controller/jobs/templates).
270
		 *
271
		 * You can overwrite the template file configuration in extensions and
272
		 * provide alternative templates. These alternative templates should be
273
		 * named like the default one but with the string "standard" replaced by
274
		 * an unique name. You may use the name of your project for this. If
275
		 * you've implemented an alternative client class as well, "standard"
276
		 * should be replaced by the name of the new class.
277
		 *
278
		 * @param string Relative path to the template creating XML code for the site map footer
279
		 * @since 2018.11
280
		 * @category Developer
281
		 * @see controller/jobs/catalog/export/sitemap/standard/template-header
282
		 * @see controller/jobs/catalog/export/sitemap/standard/template-items
283
		 * @see controller/jobs/catalog/export/sitemap/standard/template-index
284
		 */
285
		$tplconf = 'controller/jobs/catalog/export/sitemap/standard/template-footer';
286
		$default = 'catalog/export/sitemap-items-footer-standard.xml';
287
288
		$context = $this->getContext();
289
		$view = $context->getView();
290
291
		$content->add( $view->render( $context->getConfig()->get( $tplconf, $default ) ) );
292
	}
293
294
295
	/**
296
	 * Adds the content for the site map index file
297
	 *
298
	 * @param \Aimeos\MW\Container\Iface $container File container object
299
	 * @param array $files List of generated site map file names
300
	 */
301
	protected function createSitemapIndex( \Aimeos\MW\Container\Iface $container, array $files )
302
	{
303
		/** controller/jobs/catalog/export/sitemap/standard/template-index
304
		 * Relative path to the XML site map index template of the catalog site map job controller.
305
		 *
306
		 * The template file contains the XML code and processing instructions
307
		 * to generate the site map index files. The configuration string is the path
308
		 * to the template file relative to the templates directory (usually in
309
		 * controller/jobs/templates).
310
		 *
311
		 * You can overwrite the template file configuration in extensions and
312
		 * provide alternative templates. These alternative templates should be
313
		 * named like the default one but with the string "standard" replaced by
314
		 * an unique name. You may use the name of your project for this. If
315
		 * you've implemented an alternative client class as well, "standard"
316
		 * should be replaced by the name of the new class.
317
		 *
318
		 * @param string Relative path to the template creating XML code for the site map index
319
		 * @since 2018.11
320
		 * @category Developer
321
		 * @see controller/jobs/catalog/export/sitemap/standard/template-header
322
		 * @see controller/jobs/catalog/export/sitemap/standard/template-items
323
		 * @see controller/jobs/catalog/export/sitemap/standard/template-footer
324
		 */
325
		$tplconf = 'controller/jobs/catalog/export/sitemap/standard/template-index';
326
		$default = 'catalog/export/sitemap-index-standard.xml';
327
328
		$context = $this->getContext();
329
		$view = $context->getView();
330
331
		$view->siteFiles = $files;
332
333
		$content = $container->create( 'aimeos-catalog-sitemap-index.xml' );
334
		$content->add( $view->render( $context->getConfig()->get( $tplconf, $default ) ) );
335
		$container->add( $content );
336
	}
337
338
339
	/**
340
	 * Exports the catalogs into the given container
341
	 *
342
	 * @param \Aimeos\MW\Container\Iface $container Container object
343
	 * @param boolean $default True to filter exported catalogs by default criteria
344
	 * @return array List of content (file) names
345
	 */
346
	protected function export( \Aimeos\MW\Container\Iface $container, $default = true )
347
	{
348
		$domains = $this->getConfig( 'domains', [] );
349
		$maxItems = $this->getConfig( 'max-items', 10000 );
350
		$maxQuery = $this->getConfig( 'max-query', 1000 );
351
352
		$start = 0;
353
		$filenum = 1;
354
		$names = [];
355
356
		$manager = \Aimeos\MShop\Factory::createManager( $this->getContext(), 'catalog' );
357
358
		$search = $manager->createSearch( $default );
359
		$search->setSortations( array($search->sort( '+', 'catalog.id' )) );
360
		$search->setSlice( 0, $maxQuery );
361
362
		$content = $this->createContent( $container, $filenum );
363
		$names[] = $content->getResource();
364
365
		do {
366
			$items = $manager->searchItems( $search, $domains );
367
			$this->addItems( $content, $items );
368
369
			$count = count( $items );
370
			$start += $count;
371
			$search->setSlice( $start, $maxQuery );
372
373
			if ( $start + $maxQuery > $maxItems * $filenum ) {
374
				$this->closeContent( $content );
375
				$content = $this->createContent( $container, ++$filenum );
376
				$names[] = $content->getResource();
377
			}
378
		} while ($count >= $search->getSliceSize());
379
380
		$this->closeContent( $content );
381
382
		return $names;
383
	}
384
385
386
	/**
387
	 * Returns the configuration value for the given name
388
	 *
389
	 * @param string $name One of "domain", "max-items" or "max-query"
390
	 * @param mixed $default Default value if name is unknown
391
	 * @return mixed Configuration value
392
	 */
393
	protected function getConfig( $name, $default = null )
394
	{
395
		$config = $this->getContext()->getConfig();
396
397
		switch ($name) {
398
			case 'domains':
399
				/** controller/jobs/catalog/export/sitemap/domains
400
				 * List of associated items from other domains that should be fetched for the sitemap
401
				 *
402
				 * Catalogs consist not only of the base data but also of texts, media and
403
				 * other details. Those information is associated to the catalog via their lists.
404
				 * Using the "domains" option you can make more or less associated items available
405
				 * in the template.
406
				 *
407
				 * @param array List of domain names
408
				 * @since 2018.11
409
				 * @category Developer
410
				 * @category User
411
				 * @see controller/jobs/catalog/export/sitemap/container/options
412
				 * @see controller/jobs/catalog/export/sitemap/location
413
				 * @see controller/jobs/catalog/export/sitemap/max-items
414
				 * @see controller/jobs/catalog/export/sitemap/max-query
415
				 * @see controller/jobs/catalog/export/sitemap/changefreq
416
				 */
417
				return $config->get( 'controller/jobs/catalog/export/sitemap/domains', $default );
418
419
			case 'max-items':
420
				/** controller/jobs/catalog/export/sitemap/max-items
421
				 * Maximum number of catalog per site map
422
				 *
423
				 * Each site map file must not contain more than 50,000 links and it's
424
				 * size must be less than 10MB. If your catalog URLs are rather long
425
				 * and one of your site map files is bigger than 10MB, you should set
426
				 * the number of catalogs per file to a smaller value until each file
427
				 * is less than 10MB.
428
				 *
429
				 * More details about site maps can be found at
430
				 * {@link http://www.sitemaps.org/protocol.html sitemaps.org}
431
				 *
432
				 * @param integer Number of catalogs per file
433
				 * @since 2018.11
434
				 * @category Developer
435
				 * @category User
436
				 * @see controller/jobs/catalog/export/sitemap/container/options
437
				 * @see controller/jobs/catalog/export/sitemap/location
438
				 * @see controller/jobs/catalog/export/sitemap/max-query
439
				 * @see controller/jobs/catalog/export/sitemap/changefreq
440
				 * @see controller/jobs/catalog/export/sitemap/domains
441
				 */
442
				return $config->get( 'controller/jobs/catalog/export/sitemap/max-items', 50000 );
443
444
			case 'max-query':
445
				/** controller/jobs/catalog/export/sitemap/max-query
446
				 * Maximum number of catalog per query
447
				 *
448
				 * The catalogs are fetched from the database in bunches for efficient
449
				 * retrieval. The higher the value, the lower the total time the database
450
				 * is busy finding the records. Higher values also means that record
451
				 * updates in the tables need to wait longer and the memory consumption
452
				 * of the PHP process is higher.
453
				 *
454
				 * @param integer Number of catalog per query
455
				 * @since 2015.01
456
				 * @category Developer
457
				 * @see controller/jobs/catalog/export/sitemap/container/options
458
				 * @see controller/jobs/catalog/export/sitemap/location
459
				 * @see controller/jobs/catalog/export/sitemap/max-items
460
				 * @see controller/jobs/catalog/export/sitemap/changefreq
461
				 * @see controller/jobs/catalog/export/sitemap/domains
462
				 */
463
				return $config->get( 'controller/jobs/catalog/export/sitemap/max-query', 1000 );
464
		}
465
466
		return $default;
467
	}
468
469
470
	/**
471
	 * Returns the file name for the new content file
472
	 *
473
	 * @param integer $number Current file number
474
	 * @return string New file name
475
	 */
476
	protected function getFilename( $number )
477
	{
478
		return sprintf( 'aimeos-catalog-sitemap-%d.xml', $number );
479
	}
480
}
481