2017 © Pedro Peláez
 

library generator

Plain Old PHP Object (POPO) / Data Transfer Object (TDO) Generator. Convert JSON to PHP class.

image

popo/generator

Plain Old PHP Object (POPO) / Data Transfer Object (TDO) Generator. Convert JSON to PHP class.

  • Friday, July 20, 2018
  • by oliwierptak
  • Repository
  • 1 Watchers
  • 0 Stars
  • 21 Installations
  • PHP
  • 0 Dependents
  • 0 Suggesters
  • 0 Forks
  • 0 Open issues
  • 2 Versions
  • 0 % Grown

The README.md

POPO

Build and run tests, (*1)

POPO - "Plain Old Php Object" was inspired by "Plain Old Java Object" (POJO) concept., (*2)

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., (*3)

POPO Schema can be defined and extended on few levels, and it can be defined in multiple files., (*4)

Examples

Single schema file

Simple schema in YAML format, describing properties and relations of POPO objects., (*5)

#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., (*6)

#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., (*7)

In both cases, Foo object uses Bar object as its dependency, and they are both defined under Example schema name., (*8)

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:, (*9)

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:, (*10)

[
    '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., (*11)

Installation

composer require popo/generator --dev

Note: The installation can be skipped when using docker, see Docker support section., (*12)

Usage

You can either use it as composer dependency or as docker command., (*13)

  1. Define schema file, see tests/fixtures for examples., (*14)

  2. Generate POPO files, run:, (*15)

    • with composer, (*16)

      vendor/bin/popo generate -s <schema-path> -o <output-path>
      
    • with docker sh 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., (*17)

POPO Schema

POPO Schema can be defined and extended on few levels- and it can be defined in multiple files., (*18)

The schema supports key mapping- inheritance- collections and encapsulation of other POPO objects., (*19)

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., (*20)

config:
  namespace: App\Example
  ...

outputPath

Defines output directory., (*21)

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., (*22)

config:
  namespace: App\Example
  outputPath: src/
  namespaceRoot: App\
  ...

extend

Which class should the generated class extend from. Must start with \ or contain ::class., (*23)

config:
  extend: \App\Example\AbstractDto::class
  ...

implement

Which interface should the generated class implement. Must start with \ or contain ::class., (*24)

config:
  implement: \App\Example\DtoInterface::class
   ...

comment

Class comment., (*25)

config:
  comment: |
    @Document(collection="events")
...

phpComment

Generated PHP file comment., (*26)

config:
  phpComment: |
    Auto generated.
    @SuppressWarnings(PHPMD)
    @phpcs:ignoreFile
...

use

Import statements., (*27)

  config:
    use:
      - Doctrine\ODM\MongoDB\Mapping\Annotations\Document
      - Doctrine\ODM\MongoDB\Mapping\Annotations\Field
      - Doctrine\ODM\MongoDB\Mapping\Annotations\Id
    ...

trait

Traits statements., (*28)

  config:
    trait:
      - App\Example\MyTrait
    ...

attribute

Class attributes value., (*29)

  config:
    attribute: |
      #[Doctrine\ORM\Mapping\Entity(repositoryClass: LogEventRepository::class)]
    ...

attributes: array

Attribute value as collection. Supported values:, (*30)

  • name
  • value: mixed
  config:
    attributes:
      - name: Doctrine\ORM\Mapping\Entity
        value: {repositoryClass: LogEventRepository::class}
    ...

classPluginCollection: array

Additional plugins used to generate methods., (*31)

  config:
    classPluginCollection:
      - \App\Plugin\ExampleMethodPopoPlugin::class
    ...

namespacePluginCollection: array

Additional plugins used to generate namespace block., (*32)

  config:
    namespacePluginCollection:
      - \App\Plugin\ExampleNamespacePopoPlugin::class
    ...

propertyPluginCollection: array

Additional plugins used to generate properties., (*33)

  config:
    propertyPluginCollection:
      - \App\Plugin\ExamplePropertyPopoPlugin::class
    ...

mappingPolicyPluginCollection: array

Set of plugins used to map property names, e.g. fooId => FOO_ID., (*34)

  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., (*35)

property: 
  - name: title
    ...

type

Property data type, supported are:, (*36)

  • array
  • bool
  • float
  • int
  • string
  • mixed
  • const
  • popo
  • datetime

Default property type is string., (*37)

property: 
  - name: precision
    type: float
    ...

comment

Docblock value for property and methods., (*38)

property: 
  - name: title
    comment: Lorem ipsum
    ...

default: mixed

Default value., (*39)

property: 
  - name: items
    default: \App\ExampleInterface::TEST_BUZZ
    ...

extra: array

Used by datetime data type. Supported values:, (*40)

  • format
  • timezone
property: 
    - name: created
      type: datetime
      extra: 
          timezone: Europe/Paris
          format: D, d M y H:i:s O
    ...

itemType

Used by array data type together with itemName element. Describes type of single array element., (*41)

property:
    - name: products
      type: array
      itemType: Product::class
    ...

itemName

Used by array data type. Describes name of single array element. For example: setProducts(array $products), addProduct(Product $item)., (*42)

property:
    - name: products
      type: array
      itemName: product
    ...

attribute

Attribute value., (*43)

property:
    - name: price
      attribute: |
      #[Doctrine\ORM\Mapping\Column(type: Types::INTEGER)]
    ...

attributes: array

Attribute value as collection. Supported values:, (*44)

  • name
  • value: mixed
property:
    - name: id
      attributes:
        - name: Doctrine\ORM\Mapping\Column
          value: ['length: 255']
    ...

mappingPolicy: array

Dynamically remaps property names, for example, fooId => FOO_ID. Supported values:, (*45)

  • none
  • lower
  • upper
  • camel-to-snake
  • snake-to-camel
property:
  - name: fooId
    mappingPolicy:
      - camel-to-snake
      - upper
    ...

mappingPolicyValue

Statically remaps property names, for example, fooId => FOO_ID., (*46)

property:
  - name: fooId
    mappingPolicyValue: FOO_ID
  ...

Schema Inheritance

The popo-config values override schema-file-config values- and schema-file-config values overwrite schema-config values., (*47)

On top of that there is a global-config that is defined when using --schemaConfigFilename parameter., (*48)

POPO Schema, (*49)

schema-config

The configuration was defined as a Schema property. It will be used by all POPO objects in all files under given schema., (*50)

schema-file-config

The configuration was defined as a SchemaFile property. It will be used by all POPO objects in current file., (*51)

popo-config

The configuration was defined as a POPO property. It will be used by one specific POPO objects in current file., (*52)

See tests/fixtures for schema examples., (*53)

Property name remapping

POPO can remap property keys names, for example change foo_id into fooId., (*54)

See Property Name Remapping doc., (*55)

Pluggable architecture

New functionality can be provided on the command line, or via configuration., (*56)

See Plugins doc., (*57)

Doctrine Support

See Doctrine Support doc., (*58)

Command line options

See Command Line Options doc., (*59)

More Examples

See fixtures and tests for more usage examples., (*60)

Composer script

Add popo scrip to composer and run composer popo in a project., (*61)

    "scripts": {
        "popo": [
            "bin/popo generate -s <schema-path>"
        ]
    },
    "scripts-descriptions": {
        "popo": "Generate POPO files"
    }

Docker support

With docker you can generate files without installing POPO as dependency in the project., (*62)

docker container run -it --rm oliwierptak/popo /app/bin/popo

You can either run the command directly, or create an alias, e.g.:, (*63)

alias docker-popo='docker container run -it --rm oliwierptak/popo /app/bin/popo ${@}'

For example:, (*64)

docker-popo generate -s tests/fixtures/popo.yml
docker-popo report -s tests/fixtures/popo.yml

See also: bin/docker-popo., (*65)

PHP version compatibility

  • 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+

POPO schema example

Schema example that produces generated PopoConfigurator class., (*66)

$:
  config:
    namespace: Popo
    outputPath: src/
    phpComment: |
      @SuppressWarnings(PHPMD)
      @phpcs:ignoreFile

Popo:
  PopoConfigurator:
    default:
      phpFilePluginCollection:
        - \Popo\Plugin\PhpFilePlugin\StrictTypesPhpFilePlugin::class
        - \Popo\Plugin\PhpFilePlugin\CommentPhpFilePlugin::class
      namespacePluginCollection:
        - \Popo\Plugin\NamespacePlugin\UseStatementPlugin::class
      classPluginCollection:
        - \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::class
      propertyPluginCollection:
        - \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::class
      mappingPolicyPluginCollection:
        none: \Popo\Plugin\MappingPolicy\NoneMappingPolicyPlugin::class
        lower: \Popo\Plugin\MappingPolicy\LowerMappingPolicyPlugin::class
        upper: \Popo\Plugin\MappingPolicy\UpperMappingPolicyPlugin::class
        snake-to-camel: \Popo\Plugin\MappingPolicy\SnakeToCamelMappingPolicyPlugin::class
        camel-to-snake: \Popo\Plugin\MappingPolicy\CamelToSnakeMappingPolicyPlugin::class
    property: [
      {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}
    ]}}

The Versions

20/07 2018

dev-master

9999999-dev

Plain Old PHP Object (POPO) / Data Transfer Object (TDO) Generator. Convert JSON to PHP class.

  Sources   Download

MIT

The Requires

 

The Development Requires

by Oliwier Ptak

20/07 2018

1.0.0

1.0.0.0

Plain Old PHP Object (POPO) / Data Transfer Object (TDO) Generator. Convert JSON to PHP class.

  Sources   Download

MIT

The Requires

 

The Development Requires

by Oliwier Ptak