Loading src/EntityUpdateManager.php +3 −3 Original line number Diff line number Diff line Loading @@ -16,7 +16,7 @@ class EntityUpdateManager implements EntityUpdateManagerInterface { /** * The usage track service. * * @var \Drupal\entity_usage\EntityUsage * @var \Drupal\entity_usage\EntityUsageInterface */ protected $usageService; Loading @@ -37,14 +37,14 @@ class EntityUpdateManager implements EntityUpdateManagerInterface { /** * EntityUpdateManager constructor. * * @param \Drupal\entity_usage\EntityUsage $usage_service * @param \Drupal\entity_usage\EntityUsageInterface $usage_service * The usage tracking service. * @param \Drupal\entity_usage\EntityUsageTrackManager $track_manager * The PluginManager track service. * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory * The config factory. */ public function __construct(EntityUsage $usage_service, EntityUsageTrackManager $track_manager, ConfigFactoryInterface $config_factory) { public function __construct(EntityUsageInterface $usage_service, EntityUsageTrackManager $track_manager, ConfigFactoryInterface $config_factory) { $this->usageService = $usage_service; $this->trackManager = $track_manager; $this->config = $config_factory->get('entity_usage.settings'); Loading src/EntityUsageTrackBase.php +165 −4 Original line number Diff line number Diff line Loading @@ -2,6 +2,7 @@ namespace Drupal\entity_usage; use Drupal\Core\Url; use Drupal\Core\Config\ConfigFactoryInterface; use Drupal\Core\Entity\EntityFieldManagerInterface; use Drupal\Core\Entity\EntityInterface; Loading @@ -9,8 +10,10 @@ use Drupal\Core\Entity\EntityRepositoryInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Entity\FieldableEntityInterface; use Drupal\Core\Entity\RevisionableInterface; use Drupal\Core\Path\PathValidatorInterface; use Drupal\Core\Plugin\ContainerFactoryPluginInterface; use Drupal\Core\Plugin\PluginBase; use Drupal\Core\StreamWrapper\PublicStream; use Symfony\Component\DependencyInjection\ContainerInterface; /** Loading @@ -21,7 +24,7 @@ abstract class EntityUsageTrackBase extends PluginBase implements EntityUsageTra /** * The usage tracking service. * * @var \Drupal\entity_usage\EntityUsage * @var \Drupal\entity_usage\EntityUsageInterface */ protected $usageService; Loading Loading @@ -53,6 +56,20 @@ abstract class EntityUsageTrackBase extends PluginBase implements EntityUsageTra */ protected $entityRepository; /** * The Drupal Path Validator service. * * @var \Drupal\Core\Path\PathValidatorInterface */ protected $pathValidator; /** * The public file directory. * * @var string */ protected $publicFileDirectory; /** * Plugin constructor. * Loading @@ -62,7 +79,7 @@ abstract class EntityUsageTrackBase extends PluginBase implements EntityUsageTra * The plugin_id for the plugin instance. * @param mixed $plugin_definition * The plugin implementation definition. * @param \Drupal\entity_usage\EntityUsage $usage_service * @param \Drupal\entity_usage\EntityUsageInterface $usage_service * The usage tracking service. * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager * The EntityTypeManager service. Loading @@ -72,8 +89,12 @@ abstract class EntityUsageTrackBase extends PluginBase implements EntityUsageTra * The factory for configuration objects. * @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository * The EntityRepositoryInterface service. * @param \Drupal\Core\Path\PathValidatorInterface $path_validator * The Drupal Path Validator service. * @param \Drupal\Core\StreamWrapper\PublicStream $public_stream * The Public Stream service. */ public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityUsage $usage_service, EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager, ConfigFactoryInterface $config_factory, EntityRepositoryInterface $entity_repository) { public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityUsageInterface $usage_service, EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager, ConfigFactoryInterface $config_factory, EntityRepositoryInterface $entity_repository, PathValidatorInterface $path_validator, PublicStream $public_stream) { parent::__construct($configuration, $plugin_id, $plugin_definition); $this->configuration += $this->defaultConfiguration(); $this->usageService = $usage_service; Loading @@ -81,6 +102,8 @@ abstract class EntityUsageTrackBase extends PluginBase implements EntityUsageTra $this->entityFieldManager = $entity_field_manager; $this->config = $config_factory->get('entity_usage.settings'); $this->entityRepository = $entity_repository; $this->pathValidator = $path_validator; $this->publicFileDirectory = $public_stream->getDirectoryPath(); } /** Loading @@ -95,7 +118,9 @@ abstract class EntityUsageTrackBase extends PluginBase implements EntityUsageTra $container->get('entity_type.manager'), $container->get('entity_field.manager'), $container->get('config.factory'), $container->get('entity.repository') $container->get('entity.repository'), $container->get('path.validator'), $container->get('stream_wrapper.public') ); } Loading Loading @@ -247,4 +272,140 @@ abstract class EntityUsageTrackBase extends PluginBase implements EntityUsageTra return $referencing_fields_on_bundle; } /** * Process the url to a Url object. * * @param string $url * A relative or absolute URL string. * * @return \Drupal\Core\Url|false * The Url object */ protected function processUrl($url) { // Strip off the scheme and host, so we only get the path. $site_domains = $this->config->get('site_domains') ?: []; foreach ($site_domains as $site_domain) { $site_domain = rtrim($site_domain, "/"); $host_pattern = str_replace('.', '\.', $site_domain) . "/"; $host_pattern = "/" . str_replace("/", '\/', $host_pattern) . "/"; if (preg_match($host_pattern, $url)) { // Strip off everything that is not the internal path. $url = parse_url($url, PHP_URL_PATH); if (preg_match('/^[^\/]+(\/.+)/', $site_domain, $matches)) { $sub_directory = $matches[1]; if ($sub_directory && substr($url, 0, strlen($sub_directory)) == $sub_directory) { $url = substr($url, strlen($sub_directory)); } } break; } } return $this->pathValidator()->getUrlIfValidWithoutAccessCheck($url); } /** * Try to retrieve an entity from an URL string. * * @param string $url * A relative or absolute URL string. * * @return \Drupal\Core\Entity\EntityInterface|null * The entity object that corresponds to the received URL, or NULL if no * entity could be retrieved. */ protected function findEntityByUrlString($url) { if (empty($url)) { return NULL; } $entity = NULL; $url_object = $this->processUrl($url); $public_file_pattern = '{^/?' . $this->publicFileDirectory() . '/}'; if ($url_object && $url_object->isRouted()) { $entity = $this->findEntityByRoutedUrl($url_object); } elseif (preg_match($public_file_pattern, $url)) { // Check if we can map the link to a public file. $file_uri = preg_replace($public_file_pattern, 'public://', urldecode($url)); $files = $this->entityTypeManager->getStorage('file')->loadByProperties(['uri' => $file_uri]); if ($files) { // File entity found. $target_type = 'file'; $target_id = array_keys($files)[0]; if ($target_type && $target_id) { $entity = $this->entityTypeManager->getStorage($target_type)->load($target_id); } } } return $entity; } /** * Try to retrieve an entity from an URL object. * * @param \Drupal\Core\Url $url * A URL object. * * @return \Drupal\Core\Entity\EntityInterface|null * The entity object that corresponds to the URL object, or NULL if no * entity could be retrieved. */ protected function findEntityByRoutedUrl(Url $url) { if (!$url || !$url->isRouted()) { return NULL; } $entity = NULL; $target_type = NULL; $target_id = NULL; $entity_pattern = '/^entity\.([a-z_]*)\./'; if (preg_match($entity_pattern, $url->getRouteName(), $matches)) { // Ge the target entity type and ID. if ($target_entity_type = $this->entityTypeManager->getDefinition($matches[1])) { $route_parameters = $url->getRouteParameters(); $target_type = $target_entity_type->id(); $target_id = $route_parameters[$target_type]; } } if ($target_type && $target_id) { $entity = $this->entityTypeManager->getStorage($target_type)->load($target_id); } return $entity; } /** * Returns the path validator service. * * @return \Drupal\Core\Path\PathValidatorInterface * The path validator. */ protected function pathValidator() { return $this->pathValidator; } /** * Return the public file directory path. * * @return string * The public file directory path. */ protected function publicFileDirectory() { if (!$this->publicFileDirectory) { $this->publicFileDirectory = \Drupal::service('stream_wrapper.public')->getDirectoryPath(); } return $this->publicFileDirectory; } } src/Plugin/EntityUsage/Track/HtmlLink.php +12 −118 Original line number Diff line number Diff line Loading @@ -3,14 +3,6 @@ namespace Drupal\entity_usage\Plugin\EntityUsage\Track; use Drupal\Component\Utility\Html; use Drupal\Core\Config\ConfigFactoryInterface; use Drupal\Core\Entity\EntityFieldManagerInterface; use Drupal\Core\Entity\EntityRepositoryInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Path\PathValidatorInterface; use Drupal\Core\StreamWrapper\StreamWrapperInterface; use Drupal\entity_usage\EntityUsage; use Symfony\Component\DependencyInjection\ContainerInterface; /** * Tracks usage of entities referenced from regular HTML Links. Loading @@ -24,68 +16,6 @@ use Symfony\Component\DependencyInjection\ContainerInterface; */ class HtmlLink extends TextFieldEmbedBase { /** * The Drupal Path Validator service. * * @var \Drupal\Core\Path\PathValidatorInterface */ protected $pathValidator; /** * The public file directory. * * @var string */ protected $publicFileDirectory; /** * Constructs the HtmlLink plugin. * * @param array $configuration * A configuration array containing information about the plugin instance. * @param string $plugin_id * The plugin_id for the plugin instance. * @param mixed $plugin_definition * The plugin implementation definition. * @param \Drupal\entity_usage\EntityUsage $usage_service * The usage tracking service. * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager * The EntityTypeManager service. * @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager * The EntityFieldManager service. * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory * The factory for configuration objects. * @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository * The EntityRepositoryInterface service. * @param \Drupal\Core\Path\PathValidatorInterface $path_validator * The Drupal Path Validator service. * @param \Drupal\Core\StreamWrapper\StreamWrapperInterface $public_stream * The Public Stream service. */ public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityUsage $usage_service, EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager, ConfigFactoryInterface $config_factory, EntityRepositoryInterface $entity_repository, PathValidatorInterface $path_validator, StreamWrapperInterface $public_stream) { parent::__construct($configuration, $plugin_id, $plugin_definition, $usage_service, $entity_type_manager, $entity_field_manager, $config_factory, $entity_repository); $this->pathValidator = $path_validator; $this->publicFileDirectory = method_exists($public_stream, 'getDirectoryPath') ? $public_stream->getDirectoryPath() : ''; } /** * {@inheritdoc} */ public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { return new static( $configuration, $plugin_id, $plugin_definition, $container->get('entity_usage.usage'), $container->get('entity_type.manager'), $container->get('entity_field.manager'), $container->get('config.factory'), $container->get('entity.repository'), $container->get('path.validator'), $container->get('stream_wrapper.public') ); } /** * {@inheritdoc} */ Loading @@ -101,42 +31,8 @@ class HtmlLink extends TextFieldEmbedBase { try { // Get the href value of the <a> element. $href = $element->getAttribute('href'); // Strip off the scheme and host, so we only get the path. $site_domains = $this->config->get('site_domains') ?: []; foreach ($site_domains as $site_domain) { $host_pattern = '{^https?://' . str_replace('.', '\.', $site_domain) . '/}'; if (\preg_match($host_pattern, $href)) { $href = preg_replace($host_pattern, '/', $href); break; } } $target_type = $target_id = NULL; // Check if the href links to an entity. $url = $this->pathValidator->getUrlIfValidWithoutAccessCheck($href); if ($url && $url->isRouted() && preg_match('/^entity\./', $url->getRouteName())) { // Ge the target entity type and ID. $route_parameters = $url->getRouteParameters(); $target_type = array_keys($route_parameters)[0]; $target_id = $route_parameters[$target_type]; } elseif (\preg_match('{^/?' . $this->publicFileDirectory . '/}', $href)) { // Check if we can map the link to a public file. $file_uri = preg_replace('{^/?' . $this->publicFileDirectory . '/}', 'public://', urldecode($href)); $files = $this->entityTypeManager->getStorage('file')->loadByProperties(['uri' => $file_uri]); if ($files) { // File entity found. $target_type = 'file'; $target_id = array_keys($files)[0]; } } if ($target_type && $target_id) { $entity = $this->entityTypeManager->getStorage($target_type)->load($target_id); $entity = $this->findEntityByUrlString($href); if ($entity) { if ($element->hasAttribute('data-entity-uuid')) { // Normally the Linkit plugin handles when a element has this // attribute, but sometimes users may change the HREF manually and Loading @@ -144,13 +40,11 @@ class HtmlLink extends TextFieldEmbedBase { $data_uuid = $element->getAttribute('data-entity-uuid'); // If the UUID is the same as found in HREF, then skip it because // it's LinkIt's job to register this usage. if ($data_uuid == $entity->uuid()) { if ($data_uuid === $entity->uuid()) { continue; } } $entities[$entity->uuid()] = $target_type; } $entities[$entity->uuid()] = $entity->getEntityTypeId(); } } catch (\Exception $e) { Loading src/Plugin/EntityUsage/Track/LayoutBuilder.php +13 −5 Original line number Diff line number Diff line Loading @@ -9,10 +9,12 @@ use Drupal\Core\Entity\EntityFieldManagerInterface; use Drupal\Core\Entity\EntityRepositoryInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Field\FieldItemInterface; use Drupal\entity_usage\EntityUsage; use Drupal\entity_usage\EntityUsageInterface; use Drupal\entity_usage\EntityUsageTrackBase; use Drupal\layout_builder\Plugin\Field\FieldType\LayoutSectionItem; use Symfony\Component\DependencyInjection\ContainerInterface; use Drupal\Core\Path\PathValidatorInterface; use Drupal\Core\StreamWrapper\PublicStream; /** * Tracks usage of entities related in Layout Builder layouts. Loading Loading @@ -42,7 +44,7 @@ class LayoutBuilder extends EntityUsageTrackBase { * The plugin_id for the plugin instance. * @param mixed $plugin_definition * The plugin implementation definition. * @param \Drupal\entity_usage\EntityUsage $usage_service * @param \Drupal\entity_usage\EntityUsageInterface $usage_service * The usage tracking service. * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager * The EntityTypeManager service. Loading @@ -54,9 +56,13 @@ class LayoutBuilder extends EntityUsageTrackBase { * The EntityRepositoryInterface service. * @param \Drupal\Core\Block\BlockManagerInterface $blockManager * Block manager. * @param \Drupal\Core\Path\PathValidatorInterface $path_validator * The Drupal Path Validator service. * @param \Drupal\Core\StreamWrapper\PublicStream $public_stream * The Public Stream service. */ public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityUsage $usage_service, EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager, ConfigFactoryInterface $config_factory, EntityRepositoryInterface $entity_repository, BlockManagerInterface $blockManager) { parent::__construct($configuration, $plugin_id, $plugin_definition, $usage_service, $entity_type_manager, $entity_field_manager, $config_factory, $entity_repository); public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityUsageInterface $usage_service, EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager, ConfigFactoryInterface $config_factory, EntityRepositoryInterface $entity_repository, BlockManagerInterface $blockManager, PathValidatorInterface $path_validator, PublicStream $public_stream) { parent::__construct($configuration, $plugin_id, $plugin_definition, $usage_service, $entity_type_manager, $entity_field_manager, $config_factory, $entity_repository, $path_validator, $public_stream); $this->blockManager = $blockManager; } Loading @@ -73,7 +79,9 @@ class LayoutBuilder extends EntityUsageTrackBase { $container->get('entity_field.manager'), $container->get('config.factory'), $container->get('entity.repository'), $container->get('plugin.manager.block') $container->get('plugin.manager.block'), $container->get('path.validator'), $container->get('stream_wrapper.public') ); } Loading src/Plugin/EntityUsage/Track/Link.php +9 −17 Original line number Diff line number Diff line Loading @@ -22,28 +22,20 @@ class Link extends EntityUsageTrackBase { */ public function getTargetEntities(FieldItemInterface $link) { /** @var \Drupal\link\LinkItemInterface $link */ // Check if the link is referencing an entity. if ($link->isExternal()) { $url = $link->getUrl()->toString(); $entity = $this->findEntityByUrlString($url); } else { $url = $link->getUrl(); if (!$url->isRouted() || !preg_match('/^entity\./', $url->getRouteName())) { return []; $entity = $this->findEntityByRoutedUrl($url); } // Ge the target entity type and ID. $route_parameters = $url->getRouteParameters(); $target_type = array_keys($route_parameters)[0]; $target_id = $route_parameters[$target_type]; // Only return a valid result if the target entity exists. try { if (!$this->entityTypeManager->getStorage($target_type)->load($target_id)) { return []; } } catch (\Exception $exception) { if (!$entity) { return []; } return [$target_type . '|' . $target_id]; return [$entity->getEntityTypeId() . '|' . $entity->id()]; } } Loading
src/EntityUpdateManager.php +3 −3 Original line number Diff line number Diff line Loading @@ -16,7 +16,7 @@ class EntityUpdateManager implements EntityUpdateManagerInterface { /** * The usage track service. * * @var \Drupal\entity_usage\EntityUsage * @var \Drupal\entity_usage\EntityUsageInterface */ protected $usageService; Loading @@ -37,14 +37,14 @@ class EntityUpdateManager implements EntityUpdateManagerInterface { /** * EntityUpdateManager constructor. * * @param \Drupal\entity_usage\EntityUsage $usage_service * @param \Drupal\entity_usage\EntityUsageInterface $usage_service * The usage tracking service. * @param \Drupal\entity_usage\EntityUsageTrackManager $track_manager * The PluginManager track service. * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory * The config factory. */ public function __construct(EntityUsage $usage_service, EntityUsageTrackManager $track_manager, ConfigFactoryInterface $config_factory) { public function __construct(EntityUsageInterface $usage_service, EntityUsageTrackManager $track_manager, ConfigFactoryInterface $config_factory) { $this->usageService = $usage_service; $this->trackManager = $track_manager; $this->config = $config_factory->get('entity_usage.settings'); Loading
src/EntityUsageTrackBase.php +165 −4 Original line number Diff line number Diff line Loading @@ -2,6 +2,7 @@ namespace Drupal\entity_usage; use Drupal\Core\Url; use Drupal\Core\Config\ConfigFactoryInterface; use Drupal\Core\Entity\EntityFieldManagerInterface; use Drupal\Core\Entity\EntityInterface; Loading @@ -9,8 +10,10 @@ use Drupal\Core\Entity\EntityRepositoryInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Entity\FieldableEntityInterface; use Drupal\Core\Entity\RevisionableInterface; use Drupal\Core\Path\PathValidatorInterface; use Drupal\Core\Plugin\ContainerFactoryPluginInterface; use Drupal\Core\Plugin\PluginBase; use Drupal\Core\StreamWrapper\PublicStream; use Symfony\Component\DependencyInjection\ContainerInterface; /** Loading @@ -21,7 +24,7 @@ abstract class EntityUsageTrackBase extends PluginBase implements EntityUsageTra /** * The usage tracking service. * * @var \Drupal\entity_usage\EntityUsage * @var \Drupal\entity_usage\EntityUsageInterface */ protected $usageService; Loading Loading @@ -53,6 +56,20 @@ abstract class EntityUsageTrackBase extends PluginBase implements EntityUsageTra */ protected $entityRepository; /** * The Drupal Path Validator service. * * @var \Drupal\Core\Path\PathValidatorInterface */ protected $pathValidator; /** * The public file directory. * * @var string */ protected $publicFileDirectory; /** * Plugin constructor. * Loading @@ -62,7 +79,7 @@ abstract class EntityUsageTrackBase extends PluginBase implements EntityUsageTra * The plugin_id for the plugin instance. * @param mixed $plugin_definition * The plugin implementation definition. * @param \Drupal\entity_usage\EntityUsage $usage_service * @param \Drupal\entity_usage\EntityUsageInterface $usage_service * The usage tracking service. * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager * The EntityTypeManager service. Loading @@ -72,8 +89,12 @@ abstract class EntityUsageTrackBase extends PluginBase implements EntityUsageTra * The factory for configuration objects. * @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository * The EntityRepositoryInterface service. * @param \Drupal\Core\Path\PathValidatorInterface $path_validator * The Drupal Path Validator service. * @param \Drupal\Core\StreamWrapper\PublicStream $public_stream * The Public Stream service. */ public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityUsage $usage_service, EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager, ConfigFactoryInterface $config_factory, EntityRepositoryInterface $entity_repository) { public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityUsageInterface $usage_service, EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager, ConfigFactoryInterface $config_factory, EntityRepositoryInterface $entity_repository, PathValidatorInterface $path_validator, PublicStream $public_stream) { parent::__construct($configuration, $plugin_id, $plugin_definition); $this->configuration += $this->defaultConfiguration(); $this->usageService = $usage_service; Loading @@ -81,6 +102,8 @@ abstract class EntityUsageTrackBase extends PluginBase implements EntityUsageTra $this->entityFieldManager = $entity_field_manager; $this->config = $config_factory->get('entity_usage.settings'); $this->entityRepository = $entity_repository; $this->pathValidator = $path_validator; $this->publicFileDirectory = $public_stream->getDirectoryPath(); } /** Loading @@ -95,7 +118,9 @@ abstract class EntityUsageTrackBase extends PluginBase implements EntityUsageTra $container->get('entity_type.manager'), $container->get('entity_field.manager'), $container->get('config.factory'), $container->get('entity.repository') $container->get('entity.repository'), $container->get('path.validator'), $container->get('stream_wrapper.public') ); } Loading Loading @@ -247,4 +272,140 @@ abstract class EntityUsageTrackBase extends PluginBase implements EntityUsageTra return $referencing_fields_on_bundle; } /** * Process the url to a Url object. * * @param string $url * A relative or absolute URL string. * * @return \Drupal\Core\Url|false * The Url object */ protected function processUrl($url) { // Strip off the scheme and host, so we only get the path. $site_domains = $this->config->get('site_domains') ?: []; foreach ($site_domains as $site_domain) { $site_domain = rtrim($site_domain, "/"); $host_pattern = str_replace('.', '\.', $site_domain) . "/"; $host_pattern = "/" . str_replace("/", '\/', $host_pattern) . "/"; if (preg_match($host_pattern, $url)) { // Strip off everything that is not the internal path. $url = parse_url($url, PHP_URL_PATH); if (preg_match('/^[^\/]+(\/.+)/', $site_domain, $matches)) { $sub_directory = $matches[1]; if ($sub_directory && substr($url, 0, strlen($sub_directory)) == $sub_directory) { $url = substr($url, strlen($sub_directory)); } } break; } } return $this->pathValidator()->getUrlIfValidWithoutAccessCheck($url); } /** * Try to retrieve an entity from an URL string. * * @param string $url * A relative or absolute URL string. * * @return \Drupal\Core\Entity\EntityInterface|null * The entity object that corresponds to the received URL, or NULL if no * entity could be retrieved. */ protected function findEntityByUrlString($url) { if (empty($url)) { return NULL; } $entity = NULL; $url_object = $this->processUrl($url); $public_file_pattern = '{^/?' . $this->publicFileDirectory() . '/}'; if ($url_object && $url_object->isRouted()) { $entity = $this->findEntityByRoutedUrl($url_object); } elseif (preg_match($public_file_pattern, $url)) { // Check if we can map the link to a public file. $file_uri = preg_replace($public_file_pattern, 'public://', urldecode($url)); $files = $this->entityTypeManager->getStorage('file')->loadByProperties(['uri' => $file_uri]); if ($files) { // File entity found. $target_type = 'file'; $target_id = array_keys($files)[0]; if ($target_type && $target_id) { $entity = $this->entityTypeManager->getStorage($target_type)->load($target_id); } } } return $entity; } /** * Try to retrieve an entity from an URL object. * * @param \Drupal\Core\Url $url * A URL object. * * @return \Drupal\Core\Entity\EntityInterface|null * The entity object that corresponds to the URL object, or NULL if no * entity could be retrieved. */ protected function findEntityByRoutedUrl(Url $url) { if (!$url || !$url->isRouted()) { return NULL; } $entity = NULL; $target_type = NULL; $target_id = NULL; $entity_pattern = '/^entity\.([a-z_]*)\./'; if (preg_match($entity_pattern, $url->getRouteName(), $matches)) { // Ge the target entity type and ID. if ($target_entity_type = $this->entityTypeManager->getDefinition($matches[1])) { $route_parameters = $url->getRouteParameters(); $target_type = $target_entity_type->id(); $target_id = $route_parameters[$target_type]; } } if ($target_type && $target_id) { $entity = $this->entityTypeManager->getStorage($target_type)->load($target_id); } return $entity; } /** * Returns the path validator service. * * @return \Drupal\Core\Path\PathValidatorInterface * The path validator. */ protected function pathValidator() { return $this->pathValidator; } /** * Return the public file directory path. * * @return string * The public file directory path. */ protected function publicFileDirectory() { if (!$this->publicFileDirectory) { $this->publicFileDirectory = \Drupal::service('stream_wrapper.public')->getDirectoryPath(); } return $this->publicFileDirectory; } }
src/Plugin/EntityUsage/Track/HtmlLink.php +12 −118 Original line number Diff line number Diff line Loading @@ -3,14 +3,6 @@ namespace Drupal\entity_usage\Plugin\EntityUsage\Track; use Drupal\Component\Utility\Html; use Drupal\Core\Config\ConfigFactoryInterface; use Drupal\Core\Entity\EntityFieldManagerInterface; use Drupal\Core\Entity\EntityRepositoryInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Path\PathValidatorInterface; use Drupal\Core\StreamWrapper\StreamWrapperInterface; use Drupal\entity_usage\EntityUsage; use Symfony\Component\DependencyInjection\ContainerInterface; /** * Tracks usage of entities referenced from regular HTML Links. Loading @@ -24,68 +16,6 @@ use Symfony\Component\DependencyInjection\ContainerInterface; */ class HtmlLink extends TextFieldEmbedBase { /** * The Drupal Path Validator service. * * @var \Drupal\Core\Path\PathValidatorInterface */ protected $pathValidator; /** * The public file directory. * * @var string */ protected $publicFileDirectory; /** * Constructs the HtmlLink plugin. * * @param array $configuration * A configuration array containing information about the plugin instance. * @param string $plugin_id * The plugin_id for the plugin instance. * @param mixed $plugin_definition * The plugin implementation definition. * @param \Drupal\entity_usage\EntityUsage $usage_service * The usage tracking service. * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager * The EntityTypeManager service. * @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager * The EntityFieldManager service. * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory * The factory for configuration objects. * @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository * The EntityRepositoryInterface service. * @param \Drupal\Core\Path\PathValidatorInterface $path_validator * The Drupal Path Validator service. * @param \Drupal\Core\StreamWrapper\StreamWrapperInterface $public_stream * The Public Stream service. */ public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityUsage $usage_service, EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager, ConfigFactoryInterface $config_factory, EntityRepositoryInterface $entity_repository, PathValidatorInterface $path_validator, StreamWrapperInterface $public_stream) { parent::__construct($configuration, $plugin_id, $plugin_definition, $usage_service, $entity_type_manager, $entity_field_manager, $config_factory, $entity_repository); $this->pathValidator = $path_validator; $this->publicFileDirectory = method_exists($public_stream, 'getDirectoryPath') ? $public_stream->getDirectoryPath() : ''; } /** * {@inheritdoc} */ public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { return new static( $configuration, $plugin_id, $plugin_definition, $container->get('entity_usage.usage'), $container->get('entity_type.manager'), $container->get('entity_field.manager'), $container->get('config.factory'), $container->get('entity.repository'), $container->get('path.validator'), $container->get('stream_wrapper.public') ); } /** * {@inheritdoc} */ Loading @@ -101,42 +31,8 @@ class HtmlLink extends TextFieldEmbedBase { try { // Get the href value of the <a> element. $href = $element->getAttribute('href'); // Strip off the scheme and host, so we only get the path. $site_domains = $this->config->get('site_domains') ?: []; foreach ($site_domains as $site_domain) { $host_pattern = '{^https?://' . str_replace('.', '\.', $site_domain) . '/}'; if (\preg_match($host_pattern, $href)) { $href = preg_replace($host_pattern, '/', $href); break; } } $target_type = $target_id = NULL; // Check if the href links to an entity. $url = $this->pathValidator->getUrlIfValidWithoutAccessCheck($href); if ($url && $url->isRouted() && preg_match('/^entity\./', $url->getRouteName())) { // Ge the target entity type and ID. $route_parameters = $url->getRouteParameters(); $target_type = array_keys($route_parameters)[0]; $target_id = $route_parameters[$target_type]; } elseif (\preg_match('{^/?' . $this->publicFileDirectory . '/}', $href)) { // Check if we can map the link to a public file. $file_uri = preg_replace('{^/?' . $this->publicFileDirectory . '/}', 'public://', urldecode($href)); $files = $this->entityTypeManager->getStorage('file')->loadByProperties(['uri' => $file_uri]); if ($files) { // File entity found. $target_type = 'file'; $target_id = array_keys($files)[0]; } } if ($target_type && $target_id) { $entity = $this->entityTypeManager->getStorage($target_type)->load($target_id); $entity = $this->findEntityByUrlString($href); if ($entity) { if ($element->hasAttribute('data-entity-uuid')) { // Normally the Linkit plugin handles when a element has this // attribute, but sometimes users may change the HREF manually and Loading @@ -144,13 +40,11 @@ class HtmlLink extends TextFieldEmbedBase { $data_uuid = $element->getAttribute('data-entity-uuid'); // If the UUID is the same as found in HREF, then skip it because // it's LinkIt's job to register this usage. if ($data_uuid == $entity->uuid()) { if ($data_uuid === $entity->uuid()) { continue; } } $entities[$entity->uuid()] = $target_type; } $entities[$entity->uuid()] = $entity->getEntityTypeId(); } } catch (\Exception $e) { Loading
src/Plugin/EntityUsage/Track/LayoutBuilder.php +13 −5 Original line number Diff line number Diff line Loading @@ -9,10 +9,12 @@ use Drupal\Core\Entity\EntityFieldManagerInterface; use Drupal\Core\Entity\EntityRepositoryInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Field\FieldItemInterface; use Drupal\entity_usage\EntityUsage; use Drupal\entity_usage\EntityUsageInterface; use Drupal\entity_usage\EntityUsageTrackBase; use Drupal\layout_builder\Plugin\Field\FieldType\LayoutSectionItem; use Symfony\Component\DependencyInjection\ContainerInterface; use Drupal\Core\Path\PathValidatorInterface; use Drupal\Core\StreamWrapper\PublicStream; /** * Tracks usage of entities related in Layout Builder layouts. Loading Loading @@ -42,7 +44,7 @@ class LayoutBuilder extends EntityUsageTrackBase { * The plugin_id for the plugin instance. * @param mixed $plugin_definition * The plugin implementation definition. * @param \Drupal\entity_usage\EntityUsage $usage_service * @param \Drupal\entity_usage\EntityUsageInterface $usage_service * The usage tracking service. * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager * The EntityTypeManager service. Loading @@ -54,9 +56,13 @@ class LayoutBuilder extends EntityUsageTrackBase { * The EntityRepositoryInterface service. * @param \Drupal\Core\Block\BlockManagerInterface $blockManager * Block manager. * @param \Drupal\Core\Path\PathValidatorInterface $path_validator * The Drupal Path Validator service. * @param \Drupal\Core\StreamWrapper\PublicStream $public_stream * The Public Stream service. */ public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityUsage $usage_service, EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager, ConfigFactoryInterface $config_factory, EntityRepositoryInterface $entity_repository, BlockManagerInterface $blockManager) { parent::__construct($configuration, $plugin_id, $plugin_definition, $usage_service, $entity_type_manager, $entity_field_manager, $config_factory, $entity_repository); public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityUsageInterface $usage_service, EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager, ConfigFactoryInterface $config_factory, EntityRepositoryInterface $entity_repository, BlockManagerInterface $blockManager, PathValidatorInterface $path_validator, PublicStream $public_stream) { parent::__construct($configuration, $plugin_id, $plugin_definition, $usage_service, $entity_type_manager, $entity_field_manager, $config_factory, $entity_repository, $path_validator, $public_stream); $this->blockManager = $blockManager; } Loading @@ -73,7 +79,9 @@ class LayoutBuilder extends EntityUsageTrackBase { $container->get('entity_field.manager'), $container->get('config.factory'), $container->get('entity.repository'), $container->get('plugin.manager.block') $container->get('plugin.manager.block'), $container->get('path.validator'), $container->get('stream_wrapper.public') ); } Loading
src/Plugin/EntityUsage/Track/Link.php +9 −17 Original line number Diff line number Diff line Loading @@ -22,28 +22,20 @@ class Link extends EntityUsageTrackBase { */ public function getTargetEntities(FieldItemInterface $link) { /** @var \Drupal\link\LinkItemInterface $link */ // Check if the link is referencing an entity. if ($link->isExternal()) { $url = $link->getUrl()->toString(); $entity = $this->findEntityByUrlString($url); } else { $url = $link->getUrl(); if (!$url->isRouted() || !preg_match('/^entity\./', $url->getRouteName())) { return []; $entity = $this->findEntityByRoutedUrl($url); } // Ge the target entity type and ID. $route_parameters = $url->getRouteParameters(); $target_type = array_keys($route_parameters)[0]; $target_id = $route_parameters[$target_type]; // Only return a valid result if the target entity exists. try { if (!$this->entityTypeManager->getStorage($target_type)->load($target_id)) { return []; } } catch (\Exception $exception) { if (!$entity) { return []; } return [$target_type . '|' . $target_id]; return [$entity->getEntityTypeId() . '|' . $entity->id()]; } }