dolibarr/dev/tools/rector/src/Renaming/GlobalToFunction.php

433 lines
11 KiB
PHP
Raw Normal View History

<?php
namespace Dolibarr\Rector\Renaming;
use PhpParser\Node;
use PhpParser\Node\Arg;
2024-01-03 00:37:08 +01:00
use PhpParser\Node\Expr\ArrayItem;
use PhpParser\Node\Expr\ArrayDimFetch;
2024-01-05 03:52:06 +01:00
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\BinaryOp\BooleanAnd;
use PhpParser\Node\Expr\BinaryOp\Concat;
use PhpParser\Node\Expr\BinaryOp\Equal;
use PhpParser\Node\Expr\BooleanNot;
use PhpParser\Node\Expr\Empty_;
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Expr\Isset_;
2023-12-26 21:59:08 +01:00
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Name;
use PhpParser\Node\Scalar\String_;
use Rector\Core\NodeManipulator\BinaryOpManipulator;
use Rector\Core\Rector\AbstractRector;
use Rector\Php71\ValueObject\TwoNodeMatch;
use Symplify\RuleDocGenerator\Exception\PoorDocumentationException;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
2023-12-13 14:59:22 +01:00
use PhpParser\Node\Expr\BinaryOp\NotEqual;
use PhpParser\Node\Expr\BinaryOp\Greater;
use PhpParser\Node\Expr\BinaryOp\GreaterOrEqual;
use PhpParser\Node\Expr\BinaryOp\Smaller;
use PhpParser\Node\Expr\BinaryOp\SmallerOrEqual;
2023-12-13 14:59:22 +01:00
use PhpParser\Node\Expr\BinaryOp\NotIdentical;
2023-10-09 10:38:47 +02:00
/**
* Class with Rector custom rule to fix code
*/
class GlobalToFunction extends AbstractRector
{
/**
* @var \Rector\Core\NodeManipulator\BinaryOpManipulator
*/
private $binaryOpManipulator;
2023-10-09 10:38:47 +02:00
/**
* Constructor
*
* @param BinaryOpManipulator $binaryOpManipulator The $binaryOpManipulator
2023-10-09 10:38:47 +02:00
*/
public function __construct(BinaryOpManipulator $binaryOpManipulator)
{
$this->binaryOpManipulator = $binaryOpManipulator;
}
/**
2023-10-09 10:38:47 +02:00
* getRuleDefinition
*
* @return RuleDefinition
* @throws PoorDocumentationException
*/
public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition(
2023-12-13 14:59:22 +01:00
'Change $conf->global to getDolGlobal in context (1) conf->global Operator Value or (2) function(conf->global...)',
2023-12-04 10:23:11 +01:00
[new CodeSample(
'$conf->global->CONSTANT',
'getDolGlobalInt(\'CONSTANT\')'
)]
);
}
2023-10-09 10:38:47 +02:00
/**
2023-10-24 14:22:06 +02:00
* Return a node type from https://github.com/rectorphp/php-parser-nodes-docs/
2023-10-09 10:38:47 +02:00
*
2023-10-24 14:22:06 +02:00
* @return string[]
2023-10-09 10:38:47 +02:00
*/
public function getNodeTypes(): array
{
2024-01-05 03:52:06 +01:00
return [Assign::class, FuncCall::class, MethodCall::class, Equal::class, NotEqual::class, Greater::class, GreaterOrEqual::class, Smaller::class, SmallerOrEqual::class, NotIdentical::class, BooleanAnd::class, Concat::class, ArrayItem::class, ArrayDimFetch::class];
}
/**
2023-10-09 10:38:47 +02:00
* refactor
*
2023-10-24 14:22:06 +02:00
* @param Node $node A node
2023-12-12 03:29:51 +01:00
* @return FuncCall|Equal|Concat|ArrayDimFetch|void
* return $node unchanged or void to do nothing
*/
public function refactor(Node $node)
{
2024-01-05 03:52:06 +01:00
if ($node instanceof Node\Expr\Assign) {
Fix #28071 - New branch to fix bad merge (#28083) * Merge branch 'develop' of git@github.com:Dolibarr/dolibarr.git into develop * Merge branch 'develop' of git@github.com:Dolibarr/dolibarr.git into develop * Qual: Introduce getDataToShowPhoto to prepare generic code * Merge branch 'develop' of git@github.com:Dolibarr/dolibarr.git into develop * Fix missing trans * Fix langs * Merge branch 'develop' of git@github.com:Dolibarr/dolibarr.git into develop * Remove useless files in web templates * Clean code * Fix duplicate translation key * Fix duplicate translation key * Merge branch 'develop' of git@github.com:Dolibarr/dolibarr.git into develop * Fix duplicate key * Fix $object * Debug v19 * WIP SMSing * Merge branch 'develop' of git@github.com:Dolibarr/dolibarr.git into develop * WIP EMAILINGS_SUPPORT_ALSO_SMS * Merge branch 'develop' of git@github.com:Dolibarr/dolibarr.git into develop * Merge branch 'develop' of git@github.com:Dolibarr/dolibarr.git into develop * WIP SMSing * Debug the "validate" feature * Merge branch 'develop' of git@github.com:Dolibarr/dolibarr.git into develop * Clean code * Move rights->x->y into hasRight('x', 'y') * Move rights->x->y into hasRight('x', 'y') * Move rights->x->y into hasRight('x', 'y') * Move rights->x->y into hasRight('x', 'y') * Move rights->x->y into hasRight('x', 'y') * Move rights->x->y into hasRight('x', 'y') * Merge branch 'develop' of git@github.com:Dolibarr/dolibarr.git into develop * Merge branch 'develop' of git@github.com:Dolibarr/dolibarr.git into develop * Enhance rector to fix empty($user->rights->modulex->perm1) * Merge branch 'develop' of git@github.com:Dolibarr/dolibarr.git into develop * Fix template to use v19 dev rules * Fix use v19 dev rules * Fix phpunit * Debug v19 * Clean code * Use rector to convert user->rights into user->hasRight * Clean code * Use rector to convert user->rights into user->hasRight * Use rector to convert user->rights into user->hasRight * Clean code * Fix phpcs * add editorconfig for sql files (#27999) Co-authored-by: Laurent Destailleur <eldy@destailleur.fr> * add model_pdf field in llx_ticket-ticket.sql (#27996) * add model_pdf field in llx_ticket-ticket.sql * Update 19.0.0-20.0.0.sql * Update 19.0.0-20.0.0.sql * Improve wording in README (#27994) * fix phpstan (#27989) * fix phpstan * Update UserRightsToFunction.php --------- Co-authored-by: Laurent Destailleur <eldy@destailleur.fr> * Qual: Fix spelling/working in datapolicy translations (#28006) # Qual: Fix spelling/wording in datapolicy translations Fixed some spelling and wording in datapolicy translations. * qual: phpstan for htdocs/ticket/class/ticketstats.class.php (#27986) htdocs/ticket/class/ticketstats.class.php 98 Parameter #1 $year (string) of method TicketStats::getNbByMonth() should be compatible with parameter $year (int) of method Stats::getNbByMonth() * Merge branch '19.0' of git@github.com:Dolibarr/dolibarr.git into develop * Fix user with readonly perm on email template must be able to read. * Fix doc * Merge branch 'develop' of git@github.com:Dolibarr/dolibarr.git into develop * Better message * Add missing fields in merge of thirdparty * Debug v19 selection of ticket printer per terminal * Merge branch 'develop' of git@github.com:Dolibarr/dolibarr.git into develop * Use constant * NEW: Adding a recipient on emails sent, change status to sent partialy. * fix travis (#28052) * fix travis * Update partnership.class.php * fix php doc (#28047) * fix undefined array key (#28048) * Add region and departament for Cuba (#28046) * Update llx_10_c_regions.sql Add Cuba Regions (id_country=77) * Update llx_20_c_departements.sql Add Provinces Cuba (id country=77) * Find the typo (#28050) * Find the typo * clean code * add last_main_doc field to product (#28045) * add las_main_doc field to product * add field fetch * NEW Add Categorie filter for ActionComm (#28041) * New Add Categorie filter for ActionComm New Add Categorie filter for ActionComm * Fix space errors Fix space errors * Fix space errors 2 Fix space errors 2 * Update cunits.class.php (#28056) FIX: error SQL when creating a Cunit * Update codespell-lines-ignore.txt to avoid PR merge conflict --------- Co-authored-by: Laurent Destailleur <eldy@destailleur.fr> Co-authored-by: Frédéric FRANCE <frederic34@users.noreply.github.com> Co-authored-by: thibdrev <thibault.drevet@gmail.com> Co-authored-by: sonikf <93765174+sonikf@users.noreply.github.com> Co-authored-by: Ikarus <44511582+LeKarSol@users.noreply.github.com> Co-authored-by: Anthony Damhet <73399671+EchoLoGeek@users.noreply.github.com> Co-authored-by: Quentin-Seekness <72733832+Quentin-Seekness@users.noreply.github.com>
2024-02-09 15:58:49 +01:00
// var is left of = and expr is right
2024-01-05 03:52:06 +01:00
if (!isset($node->var)) {
return;
}
if ($this->isGlobalVar($node->expr)) {
$constName = $this->getConstName($node->expr);
if (empty($constName)) {
return;
}
$node->expr = new FuncCall(
new Name('getDolGlobalString'),
[new Arg($constName)]
);
}
return $node;
}
2024-01-03 00:37:08 +01:00
if ($node instanceof Node\Expr\ArrayItem) {
if (!isset($node->key)) {
return;
}
if ($this->isGlobalVar($node->value)) {
$constName = $this->getConstName($node->value);
if (empty($constName)) {
return;
}
$node->value = new FuncCall(
new Name('getDolGlobalString'),
[new Arg($constName)]
);
}
return $node;
}
if ($node instanceof Node\Expr\ArrayDimFetch) {
if (!isset($node->dim)) {
return;
}
if ($this->isGlobalVar($node->dim)) {
$constName = $this->getConstName($node->dim);
if (empty($constName)) {
return;
}
$node->dim = new FuncCall(
new Name('getDolGlobalString'),
[new Arg($constName)]
);
}
return $node;
}
2023-12-12 03:29:51 +01:00
if ($node instanceof FuncCall) {
$tmpfunctionname = $this->getName($node);
2023-12-23 19:33:51 +01:00
// If function is ok. We must avoid a lot of cases like isset(), empty()
2024-01-05 04:18:53 +01:00
if (in_array($tmpfunctionname, array('dol_escape_htmltag', 'dol_hash', 'explode', 'is_numeric', 'length_accountg', 'length_accounta', 'make_substitutions', 'min', 'max', 'trunc', 'urlencode', 'yn'))) {
2023-12-26 21:59:08 +01:00
//print "tmpfunctionname=".$tmpfunctionname."\n";
2023-12-13 14:23:18 +01:00
$args = $node->getArgs();
$nbofparam = count($args);
if ($nbofparam >= 1) {
$tmpargs = $args;
foreach ($args as $key => $arg) { // only 1 element in this array
//var_dump($key);
2023-12-12 03:29:51 +01:00
//var_dump($arg->value);exit;
if ($this->isGlobalVar($arg->value)) {
$constName = $this->getConstName($arg->value);
if (empty($constName)) {
return;
}
$a = new FuncCall(new Name('getDolGlobalString'), [new Arg($constName)]);
2023-12-13 14:23:18 +01:00
$tmpargs[$key] = new Arg($a);
$r = new FuncCall(new Name($tmpfunctionname), $tmpargs);
return $r;
2023-12-12 03:29:51 +01:00
}
}
}
}
return $node;
}
2023-12-13 14:59:22 +01:00
2023-12-26 21:59:08 +01:00
if ($node instanceof MethodCall) {
$tmpmethodname = $this->getName($node->name);
// If function is ok. We must avoid a lot of cases
2024-01-05 04:18:53 +01:00
if (in_array($tmpmethodname, array('fetch', 'idate', 'sanitize', 'select_language', 'trans'))) {
2023-12-26 21:59:08 +01:00
//print "tmpmethodname=".$tmpmethodname."\n";
$expr = $node->var;
$args = $node->getArgs();
$nbofparam = count($args);
if ($nbofparam >= 1) {
$tmpargs = $args;
foreach ($args as $key => $arg) { // only 1 element in this array
//var_dump($key);
//var_dump($arg->value);exit;
if ($this->isGlobalVar($arg->value)) {
$constName = $this->getConstName($arg->value);
if (empty($constName)) {
return;
}
$a = new FuncCall(new Name('getDolGlobalString'), [new Arg($constName)]);
$tmpargs[$key] = new Arg($a);
$r = new MethodCall($expr, $tmpmethodname, $tmpargs);
return $r;
}
}
}
}
return $node;
}
if ($node instanceof Concat) {
if ($this->isGlobalVar($node->left)) {
$constName = $this->getConstName($node->left);
if (empty($constName)) {
return;
}
$leftConcat = new FuncCall(
new Name('getDolGlobalString'),
[new Arg($constName)]
);
$rightConcat = $node->right;
}
if ($this->isGlobalVar($node->right)) {
$constName = $this->getConstName($node->right);
if (empty($constName)) {
return;
}
$rightConcat = new FuncCall(
new Name('getDolGlobalString'),
[new Arg($constName)]
);
$leftConcat = $node->left;
}
if (!isset($leftConcat, $rightConcat)) {
return;
}
return new Concat($leftConcat, $rightConcat);
}
2023-12-13 14:59:22 +01:00
if ($node instanceof BooleanAnd) {
$nodes = $this->resolveTwoNodeMatch($node);
if (!isset($nodes)) {
return;
}
/** @var Equal $node */
$node = $nodes->getFirstExpr();
}
2023-12-13 14:59:22 +01:00
// Now process all comparison like:
// $conf->global->... Operator Value
$typeofcomparison = '';
if ($node instanceof Equal) {
$typeofcomparison = 'Equal';
}
2023-12-13 14:59:22 +01:00
if ($node instanceof NotEqual) {
$typeofcomparison = 'NotEqual';
}
if ($node instanceof Greater) {
$typeofcomparison = 'Greater';
}
if ($node instanceof GreaterOrEqual) {
$typeofcomparison = 'GreaterOrEqual';
}
if ($node instanceof Smaller) {
$typeofcomparison = 'Smaller';
}
if ($node instanceof SmallerOrEqual) {
$typeofcomparison = 'SmallerOrEqual';
}
2023-12-13 14:59:22 +01:00
if ($node instanceof NotIdentical) {
$typeofcomparison = 'NotIdentical';
//var_dump($node->left);
}
if (empty($typeofcomparison)) {
return;
}
$isconfglobal = $this->isGlobalVar($node->left);
if (!$isconfglobal) {
// The left side is not conf->global->xxx, so we leave
return;
}
2023-10-24 14:22:06 +02:00
// Test the type after the comparison conf->global->xxx to know the name of function
2023-12-13 14:59:22 +01:00
$typeright = $node->right->getType();
switch ($typeright) {
case 'Scalar_LNumber':
$funcName = 'getDolGlobalInt';
break;
case 'Scalar_String':
$funcName = 'getDolGlobalString';
break;
default:
$funcName = 'getDolGlobalString';
break;
}
2023-10-24 14:22:06 +02:00
$constName = $this->getConstName($node->left);
if (empty($constName)) {
return;
}
if ($typeofcomparison == 'Equal') {
return new Equal(
new FuncCall(
new Name($funcName),
[new Arg($constName)]
),
$node->right
);
}
2023-12-13 14:59:22 +01:00
if ($typeofcomparison == 'NotEqual') {
return new NotEqual(
new FuncCall(
new Name($funcName),
[new Arg($constName)]
),
$node->right
);
}
if ($typeofcomparison == 'Greater') {
return new Greater(
new FuncCall(
new Name($funcName),
[new Arg($constName)]
),
$node->right
);
}
if ($typeofcomparison == 'GreaterOrEqual') {
return new GreaterOrEqual(
new FuncCall(
new Name($funcName),
[new Arg($constName)]
),
$node->right
);
}
if ($typeofcomparison == 'Smaller') {
return new Smaller(
new FuncCall(
new Name($funcName),
[new Arg($constName)]
),
$node->right
);
}
if ($typeofcomparison == 'SmallerOrEqual') {
return new SmallerOrEqual(
new FuncCall(
new Name($funcName),
[new Arg($constName)]
),
$node->right
);
}
2023-12-13 14:59:22 +01:00
if ($typeofcomparison == 'NotIdentical') {
return new NotIdentical(
new FuncCall(
new Name($funcName),
[new Arg($constName)]
),
$node->right
);
}
}
/**
* Get nodes with check empty
2023-10-09 10:38:47 +02:00
*
* @param BooleanAnd $booleanAnd A BooleandAnd
* @return TwoNodeMatch|null
*/
private function resolveTwoNodeMatch(BooleanAnd $booleanAnd): ?TwoNodeMatch
{
return $this->binaryOpManipulator->matchFirstAndSecondConditionNode(
$booleanAnd,
2023-12-13 14:59:22 +01:00
// Function to check if we are in the case $conf->global->... == $value
function (Node $node): bool {
if (!$node instanceof Equal) {
return \false;
}
return $this->isGlobalVar($node->left);
},
// !empty(...) || isset(...)
function (Node $node): bool {
if ($node instanceof BooleanNot && $node->expr instanceof Empty_) {
return $this->isGlobalVar($node->expr->expr);
}
if (!$node instanceof Isset_) {
return $this->isGlobalVar($node);
}
return \true;
}
);
}
/**
2023-10-24 14:22:06 +02:00
* Check if node is a global access with format conf->global->XXX
2023-10-09 10:38:47 +02:00
*
2023-10-24 14:22:06 +02:00
* @param Node $node A node
2023-12-12 03:29:51 +01:00
* @return bool Return true if node is conf->global->XXX
*/
private function isGlobalVar($node)
{
if (!$node instanceof PropertyFetch) {
return false;
}
if (!$this->isName($node->var, 'global')) {
return false;
}
$global = $node->var;
if (!$global instanceof PropertyFetch) {
return false;
}
if (!$this->isName($global->var, 'conf')) {
return false;
}
return true;
}
/**
2023-10-24 14:22:06 +02:00
* @param Node $node Node to be parsed
* @return Node|void Return the name of the constant
*/
private function getConstName($node)
{
if ($node instanceof PropertyFetch && $node->name instanceof Node\Expr) {
return $node->name;
}
$name = $this->getName($node);
if (empty($name)) {
return;
}
return new String_($name);
}
}