- Notifications
You must be signed in to change notification settings - Fork0
POPO - plain old PHP object. Generate Data Structures / Data Transfer Objects from a schema.
License
oliwierptak/popo
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
POPO - "Plain Old Php Object" was inspired by "Plain Old Java Object" (POJO) concept.
POPO generator can also locate, load, validate, and combine schemas to create PHP source code files, representingArrays / Data Structures / Data Transfer Objects / Doctrine ORM Entities / MongoDB ODM Documents.
POPO Schema can be defined and extended on few levels, and it can be defined in multiple files.
Simple schema in YAML format, describing properties and relations of POPO objects.
#example.popo.yml$:config:namespace:App\Example\ReadmeoutputPath:tests/Example:Foo:property:[{name: title}{name: bar, type: popo, default: Bar::class}]Bar:property:[{name: title}]
The same example can be split into multiple files. However, this time, it's theBar
that modifies theFoo
definition.
#foo.popo.ymlExample:Foo:property:[{name: title}]
#bar.popo.ymlExample:Foo:property:[{name: bar, type: popo, default: Bar::class}]Bar:property:[{name: title}]
The generated code is the same, but the schema dependencies are inverted.
In both cases,Foo
object usesBar
object as its dependency, and they are both defined underExample
schema name.
useApp\Example\Readme\Foo;$data = ['title' =>'A title','bar' => ['title' =>'Bar lorem ipsum', ],];$foo = (newFoo)->fromArray($data);echo$foo->getTitle();echo$foo->requireBar()->getTitle();
Output:
A titleBar lorem ipsum
useApp\Example\Readme\Foo;$foo = (newFoo);$foo->requireBar()->setTitle('new value');print_r($foo->toArray());
Output:
[ 'title' => null, 'bar' => [ 'title' => 'new value', ],];
Runbin/popo generate -s tests/fixtures/popo-readme.yml
ordocker-popo generate -s tests/fixtures/popo-readme.yml
to generate files from this example.
composer require popo/generator --dev
Note: The installation can be skipped when using docker, seeDocker support section.
You can either use it as composer dependency or as docker command.
Define schema file, seetests/fixtures for examples.
Generate POPO files, run:
with composer
vendor/bin/popo generate -s<schema-path> -o<output-path>
with docker
docker-popo generate -s<schema-path> -o<output-path>
For example:bin/popo generate -s tests/fixtures/popo.yml
ordocker-popo generate -s tests/fixtures/popo.yml
.
POPO Schema can be defined and extended on few levels- and it can be defined in multiple files.
The schema supports key mapping- inheritance- collections and encapsulation of other POPO objects.
$:# file-config, shared configuration for all POPO objects in current schema fileconfig:namespace:stringoutputPath:stringnamespaceRoot:string|null# if set remaps namespace and outputPathextend:string|null# which class POPO objects should extend fromimplement:string|null# which interface POPO objects should implementcomment:string|null# Class docblock commentphpComment:string|null# Generated PHP File docblock commentuse:array<string>|[]# Import block in generated PHP classtrait:array<string>|[]# Traits to be used with generated classattribute:string|null# Class attributes as stringattributes:array<key, value>|[]# Class attributes as key value pairsclassPluginCollection:array<string>|[]phpFilePluginCollection:array<string>|[]namespacePluginCollection:array<string>|[]propertyPluginCollection:array<string>|[]mappingPolicyPluginCollection:array<string>|[]default:array# default valuesproperty:array# shared propertiesSchemaName:# schema-config$:# shared configuration for all POPO objects in SchemaName, in all schema filesconfig:namespace:stringoutputPath:stringnamespaceRoot:string|nullextend:string|nullimplement:string|nullcomment:string|nullphpComment:string|nulluse:array<string>|[]trait:array<string>|[]attribute:string|null,attributes:array<key, value>|[]classPluginCollection:array<string>|[]phpFilePluginCollection:array<string>|[]namespacePluginCollection:array<string>|[]propertyPluginCollection:array<string>|[]mappingPolicyPluginCollection:array<string>|[]default:arrayproperty:[{name:string,type:type:stringdefault:stringsupportedTypes:['array','bool','float','int','string','mixed','const','popo', 'datetime'],comment:string|null,default:mixed,itemType:string|null,itemName:string|null,extra:{timezone: ..., format: ...},attribute:string|null,attributes:array<key, value>|[]mappingPolicy:['none', 'lower', 'upper', 'camel-to-snake', 'snake-to-camel'],mappingPolicyValue:string|null}]PopoName:# popo-configconfig:namespace:stringoutputPath:stringnamespaceRoot:string|nullextend:string|nullimplement:string|nullcomment:string|nullphpComment:string|nulluse:array<string>|[]trait:array<string>|[]attribute:string|null,attributes:array<key, value>|[]classPluginCollection:array<string>|[]phpFilePluginCollection:array<string>|[]namespacePluginCollection:array<string>|[]propertyPluginCollection:array<string>|[]mappingPolicyPluginCollection:array<string>|[]default:arrayproperty:[{name:string,type:type:stringdefault:stringsupportedTypes:['array','bool','float','int','string','mixed','const','popo', 'datetime'],comment:string|null,default:mixed,itemType:string|null,itemName:string|null,extra:{timezone: ..., format: ...},attribute:string|null,attributes:array<key, value>|[]mappingPolicy:['none', 'lower', 'upper', 'camel-to-snake', 'snake-to-camel'],mappingPolicyValue:string|null}]
Defines generated class namespace.
config:namespace:App\Example...
Defines output directory.
config:outputPath:src/...
Defines the begging ofoutputPath
that should be removed.For example to generated files undersrc/Example
withApp\Example
namespace.
config:namespace:App\ExampleoutputPath:src/namespaceRoot:App\...
Which class should the generated class extend from. Must start with\ or contain::class
.
config:extend:\App\Example\AbstractDto::class...
Which interface should the generated class implement. Must start with\ or contain::class
.
config:implement:\App\Example\DtoInterface::class...
Class comment.
config:comment:| @Document(collection="events")...
Generated PHP file comment.
config:phpComment:| Auto generated. @SuppressWarnings(PHPMD) @phpcs:ignoreFile...
Import statements.
config:use: -Doctrine\ODM\MongoDB\Mapping\Annotations\Document -Doctrine\ODM\MongoDB\Mapping\Annotations\Field -Doctrine\ODM\MongoDB\Mapping\Annotations\Id...
Traits statements.
config:trait: -App\Example\MyTrait...
Class attributes value.
config:attribute:| #[Doctrine\ORM\Mapping\Entity(repositoryClass: LogEventRepository::class)]...
Attribute value as collection. Supported values:
name
value
:mixed
config:attributes: -name:Doctrine\ORM\Mapping\Entityvalue:{repositoryClass: LogEventRepository::class}...
Additional plugins used to generate methods.
config:classPluginCollection: -\App\Plugin\ExampleMethodPopoPlugin::class...
Additional plugins used to generate namespace block.
config:namespacePluginCollection: -\App\Plugin\ExampleNamespacePopoPlugin::class...
Additional plugins used to generate properties.
config:propertyPluginCollection: -\App\Plugin\ExamplePropertyPopoPlugin::class...
Set of plugins used to map property names, e.g.fooId
=>FOO_ID
.
config:mappingPolicyPluginCollection: -\App\Plugin\SpecialCaseMappingPopoPlugin::class...
The name of the property. The property related methods will be generated based on this value. For examplegetFooBar()
.This is required parameter.
property: -name:title...
Property data type, supported are:
array
bool
float
int
string
mixed
const
popo
datetime
Default property type isstring
.
property: -name:precisiontype:float...
Docblock value for property and methods.
property: -name:titlecomment:Lorem ipsum...
Default value.
property: -name:itemsdefault:\App\ExampleInterface::TEST_BUZZ...
Used bydatetime
data type. Supported values:
format
timezone
property: -name:createdtype:datetimeextra:timezone:Europe/Parisformat:D, d M y H:i:s O...
Used byarray
data type together withitemName
element. Describes type of single array element.
property: -name:productstype:arrayitemType:Product::class...
Used byarray
data type. Describes name of single array element. For example:setProducts(array $products)
,addProduct(Product $item)
.
property: -name:productstype:arrayitemName:product...
Attribute value.
property: -name:priceattribute:|#[Doctrine\ORM\Mapping\Column(type: Types::INTEGER)]...
Attribute value as collection. Supported values:
name
value
:mixed
property: -name:idattributes: -name:Doctrine\ORM\Mapping\Columnvalue:['length: 255']...
Dynamically remaps property names, for example,fooId
=>FOO_ID
. Supported values:
none
lower
upper
camel-to-snake
snake-to-camel
property: -name:fooIdmappingPolicy: -camel-to-snake -upper...
Statically remaps property names, for example,fooId
=>FOO_ID
.
property: -name:fooIdmappingPolicyValue:FOO_ID...
Thepopo-config
values overrideschema-file-config
values- andschema-file-config
values overwriteschema-config
values.
On top of that there is aglobal-config
that is defined when using--schemaConfigFilename
parameter.
The configuration was defined as aSchema
property.It will be used byall POPO objects inall files under given schema.
The configuration was defined as aSchemaFile
property.It will be used byall POPO objects incurrent file.
The configuration was defined as aPOPO
property.It will be used by onespecific POPO objects incurrent file.
Seetests/fixtures for schema examples.
POPO can remap property keys names, for example changefoo_id
intofooId
.
SeeProperty Name Remapping doc.
New functionality can be provided on the command line, or via configuration.
SeePlugins doc.
SeeDoctrine Support doc.
SeeCommand Line Options doc.
Seefixtures andtests for more usage examples.
Add popo scrip to composer and runcomposer popo
in a project.
"scripts": { "popo": [ "bin/popo generate -s <schema-path>" ] }, "scripts-descriptions": { "popo": "Generate POPO files" }
With docker you can generate files without installingPOPO
as dependency in the project.
docker container run -it --rm oliwierptak/popo /app/bin/popo
You can either run the command directly, or create an alias, e.g.:
alias docker-popo='docker container run -it --rm oliwierptak/popo /app/bin/popo ${@}'
For example:
docker-popo generate -s tests/fixtures/popo.ymldocker-popo report -s tests/fixtures/popo.yml
See also:bin/docker-popo.
- POPO
v1.x
- PHP 7.2+ - POPO
v2.x
- PHP 7.2+ - POPO
v3.x
- PHP 7.4+ - POPO
v4.x
- PHP 7.4+ - POPO
v5.x
- PHP 7.4+ - POPO
v6.x
- PHP 8+
Schema example that produces generatedPopoConfigurator class.
$:config:namespace:PopooutputPath:src/phpComment:| @SuppressWarnings(PHPMD) @phpcs:ignoreFilePopo:PopoConfigurator:default:phpFilePluginCollection: -\Popo\Plugin\PhpFilePlugin\StrictTypesPhpFilePlugin::class -\Popo\Plugin\PhpFilePlugin\CommentPhpFilePlugin::classnamespacePluginCollection: -\Popo\Plugin\NamespacePlugin\UseStatementPlugin::classclassPluginCollection: -\Popo\Plugin\ClassPlugin\ClassAttributePlugin::class -\Popo\Plugin\ClassPlugin\ClassCommentPlugin::class -\Popo\Plugin\ClassPlugin\ConstPropertyClassPlugin::class -\Popo\Plugin\ClassPlugin\DateTimeMethodClassPlugin::class -\Popo\Plugin\ClassPlugin\ExtendClassPlugin::class -\Popo\Plugin\ClassPlugin\ImplementClassPlugin::class -\Popo\Plugin\ClassPlugin\IsNewClassPlugin::class -\Popo\Plugin\ClassPlugin\ListModifiedPropertiesClassPlugin::class -\Popo\Plugin\ClassPlugin\MetadataClassPlugin::class -\Popo\Plugin\ClassPlugin\ModifiedToArrayClassPlugin::class -\Popo\Plugin\ClassPlugin\PopoMethodClassPlugin::class -\Popo\Plugin\ClassPlugin\RequireAllClassPlugin::class -\Popo\Plugin\ClassPlugin\UpdateMapClassPlugin::class -\Popo\Plugin\ClassPlugin\FromArrayClassPlugin::class -\Popo\Plugin\ClassPlugin\FromMappedArrayClassPlugin::class -\Popo\Plugin\ClassPlugin\ToArrayClassPlugin::class -\Popo\Plugin\ClassPlugin\ToMappedArrayClassPlugin::class -\Popo\Plugin\ClassPlugin\MappingPolicyMethod\ToArrayLowercasePlugin::class -\Popo\Plugin\ClassPlugin\MappingPolicyMethod\ToArrayUppercasePlugin::class -\Popo\Plugin\ClassPlugin\MappingPolicyMethod\ToArraySnakeToCamelPlugin::class -\Popo\Plugin\ClassPlugin\MappingPolicyMethod\ToArrayCamelToSnakePlugin::classpropertyPluginCollection: -\Popo\Plugin\PropertyPlugin\AddItemPropertyMethodPlugin::class -\Popo\Plugin\PropertyPlugin\DefinePropertyPlugin::class -\Popo\Plugin\PropertyPlugin\GetPropertyMethodPlugin::class -\Popo\Plugin\PropertyPlugin\HasPropertyMethodPlugin::class -\Popo\Plugin\PropertyPlugin\RequirePropertyMethodPlugin::class -\Popo\Plugin\PropertyPlugin\SetPropertyMethodPlugin::classmappingPolicyPluginCollection:none:\Popo\Plugin\MappingPolicy\NoneMappingPolicyPlugin::classlower:\Popo\Plugin\MappingPolicy\LowerMappingPolicyPlugin::classupper:\Popo\Plugin\MappingPolicy\UpperMappingPolicyPlugin::classsnake-to-camel:\Popo\Plugin\MappingPolicy\SnakeToCamelMappingPolicyPlugin::classcamel-to-snake:\Popo\Plugin\MappingPolicy\CamelToSnakeMappingPolicyPlugin::classproperty:[{name: schemaPath}{name: namespace}{name: namespaceRoot}{name: outputPath}{name: phpFilePluginCollection, type: array, itemType: string, itemName: phpFilePluginClass}{name: namespacePluginCollection, type: array, itemType: string, itemName: namespacePluginClass}{name: classPluginCollection, type: array, itemType: string, itemName: classPluginClass}{name: propertyPluginCollection, type: array, itemType: string, itemName: propertyPluginClass}{name: mappingPolicyPluginCollection, type: array, itemType: string, itemName: mappingPolicyPluginClass}{name: schemaConfigFilename}{name: schemaPathFilter}{name: schemaFilenameMask, default: '*.popo.yml'}{name: shouldIgnoreNonExistingSchemaFolder, type: bool}]}}
About
POPO - plain old PHP object. Generate Data Structures / Data Transfer Objects from a schema.