Skip to content

Commit cd36d7e

Browse files
authored
Create Staging.md
1 parent 8794f4e commit cd36d7e

File tree

1 file changed

+245
-0
lines changed

1 file changed

+245
-0
lines changed
+245
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
# Magento 2 Staging
2+
3+
## High level staging implementation overview
4+
5+
- Future editions of products/categories etc. are saved as a copy with a timestamped from-to columns.
6+
- Current staging version is saved as a flag, used in all collections to add WHERE condition
7+
- You can browse (preview) frontend site seeing future versions passing version and signature GET parameters
8+
9+
10+
## Demonstrate an understanding of the events processing flow
11+
12+
Influence of Staging on the event processing.
13+
14+
What is a modification of the event processing mechanism introduced by the staging module?
15+
16+
17+
\Magento\Staging\Model\Event\Manager:
18+
19+
- ban some events in preview mode - none by default
20+
- ban some observers in preview mode
21+
22+
- `catalog_category_prepare_save`
23+
- `catalog_category_save_after`
24+
- `catalog_category_save_before`
25+
- `catalog_category_move_after`
26+
27+
28+
## DB collection flag `disable_staging_preview`
29+
30+
- connection->select()
31+
- \Magento\Framework\DB\Adapter\Pdo\Mysql::select
32+
- Magento\Framework\DB\SelectFactory::create
33+
- Magento\Framework\DB\Select\SelectRenderer
34+
- // work with select...
35+
- \Magento\Framework\DB\Select::assemble
36+
- \Magento\Framework\DB\Select\SelectRenderer::render
37+
- \Magento\Framework\DB\Select\FromRenderer
38+
- \Magento\Staging\Model\Select\FromRenderer
39+
40+
41+
```
42+
from = [
43+
flag = [
44+
joinType = 'from'
45+
tableName = 'flag'
46+
]
47+
]
48+
```
49+
50+
```
51+
$select->where($alias . '.created_in <= ?', $versionId);
52+
$select->where($alias . '.updated_in > ?', $versionId);
53+
```
54+
55+
Only known staged tables are affected - \Magento\Staging\Model\StagingList::getEntitiesTables - `*_entity`
56+
57+
58+
## Staging modification to the Magento database operations (row_id, entity managers)
59+
60+
Flow modifications introduced by staging (triggers, row_id, data versions).
61+
62+
- deletes foreign keys to removed entity_id column
63+
- creates foreign key to row_id
64+
- replaces indexes
65+
66+
**Triggers** created differently! Attributes no longer have entity_id for `_cl` tables, so one more
67+
extra call to load entity_id by row_id is added to each update by schedule trigger.
68+
69+
\Magento\Framework\Mview\View\Subscription::buildStatement
70+
vs
71+
\Magento\CatalogStaging\Model\Mview\View\Attribute\Subscription::buildStatement
72+
73+
74+
trg_catalog_product_entity_int_after_insert:
75+
```SQL
76+
-- before
77+
INSERT IGNORE INTO `catalog_product_flat_cl` (`entity_id`) VALUES (NEW.`entity_id`);
78+
-- after
79+
SET @entity_id = (SELECT `entity_id` FROM `catalog_product_entity` WHERE `row_id` = NEW.`row_id`);
80+
INSERT IGNORE INTO `catalog_product_flat_cl` (`entity_id`) values(@entity_id);
81+
```
82+
83+
trg_catalog_product_entity_int_after_update:
84+
```SQL
85+
-- before
86+
IF (NEW.`value_id` <=> OLD.`value_id` OR NEW.`attribute_id` <=> OLD.`attribute_id` OR NEW.`store_id` <=> OLD.`store_id` OR NEW.`entity_id` <=> OLD.`entity_id` OR NEW.`value` <=> OLD.`value`) THEN INSERT IGNORE INTO `catalog_product_flat_cl` (`entity_id`) VALUES (NEW.`entity_id`); END IF;
87+
-- after
88+
SET @entity_id = (SELECT `entity_id` FROM `catalog_product_entity` WHERE `row_id` = NEW.`row_id`);
89+
IF (NOT(NEW.`value_id` <=> OLD.`value_id`) OR NOT(NEW.`attribute_id` <=> OLD.`attribute_id`) OR NOT(NEW.`store_id` <=> OLD.`store_id`) OR NOT(NEW.`value` <=> OLD.`value`) OR NOT(NEW.`row_id` <=> OLD.`row_id`)) THEN INSERT IGNORE INTO `catalog_product_flat_cl` (`entity_id`) values(@entity_id); END IF;
90+
```
91+
92+
trg_catalog_product_entity_int_after_delete:
93+
```SQL
94+
-- before
95+
INSERT IGNORE INTO `catalog_product_flat_cl` (`entity_id`) VALUES (OLD.`entity_id`);
96+
-- after
97+
SET @entity_id = (SELECT `entity_id` FROM `catalog_product_entity` WHERE `row_id` = OLD.`row_id`);
98+
INSERT IGNORE INTO `catalog_product_flat_cl` (`entity_id`) values(@entity_id);
99+
```
100+
101+
102+
## sequence tables
103+
104+
Staging migration scripts do this: `row_id` becomes auto_increment, and `entity_id` (`page_id` etc.) column
105+
is no longer auto incremented, but still required!
106+
107+
Requests like `INSERT INTO cms_page (identified) VALUES("test_page")` would result in error because page_id
108+
is normally auto_increment and not passed in request.
109+
110+
Magento fixes this by manually generating auto increments for entity_id in separate sequence tables.
111+
112+
Exmple:
113+
114+
- \Magento\Framework\Model\ResourceModel\Db\CreateEntityRow::prepareData
115+
- `$output[$metadata->getIdentifierField()] = $metadata->generateIdentifier();`
116+
- \Magento\Framework\EntityManager\Sequence\Sequence::getNextValue
117+
- insert and return next ID into `sequence_*` table
118+
119+
`sequence_cms_page`, `sequence_catalog_category`, `sequence_catalogrule`, ...
120+
121+
In community edition (no staging), `$metadata->generateIdentifier()` because sequenceTable is not passed.
122+
123+
124+
- \Magento\Framework\EntityManager\MetadataPool::getMetadata
125+
- \Magento\Framework\EntityManager\MetadataPool::createMetadata
126+
- new \Magento\Framework\EntityManager\EntityMetadata
127+
- `sequence` argument: \Magento\Framework\EntityManager\Sequence\SequenceFactory::create:
128+
- no staging - sequence = null
129+
- staging defines `sequenceTable` - `new \Magento\Framework\EntityManager\Sequence\Sequence(connection, sequenceTable)`
130+
131+
132+
133+
## Common staging plugins
134+
135+
- FrontControllerInterface::beforeDispatch - validate `___version`, `___timestamp`, `___signature`
136+
- Magento\PageCache\Model\Config::afterIsEnabled - disabled in preview mode
137+
- Magento\Store\Model\BaseUrlChecker - disabled in preview mode
138+
- Magento\Framework\Stdlib\DateTime\Timezone::isScopeDateInInterval - interval never validated in preview mode
139+
- Magento\Store\Model\StoreResolver::getCurrentStoreId - use `___store` in preview mode
140+
- Magento\Customer\Model\Session::regenerateId, destroy - never regenerate/destroy in preview mode
141+
- getUrl - adds `___version`, `___store`, possibly `__timestamp`, `__signature` in preview mode
142+
- disables block_html caching
143+
144+
145+
## Staging-related modifications of the indexing process
146+
147+
- plugin before Magento\Catalog\Controller\Category\View
148+
- \Magento\CatalogStaging\Model\Plugin\Controller\View::beforeExecute
149+
- \Magento\CatalogStaging\Model\Indexer\Category\Product\Preview::execute
150+
- \Magento\Catalog\Model\Indexer\Category\Product\AbstractAction::reindex
151+
152+
Reindex using temporary tables with suffix `_catalog_staging_tmp`,
153+
e.g. `catalog_category_product_index_store1_catalog_staging_tmp`
154+
155+
156+
## Save staging update
157+
158+
\Magento\SalesRuleStaging\Controller\Adminhtml\Update\Save::execute
159+
\Magento\Staging\Model\Entity\Update\Save::execute
160+
161+
```
162+
staging[mode]: save
163+
staging[update_id]:
164+
staging[name]: 3 September
165+
staging[description]: Everything is new
166+
staging[start_time]: 2020-09-03T07:00:00.000Z
167+
staging[end_time]:
168+
```
169+
170+
\Magento\Staging\Model\Entity\Update\Action\Pool::getAction(
171+
entityType = 'Magento\SalesRule\Api\Data\RuleInterface',
172+
namespace = 'save',
173+
actionType = mode = 'save'
174+
)
175+
176+
- \Magento\Staging\Model\Entity\Update\Action\Save\SaveAction:
177+
- \Magento\Staging\Model\Entity\Update\Action\Save\SaveAction::createUpdate
178+
- \Magento\Staging\Model\EntityStaging::schedule
179+
- \Magento\CatalogRuleStaging\Model\CatalogRuleStaging::schedule
180+
- validates intersecting updates
181+
- sets `created_in`, saves entity model (catalog rule)
182+
- Magento\CatalogRuleStaging\Model\Rule\Hydrator
183+
- \Magento\CatalogRuleStaging\Model\Rule\Retriever::getEntity - $this->ruleRepository->get($entityId)
184+
185+
186+
## Preview
187+
188+
All links are automatially updated:
189+
- \Magento\Framework\Url::getUrl
190+
- \Magento\Framework\Url\RouteParamsPreprocessorComposite::execute
191+
- \Magento\Staging\Model\Preview\RouteParamsPreprocessor::execute
192+
- `[_query][___version]=`, `[_query][___store]=`
193+
- `__timestamp=`, `__signature=`
194+
195+
Example:
196+
197+
vendor/magento/module-catalog/view/frontend/layout/default.xml:
198+
```XML
199+
<block class="Magento\Catalog\Block\FrontendStorageManager" name="frontend-storage-manager" before="-"
200+
template="Magento_Catalog::frontend_storage_manager.phtml">
201+
<arguments>
202+
<!-- ... -->
203+
<item name="updateRequestConfig" xsi:type="array">
204+
<item name="url" xsi:type="serviceUrl" path="/products-render-info"/>
205+
</item>
206+
```
207+
208+
- \Magento\Store\Model\Argument\Interpreter\ServiceUrl::evaluate
209+
- https://m24ee.local/rest/default/V1/?___store=default&___version=1599422820&__signature=b5cd66d9ea383ea57356f28cf2dd0f8edeecbc516b4d7982f8aef2ce4bcd4d32&__timestamp=1599165421products-render-info
210+
211+
212+
URL examples:
213+
214+
- REST - `?___version=`
215+
- category - `?update_id=`
216+
217+
218+
Preview from admin panel:
219+
220+
- https://m24ee.local/admin/staging/update/preview/key/.../?preview_store=default&preview_url=https:/m24ee.local/&preview_version=1599116400
221+
- header and iframe
222+
- https://m24ee.local/?___version=1599116400&___store=default&__timestamp=1599077245&__signature=a8f3a05adb92374873a3f9c4e1d36c1bddcc9748b32b046af4264b496243f95d
223+
224+
225+
\Magento\Staging\Plugin\Framework\App\FrontController::beforeDispatch - validate signature:
226+
227+
```
228+
__signature = hash(sha256, "__version,__timestamp", secret key from env.php)
229+
```
230+
231+
232+
## Set current version
233+
234+
\Magento\CatalogStaging\Model\Category\DataProvider::getCurrentCategory
235+
236+
```
237+
$updateId = (int) $this->request->getParam('update_id');
238+
$this->versionManager->setCurrentVersionId($update->getId());
239+
```
240+
241+
242+
## checkout-staging
243+
244+
- disable place order in preview
245+
- any quote, saved in preview mode, is saved in db table `quote_preview` and deleted by cron

0 commit comments

Comments
 (0)