POPO architecture is fully pluggable, meaning any new or existing functionality can be customized.
There is lots of default plugins, and new ones can be added very easily.
Schema:
$:
config:
classPluginCollection:
- \App\Plugin\ExampleMethodPopoPlugin::class
namespacePluginCollection: []
phpFilePluginCollection: []
propertyPluginCollection: []
mappingPolicyPluginCollection: []
Example:
Foo:
property:
- name: title
Plugin:
namespace App\Plugin;
class ExampleMethodPopoPlugin implements \Popo\Plugin\ClassPluginInterface
{
public function run(BuilderPluginInterface $builder): void
{
$builder->getClass()
->addMethod('example')
->setReturnType('int')
->setBody('return 10;');
}
}
Output:
class Foo
...
public function example(): int
{
return 10;
}
...
}
vendor/bin/popo generate -s popo.yml --classPluginCollection "App\\Plugin\\ExampleMethodPopoPlugin"
-clp, --classPluginCollection[=CLASSPLUGINCOLLECTION] Collection of class names for plugins implementing \Popo\Plugin\ClassPluginInterface
-mpp, --mappingPolicyPluginCollection[=MAPPINGPOLICYPLUGINCOLLECTION] Collection of class names for plugins implementing \Popo\Plugin\MappingPolicyPluginInterface
-nsp, --namespacePluginCollection[=NAMESPACEPLUGINCOLLECTION] Collection of class names for plugins implementing \Popo\Plugin\NamespacePluginInterface
-pfp, --phpFilePluginCollection[=PHPFILEPLUGINCOLLECTION] Collection of class names for plugins implementing \Popo\Plugin\PhpFilePluginInterface
-ppp, --propertyPluginCollection[=PROPERTYPLUGINCOLLECTION] Collection of class names for plugins implementing \Popo\Plugin\PropertyPluginInterface
$configurator = (new PopoConfigurator)
->addPhpFilePluginClass(PhpFilePluginClass::class)
->addNamespacePluginClass(NamespacePluginClass::class)
->addClassPluginClass(PluginClass1:class)
->addClassPluginClass(PluginClass2:class)
->addPropertyPluginClass(PluginProperty1::class)
->addPropertyPluginClass(PluginProperty2::class);
(new PopoFacade)->generate($configurator);
Apart from the typical setters and getters POPO objects have additional helper methods which ease access to, and offer more insight about the data that they represent.
Some of the methods supported by class
type plugins:
isNew
fromArray
fromMappedArray
toArray
toMappedArray
toArrayCamelToSnake
toArraySnakeToCamel
modifiedToArray
requireAll
listModifiedProperties
- ...
Some of the methods supported by property
type plugins:
set
get
require
has
addCollectionItem
- ...
Note: Plugins can be disabled with:
$configurator = (new PopoConfigurator)
->setClassPluginCollection([])
->setPropertyPluginCollection([])
...
POPO generation process is split into few parts:
- PHP file header code generation
- Namespace code generation
- Class methods code generation
- Properties and property methods code generation
Each has corresponding set of plugins.
-
Generates code related to PHP header, e.g. strict type, file comments.
interface PhpFilePluginInterface { public function run(PhpFile $file, Schema $schema): PhpFile; }
-
Generates code related to namespace, e.g. aliases, use statements.
interface NamespacePluginInterface { public function run(BuilderPluginInterface $builder, PhpNamespace $namespace): PhpNamespace; }
-
Generates code related to class methods, e.g.
toArray()
,isNew()
,extends
orimplements
keywords.interface ClassPluginInterface { public function run(BuilderPluginInterface $builder): void; }
-
Generates code related to properties and their methods, e.g.
hasFoo()
,getFoo()
,setFoo()
.interface PropertyPluginInterface { public function run(BuilderPluginInterface $builder, Property $property): void; }
The plugins responsible for code related to schema key mapping, e.g. transforming foo_id
to fooId
.
interface Popo\Plugin\MappingPolicyPluginInterface
{
public function run(string $key): string;
}
See src/Popo/Plugin.