mirror of
https://github.com/rectorphp/rector.git
synced 2025-04-22 00:12:29 +02:00
add Mysql to Mysqli set
This commit is contained in:
parent
a43986832f
commit
d376e90319
36
config/level/php/mysql_to_mysqli.yml
Normal file
36
config/level/php/mysql_to_mysqli.yml
Normal file
@ -0,0 +1,36 @@
|
||||
# https://stackoverflow.com/a/1390625/1348344
|
||||
# https://github.com/philip/MySQLConverterTool/blob/master/Converter.php
|
||||
services:
|
||||
Rector\Rector\Function_\FunctionReplaceRector:
|
||||
mysql_affected_rows: 'mysqli_affected_rows'
|
||||
mysql_close: 'mysqli_close'
|
||||
mysql_data_seek: 'mysqli_data_seek'
|
||||
mysql_errno: 'mysqli_errno'
|
||||
mysql_error: 'mysqli_error'
|
||||
mysql_fetch_array: 'mysqli_fetch_array'
|
||||
mysql_fetch_assoc: 'mysqli_fetch_assoc'
|
||||
mysql_fetch_lengths: 'mysqli_fetch_lengths'
|
||||
mysql_fetch_object: 'mysqli_fetch_object'
|
||||
mysql_fetch_row: 'mysqli_fetch_row'
|
||||
mysql_field_seek: 'mysqli_field_seek'
|
||||
mysql_free_result: 'mysqli_free_result'
|
||||
mysql_get_client_info: 'mysqli_get_client_info'
|
||||
mysql_get_host_info: 'mysqli_get_host_info'
|
||||
mysql_get_proto_info: 'mysqli_get_proto_info'
|
||||
mysql_get_server_info: 'mysqli_get_server_info'
|
||||
mysql_info: 'mysqli_info'
|
||||
mysql_insert_id: 'mysqli_insert_id'
|
||||
mysql_num_rows: 'mysqli_num_rows'
|
||||
mysql_ping: 'mysqli_ping'
|
||||
mysql_query: 'mysqli_query'
|
||||
mysql_real_escape_string: 'mysqli_real_escape_string'
|
||||
mysql_select_db: 'mysqli_select_db'
|
||||
mysql_set_charset: 'mysqli_set_charset'
|
||||
mysql_stat: 'mysqli_stat'
|
||||
mysql_thread_id: 'mysqli_thread_id'
|
||||
mysql_numfields: 'mysqli_num_fields'
|
||||
mysql_escape_string: 'mysqli_real_escape_string'
|
||||
mysql_client_encoding: 'mysqli_character_set_name'
|
||||
mysql_numrows: 'mysqli_num_rows'
|
||||
mysql_list_processes: 'mysqli_thread_id'
|
||||
mysql_num_fields: 'mysqli_field_count'
|
@ -1,3 +1,6 @@
|
||||
imports:
|
||||
- { resource: "mysql_to_mysqli.yml" }
|
||||
|
||||
services:
|
||||
Rector\Php\Rector\FunctionLike\Php4ConstructorRector: ~
|
||||
Rector\Php\Rector\Ternary\TernaryToNullCoalescingRector: ~
|
||||
|
175
packages/Php/src/Rector/Assign/MysqlAssignToMysqliRector.php
Normal file
175
packages/Php/src/Rector/Assign/MysqlAssignToMysqliRector.php
Normal file
@ -0,0 +1,175 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\Php\Rector\Assign;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\ArrayDimFetch;
|
||||
use PhpParser\Node\Expr\Assign;
|
||||
use PhpParser\Node\Expr\BinaryOp\Smaller;
|
||||
use PhpParser\Node\Expr\FuncCall;
|
||||
use PhpParser\Node\Expr\PostInc;
|
||||
use PhpParser\Node\Expr\PropertyFetch;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
use PhpParser\Node\Name;
|
||||
use PhpParser\Node\Scalar\LNumber;
|
||||
use PhpParser\Node\Stmt\Expression;
|
||||
use PhpParser\Node\Stmt\For_;
|
||||
use Rector\NodeTypeResolver\Node\Attribute;
|
||||
use Rector\Rector\AbstractRector;
|
||||
use Rector\RectorDefinition\CodeSample;
|
||||
use Rector\RectorDefinition\RectorDefinition;
|
||||
|
||||
/**
|
||||
* @see https://www.phpclasses.org/blog/package/9199/post/3-Smoothly-Migrate-your-PHP-Code-using-the-Old-MySQL-extension-to-MySQLi.html
|
||||
*/
|
||||
final class MysqlAssignToMysqliRector extends AbstractRector
|
||||
{
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
private $fieldToFieldDirect = [
|
||||
'mysql_field_len' => 'length',
|
||||
'mysql_field_name' => 'name',
|
||||
'mysql_field_table' => 'table',
|
||||
];
|
||||
|
||||
public function getDefinition(): RectorDefinition
|
||||
{
|
||||
return new RectorDefinition(
|
||||
'Converts more complex mysql functions to mysqli',
|
||||
[
|
||||
new CodeSample(
|
||||
<<<'CODE_SAMPLE'
|
||||
$data = mysql_db_name($result, $row);
|
||||
CODE_SAMPLE
|
||||
,
|
||||
<<<'CODE_SAMPLE'
|
||||
mysqli_data_seek($result, $row);
|
||||
$fetch = mysql_fetch_row($result);
|
||||
$data = $fetch[0];
|
||||
CODE_SAMPLE
|
||||
),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getNodeTypes(): array
|
||||
{
|
||||
return [Assign::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Assign $node
|
||||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
if (! $node->expr instanceof FuncCall) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @var FuncCall $funcCallNode */
|
||||
$funcCallNode = $node->expr;
|
||||
|
||||
if ($this->isName($funcCallNode, 'mysql_tablename')) {
|
||||
return $this->processMysqlTableName($node, $funcCallNode);
|
||||
}
|
||||
|
||||
if ($this->isName($funcCallNode, 'mysql_db_name')) {
|
||||
return $this->processMysqlDbName($node, $funcCallNode);
|
||||
}
|
||||
|
||||
if ($this->isName($funcCallNode, 'mysql_db_query')) {
|
||||
return $this->processMysqliSelectDb($node, $funcCallNode);
|
||||
}
|
||||
|
||||
if ($this->isName($funcCallNode, 'mysql_fetch_field')) {
|
||||
return $this->processMysqlFetchField($node, $funcCallNode);
|
||||
}
|
||||
|
||||
return $this->processFieldToFieldDirect($node, $funcCallNode);
|
||||
}
|
||||
|
||||
private function processMysqlDbName(Assign $assignNode, FuncCall $funcCallNode): FuncCall
|
||||
{
|
||||
$funcCallNode->name = new Name('mysqli_data_seek');
|
||||
|
||||
$mysqlFetchRowFuncCall = new FuncCall(new Name('mysql_fetch_row'), [$funcCallNode->args[0]]);
|
||||
$fetchVariable = new Variable('fetch');
|
||||
$newAssignNode = new Assign($fetchVariable, $mysqlFetchRowFuncCall);
|
||||
$this->addNodeAfterNode($newAssignNode, $assignNode);
|
||||
|
||||
$newAssignNode = new Assign($assignNode->var, new ArrayDimFetch($fetchVariable, new LNumber(0)));
|
||||
$this->addNodeAfterNode($newAssignNode, $assignNode);
|
||||
|
||||
return $funcCallNode;
|
||||
}
|
||||
|
||||
private function processMysqliSelectDb(Assign $assignNode, FuncCall $funcCallNode): FuncCall
|
||||
{
|
||||
$funcCallNode->name = new Name('mysqli_select_db');
|
||||
|
||||
$newAssignNode = new Assign($assignNode->var, new FuncCall(new Name('mysqli_query'), [$funcCallNode->args[1]]));
|
||||
$this->addNodeAfterNode($newAssignNode, $assignNode);
|
||||
|
||||
unset($funcCallNode->args[1]);
|
||||
|
||||
return $funcCallNode;
|
||||
}
|
||||
|
||||
private function processMysqlFetchField(Assign $assignNode, FuncCall $funcCallNode): Assign
|
||||
{
|
||||
$funcCallNode->name = new Name('mysqli_fetch_field');
|
||||
|
||||
if (! isset($funcCallNode->args[1])) {
|
||||
return $assignNode;
|
||||
}
|
||||
|
||||
unset($funcCallNode->args[1]);
|
||||
|
||||
// add for
|
||||
$xVar = new Variable('x');
|
||||
$forNode = new For_([
|
||||
'init' => [new Assign($xVar, new LNumber(0))],
|
||||
'cond' => [new Smaller($xVar, new LNumber(5))],
|
||||
'loop' => [new PostInc($xVar)],
|
||||
'stmts' => [new Expression($funcCallNode)],
|
||||
]);
|
||||
|
||||
$this->addNodeAfterNode($forNode, $assignNode->getAttribute(Attribute::PREVIOUS_EXPRESSION));
|
||||
|
||||
return $assignNode;
|
||||
}
|
||||
|
||||
private function processMysqlTableName(Assign $assignNode, FuncCall $funcCall): FuncCall
|
||||
{
|
||||
$funcCall->name = new Name('mysqli_data_seek');
|
||||
|
||||
$newFuncCall = new FuncCall(new Name('mysql_fetch_array'), [$funcCall->args[0]]);
|
||||
$newAssignNode = new Assign($assignNode->var, new ArrayDimFetch($newFuncCall, new LNumber(0)));
|
||||
|
||||
$this->addNodeAfterNode($newAssignNode, $assignNode);
|
||||
|
||||
return $funcCall;
|
||||
}
|
||||
|
||||
private function processFieldToFieldDirect(Assign $assignNode, FuncCall $funcCallNode): ?Assign
|
||||
{
|
||||
foreach ($this->fieldToFieldDirect as $funcName => $property) {
|
||||
if ($this->isName($funcCallNode, $funcName)) {
|
||||
if ($funcCallNode->getAttribute(Attribute::PARENT_NODE) instanceof PropertyFetch) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$funcCallNode->name = new Name('mysqli_fetch_field_direct');
|
||||
$assignNode->expr = new PropertyFetch($funcCallNode, $property);
|
||||
|
||||
return $assignNode;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\Php\Rector\FuncCall;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Arg;
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Expr\BinaryOp\Concat;
|
||||
use PhpParser\Node\Expr\FuncCall;
|
||||
use PhpParser\Node\Name;
|
||||
use PhpParser\Node\Scalar\String_;
|
||||
use Rector\Rector\AbstractRector;
|
||||
use Rector\RectorDefinition\CodeSample;
|
||||
use Rector\RectorDefinition\RectorDefinition;
|
||||
|
||||
/**
|
||||
* @see https://www.phpclasses.org/blog/package/9199/post/3-Smoothly-Migrate-your-PHP-Code-using-the-Old-MySQL-extension-to-MySQLi.html
|
||||
*/
|
||||
final class MysqlFuncCallToMysqliRector extends AbstractRector
|
||||
{
|
||||
public function getDefinition(): RectorDefinition
|
||||
{
|
||||
return new RectorDefinition(
|
||||
'Converts more complex mysql functions to mysqli',
|
||||
[
|
||||
new CodeSample(
|
||||
<<<'CODE_SAMPLE'
|
||||
mysql_drop_db($database);
|
||||
CODE_SAMPLE
|
||||
,
|
||||
<<<'CODE_SAMPLE'
|
||||
mysqli_query('DROP DATABASE ' . $database);
|
||||
CODE_SAMPLE
|
||||
),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getNodeTypes(): array
|
||||
{
|
||||
return [FuncCall::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param FuncCall $node
|
||||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
if ($this->isName($node, 'mysql_drop_db')) {
|
||||
return $this->processMysqlDropDb($node);
|
||||
}
|
||||
|
||||
if ($this->isName($node, 'mysql_list_dbs')) {
|
||||
$node->name = new Name('mysqli_query');
|
||||
$node->args[0] = new Arg(new String_('SHOW DATABASES'));
|
||||
}
|
||||
|
||||
if ($this->isName($node, 'mysql_list_fields')) {
|
||||
$node->name = new Name('mysqli_query');
|
||||
$node->args[0]->value = $this->joinStringWithNode('SHOW COLUMNS FROM', $node->args[1]->value);
|
||||
|
||||
unset($node->args[1]);
|
||||
}
|
||||
|
||||
if ($this->isName($node, 'mysql_list_tables')) {
|
||||
$node->name = new Name('mysqli_query');
|
||||
$node->args[0]->value = $this->joinStringWithNode('SHOW TABLES FROM', $node->args[0]->value);
|
||||
}
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
private function processMysqlDropDb(FuncCall $funcCallNode): FuncCall
|
||||
{
|
||||
$funcCallNode->name = new Name('mysqli_query');
|
||||
$funcCallNode->args[0]->value = $this->joinStringWithNode('DROP DATABASE', $funcCallNode->args[0]->value);
|
||||
|
||||
return $funcCallNode;
|
||||
}
|
||||
|
||||
private function joinStringWithNode(string $string, Expr $node): Expr
|
||||
{
|
||||
if ($node instanceof String_) {
|
||||
return new String_($string . ' ' . $node->value);
|
||||
}
|
||||
|
||||
return new Concat(new String_($string . ' '), $node);
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
function mysql_to_mysqli_assign() {
|
||||
$result = [];
|
||||
$row = 1;
|
||||
$data = mysql_db_name($result, $row);
|
||||
|
||||
$result = mysql_db_query('database', 'query');
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
function mysql_to_mysqli_assign() {
|
||||
$result = [];
|
||||
$row = 1;
|
||||
mysqli_data_seek($result, $row);
|
||||
$fetch = mysql_fetch_row($result);
|
||||
$data = $fetch[0];
|
||||
|
||||
mysqli_select_db('database');
|
||||
$result = mysqli_query('query');
|
||||
}
|
||||
|
||||
?>
|
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
function mysql_to_mysqli_assign2() {
|
||||
$result = [];
|
||||
$fetch = mysql_fetch_field($result, 5);
|
||||
|
||||
$fetch = mysql_fetch_field($result);
|
||||
|
||||
$length = mysql_field_len($result, 5);
|
||||
$name = mysql_field_name($result, 5);
|
||||
$table = mysql_field_table($result, 5);
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
function mysql_to_mysqli_assign2() {
|
||||
$result = [];
|
||||
for ($x = 0; $x < 5; $x++) {
|
||||
mysqli_fetch_field($result);
|
||||
}
|
||||
$fetch = mysqli_fetch_field($result);
|
||||
|
||||
$fetch = mysqli_fetch_field($result);
|
||||
|
||||
$length = mysqli_fetch_field_direct($result, 5)->length;
|
||||
$name = mysqli_fetch_field_direct($result, 5)->name;
|
||||
$table = mysqli_fetch_field_direct($result, 5)->table;
|
||||
}
|
||||
|
||||
?>
|
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
function mysql_to_mysqli_assign3() {
|
||||
$result = [];
|
||||
$name = mysql_tablename($result, 3);
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
function mysql_to_mysqli_assign3() {
|
||||
$result = [];
|
||||
mysqli_data_seek($result, 3);
|
||||
$name = mysql_fetch_array($result)[0];
|
||||
}
|
||||
|
||||
?>
|
@ -0,0 +1,23 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\Php\Tests\Rector\Assign\MysqlAssignToMysqliRector;
|
||||
|
||||
use Rector\Php\Rector\Assign\MysqlAssignToMysqliRector;
|
||||
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
|
||||
|
||||
final class MysqlAssignToMysqliRectorTest extends AbstractRectorTestCase
|
||||
{
|
||||
public function test(): void
|
||||
{
|
||||
$this->doTestFiles([
|
||||
__DIR__ . '/Fixture/fixture.php.inc',
|
||||
__DIR__ . '/Fixture/fixture2.php.inc',
|
||||
__DIR__ . '/Fixture/fixture3.php.inc',
|
||||
]);
|
||||
}
|
||||
|
||||
public function getRectorClass(): string
|
||||
{
|
||||
return MysqlAssignToMysqliRector::class;
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
function mysql_to_mysqli_func_call() {
|
||||
mysql_drop_db('database_name');
|
||||
|
||||
$database = 'database_name';
|
||||
mysql_drop_db($database);
|
||||
|
||||
$list = mysql_list_dbs();
|
||||
$list = mysql_list_tables($database);
|
||||
|
||||
mysql_list_fields($database_name, $table_name);
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
function mysql_to_mysqli_func_call() {
|
||||
mysqli_query('DROP DATABASE database_name');
|
||||
|
||||
$database = 'database_name';
|
||||
mysqli_query('DROP DATABASE ' . $database);
|
||||
|
||||
$list = mysqli_query('SHOW DATABASES');
|
||||
$list = mysqli_query('SHOW TABLES FROM ' . $database);
|
||||
|
||||
mysqli_query('SHOW COLUMNS FROM ' . $table_name);
|
||||
}
|
||||
|
||||
?>
|
@ -0,0 +1,19 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\Php\Tests\Rector\FuncCall\MysqlFuncCallToMysqliRector;
|
||||
|
||||
use Rector\Php\Rector\FuncCall\MysqlFuncCallToMysqliRector;
|
||||
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
|
||||
|
||||
final class MysqlFuncCallToMysqliRectorTest extends AbstractRectorTestCase
|
||||
{
|
||||
public function test(): void
|
||||
{
|
||||
$this->doTestFiles([__DIR__ . '/Fixture/fixture.php.inc']);
|
||||
}
|
||||
|
||||
public function getRectorClass(): string
|
||||
{
|
||||
return MysqlFuncCallToMysqliRector::class;
|
||||
}
|
||||
}
|
@ -30,6 +30,9 @@ parameters:
|
||||
- '#(.*?)\(\) should return Psr\\Container\\ContainerInterface but returns Symfony\\Component\\DependencyInjection\\ContainerInterface\|null#'
|
||||
|
||||
# false positives
|
||||
- '#Instanceof between PhpParser\\Node\\Expr\\FuncCall and PhpParser\\Node\\Expr\\Assign will always evaluate to false#'
|
||||
- '#Result of && is always false#'
|
||||
|
||||
- '#Offset string does not exist on string#' # 1
|
||||
- '#Array \(array<array<PhpParser\\Node\\Stmt>>\) does not accept array<PhpParser\\Node\\Stmt|null>#'
|
||||
- '#Property Rector\\DependencyInjection\\Loader\\RectorServiceParametersShifter::\$serviceKeywords \(array<string>\) does not accept ReflectionProperty#'
|
||||
@ -46,6 +49,7 @@ parameters:
|
||||
- '#Method Rector\\NodeTypeResolver\\PhpDoc\\NodeAnalyzer\\DocBlockAnalyzer::getTagByName\(\) should return PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PhpDocTagNode but returns PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PhpDocTagNode\|null#'
|
||||
- '#Parameter \#1 \$expr of class PhpParser\\Node\\Expr\\BooleanNot constructor expects PhpParser\\Node\\Expr, PhpParser\\Node given#'
|
||||
- '#Parameter \#1 \$binaryOpNode of method Rector\\CodeQuality\\Rector\\Identical\\SimplifyConditionsRector::createInversedBooleanOp\(\) expects PhpParser\\Node\\Expr\\BinaryOp, PhpParser\\Node given#'
|
||||
- '#Parameter \#1 \$node of method Rector\\PhpParser\\Node\\Commander\\NodeAddingCommander::wrapToExpression\(\) expects PhpParser\\Node\\Expr\|PhpParser\\Node\\Stmt, PhpParser\\Node given#'
|
||||
|
||||
# irelevant
|
||||
- '#Call to function in_array\(\) with arguments string, (.*?) and true will always evaluate to false#'
|
||||
|
@ -41,7 +41,7 @@ final class NodeAddingCommander implements CommanderInterface
|
||||
$this->betterNodeFinder = $betterNodeFinder;
|
||||
}
|
||||
|
||||
public function addNodeAfterNode(Expr $node, Node $positionNode): void
|
||||
public function addNodeAfterNode(Node $node, Node $positionNode): void
|
||||
{
|
||||
$position = $this->resolveNearestExpressionPosition($positionNode);
|
||||
|
||||
|
@ -3,7 +3,6 @@
|
||||
namespace Rector\Rector;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Stmt\Class_;
|
||||
use Rector\Application\AppliedRectorCollector;
|
||||
use Rector\PhpParser\Node\Commander\NodeAddingCommander;
|
||||
@ -47,7 +46,7 @@ trait NodeCommandersTrait
|
||||
$this->propertyAddingCommander = $propertyAddingCommander;
|
||||
}
|
||||
|
||||
protected function addNodeAfterNode(Expr $node, Node $positionNode): void
|
||||
protected function addNodeAfterNode(Node $node, Node $positionNode): void
|
||||
{
|
||||
$this->nodeAddingCommander->addNodeAfterNode($node, $positionNode);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user