There is a complete lack of documentation on creating custom generators, but its a slight abstract of the Zend code generator. Which you will probs have a better time find documentation for. But in terms of registering a new generator in Magento it's basically 2 steps to do so.
https://framework.zend.com/manual/2.4/en/modules/zend.code.generator.examples.html
Create the generator
Generators are extended from the Magento\Framework\Code\Generator\EntityAbstract class and require the following methods are defined _getDefaultConstructorDefinition _getClassMethods.
Good examples imo to work from are either the factory or proxy generators. \Magento\Framework\ObjectManager\Code\Generator\Factory \Magento\Framework\ObjectManager\Code\Generator\Proxy
But a basic generator would look something along the lines of
app/code/Bigeyedeers/Generator/Code/Generator/Example.php
<?php namespace Bigeyedeers\Generated\Code\Generator; class Example extends \Magento\Framework\Code\Generator\EntityAbstract { const ENTITY_TYPE = 'example'; protected function _getDefaultConstructorDefinition() { return [ 'name' => '__construct', 'parameters' => [ ['name' => 'objectManager', 'type' => '\\' . \Magento\Framework\ObjectManagerInterface::class], ['name' => 'instanceName', 'defaultValue' => $this->getSourceClassName()], ], 'body' => "\$this->_objectManager = \$objectManager;\n\$this->_instanceName = \$instanceName;", 'docblock' => [ 'shortDescription' => ucfirst(static::ENTITY_TYPE) . ' constructor', 'tags' => [ [ 'name' => 'param', 'description' => '\Magento\Framework\ObjectManagerInterface $objectManager', ], ['name' => 'param', 'description' => 'string $instanceName'], ], ] ]; } protected function _getClassMethods() { $construct = $this->_getDefaultConstructorDefinition(); // public function create(array $data = array()) $create = [ 'name' => 'create', 'parameters' => [['name' => 'data', 'type' => 'array', 'defaultValue' => []]], 'body' => 'return $this->_objectManager->create($this->_instanceName, $data);', 'docblock' => [ 'shortDescription' => 'Create class instance with specified parameters', 'tags' => [ ['name' => 'param', 'description' => 'array $data'], [ 'name' => 'return', 'description' => $this->getSourceClassName() ], ], ], ]; return [$construct, $create]; } }
Update the generated entities array
I was having trouble adding a new item node into the type declaration from a module. Im sure with more time you'd be able to work it out.
But within app/etc/di.xml add a new item node to the generatedEntities argument of the Magento\Framework\Code\Generator type declartion that points to your new generator class.
app/etc/di.xml
... <type name="Magento\Framework\Code\Generator"> <arguments> <argument name="generatedEntities" xsi:type="array"> <item name="example" xsi:type="string">\Bigeyedeers\Generated\Code\Generator\Example</item> ...
Usage
Now you can inject your generated class just like proxies/factories etc. When you compile then it should pull your new generated class
public function __construct(\Magento\Catalog\Model\CategoryExample $categoryExample) { $this->_categoryExample = $categoryExample; }
Edit by OP
In order not to change the core file app/etc/di.xml, the configuration can be added in app/etc/additional/di.xml (or any other subfolder of app/etc/) and it will be picked up by the config loader automatically.
<?xml version="1.0"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> <type name="Magento\Framework\Code\Generator"> <arguments> <argument name="generatedEntities" xsi:type="array"> <item name="example" xsi:type="string">\Bigeyedeers\Generated\Code\Generator</item> </argument> </arguments> </type> </config>
Bootstrap::create(BP, $_SERVER);which callsself::createObjectManagerFactory($rootDir, $initParams);where the object manager is configured and where the entity generator is instantiated, and then returns an instance of Boostrap. But when creating an instalnce of bootstrap the object manager is instantiated and you cannot pass anymore parameters to the entity generator. This is done way before the modules are readdi.xmlinto theapp/etc/{custom}directory during module installation if the file doesnt exist. Time for some prototyping now we got the facts straight. Thanks for your time, appreciate it!