Skip to content

Commit

Permalink
Performance Improvements (#23)
Browse files Browse the repository at this point in the history
* Cache resource manager base uris, and build resource uri manually

* Improve external url check

* Cache optimisation

* Cache file hashes

* Cache file hashes

* Static file cache

* Hash cache

* Clear hash cache when changing salt
  • Loading branch information
bajb authored Feb 7, 2020
1 parent f538855 commit 48d3515
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 24 deletions.
15 changes: 11 additions & 4 deletions src/Dispatch.php
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,12 @@ public static function destroy()
public function setHashSalt(string $hashSalt)
{
$this->_hashSalt = $hashSalt;
static::$_hashCache = [];
return $this;
}

protected static $_hashCache = [];

/**
* Generate a hash against specific content, for a desired length
*
Expand All @@ -115,12 +118,16 @@ public function setHashSalt(string $hashSalt)
*/
public function generateHash($content, int $length = null)
{
$hash = md5($content . $this->_hashSalt);
if(!isset(static::$_hashCache[$content]))
{
static::$_hashCache[$content] = md5($content . $this->_hashSalt);
}

if($length !== null)
{
return substr($hash, 0, $length);
return substr(static::$_hashCache[$content], 0, $length);
}
return $hash;
return static::$_hashCache[$content];
}

public function getResourcesPath()
Expand Down Expand Up @@ -303,7 +310,7 @@ protected function _getClassLoader()
{
if($this->_classLoader === null)
{
foreach(spl_autoload_functions() as list($loader))
foreach(spl_autoload_functions() as [$loader])
{
if($loader instanceof ClassLoader)
{
Expand Down
63 changes: 43 additions & 20 deletions src/ResourceManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
use RuntimeException;
use function apcu_fetch;
use function apcu_store;
use function array_merge;
use function array_unshift;
use function base_convert;
use function count;
Expand Down Expand Up @@ -43,7 +42,7 @@ class ResourceManager

protected $_type = self::MAP_RESOURCES;
protected $_mapOptions = [];
protected $_baseUri = [];
protected $_baseUri;
protected $_componentPath;
protected $_options = [];

Expand All @@ -69,7 +68,17 @@ public function __construct($type, array $mapOptions = [], array $options = [])
$this->setOption($option, $optionValue);
}
$this->_options = $options;
$this->_baseUri = array_merge([$type], $mapOptions);
}

public function getBaseUri()
{
if($this->_baseUri === null)
{
$this->_baseUri = (Dispatch::instance() ? Dispatch::instance()->getBaseUri() : '/')
. '/' . $this->_type . '/' . implode('/', $this->_mapOptions);
$this->_baseUri = trim($this->_baseUri, '/');
}
return $this->_baseUri;
}

/**
Expand Down Expand Up @@ -297,20 +306,22 @@ public function getResourceUri($relativeFullPath, bool $allowComponentBubble = t
{
return null;
}
return Path::custom(
'/',
array_merge(
[Dispatch::instance()->getBaseUri()],
$this->_baseUri,
[$hash . $relHash . ($bits > 0 ? '-' . base_convert($bits, 10, 36) : ''), $relativeFullPath]
)
);

return $this->getBaseUri()
. '/' . $hash . $relHash . ($bits > 0 ? '-' . base_convert($bits, 10, 36) : '')
. '/' . $relativeFullPath;
}

protected $_optimizeWebP;

protected function _optimisePath($path, $relativeFullPath)
{
$optimise = ValueAs::bool(Dispatch::instance()->config()->getItem('optimisation', 'webp', false));
if($optimise
if($this->_optimizeWebP === null)
{
$this->_optimizeWebP = ValueAs::bool(Dispatch::instance()->config()->getItem('optimisation', 'webp', false));
}

if($this->_optimizeWebP
&& in_array(substr($path, -4), ['.jpg', 'jpeg', '.png', '.gif', '.bmp', 'tiff', '.svg'])
&& file_exists($path . '.webp'))
{
Expand All @@ -328,11 +339,11 @@ protected function _optimisePath($path, $relativeFullPath)
*/
public function isExternalUrl($path)
{
return strlen($path) > 8 && (
Strings::startsWith($path, 'http://', true, 7) ||
Strings::startsWith($path, 'https://', true, 8) ||
Strings::startsWith($path, '//', true, 2)
);
return isset($path[8])
&& (
($path[0] == '/' && $path[1] == '/')
|| strncasecmp($path, 'http://', 7) == 0
|| strncasecmp($path, 'https://', 8) == 0);
}

/**
Expand Down Expand Up @@ -377,16 +388,27 @@ public function getRelativeHash($filePath)
return Dispatch::instance()->generateHash(Dispatch::instance()->calculateRelativePath($filePath), 4);
}

protected static $_fileHashCache = [];

public function getFileHash($fullPath)
{
if(!file_exists($fullPath))
$cached = static::$_fileHashCache[$fullPath] ?? null;

if($cached === -1 || ($cached === null && !file_exists($fullPath)))
{
self::$_fileHashCache[$fullPath] = -1;
if($this->getOption(self::OPT_THROW_ON_FILE_NOT_FOUND, true))
{
throw new RuntimeException("Unable to find dispatch file '$fullPath'", 404);
}
return null;
}

if(!empty($cached))
{
return $cached;
}

$key = 'pdspfh-' . md5($fullPath) . '-' . filectime($fullPath);

if(function_exists("apcu_fetch"))
Expand All @@ -396,12 +418,13 @@ public function getFileHash($fullPath)
if($exists && $hash)
{
// @codeCoverageIgnoreStart
self::$_fileHashCache[$fullPath] = $hash;
return $hash;
// @codeCoverageIgnoreEnd
}
}

$hash = Dispatch::instance()->generateHash(md5_file($fullPath), 8);
self::$_fileHashCache[$fullPath] = $hash = Dispatch::instance()->generateHash(md5_file($fullPath), 8);
if($hash && function_exists('apcu_store'))
{
apcu_store($key, $hash, 86400);
Expand Down
6 changes: 6 additions & 0 deletions tests/ResourceManagerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,13 @@ public function testIsExternalUrl()
{
$manager = ResourceManager::external();
$this->assertTrue($manager->isExternalUrl('http://www.google.com'));
$this->assertTrue($manager->isExternalUrl('hTTp://www.google.com'));
$this->assertFalse($manager->isExternalUrl('abhttp://www.google.com'));
$this->assertTrue($manager->isExternalUrl('https://www.google.com'));
$this->assertTrue($manager->isExternalUrl('httPS://www.google.com'));
$this->assertFalse($manager->isExternalUrl('abhttps://www.google.com'));
$this->assertTrue($manager->isExternalUrl('//www.google.com'));
$this->assertFalse($manager->isExternalUrl('://www.google.com'));

//Check external still work on other resource types
$manager = ResourceManager::public();
Expand Down

0 comments on commit 48d3515

Please sign in to comment.