Skip to content

Commit 4199cd1

Browse files
mitelgIsengo1989
andauthored
feat: Add troubleshooting section for PHPStan (#1961)
* feat: Add troubleshooting section for PHPStan * spell check * another spell check fix * feat/add-new-subsection --------- Co-authored-by: Micha <[email protected]>
1 parent 159e208 commit 4199cd1

File tree

3 files changed

+139
-4
lines changed

3 files changed

+139
-4
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
nav:
3+
title: Troubleshooting
4+
position: 10
5+
6+
---
7+
8+
# Troubleshooting
9+
10+
Use this section to diagnose and resolve common issues you might encounter while working with Shopware projects.

resources/guidelines/troubleshooting.md renamed to resources/guidelines/troubleshooting/performance.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
---
22
nav:
3-
title: Troubleshooting
4-
position: 80
3+
title: Performance
4+
position: 20
55

66
---
77

8-
# Troubleshooting
8+
# Performance
99

10-
## Performance
10+
## Common Performance Considerations
1111

1212
### Dynamic product groups are slow to load
1313

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
---
2+
nav:
3+
title: PHPStan
4+
position: 30
5+
---
6+
7+
# PHPStan
8+
9+
## Common PHPStan Issues in Shopware Code
10+
11+
### EntityRepository Should Define a Generic Type
12+
13+
**Problem**: Repository returns EntityCollection without type information.
14+
15+
```php
16+
$products = $this->productRepository->search($criteria, $context)->getEntities();
17+
foreach ($products as $product) {
18+
// PHPStan doesn't know $product is ProductEntity
19+
$name = $product->getName(); // Call to an undefined method Shopware\Core\Framework\DataAbstractionLayer\Entity::getName()
20+
}
21+
```
22+
23+
**Solution**: Add a PHP doc with a generic type to EntityRepository:
24+
25+
```php
26+
class Foo
27+
{
28+
/**
29+
* @param EntityRepository<ProductCollection> $productRepository
30+
*/
31+
public function __construct(
32+
private readonly EntityRepository $productRepository,
33+
) {
34+
}
35+
36+
public function doSomething(): void
37+
{
38+
// ...
39+
$products = $this->productRepository->search($criteria, $context)->getEntities();
40+
foreach ($products as $product) {
41+
$name = $product->getName(); // PHPStan correctly identifies this as ProductEntity
42+
}
43+
}
44+
}
45+
```
46+
47+
Be aware that the `EntityRepository` class is a generic class, which gets an EntityCollection as type.
48+
This might sound counter-intuitive and different to other well-known repository classes, which take the Entity class as the generic type.
49+
But it was the easiest technical solution to get PHPStan to understand the type of the collection returned by the search method.
50+
51+
### Null Safety with First method and Associations
52+
53+
**Problem**: Calling `first` could return `null`, also entity associations can be `null` if not loaded.
54+
55+
```php
56+
$product = $this->productRepository->search($criteria, $context)->first();
57+
$manufacturer = $product->getManufacturer(); // Cannot call method getManufacturer() on Shopware\Core\Content\Product\ProductEntity|null.
58+
$manufacturerName = $manufacturer->getName(); // Cannot call method getName() on Shopware\Core\Content\Product\Aggregate\ProductManufacturer\ProductManufacturerEntity|null.
59+
```
60+
61+
**Solution**: Ensure associations are added before in the criteria and always check for possible `null` returns:
62+
63+
```php
64+
$criteria = new Criteria();
65+
$criteria->addAssociation('manufacturer');
66+
67+
$product = $this->productRepository->search($criteria, $context)->first();
68+
if ($product === null) {
69+
throw new ProductNotFoundException();
70+
}
71+
72+
$manufacturer = $product->getManufacturer();
73+
if ($manufacturer === null) {
74+
throw new ManufacturerNotLoadedException();
75+
}
76+
77+
$manufacturerName = $manufacturer->getName(); // No error
78+
```
79+
80+
Or use the null-safe operators:
81+
82+
```php
83+
$manufacturerName = $product?->getManufacturer()?->getName() ?? 'Unknown';
84+
```
85+
86+
### Missing Generic Type for EntityCollection
87+
88+
**Problem**: Custom EntityCollection does not have a generic type.
89+
90+
```php
91+
class FooCollection extends EntityCollection
92+
{
93+
protected function getExpectedClass(): string
94+
{
95+
return FooEntity::class;
96+
}
97+
}
98+
99+
$foo = $fooCollection->first();
100+
if ($foo === null) {
101+
throw new FooNotFoundException();
102+
}
103+
$foo->bar(); // Cannot call method bar() on Shopware\Core\Framework\DataAbstractionLayer\Entity.
104+
```
105+
106+
**Solution**: Add a generic type to EntityCollection:
107+
108+
```php
109+
/**
110+
* @extends EntityCollection<FooEntity>
111+
*/
112+
class FooCollection extends EntityCollection
113+
{
114+
protected function getExpectedClass(): string
115+
{
116+
return FooEntity::class;
117+
}
118+
}
119+
120+
$foo = $fooCollection->first();
121+
if ($foo === null) {
122+
throw new FooNotFoundException();
123+
}
124+
$foo->bar(); // No error
125+
```

0 commit comments

Comments
 (0)