ex_icons-8.x-1.0/src/Discovery/SvgSymbolDiscovery.php
src/Discovery/SvgSymbolDiscovery.php
<?php
namespace Drupal\ex_icons\Discovery;
use Drupal\Component\Discovery\DiscoverableInterface;
use Drupal\Component\FileCache\FileCacheFactory;
use Drupal\Core\File\FileUrlGeneratorInterface;
use Drupal\ex_icons\Serialization\SvgSpriteSheet;
/**
* Provides discovery for SVG symbol icons within a given set of directories.
*/
class SvgSymbolDiscovery implements DiscoverableInterface {
/**
* The basename of the file to look for in each directory.
*
* @var string
*/
protected $basename;
/**
* An array of directories to scan, keyed by the provider.
*
* @var array
*/
protected $directories = [];
/**
* The file URL generator.
*
* @var \Drupal\Core\File\FileUrlGeneratorInterface
*/
protected $fileUrlGenerator;
/**
* Constructs a SvgSymbolDiscovery object.
*
* @param string $basename
* The basename of the file to look for in each directory. Can include
* slashes to designate sub-directories.
* @param array $directories
* An array of directories to scan, keyed by the provider.
*/
public function __construct($basename, array $directories) {
$this->basename = $basename;
$this->directories = $directories;
}
/**
* {@inheritdoc}
*/
public function findAll() {
$all = [];
$files = $this->findFiles();
$provider_by_files = array_flip($files);
$file_cache = FileCacheFactory::get('svg_symbol_discovery');
// Try to load from the file cache first.
foreach ($file_cache->getMultiple($files) as $file => $data) {
$all[$provider_by_files[$file]] = $data;
unset($provider_by_files[$file]);
}
// If there are files left that were not returned from the cache, load and
// parse them now. This list was flipped above and is keyed by filename.
if ($provider_by_files) {
foreach ($provider_by_files as $file => $provider) {
$data = $this->decode($file);
$file_url = $this->transformFileUrl($file);
// Generate a hash based on the sprite sheet content for browser
// cache versioning purposes.
$hash = substr(hash_file('sha256', $file), 0, 16);
$all[$provider] = ['base_url' => "$file_url?$hash"] + $data;
$file_cache->set($file, $all[$provider]);
}
}
return $all;
}
/**
* Decode a SVG sprite sheet file.
*
* @param string $file
* SVG file path.
*
* @return array
* SVG sprite sheet data.
*/
protected function decode($file) {
// If a file is empty or its contents are commented out, return an empty
// array instead of NULL for type consistency.
return SvgSpriteSheet::decode(file_get_contents($file)) ?: [];
}
/**
* Returns an array of file paths, keyed by provider.
*
* @return string[]
* The list of file paths, keyed by provider.
*/
protected function findFiles() {
$files = [];
foreach ($this->directories as $provider => $directory) {
$file = "$directory/$this->basename.svg";
if (file_exists($file)) {
$files[$provider] = $file;
}
}
return $files;
}
/**
* Gets the file url generator.
*
* @return \Drupal\Core\File\FileUrlGeneratorInterface
* The file url generator.
*/
protected function getFileUrlGenerator() {
// @phpstan-ignore-next-line
if (!$this->fileUrlGenerator && \Drupal::hasService('file_url_generator')) {
// @phpstan-ignore-next-line
$this->fileUrlGenerator = \Drupal::service('file_url_generator');
}
return $this->fileUrlGenerator;
}
/**
* Sets the file URL generator to use.
*
* @param \Drupal\Core\File\FileUrlGeneratorInterface $file_url_generator
* The file URL generator.
*
* @return $this
* Returns self for chaining.
*/
public function setFileUrlGenerator(FileUrlGeneratorInterface $file_url_generator) {
$this->fileUrlGenerator = $file_url_generator;
return $this;
}
/**
* Transforms a file path to a relative, web-accessible URL.
*
* @todo Remove this Drupal-specific code so this class is independent of
* Drupal, to follow the convention of
* \Drupal\Component\Discovery\YamlDiscovery and
* \Drupal\Component\Discovery\YamlDirectoryDiscovery.
*
* @param string $file_path
* The path to transform.
*
* @return string
* The transformed, web-accessible URL.
*/
protected function transformFileUrl($file_path) {
// @phpstan-ignore-next-line
$relative = str_replace(\Drupal::root() . '/', '', $file_path);
return $this->getFileUrlGenerator()->generateString($relative);
}
}
