This module integrates the Campaign Monitor API into Drupal and provides a webform submit handler that lets you subscribe users to specific lists on Campaign Monitor. You can use triggering element (usually checkbox) to conditionally subscribe user.

Project link

https://www.drupal.org/project/campaign_monitor_webform

Comments

le72 created an issue. See original summary.

bigbaldy’s picture

This review uses the Project Application Review Template.

Automated Review

Automated review is not working. I ran phpcs manually with both the Drupal and DrupalPractice standards. Neither generated errors

Note that perfect adherence to Drupal Coding Standard is NOT a reason to block an application, except for total disregard of them. However, modules should follow them as closely as possible.

Manual Review

Individual user account
[Yes: Follows] the guidelines for individual user accounts.
No duplication
[Yes: Does not cause] module duplication and/or fragmentation.
Master Branch
[Yes: Follows] the guidelines for master branch.

The module uses branching at the Major semantic version (ie. 2.x .) The guideline is unclear as to any preferences between a new branch at the major or minor release. The example in the guideline shows a new branch for a minor release (ex. 2.0.x)

Licensing
[Yes: Follows] the licensing requirements.
3rd party assets/code
[Yes: Follows] the guidelines for 3rd party assets/code.
README.txt/README.md
[Yes: Partially Follows] the guidelines for in-project documentation and/or the README Template.

The format is correct, but the content has not been completed.

Code long/complex enough for review
[Yes: Limited] the guidelines for project length and complexity. Project is detailed but the commits submitted by the applicant are older and limited in number.
Secure code
[Yes: Meets the security requirements.
Coding style & Drupal API usage
[List of identified issues in no particular order. Use (*) and (+) to indicate an issue importance. Replace the text below by the issues themselves:
  1. (+) Update README.md file
  2. This review is of the project overall. The intent of the security advisory coverage application though, is to evaluate the individual submitting the request. The submitter's last commit to the project was in July 2015 for a first version at 8.x. Eight additional commits were for 7.x in December of 2014. There was one project page update in 2020. The commits by the submitter look reasonable. Given the age and number of commits I'm not sure if there is enough information for the application based on this project alone. It did notice a significant number of commits to other projects.

The starred items (*) are fairly big issues and warrant going back to Needs Work. Items marked with a plus sign (+) are important and should be addressed before a stable project release. The rest of the comments in the code walkthrough are recommendations.

If added, please don't remove the security tag, we keep that for statistics and to show examples of security problems.

This review uses the Project Application Review Template.

bigbaldy’s picture

Status: Needs review » Needs work
avpaderno’s picture

Issue summary: View changes
le72’s picture

Thank you for your review.

  1. I updated README.md
  2. Yes, it's true, I worked on Drupal 7 version of this module and did just initial steps of migration to Drupal 8.
  3. Yes, besides the wish of making this module covered by security advisory, I need permission to opt into security advisory coverage as I want to maintain the NodeJS Integration module (https://www.drupal.org/project/nodejs/issues/3237094). The initial maintainer disappeared for a long time but I/we use the module in the live projects.
le72’s picture

Status: Needs work » Needs review
avpaderno’s picture

Status: Needs review » Needs work

For these applications, we need at least a branch where the code has been committed from the user who applies. In this case, in the 2.x branch there are commits from other users. This means we cannot understand what the user who applies understands about writing secure code that follows the coding standards and correctly uses the Drupal API, since the code has been written from more users.

This application can continue, with a project/branch where most of the commits have been done from the user who applies. (The ideal would be a project where the commits for a branch are done from the user who applies.)

le72’s picture

Correct, I updated the README.md only (last commit) as requested.
What else can I do here to make the module "green"? :-)

le72’s picture

Status: Needs work » Needs review
avpaderno’s picture

Status: Needs review » Needs work

See my previous comment.

avpaderno’s picture

Priority: Normal » Minor
le72’s picture

Priority: Minor » Normal
Issue summary: View changes

I added another project. Please review it so I could make it green under Security advisory coverage.
https://www.drupal.org/project/campaign_monitor_webform

le72’s picture

Status: Needs work » Needs review
avpaderno’s picture

Title: [D9] Better Messages » [D9] Campaign Monitor Webform Handler
Issue summary: View changes
le72’s picture

Hi @apaderno.
Can you please review it before September 20-21 https://www.drupal.org/project/campaign_monitor_webform?
I am going to talk a bit about this module at DrupalCon in Prague.
Thanks in advance.

avpaderno’s picture

Status: Needs review » Needs work
  • What follows is a quick review of the project; it doesn't mean to be complete
  • For each point, the review usually shows some lines that should be fixed (except in the case the point is about the full content of a file); it doesn't show all the lines that need to be changed for the same reason
  • A review is about code that doesn't follow the coding standards, contains possible security issue, or doesn't correctly use the Drupal API; the single points aren't ordered, not even by importance
core_version_requirement: ^8.8.2 || ^9 || ^10

The minimum required Drupal 8.x version should be 8.8.3, when using semantic versions. Earlier Drupal versions don't handle semantic versions correctly.

  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    $instance = parent::create($container, $configuration, $plugin_id, $plugin_definition);
    $instance->loggerFactory = $container->get('logger.factory')->get('webform_campaign_monitor');
    $instance->campaignMonitorRESTClient = $container->get('campaign_monitor_rest_client');
    return $instance;
  }

The purpose of ContainerInjectionInterface::create() (or similar methods like ContainerFactoryPluginInterface::create()) is passing the injected dependencies to the class constructor, non initializing the instance properties.

      catch (ClientException $exception) {
        \Drupal::messenger()->addMessage("Something went wrong with your subscription." . $exception->getMessage(), "warning");
      }

The first argument passed to MessengerInterface::addError(), MessengerInterface::addMessage(), MessengerInterface::addStatus(), and MessengerInterface::addWarning() must be a translatable string that uses placeholders.

      $this->loggerFactory->info("Subscription have not sent to Campaign Monitor, because of " .
        $this->configuration['trigger'] .
      " value: " . print_r($wf_submission[$this->configuration['trigger']], TRUE));
    }

The $message parameter passed to the LoggerInterface methods must be a literal string and use placeholders.

avpaderno’s picture

Issue tags: +PAreview: security
le72’s picture

Thank you for the quick review.
I am fixing now, BUT regarding

The purpose of ContainerInjectionInterface::create() (or similar methods like ContainerFactoryPluginInterface::create()) is passing the injected dependencies to the class constructor, non initializing the instance properties.

I have a question. I used example of WebformHandlerBase . And actually all WebformHandlers initializing the instance properties in the create method. Should I still change my module and move initialization to construct()? In that case, the module's custom Webform Handler will have different look comparing to other similar implimintations. I am fine wiht it, just need an advice and confirmation.

avpaderno’s picture

Services and dependency injection in Drupal 8+ / Injecting dependencies into controllers, forms and blocks says:

Every object which uses Drupal\Core\DependencyInjection\ContainerInjectionInterface (for example, controllers, forms, and blocks), must implement the create() factory method to pass the dependencies into the class constructor.

Passing the dependencies to the constructor makes sense, as initializing the constructed object is the constructor's responsibility. It's what other static methods do too, for example Url::fromEntityUri() or Url::fromRouteUri().

protected static function fromRouteUri(array $uri_parts, array $options, $uri) {
  $route_parts = explode(';', $uri_parts['path'], 2);
  $route_name = $route_parts[0];
  if ($route_name === '') {
    throw new \InvalidArgumentException("The route URI '{$uri}' is invalid. You must have a route name in the URI. e.g., route:system.admin");
  }
  $route_parameters = [];
  if (!empty($route_parts[1])) {
    parse_str($route_parts[1], $route_parameters);
  }
  return new static($route_name, $route_parameters, $options);
}
le72’s picture

Well, thank you very much @apaderno. I created an issue on webforms project (https://www.drupal.org/project/webform/issues/3311986#comment-14708352)
In my Campaign Monitor Webform Handler I can't just change the create method and add __construct, because the handler is inheriting the WebformHandlerBase. I can do everything in the way you recommend, but I will need to add all services of WebformHandlerBase to my custom handler. I know the webform maintainers are pretty responsive, so I want to see what they tell, maybe there are some reasons to write create() method in a way they did everywhere in the webforms.

The other notices are fixed and pished to v1.0.6

avpaderno’s picture

WebformCampaignMonitorHandler still needs to implements its constructor, which is what WebformHandlerBase::create() calls with new static().

How WebformHandlerBase::create() is written, it doesn't allow to easily extend it. You should extend create() to pass all the dependencies to __construct(), which then initializes all the properties, including the WebformHandlerBase's properties.

le72’s picture

Hi @apaderno, here is an answer:

This "unconventional" but documented approach to dependency injection allows handlers to be extended while allowing the parent class to add dependencies without breaking anything.

@see https://www.jrockowitz.com/blog/webform-road-to-drupal-9

I see what you mean in your last comment and agree all dependencies in subclasses also should be written and passed to __construct(). But I think what jrockowitz is saying makes sence.

Maybe we can let it as it's done in webform for all other handlers?
Thanks in advance.

avpaderno’s picture

@le72 If you made the other changes, feel free to change status. That isn't an issue you can resolve in your module.

The only change you can eventually do is requiring a specific Webform version, if that change is present starting with Webform 6.x. This isn't a change required from these applications, though.

le72’s picture

Status: Needs work » Needs review

Yes, the other changes are here: v1.0.6

avpaderno’s picture

Status: Needs review » Fixed

Thank you for your contribution! I am going to update your account.

These are some recommended readings to help with excellent maintainership:

You can find more contributors chatting on the Slack #contribute channel. So, come hang out and stay involved.
Thank you, also, for your patience with the review process.
Anyone is welcome to participate in the review process. Please consider reviewing other projects that are pending review. I encourage you to learn more about that process and join the group of reviewers.

I thank all the reviewers.

avpaderno’s picture

Assigned: Unassigned » avpaderno
le72’s picture

Thank you!

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.