Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DRUP-803] Deprecate apidocs module #198

Merged
merged 8 commits into from
May 22, 2019
3 changes: 2 additions & 1 deletion modules/apigee_edge_apidocs/apigee_edge_apidocs.info.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: 'Apigee Edge API Docs'
name: 'Apigee Edge API Docs (deprecated)'
Jaesin marked this conversation as resolved.
Show resolved Hide resolved
type: module
description: 'Display OpenAPI documentation of your APIs to your developers.'
core: 8.x
Expand All @@ -8,3 +8,4 @@ dependencies:
- drupal:text
- drupal:file
- apigee_edge:apigee_edge
- apigee_edge:deprecated
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes the module uninstallable in the install screen before the requirements is ever reached.

image

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, this is rather seems to be some kind of hack then a proper solution ;S Have you seen this doing by other modules?
What I originally suggested on the sprint planning call is an "install" phase check in apigee_edge_apidocs_requirements() that does not allow to enable the module anymore and displays a deprecation message. Isn't that possible?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually what you have added to apigee_edge_apidocs_requirements() is perfectly enough.

Peek 2019-05-22 08-10

Copy link
Contributor

@mxr576 mxr576 May 22, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Meh... so there is an issue with Drush... It does not run hook_requirements().
drush-ops/drush#3669
@Jaesin If we do not find a better workaround for this problem, please document in the info.yml with a comment why this "hack" was needed. Preferably with a deep link to the related Drush issue.

Copy link
Contributor

@mxr576 mxr576 May 22, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The drawback of the info.yml trick is this:
image

(and the problem is the same with Drush).

Another potential solution that I could figure out is this. The possible drawback of this solution that module gets installed partially with Drush so we have to uninstall it.

<?php
/**
 * Implements hook_module_preinstall().
 */
function apigee_edge_apidocs_module_preinstall($module) {
  if (PHP_SAPI === 'cli' && $module === 'apigee_edge_apidocs') {
    // Workaround for a bug in Drush: https://github.com/drush-ops/drush/issues/3669
    \Drupal::service('module_installer')->uninstall(['apigee_edge_apidocs']);
    throw new RuntimeException('The Apigee Edge Apidocs module is deprecated and will be removed before Apigee Edge version 8.x-1.0 is released. Please use the Apigee API Catalog module as an alternative: https://www.drupal.org/project/apigee_api_catalog.');
  }
}
cli-drupal:/app$ drush pmu apigee_edge_apidocs -y
 [success] Successfully uninstalled: apigee_edge_apidocs
cli-drupal:/app$ drush en apigee_edge_apidocs -y

In apigee_edge_apidocs.module line 53:
                                                                                                                                                                                                                       
  The Apigee Edge Apidocs module is deprecated and will be removed before Apigee Edge version 8.x-1.0 is released. Please use the Apigee API Catalog module as an alternative: https://www.drupal.org/project/apigee_  
  api_catalog.                                                                                                                                                                                                         
                                                                                                                                                                                                                       

pm:enable [-h|--help] [-q|--quiet] [-v|vv|vvv|--verbose] [-V|--version] [--ansi] [--no-ansi] [-n|--no-interaction] [-d|--debug] [-y|--yes] [--no] [--remote-host REMOTE-HOST] [--remote-user REMOTE-USER] [-r|--root ROOT] [-l|--uri URI] [--simulate] [--pipe] [-D|--define DEFINE] [--druplicon] [--xh-link XH-LINK] [--notify [NOTIFY]] [--] <command> [<modules>]...

cli-drupal:/app$ drush pm:list | grep apigee_edge_apidocs
  Apigee (Deprecated)                  Apigee Edge API Docs (apigee_edge_apidocs)                              Disabled   8.x-1.0-rc4   

At least Drupal Console calls hook_requirements().

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does drush 9 still try to install the module if you keep - apigee_edge:deprecated?

43 changes: 43 additions & 0 deletions modules/apigee_edge_apidocs/apigee_edge_apidocs.install
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

/**
* @file
* Copyright 2019 Google Inc.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License version 2 as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

/**
* @file
* Install file for Apigee Edge API Docs.
*/

use Drupal\Core\Link;
use Drupal\Core\Url;

/**
* Implements hook_requirements().
*/
function apigee_edge_apidocs_requirements($phase) {
return [
'apigee_edge_apidocs_all' => [
Jaesin marked this conversation as resolved.
Show resolved Hide resolved
'title' => t('Apigee Edge Apidocs module.'),
'value' => t('The Apigee Edge Apidocs module has been deprecated.'),
'description' => t('The Apigee Edge Apidocs module has been deprecated and will be removed before a Apigee Edge v8.x-1.0 is released. Please use the @catalog_link module as an alternative.', [
'@catalog_link' => Link::fromTextAndUrl('Apigee API Catalog', Url::fromUri('https://www.drupal.org/project/apigee_api_catalog'))->toString(),
]),
'severity' => REQUIREMENT_ERROR,
],
];
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,25 +61,11 @@ class TeamStatusWarningSubscriber implements EventSubscriberInterface {
private $messenger;

/**
* The team storage.
* The entity type manager.
*
* @var \Drupal\apigee_edge\Entity\Storage\DeveloperStorageInterface
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
private $teamStorage;

/**
* The team entity type.
*
* @var \Drupal\Core\Entity\EntityTypeInterface
*/
private $teamEntityType;

/**
* The team app entity type.
*
* @var \Drupal\Core\Entity\EntityTypeInterface
*/
private $teamAppEntityType;
private $entityTypeManager;

/**
* TeamStatusWarningSubscriber constructor.
Expand All @@ -100,9 +86,7 @@ class TeamStatusWarningSubscriber implements EventSubscriberInterface {
public function __construct(AccountInterface $current_user, RouteMatchInterface $route_match, EntityTypeManagerInterface $entity_type_manager, TeamMembershipManagerInterface $team_membership_manager, MessengerInterface $messenger, TranslationInterface $string_translation) {
$this->routeMatch = $route_match;
$this->currentUser = $current_user;
$this->teamStorage = $entity_type_manager->getStorage('team');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are unrelated changes to the PR, please remove them.

Copy link
Contributor Author

@Jaesin Jaesin May 22, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is related as it prevents a clean uninstall of the apigee_edge_apidocs module. Accessing methods that access entity type discovery in a service constructor prevents clearing the entity type cache. See the following commit message: b49093a

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I remove @Jaesin 's changes I get the following error on uninstall, so these changes need to be in here:

The website encountered an unexpected error. Please try again later.</br></br><em class="placeholder">Drupal\Component\Plugin\Exception\PluginNotFoundException</em>: The &quot;apidoc&quot; entity type does not exist. in <em class="placeholder">Drupal\Core\Entity\EntityTypeManager-&gt;getDefinition()</em> (line <em class="placeholder">150</em> of <em class="placeholder">core/lib/Drupal/Core/Entity/EntityTypeManager.php</em>). <pre class="backtrace">Drupal\Core\Entity\EntityTypeManager-&gt;getHandler(&#039;apidoc&#039;, &#039;views_data&#039;) (Line: 157)
Drupal\Core\Entity\EntityManager-&gt;getHandler(&#039;apidoc&#039;, &#039;views_data&#039;) (Line: 177)
views_views_data()
call_user_func_array(&#039;views_views_data&#039;, Array) (Line: 392)
Drupal\Core\Extension\ModuleHandler-&gt;invoke(&#039;views&#039;, &#039;views_data&#039;) (Line: 243)
Drupal\views\ViewsData-&gt;getData() (Line: 160)
Drupal\views\ViewsData-&gt;get(&#039;apidoc&#039;) (Line: 91)
Drupal\views\Plugin\Derivative\ViewsEntityRow-&gt;getDerivativeDefinitions(Array) (Line: 101)
Drupal\Component\Plugin\Discovery\DerivativeDiscoveryDecorator-&gt;getDerivatives(Array) (Line: 87)
Drupal\Component\Plugin\Discovery\DerivativeDiscoveryDecorator-&gt;getDefinitions() (Line: 284)
Drupal\Core\Plugin\DefaultPluginManager-&gt;findDefinitions() (Line: 175)
Drupal\Core\Plugin\DefaultPluginManager-&gt;getDefinitions() (Line: 147)
views_theme(Array, &#039;module&#039;, &#039;views&#039;, &#039;core/modules/views&#039;) (Line: 447)
Drupal\Core\Theme\Registry-&gt;processExtension(Array, &#039;views&#039;, &#039;module&#039;, &#039;views&#039;, &#039;core/modules/views&#039;) (Line: 334)
Drupal\Core\Theme\Registry-&gt;build() (Line: 233)
Drupal\Core\Theme\Registry-&gt;get() (Line: 86)
Drupal\Core\Utility\ThemeRegistry-&gt;initializeRegistry() (Line: 67)
Drupal\Core\Utility\ThemeRegistry-&gt;__construct(&#039;theme_registry:runtime:seven&#039;, Object, Object, Array, 1) (Line: 253)
Drupal\Core\Theme\Registry-&gt;getRuntime() (Line: 142)
Drupal\Core\Theme\ThemeManager-&gt;render(Array, Array) (Line: 437)
Drupal\Core\Render\Renderer-&gt;doRender(Array, ) (Line: 195)
Drupal\Core\Render\Renderer-&gt;render(Array, ) (Line: 226)
Drupal\Core\Render\MainContent\HtmlRenderer-&gt;Drupal\Core\Render\MainContent\{closure}() (Line: 582)
Drupal\Core\Render\Renderer-&gt;executeInRenderContext(Object, Object) (Line: 227)
Drupal\Core\Render\MainContent\HtmlRenderer-&gt;prepare(Array, Object, Object) (Line: 117)
Drupal\Core\Render\MainContent\HtmlRenderer-&gt;renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber-&gt;onViewRenderArray(Object, &#039;kernel.view&#039;, Object)
call_user_func(Array, Object, &#039;kernel.view&#039;, Object) (Line: 111)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher-&gt;dispatch(&#039;kernel.view&#039;, Object) (Line: 156)
Symfony\Component\HttpKernel\HttpKernel-&gt;handleRaw(Object, 1) (Line: 68)
Symfony\Component\HttpKernel\HttpKernel-&gt;handle(Object, 1, 1) (Line: 57)
Drupal\Core\StackMiddleware\Session-&gt;handle(Object, 1, 1) (Line: 47)
Drupal\Core\StackMiddleware\KernelPreHandle-&gt;handle(Object, 1, 1) (Line: 106)
Drupal\page_cache\StackMiddleware\PageCache-&gt;pass(Object, 1, 1) (Line: 85)
Drupal\page_cache\StackMiddleware\PageCache-&gt;handle(Object, 1, 1) (Line: 47)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware-&gt;handle(Object, 1, 1) (Line: 52)
Drupal\Core\StackMiddleware\NegotiationMiddleware-&gt;handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel-&gt;handle(Object, 1, 1) (Line: 693)
Drupal\Core\DrupalKernel-&gt;handle(Object) (Line: 19)
</pre>

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would have been great if someone had validated #141 before this got merged.

Copy link
Contributor

@mxr576 mxr576 May 23, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A note about services that access the entity type manager in their constructors. Of course it's OK to inject the entity type manager in a service constructor but accessing any methods that result in getDefinitions being called should not be used in a service constructor. When a module is uninstalled, the last thing that happens is the service container is rebuilt. This happens when the module that is being uninstalled is still discoverable. Any entities the module defines will be cached when getDefinitions is called on the entity type manager.

This results in a PluginNotFoundException exception for subsequent page requests. The only way to get back to a working site is to clear the cache which would have to happen through drush. That is fine for developers but it is a problem for anyone that doesn't have drush or the correct alias set up.

@Jaesin Thanks for the investigation and the detailed answer but you haven't captured the real root of the problem. Generally speaking, there should not be any problem with retrieving an instance of a class from an object repository (EntityTypeManager) in a constructor - unless there is a bug somewhere in the system. This is what I tried to convince you in #140 and #141 and this is the reason why I continued my investigation regarding this problem today. Based on my findings this Drupal core issue causes the problem: https://www.drupal.org/project/drupal/issues/3056604

When you uninstall the Apigee Edge Teams module then it gets uninstalled, you can see in the logs: apigee_edge_teams module uninstalled.. After that HTTP Kernel triggers the KernelEvents::RESPONSE event and the 💩 event dispatcher calls the uninstalled Apigee Edge Teams module's TeamStatusWarningSubscriber event subscriber, but it should not.

screeshot-2019-05-23-11-08-39

(Stack trace captured after the Teams module uninstalled and the request has not been resolved. This confirms that the TeamStatusWarningSubscriber gets called because it is still registered in that instance of the event dispatcher and it fails because the "team" and "team_app" entity types have been unregistered already.)

Update: POC 2, what you changed only works because the TeamStatusWarningSubscriber only listening on team app routes at this moment. If you remove that condition from event subscriber you still get a WSOD.

https://drive.google.com/open?id=1jQKtoMerpQXvuRQtQ_2KReJVl7u62lu1

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found the same thing. Besides the TeamStatusWarningSubscriber, the DeveloperStatusWarningSubscriber causes the same issue. The teams module wasn't installed in the case of the error described in this issue.

This is not likely to get fixed in Drupal core any time soon (see: https://www.drupal.org/project/drupal/issues/3056604#comment-13118160). It is true that this results from issues in Drupal core but to be practical, we should work around it by not accessing methods that would cause the entity type cache to be rebuilt when the container is built. There aren't any services in Drupal core that use this pattern even through the entity type manager is used extensively in services so we should avoid it as well. Although the problem is showing itself while uninstalling modules, there could be edge cases where it shows up again.

Copy link
Contributor

@mxr576 mxr576 May 24, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But entity type cache is not being rebuilt when you call $entity_type_manager->getStorage() in the event's constructor... it had been rebuilt when the module uninstalled (this is what this method does) and after that the only problem that Drupal core calls an uninstalled event dispatcher which tries to retrieve an uninstalled entity type. It does not matter where it tries to retrieve it, in its constructor or in the method that handles the event, it fails. (It does not even matter that this is an event subscriber, any code that runs in the same page request after a module has been uninstalled and it would try to retrieve an uninstalled entity type it would fail.) This is what the video above confirms.

This is not likely to get fixed in Drupal core any time soon

I'll work on this, just as I worked on the JSON API related bugs to ensure this gets fixed sooner as you would expect.

Let's continue this conversation in #203.

$this->teamEntityType = $entity_type_manager->getDefinition('team');
$this->teamAppEntityType = $entity_type_manager->getDefinition('team_app');
$this->entityTypeManager = $entity_type_manager;
$this->messenger = $messenger;
$this->stringTranslation = $string_translation;
}
Expand All @@ -124,14 +108,14 @@ public function onRespond(FilterResponseEvent $event) {
/** @var \Drupal\apigee_edge_teams\Entity\TeamAppInterface $app */
$app = $this->routeMatch->getParameter('team_app') ?? $this->routeMatch->getParameter('app');
if ($app) {
$team = $this->teamStorage->load($app->getCompanyName());
$team = $this->entityTypeManager->getStorage('team')->load($app->getCompanyName());
}
}

if ($team && $team->getStatus() === TeamInterface::STATUS_INACTIVE) {
$this->messenger->addWarning($this->t('This @team has inactive status so @team members will not be able to use @team_app credentials until the @team gets activated. Please contact support for further assistance.', [
'@team' => $this->teamEntityType->getLowercaseLabel(),
'@team_app' => $this->teamAppEntityType->getLowercaseLabel(),
'@team' => $this->entityTypeManager->getDefinition('team')->getLowercaseLabel(),
'@team_app' => $this->entityTypeManager->getDefinition('team_app')->getLowercaseLabel(),
]));
}
}
Expand Down
19 changes: 5 additions & 14 deletions modules/apigee_edge_teams/src/TeamPermissionHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,13 +98,6 @@ final class TeamPermissionHandler implements TeamPermissionHandlerInterface {
*/
private $yamlDiscovery;

/**
* The team member role entity storage.
*
* @var \Drupal\apigee_edge_teams\Entity\Storage\TeamMemberRoleStorageInterface
*/
private $teamMemberRoleStorage;

/**
* The team membership manager service.
*
Expand All @@ -113,11 +106,11 @@ final class TeamPermissionHandler implements TeamPermissionHandlerInterface {
private $teamMembershipManager;

/**
* The team role storage.
* The entity type manager.
*
* @var \Drupal\apigee_edge_teams\Entity\Storage\TeamRoleStorageInterface
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
private $teamRoleStorage;
private $entityTypeManager;

/**
* TeamPermissionHandler constructor.
Expand All @@ -135,8 +128,6 @@ public function __construct(ModuleHandlerInterface $module_handler, ClassResolve
$this->moduleHandler = $module_handler;
$this->classResolver = $class_resolver;
$this->teamMembershipManager = $team_membership_manager;
$this->teamRoleStorage = $entity_type_manager->getStorage('team_role');
$this->teamMemberRoleStorage = $entity_type_manager->getStorage('team_member_role');
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is missing $this->entityTypeManager = $entity_type_manager;

}

/**
Expand Down Expand Up @@ -167,10 +158,10 @@ public function getDeveloperPermissionsByTeam(TeamInterface $team, AccountInterf
// is still member of the team in Apigee Edge.
if (in_array($team->id(), $developer_team_ids)) {
/** @var \Drupal\apigee_edge_teams\Entity\TeamRoleInterface $member_role */
$member_role = $this->teamRoleStorage->load(TeamRoleInterface::TEAM_MEMBER_ROLE);
$member_role = $this->entityTypeManager->getStorage('team_role')->load(TeamRoleInterface::TEAM_MEMBER_ROLE);
$permissions += $member_role->getPermissions();
/** @var \Drupal\apigee_edge_teams\Entity\TeamMemberRoleInterface|null $dev_team_role */
$dev_team_role = $this->teamMemberRoleStorage->loadByDeveloperAndTeam($account, $team);
$dev_team_role = $this->entityTypeManager->getStorage('team_member_role')->loadByDeveloperAndTeam($account, $team);
Jaesin marked this conversation as resolved.
Show resolved Hide resolved
if ($dev_team_role) {
foreach ($dev_team_role->getTeamRoles() as $role) {
$permissions = array_merge($permissions, $role->getPermissions());
Expand Down
13 changes: 7 additions & 6 deletions src/EventSubscriber/DeveloperStatusWarningSubscriber.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,11 @@ final class DeveloperStatusWarningSubscriber implements EventSubscriberInterface
private $messenger;

/**
* The developer storage.
* The entity type manager.
*
* @var \Drupal\apigee_edge\Entity\Storage\DeveloperStorageInterface
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
private $developerStorage;
private $entityTypeManager;

/**
* DeveloperStatusWarningSubscriber constructor.
Expand All @@ -84,7 +84,7 @@ final class DeveloperStatusWarningSubscriber implements EventSubscriberInterface
public function __construct(AccountInterface $current_user, RouteMatchInterface $route_match, EntityTypeManagerInterface $entity_type_manager, MessengerInterface $messenger, TranslationInterface $string_translation) {
$this->routeMatch = $route_match;
$this->currentUser = $current_user;
$this->developerStorage = $entity_type_manager->getStorage('developer');
$this->entityTypeManager = $entity_type_manager;
Jaesin marked this conversation as resolved.
Show resolved Hide resolved
$this->messenger = $messenger;
$this->stringTranslation = $string_translation;
}
Expand All @@ -98,6 +98,7 @@ public function __construct(AccountInterface $current_user, RouteMatchInterface
public function onRespond(FilterResponseEvent $event) {
// Anonymous user's does not have access to these routes.
if ($this->currentUser->isAuthenticated() && strpos($this->routeMatch->getRouteName(), 'entity.developer_app.') === 0) {
$developer_storage = $this->entityTypeManager->getStorage('developer');
/** @var \Drupal\apigee_edge\Entity\DeveloperInterface|NULL $developer */
$developer = NULL;
/** @var \Drupal\Core\Session\AccountInterface|NULL $account */
Expand All @@ -106,14 +107,14 @@ public function onRespond(FilterResponseEvent $event) {
$app = $this->routeMatch->getParameter('developer_app') ?? $this->routeMatch->getParameter('app');
if ($app) {
/** @var \Drupal\apigee_edge\Entity\DeveloperInterface $developer */
$developer = $this->developerStorage->load($app->getDeveloperId());
$developer = $developer_storage->load($app->getDeveloperId());
$account = $developer->getOwner();
}
// Taking special care of the "Apps" page.
elseif ($this->routeMatch->getRouteName() === 'entity.developer_app.collection_by_developer') {
/** @var \Drupal\Core\Session\AccountInterface $account */
$account = $this->routeMatch->getParameter('user');
$developer = $this->developerStorage->load($account->getEmail());
$developer = $developer_storage->load($account->getEmail());
}

// If we could figure out the developer from the route and its status
Expand Down
10 changes: 5 additions & 5 deletions src/KeyEntityFormEnhancer.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,11 @@ final class KeyEntityFormEnhancer {
private $connector;

/**
* The key entity storage.
* The entity type manager.
*
* @var \Drupal\Core\Config\Entity\ConfigEntityStorageInterface
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
private $keyStorage;
private $entityTypeManager;
Jaesin marked this conversation as resolved.
Show resolved Hide resolved

/**
* The OAuth token storage.
Expand Down Expand Up @@ -101,7 +101,7 @@ final class KeyEntityFormEnhancer {
*/
public function __construct(SDKConnectorInterface $connector, OauthTokenStorageInterface $oauth_token_storage, EntityTypeManagerInterface $entity_type_manager, ConfigFactoryInterface $config_factory) {
$this->connector = $connector;
$this->keyStorage = $entity_type_manager->getStorage('key');
$this->entityTypeManager = $entity_type_manager;
$this->oauthTokenStorage = $oauth_token_storage;
$this->configFactory = $config_factory;
}
Expand Down Expand Up @@ -301,7 +301,7 @@ public function validateForm(array &$form, FormStateInterface $form_state): void
// Create a temp key for testing without saving it.
$random = new Random();
/** @var \Drupal\key\KeyInterface $test_key */
$test_key = $this->keyStorage->create([
$test_key = $this->entityTypeManager->getStorage('key')->create([
'id' => strtolower($random->name(16)),
'key_type' => $key->getKeyType()->getPluginID(),
'key_input' => $key->getKeyInput()->getPluginID(),
Expand Down