This is a follow up to #2548297: Replace broken call flag_reset_flag.

It would be more controlled to inject the FlagService directly, rather than leave an implicit dependancy on Drupal.php through the call to \Drupal::service('flag')->reset($this->flag);

As mentioned in the parent issue - This is just a implementation of

https://www.drupal.org/node/2203931

CommentFileSizeAuthor
#2 inject-2548687-2.patch1.62 KBmartin107

Comments

martin107 created an issue. See original summary.

martin107’s picture

Assigned: martin107 » Unassigned
Issue summary: View changes
Status: Active » Needs review
Parent issue: » #2548297: Replace broken call flag_reset_flag.
StatusFileSize
new1.62 KB

I should have done it like this the first time:)

joachim’s picture

Thanks for filing this, and the patch

I'm thinking that we should maybe add some test coverage for this, as obviously there isn't any given our code was broken here! (Probably should have done that in the bugfix issue TBH...)
Doesn't need to be fancy -- just create a basic flag programmatically, flag a node (programmatically will do too here, we're not testing the flagging UI), then reset it with the form, then query to check there are no more flaggings.

+++ b/src/Form/FlagResetForm.php
@@ -24,6 +32,22 @@ class FlagResetForm extends ConfirmFormBase {
   /**
+   * Class constructor.
+   */
+  public function __construct(FlagService $flag_service) {
+    $this->flagService = $flag_service;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container) {
+    return new static(
+      $container->get('flag')
+    );
+  }
+
+  /**

This looks the same as the docs I found, but I've not yet seen an explanation of how it works. How does the property name $this->flagService get magically determined? (This is a nitpick at the docs, not the patch!)

martin107’s picture

This looks the same as the docs I found, but I've not yet seen an explanation of how it works

I can give a short chain of logic.

1) FlagResetForm is build in a factory.
2) FlagResetForm::create() is called by the factory to determine the parameters used in preparing the call to " new FlagResetForm(....)"
3) FlagResetForm::__construct is called after which $this->flagService is populated.

FormBase implements and overrides a method "create()" as part of it contract to implement \Drupal\Core\DependencyInjection\ContainerInjectionInterface
and the documentation in there says all this in more formal language..

My argument would be better if I could put my finger on the exact factory... what I do know is that this is not a symfony convention ... so it has to exist as somewhere in the logic glueing Drupal8 onto on of it.

I hope this helps.

I will get to the integration testing sometime this week....

joachim’s picture

But more specifically, how does it know to call it flagService and not ElectricBoogaloo? Or flag_service (which IIRC is the name of it in the services.yml file)?

And thanks -- if you can work on the tests that would be ace. I'm getting very little free time to code at the moment.

martin107’s picture

Ah your understanding is correct, but the name for the service in the flag.services.yml file is 'flag'
and that is what I had to plumb into FlagResetForm::create().

PS

Just to fill in something I did not know when I wrote #4 When I say factory ... well in this case
it looks like the routing of all forms go through \Drupal\Core\Controller\FormController.
The first line of FormController::getContentResult extracts the class from the _form parameter in the routing file.


public function getContentResult(Request $request, RouteMatchInterface $route_match) {
$form_arg = $this->getFormArgument($route_match);

joachim’s picture

> Ah your understanding is correct, but the name for the service in the flag.services.yml file is 'flag'

Ah, right, so the property name is fooService, where foo is the name in your services.yml file.

berdir’s picture

No. There is no connection between those two things. Or the only thing that does connect them is the create() and __construct() method, you can name those properties however you want.

The only magic that is involved here is that the form system knows to call the create() method if it exists. Then everything is controlled by those two methods.

martin107’s picture

I hope I am not labouring the point, but it is the order of the parameters, not the name,
that ties the services collected in the create function to the parameters passed into the constructor.

the book module has a more complex example.

  /**
   * Constructs a BookController object.
   *
   * @param \Drupal\book\BookManagerInterface $bookManager
   *   The book manager.
   * @param \Drupal\book\BookExport $bookExport
   *   The book export service.
   * @param \Drupal\Core\Render\RendererInterface $renderer
   *   The renderer.
   */
  public function __construct(BookManagerInterface $bookManager, BookExport $bookExport, RendererInterface $renderer) {
    $this->bookManager = $bookManager;
    $this->bookExport = $bookExport;
    $this->renderer = $renderer;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('book.manager'),
      $container->get('book.export'),
      $container->get('renderer')
    );
  }
joachim’s picture

Ah right, I've got it now. Sorry, was being totally dense earlier! create() gets the container passed to it, and 'new static()' causes __construct() to be called. Thank you both for your patience!

joachim’s picture

Status: Needs review » Fixed

Tests should wait for #2501811: Create FlagTestBase to house common functions, so I'm going to commit this now and file a follow-up.

  • joachim committed 3b23c86 on 8.x-4.x authored by martin107
    Issue #2548687 by martin107: Changed FlagResetForm to have flag service...
martin107’s picture

Follow up has been created..

Status: Fixed » Closed (fixed)

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