Coder is library for code-generation, e.g. add property to class, parameter to method, value to array and etc. Library is based on Rector.
This library should be installed as a dependency using Composer:
composer.phar require crmplease/coder --dev
The facade class of this library is Coder
, you need to just create it and call methods, example:
use Crmplease\Coder\Coder;
$coder = Coder::create();
$coder->addToFileReturnArrayByOrder(
'/path/to/file.php',
// path in array
['level1', 'level2.1'],
'value'
);
In all methods value can be:
- int
- float
- string
- instance of
Constant
class (see below) - instance of
Code
class (see below) - array of arrays or types above with keys of types below
In all methods key can be:
- int
- string
- instance of
Constant
class (see below)
In all methods path is a path in array, if path not found, then it will be added. Path is array, so if we use path ['level1', 'level2']
, then empty array became:
[
'level1' => [
'level2' => [
// key => value or value will be added here
],
],
];
Use empty path if you want to change root level in array.
Parts of the path can be same as key:
- int
- string
- instance of
Constant
class (see below)
If you need to pass code, which will be added as is, then you can use Code
class:
use Crmplease\Coder\Code;
new Code('$a = $b;');
If you need to pass some constant, the you can use Constant
class :
use Crmplease\Coder\Constant;
new Constant('\Some\ClassName::class');
$coder->addToFileReturnArrayByOrder(
'/path/to/file.php',
// path in array
['level1.1', 'level2.1'],
// value to add
'newValue'
);
If value 'newValue'
already exists in array, then nothing changed.
Example:
// file /path/to/file.php
return [
'level1.1' => [
'level2.1' => [
'existsValue',
],
],
'level1.2' => [
'value',
],
];
Became:
// file /path/to/file.php
return [
'level1.1' => [
'level2.1' => [
'existsValue',
'newValue',
],
],
'level1.2' => [
'value',
],
];
$coder->addToReturnArrayByOrder(
__DIR__ . '/path/to/ClassName.php',
// method name
'getArray',
// path in array
['level1.1', 'level2.1'],
// value to add
'newValue'
);
If value 'newValue'
already exists in array, then nothing changed.
Example:
// file /path/to/ClassName.php
class ClassName
{
public function getArray(): array
{
return [
'level1.1' => [
'level2.1' => [
'existsValue',
],
],
'level1.2' => [
'value',
],
];
}
}
Became:
// file /path/to/ClassName.php
class ClassName
{
public function getArray(): array
{
return [
'level1.1' => [
'level2.1' => [
'existsValue',
'newValue',
],
],
'level1.2' => [
'value',
],
];
}
}
$coder->addToPropertyArrayByOrder(
__DIR__ . '/path/to/ClassName.php',
// property name
'array',
// path in array
['level1.1', 'level2.1'],
// value to add
'newValue'
);
If value 'newValue'
already exists in array, then nothing changed.
Example:
// file /path/to/ClassName.php
class ClassName
{
protected $array = [
'level1.1' => [
'level2.1' => [
'existsValue',
],
],
'level1.2' => [
'value',
],
];
}
Became:
// file /path/to/ClassName.php
class ClassName
{
protected $array = [
'level1.1' => [
'level2.1' => [
'existsValue',
'newValue',
],
],
'level1.2' => [
'value',
],
];
}
$coder->addToFileReturnArrayByKey(
'/path/to/file.php',
// path in array
['level1.1', 'level2.1'],
// key to add
'newKey',
// value to add
'newValue'
);
If key 'newKey'
already exists in array, then value for this key will be changed to 'newValue'
.
Example:
// file /path/to/file.php
return [
'level1.1' => [
'level2.1' => [
'existsKey' => 'existsValue',
],
],
'level1.2' => [
'key' => 'value',
],
];
Became:
// file /path/to/file.php
return [
'level1.1' => [
'level2.1' => [
'existsKey' => 'existsValue',
'newKey' => 'newValue',
],
],
'level1.2' => [
'key' => 'value',
],
];
$coder->addToReturnArrayByKey(
__DIR__ . '/path/to/ClassName.php',
// method name
'getArray',
// path in array
['level1.1', 'level2.1'],
// key to add
'newKey',
// value to add
'newValue'
);
If key 'newKey'
already exists in array, then value for this key will be changed to 'newValue'
.
Example:
// file /path/to/ClassName.php
class ClassName
{
public function getArray(): array
{
return [
'level1.1' => [
'level2.1' => [
'existsKey' => 'existsValue',
],
],
'level1.2' => [
'key' => 'value',
],
];
}
}
Became:
// file /path/to/ClassName.php
class ClassName
{
public function getArray(): array
{
return [
'level1.1' => [
'level2.1' => [
'existsKey' => 'existsValue',
'newKey' => 'newValue',
],
],
'level1.2' => [
'key' => 'value',
],
];
}
}
$coder->addToPropertyArrayByKey(
__DIR__ . '/path/to/ClassName.php',
// property name
'array',
// path in array
['level1.1', 'level2.1'],
// key to add
'newKey',
// value to add
'newValue'
);
If key 'newKey'
already exists in array, then value for this key will be changed to 'newValue'
.
Example:
// file /path/to/ClassName.php
class ClassName
{
protected $array = [
'level1.1' => [
'level2.1' => [
'existsKey' => 'existsValue',
],
],
'level1.2' => [
'key' => 'value',
],
];
}
Became:
// file /path/to/ClassName.php
class ClassName
{
protected $array = [
'level1.1' => [
'level2.1' => [
'existsKey' => 'existsValue',
'newKey' => 'newValue',
],
],
'level1.2' => [
'key' => 'value',
],
];
}
use Crmplease\Coder\Rector\AddPropertyToClassRector;
$coder->addPropertyToClass(
'/path/to/ClassName.php',
// property name
'newProperty',
// pass true if property should be static
false,
// property visibility, can be VISIBILITY_PRIVATE, VISIBILITY_PROTECTED or VISIBILITY_PUBLIC
AddPropertyToClassRector::VISIBILITY_PRIVATE,
// default value for property, skip it or pass null if isn't needed
'newValue',
// property type in Phpdoc
'string',
// property description in Phpdoc
'description'
);
If property exists, then property will be updated.
Example:
// file /path/to/ClassName.php
class ClassName
{
protected $existsProperty;
}
Became:
// file /path/to/ClassName.php
class ClassName
{
protected $existsProperty;
/**
* @var string description
*/
private $newProperty = 'newValue';
}
$coder->addParameterToMethod(
'/path/to/ClassName.php',
// method name
'__construct',
// parameter name
'newParameter',
// parameter type
'?string',
// if parameter has default value, then true
true,
// parameter default value
'newValue'
);
If parameter exists, then type will be checked. If it's different, then RectorException
will be thrown. If it's equal, then default value will be changed.
Example:
// file /path/to/ClassName.php
class ClassName
{
public function __construct(int $existsParameter = 123) {}
}
Became:
// file /path/to/ClassName.php
class ClassName
{
public function __construct(int $existsParameter = 123, ?string $newParameter = 'newValue') {}
}
$coder->addCodeToMethod(
'/path/to/ClassName.php',
// method name
'__construct',
// code as string
'$this->newProperty = $newParameter;'
);
In simple cases code duplicates is checked (when you try to add one line code).
Example:
// file /path/to/ClassName.php
class ClassName
{
protected $existsProperty;
private $newProperty;
public function __construct(int $existsParameter = 123, ?string $newParameter = 'newValue')
{
$this->existsProperty = $existsParameter;
}
}
Became:
// file /path/to/ClassName.php
class ClassName
{
protected $existsProperty;
private $newProperty;
public function __construct(int $existsParameter = 123, ?string $newParameter = 'newValue')
{
$this->existsProperty = $existsParameter;
$this->newProperty = $newParameter;
}
}
use Crmplease\Coder\Rector\AddMethodToClassRector;
$coder->addMethodToClass(
'/path/to/ClassName.php',
// method name
'newMethod',
// method visibility, can be VISIBILITY_PRIVATE, VISIBILITY_PROTECTED or VISIBILITY_PUBLIC
AddMethodToClassRector::VISIBILITY_PUBLIC,
// pass true if method should be static
false,
// pass true if method should be abstract
false,
// pass true if method should be final
false,
// method return type
'int',
// return description
'return description',
// method description
'method description'
);
If method exists, then signature and Phpdoc will be updated.
Example:
// file /path/to/ClassName.php
class ClassName
{
/**
* Exists description
*
* @return int exists return description
*/
public function existsMethod(): int
{
return 0;
}
}
Became:
// file /path/to/ClassName.php
class ClassName
{
/**
* Exists description
*
* @return int exists return description
*/
public function existsMethod(): int
{
return 0;
}
/**
* method description
* @return int return description
*/
public function newMethod(): int
{
return 0;
}
}
$coder->addPhpdocParamToMethod(
'/path/to/ClassName.php',
// method name
'__construct',
// parameter, for which need to add Phpdoc
'newParameter',
// parameter type
'string|null',
// description for parameter
'some description'
);
If Phpdoc for parameter already exists, then it will be removed and added again.
Example:
// file /path/to/ClassName.php
class ClassName
{
/**
* @param int $existsParameter
*/
public function __construct(int $existsParameter = 123, ?string $newParameter = 'newValue') {}
}
Became
// file /path/to/ClassName.php
class ClassName
{
/**
* @param int $existsParameter
* @param string|null $newParameter some description
*/
public function __construct(int $existsParameter = 123, ?string $newParameter = 'newValue') {}
}
use \Crmplease\Coder\PhpdocProperty;
$coder->addPhpdocPropertyToClass(
'/path/to/ClassName.php',
new PhpdocProperty(
// property name
'newProperty',
// property type, default is mixed
'string|null',
// description for property
'some description'
)
);
If Phpdoc for property already exists, then it will be updated.
Example:
// file /path/to/ClassName.php
/**
* @property int $existsProperty
*/
class ClassName {}
Became
// file /path/to/ClassName.php
/**
* @property int $existsProperty
* @property string|null $newProperty some description
*/
class ClassName {}
You can add several properties:
use \Crmplease\Coder\PhpdocProperty;
$coder->addPhpdocPropertiesToClass(
'/path/to/ClassName.php',
[
new PhpdocProperty('newProperty1'),
new PhpdocProperty('newProperty2'),
]
);
use \Crmplease\Coder\PhpdocMethod;
use \Crmplease\Coder\PhpdocMethodParameter;
$coder->addPhpdocMethodToClass(
'/path/to/ClassName.php',
new PhpdocMethod(
// method name
'newMethod',
// return type, default is mixed
'string|null',
// true if should be static
false,
// array of parameters
[
new PhpdocMethodParameter(
// parameter name
'parameter1',
// parameter type
'int',
// has default value if true
true,
// default value
0
),
],
// description for method
'some description'
)
);
If Phpdoc for method already exists, then it will be updated.
Example:
// file /path/to/ClassName.php
/**
* @method int existsMethod()
*/
class ClassName {}
Became
// file /path/to/ClassName.php
/**
* @method int existsMethod()
* @method string|null newMethod(int $parameter1 = 0) some description
*/
class ClassName {}
You can add several methods:
use \Crmplease\Coder\PhpdocMethod;
$coder->addPhpdocMethodsToClass(
'/path/to/ClassName.php',
[
new PhpdocMethod('newMethod1'),
new PhpdocMethod('newMethod2'),
]
);
$coder->addTraitToClass(
'/path/to/ClassName.php',
\Some\NewTraitName::class
);
If trait is already used, then nothing will be changed.
Example:
// file /path/to/ClassName.php
class ClassName
{
use \Some\ExistsTraitName;
}
Became:
// file /path/to/ClassName.php
class ClassName
{
use \Some\ExistsTraitName;
use \Some\NewTraitName;
}
$coder->removeTraitFromClass(
'/path/to/ClassName.php',
\Some\ExistsTraitName::class
);
If trait isn't used, then nothing will be changed.
Example:
// file /path/to/ClassName.php
class ClassName
{
use \Some\ExistsTraitName;
}
Became:
// file /path/to/ClassName.php
class ClassName
{
}
$coder->changeClassParent(
__DIR__ . '/../src/Mougrim/TestClass.php',
\Some\OtherClass::class
);
If parent doesn't exists, then it will be added.
Example:
// file /path/to/ClassName.php
class ClassName extends \Some\ParentClass {}
Became:
// file /path/to/ClassName.php
class ClassName extends \Some\OtherClass {}
More complex example with constants and code:
use Crmplease\Coder\Code;
use Crmplease\Coder\Constant;
$coder->addToFileReturnArrayByOrder(
'/path/to/file.php',
// path in array
['level1.1', new Constant('\Some\ClassName::class')],
// value to add
[
'newValue',
new Constant('\Some\ClassName::SOME_CONSTANT'),
new Code('Rule::unique(\'countries\')->ignore($country->getKey())'),
]
);
If value 'newValue'
already exists in array, then nothing changed.
Example:
// file /path/to/file.php
return [
'level1.1' => [
\Some\OtherClass::class => ['value'],
\Some\ClassName::class => [
'existsValue',
],
],
'level1.2' => [
'value',
],
];
Became:
// file /path/to/file.php
return [
'level1.1' => [
\Some\OtherClass::class => ['value'],
\Some\ClassName::class => [
'existsValue',
[
'newValue',
\Some\ClassName::SOME_CONSTANT,
Rule::unique('countries')->ignore($country->getKey()),
]
],
],
'level1.2' => [
'value',
],
];
You can provide config object when create coder:
use Crmplease\Coder\Coder;
use Crmplease\Coder\Config;
$config = new Config();
$coder = Coder::create($config);
By default rector shows progress bar when change files. You can disable it:
use Crmplease\Coder\Config;
$config = (new Config())
->setShowProgressBar(false);
By default auto import classes is disabled by config/rector.php
. You can change default value or use mapping/callback for enable/disable auto import classes:
use Crmplease\Coder\Config;
$config = (new Config())
// use default value
->setAutoImport(null)
// always auto import
->setAutoImport(true)
// newer auto import
->setAutoImport(false)
->setAutoImport(
[
// auto import this file
'/path/to/file/with/enabled/auto/import/classes.php' => true,
// doesn't auto import this file
'/path/to/file/with/disabled/auto/import/classes.php' => false,
// use default value
'/path/to/file/with/defaul/auto/import/classes.php' => null,
]
)
->setAutoImport(
static function (string $file): ?bool {
// some logic
// if null is returned, then default value will be used
return $result;
}
)
->setAutoImport([SomeClass::class, 'method']);
Rector config file for coder is config/rector.php
. You can provide path to your own config file with redeclare values from config/rector.php
or add new one:
use Crmplease\Coder\Config;
$config = (new Config())
->setRectorConfigPath('/path/to/rector.php');
For more information about rector configuration see rector documentation.
If you want to auto import classes, then change parameters.auto_import_names
to true
in config/rector.php
.
You can run Rector using command line interface:
vendor/bin/rector process --config path/to/project/rector.php\\
--autoload-file path/to/project/vendor/autoload.php\\
--only "\Crmplease\Coder\Rector\AddToReturnArrayByOrderRector"\\
path/to/project/Path/To/Class.php
But command line interface doesn't allow to pass parameters to rectors. You can pass parameters using setters in config file config/rector.php
config. For example:
// ...
$services->set(Rector\AddToReturnArrayByOrderRector::class)
->call('setMethod', ['getArray'])
->call('setPath', ['level1', 'level2'])
->call('setValue', ['newValue']);
// ...
Config for AddToFileReturnArrayByOrderRector:
- setPath: path in array where need to add value
- setValue: value, which need to add to return array
Config for AddToReturnArrayByOrderRector:
- setMethod: method name, to which need to add value/constant to return array, method should have only one return statement, which return array
- setPath: path in array where need to add value
- setValue: value, which need to add to return array
Config for AddToPropertyArrayByOrderRector:
- setProperty: property name, to which need to add value/constant, property should be array
- setPath: path in array where need to add value
- setValue: value, which need to add to return array
Config for AddToFileReturnArrayByKeyRector:
- setPath: path in array where need to add key => value
- setKey: key, by which need to add to return array
- setValue: value, which need to add to return array by key
Config for AddToReturnArrayByKeyRector:
- setMethod: method name, to which need to add value/constant to return array by key, method should have only one return statement, which return array
- setPath: path in array where need to add key => value
- setKey: key, by which need to add to return array
- setValue: value, which need to add to return array by key
Config for AddToPropertyArrayByKeyRector:
- setProperty: property name, to which need to add value/constant by key, property should be array
- setPath: path in array where need to add key => value
- setKey: key, by which need to add to property array
- setValue: value, which need to add to property array by key
Config for AddPropertyToClassRector:
- setProperty: property name which need to add
- setVisibility: property visibility 'public', 'protected' or 'private', default is 'private'
- setIsStatic: is property static or no, true or false, default false
- setValue: default property value, don't pass it if isn't needed
- setType: property type in Phpdoc, can be class name started with '\' or scalar type, can by autodetected by default value
- setDescription: property description in Phpdoc
Config for AddParameterToMethodRector:
- setMethod: method name, to which need to add parameter
- setParameter: parameter name which need to add
- setParameterType: parameter type which need to add, can be class name started with '\' or scalar type
- setHasValue: has default value or not, true or false, default true
- setValue: default parameter value
Config for AddCodeToMethodRector:
- setMethod: method name, to which need to add code
- setCode: code which need to add
Config for AddMethodToClassRector:
- setMethod: method name which need to add
- setVisibility: method visibility 'public', 'protected' or 'private', default is 'private'
- setIsStatic: is method static or no, true or false, default false
- setIsAbstract: is method abstract or no, true or false, default false
- setIsFinal: is method final or no, true or false, default false
- setReturnType: method return type, can be class name started with '\' or scalar type or void
- setReturnDescription: return description in Phpdoc
- setDescription: method description in Phpdoc
Config for AddTraitToClassRector:
- setTrait: trait name, to which need to add to class
Config for RemoveTraitFromClassRector:
- setTrait: trait name, to which need to remove from class
Config for AddPhpdocParamToMethodRector:
- setMethod: method name, to which Phpdoc need to add parameter
- setParameter: parameter name which need to add to Phpdoc
- setParameterType: parameter type which need to add to Phpdoc, can be class name started with '\' or scalar type, collections, union type
- setDescription: description for param in Phpdoc
Config for AddPhpdocPropertyToClassRector:
- setProperty: property name which need to add to Phpdoc
- setPropertyType: property type which need to add to Phpdoc, can be class name started with '\' or scalar type, collections, union type
- setDescription: description for property in Phpdoc
Config for AddPhpdocMethodToClassRector:
- setMethod: method name which need to add to Phpdoc
- setReturnType: method return type which need to add to Phpdoc, can be class name started with '\' or scalar type, collections, union type
- setIsStatic: is method static or no, true or false, default false
- setParameters: array of
PhpdocMethodParameter
objects - setDescription: description for method in Phpdoc
Config for ChangeClassParentRector:
- setParentClass: new parent class name