- Issue created by @daniel.rosenkranz
- 🇮🇹Italy apaderno Brescia, 🇮🇹
Thank you for applying!
Please read Review process for security advisory coverage: What to expect → for more details and Security advisory coverage application checklist → to understand what reviewers look for. Tips for ensuring a smooth review → gives some hints for a smoother review.
The important notes are the following.
- If you have not done it yet, enable GitLab CI for the project, and fix what reported from the phpcs job. This help to fix most of what reviewers would report.
- For the time this application is open, only your commits are allowed. No other people, including other maintainers/co-maintainers can make commits.
- The purpose of this application is giving you a new drupal.org role that allows you to opt projects into security advisory coverage, either projects you already created, or projects you will create. The project status won't be changed by this application.
- Nobody else will get the permission to opt projects into security advisory policy. If there are other maintainers/co-maintainers who will to get that permission, they need to apply with a different module.
- We only accept an application per user. If you change your mind about the project to use for this application, or it is necessary to use a different project for the application, please update the issue summary with the link to the correct project and the issue title with the project name and the branch to review.
To the reviewers
Please read How to review security advisory coverage applications → , Application workflow → , What to cover in an application review → , and Tools to use for reviews → .
The important notes are the following.
- It is preferable to wait for a Code Review Administrator before commenting on newly created applications. Code Review Administrators will do some preliminary checks that are necessary before any change on the project files is suggested.
- Reviewers should show the output of a CLI tool → only once per application. The configuration used for these tools needs to be the same configuration used by GitLab CI, stored in the GitLab Templates repository.
- It may be best to have the applicant fix things before further review.
For new reviewers, I would also suggest to first read In which way the issue queue for coverage applications is different from other project queues → .
- 🇮🇳India vishal.kadam Mumbai
1. FILE: paragraph_group.libraries.yml
main: version: VERSION
settings: version: VERSION
VERSION is only used by Drupal core modules. Contributed modules should use a literal string that does not change with the Drupal core version a site is using.
2. FILE: paragraph_group.module
/** * @file * Contains paragraph_group.module. */
The usual description for a .module file is “Hook implementations for the [module name] module”, where [module name] is the module name given in the .info.yml file.
/** * Implements hook_form_FORM_ID_alter(). * * @param array $form * The form array, passed by reference. * @param \Drupal\Core\Form\FormStateInterface $form_state * The form state object. * @param string $form_id * The form ID. */ function paragraph_group_form_paragroup_config_form_alter(
/** * Implements hook_form_FORM_ID_alter(). * * @param array $form * The form array, passed by reference. * @param \Drupal\Core\Form\FormStateInterface $form_state * The form state object. * @param string $form_id * The form ID. */ function paragraph_group_form_system_themes_admin_form_alter(
The description for this hook should also say for which form that hook is implemented, either by indicating that with the name of the class that implements the form (namespace included) or the form ID (which is usually indicated by
getFormId()
).3. FILE: src/Form/ParagroupConfigForm.php
/** * Constructor. * * @param \Drupal\paragraph_group\Paragroup\ParagroupBatch $batch_obj * The batch processing service. * @param \Drupal\paragraph_group\Paragroup\ParagroupFormData $form_data * The form data service. */ public function __construct(
FILE: src/Paragroup/ParagroupBatch.php
/** * Constructor. * * @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation * The string translation service. * @param \Drupal\paragraph_group\Paragroup\ParagroupFormData $form_data * The form data service. */ public function __construct(
FILE: src/Paragroup/ParagroupFormData.php
/** * Constructor. * * @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation * The string translation service. */ public function __construct(TranslationInterface $string_translation) {
The documentation comment for constructors is not mandatory anymore, If it is given, the description must be “Constructs a new [class name] object”, where [class name] includes the class namespace.
- 🇦🇺Australia daniel.rosenkranz
Thanks for your replies everyone. The fixes mentioned by @vishal.kadam should be fine, but I'm also setting up Gitlab CI as well as advised by @avpaderno. So I'll let you know when I've completed all the resulting fixes asap.
- 🇦🇺Australia daniel.rosenkranz
Hi all,
I have now:
- Implemented Gitlab CI for my module, and duplicated it's PHPCS configuration in my local development environment.
- Fixed all issues noted by PHPCS. Commits at https://git.drupalcode.org/project/paragraph_group are now passing the PHPCS test in the Gitlab CI build pipeline.
- Also fixed the issues raised by Vishal Kadam above.
So please let me know any further issues, and I'll do my best to address them asap. Appreciate your help.
- 🇮🇹Italy apaderno Brescia, 🇮🇹
- The following points are just a start and don't necessarily encompass all of the changes that may be necessary
- A specific point may just be an example and may apply in other places
- A review is about code that does not follow the coding standards, contains possible security issue, or does not correctly use the Drupal API
- The single review points are not ordered, not even by importance
src/Form/ParagroupConfigForm.php
ConfigFormBase::__construct()
needs to be called. Since its parameters changed in Drupal 10.2, the project cannot be compatible with all the Drupal 10 releases and Drupal 11; it needs to require at least Drupal 10.2.With Drupal 10 and Drupal 11, there is no longer need to use
#default_value
for each form element, when the parent class isConfigFormBase
: It is sufficient to use#config_target
, as in the following code.$form['image_toolkit'] = [ '#type' => 'radios', '#title' => $this->t('Select an image processing toolkit'), '#config_target' => 'system.image:toolkit', '#options' => [], ];
Using that code, it is no longer needed to save the configuration values in the form submission handler: The parent class will take care of that.
Truly, given the code used by that class,
ConfigFormBase
is not the appropriate parent class. Form classes do not need to have a parent class; they just need to implementFormInterface
./** * Create function for constructor. * * @param \Symfony\Component\DependencyInjection\ContainerInterface $container * The dependency injection container. * * @return static * A new instance of this class. */
The short description is wrong, but it is also not necessary, since for methods defined in a parent class, a trait, or an interface, the documentation comment is just
@{inheritdoc}
.$msg = t('Configuration changes saved successfully.'); \Drupal::messenger()->addStatus($msg);
Dependencies needs to be injected via
create()
.Classes that implements
ContainerInjectionInterface
use $this->t(), nott()
(which requires them to useStringTranslationTrait
.src/Paragroup/ParagroupBatch.php
if ($result) { $result = $result . ' out of ' . $result; $info = self::getSectionInfoFromFuncName($func_name); $msg_params = [ '@result' => $result, '@section_type' => $info[0], '@action' => $info[1], ]; $msg = t('@result @section_type @action.', $msg_params);
'out of'
is not translated int('@result @section_type @action.', $msg_params);
. What the translators can do with @result @section_type @action. is changing the order of the placeholders to the correct order for their languange, and replacing the character at the end of the sentence with the right character in their language. (For example, Japanese uses 。.)src/Paragroup/ParagroupFormData.php
/** * The string translation service. * * @var \Drupal\Core\StringTranslation\TranslationInterface */ protected $stringTranslation;
That is a property already defined by
StringTranslationTrait
.public function __construct(TranslationInterface $string_translation) { $this->stringTranslation = $string_translation; }
It is correct to initialize that property, but there is
StringTranslationTrait::setStringTranslation()
$manage_fields = $this->t('<a href="@url" target="_blank">Manage Fields</a>', ['@url' => $url]); $has_field = $this->hasAdminTitleField($machine_name);
The correct placeholder for URLs is :variable as shown in the documentation for
FormattableMarkup::placeholderFormat()
and must always be wrapped in quotes. That is the placeholder used also by Drupal core code for URLs that take to drupal.org.$output = ''; $output .= '<h3>' . t('About') . '</h3>'; $output .= '<p>' . t('The Actions module provides tasks that can be executed by the site such as unpublishing content, sending email messages, or blocking a user. Other modules can trigger these actions when specific system events happen; for example, when new content is posted or when a user logs in. Modules can also provide additional actions. For more information, see the <a href=":documentation">online documentation for the Actions module</a>.', [ ':documentation' => 'https://www.drupal.org/documentation/modules/action', ]) . '</p>';
paragraph_group.module
For a new module that aims to be compatible with Drupal 10 and Drupal 11, I would rather implement hooks as class methods as described in Support for object oriented hook implementations using autowired services → .
- 🇦🇺Australia daniel.rosenkranz
Thank you for your feedback @avpaderno. Just to let you know that I’m currently working on some refactorings based on your recommendations, which should be complete by early next week.
- 🇦🇺Australia daniel.rosenkranz
Thank you avpaderno for your detailed initial code review. Please see the current commit at https://git.drupalcode.org/project/paragraph_group
I have tried to address your feedback through a comprehensive three-phase approach to ensure the highest possible code quality and security standards in my implementation.
1. Direct Issue Resolution: I have systematically addressed each explicit issue raised in your review, implementing proper dependency injection, modern config targets, constructor patterns, translation improvements, and particularly object-oriented hook implementations. I have now also been able to delete the paragraph_group.module file. So these changes ensure consistent adherence to current Drupal coding standards throughout the identified areas.
2. Systematic Extrapolation: Taking your note that the review points were just a start, I conducted comprehensive dependency injection refactoring across the entire codebase. This eliminated all static \Drupal::service() calls, converted utility classes to proper services, and applied security best practices systematically beyond the explicitly mentioned areas.
3. Comprehensive Quality Assurance: I have also now achieved 100% compliance with all Gitlab-CI test suites at git.drupalcode.org, including PHPStan static analysis, ESLint JavaScript standards, spell checking, and code formatting. This demonstrates proactive security awareness extending well beyond the minimum PHPCS requirements mentioned in the application process.
So I feel that these changes collectively demonstrate my commitment to exceptional code quality, security best practices, and modern Drupal architecture. And while I'm obviously keen to meet requirements as soon as possible, I remain ready to implement further fixes from further reviews as needed. So I look forward to more feedback.
- 🇷🇴Romania bbu23
Hi! I didn't manage to do a full review, but below you have a brief one. This should give an idea:
- There is no dev release. While not mandatory, it's a highly encouraged practice in the Drupal community.
- I can still see some PHPCS warnings when using the "DrupalPractice" standard:
FILE: /var/www/html/web/modules/custom/paragraph_group/paragraph_group.install ------------------------------------------------------------------------------ FOUND 0 ERRORS AND 2 WARNINGS AFFECTING 2 LINES ------------------------------------------------------------------------------ 9 | WARNING | There must be no blank line following an inline comment 99 | WARNING | Unused variable $version. ------------------------------------------------------------------------------ FILE: /var/www/html/web/modules/custom/paragraph_group/src/Form/ParagroupConfigForm.php --------------------------------------------------------------------------------------- FOUND 0 ERRORS AND 4 WARNINGS AFFECTING 4 LINES --------------------------------------------------------------------------------------- 89 | WARNING | Unused variable $key. 573 | WARNING | Unused variable $section. 717 | WARNING | Unused variable $section. 723 | WARNING | Unused variable $key. --------------------------------------------------------------------------------------- FILE: /var/www/html/web/modules/custom/paragraph_group/src/Paragroup/ParagroupFieldGroupManager.php --------------------------------------------------------------------------------------------------- FOUND 0 ERRORS AND 3 WARNINGS AFFECTING 2 LINES --------------------------------------------------------------------------------------------------- 211 | WARNING | Unused variable $entity_type. 295 | WARNING | Unused variable $entity_type. 295 | WARNING | Unused variable $bundle. --------------------------------------------------------------------------------------------------- FILE: /var/www/html/web/modules/custom/paragraph_group/src/Paragroup/ParagroupFormData.php ------------------------------------------------------------------------------------------ FOUND 0 ERRORS AND 1 WARNING AFFECTING 1 LINE ------------------------------------------------------------------------------------------ 217 | WARNING | Unused variable $field_name. ------------------------------------------------------------------------------------------
- Kindly review the README file format, including first line, links, sections, headings etc. More in README.md template →
- Object oriented hooks are not supported in Drupal 10 unless they're called from the module file. Your module supports both Drupal 10 and 11, therefore you need to add backwards compatibility as described in the article linked in comment #7 📌 [3.0.x] Paragraph Group Needs review . In its current form, the module hooks are not invoked at all in Drupal 10.
- Also, you don't have many hooks, but there are 2 service parameters that can tell Drupal 11 to stop procedural hook scan and these are purely optional: Improve performance by preventing unnecessary scanning of procedural hooks → and hooks_converted parameter and StopProceduralHookScan attributes have been renamed. → . Example if you wish to add them:
parameters: # For Drupal 11.1 and lower. MODULENAME.hooks_converted: true # For Drupal 11.2 and higher. MODULENAME.skip_procedural_hook_scan: true
- The error message passed to the
addError
method is not translatable insrc/Hook/ParagroupHooks.php
line 128.- The
create
method should returnnew static()
instead ofnew self()
in src/Form/ParagroupConfigForm.php-
src/Hook/ParagroupHooks.php
: The$helper
and$field_group_manager
arguments are missing their type causing the autowire service to fail. Also, the@var \Drupal\paragraph_group\Paragroup\ParagroupHelper
class doesn't seem to exist anymore (line 31).- The
validateForm
is a method that returnsvoid
. In thesrc/Form/ParagroupConfigForm.php
returning a void function result is incorrect.- There is no entity type that has the
paragraph_type
ID:$this->entityTypeManager->getStorage('paragraph_type')->loadMultiple();
insrc/Paragroup/ParagroupFormData.php
Actually, in its current state, the module throws fatal errors in both Drupal 10 and 11, it is unusable. Please ensure that the module is running smoothly with Drupal Core ^10.2 || 11 as described in the info file, and carefully test every aspect of it and/or provide tests to ensure quality and stability.
- 🇦🇺Australia daniel.rosenkranz
Hi bbu23,
Thank you for your detailed review, and apologies for leaving some errors you mentioned unaddressed previously. I have now fixed a disconcerting oversight in my workflow which did cause some of these issues to elude me before, under time pressures I am under in other domains. So regarding your review, I have now:
- Fixed all issues that were causing any WSODs in Drupal 10 and 11. Paragraph Group 3.0.x development branch has now been significantly more thoroughly tested in both versions. The current commit / dev release should now be without these errors, *as well as also passing all Gitlab-CI tests*. The current public 3.0.3 release also remains stable to the best of my knowledge, and is without issue queue notifications thus far after nearly 3 months in production. (I will of course be happy to fix any issues as part of the next public release to emerge from these reviews.)
- Fixed PHPCS issues with DrupalPractice rules in addition to standard Drupal rules, so there are no issues with either now. I have now enabled DrupalPractice rules alongside Drupal rules as a permanent part of my PHPCS workflow.
- Updated my README.md file to match the README.md standard template.
- Restored my paragraph_group.module file which invokes src/Hook/ParagroupHooks.php, and is now compatible with Drupal 10 and 11.
- Per the above point, have also implemented the `hooks_converted` and `skip_procedural_hook_scan` in my paragraph_group.services.yml file to ensure redirection to the relevant old or new hooks system depending on Drupal version.
- Fixed the `$error_msg` variable in the `form_system_themes_admin_form_alter` hook in src/Hook/ParagroupHooks.php so it is now translatable.
- Fixed the `create` method in src/Form/ParagroupConfigForm.php so it returns `new static()` instead of `new self()`.
- Added the relevant type information to the `$helper` and `$field_group_manager` arguments of the constructor in `src/Hook/ParagroupHooks.php`. And set the classname of the helper class correctly to `ParagroupHelperService` instead of ParagroupHelper.
- Removed the return value from the `validateForm` function in src/Form/ParagroupConfigForm.php so that it returns void.
- Fixed the `getParagraphTypes` function in src/Paragroup/ParagroupFormData.php so that it searches for the correct 'paragraphs_type' entity type, instead of 'paragraph_type'.
I have also now released a dev release as suggested, so that reviewers can try it out more easily if needed. As mentioned previously, this release is now better tested across all facets with Drupal 10 and 11.
Given the still somewhat neglected state of Drupal's admin theme editing within the Paragraphs ecosystem, I remain committed to continually improving Paragraph Group and obtaining it's security approval. I believe that by improving Drupal's content editing and strengthening the usability of recursive Paragraphs, Paragraph Group significantly improves Drupal as a Digital Public Good.
So I continue to welcome all reviews, and will continue to fix all relevant issues raised here.