Popo
POPO - plain old PHP object. Generate Data Structures / Data Transfer Objects from a schema.
Install / Use
/learn @oliwierptak/PopoREADME
POPO
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, representing Arrays / 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.
Examples
Single schema file
Simple schema in YAML format, describing properties and relations of POPO objects.
#example.popo.yml
$:
config:
namespace: App\Example\Readme
outputPath: tests/
Example:
Foo:
property: [
{name: title}
{name: bar, type: popo, default: Bar::class}
]
Bar:
property: [
{name: title}
]
Multiple schema files
The same example can be split into multiple files. However, this time, it's the Bar that modifies the Foo definition.
#foo.popo.yml
Example:
Foo:
property: [
{name: title}
]
#bar.popo.yml
Example:
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 uses Bar object as its dependency, and they are both defined under Example schema name.
Generated code usage examples
Instantiate data structure from an array.
use App\Example\Readme\Foo;
$data = [
'title' => 'A title',
'bar' => [
'title' => 'Bar lorem ipsum',
],
];
$foo = (new Foo)->fromArray($data);
echo $foo->getTitle();
echo $foo->requireBar()->getTitle();
Output:
A title
Bar lorem ipsum
Display hierarchy of objects as an array.
use App\Example\Readme\Foo;
$foo = (new Foo);
$foo->requireBar()->setTitle('new value');
print_r($foo->toArray());
Output:
[
'title' => null,
'bar' => [
'title' => 'new value',
],
];
Run bin/popo generate -s tests/fixtures/popo-readme.yml or docker-popo generate -s tests/fixtures/popo-readme.yml to generate files from this example.
Installation
composer require popo/generator --dev
Note: The installation can be skipped when using docker, see Docker support section.
Usage
You can either use it as composer dependency or as docker command.
-
Define schema file, see tests/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 or docker-popo generate -s tests/fixtures/popo.yml.
POPO Schema
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.
Schema Definition
$: # file-config, shared configuration for all POPO objects in current schema file
config:
namespace: string
outputPath: string
namespaceRoot: string|null # if set remaps namespace and outputPath
extend: string|null # which class POPO objects should extend from
implement: string|null # which interface POPO objects should implement
comment: string|null # Class docblock comment
phpComment: string|null # Generated PHP File docblock comment
use: array<string>|[] # Import block in generated PHP class
trait: array<string>|[] # Traits to be used with generated class
attribute: string|null # Class attributes as string
attributes: array<key, value>|[] # Class attributes as key value pairs
classPluginCollection: array<string>|[]
phpFilePluginCollection: array<string>|[]
namespacePluginCollection: array<string>|[]
propertyPluginCollection: array<string>|[]
mappingPolicyPluginCollection: array<string>|[]
default: array # default values
property: array # shared properties
SchemaName: # schema-config
$: # shared configuration for all POPO objects in SchemaName, in all schema files
config:
namespace: string
outputPath: string
namespaceRoot: string|null
extend: string|null
implement: string|null
comment: string|null
phpComment: string|null
use: 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: array
property: [{
name: string,
type:
type: string
default: string
supportedTypes: ['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-config
config:
namespace: string
outputPath: string
namespaceRoot: string|null
extend: string|null
implement: string|null
comment: string|null
phpComment: string|null
use: 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: array
property: [{
name: string,
type:
type: string
default: string
supportedTypes: ['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
}]
Schema configuration options
namespace
Defines generated class namespace.
config:
namespace: App\Example
...
outputPath
Defines output directory.
config:
outputPath: src/
...
namespaceRoot
Defines the begging of outputPath that should be removed.
For example to generated files under src/Example with App\Example namespace.
config:
namespace: App\Example
outputPath: src/
namespaceRoot: App\
...
extend
Which class should the generated class extend from. Must start with \ or contain ::class.
config:
extend: \App\Example\AbstractDto::class
...
implement
Which interface should the generated class implement. Must start with \ or contain ::class.
config:
implement: \App\Example\DtoInterface::class
...
comment
Class comment.
config:
comment: |
@Document(collection="events")
...
phpComment
Generated PHP file comment.
config:
phpComment: |
Auto generated.
@SuppressWarnings(PHPMD)
@phpcs:ignoreFile
...
use
Import statements.
config:
use:
- Doctrine\ODM\MongoDB\Mapping\Annotations\Document
- Doctrine\ODM\MongoDB\Mapping\Annotations\Field
- Doctrine\ODM\MongoDB\Mapping\Annotations\Id
...
trait
Traits statements.
config:
trait:
- App\Example\MyTrait
...
attribute
Class attributes value.
config:
attribute: |
#[Doctrine\ORM\Mapping\Entity(repositoryClass: LogEventRepository::class)]
...
attributes: array
Attribute value as collection. Supported values:
namevalue:mixed
config:
attributes:
- name: Doctrine\ORM\Mapping\Entity
value: {repositoryClass: LogEventRepository::class}
...
classPluginCollection: array
Additional plugins used to generate methods.
config:
classPluginCollection:
- \App\Plugin\ExampleMethodPopoPlugin::class
...
namespacePluginCollection: array
Additional plugins used to generate namespace block.
config:
namespacePluginCollection:
- \App\Plugin\ExampleNamespacePopoPlugin::class
...
propertyPluginCollection: array
Additional plugins used to generate properties.
config:
propertyPluginCollection:
- \App\Plugin\ExamplePropertyPopoPlugin::class
...
mappingPolicyPluginCollection: array
Set of plugins used to map property names, e.g. fooId => FOO_ID.
config:
mappingPolicyPluginCollection:
- \App\Plugin\SpecialCaseMappingPopoPlugin::class
...
Property configuration options
name
The name of the property. The property related methods will be generated based on this value. For example getFooBar().
This is required parameter.
property:
- name: title
...
type
Property data type, supported are:
arrayboolfloatintstringmixedconstpopodatetime
Default property type is string.
property:
- name: precision
type: float
