1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/* |
4
|
|
|
* This file is part of the Sylius package. |
5
|
|
|
* |
6
|
|
|
* (c) Paweł Jędrzejewski |
7
|
|
|
* |
8
|
|
|
* For the full copyright and license information, please view the LICENSE |
9
|
|
|
* file that was distributed with this source code. |
10
|
|
|
*/ |
11
|
|
|
|
12
|
|
|
namespace Sylius\Behat\Context\Ui\Shop; |
13
|
|
|
|
14
|
|
|
use Behat\Behat\Context\Context; |
15
|
|
|
use Behat\Mink\Element\NodeElement; |
16
|
|
|
use Sylius\Behat\Page\Shop\Product\ShowPageInterface; |
17
|
|
|
use Sylius\Behat\Page\Shop\ProductReview\IndexPageInterface; |
18
|
|
|
use Sylius\Behat\Page\Shop\Taxon\ShowPageInterface as TaxonShowPageInterface; |
19
|
|
|
use Sylius\Component\Core\Model\ProductInterface; |
20
|
|
|
use Sylius\Component\Core\Model\TaxonInterface; |
21
|
|
|
use Webmozart\Assert\Assert; |
22
|
|
|
|
23
|
|
|
/** |
24
|
|
|
* @author Kamil Kokot <[email protected]> |
25
|
|
|
* @author Magdalena Banasiak <[email protected]> |
26
|
|
|
* @author Anna Walasek <[email protected]> |
27
|
|
|
*/ |
28
|
|
|
final class ProductContext implements Context |
29
|
|
|
{ |
30
|
|
|
/** |
31
|
|
|
* @var ShowPageInterface |
32
|
|
|
*/ |
33
|
|
|
private $showPage; |
34
|
|
|
|
35
|
|
|
/** |
36
|
|
|
* @var TaxonShowPageInterface |
37
|
|
|
*/ |
38
|
|
|
private $taxonShowPage; |
39
|
|
|
|
40
|
|
|
/** |
41
|
|
|
* @var IndexPageInterface |
42
|
|
|
*/ |
43
|
|
|
private $productReviewsIndexPage; |
44
|
|
|
|
45
|
|
|
/** |
46
|
|
|
* @param ShowPageInterface $showPage |
47
|
|
|
* @param TaxonShowPageInterface $taxonShowPage |
48
|
|
|
* @param IndexPageInterface $productReviewsIndexPage |
49
|
|
|
*/ |
50
|
|
|
public function __construct( |
51
|
|
|
ShowPageInterface $showPage, |
52
|
|
|
TaxonShowPageInterface $taxonShowPage, |
53
|
|
|
IndexPageInterface $productReviewsIndexPage |
54
|
|
|
) { |
55
|
|
|
$this->showPage = $showPage; |
56
|
|
|
$this->taxonShowPage = $taxonShowPage; |
57
|
|
|
$this->productReviewsIndexPage = $productReviewsIndexPage; |
58
|
|
|
} |
59
|
|
|
|
60
|
|
|
/** |
61
|
|
|
* @Then I should be able to access product :product |
62
|
|
|
*/ |
63
|
|
|
public function iShouldBeAbleToAccessProduct(ProductInterface $product) |
64
|
|
|
{ |
65
|
|
|
$this->showPage->tryToOpen(['slug' => $product->getSlug()]); |
66
|
|
|
|
67
|
|
|
Assert::true( |
68
|
|
|
$this->showPage->isOpen(['slug' => $product->getSlug()]), |
69
|
|
|
'Product show page should be open, but it does not.' |
70
|
|
|
); |
71
|
|
|
} |
72
|
|
|
|
73
|
|
|
/** |
74
|
|
|
* @Then I should not be able to access product :product |
75
|
|
|
*/ |
76
|
|
|
public function iShouldNotBeAbleToAccessProduct(ProductInterface $product) |
77
|
|
|
{ |
78
|
|
|
$this->showPage->tryToOpen(['slug' => $product->getSlug()]); |
79
|
|
|
|
80
|
|
|
Assert::false( |
81
|
|
|
$this->showPage->isOpen(['slug' => $product->getSlug()]), |
82
|
|
|
'Product show page should not be open, but it does.' |
83
|
|
|
); |
84
|
|
|
} |
85
|
|
|
|
86
|
|
|
/** |
87
|
|
|
* @When /^I check (this product)'s details/ |
88
|
|
|
* @When I view product :product |
89
|
|
|
*/ |
90
|
|
|
public function iOpenProductPage(ProductInterface $product) |
91
|
|
|
{ |
92
|
|
|
$this->showPage->open(['slug' => $product->getSlug()]); |
93
|
|
|
} |
94
|
|
|
|
95
|
|
|
/** |
96
|
|
|
* @Given I should see the product name :name |
97
|
|
|
*/ |
98
|
|
|
public function iShouldSeeProductName($name) |
99
|
|
|
{ |
100
|
|
|
Assert::same( |
101
|
|
|
$name, |
102
|
|
|
$this->showPage->getName(), |
103
|
|
|
'Product should have name %2$s, but it has %s' |
104
|
|
|
); |
105
|
|
|
} |
106
|
|
|
|
107
|
|
|
/** |
108
|
|
|
* @When I open page :url |
109
|
|
|
*/ |
110
|
|
|
public function iOpenPage($url) |
111
|
|
|
{ |
112
|
|
|
$this->showPage->visit($url); |
113
|
|
|
} |
114
|
|
|
|
115
|
|
|
/** |
116
|
|
|
* @Then I should be on :product product detailed page |
117
|
|
|
* @Then I should still be on product :product page |
118
|
|
|
*/ |
119
|
|
|
public function iShouldBeOnProductDetailedPage(ProductInterface $product) |
120
|
|
|
{ |
121
|
|
|
Assert::true( |
122
|
|
|
$this->showPage->isOpen(['slug' => $product->getSlug()]), |
123
|
|
|
sprintf('Product %s show page should be open, but it does not.', $product->getName()) |
124
|
|
|
); |
125
|
|
|
} |
126
|
|
|
|
127
|
|
|
/** |
128
|
|
|
* @Then I should see the product attribute :attributeName with value :expectedAttribute |
129
|
|
|
*/ |
130
|
|
|
public function iShouldSeeTheProductAttributeWithValue($attributeName, $expectedAttribute) |
131
|
|
|
{ |
132
|
|
|
$certainAttribute = $this->showPage->getAttributeByName($attributeName); |
133
|
|
|
Assert::same( |
134
|
|
|
$certainAttribute, |
135
|
|
|
$expectedAttribute, |
136
|
|
|
sprintf( |
137
|
|
|
'Product should have attribute %s with value %s, but has %s.', |
138
|
|
|
$attributeName, |
139
|
|
|
$expectedAttribute, |
140
|
|
|
$certainAttribute |
141
|
|
|
) |
142
|
|
|
); |
143
|
|
|
} |
144
|
|
|
|
145
|
|
|
/** |
146
|
|
|
* @Then I should see :count attributes |
147
|
|
|
*/ |
148
|
|
|
public function iShouldSeeAttributes($count) |
149
|
|
|
{ |
150
|
|
|
$attributes = $this->getProductAttributes(); |
151
|
|
|
|
152
|
|
|
Assert::same( |
153
|
|
|
count($attributes), |
154
|
|
|
(int) $count, |
155
|
|
|
'Product should have %2$d attributes, but has %d instead.' |
156
|
|
|
); |
157
|
|
|
} |
158
|
|
|
|
159
|
|
|
/** |
160
|
|
|
* @Then the first attribute should be :name |
161
|
|
|
*/ |
162
|
|
|
public function theFirstAttributeShouldBe($name) |
163
|
|
|
{ |
164
|
|
|
$attributes = $this->getProductAttributes(); |
165
|
|
|
$firstAttribute = reset($attributes); |
166
|
|
|
|
167
|
|
|
Assert::same( |
168
|
|
|
$firstAttribute->getText(), |
169
|
|
|
$name, |
170
|
|
|
'Expected the first attribute to be %2$s, found %s instead.' |
171
|
|
|
); |
172
|
|
|
} |
173
|
|
|
|
174
|
|
|
/** |
175
|
|
|
* @Then the last attribute should be :name |
176
|
|
|
*/ |
177
|
|
|
public function theLastAttributeShouldBe($name) |
178
|
|
|
{ |
179
|
|
|
$attributes = $this->getProductAttributes(); |
180
|
|
|
$lastAttribute = end($attributes); |
181
|
|
|
|
182
|
|
|
Assert::same( |
183
|
|
|
$lastAttribute->getText(), |
184
|
|
|
$name, |
185
|
|
|
'Expected the first attribute to be %2$s, found %s instead.' |
186
|
|
|
); |
187
|
|
|
} |
188
|
|
|
|
189
|
|
|
/** |
190
|
|
|
* @When /^I browse products from (taxon "([^"]+)")$/ |
191
|
|
|
*/ |
192
|
|
|
public function iCheckListOfProductsForTaxon(TaxonInterface $taxon) |
193
|
|
|
{ |
194
|
|
|
$this->taxonShowPage->open(['slug' => $taxon->getSlug()]); |
195
|
|
|
} |
196
|
|
|
|
197
|
|
|
/** |
198
|
|
|
* @When I search for products with name :name |
199
|
|
|
*/ |
200
|
|
|
public function iSearchForProductsWithName($name) |
201
|
|
|
{ |
202
|
|
|
$this->taxonShowPage->search($name); |
203
|
|
|
} |
204
|
|
|
|
205
|
|
|
/** |
206
|
|
|
* @When I clear filter |
207
|
|
|
*/ |
208
|
|
|
public function iClearFilter() |
209
|
|
|
{ |
210
|
|
|
$this->taxonShowPage->clearFilter(); |
211
|
|
|
} |
212
|
|
|
|
213
|
|
|
/** |
214
|
|
|
* @Then I should see the product :productName |
215
|
|
|
*/ |
216
|
|
|
public function iShouldSeeProduct($productName) |
217
|
|
|
{ |
218
|
|
|
Assert::true( |
219
|
|
|
$this->taxonShowPage->isProductOnList($productName), |
220
|
|
|
sprintf("The product %s should appear on page, but it does not.", $productName) |
|
|
|
|
221
|
|
|
); |
222
|
|
|
} |
223
|
|
|
|
224
|
|
|
/** |
225
|
|
|
* @Then I should not see the product :productName |
226
|
|
|
*/ |
227
|
|
|
public function iShouldNotSeeProduct($productName) |
228
|
|
|
{ |
229
|
|
|
Assert::false( |
230
|
|
|
$this->taxonShowPage->isProductOnList($productName), |
231
|
|
|
sprintf("The product %s should not appear on page, but it does.", $productName) |
|
|
|
|
232
|
|
|
); |
233
|
|
|
} |
234
|
|
|
|
235
|
|
|
/** |
236
|
|
|
* @Then I should see empty list of products |
237
|
|
|
*/ |
238
|
|
|
public function iShouldSeeEmptyListOfProducts() |
239
|
|
|
{ |
240
|
|
|
Assert::true( |
241
|
|
|
$this->taxonShowPage->isEmpty(), |
242
|
|
|
'There should appear information about empty list of products, but it does not.' |
243
|
|
|
); |
244
|
|
|
} |
245
|
|
|
|
246
|
|
|
/** |
247
|
|
|
* @Then I should see that it is out of stock |
248
|
|
|
*/ |
249
|
|
|
public function iShouldSeeItIsOutOfStock() |
250
|
|
|
{ |
251
|
|
|
Assert::true( |
252
|
|
|
$this->showPage->isOutOfStock(), |
253
|
|
|
'Out of stock label should be visible.' |
254
|
|
|
); |
255
|
|
|
} |
256
|
|
|
|
257
|
|
|
/** |
258
|
|
|
* @Then I should be unable to add it to the cart |
259
|
|
|
*/ |
260
|
|
|
public function iShouldBeUnableToAddItToTheCart() |
261
|
|
|
{ |
262
|
|
|
Assert::false( |
263
|
|
|
$this->showPage->hasAddToCartButton(), |
264
|
|
|
'Add to cart button should not be visible.' |
265
|
|
|
); |
266
|
|
|
} |
267
|
|
|
|
268
|
|
|
/** |
269
|
|
|
* @Then the product price should be :price |
270
|
|
|
* @Then I should see the product price :price |
271
|
|
|
*/ |
272
|
|
|
public function iShouldSeeTheProductPrice($price) |
273
|
|
|
{ |
274
|
|
|
Assert::same( |
275
|
|
|
$price, |
276
|
|
|
$this->showPage->getPrice(), |
277
|
|
|
'Product should have price %2$s, but it has %s' |
278
|
|
|
); |
279
|
|
|
} |
280
|
|
|
|
281
|
|
|
/** |
282
|
|
|
* @When I set its :optionName to :optionValue |
283
|
|
|
*/ |
284
|
|
|
public function iSetItsOptionTo($optionName, $optionValue) |
285
|
|
|
{ |
286
|
|
|
$this->showPage->selectOption($optionName, $optionValue); |
287
|
|
|
} |
288
|
|
|
|
289
|
|
|
/** |
290
|
|
|
* @When I select :variantName variant |
291
|
|
|
*/ |
292
|
|
|
public function iSelectVariant($variantName) |
293
|
|
|
{ |
294
|
|
|
$this->showPage->selectVariant($variantName); |
295
|
|
|
} |
296
|
|
|
|
297
|
|
|
/** |
298
|
|
|
* @Then I should see the product :productName with price :productPrice |
299
|
|
|
*/ |
300
|
|
|
public function iShouldSeeTheProductWithPrice($productName, $productPrice) |
301
|
|
|
{ |
302
|
|
|
Assert::true( |
303
|
|
|
$this->taxonShowPage->isProductWithPriceOnList($productName, $productPrice), |
304
|
|
|
sprintf("The product %s with price %s should appear on page, but it does not.", $productName, $productPrice) |
|
|
|
|
305
|
|
|
); |
306
|
|
|
} |
307
|
|
|
|
308
|
|
|
/** |
309
|
|
|
* @Then /^I should be notified that (this product) does not have sufficient stock$/ |
310
|
|
|
*/ |
311
|
|
|
public function iShouldBeNotifiedThatThisProductDoesNotHaveSufficientStock(ProductInterface $product) |
312
|
|
|
{ |
313
|
|
|
$this->showPage->waitForValidationErrors(3); |
314
|
|
|
|
315
|
|
|
Assert::true( |
316
|
|
|
$this->showPage->hasProductOutOfStockValidationMessage($product), |
317
|
|
|
sprintf('I should see validation message for %s product', $product->getName()) |
318
|
|
|
); |
319
|
|
|
} |
320
|
|
|
|
321
|
|
|
/** |
322
|
|
|
* @Then /^I should not be notified that (this product) does not have sufficient stock$/ |
323
|
|
|
*/ |
324
|
|
|
public function iShouldNotBeNotifiedThatThisProductDoesNotHaveSufficientStock(ProductInterface $product) |
325
|
|
|
{ |
326
|
|
|
Assert::false( |
327
|
|
|
$this->showPage->hasProductOutOfStockValidationMessage($product), |
328
|
|
|
sprintf('I should see validation message for %s product', $product->getName()) |
329
|
|
|
); |
330
|
|
|
} |
331
|
|
|
|
332
|
|
|
/** |
333
|
|
|
* @Then I should see a main image |
334
|
|
|
*/ |
335
|
|
|
public function iShouldSeeAMainImage() |
336
|
|
|
{ |
337
|
|
|
Assert::true( |
338
|
|
|
$this->showPage->isMainImageDisplayed(), |
339
|
|
|
'The main image should have been displayed.' |
340
|
|
|
); |
341
|
|
|
} |
342
|
|
|
|
343
|
|
|
/** |
344
|
|
|
* @When /^I view (oldest|newest) products from (taxon "([^"]+)")$/ |
345
|
|
|
*/ |
346
|
|
|
public function iViewSortedProductsFromTaxon($sortDirection, TaxonInterface $taxon) |
347
|
|
|
{ |
348
|
|
|
$sorting = ['createdAt' => 'oldest' === $sortDirection ? 'asc' : 'desc']; |
349
|
|
|
|
350
|
|
|
$this->taxonShowPage->open(['slug' => $taxon->getSlug(), 'sorting' => $sorting]); |
351
|
|
|
} |
352
|
|
|
|
353
|
|
|
/** |
354
|
|
|
* @Then I should see :numberOfProducts products in the list |
355
|
|
|
*/ |
356
|
|
|
public function iShouldSeeProductsInTheList($numberOfProducts) |
357
|
|
|
{ |
358
|
|
|
$foundRows = $this->taxonShowPage->countProductsItems(); |
359
|
|
|
|
360
|
|
|
Assert::same( |
361
|
|
|
(int) $numberOfProducts, |
362
|
|
|
$foundRows, |
363
|
|
|
'%s rows with products should appear on page, %s rows has been found' |
364
|
|
|
); |
365
|
|
|
} |
366
|
|
|
|
367
|
|
|
/** |
368
|
|
|
* @Then I should see a product with name :name |
369
|
|
|
*/ |
370
|
|
|
public function iShouldSeeProductWithName($name) |
371
|
|
|
{ |
372
|
|
|
Assert::true( |
373
|
|
|
$this->taxonShowPage->isProductOnPageWithName($name), |
374
|
|
|
sprintf('The product with name "%s" has not been found.', $name) |
375
|
|
|
); |
376
|
|
|
} |
377
|
|
|
|
378
|
|
|
/** |
379
|
|
|
* @Then the first product on the list should have name :name |
380
|
|
|
*/ |
381
|
|
|
public function theFirstProductOnTheListShouldHaveName($name) |
382
|
|
|
{ |
383
|
|
|
$actualName = $this->taxonShowPage->getFirstProductNameFromList(); |
384
|
|
|
|
385
|
|
|
Assert::same( |
386
|
|
|
$actualName, |
387
|
|
|
$name, |
388
|
|
|
sprintf('Expected first product\'s name to be "%s", but it is "%s".', $name, $actualName) |
389
|
|
|
); |
390
|
|
|
} |
391
|
|
|
|
392
|
|
|
/** |
393
|
|
|
* @Then I should see :count product reviews |
394
|
|
|
*/ |
395
|
|
|
public function iShouldSeeProductReviews($count) |
396
|
|
|
{ |
397
|
|
|
Assert::same( |
398
|
|
|
(int) $count, |
399
|
|
|
$this->showPage->countReviews(), |
400
|
|
|
'Product has %2$s reviews, but should have %s.' |
401
|
|
|
); |
402
|
|
|
} |
403
|
|
|
|
404
|
|
|
/** |
405
|
|
|
* @Then I should see reviews titled :firstReview, :secondReview and :thirdReview |
406
|
|
|
*/ |
407
|
|
|
public function iShouldSeeReviewsTitled(...$reviews) |
408
|
|
|
{ |
409
|
|
|
foreach ($reviews as $review) { |
410
|
|
|
Assert::true( |
411
|
|
|
$this->showPage->hasReviewTitled($review), |
412
|
|
|
sprintf('Product should have review titled "%s" but it does not.', $review) |
413
|
|
|
); |
414
|
|
|
} |
415
|
|
|
} |
416
|
|
|
|
417
|
|
|
/** |
418
|
|
|
* @Then I should not see review titled :title |
419
|
|
|
*/ |
420
|
|
|
public function iShouldNotSeeReviewTitled($title) |
421
|
|
|
{ |
422
|
|
|
Assert::false( |
423
|
|
|
$this->showPage->hasReviewTitled($title), |
424
|
|
|
sprintf('Product should not have review titled "%s" but it does.', $title) |
425
|
|
|
); |
426
|
|
|
} |
427
|
|
|
|
428
|
|
|
/** |
429
|
|
|
* @When /^I check (this product)'s reviews$/ |
430
|
|
|
*/ |
431
|
|
|
public function iCheckThisProductSReviews(ProductInterface $product) |
432
|
|
|
{ |
433
|
|
|
$this->productReviewsIndexPage->open(['slug' => $product->getSlug()]); |
434
|
|
|
} |
435
|
|
|
|
436
|
|
|
/** |
437
|
|
|
* @Then /^I should see (\d+) product reviews in the list$/ |
438
|
|
|
*/ |
439
|
|
|
public function iShouldSeeNumberOfProductReviewsInTheList($count) |
440
|
|
|
{ |
441
|
|
|
Assert::same( |
442
|
|
|
(int) $count, |
443
|
|
|
$this->productReviewsIndexPage->countReviews(), |
444
|
|
|
'Product has %2$s reviews in the list, but should have %s.' |
445
|
|
|
); |
446
|
|
|
} |
447
|
|
|
|
448
|
|
|
/** |
449
|
|
|
* @Then I should not see review titled :title in the list |
450
|
|
|
*/ |
451
|
|
|
public function iShouldNotSeeReviewTitledInTheList($title) |
452
|
|
|
{ |
453
|
|
|
Assert::false( |
454
|
|
|
$this->productReviewsIndexPage->hasReviewTitled($title), |
455
|
|
|
sprintf('Product should not have review titled "%s" but it does.', $title) |
456
|
|
|
); |
457
|
|
|
} |
458
|
|
|
|
459
|
|
|
/** |
460
|
|
|
* @Then /^I should be notified that there are no reviews$/ |
461
|
|
|
*/ |
462
|
|
|
public function iShouldBeNotifiedThatThereAreNoReviews() |
463
|
|
|
{ |
464
|
|
|
Assert::true( |
465
|
|
|
$this->productReviewsIndexPage->hasNoReviewMessage(), |
466
|
|
|
'There should be message about no reviews but there is not.' |
467
|
|
|
); |
468
|
|
|
} |
469
|
|
|
|
470
|
|
|
/** |
471
|
|
|
* @Then I should see :rating as its average rating |
472
|
|
|
*/ |
473
|
|
|
public function iShouldSeeAsItsAverageRating($rating) |
474
|
|
|
{ |
475
|
|
|
$averageRating = $this->showPage->getAverageRating(); |
476
|
|
|
|
477
|
|
|
Assert::same( |
478
|
|
|
(float) $rating, |
479
|
|
|
$averageRating, |
480
|
|
|
'Product should have average rating %2$s but has %s.' |
481
|
|
|
); |
482
|
|
|
} |
483
|
|
|
|
484
|
|
|
/** |
485
|
|
|
* @Then /^I should(?:| also) see the product association "([^"]+)" with (products "[^"]+" and "[^"]+")$/ |
486
|
|
|
*/ |
487
|
|
|
public function iShouldSeeTheProductAssociationWithProducts($productAssociationName, array $products) |
488
|
|
|
{ |
489
|
|
|
Assert::true( |
490
|
|
|
$this->showPage->hasAssociation($productAssociationName), |
491
|
|
|
sprintf('There should be an association named "%s" but it does not.', $productAssociationName) |
492
|
|
|
); |
493
|
|
|
|
494
|
|
|
foreach ($products as $product) { |
495
|
|
|
$this->assertIsProductIsInAssociation($product->getName(), $productAssociationName); |
496
|
|
|
} |
497
|
|
|
} |
498
|
|
|
|
499
|
|
|
/** |
500
|
|
|
* @Then /^average rating of (product "[^"]+") should be (\d+)$/ |
501
|
|
|
*/ |
502
|
|
|
public function thisProductAverageRatingShouldBe(ProductInterface $product, $averageRating) |
503
|
|
|
{ |
504
|
|
|
$this->showPage->tryToOpen(['slug' => $product->getSlug()]); |
505
|
|
|
$this->iShouldSeeAsItsAverageRating($averageRating); |
506
|
|
|
} |
507
|
|
|
|
508
|
|
|
/** |
509
|
|
|
* @Then they should have order like :firstProductName, :secondProductName and :thirdProductName |
510
|
|
|
*/ |
511
|
|
|
public function theyShouldHaveOrderLikeAnd(...$productNames) |
512
|
|
|
{ |
513
|
|
|
Assert::true( |
514
|
|
|
$this->taxonShowPage->hasProductsInOrder($productNames), |
515
|
|
|
'The products have wrong order.' |
516
|
|
|
); |
517
|
|
|
} |
518
|
|
|
|
519
|
|
|
/** |
520
|
|
|
* @param string $productName |
521
|
|
|
* @param string $productAssociationName |
522
|
|
|
* |
523
|
|
|
* @throws \InvalidArgumentException |
524
|
|
|
*/ |
525
|
|
|
private function assertIsProductIsInAssociation($productName, $productAssociationName) |
526
|
|
|
{ |
527
|
|
|
Assert::true( |
528
|
|
|
$this->showPage->hasProductInAssociation($productName, $productAssociationName), |
529
|
|
|
sprintf( |
530
|
|
|
'There should be an associated product "%s" under association "%s" but it does not.', |
531
|
|
|
$productName, |
532
|
|
|
$productAssociationName |
533
|
|
|
) |
534
|
|
|
); |
535
|
|
|
} |
536
|
|
|
|
537
|
|
|
/** |
538
|
|
|
* @return NodeElement[] |
539
|
|
|
* |
540
|
|
|
* @throws \InvalidArgumentException |
541
|
|
|
*/ |
542
|
|
|
private function getProductAttributes() |
543
|
|
|
{ |
544
|
|
|
$attributes = $this->showPage->getAttributes(); |
545
|
|
|
Assert::notNull($attributes, 'The product has no attributes.'); |
546
|
|
|
|
547
|
|
|
return $attributes; |
548
|
|
|
} |
549
|
|
|
} |
550
|
|
|
|
PHP provides two ways to mark string literals. Either with single quotes
'literal'
or with double quotes"literal"
. The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (
\'
) and the backslash (\\
). Every other character is displayed as is.Double quoted string literals may contain other variables or more complex escape sequences.
will print an indented:
Single is Value
If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.
For more information on PHP string literals and available escape sequences see the PHP core documentation.