[MysqlToMysqli] Add MysqlQueryMysqlErrorWithLinkRector

This commit is contained in:
TomasVotruba 2020-02-23 22:49:30 +01:00
parent d4aa8e1671
commit 25aca8b774
8 changed files with 279 additions and 3 deletions

View File

@ -21,7 +21,6 @@ services:
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'
@ -37,7 +36,6 @@ services:
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'
@ -63,3 +61,4 @@ services:
MYSQL_CLIENT_INTERACTIVE: 'MYSQLI_CLIENT_INTERACTIVE'
MYSQL_CLIENT_SSL: 'MYSQLI_CLIENT_SSL'
MYSQL_PRIMARY_KEY_FLAG: 'MYSQLI_PRI_KEY_FLAG'
Rector\MysqlToMysqli\Rector\FuncCall\MysqlQueryMysqlErrorWithLinkRector: null

View File

@ -1,4 +1,4 @@
# All 462 Rectors Overview
# All 463 Rectors Overview
- [Projects](#projects)
- [General](#general)
@ -4337,6 +4337,32 @@ Replace mysql_pconnect() with mysqli_connect() with host p: prefix
<br>
### `MysqlQueryMysqlErrorWithLinkRector`
- class: [`Rector\MysqlToMysqli\Rector\FuncCall\MysqlQueryMysqlErrorWithLinkRector`](/../master/rules/mysql-to-mysqli/src/Rector/FuncCall/MysqlQueryMysqlErrorWithLinkRector.php)
- [test fixtures](/../master/rules/mysql-to-mysqli/tests/Rector/FuncCall/MysqlQueryMysqlErrorWithLinkRector/Fixture)
Add mysql_query and mysql_error with connection
```diff
class SomeClass
{
public function run()
{
$conn = mysqli_connect('host', 'user', 'pass');
- mysql_error();
+ mysqli_error($conn);
$sql = 'SELECT';
- return mysql_query($sql);
+ return mysqli_query($conn, $sql);
}
}
```
<br>
## Nette
### `AddDatePickerToDateControlRector`

View File

@ -17,6 +17,7 @@ use Rector\Core\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
*
* @see \Rector\MysqlToMysqli\Tests\Rector\FuncCall\MysqlFuncCallToMysqliRector\MysqlFuncCallToMysqliRectorTest
*/
final class MysqlFuncCallToMysqliRector extends AbstractRector

View File

@ -0,0 +1,128 @@
<?php
declare(strict_types=1);
namespace Rector\MysqlToMysqli\Rector\FuncCall;
use PhpParser\Node;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Name;
use PHPStan\Type\ObjectType;
use PHPStan\Type\UnionType;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\RectorDefinition\CodeSample;
use Rector\Core\RectorDefinition\RectorDefinition;
/**
* @see https://www.php.net/manual/en/mysqli.error.php
* @see https://www.php.net/manual/en/mysqli.query.php
*
* @see \Rector\MysqlToMysqli\Tests\Rector\FuncCall\MysqlQueryMysqlErrorWithLinkRector\MysqlQueryMysqlErrorWithLinkRectorTest
*/
final class MysqlQueryMysqlErrorWithLinkRector extends AbstractRector
{
/**
* @var string[]
*/
private const FUNCTION_RENAME_MAP = [
'mysql_error' => 'mysqli_error',
'mysql_query' => 'mysqli_query',
];
public function getDefinition(): RectorDefinition
{
return new RectorDefinition('Add mysql_query and mysql_error with connection', [
new CodeSample(
<<<'PHP'
class SomeClass
{
public function run()
{
$conn = mysqli_connect('host', 'user', 'pass');
mysql_error();
$sql = 'SELECT';
return mysql_query($sql);
}
}
PHP
,
<<<'PHP'
class SomeClass
{
public function run()
{
$conn = mysqli_connect('host', 'user', 'pass');
mysqli_error($conn);
$sql = 'SELECT';
return mysqli_query($conn, $sql);
}
}
PHP
),
]);
}
/**
* @return string[]
*/
public function getNodeTypes(): array
{
return [FuncCall::class];
}
/**
* @param FuncCall $node
*/
public function refactor(Node $node): ?Node
{
$connectionVariable = $this->findConnectionVariable($node);
// no connection? → unable to refactor
if ($connectionVariable === null) {
return null;
}
foreach (self::FUNCTION_RENAME_MAP as $oldFunction => $newFunction) {
if (! $this->isName($node, $oldFunction)) {
continue;
}
$node->name = new Name($newFunction);
$node->args = array_merge([new Arg($connectionVariable)], $node->args);
}
return $node;
}
private function findConnectionVariable(FuncCall $funcCall): ?Expr
{
$connectionAssign = $this->betterNodeFinder->findFirstPrevious($funcCall, function (Node $node) {
if (! $node instanceof Assign) {
return null;
}
$staticType = $this->getStaticType($node);
if ($staticType instanceof UnionType) {
if ($staticType->isSuperTypeOf(new ObjectType('mysqli'))) {
return true;
}
if ($staticType->isSuperTypeOf(new ObjectType('mysql'))) {
return true;
}
}
return false;
});
return $connectionAssign !== null ? $connectionAssign->var : null;
}
}

View File

@ -0,0 +1,37 @@
<?php
namespace Rector\MysqlToMysqli\Tests\Rector\FuncCall\MysqlQueryMysqlErrorWithLinkRector\Fixture;
class SomeClass
{
public function run()
{
$conn = mysqli_connect('host', 'user', 'pass');
mysql_error();
$sql = 'SELECT';
return mysql_query($sql);
}
}
?>
-----
<?php
namespace Rector\MysqlToMysqli\Tests\Rector\FuncCall\MysqlQueryMysqlErrorWithLinkRector\Fixture;
class SomeClass
{
public function run()
{
$conn = mysqli_connect('host', 'user', 'pass');
mysqli_error($conn);
$sql = 'SELECT';
return mysqli_query($conn, $sql);
}
}
?>

View File

@ -0,0 +1,41 @@
<?php
namespace Rector\MysqlToMysqli\Tests\Rector\FuncCall\MysqlQueryMysqlErrorWithLinkRector\Fixture;
class PropertyConnection
{
private $conn;
public function run()
{
$this->conn = mysqli_connect('host', 'user', 'pass');
mysql_error();
$sql = 'SELECT';
return mysql_query($sql);
}
}
?>
-----
<?php
namespace Rector\MysqlToMysqli\Tests\Rector\FuncCall\MysqlQueryMysqlErrorWithLinkRector\Fixture;
class PropertyConnection
{
private $conn;
public function run()
{
$this->conn = mysqli_connect('host', 'user', 'pass');
mysqli_error($this->conn);
$sql = 'SELECT';
return mysqli_query($this->conn, $sql);
}
}
?>

View File

@ -0,0 +1,14 @@
<?php
namespace Rector\MysqlToMysqli\Tests\Rector\FuncCall\MysqlQueryMysqlErrorWithLinkRector\Fixture;
class SkipMissingConnect
{
public function run()
{
mysql_error();
$sql = 'SELECT';
return mysql_query($sql);
}
}

View File

@ -0,0 +1,30 @@
<?php
declare(strict_types=1);
namespace Rector\MysqlToMysqli\Tests\Rector\FuncCall\MysqlQueryMysqlErrorWithLinkRector;
use Iterator;
use Rector\Core\Testing\PHPUnit\AbstractRectorTestCase;
use Rector\MysqlToMysqli\Rector\FuncCall\MysqlQueryMysqlErrorWithLinkRector;
final class MysqlQueryMysqlErrorWithLinkRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideData()
*/
public function test(string $file): void
{
$this->doTestFile($file);
}
public function provideData(): Iterator
{
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
}
protected function getRectorClass(): string
{
return MysqlQueryMysqlErrorWithLinkRector::class;
}
}