承接 popo/generator 相关项目开发

从需求分析到上线部署,全程专人跟进,保证项目质量与交付效率

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

popo/generator

Composer 安装命令:

composer require popo/generator

包简介

Plain Old PHP Object (POPO) / Data Structure / Data Transfer Object (DTO) Generator. Convert YAML schema to PHP class.

README 文档

README

Build and run tests

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.

  1. Define schema file, see tests/fixtures for examples.

  2. 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:

  • name
  • value: 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:

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

Default property type is string.

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

comment

Docblock value for property and methods.

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

default: mixed

Default value.

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

extra: array

Used by datetime data type. Supported values:

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

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).

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

attribute

Attribute value.

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

attributes: array

Attribute value as collection. Supported values:

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

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

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.

On top of that there is a global-config that is defined when using --schemaConfigFilename parameter.

POPO Schema

schema-config

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

schema-file-config

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

popo-config

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

See tests/fixtures for schema examples.

Property name remapping

POPO can remap property keys names, for example change foo_id into fooId.

See Property Name Remapping doc.

Pluggable architecture

New functionality can be provided on the command line, or via configuration.

See Plugins doc.

Doctrine Support

See Doctrine Support doc.

Command line options

See Command Line Options doc.

More Examples

See fixtures and tests for more usage examples.

Composer script

Add popo scrip to composer and run composer popo in a project.

    "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.

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.yml
docker-popo report -s tests/fixtures/popo.yml

See also: bin/docker-popo.

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.

$:
  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}
    ]}}

popo/generator 适用场景与选型建议

popo/generator 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 40.49k 次下载、GitHub Stars 达 20, 最近一次更新时间为 2018 年 07 月 06 日, 在 PHP 生态内属于活跃度较高的组件。

我们在过去多个企业项目中使用过 popo/generator 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 popo/generator 我们能提供哪些服务?
定制开发 / 二次开发

基于 popo/generator 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 40.49k
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 21
  • 点击次数: 10
  • 依赖项目数: 9
  • 推荐数: 0

GitHub 信息

  • Stars: 20
  • Watchers: 1
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2018-07-06