Skip to content
Snippets Groups Projects
Commit d33e7087 authored by Youri van Koppen's avatar Youri van Koppen
Browse files

Issue #3468323 by megachriz, ankitv18: Fixed RouteNotFoundException thrown...

Issue #3468323 by megachriz, ankitv18: Fixed RouteNotFoundException thrown when viewing imported product variations (from Commerce).
parent 47a8421d
No related branches found
No related tags found
1 merge request!189Catch any exception in ItemListController. Ignore some, log others.
Pipeline #262511 passed
...@@ -8,10 +8,15 @@ use Drupal\Core\Controller\ControllerBase; ...@@ -8,10 +8,15 @@ use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Datetime\DateFormatterInterface; use Drupal\Core\Datetime\DateFormatterInterface;
use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\Exception\UndefinedLinkTemplateException; use Drupal\Core\Entity\Exception\UndefinedLinkTemplateException;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\Utility\Error;
use Drupal\feeds\FeedInterface; use Drupal\feeds\FeedInterface;
use Drupal\feeds\Plugin\Type\Processor\EntityProcessorInterface; use Drupal\feeds\Plugin\Type\Processor\EntityProcessorInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Exception\MissingMandatoryParametersException;
use Symfony\Component\Routing\Exception\RouteNotFoundException;
/** /**
* Lists the feed items belonging to a feed. * Lists the feed items belonging to a feed.
...@@ -33,16 +38,36 @@ class ItemListController extends ControllerBase { ...@@ -33,16 +38,36 @@ class ItemListController extends ControllerBase {
protected $dateFormatter; protected $dateFormatter;
/** /**
* The constructor. * The messenger service.
*
* @var \Drupal\Core\Messenger\MessengerInterface
*/
protected $messenger;
/**
* A logger instance.
*
* @var \Psr\Log\LoggerInterface
*/
protected $logger;
/**
* Constructs a new ItemListController object.
* *
* @param \Drupal\Component\Datetime\TimeInterface $time * @param \Drupal\Component\Datetime\TimeInterface $time
* The object for obtaining system time. * The object for obtaining system time.
* @param \Drupal\Core\Datetime\DateFormatterInterface $date_formatter * @param \Drupal\Core\Datetime\DateFormatterInterface $date_formatter
* The services of date. * The services of date.
* @param \Drupal\Core\Messenger\MessengerInterface $messenger
* The messenger service.
* @param \Psr\Log\LoggerInterface $logger
* A logger instance.
*/ */
public function __construct(TimeInterface $time, DateFormatterInterface $date_formatter) { public function __construct(TimeInterface $time, DateFormatterInterface $date_formatter, MessengerInterface $messenger, LoggerInterface $logger) {
$this->time = $time; $this->time = $time;
$this->dateFormatter = $date_formatter; $this->dateFormatter = $date_formatter;
$this->messenger = $messenger;
$this->logger = $logger;
} }
/** /**
...@@ -51,7 +76,9 @@ class ItemListController extends ControllerBase { ...@@ -51,7 +76,9 @@ class ItemListController extends ControllerBase {
public static function create(ContainerInterface $container) { public static function create(ContainerInterface $container) {
return new static( return new static(
$container->get('datetime.time'), $container->get('datetime.time'),
$container->get('date.formatter') $container->get('date.formatter'),
$container->get('messenger'),
$container->get('logger.factory')->get('feeds'),
); );
} }
...@@ -107,14 +134,33 @@ class ItemListController extends ControllerBase { ...@@ -107,14 +134,33 @@ class ItemListController extends ControllerBase {
// Entity link. // Entity link.
try { try {
$label = $entity->label();
if (is_string($label)) {
$label = Unicode::truncate($entity->label(), 75, TRUE, TRUE);
}
$row[] = [ $row[] = [
'data' => $entity->toLink(Unicode::truncate($entity->label(), 75, TRUE, TRUE)), 'data' => $entity->toLink($label),
'title' => $entity->label(), 'title' => $entity->label(),
]; ];
} }
catch (UndefinedLinkTemplateException $e) { catch (UndefinedLinkTemplateException $e) {
$row[] = $entity->label(); $row[] = $entity->label();
} }
catch (RouteNotFoundException $e) {
$row[] = $entity->label();
}
catch (MissingMandatoryParametersException $e) {
$row[] = $entity->label();
}
catch (\Exception $e) {
// Log this exception and display a message, if applicable.
Error::logException($this->logger, $e);
$message = $e->getMessage();
if (is_string($message) && strlen($message) > 0) {
$this->messenger->addError($message);
}
$row[] = $entity->label();
}
// Imported ago. // Imported ago.
$row[] = $this->t('@time ago', ['@time' => $ago]); $row[] = $this->t('@time ago', ['@time' => $ago]);
......
route_callbacks:
- '\Drupal\feeds_test_entity\Routing\EntityTestRoutes::routes'
<?php
namespace Drupal\feeds_test_entity\Entity;
use Drupal\entity_test\Entity\EntityTest;
/**
* An entity test class where generating a url could lead to an exception.
*
* @ContentEntityType(
* id = "feeds_test_entity_test_no_url",
* label = @Translation("Test entity with url exception"),
* handlers = {
* "access" = "Drupal\entity_test\EntityTestAccessControlHandler",
* "form" = {
* "default" = "Drupal\entity_test\EntityTestForm"
* },
* "route_provider" = {
* "html" = "Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider",
* },
* },
* base_table = "feeds_test_entity_test_no_url",
* admin_permission = "administer entity_test content",
* entity_keys = {
* "id" = "id",
* "uuid" = "uuid",
* "bundle" = "type",
* "label" = "name",
* },
* field_ui_base_route = "entity.feeds_test_entity_test_no_url.admin_form",
* links = {
* "canonical" = "/feeds_test_entity_test_no_url/manage/{feeds_test_entity_test_no_url}",
* "add-form" = "/feeds_test_entity_test_no_url/add",
* "edit-form" = "/feeds_test_entity_test_no_url/manage/{feeds_test_entity_test_no_url}",
* },
* )
*/
class EntityTestNoUrl extends EntityTest {
/**
* {@inheritdoc}
*/
public function toUrl($rel = 'canonical', array $options = []) {
$exception = \Drupal::state()->get('feeds_test_entity_test_no_url.exception');
if (isset($exception['class'])) {
$class = $exception['class'];
if (count($exception['args']) > 0) {
$instance = (new \ReflectionClass($class))->newInstanceArgs($exception['args']);
}
else {
$instance = new $class();
}
throw $instance;
}
return parent::toUrl($rel, $options);
}
}
<?php
namespace Drupal\feeds_test_entity\Routing;
use Symfony\Component\Routing\Route;
/**
* Subscriber for Entity Test routes.
*/
class EntityTestRoutes {
/**
* Returns an array of route objects.
*
* @return \Symfony\Component\Routing\Route[]
* An array of route objects.
*/
public function routes() {
$types = [
'feeds_test_entity_test_no_url',
];
$routes = [];
foreach ($types as $entity_type_id) {
$routes["entity.$entity_type_id.admin_form"] = new Route(
"$entity_type_id/structure/{bundle}",
['_controller' => '\Drupal\entity_test\Controller\EntityTestController::testAdmin'],
['_permission' => 'administer entity_test content'],
['_admin_route' => TRUE]
);
}
return $routes;
}
}
...@@ -2,7 +2,10 @@ ...@@ -2,7 +2,10 @@
namespace Drupal\Tests\feeds\Functional\Controller; namespace Drupal\Tests\feeds\Functional\Controller;
use Drupal\Core\Entity\EntityMalformedException;
use Drupal\Tests\feeds\Functional\FeedsBrowserTestBase; use Drupal\Tests\feeds\Functional\FeedsBrowserTestBase;
use Symfony\Component\Routing\Exception\MissingMandatoryParametersException;
use Symfony\Component\Routing\Exception\RouteNotFoundException;
/** /**
* Lists the feed items belonging to a feed. * Lists the feed items belonging to a feed.
...@@ -58,4 +61,115 @@ class ItemListControllerTest extends FeedsBrowserTestBase { ...@@ -58,4 +61,115 @@ class ItemListControllerTest extends FeedsBrowserTestBase {
$this->assertSession()->responseContains('Ut wisi enim ad minim veniam'); $this->assertSession()->responseContains('Ut wisi enim ad minim veniam');
} }
/**
* Tests listing items for an entity where url creation failed.
*
* @param string $exception_class
* The type of exception to throw.
* @param string|int $exception_message
* The exception message or null.
* @param bool $display_message
* Whether or not a message should be displayed.
* @param array $args
* (optional) The arguments to use for constructing the exception.
*
* @dataProvider entityExceptionsProvider
*/
public function testListItemsForAnEntityTypeWithUrlFailure(string $exception_class, ?string $exception_message, bool $display_message, array $args = []) {
$feed_type = $this->createFeedType([
'parser' => 'csv',
'processor' => 'entity:feeds_test_entity_test_no_url',
'processor_configuration' => [
'authorize' => FALSE,
'values' => [
'type' => 'feeds_test_entity_test_no_url',
],
],
'custom_sources' => [
'title' => [
'label' => 'title',
'value' => 'title',
'machine_name' => 'title',
],
],
'mappings' => [
[
'target' => 'name',
'map' => ['value' => 'title'],
],
],
]);
// Import CSV file.
$feed = $this->createFeed($feed_type->id(), [
'source' => $this->resourcesUrl() . '/csv/content.csv',
]);
$feed->import();
if (count($args) < 1 && is_string($exception_message)) {
$args[] = $exception_message;
}
\Drupal::state()->set('feeds_test_entity_test_no_url.exception', [
'class' => $exception_class,
'args' => $args,
]);
// Go to the items page and assert that two items are shown there.
$this->drupalGet('/feed/1/list');
$this->assertSession()->statusCodeEquals(200);
$this->assertSession()->pageTextContains('Lorem ipsum');
$this->assertSession()->pageTextContains('Ut wisi enim ad minim veniam');
if (is_string($exception_message)) {
if ($display_message) {
$this->assertSession()->pageTextContains($exception_message);
}
else {
$this->assertSession()->pageTextNotContains($exception_message);
}
}
}
/**
* Data provider for testListItemsForAnEntityTypeWithUrlFailure().
*/
public static function entityExceptionsProvider(): array {
return [
// A RouteNotFoundException can be thrown for some entity types and is not
// considered an error.
[
'class' => RouteNotFoundException::class,
'message' => 'No route',
'display_message' => FALSE,
],
// A MissingMandatoryParametersException can be thrown for some entity
// types and is not considered an error.
[
'class' => MissingMandatoryParametersException::class,
'message' => 'Some mandatory parameters are missing',
'display_message' => FALSE,
'args' => [
'foo.route',
[
'bar',
],
],
],
// An EntityMalformedException should be considered an error that should
// be displayed and logged.
[
'class' => EntityMalformedException::class,
'message' => 'The entity is malformed.',
'display_message' => TRUE,
],
// A RuntimeException should be considered an error that should be
// displayed and logged. However, in this case there is no message to be
// shown, so it should only get logged.
[
'class' => \RuntimeException::class,
'message' => NULL,
'display_message' => FALSE,
],
];
}
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment