Skip to content

Commit a658dba

Browse files
[PWA-1204] Inlining page data and webpack chunks (#10)
* PWA-1906 adding Compute pool and PageType resolver * PWA-1906 refactor page info into model, adding new type of webpack chunks, changing interface to use iterator instead of context * PWA-1204 changing Computed interface to pass in definition, changing page info resolver to fetch addtional data from yaml * PWA-1204 fixing stripping store code from start of url * PWA-1906 Moved interface to API, adding missing docblocks, refactor for maintainability * PWA-1906 docblocks * PWA-1204 removing composer versioning * PWA-1204 adding nonce resolver for page type inline script * PWA-1204 simplifying nonce to use random string * PWA-1204 adding custom provider for page information to avoid content filtering * PWA-1204 code cleanup Co-authored-by: Justin Conabree <[email protected]>
1 parent f1b8586 commit a658dba

File tree

9 files changed

+720
-0
lines changed

9 files changed

+720
-0
lines changed

Api/ComputedInterface.php

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
declare(strict_types=1);
8+
9+
namespace Magento\UpwardConnector\Api;
10+
11+
use Magento\Upward\Definition;
12+
use Magento\Upward\DefinitionIterator;
13+
14+
/**
15+
* Resolves a computed value for UPWARD
16+
*/
17+
interface ComputedInterface
18+
{
19+
/**
20+
* Resolve value to use in upward config
21+
*
22+
* @param \Magento\Upward\DefinitionIterator $iterator
23+
* @param \Magento\Upward\Definition $definition
24+
*
25+
* @return array|int|string|null
26+
*/
27+
public function resolve(DefinitionIterator $iterator, Definition $definition);
28+
}

Model/Computed/PageInfo.php

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
declare(strict_types=1);
8+
9+
namespace Magento\UpwardConnector\Model\Computed;
10+
11+
use Magento\Framework\Serialize\Serializer\Json;
12+
use Magento\Store\Model\StoreManagerInterface;
13+
use Magento\Upward\Definition;
14+
use Magento\Upward\DefinitionIterator;
15+
use Magento\UpwardConnector\Api\ComputedInterface;
16+
use Magento\UpwardConnector\Model\PageType;
17+
use Magento\UrlRewriteGraphQl\Model\DataProvider\EntityDataProviderComposite;
18+
19+
class PageInfo implements ComputedInterface
20+
{
21+
/** @var \Magento\UpwardConnector\Model\PageType */
22+
private $pageTypeResolver;
23+
24+
/** @var \Magento\Store\Model\StoreManagerInterface */
25+
private $storeManager;
26+
27+
/** @var \Magento\Framework\Serialize\Serializer\Json */
28+
private $json;
29+
30+
/** @var \Magento\UrlRewriteGraphQl\Model\DataProvider\EntityDataProviderComposite */
31+
private $entityDataProviderComposite;
32+
33+
/**
34+
* @param \Magento\UpwardConnector\Model\PageType $pageTypeResolver
35+
* @param \Magento\Store\Model\StoreManagerInterface $storeManager
36+
* @param \Magento\Framework\Serialize\Serializer\Json $json
37+
* @param \Magento\UrlRewriteGraphQl\Model\DataProvider\EntityDataProviderComposite $entityDataProviderComposite
38+
*/
39+
public function __construct(
40+
PageType $pageTypeResolver,
41+
StoreManagerInterface $storeManager,
42+
Json $json,
43+
EntityDataProviderComposite $entityDataProviderComposite
44+
) {
45+
$this->pageTypeResolver = $pageTypeResolver;
46+
$this->storeManager = $storeManager;
47+
$this->json = $json;
48+
$this->entityDataProviderComposite = $entityDataProviderComposite;
49+
}
50+
51+
/**
52+
* @param \Magento\Upward\DefinitionIterator $iterator
53+
* @param \Magento\Upward\Definition $definition
54+
*
55+
* @return string
56+
* @throws \Magento\Framework\Exception\NoSuchEntityException
57+
*/
58+
public function resolve(DefinitionIterator $iterator, Definition $definition)
59+
{
60+
$pageInfo = $this->pageTypeResolver
61+
->setContext($iterator->getContext())
62+
->getInfo();
63+
64+
if (!$pageInfo) {
65+
return '';
66+
}
67+
68+
$storeId = (int) $this->storeManager->getStore()->getId();
69+
$type = $pageInfo['type'];
70+
$additionalMap = $this->getAdditionalMap($definition, $type);
71+
72+
$entityData = $this->isPageInfoComplete($pageInfo, $additionalMap) ?
73+
$pageInfo :
74+
$this->entityDataProviderComposite->getData(
75+
$type,
76+
(int)$pageInfo['id'],
77+
null,
78+
$storeId
79+
);
80+
81+
if (empty($entityData)) {
82+
return '';
83+
}
84+
85+
$result = $this->filterData(
86+
$entityData,
87+
$additionalMap,
88+
$type
89+
);
90+
$result['redirect_code'] = $pageInfo['redirect_code'];
91+
$result['relative_url'] = $pageInfo['relative_url'];
92+
$result['type'] = $type;
93+
94+
return $this->json->serialize($result);
95+
}
96+
97+
/**
98+
* @param \Magento\Upward\Definition $definition
99+
* @param string $type
100+
*
101+
* @return false|string[]
102+
*/
103+
public function getAdditionalMap(Definition $definition, string $type)
104+
{
105+
$definitionArray = $definition->toArray();
106+
$additional = $definitionArray['additional'] ?? null;
107+
108+
if (!$additional) {
109+
return false;
110+
}
111+
$additionalInfo = [];
112+
$typeCheck = strtolower($type);
113+
foreach ($additional as $additionalType) {
114+
if ($additionalType['type'] === $typeCheck) {
115+
$additionalInfo = explode(',', $additionalType['fetch']);
116+
117+
break;
118+
}
119+
}
120+
121+
return $additionalInfo;
122+
}
123+
124+
/**
125+
* @param array $pageInfo
126+
* @param string[]|bool $additionalMap
127+
*
128+
* @return bool
129+
*/
130+
public function isPageInfoComplete($pageInfo, $additionalMap): bool
131+
{
132+
$pageInfoHasAllData = true;
133+
if ($additionalMap) {
134+
foreach($additionalMap as $key) {
135+
if (!isset($pageInfo[$key])) {
136+
$pageInfoHasAllData = false;
137+
138+
break;
139+
}
140+
}
141+
}
142+
143+
return $pageInfoHasAllData;
144+
}
145+
146+
/**
147+
* @param array $data
148+
* @param array{type: string, fetch: string}|bool $map
149+
*
150+
* @return array
151+
*/
152+
public function filterData($data, $map, $type)
153+
{
154+
if (!$map || empty($map) || empty($data)) {
155+
return [];
156+
}
157+
158+
$result = [];
159+
foreach($map as $valueKey) {
160+
$result[$valueKey] = $this->getEntityValue($data, $valueKey, $type);
161+
}
162+
163+
return $result;
164+
}
165+
166+
/**
167+
* @param array $data
168+
* @param string $key
169+
* @param string $type
170+
*
171+
* @return string|null
172+
*/
173+
public function getEntityValue(array $data, string $key, string $type)
174+
{
175+
if ($key === '__typename') {
176+
if ($type === 'PRODUCT') {
177+
return ucfirst($data['type_id']) . 'Product';
178+
}
179+
180+
return $data['type_id'] ? ucfirst($data['type_id']) : ucfirst(strtolower($type));
181+
}
182+
183+
if ($key === 'id') {
184+
return $data['id'] ?? $data['entity_id'];
185+
}
186+
187+
return $data[$key] ?? null;
188+
}
189+
}

Model/Computed/PageInfoNonce.php

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
declare(strict_types=1);
8+
9+
namespace Magento\UpwardConnector\Model\Computed;
10+
11+
use Magento\Framework\Math\Random;
12+
use Magento\Upward\Definition;
13+
use Magento\Upward\DefinitionIterator;
14+
use Magento\UpwardConnector\Api\ComputedInterface;
15+
16+
class PageInfoNonce implements ComputedInterface
17+
{
18+
const NONCE_LENGTH = 45;
19+
20+
/** @var \Magento\Framework\Math\Random */
21+
private $randomGenerator;
22+
23+
/** @var array<string, string> */
24+
private $nonces = [];
25+
26+
/**
27+
* @param \Magento\Framework\Math\Random $randomGenerator
28+
*/
29+
public function __construct(
30+
Random $randomGenerator
31+
) {
32+
$this->randomGenerator = $randomGenerator;
33+
}
34+
35+
/**
36+
* @param \Magento\Upward\DefinitionIterator $iterator
37+
* @param \Magento\Upward\Definition $definition
38+
*
39+
* @return array|int|string|null
40+
* @throws \Magento\Framework\Exception\LocalizedException
41+
*/
42+
public function resolve(DefinitionIterator $iterator, Definition $definition)
43+
{
44+
if (!isset($this->nonces[$definition->getTreeAddress()])) {
45+
$this->nonces[$definition->getTreeAddress()] = $this->generateNonce();
46+
}
47+
48+
return $this->nonces[$definition->getTreeAddress()];
49+
}
50+
51+
/**
52+
* @throws \Magento\Framework\Exception\LocalizedException
53+
*/
54+
private function generateNonce(): string
55+
{
56+
return $this->randomGenerator->getRandomString(self::NONCE_LENGTH);
57+
}
58+
}

Model/Computed/WebpackChunks.php

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
declare(strict_types=1);
8+
9+
namespace Magento\UpwardConnector\Model\Computed;
10+
11+
use Magento\Framework\Filesystem\Driver\File;
12+
use Magento\Upward\Definition;
13+
use Magento\Upward\DefinitionIterator;
14+
use Magento\UpwardConnector\Api\ComputedInterface;
15+
use Magento\UpwardConnector\Model\PageType;
16+
17+
class WebpackChunks implements ComputedInterface
18+
{
19+
public const SEARCH_PATTERN = 'RootCmp_{{SEARCH}}__';
20+
21+
/** @var \Magento\UpwardConnector\Model\PageType */
22+
private PageType $pageTypeResolver;
23+
24+
/** @var \Magento\Framework\Filesystem\Driver\File */
25+
private File $driverFile;
26+
27+
/**
28+
* @param \Magento\UpwardConnector\Model\PageType $pageTypeResolver
29+
* @param \Magento\Framework\Filesystem\Driver\File $driverFile
30+
*/
31+
public function __construct(
32+
PageType $pageTypeResolver,
33+
File $driverFile
34+
) {
35+
$this->pageTypeResolver = $pageTypeResolver;
36+
$this->driverFile = $driverFile;
37+
}
38+
39+
/**
40+
* @param \Magento\Upward\DefinitionIterator $iterator
41+
* @param \Magento\Upward\Definition $definition
42+
*
43+
* @return string[]
44+
* @throws \Magento\Framework\Exception\FileSystemException
45+
*/
46+
public function resolve(DefinitionIterator $iterator, Definition $definition)
47+
{
48+
$pageType = $this->pageTypeResolver->setContext($iterator->getContext())->getPageType();
49+
50+
if (!$pageType) {
51+
return [];
52+
}
53+
54+
$scripts = [];
55+
$distPath = $iterator->getRootDefinition()->getBasepath();
56+
57+
$searchTerm = str_replace('{{SEARCH}}', $pageType, self::SEARCH_PATTERN);
58+
$files = $this->driverFile->readDirectory(realpath($distPath));
59+
foreach ($files as $file) {
60+
if (strpos($file, $searchTerm) !== false) {
61+
$fileParts = explode(\DIRECTORY_SEPARATOR, $file);
62+
$scripts[] = end($fileParts);
63+
}
64+
}
65+
66+
return $scripts;
67+
}
68+
}

Model/ComputedPool.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
declare(strict_types=1);
8+
9+
namespace Magento\UpwardConnector\Model;
10+
11+
use Magento\UpwardConnector\Api\ComputedInterface;
12+
13+
class ComputedPool
14+
{
15+
/** @var \Magento\UpwardConnector\Api\ComputedInterface[] */
16+
private $items;
17+
18+
/**
19+
* @param \Magento\UpwardConnector\Api\ComputedInterface[]|null $items
20+
*/
21+
public function __construct(?array $items = [])
22+
{
23+
$this->items = $items;
24+
}
25+
26+
/**
27+
* Get resolving ComputedInterface class
28+
*
29+
* @param string $classKey
30+
* @return \Magento\UpwardConnector\Api\ComputedInterface|null
31+
*/
32+
public function getItem(string $classKey): ?ComputedInterface
33+
{
34+
return $this->items[$classKey] ?? null;
35+
}
36+
}

0 commit comments

Comments
 (0)