Passed
Push — master ( 29d5f6...586595 )
by Aimeos
04:48
created

src/MShop/Locale/Manager/Language/Standard.php (1 issue)

Labels
Severity
1
<?php
2
3
/**
4
 * @license LGPLv3, http://opensource.org/licenses/LGPL-3.0
5
 * @copyright Metaways Infosystems GmbH, 2011
6
 * @copyright Aimeos (aimeos.org), 2015-2018
7
 * @package MShop
8
 * @subpackage Locale
9
 */
10
11
12
namespace Aimeos\MShop\Locale\Manager\Language;
13
14
15
/**
16
 * Default implementation for managing languages.
17
 *
18
 * @package MShop
19
 * @subpackage Locale
20
 */
21
class Standard
22
	extends \Aimeos\MShop\Common\Manager\Base
23
	implements \Aimeos\MShop\Locale\Manager\Language\Iface, \Aimeos\MShop\Common\Manager\Factory\Iface
24
{
25
	private $searchConfig = array(
26
		'locale.language.id' => array(
27
			'code' => 'locale.language.id',
28
			'internalcode' => 'mlocla."id"',
29
			'internaldeps' => array( 'LEFT JOIN "mshop_locale_language" AS mlocla ON (mloc."langid" = mlocla."id")' ),
30
			'label' => 'Language ID',
31
			'type' => 'string',
32
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
33
			'public' => false,
34
		),
35
		'locale.language.siteid' => array(
36
			'code' => 'locale.language.siteid',
37
			'internalcode' => 'mlocla."siteid"',
38
			'label' => 'Language site ID',
39
			'type' => 'string',
40
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_INT,
41
			'public' => false,
42
		),
43
		'locale.language.label' => array(
44
			'code' => 'locale.language.label',
45
			'internalcode' => 'mlocla."label"',
46
			'label' => 'Language label',
47
			'type' => 'string',
48
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
49
		),
50
		'locale.language.code' => array(
51
			'code' => 'locale.language.code',
52
			'internalcode' => 'mlocla."id"',
53
			'label' => 'Language code',
54
			'type' => 'string',
55
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
56
		),
57
		'locale.language.status' => array(
58
			'code' => 'locale.language.status',
59
			'internalcode' => 'mlocla."status"',
60
			'label' => 'Language status',
61
			'type' => 'integer',
62
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_INT,
63
		),
64
		'locale.language.ctime' => array(
65
			'code' => 'locale.language.ctime',
66
			'internalcode' => 'mlocla."ctime"',
67
			'label' => 'Language create date/time',
68
			'type' => 'datetime',
69
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
70
			'public' => false,
71
		),
72
		'locale.language.mtime' => array(
73
			'code' => 'locale.language.mtime',
74
			'internalcode' => 'mlocla."mtime"',
75
			'label' => 'Language modify date/time',
76
			'type' => 'datetime',
77
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
78
			'public' => false,
79
		),
80
		'locale.language.editor' => array(
81
			'code' => 'locale.language.editor',
82
			'internalcode' => 'mlocla."editor"',
83
			'label' => 'Language editor',
84
			'type' => 'string',
85
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
86
			'public' => false,
87
		),
88
	);
89
90
91
	/**
92
	 * Initializes the object.
93
	 *
94
	 * @param \Aimeos\MShop\Context\Item\Iface $context Context object
95
	 */
96
	public function __construct( \Aimeos\MShop\Context\Item\Iface $context )
97
	{
98
		parent::__construct( $context );
99
		$this->setResourceName( 'db-locale' );
100
	}
101
102
103
	/**
104
	 * Creates a new empty item instance
105
	 *
106
	 * @param string|null Type the item should be created with
107
	 * @param string|null Domain of the type the item should be created with
108
	 * @param array $values Values the item should be initialized with
109
	 * @return \Aimeos\MShop\Locale\Item\Language\Iface New locale language item object
110
	 */
111
	public function createItem( $type = null, $domain = null, array $values = [] )
112
	{
113
		try {
114
			$values['locale.language.siteid'] = $this->getContext()->getLocale()->getSiteId();
115
		} catch( \Exception $ex ) {
116
			$values['locale.language.siteid'] = null;
117
		}
118
119
		return $this->createItemBase( $values );
120
	}
121
122
123
	/**
124
	 * Saves the language object to the storage.
125
	 *
126
	 * @param \Aimeos\MShop\Common\Item\Iface $item Language object
127
	 * @param boolean $fetch True if the new ID should be returned in the item
128
	 * @return \Aimeos\MShop\Common\Item\Iface $item Updated item including the generated ID
129
	 */
130
	public function saveItem( \Aimeos\MShop\Common\Item\Iface $item, $fetch = true )
131
	{
132
		self::checkClass( '\\Aimeos\\MShop\\Locale\\Item\\Language\\Iface', $item );
133
134
		if( !$item->isModified() ) {
135
			return $item;
136
		}
137
138
		$context = $this->getContext();
139
140
		$dbm = $context->getDatabaseManager();
141
		$dbname = $this->getResourceName();
142
		$conn = $dbm->acquire( $dbname );
143
144
		try
145
		{
146
			$id = $item->getId();
147
			$date = date( 'Y-m-d H:i:s' );
148
149
			if( $id === null )
150
			{
151
				/** mshop/locale/manager/language/standard/insert/mysql
152
				 * Inserts a new language record into the database table
153
				 *
154
				 * @see mshop/locale/manager/language/standard/insert/ansi
155
				 */
156
157
				/** mshop/locale/manager/language/standard/insert/ansi
158
				 * Inserts a new language record into the database table
159
				 *
160
				 * The SQL statement must be a string suitable for being used as
161
				 * prepared statement. It must include question marks for binding
162
				 * the values from the language item to the statement before they are
163
				 * sent to the database server. The number of question marks must
164
				 * be the same as the number of columns listed in the INSERT
165
				 * statement. The order of the columns must correspond to the
166
				 * order in the saveItems() method, so the correct values are
167
				 * bound to the columns.
168
				 *
169
				 * The SQL statement should conform to the ANSI standard to be
170
				 * compatible with most relational database systems. This also
171
				 * includes using double quotes for table and column names.
172
				 *
173
				 * @param string SQL statement for inserting records
174
				 * @since 2014.03
175
				 * @category Developer
176
				 * @see mshop/locale/manager/language/standard/update/ansi
177
				 * @see mshop/locale/manager/language/standard/delete/ansi
178
				 * @see mshop/locale/manager/language/standard/search/ansi
179
				 * @see mshop/locale/manager/language/standard/count/ansi
180
				 */
181
				$path = 'mshop/locale/manager/language/standard/insert';
182
			}
183
			else
184
			{
185
				/** mshop/locale/manager/language/standard/update/mysql
186
				 * Updates an existing language record in the database
187
				 *
188
				 * @see mshop/locale/manager/language/standard/update/ansi
189
				 */
190
191
				/** mshop/locale/manager/language/standard/update/ansi
192
				 * Updates an existing language record in the database
193
				 *
194
				 * The SQL statement must be a string suitable for being used as
195
				 * prepared statement. It must include question marks for binding
196
				 * the values from the language item to the statement before they are
197
				 * sent to the database server. The order of the columns must
198
				 * correspond to the order in the saveItems() method, so the
199
				 * correct values are bound to the columns.
200
				 *
201
				 * The SQL statement should conform to the ANSI standard to be
202
				 * compatible with most relational database systems. This also
203
				 * includes using double quotes for table and column names.
204
				 *
205
				 * @param string SQL statement for updating records
206
				 * @since 2014.03
207
				 * @category Developer
208
				 * @see mshop/locale/manager/language/standard/insert/ansi
209
				 * @see mshop/locale/manager/language/standard/delete/ansi
210
				 * @see mshop/locale/manager/language/standard/search/ansi
211
				 * @see mshop/locale/manager/language/standard/count/ansi
212
				 */
213
				$path = 'mshop/locale/manager/language/standard/update';
214
			}
215
216
			$stmt = $this->getCachedStatement( $conn, $path );
217
218
			$stmt->bind( 1, $item->getLabel() );
1 ignored issue
show
The method getLabel() does not exist on Aimeos\MShop\Common\Item\Iface. It seems like you code against a sub-type of Aimeos\MShop\Common\Item\Iface such as Aimeos\MShop\Product\Item\Iface or Aimeos\MShop\Service\Item\Iface or Aimeos\MShop\Locale\Item\Site\Iface or Aimeos\MShop\Customer\Item\Iface or Aimeos\MShop\Text\Item\Iface or Aimeos\MShop\Customer\Item\Group\Iface or Aimeos\MShop\Media\Item\Iface or Aimeos\MShop\Coupon\Item\Iface or Aimeos\MAdmin\Job\Item\Iface or Aimeos\MShop\Tag\Item\Iface or Aimeos\MShop\Common\Item\Type\Iface or Aimeos\MShop\Attribute\Item\Iface or Aimeos\MShop\Locale\Item\Language\Iface or Aimeos\MShop\Catalog\Item\Iface or Aimeos\MShop\Plugin\Item\Iface or Aimeos\MShop\Supplier\Item\Iface or Aimeos\MShop\Locale\Item\Currency\Iface or Aimeos\MShop\Attribute\Item\Standard or Aimeos\MShop\Catalog\Item\Standard or Aimeos\MShop\Customer\Item\Base or Aimeos\MShop\Plugin\Item\Standard or Aimeos\MShop\Tag\Item\Standard or Aimeos\MShop\Customer\Item\Group\Standard or Aimeos\MShop\Media\Item\Standard or Aimeos\MAdmin\Job\Item\Standard or Aimeos\MShop\Common\Item\Type\Standard or Aimeos\MShop\Locale\Item\Site\Standard or Aimeos\MShop\Locale\Item\Currency\Standard or Aimeos\MShop\Text\Item\Standard or Aimeos\MShop\Locale\Item\Language\Standard or Aimeos\MShop\Service\Item\Standard or Aimeos\MShop\Common\Item\ListRef\Base or Aimeos\MShop\Price\Item\Base or Aimeos\MShop\Supplier\Item\Standard or Aimeos\MShop\Coupon\Item\Standard or Aimeos\MShop\Product\Item\Standard or Aimeos\MShop\Product\Item\Iface or Aimeos\MShop\Service\Item\Iface or Aimeos\MShop\Customer\Item\Iface or Aimeos\MShop\Text\Item\Iface or Aimeos\MShop\Media\Item\Iface or Aimeos\MShop\Coupon\Item\Iface or Aimeos\MAdmin\Job\Item\Iface or Aimeos\MShop\Common\Item\Type\Iface or Aimeos\MShop\Attribute\Item\Iface or Aimeos\MShop\Locale\Item\Language\Iface or Aimeos\MShop\Common\Item\Tree\Iface or Aimeos\MShop\Plugin\Item\Iface or Aimeos\MShop\Supplier\Item\Iface or Aimeos\MShop\Locale\Item\Currency\Iface or Aimeos\MShop\Price\Item\Base or Aimeos\MShop\Price\Item\Base. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

218
			$stmt->bind( 1, $item->/** @scrutinizer ignore-call */ getLabel() );
Loading history...
219
			$stmt->bind( 2, $item->getStatus(), \Aimeos\MW\DB\Statement\Base::PARAM_INT );
220
			$stmt->bind( 3, $item->getSiteId(), \Aimeos\MW\DB\Statement\Base::PARAM_INT );
221
			$stmt->bind( 4, $date ); // mtime
222
			$stmt->bind( 5, $context->getEditor() );
223
			// code and ID are identical after saving and ID is the flag to detect updates or inserts
224
			$stmt->bind( 6, $item->getCode() );
225
226
			if( $id === null ) {
227
				$stmt->bind( 7, $date ); // ctime
228
			}
229
230
			$stmt->execute()->finish();
231
232
			$item->setId( $item->getCode() ); // set modified flag to false
233
234
			$dbm->release( $conn, $dbname );
235
		}
236
		catch( \Exception $e )
237
		{
238
			$dbm->release( $conn, $dbname );
239
			throw $e;
240
		}
241
242
		return $item;
243
	}
244
245
246
	/**
247
	 * Removes multiple items specified by ids in the array.
248
	 *
249
	 * @param array $ids List of IDs
250
	 */
251
	public function deleteItems( array $ids )
252
	{
253
		/** mshop/locale/manager/language/standard/delete/mysql
254
		 * Deletes the items matched by the given IDs from the database
255
		 *
256
		 * @see mshop/locale/manager/language/standard/delete/ansi
257
		 */
258
259
		/** mshop/locale/manager/language/standard/delete/ansi
260
		 * Deletes the items matched by the given IDs from the database
261
		 *
262
		 * Removes the language records specified by the given IDs from the
263
		 * locale database. The records must be from the site that is configured
264
		 * via the context item.
265
		 *
266
		 * The ":cond" placeholder is replaced by the name of the ID column and
267
		 * the given ID or list of IDs while the site ID is bound to the question
268
		 * mark.
269
		 *
270
		 * The SQL statement should conform to the ANSI standard to be
271
		 * compatible with most relational database systems. This also
272
		 * includes using double quotes for table and column names.
273
		 *
274
		 * @param string SQL statement for deleting items
275
		 * @since 2014.03
276
		 * @category Developer
277
		 * @see mshop/locale/manager/language/standard/insert/ansi
278
		 * @see mshop/locale/manager/language/standard/update/ansi
279
		 * @see mshop/locale/manager/language/standard/search/ansi
280
		 * @see mshop/locale/manager/language/standard/count/ansi
281
		 */
282
		$path = 'mshop/locale/manager/language/standard/delete';
283
		$this->deleteItemsBase( $ids, $path );
284
	}
285
286
287
	/**
288
	 * Create a Language object from a given Language ID/Key.
289
	 *
290
	 * @param string $id Language id to create the Language object
291
	 * @param string[] $ref List of domains to fetch list items and referenced items for
292
	 * @return \Aimeos\MShop\Locale\Item\Language\Iface Returns the language item of the given id
293
	 * @param boolean $default Add default criteria
294
	 * @throws \Aimeos\MW\DB\Exception If language object couldn't be fetched
295
	 * @throws \Aimeos\MShop\Exception If item couldn't be found
296
	 */
297
	public function getItem( $id, array $ref = [], $default = false )
298
	{
299
		return $this->getItemBase( 'locale.language.id', $id, $ref, $default );
300
	}
301
302
303
	/**
304
	 * Returns the available manager types
305
	 *
306
	 * @param boolean $withsub Return also the resource type of sub-managers if true
307
	 * @return array Type of the manager and submanagers, subtypes are separated by slashes
308
	 */
309
	public function getResourceType( $withsub = true )
310
	{
311
		$path = 'mshop/locale/manager/language/submanagers';
312
313
		return $this->getResourceTypeBase( 'locale/language', $path, [], $withsub );
314
	}
315
316
317
	/**
318
	 * Returns the attributes that can be used for searching.
319
	 *
320
	 * @param boolean $withsub Return also attributes of sub-managers if true
321
	 * @return array List of attribute items implementing \Aimeos\MW\Criteria\Attribute\Iface
322
	 */
323
	public function getSearchAttributes( $withsub = true )
324
	{
325
		/** mshop/locale/manager/language/submanagers
326
		 * List of manager names that can be instantiated by the locale language manager
327
		 *
328
		 * Managers provide a generic interface to the underlying storage.
329
		 * Each manager has or can have sub-managers caring about particular
330
		 * aspects. Each of these sub-managers can be instantiated by its
331
		 * parent manager using the getSubManager() method.
332
		 *
333
		 * The search keys from sub-managers can be normally used in the
334
		 * manager as well. It allows you to search for items of the manager
335
		 * using the search keys of the sub-managers to further limit the
336
		 * retrieved list of items.
337
		 *
338
		 * @param array List of sub-manager names
339
		 * @since 2014.03
340
		 * @category Developer
341
		 */
342
		$path = 'mshop/locale/manager/language/submanagers';
343
344
		return $this->getSearchAttributesBase( $this->searchConfig, $path, [], $withsub );
345
	}
346
347
348
	/**
349
	 * Returns a new sub manager of the given type and name.
350
	 *
351
	 * @param string $manager Name of the sub manager type in lower case
352
	 * @param string|null $name Name of the implementation, will be from configuration (or Default) if null
353
	 * @return \Aimeos\MShop\Locale\Manager\Iface manager
354
	 */
355
	public function getSubManager( $manager, $name = null )
356
	{
357
		/** mshop/locale/manager/language/name
358
		 * Class name of the used locale language manager implementation
359
		 *
360
		 * Each default locale language manager can be replaced by an alternative imlementation.
361
		 * To use this implementation, you have to set the last part of the class
362
		 * name as configuration value so the manager factory knows which class it
363
		 * has to instantiate.
364
		 *
365
		 * For example, if the name of the default class is
366
		 *
367
		 *  \Aimeos\MShop\Locale\Manager\Language\Standard
368
		 *
369
		 * and you want to replace it with your own version named
370
		 *
371
		 *  \Aimeos\MShop\Locale\Manager\Language\Mylanguage
372
		 *
373
		 * then you have to set the this configuration option:
374
		 *
375
		 *  mshop/locale/manager/language/name = Mylanguage
376
		 *
377
		 * The value is the last part of your own class name and it's case sensitive,
378
		 * so take care that the configuration value is exactly named like the last
379
		 * part of the class name.
380
		 *
381
		 * The allowed characters of the class name are A-Z, a-z and 0-9. No other
382
		 * characters are possible! You should always start the last part of the class
383
		 * name with an upper case character and continue only with lower case characters
384
		 * or numbers. Avoid chamel case names like "MyLanguage"!
385
		 *
386
		 * @param string Last part of the class name
387
		 * @since 2014.03
388
		 * @category Developer
389
		 */
390
391
		/** mshop/locale/manager/language/decorators/excludes
392
		 * Excludes decorators added by the "common" option from the locale language manager
393
		 *
394
		 * Decorators extend the functionality of a class by adding new aspects
395
		 * (e.g. log what is currently done), executing the methods of the underlying
396
		 * class only in certain conditions (e.g. only for logged in users) or
397
		 * modify what is returned to the caller.
398
		 *
399
		 * This option allows you to remove a decorator added via
400
		 * "mshop/common/manager/decorators/default" before they are wrapped
401
		 * around the locale language manager.
402
		 *
403
		 *  mshop/locale/manager/language/decorators/excludes = array( 'decorator1' )
404
		 *
405
		 * This would remove the decorator named "decorator1" from the list of
406
		 * common decorators ("\Aimeos\MShop\Common\Manager\Decorator\*") added via
407
		 * "mshop/common/manager/decorators/default" for the locale language manager.
408
		 *
409
		 * @param array List of decorator names
410
		 * @since 2014.03
411
		 * @category Developer
412
		 * @see mshop/common/manager/decorators/default
413
		 * @see mshop/locale/manager/language/decorators/global
414
		 * @see mshop/locale/manager/language/decorators/local
415
		 */
416
417
		/** mshop/locale/manager/language/decorators/global
418
		 * Adds a list of globally available decorators only to the locale language manager
419
		 *
420
		 * Decorators extend the functionality of a class by adding new aspects
421
		 * (e.g. log what is currently done), executing the methods of the underlying
422
		 * class only in certain conditions (e.g. only for logged in users) or
423
		 * modify what is returned to the caller.
424
		 *
425
		 * This option allows you to wrap global decorators
426
		 * ("\Aimeos\MShop\Common\Manager\Decorator\*") around the locale language
427
		 * manager.
428
		 *
429
		 *  mshop/locale/manager/language/decorators/global = array( 'decorator1' )
430
		 *
431
		 * This would add the decorator named "decorator1" defined by
432
		 * "\Aimeos\MShop\Common\Manager\Decorator\Decorator1" only to the locale
433
		 * language manager.
434
		 *
435
		 * @param array List of decorator names
436
		 * @since 2014.03
437
		 * @category Developer
438
		 * @see mshop/common/manager/decorators/default
439
		 * @see mshop/locale/manager/language/decorators/excludes
440
		 * @see mshop/locale/manager/language/decorators/local
441
		 */
442
443
		/** mshop/locale/manager/language/decorators/local
444
		 * Adds a list of local decorators only to the locale language manager
445
		 *
446
		 * Decorators extend the functionality of a class by adding new aspects
447
		 * (e.g. log what is currently done), executing the methods of the underlying
448
		 * class only in certain conditions (e.g. only for logged in users) or
449
		 * modify what is returned to the caller.
450
		 *
451
		 * This option allows you to wrap local decorators
452
		 * ("\Aimeos\MShop\Locale\Manager\Language\Decorator\*") around the locale
453
		 * language manager.
454
		 *
455
		 *  mshop/locale/manager/language/decorators/local = array( 'decorator2' )
456
		 *
457
		 * This would add the decorator named "decorator2" defined by
458
		 * "\Aimeos\MShop\Locale\Manager\Language\Decorator\Decorator2" only to the
459
		 * locale language manager.
460
		 *
461
		 * @param array List of decorator names
462
		 * @since 2014.03
463
		 * @category Developer
464
		 * @see mshop/common/manager/decorators/default
465
		 * @see mshop/locale/manager/language/decorators/excludes
466
		 * @see mshop/locale/manager/language/decorators/global
467
		 */
468
469
		return $this->getSubManagerBase( 'locale', 'language/' . $manager, $name );
470
	}
471
472
473
	/**
474
	 * Returns the item specified by its code and domain/type if necessary
475
	 *
476
	 * @param string $code Code of the item
477
	 * @param string[] $ref List of domains to fetch list items and referenced items for
478
	 * @param string|null $domain Domain of the item if necessary to identify the item uniquely
479
	 * @param string|null $type Type code of the item if necessary to identify the item uniquely
480
	 * @param boolean $default True to add default criteria
481
	 * @return \Aimeos\MShop\Common\Item\Iface Item object
482
	 */
483
	public function findItem( $code, array $ref = [], $domain = null, $type = null, $default = false )
484
	{
485
		return $this->findItemBase( array( 'locale.language.id' => $code ), $ref, $default );
486
	}
487
488
489
	/**
490
	 * Searches for language items matching the given criteria.
491
	 *
492
	 * @param \Aimeos\MW\Criteria\Iface $search Search criteria object
493
	 * @param string[] $ref List of domains to fetch list items and referenced items for
494
	 * @param integer|null &$total Number of items that are available in total
495
	 * @return array List of items implementing \Aimeos\MShop\Locale\Language\Item\Iface
496
	 */
497
	public function searchItems( \Aimeos\MW\Criteria\Iface $search, array $ref = [], &$total = null )
498
	{
499
		$items = [];
500
		$context = $this->getContext();
501
502
		$dbm = $context->getDatabaseManager();
503
		$dbname = $this->getResourceName();
504
		$conn = $dbm->acquire( $dbname );
505
506
		try
507
		{
508
			$attributes = $this->getObject()->getSearchAttributes();
509
			$types = $this->getSearchTypes( $attributes );
510
			$translations = $this->getSearchTranslations( $attributes );
511
			$columns = $search->translate( $search->getSortations(), $translations );
512
513
			$find = array( ':cond', ':order', ':columns', ':start', ':size' );
514
			$replace = array(
515
				$search->getConditionSource( $types, $translations ),
516
				$search->getSortationSource( $types, $translations ),
517
				( $columns ? ', ' . implode( ',', $columns ) : '' ),
518
				$search->getSliceStart(),
519
				$search->getSliceSize(),
520
			);
521
522
			/** mshop/locale/manager/language/standard/search/mysql
523
			 * Retrieves the records matched by the given criteria in the database
524
			 *
525
			 * @see mshop/locale/manager/language/standard/search/ansi
526
			 */
527
528
			/** mshop/locale/manager/language/standard/search/ansi
529
			 * Retrieves the records matched by the given criteria in the database
530
			 *
531
			 * Fetches the records matched by the given criteria from the attribute
532
			 * database. The records must be from one of the sites that are
533
			 * configured via the context item. If the current site is part of
534
			 * a tree of sites, the SELECT statement can retrieve all records
535
			 * from the current site and the complete sub-tree of sites.
536
			 *
537
			 * As the records can normally be limited by criteria from sub-managers,
538
			 * their tables must be joined in the SQL context. This is done by
539
			 * using the "internaldeps" property from the definition of the ID
540
			 * column of the sub-managers. These internal dependencies specify
541
			 * the JOIN between the tables and the used columns for joining. The
542
			 * ":joins" placeholder is then replaced by the JOIN strings from
543
			 * the sub-managers.
544
			 *
545
			 * To limit the records matched, conditions can be added to the given
546
			 * criteria object. It can contain comparisons like column names that
547
			 * must match specific values which can be combined by AND, OR or NOT
548
			 * operators. The resulting string of SQL conditions replaces the
549
			 * ":cond" placeholder before the statement is sent to the database
550
			 * server.
551
			 *
552
			 * If the records that are retrieved should be ordered by one or more
553
			 * columns, the generated string of column / sort direction pairs
554
			 * replaces the ":order" placeholder. In case no ordering is required,
555
			 * the complete ORDER BY part including the "\/*-orderby*\/...\/*orderby-*\/"
556
			 * markers is removed to speed up retrieving the records. Columns of
557
			 * sub-managers can also be used for ordering the result set but then
558
			 * no index can be used.
559
			 *
560
			 * The number of returned records can be limited and can start at any
561
			 * number between the begining and the end of the result set. For that
562
			 * the ":size" and ":start" placeholders are replaced by the
563
			 * corresponding values from the criteria object. The default values
564
			 * are 0 for the start and 100 for the size value.
565
			 *
566
			 * The SQL statement should conform to the ANSI standard to be
567
			 * compatible with most relational database systems. This also
568
			 * includes using double quotes for table and column names.
569
			 *
570
			 * @param string SQL statement for searching items
571
			 * @since 2014.03
572
			 * @category Developer
573
			 * @see mshop/locale/manager/language/standard/insert/ansi
574
			 * @see mshop/locale/manager/language/standard/update/ansi
575
			 * @see mshop/locale/manager/language/standard/delete/ansi
576
			 * @see mshop/locale/manager/language/standard/count/ansi
577
			 */
578
			$path = 'mshop/locale/manager/language/standard/search';
579
580
			$sql = $this->getSqlConfig( $path );
581
			$results = $this->getSearchResults( $conn, str_replace( $find, $replace, $sql ) );
582
583
			try
584
			{
585
				while( ( $row = $results->fetch() ) !== false ) {
586
					$items[$row['locale.language.id']] = $this->createItemBase( $row );
587
				}
588
			}
589
			catch( \Exception $e )
590
			{
591
				$results->finish();
592
				throw $e;
593
			}
594
595
			if( $total !== null ) {
596
				$total = $this->getTotal( $conn, $find, $replace );
597
			}
598
599
			$dbm->release( $conn, $dbname );
600
		}
601
		catch( \Exception $e )
602
		{
603
			$dbm->release( $conn, $dbname );
604
			throw $e;
605
		}
606
607
		return $items;
608
	}
609
610
611
	/**
612
	 * Creates a search object and sets base criteria.
613
	 *
614
	 * @param boolean $default
615
	 * @return \Aimeos\MW\Criteria\Iface
616
	 */
617
	public function createSearch( $default = false )
618
	{
619
		if( $default === true ) {
620
			return $this->createSearchBase( 'locale.language' );
621
		}
622
623
		return parent::createSearch();
624
	}
625
626
627
	/**
628
	 * Returns the search results for the given SQL statement.
629
	 *
630
	 * @param \Aimeos\MW\DB\Connection\Iface $conn Database connection
631
	 * @param string $sql SQL statement
632
	 * @return \Aimeos\MW\DB\Result\Iface Search result object
633
	 */
634
	protected function getSearchResults( \Aimeos\MW\DB\Connection\Iface $conn, $sql )
635
	{
636
		$time = microtime( true );
637
638
		$stmt = $conn->create( $sql );
639
		$result = $stmt->execute();
640
641
		$msg = [
642
			'time' => ( microtime( true ) - $time ) * 1000,
643
			'class' => get_class( $this ),
644
			'stmt' => (string) $stmt,
645
		];
646
		$this->getContext()->getLogger()->log( $msg, \Aimeos\MW\Logger\Base::DEBUG, 'core/sql' );
647
648
		return $result;
649
	}
650
651
652
	/**
653
	 * Create new item object initialized with given parameters.
654
	 *
655
	 * @param array $data Associative list of item key/value pairs
656
	 * @return \Aimeos\MShop\Locale\Item\Language\Iface Language item
657
	 */
658
	protected function createItemBase( array $data = [] )
659
	{
660
		return new \Aimeos\MShop\Locale\Item\Language\Standard( $data );
661
	}
662
663
664
	/**
665
	 * Returns the total number of items found for the conditions
666
	 *
667
	 * @param \Aimeos\MW\DB\Connection\Iface $conn Database connection
668
	 * @param array $find List of markers that should be replaced in the SQL statement
669
	 * @param array $replace List of replacements for the markers in the SQL statement
670
	 * @throws \Aimeos\MShop\Locale\Exception If no total value was found
671
	 * @return integer Total number of found items
672
	 */
673
	protected function getTotal( \Aimeos\MW\DB\Connection\Iface $conn, array $find, array $replace )
674
	{
675
		/** mshop/locale/manager/language/standard/count/mysql
676
		 * Counts the number of records matched by the given criteria in the database
677
		 *
678
		 * @see mshop/locale/manager/language/standard/count/ansi
679
		 */
680
681
		/** mshop/locale/manager/language/standard/count/ansi
682
		 * Counts the number of records matched by the given criteria in the database
683
		 *
684
		 * Counts all records matched by the given criteria from the attribute
685
		 * database. The records must be from one of the sites that are
686
		 * configured via the context item. If the current site is part of
687
		 * a tree of sites, the statement can count all records from the
688
		 * current site and the complete sub-tree of sites.
689
		 *
690
		 * As the records can normally be limited by criteria from sub-managers,
691
		 * their tables must be joined in the SQL context. This is done by
692
		 * using the "internaldeps" property from the definition of the ID
693
		 * column of the sub-managers. These internal dependencies specify
694
		 * the JOIN between the tables and the used columns for joining. The
695
		 * ":joins" placeholder is then replaced by the JOIN strings from
696
		 * the sub-managers.
697
		 *
698
		 * To limit the records matched, conditions can be added to the given
699
		 * criteria object. It can contain comparisons like column names that
700
		 * must match specific values which can be combined by AND, OR or NOT
701
		 * operators. The resulting string of SQL conditions replaces the
702
		 * ":cond" placeholder before the statement is sent to the database
703
		 * server.
704
		 *
705
		 * Both, the strings for ":joins" and for ":cond" are the same as for
706
		 * the "search" SQL statement.
707
		 *
708
		 * Contrary to the "search" statement, it doesn't return any records
709
		 * but instead the number of records that have been found. As counting
710
		 * thousands of records can be a long running task, the maximum number
711
		 * of counted records is limited for performance reasons.
712
		 *
713
		 * The SQL statement should conform to the ANSI standard to be
714
		 * compatible with most relational database systems. This also
715
		 * includes using double quotes for table and column names.
716
		 *
717
		 * @param string SQL statement for counting items
718
		 * @since 2014.03
719
		 * @category Developer
720
		 * @see mshop/locale/manager/language/standard/insert/ansi
721
		 * @see mshop/locale/manager/language/standard/update/ansi
722
		 * @see mshop/locale/manager/language/standard/delete/ansi
723
		 * @see mshop/locale/manager/language/standard/search/ansi
724
		 */
725
		$path = 'mshop/locale/manager/language/standard/count';
726
727
		$sql = $this->getSqlConfig( $path );
728
		$results = $this->getSearchResults( $conn, str_replace( $find, $replace, $sql ) );
729
730
		$row = $results->fetch();
731
		$results->finish();
732
733
		if( $row === false ) {
734
			throw new \Aimeos\MShop\Locale\Exception( 'No total results value found' );
735
		}
736
737
		return $row['count'];
738
	}
739
}
740