139 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			PHP
		
	
	
		
			Executable File
		
	
	
			
		
		
	
	
			139 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			PHP
		
	
	
		
			Executable File
		
	
	
<?php
 | 
						|
/**
 | 
						|
 * Copyright © Magento, Inc. All rights reserved.
 | 
						|
 * See COPYING.txt for license details.
 | 
						|
 */
 | 
						|
 | 
						|
declare(strict_types=1);
 | 
						|
 | 
						|
namespace Magento\Test\Integrity\DBSchema;
 | 
						|
 | 
						|
use Magento\Framework\App\Utility\Files;
 | 
						|
use Magento\Framework\Exception\LocalizedException;
 | 
						|
use Magento\Framework\Setup\Declaration\Schema\Config\Converter;
 | 
						|
use PHPUnit\Framework\TestCase;
 | 
						|
 | 
						|
/**
 | 
						|
 * Test for finding database tables missing primary key
 | 
						|
 */
 | 
						|
class PrimaryKeyTest extends TestCase
 | 
						|
{
 | 
						|
    /**
 | 
						|
     * Check missing database tables' primary key
 | 
						|
     *
 | 
						|
     * @throws LocalizedException
 | 
						|
     */
 | 
						|
    public function testMissingPrimaryKey()
 | 
						|
    {
 | 
						|
        $exemptionList = $this->getExemptionList();
 | 
						|
        $tablesSchemaDeclaration = $this->getDbSchemaDeclarations()['table'];
 | 
						|
        $exemptionList = array_intersect(array_keys($tablesSchemaDeclaration), $exemptionList);
 | 
						|
        foreach ($exemptionList as $exemptionTableName) {
 | 
						|
            unset($tablesSchemaDeclaration[$exemptionTableName]);
 | 
						|
        }
 | 
						|
        $errorMessage = '';
 | 
						|
        $failedTableCtr = 0;
 | 
						|
        foreach ($tablesSchemaDeclaration as $tableName => $tableSchemaDeclaration) {
 | 
						|
            if (!$this->hasPrimaryKey($tableSchemaDeclaration)) {
 | 
						|
                $message = '';
 | 
						|
                if (!empty($tableSchemaDeclaration['modules'])) {
 | 
						|
                    $message = "It is declared in the following modules: \n" . implode(
 | 
						|
                            "\t\n",
 | 
						|
                            $tableSchemaDeclaration['modules']
 | 
						|
                        );
 | 
						|
                }
 | 
						|
                $errorMessage .= 'Table ' . $tableName . ' does not have primary key. ' . $message . "\n";
 | 
						|
                $failedTableCtr ++;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        if (!empty($errorMessage)) {
 | 
						|
            $errorMessage .= "\n\nTotal " . $failedTableCtr . " tables failed";
 | 
						|
            $this->fail($errorMessage);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Check table schema and verify if the table has primary key defined.
 | 
						|
     *
 | 
						|
     * @param array $tableSchemaDeclaration
 | 
						|
     * @return bool
 | 
						|
     */
 | 
						|
    private function hasPrimaryKey(array $tableSchemaDeclaration): bool
 | 
						|
    {
 | 
						|
        if (isset($tableSchemaDeclaration['constraint'])) {
 | 
						|
            foreach ($tableSchemaDeclaration['constraint'] as $constraint) {
 | 
						|
                if ($constraint['type'] == 'primary') {
 | 
						|
                    return true;
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Get database schema declarations from file.
 | 
						|
     *
 | 
						|
     * @param string $filePath
 | 
						|
     * @return array
 | 
						|
     */
 | 
						|
    private function getDbSchemaDeclarationByFile(string $filePath): array
 | 
						|
    {
 | 
						|
        $dom = new \DOMDocument();
 | 
						|
        $dom->loadXML(file_get_contents($filePath));
 | 
						|
        return (new Converter())->convert($dom);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Get database schema declarations for whole application
 | 
						|
     *
 | 
						|
     * @return array
 | 
						|
     * @throws LocalizedException
 | 
						|
     */
 | 
						|
    private function getDbSchemaDeclarations(): array
 | 
						|
    {
 | 
						|
        $declarations = [];
 | 
						|
        foreach (Files::init()->getDbSchemaFiles() as $filePath) {
 | 
						|
            $filePath = reset($filePath);
 | 
						|
            preg_match('#/(\w+/\w+)/etc/db_schema.xml#', $filePath, $result);
 | 
						|
            $moduleName = str_replace('/', '_', $result[1]);
 | 
						|
            $moduleDeclaration = $this->getDbSchemaDeclarationByFile($filePath);
 | 
						|
 | 
						|
            foreach ($moduleDeclaration['table'] as $tableName => $tableDeclaration) {
 | 
						|
                if (!isset($tableDeclaration['modules'])) {
 | 
						|
                    $tableDeclaration['modules'] = [];
 | 
						|
                }
 | 
						|
                array_push($tableDeclaration['modules'], $moduleName);
 | 
						|
                $moduleDeclaration = array_replace_recursive(
 | 
						|
                    $moduleDeclaration,
 | 
						|
                    [
 | 
						|
                        'table' => [
 | 
						|
                            $tableName => $tableDeclaration,
 | 
						|
                        ]
 | 
						|
                    ]
 | 
						|
                );
 | 
						|
            }
 | 
						|
            $declarations = array_merge_recursive($declarations, $moduleDeclaration);
 | 
						|
        }
 | 
						|
        return $declarations;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Return primary key exemption tables list
 | 
						|
     *
 | 
						|
     * @return string[]
 | 
						|
     */
 | 
						|
    private function getExemptionList(): array
 | 
						|
    {
 | 
						|
        $exemptionListFiles = str_replace(
 | 
						|
            '\\',
 | 
						|
            '/',
 | 
						|
            realpath(__DIR__) . '/_files/primary_key_exemption_list*.txt'
 | 
						|
        );
 | 
						|
        $exemptionList = [];
 | 
						|
        foreach (glob($exemptionListFiles) as $fileName) {
 | 
						|
            $exemptionList[] = file($fileName, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
 | 
						|
        }
 | 
						|
        return array_merge([], ...$exemptionList);
 | 
						|
    }
 | 
						|
}
 |