Passed
Pull Request — master (#297)
by Aimeos
10:30
created

StandardTest::testSearchItemsBase()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 9
c 1
b 0
f 0
dl 0
loc 13
rs 9.9666
cc 2
nc 2
nop 0
1
<?php
2
3
/**
4
 * @license LGPLv3, https://opensource.org/licenses/LGPL-3.0
5
 * @copyright Metaways Infosystems GmbH, 2011
6
 * @copyright Aimeos (aimeos.org), 2015-2022
7
 */
8
9
10
namespace Aimeos\MShop\Index\Manager;
11
12
13
class StandardTest extends \PHPUnit\Framework\TestCase
14
{
15
	private static $products;
16
	private $context;
17
	private $object;
18
19
20
	public static function setUpBeforeClass() : void
21
	{
22
		$context = \TestHelper::context();
23
24
		$manager = new \Aimeos\MShop\Index\Manager\Standard( $context );
25
		$productManager = \Aimeos\MShop::create( $context, 'product' );
26
27
		$search = $productManager->filter()->add( ['product.code' => ['CNC', 'CNE']] );
28
		$result = $productManager->search( $search, ['attribute', 'price', 'text', 'product'] );
29
30
		if( count( $result ) !== 2 ) {
31
			throw new \RuntimeException( 'Products not available' );
32
		}
33
34
		foreach( $result as $item )
35
		{
36
			self::$products[$item->getCode()] = $item;
37
			$manager->save( $item );
38
		}
39
	}
40
41
42
	protected function setUp() : void
43
	{
44
		$this->context = \TestHelper::context();
45
		$this->object = new \Aimeos\MShop\Index\Manager\Standard( $this->context );
46
	}
47
48
49
	protected function tearDown() : void
50
	{
51
		unset( $this->object, $this->context );
52
	}
53
54
55
	public function testCreateItem()
56
	{
57
		$this->assertInstanceOf( \Aimeos\MShop\Product\Item\Iface::class, $this->object->create() );
58
	}
59
60
61
	public function testCreateSearch()
62
	{
63
		$this->assertInstanceOf( \Aimeos\Base\Criteria\Iface::class, $this->object->filter() );
64
	}
65
66
67
	public function testAggregate()
68
	{
69
		$id = \Aimeos\MShop::create( \TestHelper::context(), 'attribute' )
70
			->find( 'white', [], 'product', 'color' )->getId();
71
72
		$search = $this->object->filter( true )->add( ['index.catalog.id' => null], '!=' );
73
		$result = $this->object->aggregate( $search, 'index.attribute.id' )->toArray();
74
75
		$this->assertEquals( 14, count( $result ) );
76
		$this->assertArrayHasKey( $id, $result );
77
		$this->assertEquals( 4, $result[$id] );
78
	}
79
80
81
	public function testAggregateMultiple()
82
	{
83
		$id = \Aimeos\MShop::create( \TestHelper::context(), 'attribute' )
84
			->find( 'white', [], 'product', 'color' )->getId();
85
86
		$search = $this->object->filter( true )->add( ['index.catalog.id' => null], '!=' );
87
		$result = $this->object->aggregate( $search, ['product.status', 'index.attribute.id'] )->toArray();
88
89
		$this->assertEquals( 14, count( $result[1] ) );
90
		$this->assertArrayHasKey( $id, $result[1] );
91
		$this->assertEquals( 4, $result[1][$id] );
92
	}
93
94
95
	public function testAggregateMax()
96
	{
97
		$search = $this->object->filter( true );
98
		$search->add( $search->is( $search->make( 'index.price:value', ['EUR'] ), '!=', null ) );
99
100
		$result = $this->object->aggregate( $search, 'product.status', 'agg:index.price:value("EUR")', 'max' )->max();
101
102
		$this->assertEquals( 600, $result );
103
	}
104
105
106
	public function testAggregateMin()
107
	{
108
		$search = $this->object->filter( true );
109
		$search->add( $search->is( $search->make( 'index.price:value', ['EUR'] ), '!=', null ) );
110
111
		$result = $this->object->aggregate( $search, 'product.status', 'agg:index.price:value("EUR")', 'min' )->min();
112
113
		$this->assertEquals( 12, $result );
114
	}
115
116
117
	public function testDeleteItems()
118
	{
119
		$this->assertEquals( $this->object, $this->object->delete( [-1] ) );
120
	}
121
122
123
	public function testFindItem()
124
	{
125
		$product = \Aimeos\MShop::create( $this->context, 'product' )->find( 'CNE' );
126
127
		$this->assertEquals( $product, $this->object->find( 'CNE' ) );
128
	}
129
130
131
	public function testGetItem()
132
	{
133
		$product = \Aimeos\MShop::create( $this->context, 'product' )->find( 'CNE' );
134
135
		$item = $this->object->get( $product->getId() );
136
		$this->assertEquals( $product, $item );
137
	}
138
139
140
	public function testGetResourceType()
141
	{
142
		$result = $this->object->getResourceType();
143
144
		$this->assertContains( 'index', $result );
145
		$this->assertContains( 'index/attribute', $result );
146
		$this->assertContains( 'index/supplier', $result );
147
		$this->assertContains( 'index/catalog', $result );
148
		$this->assertContains( 'index/price', $result );
149
		$this->assertContains( 'index/text', $result );
150
	}
151
152
153
	public function testGetSearchAttributes()
154
	{
155
		$attributes = $this->object->getSearchAttributes();
156
157
		foreach( $attributes as $attribute ) {
158
			$this->assertInstanceOf( \Aimeos\Base\Criteria\Attribute\Iface::class, $attribute );
159
		}
160
161
		$this->assertArrayHasKey( 'index.attribute.id', $attributes );
162
		$this->assertArrayHasKey( 'index.catalog.id', $attributes );
163
		$this->assertArrayHasKey( 'index.supplier.id', $attributes );
164
	}
165
166
167
	public function testIterate()
168
	{
169
		$iterator = $this->object->iterator( $this->object->filter( true )->add( 'index.catalog.id', '!=', null ) );
170
		$products = $this->object->iterate( $iterator, [], 10 );
171
172
		$this->assertEquals( 8, count( $products ) );
173
174
		foreach( $products as $itemId => $item ) {
175
			$this->assertEquals( $itemId, $item->getId() );
176
		}
177
	}
178
179
180
	public function testSave()
181
	{
182
		$item = self::$products['CNE'];
183
184
		$context = $this->context;
185
		$conn = $context->db( 'db-index' );
186
		$siteId = $context->locale()->getSiteId();
187
188
		$sqlAttribute = 'SELECT COUNT(*) as count FROM "mshop_index_attribute" WHERE "siteid" = ? AND "prodid" = ?';
189
		$sqlCatalog = 'SELECT COUNT(*) as count FROM "mshop_index_catalog" WHERE "siteid" = ? AND "prodid" = ?';
190
		$sqlPrice = 'SELECT COUNT(*) as count FROM "mshop_index_price" WHERE "siteid" = ? AND "prodid" = ?';
191
		$sqlText = 'SELECT COUNT(*) as count FROM "mshop_index_text" WHERE "siteid" = ? AND "prodid" = ?';
192
193
		$this->object->save( $item );
194
195
		$cntAttribute = $this->getValue( $conn, $sqlAttribute, 'count', $siteId, $item->getId() );
196
		$cntCatalog = $this->getValue( $conn, $sqlCatalog, 'count', $siteId, $item->getId() );
197
		$cntPrice = $this->getValue( $conn, $sqlPrice, 'count', $siteId, $item->getId() );
198
		$cntText = $this->getValue( $conn, $sqlText, 'count', $siteId, $item->getId() );
199
200
		$this->assertEquals( 6, $cntAttribute );
201
		$this->assertEquals( 5, $cntCatalog );
202
		$this->assertEquals( 1, $cntPrice );
203
		$this->assertEquals( 2, $cntText );
204
	}
205
206
207
	public function testSaveMultiple()
208
	{
209
		$result = $this->object->save( self::$products );
210
		$expected = [
211
			'CNC' => self::$products['CNC'],
212
			'CNE' => self::$products['CNE']
213
		];
214
		$this->assertEquals( $expected, $result );
215
	}
216
217
218
	public function testSearchItems()
219
	{
220
		$total = 0;
221
		$search = $this->object->filter();
222
		$search->slice( 0, 1 );
223
224
		$expr = array(
225
			$search->compare( '!=', 'index.catalog.id', null ),
226
			$search->compare( '=~', 'product.label', 'Cafe Noire' ),
227
		);
228
		$search->setConditions( $search->and( $expr ) );
229
230
		$result = $this->object->search( $search, [], $total )->toArray();
231
232
		$this->assertEquals( 1, count( $result ) );
233
		$this->assertEquals( 2, $total );
234
	}
235
236
237
	public function testSearchItemsBase()
238
	{
239
		$search = $this->object->filter( true );
240
		$conditions = array(
241
			$search->compare( '!=', 'index.catalog.id', null ),
242
			$search->getConditions()
243
		);
244
		$search->setConditions( $search->and( $conditions ) );
245
		$products = $this->object->search( $search )->toArray();
246
		$this->assertEquals( 8, count( $products ) );
247
248
		foreach( $products as $itemId => $item ) {
249
			$this->assertEquals( $itemId, $item->getId() );
250
		}
251
	}
252
253
254
	public function testSearchItemsSub()
255
	{
256
		$total = 0;
257
		$search = $this->object->filter();
258
		$search->slice( 0, 1 );
259
260
		$expr = array(
261
			$search->compare( '!=', 'index.attribute.id', null ),
262
			$search->compare( '!=', 'index.catalog.id', null ),
263
			$search->compare( '!=', 'index.supplier.id', null ),
264
			$search->compare( '>=', $search->make( 'index.price:value', ['EUR'] ), 0 ),
265
			$search->compare( '>=', $search->make( 'index.text:name', ['de'] ), '' ),
266
		);
267
268
		$search->setConditions( $search->and( $expr ) );
269
		$result = $this->object->search( $search, [], $total )->toArray();
270
271
		$this->assertEquals( 1, count( $result ) );
272
		$this->assertEquals( 2, $total );
273
	}
274
275
276
	public function testOptimize()
277
	{
278
		$this->assertInstanceOf( \Aimeos\MShop\Index\Manager\Iface::class, $this->object->optimize() );
279
	}
280
281
282
	public function testCleanup()
283
	{
284
		$this->assertInstanceOf( \Aimeos\MShop\Index\Manager\Iface::class, $this->object->cleanup( '1970-01-01 00:00:00' ) );
285
	}
286
287
288
	public function testRate()
289
	{
290
		$this->assertEquals( $this->object, $this->object->rate( -1, 0, 0 ) );
291
	}
292
293
294
	public function testRebuildWithList()
295
	{
296
		$manager = \Aimeos\MShop::create( $this->context, 'product' );
297
		$search = $manager->filter();
0 ignored issues
show
Unused Code introduced by
The assignment to $search is dead and can be removed.
Loading history...
298
299
		$search = $manager->filter();
300
		$search->setConditions( $search->compare( '==', 'product.code', array( 'CNE', 'CNC' ) ) );
301
		$items = $manager->search( $search )->toArray();
302
303
		$this->object->cleanup( date( 'Y-m-d H:i:s', time() + 1 ) )->rebuild( $items );
304
305
		$afterInsertAttr = $this->getCatalogSubDomainItems( 'index.attribute.id', 'attribute' );
306
		$afterInsertCat = $this->getCatalogSubDomainItems( 'index.catalog.id', 'catalog' );
307
308
		$this->assertEquals( 2, count( $afterInsertAttr ) );
309
		$this->assertEquals( 2, count( $afterInsertCat ) );
310
	}
311
312
313
	public function testRebuild()
314
	{
315
		$this->object->cleanup( date( 'Y-m-d H:i:s', time() + 1 ) )->rebuild();
316
317
		$afterInsertAttr = $this->getCatalogSubDomainItems( 'index.attribute.id', 'attribute' );
318
		$afterInsertCat = $this->getCatalogSubDomainItems( 'index.catalog.id', 'catalog' );
319
320
		$this->assertEquals( 15, count( $afterInsertAttr ) );
321
		$this->assertEquals( 9, count( $afterInsertCat ) );
322
	}
323
324
325
	public function testRemove()
326
	{
327
		$this->assertEquals( $this->object, $this->object->remove( [-1] ) );
328
	}
329
330
331
	public function testStock()
332
	{
333
		$this->assertEquals( $this->object, $this->object->stock( -1, 0 ) );
334
	}
335
336
337
	/**
338
	 * Returns value of a catalog_index column.
339
	 *
340
	 * @param \Aimeos\Base\DB\Connection\Iface $conn Database connection
341
	 * @param string $sql Specified db query to find only one value
342
	 * @param string $column Column where to search
343
	 * @param string $siteId Siteid of the db entry
344
	 * @param string $productId Product id
345
	 * @return string $value Value returned for specified sql statement
346
	 * @throws \Exception If column not available or error during a connection to db
347
	 */
348
	protected function getValue( \Aimeos\Base\DB\Connection\Iface $conn, $sql, $column, $siteId, $productId )
349
	{
350
		$stmt = $conn->create( $sql );
351
		$stmt->bind( 1, $siteId, \Aimeos\Base\DB\Statement\Base::PARAM_INT );
352
		$stmt->bind( 2, $productId, \Aimeos\Base\DB\Statement\Base::PARAM_INT );
353
		$result = $stmt->execute();
354
355
		if( ( $row = $result->fetch() ) === null ) {
356
			throw new \RuntimeException( 'No rows available' );
357
		}
358
359
		if( !isset( $row[$column] ) ) {
360
			throw new \RuntimeException( sprintf( 'Column "%1$s" not available for "%2$s"', $column, $sql ) );
361
		}
362
363
		return $row[$column];
364
	}
365
366
367
	/**
368
	 * Gets product items of index subdomains specified by the key.
369
	 *
370
	 * @param string $key Key for searchItems
371
	 * @param string $domain Subdomain of index manager
372
	 */
373
	protected function getCatalogSubDomainItems( $key, $domain )
374
	{
375
		$subIndex = $this->object->getSubManager( $domain );
376
		$search = $subIndex->filter();
377
378
		$expr = array(
379
			$search->compare( '!=', $key, null ),
380
		);
381
382
		$search->setConditions( $search->and( $expr ) );
383
384
		return $subIndex->search( $search )->toArray();
385
	}
386
387
}
388