A command line code generator for Drupal.

Last update: May 20, 2022

Drupal Code Generator

Tests Total Downloads Minimum PHP Version

A command line code generator for Drupal.

Installation

  1. Download the latest stable release of the code generator.
  2. Make the file executable.
  3. Move it to a directory that is part of your PATH.

Installation using Composer is also supported.

Upgrade

Simply repeat installation commands.

Usage

# Display navigation.
dcg

# Call generator directly.
dcg plugin:field:widget

# Generate code non-interactively.
dcg config-form -a Example -a example -a SettingsForm -a No

Compatibility

DCG PHP Symfony Twig Drupal Drush
1 7.1+ 3, 4 1, 2 7, 8 9+
2 7.3+ 4, 5 2, 3 7, 9

License

GNU General Public License, version 2 or later.

GitHub

https://github.com/Chi-teck/drupal-code-generator
Comments
  • 1. Version check causes Twig Environment class to be loaded early

    The test for the Twig version in bootstrap.php is loading the Environment class early, even when just parsing for code analysis. I'm just starting to look at this, and I think I'm right the test doesn't happen early in the v2 (master) branch, only v1 used by Drush? So am wondering if there is already a good alternative?

    I stumbled onto the issue because of phpactor/phpactor#1043

    Reviewed by ekes at 2020-05-09 17:40
  • 2. Entity administer permissions

    Currently, content entity generates this kind of permissions:

    Example:

    …
    {% if bundle %}
     *   admin_permission = "administer {{ entity_type_label|lower }} types",
    {% elseif fieldable %}
     *   admin_permission = "administer {{ entity_type_label|lower }}",
    {% else %}
    …
    

    Is that safe and works as intended or this is a bug?

    If user tries to generate custom entity and gives it label "Node" it will share permissions with core "node" module. This is not very obvious and can lead to a lot of problems in the future.

    Config entity type on the other hand, uses entity_type_id.

    I propose to change content entity type permission from using this {{ entity_type_label|lower }} to that {{ entity_type_label }}. This will make generation across entity types consistent and safer for common entity labels.

    Reviewed by Niklan at 2020-04-14 07:40
  • 3. how to use default values via --answers options

    When providing answers via the --answers option, is it possible to allow the default values to be used non-interactively?

    For example, dcg twig-extension -a '{"name": "Example", "machine_name": "example", "class": "ExampleTwigExtension"}' Leaving off class prompts for input. Other values like true, false and null don't seem to work either.

    Thanks!

    Reviewed by richardbporter at 2018-01-09 16:44
  • 4. Allow symfony/filesystem v6

    I was able to install this package with symfony/filesystem v6, but I also had to allow the dev-master version of friendsoftwig/twigcs as there is not yet a compatible release of that package.

    Reviewed by mfb at 2022-02-21 13:16
  • 5. The class_alias in bootstrap.php causes warnings when using preloading

    I am using a generated preloading script which looks something like this:

    $loader = require_once '/app/web/autoload.php';
    // more lines to load PSR-4 directories (irrelevant to this issue)
    
    $files = [
        '/app/vendor/autoload.php',
        '/app/load.environment.php',
        '/app/vendor/composer/autoload_static.php',
        // more files to be preloaded
    ];
    
    foreach ($files as $file) {
        try {
            if (!(is_file($file) && is_readable($file))) {
                throw new \Exception("{$file} does not exist or is unreadable.");
            }
            require_once $file;
        } catch (\Throwable $e) {
            // ...
            throw $e;
        }
    }
    

    This script is set to opcache.preload setting. The script works and I see that the preload is making a difference, but there is a warning on all pages.

    
    Warning: Cannot declare class DrupalCodeGenerator\Twig\TwigEnvironment, because the name is already in use in /app/vendor/chi-teck/drupal-code-generator/src/bootstrap.php on line 44
    
    Warning: Cannot declare class DrupalCodeGenerator\TwigEnvironment, because the name is already in use in /app/vendor/chi-teck/drupal-code-generator/src/bootstrap.php on line 47
    

    After debugging, I realized this is because bootstrap.php is loaded by composer (it's part of composer.json's autoload.files option). As the warnings suggest, this is due to the class_alias line.

    After a lot of debugging and research, I conclude that the problem is that the preloading works somewhat differently for class_alias. In other words, this could be a PHP bug and I do some hints for this in https://github.com/php/php-src/pull/3538 and https://github.com/symfony/symfony/issues/29105.

    My theory is that while preloading correctly handles all the regular classes and functions, it cannot handle class_alias properly. Since class_alias runs both while preloading (as we are requiring the autoloader) and during the execution, it seems that the internal PHP entry for the class name persists during the runtime causing the warning.

    The fix in my case was to wrap the class_alias call inside an if block with class_exists condition. I don't see any warnings after that. I'm going to create a PR against 1.x branch for that shortly.

    Footnote: This is tangentially related to #46 but I don't know if this change would help static analyzers.

    Reviewed by hussainweb at 2020-07-13 13:59
  • 6. Cancel url used during submit() of a confirm form

    A bit confusing to use cancel url here IMO. https://github.com/Chi-teck/drupal-code-generator/blob/e3ce7b84f46f767ebb6405e5bfa8af3237f6ef89/templates/form/confirm/form.twig#L41

    Reviewed by weitzman at 2019-09-15 12:51
  • 7. [1.x] Running commands from other commands, `HelperSet` is initialised at Application level, so InputHandler is filled with questions from prior commands.

    This affects running multiple commands from one

    Running commands from other commands, HelperSet is initialised at Application level, so InputHandler is filled with questions from prior commands.

    I have a generator that:

    • reads in csv data
    • calls another command to generate entity types with that data (repeatedly)

    The input from the last command is still present because the InputHandler is not re-initialised each command only at application level.

    Potential solutions:

    • Initialise a command initiated HelperSet instead of at Application
    • Re-initialise InputHandler within the command so it is clean when the command is run.

    Happy to implement a solution, would either of the above solutions be preferred or accepted?

    Reviewed by richardgaunt at 2021-08-28 03:53
  • 8. Why don't I get a menu link for my settings page when I generate a module?

    I was thinking about adding a template to generate the links menu, but I found that links.menu.twig already exists. Still, the file is not generated. Is this a known issue?

    Did not dig into the code.

    $ drush generate module
    
     Welcome to module-standard generator!
    –––––––––––––––––––––––––––––––––––––––
    
     Module name:
     ➤ Guest Upload
    
     Module machine name [guest_upload]:
     ➤ 
    
     Module description [The description.]:
     ➤ Allow anonymous users to upload images
    
     Package [Custom]:
     ➤ Other
    
     Dependencies (comma separated):
     ➤ block_upload
    
     Would you like to create install file? [Yes]:
     ➤ 
    
     Would you like to create libraries.yml file? [Yes]:
     ➤ no
    
     Would you like to create permissions.yml file? [Yes]:
     ➤ 
    
     Would you like to create event subscriber? [Yes]:
     ➤ 
    
     Would you like to create block plugin? [Yes]:
     ➤ no
    
     Would you like to create a controller? [Yes]:
     ➤ 
    
     Would you like to create settings form? [Yes]:
     ➤ 
    
     The following directories and files have been created or updated:
    –––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
     • modules/custom/guest_upload/guest_upload.info.yml
     • modules/custom/guest_upload/guest_upload.install
     • modules/custom/guest_upload/guest_upload.module
     • modules/custom/guest_upload/guest_upload.permissions.yml
     • modules/custom/guest_upload/guest_upload.routing.yml
     • modules/custom/guest_upload/guest_upload.services.yml
     • modules/custom/guest_upload/src/Controller/GuestUploadController.php
     • modules/custom/guest_upload/src/EventSubscriber/GuestUploadSubscriber.php
     • modules/custom/guest_upload/src/Form/SettingsForm.php
    
    Reviewed by greg-1-anderson at 2020-10-08 16:06
  • 9. Create .phpstorm.meta.php

    Please create generator phpstorm meta file. https://confluence.jetbrains.com/display/PhpStorm/PhpStorm+Advanced+Metadata

    ###EXAMPLE

    <?php
    
    namespace PHPSTORM_META {
    
      use Drupal\node\NodeStorageInterface;
    
      override(\Drupal::service(0), map([
        'date.formatter' => \Drupal\Core\Datetime\DateFormatterInterface::class,
      ]));
      override(\Drupal::entityTypeManager()->getStorage(0), map([
        'node' => NodeStorageInterface::class,
      ]));
    }
    
    Reviewed by batkor at 2020-03-28 12:42
  • 10. ::save() method in content entity form can call parent method

    The generated edit form for a content entity currently copies the logic from the parent method. It is a better practice to instead call the parent method.

    Reviewed by pfrenssen at 2020-09-30 13:26
  • 11. Add support for normalizers in question API.

    This PR is used by https://github.com/drush-ops/drush/pull/2802.

    In general, the question API we offer for generators (a long array) might be getting unweildy. Perhaps we should expect (wrapped?) Symfony Question objects. That can be a future PR.

    Reviewed by weitzman at 2017-06-09 19:01
  • 12. Add service type for config.factory.override implementations

    If I'm not mistaken we don't have this one yet: https://drupal.org/docs/drupal-apis/configuration-api/configuration-override-system#s-providing-overrides-from-modules.

    Just logging my need for it. I do not have time to make a pull request right now.

    Reviewed by verbruggenalex at 2022-04-26 11:18
  • 13. Drop support for global installation

    That applies to both Composer and PHAR installation.

    Reasons

    1. It seems global installation is not widely used. Most people have DCG installed as a local Composer package and use it through Drush.

    2. Maintenance cost. No need to dump services and hooks for autocompletion. Also PHAR compiler can be removed.

    3. Reducing complexity. Currently generators follow "Progressive Enhancement" strategy. Meaning they are capable to work when Drupal is not bootstrapped. And if Drupal context is availble they can enhance user experience somehow. For instance by providing more accurate autocompletion. In practice that looks like follows.

      if ($this->drupalContext) {
        // Some code that enhances UX if Drupal is installed.
      }
      

      This duality brings complexity. With this change we can get rid of this condition and assume that Drupal Context is always available. Eventually that would allow generators to implement deeper integration with Drupal.

    Proposed solution

    • [x] Update installation instruction in README.md and stop generating PHAR file since 2.4.0.
    • [ ] Remove Drupal Conext conditions, dumper scripts, PHAR complier, etc.
    • [ ] Require Drupal core for testing.
    Reviewed by Chi-teck at 2022-01-12 08:16
  • 14. Rethink the namespace for Entity Bundle Classes

    For now, entity bundle classes generated by DCG 2 are placed in the namespace Drupal\mymodule\Entity\Bundle:

    <?php
    
    namespace Drupal\mymodule\Entity\Bundle;
    
    use Drupal\node\Entity\Node;
    
    /**
     * A bundle class for node entities.
     */
    class ArticleBundle extends Node {
    ...
    }
    
    

    However, most documentation and blog posts I've seen for now favor putting them directly in the 'Entity' namespace. Here's an excellent example: https://www.hashbangcode.com/article/drupal-9-entity-bundle-classes.

    This is highly opinionated, but IMHO DCG should follow established best practices, so I'd suggest changing the namespace.

    Reviewed by drubb at 2022-01-06 16:01
  • 15. Database prefixes in PHPSTORM_META

    PhpStorm 2021.1 will support Database prefixes. Should we add support for it?

    namespace PHPSTORM_META {
      override(
        // Virtual function to indicate that all SQL
        // injections will have the following replacement rules.
        sql_injection_subst(),
        map([
          '{' => "PS2021_", // all `{` in injected SQL strings will be replaced with a prefix
          '}' => '',        // all `}` will be replaced with an empty string
        ]));
    }
    

    I can try to implement it.

    Reviewed by Niklan at 2021-03-06 06:20
  • 16. Do not override constructors for service objects, plugins, and controllers

    Problem/Motivation

    According to the Drupal 8 Backward Compatibility Policy, constructors for service objects are considered internal, which means they are subject to change on a minor release:

    The constructor for a service object (one in the container), plugin, or controller is considered internal unless otherwise marked, and may change in a minor release. These are objects where developers are not expected to call the constructor directly in the first place. Constructors for value objects where a developer will be calling the constructor directly are excluded from this statement.

    The implication is that if we override their constructors, and they happen to change their signature on a minor release, it would require us to update our current code for all instances where we're overriding their constructors, to conform to the new signature. This shouldn't have to happen to conform to a minor release.

    There is a good blog post from jrockwitz (maintainer of Webform for D8), that goes into more detail: https://www.jrockowitz.com/blog/webform-road-to-drupal-9

    Solution

    We can implement a new design pattern that would fix the problem.

    As an example, from the controller command, injecting 3 services as an example.

    Before:

    ...
      public function __construct(
        RequestStack $request_stack,
        LoggerInterface $logger,
        Client $httpClient) {
        $this->request = $request_stack->getCurrentRequest();
        $this->logger = $logger;
        $this->httpClient = $httpClient;
      }
    
      public static function create(ContainerInterface $container) {
        return new static(
          $container->get('request_stack'),
          $container->get('logger.factory')->get('foo'),
          $container->get('http_client')
        );
      }
    ...
    

    After:

    ...
      public static function create(ContainerInterface $container) {
        $instance = parent::create($container);
        $instance->request = $container->get('request_stack')->getCurrentRequest();
        $instance->logger = $container->get('logger.factory')->get('foo');
        $instance->httpClient = $container->get('http_client');
        return $instance;
      }
    ...
    

    Some of the most used Drupal contrib modules are already using this design pattern, like the aforementioned Webform, Migrate Plus, Search API, etc.

    Some extra benefits from this approach also include less code bloat:

    • We no longer need a __construct() method, since the __construct() and create() methods are effectively merged into one.
    • We no longer need a use statement per service injected. Their only purpose was so we could typehint on the constructor.

    That reduces the final code lines by quite a bit. Also due to the above, adding a new service dependency injection after already running the generate command is no longer a major PITA.

    I think this solution would include:

    • A change in di.twig's container(services) macro that would use this new design pattern.
    • A change to the generator twig template files, to use this new function, and also remove the now unnecessary use statements as well as the constructor.

    I have a PR ready for these changes.

    This solution could be applied to the following generators:

    • [x] controller
    • [x] block
    • [x] views-argument-default
    • [x] views-field
    Reviewed by GueGuerreiro at 2020-10-04 10:41
Lovely PHP wrapper for using the command-line

ShellWrap What is it? It's a beautiful way to use powerful Linux/Unix tools in PHP. Easily and logically pipe commands together, capture errors as PHP

May 3, 2022
A PHP library for command-line argument processing

GetOpt.PHP GetOpt.PHP is a library for command-line argument processing. It supports PHP version 5.4 and above. Releases For an overview of the releas

May 24, 2022
Command-Line Interface tools

Aura.Cli Provides the equivalent of request ( Context ) and response ( Stdio ) objects for the command line interface, including Getopt support, and a

May 6, 2022
Another Command Line Argument Parser

Optparse — Another Command Line Argument Parser Install 1. Get composer. 2. Put this into your local composer.json: { "require": { "chh/optparse

Nov 1, 2019
👨🏻‍🚀 A command-line tool that gives you the Alpine Day 2021 schedule in your timezone. 🚀
👨🏻‍🚀 A command-line tool that gives you the Alpine Day 2021 schedule in your timezone. 🚀

Alpine Day Schedule a command-line tool that gives you the Alpine Day 2021 schedule in your timezone. ?? Quick start Requires PHP 7.4+ # First, instal

Jun 10, 2021
PHP Interminal is a command-line tool that gives you access to PHP Internals discussions in your terminal.
PHP Interminal is a command-line tool that gives you access to PHP Internals discussions in your terminal.

PHP Interminal is a command-line tool that gives you access to PHP Internals discussions in your terminal. ??

Dec 12, 2021
Patrol is an elegant command-line tool that keeps your PHP Project's dependencies in check.
Patrol is an elegant command-line tool that keeps your PHP Project's dependencies in check.

Patrol is an elegant command-line tool that keeps your PHP Project's dependencies in check. Installation / Usage Requires PHP 8.0+ First, install Patr

May 27, 2022
Twitter raffles in the command line, with PHP and minicli
Twitter raffles in the command line, with PHP and minicli

Rafflebird Rafflebird is a highly experimental CLI application for giveaways / raffles on Twitter, built in PHP with Minicli. Disclaimer: The recent s

May 14, 2022
A PHP command line tool used to install shlink
A PHP command line tool used to install shlink

Shlink installer A PHP command line tool used to install shlink. Installation Install this tool using composer.

Jan 10, 2022
Laracon Schedule a command-line tool that gives you the Laracon Online schedule in your timezone.
Laracon Schedule a command-line tool that gives you the Laracon Online schedule in your timezone.

Laracon Schedule a command-line tool that gives you the Laracon Online schedule in your timezone. ?? Quick start Requires PHP 7.4+ # First, install: c

Dec 13, 2021
Command-line control panel for Nginx Server to manage WordPress sites running on Nginx, PHP, MySQL, and Let's Encrypt
Command-line control panel for Nginx Server to manage WordPress sites running on Nginx, PHP, MySQL, and Let's Encrypt

EasyEngine v4 EasyEngine makes it greatly easy to manage nginx, a fast web-server software that consumes little memory when handling increasing volume

May 22, 2022
Generic PHP command line flags parse library
Generic PHP command line flags parse library

PHP Flag Generic PHP command line flags parse library Features Generic CLI options and arguments parser. Support set value data type(int,string,bool,a

Mar 2, 2022
A simple command-line tool whose aim is to facilitate the continous delivery of PHP apps
A simple command-line tool whose aim is to facilitate the continous delivery of PHP apps

Deployer Simple command-line tool that aims to facilitate the continous delivery of PHP apps, particularly Laravel apps. Imagine you want to update yo

Sep 8, 2021
🍃 In short, it's like Tailwind CSS, but for the PHP command-line applications.
🍃 In short, it's like Tailwind CSS, but for the PHP command-line applications.

Termwind Termwind allows you to build unique and beautiful PHP command-line applications, using the Tailwind CSS API. In short, it's like Tailwind CSS

May 27, 2022
A PHP Command Line tool that makes it easy to compile, concat, and minify front-end Javascript and CSS/SCSS dependencies.

Front End Compiler A PHP Command Line tool that makes it easy to compile, concat, and minify front-end Javascript and CSS/SCSS dependencies. The minif

Nov 12, 2021
php command line script to DCA crypto from Coinbase Pro

dca.php A simple php script designed to be run via the command line via a cron job. This will connect to coinbase pro and buy the crypto coins specifi

Oct 22, 2021
Simple command-line tool to access HiWeb account information

Simple command-line tool to access HiWeb account information.

Nov 17, 2021
💥 Collision is a beautiful error reporting tool for command-line applications
💥 Collision is a beautiful error reporting tool for command-line applications

Collision was created by, and is maintained by Nuno Maduro, and is a package designed to give you beautiful error reporting when interacting with your

May 26, 2022
Console - The Console component eases the creation of beautiful and testable command line interfaces.

Console Component The Console component eases the creation of beautiful and testable command line interfaces. Sponsor The Console component for Symfon

May 25, 2022