| Current Path : /home/rtorresani/www/vendor/magento/framework/Setup/Declaration/Schema/ |
| Current File : //home/rtorresani/www/vendor/magento/framework/Setup/Declaration/Schema/OperationsExecutor.php |
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Framework\Setup\Declaration\Schema;
use Magento\Framework\App\ResourceConnection;
use Magento\Framework\Setup\Declaration\Schema\DataSavior\DataSaviorInterface;
use Magento\Framework\Setup\Declaration\Schema\Db\DbSchemaWriterInterface;
use Magento\Framework\Setup\Declaration\Schema\Db\StatementAggregatorFactory;
use Magento\Framework\Setup\Declaration\Schema\Db\StatementFactory;
use Magento\Framework\Setup\Declaration\Schema\Diff\DiffInterface;
use Magento\Framework\Setup\Declaration\Schema\Dto\ElementInterface;
use Magento\Framework\Setup\Declaration\Schema\Operations\AddColumn;
use Magento\Framework\Setup\Declaration\Schema\Operations\CreateTable;
use Magento\Framework\Setup\Declaration\Schema\Operations\ReCreateTable;
/**
* Schema operations executor.
*
* Go through all available SQL operations and execute each one with data from change registry.
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class OperationsExecutor
{
/**
* Request keys.
*/
const KEY_SAFE_MODE = 'safe-mode';
const KEY_DATA_RESTORE = 'data-restore';
/**
* @var OperationInterface[]
*/
private $operations;
/**
* @var Sharding
*/
private $sharding;
/**
* @var ResourceConnection
*/
private $resourceConnection;
/**
* @var StatementFactory
*/
private $statementFactory;
/**
* @var DbSchemaWriterInterface
*/
private $dbSchemaWriter;
/**
* @var StatementAggregatorFactory
*/
private $statementAggregatorFactory;
/**
* @var DataSaviorInterface[]
*/
private $dataSaviorsCollection;
/**
* @var DryRunLogger
*/
private $dryRunLogger;
/**
* Constructor.
*
* @param array $operations
* @param array $dataSaviorsCollection
* @param Sharding $sharding
* @param ResourceConnection $resourceConnection
* @param StatementFactory $statementFactory
* @param DbSchemaWriterInterface $dbSchemaWriter
* @param StatementAggregatorFactory $statementAggregatorFactory
* @param DryRunLogger $dryRunLogger
*/
public function __construct(
array $operations,
array $dataSaviorsCollection,
Sharding $sharding,
ResourceConnection $resourceConnection,
StatementFactory $statementFactory,
DbSchemaWriterInterface $dbSchemaWriter,
StatementAggregatorFactory $statementAggregatorFactory,
DryRunLogger $dryRunLogger
) {
$this->operations = $operations;
$this->sharding = $sharding;
$this->resourceConnection = $resourceConnection;
$this->statementFactory = $statementFactory;
$this->dbSchemaWriter = $dbSchemaWriter;
$this->statementAggregatorFactory = $statementAggregatorFactory;
$this->dataSaviorsCollection = $dataSaviorsCollection;
$this->dryRunLogger = $dryRunLogger;
}
/**
* Retrieve only destructive operation names.
*
* For example, drop_table, recreate_table, etc.
*
* @return array
*/
public function getDestructiveOperations()
{
$operations = [];
foreach ($this->operations as $operation) {
if ($operation->isOperationDestructive()) {
$operations[$operation->getOperationName()] = $operation->getOperationName();
}
}
return $operations;
}
/**
* In order to successfully run all operations we need to start setup for all
* connections first.
*
* @return void
*/
private function startSetupForAllConnections()
{
foreach ($this->sharding->getResources() as $resource) {
$connection = $this->resourceConnection->getConnection($resource);
$connection->startSetup();
$connection->query('SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0');
}
}
/**
* In order to revert previous state we need to end setup for all connections
* connections first.
*
* @return void
*/
private function endSetupForAllConnections()
{
foreach ($this->sharding->getResources() as $resource) {
$connection = $this->resourceConnection->getConnection($resource);
$connection->query('SET UNIQUE_CHECKS=IF(@OLD_UNIQUE_CHECKS=0, 0, 1)');
$connection->endSetup();
}
}
/**
* Check if during this operation we need to restore data
*
* @param OperationInterface $operation
* @return bool
*/
private function operationIsOppositeToDestructive(OperationInterface $operation)
{
return $operation instanceof AddColumn ||
$operation instanceof CreateTable ||
$operation instanceof ReCreateTable;
}
/**
* Loop through all operations that are configured in di.xml
* and execute them with elements from Diff.
*
* @see OperationInterface
* @param DiffInterface $diff
* @param array $requestData
* @return void
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.NPathComplexity)
*/
public function execute(DiffInterface $diff, array $requestData)
{
$this->startSetupForAllConnections();
$tableHistories = $diff->getAll();
$dryRun = isset($requestData[DryRunLogger::INPUT_KEY_DRY_RUN_MODE]) &&
$requestData[DryRunLogger::INPUT_KEY_DRY_RUN_MODE];
if ($dryRun) {
$this->dryRunLogger->prepareToDryRun();
}
if (is_array($tableHistories)) {
foreach ($tableHistories as $tableHistory) {
$destructiveElements = [];
$oppositeToDestructiveElements = [];
$statementAggregator = $this->statementAggregatorFactory->create();
foreach ($this->operations as $operation) {
if (isset($tableHistory[$operation->getOperationName()])) {
/** @var ElementHistory $elementHistory */
foreach ($tableHistory[$operation->getOperationName()] as $elementHistory) {
$statementAggregator->addStatements($operation->doOperation($elementHistory));
if ($operation->isOperationDestructive()) {
$destructiveElements[] = $elementHistory->getOld();
} elseif ($this->operationIsOppositeToDestructive($operation)) {
$oppositeToDestructiveElements[] = $elementHistory->getNew();
}
}
}
}
$this->doDump($destructiveElements, $requestData);
$this->dbSchemaWriter->compile($statementAggregator, $dryRun);
$this->doRestore($oppositeToDestructiveElements, $requestData);
}
}
$this->endSetupForAllConnections();
}
/**
* Do restore of destructive operations
*
* @param array $elements
* @param array $requestData
*/
private function doRestore(array $elements, array $requestData)
{
$restoreMode = isset($requestData[self::KEY_DATA_RESTORE]) && $requestData[self::KEY_DATA_RESTORE];
if ($restoreMode) {
/**
* @var ElementInterface $element
*/
foreach ($elements as $element) {
foreach ($this->dataSaviorsCollection as $dataSavior) {
if ($dataSavior->isAcceptable($element)) {
$dataSavior->restore($element);
break;
}
}
}
}
}
/**
* Do dump of destructive operations
*
* @param array $elements
* @param array $requestData
*/
private function doDump(array $elements, array $requestData)
{
$safeMode = isset($requestData[self::KEY_SAFE_MODE]) && $requestData[self::KEY_SAFE_MODE];
if ($safeMode) {
/**
* @var ElementInterface $element
*/
foreach ($elements as $element) {
foreach ($this->dataSaviorsCollection as $dataSavior) {
if ($dataSavior->isAcceptable($element)) {
$dataSavior->dump($element);
break;
}
}
}
}
}
}