Implemented ObjectStorage into Core.
Some checks failed
continuous-integration/drone/push Build is failing

After careful deliberation it was decided to merge ObjectStorage into Core, as it's slowly getting used by every part of FuzeWorks.
This commit is contained in:
Abel Hoogeveen 2022-12-10 13:14:38 +01:00
parent 0b0f4998b4
commit b5bf0425f3
Signed by: abelhooge
GPG Key ID: D4F7FB321E3868B7
15 changed files with 2145 additions and 703 deletions

View File

@ -1,24 +1,53 @@
kind: pipeline kind: pipeline
type: docker type: docker
name: test name: test
steps: services:
- name: composer - name: cache
image: composer:latest image: redis
commands:
- composer install steps:
- name: composer
- name: php81test image: composer:latest
image: registry.i15.nl/i15/fuzephp:8.1-alpine commands:
commands: - composer install
- docker-php-ext-enable xdebug
- vendor/bin/phpunit -c test/phpunit.xml - name: PHP81CoreTest
image: registry.i15.nl/i15/fuzephp:8.1-alpine
- name: coverage commands:
image: registry.i15.nl/i15/fuzephp:8.1-alpine - docker-php-ext-enable xdebug
commands: - vendor/bin/phpunit -c test/phpunit.xml --testsuite core
- docker-php-ext-enable xdebug
- vendor/bin/phpunit -c test/phpunit.xml --coverage-text - name: PHP81DummyProviderTest
image: registry.i15.nl/i15/fuzephp:8.1-alpine
image_pull_secrets: commands:
- docker-php-ext-enable xdebug
- vendor/bin/phpunit -c test/phpunit.xml --testsuite storage
environment:
OBJECTSTORAGE_PROVIDER: DummyProvider
- name: PHP81FileProviderTest
image: registry.i15.nl/i15/fuzephp:8.1-alpine
commands:
- docker-php-ext-enable xdebug
- vendor/bin/phpunit -c test/phpunit.xml --testsuite storage
environment:
OBJECTSTORAGE_PROVIDER: FileProvider
- name: PHP81RedisProviderTest
image: registry.i15.nl/i15/fuzephp:8.1-alpine
commands:
- docker-php-ext-enable xdebug
- vendor/bin/phpunit -c test/phpunit.xml --testsuite storage
environment:
OBJECTSTORAGE_PROVIDER: RedisProvider
OBJECTSTORAGE_REDIS_HOST: cache
- name: coverage
image: registry.i15.nl/i15/fuzephp:8.1-alpine
commands:
- docker-php-ext-enable xdebug
- vendor/bin/phpunit -c test/phpunit.xml --testsuite core --coverage-text
image_pull_secrets:
- dockerconfig - dockerconfig

View File

@ -10,7 +10,8 @@
} }
], ],
"require": { "require": {
"php": ">=8.1.0" "php": ">=8.1.0",
"psr/simple-cache": "1.0.1"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "^9", "phpunit/phpunit": "^9",

View File

@ -0,0 +1,60 @@
<?php
/**
* FuzeWorks ObjectStorage Component.
*
* The FuzeWorks PHP FrameWork
*
* Copyright (C) 2013-2020 i15
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* @author i15
* @copyright Copyright (c) 2013 - 2020, i15. (https://i15.nl)
* @license https://opensource.org/licenses/MIT MIT License
*
* @since Version 1.3.0
*
* @version Version 1.3.0
*/
use FuzeWorks\Core;
return [
// Which provider shall be used
// Options: DummyProvider, RedisProvider, FileProvider
'StorageProvider' => Core::getEnv('STORAGE_PROVIDER', null),
'DummyProvider' => [],
'RedisProvider' => [
// Type can be 'tcp' or 'unix'
'socket_type' => Core::getEnv('STORAGE_REDIS_SOCKET_TYPE', 'tcp'),
// If socket_type == 'unix', set the socket here
'socket' => Core::getEnv('STORAGE_REDIS_SOCKET', null),
// If socket_type == 'tcp', set the host here
'host' => Core::getEnv('STORAGE_REDIS_HOST', '127.0.0.1'),
// And some standard settings
'port' => Core::getEnv('STORAGE_REDIS_PORT', 6379),
'password' => Core::getEnv('STORAGE_REDIS_PASSWORD', null),
'timeout' => Core::getEnv('STORAGE_REDIS_TIMEOUT', 0),
'db_index' => Core::getEnv('STORAGE_REDIS_DBINDEX', 0),
],
'FileProvider' => [
// The directory where objects get stored by the FileProvider
'storage_directory' => Core::getEnv('STORAGE_FILE_DIRECTORY', Core::$tempDir)
]
];

View File

@ -0,0 +1,40 @@
<?php
/**
* FuzeWorks ObjectStorage Component.
*
* The FuzeWorks PHP FrameWork
*
* Copyright (C) 2013-2020 i15
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* @author i15
* @copyright Copyright (c) 2013 - 2020, i15. (https://i15.nl)
* @license https://opensource.org/licenses/MIT MIT License
*
* @since Version 1.3.0
*
* @version Version 1.3.0
*/
namespace FuzeWorks\Exception;
class StorageException extends CoreException
{
}

View File

@ -1,334 +1,342 @@
<?php <?php
/** /**
* FuzeWorks Framework Core. * FuzeWorks Framework Core.
* *
* The FuzeWorks PHP FrameWork * The FuzeWorks PHP FrameWork
* *
* Copyright (C) 2013-2019 TechFuze * Copyright (C) 2013-2019 TechFuze
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights * in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is * copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions: * furnished to do so, subject to the following conditions:
* *
* The above copyright notice and this permission notice shall be included in all * The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software. * copies or substantial portions of the Software.
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. * SOFTWARE.
* *
* @author TechFuze * @author TechFuze
* @copyright Copyright (c) 2013 - 2019, TechFuze. (http://techfuze.net) * @copyright Copyright (c) 2013 - 2019, TechFuze. (http://techfuze.net)
* @license https://opensource.org/licenses/MIT MIT License * @license https://opensource.org/licenses/MIT MIT License
* *
* @link http://techfuze.net/fuzeworks * @link http://techfuze.net/fuzeworks
* @since Version 0.0.1 * @since Version 0.0.1
* *
* @version Version 1.3.0 * @version Version 1.3.0
*/ */
namespace FuzeWorks; namespace FuzeWorks;
use FuzeWorks\Exception\ConfigException; use FuzeWorks\Exception\ConfigException;
use FuzeWorks\Exception\CoreException; use FuzeWorks\Exception\CoreException;
use FuzeWorks\Exception\EventException; use FuzeWorks\Exception\EventException;
use FuzeWorks\Exception\FactoryException; use FuzeWorks\Exception\FactoryException;
/** /**
* Factory Class. * Factory Class.
* *
* The Factory class is the central point for class communication in FuzeWorks. * The Factory class is the central point for class communication in FuzeWorks.
* When someone needs to load, for instance, the layout class, one has to do the following: * When someone needs to load, for instance, the layout class, one has to do the following:
* $factory = Factory::getInstance(); * $factory = Factory::getInstance();
* $layout = $factory->layout; * $layout = $factory->layout;
* *
* The Factory class allows the user to replace dependencies on the fly. It is possible for a class * The Factory class allows the user to replace dependencies on the fly. It is possible for a class
* to replace a dependency, like Logger, on the fly by calling the $factory->newInstance('Logger'); or the * to replace a dependency, like Logger, on the fly by calling the $factory->newInstance('Logger'); or the
* $factory->setInstance('Logger', $object); This allows for creative ways to do dependency injection, or keep classes * $factory->setInstance('Logger', $object); This allows for creative ways to do dependency injection, or keep classes
* separated. * separated.
* *
* It is also possible to load a cloned instance of the Factory class, so that all properties are independant as well, * It is also possible to load a cloned instance of the Factory class, so that all properties are independant as well,
* all to suit your very needs. * all to suit your very needs.
* *
* The Factory class is also extendible. This allows classes that extend Factory to access all it's properties. * The Factory class is also extendible. This allows classes that extend Factory to access all it's properties.
* *
* @author TechFuze <contact@techfuze.net> * @author TechFuze <contact@techfuze.net>
* @copyright Copyright (c) 2013 - 2019, TechFuze. (http://techfuze.net) * @copyright Copyright (c) 2013 - 2019, TechFuze. (http://techfuze.net)
*/ */
class Factory class Factory
{ {
/** /**
* The Factory instance that is shared by default when calling Factory::getInstance(); * The Factory instance that is shared by default when calling Factory::getInstance();
* *
* @var Factory|null Default shared instance * @var Factory|null Default shared instance
*/ */
private static ?Factory $sharedFactoryInstance = null; private static ?Factory $sharedFactoryInstance = null;
/** /**
* Whether the Factory has been initialized or not * Whether the Factory has been initialized or not
* *
* @var bool $initialized * @var bool $initialized
*/ */
private bool $initialized = false; private bool $initialized = false;
/** /**
* Config Object * Config Object
* @var Config * @var Config
*/ */
public Config $config; public Config $config;
/** /**
* Logger Object * Logger Object
* @var Logger * @var Logger
*/ */
public Logger $logger; public Logger $logger;
/** /**
* Events Object * Events Object
* @var Events * @var Events
*/ */
public Events $events; public Events $events;
/** /**
* Libraries Object * Libraries Object
* @var Libraries * @var Libraries
*/ */
public Libraries $libraries; public Libraries $libraries;
/** /**
* Helpers Object * Helpers Object
* @var Helpers * @var Helpers
*/ */
public Helpers $helpers; public Helpers $helpers;
/** /**
* Plugins Object * Plugins Object
* @var Plugins * @var Plugins
*/ */
public Plugins $plugins; public Plugins $plugins;
/** /**
* Factory instance constructor. Should only really be called once * Storage Object
* @throws FactoryException *
*/ * @var Storage
public function __construct() */
{ public Storage $storage;
// If there is no sharedFactoryInstance, prepare it
if (is_null(self::$sharedFactoryInstance)) /**
{ * Factory instance constructor. Should only really be called once
// @codeCoverageIgnoreStart * @throws FactoryException
self::$sharedFactoryInstance = $this; */
$this->config = new Config(); public function __construct()
$this->logger = new Logger(); {
$this->events = new Events(); // If there is no sharedFactoryInstance, prepare it
$this->libraries = new Libraries(); if (is_null(self::$sharedFactoryInstance))
$this->helpers = new Helpers(); {
$this->plugins = new Plugins(); // @codeCoverageIgnoreStart
self::$sharedFactoryInstance = $this;
return; $this->config = new Config();
} $this->logger = new Logger();
// @codeCoverageIgnoreEnd $this->events = new Events();
$this->libraries = new Libraries();
// Otherwise, copy the existing instances $this->helpers = new Helpers();
$x = self::getInstance(); $this->plugins = new Plugins();
foreach ($x as $key => $value) $this->storage = new Storage();
$this->{$key} = $value;
return;
} }
// @codeCoverageIgnoreEnd
/**
* Finalizes the Factory and sends out a coreStartEvent // Otherwise, copy the existing instances
* $x = self::getInstance();
* @return Factory foreach ($x as $key => $value)
* @throws CoreException $this->{$key} = $value;
*/
public function initFactory(): Factory }
{
// If already initialized, cancel /**
if ($this->initialized) * Finalizes the Factory and sends out a coreStartEvent
return $this; *
* @return Factory
// Load the config file of the FuzeWorks core * @throws CoreException
try { */
$cfg = $this->config->get('core'); public function initFactory(): Factory
} catch (ConfigException) { {
throw new CoreException("Could not initiate Factory. Config 'core' could not be found."); // If already initialized, cancel
} if ($this->initialized)
return $this;
// Disable events if requested to do so
if (!$cfg->get('enable_events')) // Load the config file of the FuzeWorks core
Events::disable(); try {
$cfg = $this->config->get('core');
// Initialize all components } catch (ConfigException) {
foreach ($this as $component) throw new CoreException("Could not initiate Factory. Config 'core' could not be found.");
{ }
if (!is_object($component))
continue; // Disable events if requested to do so
if (!$cfg->get('enable_events'))
if (method_exists($component, 'init')) Events::disable();
$component->init();
} // Initialize all components
foreach ($this as $component)
// Initialize all plugins {
$this->plugins->loadHeadersFromPluginPaths(); if (!is_object($component))
continue;
// Log actions
Logger::logInfo("FuzeWorks initialized. Firing coreStartEvent."); if (method_exists($component, 'init'))
$component->init();
// And fire the coreStartEvent }
try {
Events::fireEvent('coreStartEvent'); // Initialize all plugins
} catch (EventException $e) { $this->plugins->loadHeadersFromPluginPaths();
throw new CoreException("Could not initiate Factory. coreStartEvent threw exception: ".$e->getMessage());
} // Log actions
Logger::logInfo("FuzeWorks initialized. Firing coreStartEvent.");
return $this;
} // And fire the coreStartEvent
try {
/** Events::fireEvent('coreStartEvent');
* Get an instance of a componentClass. } catch (EventException $e) {
* throw new CoreException("Could not initiate Factory. coreStartEvent threw exception: ".$e->getMessage());
* @param string|null $instanceName }
* @return mixed
* @throws FactoryException return $this;
*/ }
public static function getInstance(string $instanceName = null): mixed
{ /**
if (is_null($instanceName)) * Get an instance of a componentClass.
return self::$sharedFactoryInstance; *
* @param string|null $instanceName
// Determine the instance name * @return mixed
$instanceName = strtolower($instanceName); * @throws FactoryException
*/
if (!isset(self::$sharedFactoryInstance->{$instanceName})) public static function getInstance(string $instanceName = null): mixed
throw new FactoryException("Could not get instance. Instance was not found."); {
if (is_null($instanceName))
return self::$sharedFactoryInstance->{$instanceName}; return self::$sharedFactoryInstance;
}
// Determine the instance name
/** $instanceName = strtolower($instanceName);
* Create a new instance of one of the loaded classes.
* It reloads the class. It does NOT clone it. if (!isset(self::$sharedFactoryInstance->{$instanceName}))
* throw new FactoryException("Could not get instance. Instance was not found.");
* @param string $className The name of the loaded class, WITHOUT the namespace
* @param string $namespace Optional namespace. Defaults to 'FuzeWorks\' return self::$sharedFactoryInstance->{$instanceName};
* @return Factory Instance }
* @throws FactoryException
*/ /**
public function newInstance(string $className, string $namespace = 'FuzeWorks\\'): self * Create a new instance of one of the loaded classes.
{ * It reloads the class. It does NOT clone it.
// Determine the class to load *
$instanceName = strtolower($className); * @param string $className The name of the loaded class, WITHOUT the namespace
$className = $namespace.ucfirst($className); * @param string $namespace Optional namespace. Defaults to 'FuzeWorks\'
* @return Factory Instance
if (!isset($this->{$instanceName})) * @throws FactoryException
{ */
throw new FactoryException("Could not load new instance of '".$instanceName."'. Instance was not found.", 1); public function newInstance(string $className, string $namespace = 'FuzeWorks\\'): self
} {
elseif (!class_exists($className, false)) // Determine the class to load
{ $instanceName = strtolower($className);
throw new FactoryException("Could not load new instance of '".$instanceName."'. Class not found.", 1); $className = $namespace.ucfirst($className);
}
if (!isset($this->{$instanceName}))
// Remove the current instance {
unset($this->{$instanceName}); throw new FactoryException("Could not load new instance of '".$instanceName."'. Instance was not found.", 1);
}
// And set the new one elseif (!class_exists($className, false))
$this->{$instanceName} = new $className(); {
throw new FactoryException("Could not load new instance of '".$instanceName."'. Class not found.", 1);
// Return itself }
return $this;
} // Remove the current instance
unset($this->{$instanceName});
/**
* Clone an instance of one of the loaded classes. // And set the new one
* It clones the class. It does NOT re-create it. $this->{$instanceName} = new $className();
*
* If the $onlyReturn = true is provided, the cloned instance will only be returned, and not set to the factory. // Return itself
* return $this;
* @param string $className The name of the loaded class, WITHOUT the namespace }
* @param bool $onlyReturn
* @return mixed /**
* @throws FactoryException * Clone an instance of one of the loaded classes.
*/ * It clones the class. It does NOT re-create it.
public static function cloneInstance(string $className, bool $onlyReturn = false): mixed *
{ * If the $onlyReturn = true is provided, the cloned instance will only be returned, and not set to the factory.
// Determine the class to load *
$instanceName = strtolower($className); * @param string $className The name of the loaded class, WITHOUT the namespace
* @param bool $onlyReturn
if (!isset(self::$sharedFactoryInstance->{$instanceName})) * @return mixed
throw new FactoryException("Could not clone instance of '".$instanceName."'. Instance was not found.", 1); * @throws FactoryException
*/
if ($onlyReturn) public static function cloneInstance(string $className, bool $onlyReturn = false): mixed
return clone self::$sharedFactoryInstance->{$instanceName}; {
// Determine the class to load
// Clone the instance $instanceName = strtolower($className);
self::$sharedFactoryInstance->{$instanceName} = clone self::$sharedFactoryInstance->{$instanceName};
if (!isset(self::$sharedFactoryInstance->{$instanceName}))
// Return itself throw new FactoryException("Could not clone instance of '".$instanceName."'. Instance was not found.", 1);
return self::$sharedFactoryInstance->{$instanceName};
} if ($onlyReturn)
return clone self::$sharedFactoryInstance->{$instanceName};
/**
* Set an instance of one of the loaded classes with your own $object. // Clone the instance
* Replace the existing class with one of your own. self::$sharedFactoryInstance->{$instanceName} = clone self::$sharedFactoryInstance->{$instanceName};
*
* @param string $objectName The name of the loaded class, WITHOUT the namespace // Return itself
* @param mixed $object Object to replace the class with return self::$sharedFactoryInstance->{$instanceName};
* @return Factory Instance }
*/
public function setInstance(string $objectName, mixed $object): self /**
{ * Set an instance of one of the loaded classes with your own $object.
// Determine the instance name * Replace the existing class with one of your own.
$instanceName = strtolower($objectName); *
* @param string $objectName The name of the loaded class, WITHOUT the namespace
// Unset and set * @param mixed $object Object to replace the class with
unset($this->{$instanceName}); * @return Factory Instance
$this->{$instanceName} = $object; */
public function setInstance(string $objectName, mixed $object): self
// Return itself {
return $this; // Determine the instance name
} $instanceName = strtolower($objectName);
/** // Unset and set
* Remove an instance of one of the loaded classes. unset($this->{$instanceName});
* $this->{$instanceName} = $object;
* @param string $className The name of the loaded class, WITHOUT the namespace
* @return Factory Factory Instance // Return itself
* @throws FactoryException return $this;
*/ }
public function removeInstance(string $className): self
{ /**
// Determine the instance name * Remove an instance of one of the loaded classes.
$instanceName = strtolower($className); *
* @param string $className The name of the loaded class, WITHOUT the namespace
if (!isset($this->{$instanceName})) * @return Factory Factory Instance
{ * @throws FactoryException
throw new FactoryException("Could not remove instance of '".$instanceName."'. Instance was not found.", 1); */
} public function removeInstance(string $className): self
{
// Unset // Determine the instance name
unset($this->{$instanceName}); $instanceName = strtolower($className);
// Return itself if (!isset($this->{$instanceName}))
return $this; {
} throw new FactoryException("Could not remove instance of '".$instanceName."'. Instance was not found.", 1);
}
/**
* Returns true if component is part of this Factory. // Unset
* unset($this->{$instanceName});
* @param $componentName
* @return bool // Return itself
*/ return $this;
public function instanceIsset($componentName): bool }
{
return isset($this->{$componentName}); /**
} * Returns true if component is part of this Factory.
} *
* @param $componentName
* @return bool
*/
public function instanceIsset($componentName): bool
{
return isset($this->{$componentName});
}
}

140
src/FuzeWorks/Storage.php Normal file
View File

@ -0,0 +1,140 @@
<?php
/**
* FuzeWorks Storage Component.
*
* The FuzeWorks PHP FrameWork
*
* Copyright (C) 2013-2020 i15
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* @author i15
* @copyright Copyright (c) 2013 - 2020, i15. (https://i15.nl)
* @license https://opensource.org/licenses/MIT MIT License
*
* @since Version 1.3.0
*
* @version Version 1.4.0
*/
namespace FuzeWorks;
use FuzeWorks\Exception\ConfigException;
use FuzeWorks\Exception\FactoryException;
use FuzeWorks\Exception\StorageException;
use FuzeWorks\Storage\iStorageProvider;
use FuzeWorks\Storage\StorageCache;
use Psr\SimpleCache\CacheInterface;
/**
* Storage Class.
*
* This class doesn't do very much, except show the FuzeWorks\Configurator that this dependency has been loaded.
*
* @author i15
* @copyright Copyright (c) 2013 - 2020, i15. (https://i15.nl)
*/
class Storage
{
/**
* The configuration file for Storage
*
* @var array
*/
private array $cfg;
/**
* The currently selected StorageProvider
*
* @var iStorageProvider
*/
private iStorageProvider $provider;
/**
* The currently used CacheInterface
*
* @var CacheInterface
*/
private CacheInterface $cache;
/**
* Fetches and returns the currently selected StorageProvider
*
* @return iStorageProvider
*@throws StorageException
*/
public function getStorage(): iStorageProvider
{
// If the provider is already loaded, return that one
if (isset($this->provider))
return $this->provider;
// Load the config, if it isn't loaded yet
if (!isset($this->cfg))
{
try {
/** @var Config $configs */
$configs = Factory::getInstance('config');
$this->cfg = $configs->getConfig('storage')->toArray();
} catch (ConfigException | FactoryException $e) {
throw new StorageException("Could not get StorageProvider. No config file named 'config.storage.php' could be found.");
}
}
// Get the currently selected StorageProvider
$selected = $this->cfg['StorageProvider'];
if (is_null($selected))
throw new StorageException("Could not get StorageProvider. Selected provider is null!");
// Try and load the StorageProvider
$class = '\FuzeWorks\Storage\Provider\\' . $selected;
if (!class_exists($class, true))
throw new StorageException("Could not get StorageProvider. Selected provider '".$selected."' is not recognized.");
/** @var iStorageProvider $provider */
$provider = new $class();
if (!$provider instanceof iStorageProvider)
throw new StorageException("Could not get StorageProvider. Selected provider '".$selected."' is not an instance of iStorageProvider'.");
// Fetch the parameters
$params = isset($this->cfg[$selected]) && is_array($this->cfg[$selected]) ? $this->cfg[$selected] : [];
if (!$provider->init($params))
throw new StorageException("Could not get StorageProvider. Selected provider '".$selected."' failed to load.");
$this->provider = $provider;
return $this->provider;
}
/**
* Returns a PSR compatible Cache object
*
* @return CacheInterface
* @throws StorageException
*/
public function getCache(): CacheInterface
{
if (isset($this->cache))
return $this->cache;
$storageProvider = $this->getStorage();
$this->cache = new StorageCache($storageProvider);
return $this->cache;
}
}

View File

@ -0,0 +1,117 @@
<?php
/**
* FuzeWorks ObjectStorage Component.
*
* The FuzeWorks PHP FrameWork
*
* Copyright (C) 2013-2020 i15
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* @author i15
* @copyright Copyright (c) 2013 - 2020, i15. (https://i15.nl)
* @license https://opensource.org/licenses/MIT MIT License
*
* @since Version 1.3.0
*
* @version Version 1.3.0
*/
namespace FuzeWorks\Storage\Provider;
use FuzeWorks\Storage\iStorageProvider;
class DummyProvider implements iStorageProvider
{
private array $data = ['index' => [], 'data' => []];
public function init(array $providerConfig): bool
{
return true;
}
public function getIndex(): array
{
return $this->data['index'];
}
public function getItem(string $key)
{
if (!in_array($key, $this->data['index']))
return null;
return $this->data['data'][$key]['data'];
}
public function getItemMeta(string $key): ?array
{
if (!in_array($key, $this->data['index']))
return null;
return $this->data['data'][$key]['meta'];
}
public function getItems(array $keys = []): array
{
$output = [];
foreach ($keys as $key)
$output[$key] = $this->getItem($key);
return $output;
}
public function hasItem(string $key): bool
{
return in_array($key, $this->data['index']);
}
public function clear(): bool
{
return $this->deleteItems($this->getIndex());
}
public function deleteItem(string $key): bool
{
// Remove the index
if (($k = array_search($key, $this->data['index'])) !== false) {
unset($this->data['index'][$k]);
}
// And remove the data
unset($this->data['data'][$key]);
return true;
}
public function deleteItems(array $keys): bool
{
foreach ($keys as $key)
$this->deleteItem($key);
return true;
}
public function save(string $key, $value, array $metaData = []): bool
{
if (!in_array($key, $this->data['index']))
$this->data['index'][] = $key;
$this->data['data'][$key] = ['data' => $value, 'meta' => $metaData];
return true;
}
}

View File

@ -0,0 +1,256 @@
<?php
/**
* FuzeWorks ObjectStorage Component.
*
* The FuzeWorks PHP FrameWork
*
* Copyright (C) 2013-2020 i15
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* @author i15
* @copyright Copyright (c) 2013 - 2020, i15. (https://i15.nl)
* @license https://opensource.org/licenses/MIT MIT License
*
* @since Version 1.3.0
*
* @version Version 1.3.0
*/
namespace FuzeWorks\Storage\Provider;
use FuzeWorks\Core;
use FuzeWorks\Exception\StorageException;
use FuzeWorks\Storage\iStorageProvider;
/**
* FileProvider
*
* An ObjectStorage provider which saves objects in files using the serialize() and unserialize() functions.
* The easiest to use StorageProvider, though with its caveats. It's nimble and works on nearly everything, but
* not particularly fast, and has some risks when multiple processes use the data at the same time.
*
* @todo Figure out a way to prevent indexes from clashing in multiple threads
* @todo Find a better way to sanitize key names other than hashing them using crc32
* @author i15
* @copyright Copyright (c) 2013 - 2020, i15. (https://i15.nl)
*/
class FileProvider implements iStorageProvider
{
/**
* The directory where all objects are saved
*
* @var string
*/
protected string $directory;
/**
* The file where the index for this provider is saved
*
* @var string
*/
protected string $indexFile;
/**
* The index of all objects stored
*
* @var array
*/
protected array $index;
/**
* @param array $providerConfig
* @return bool
* @throws StorageException
*/
public function init(array $providerConfig): bool
{
// First load the directory from the providerConfig
$directory = $providerConfig['storage_directory'] ?? null;
// Check if the directory exists
if (!file_exists($directory) || !is_dir($directory))
throw new StorageException("Could not load FileProvider Storage. Provided storageDirectory is not a directory.");
// Check if that directory also is writeable
if (!Core::isReallyWritable($directory))
throw new StorageException("Could not load FileProvider Storage. Provided storageDirectory is not writeable.");
// Save the directory and indexFile, and load or initialize the indexFile
$this->directory = rtrim($directory);
$this->indexFile = $this->directory . DS . 'index.fwstorage';
// If the index does not exist yet, load it
if (!file_exists($this->indexFile))
{
if (!$this->write_file($this->indexFile, serialize(['index' => []])))
throw new StorageException("Could not load FileProvider Storage. Could not write index.");
chmod($this->indexFile, 0640);
}
// And finally, load the index
$this->index = unserialize(file_get_contents($this->indexFile))['index'];
return true;
}
public function getIndex(): array
{
$out = [];
foreach ($this->index as $key => $val)
$out[] = $key;
return $out;
}
public function getItem(string $key)
{
// Convert the key
$file = $this->directory . DS . crc32($key) . '.fwstorage';
// If the key could not be found in the index, return null
if (!isset($this->index[$key]))
return null;
// Check if the file exists. If not, delete the indexed value
if (!file_exists($file))
{
$this->deleteItem($key);
return null;
}
// Otherwise try and load the metaData and contents
return unserialize(file_get_contents($file));
}
public function getItemMeta(string $key): ?array
{
// If the key could not be found in the index, return null
if (!isset($this->index[$key]))
return null;
// Otherwise return the meta data
return $this->index[$key]['meta'];
}
public function getItems(array $keys = []): array
{
$output = [];
foreach ($keys as $key)
$output[$key] = $this->getItem($key);
return $output;
}
public function hasItem(string $key): bool
{
return isset($this->index[$key]);
}
public function clear(): bool
{
$keys = array_keys($this->index);
return $this->deleteItems($keys);
}
public function deleteItem(string $key): bool
{
// Convert the key
$file = $this->directory . DS . crc32($key) . '.fwstorage';
// Remove the file first
if (file_exists($file))
unlink($file);
// And remove it from the index
if (isset($this->index[$key]))
unset($this->index[$key]);
// And commit the index
return $this->commitIndex();
}
public function deleteItems(array $keys): bool
{
foreach ($keys as $key)
$this->deleteItem($key);
return true;
}
public function save(string $key, $value, array $metaData = []): bool
{
// Convert the key
$file = $this->directory . DS . crc32($key) . '.fwstorage';
// Remove the file if it already exists
if (file_exists($file))
unlink($file);
// Write everything to the index
$this->index[$key] = ['meta' => $metaData];
$this->commitIndex();
// And write the contents
if ($this->write_file($file, serialize($value))) {
chmod($file, 0640);
return true;
}
return false;
}
private function commitIndex(): bool
{
if ($this->write_file($this->indexFile, serialize(['index' => $this->index]))) {
chmod($this->indexFile, 0640);
return true;
}
return false;
}
/**
* Write File
*
* Writes data to the file specified in the path.
* Creates a new file if non-existent.
*
* @param string $path File path
* @param string $data Data to write
* @return bool
*/
private function write_file(string $path, string $data): bool
{
if ( ! $fp = @fopen($path, 'wb'))
return false;
flock($fp, LOCK_EX);
for ($result = $written = 0, $length = strlen($data); $written < $length; $written += $result)
if (($result = fwrite($fp, substr($data, $written))) === false)
break;
flock($fp, LOCK_UN);
fclose($fp);
return is_int($result);
}
}

View File

@ -0,0 +1,188 @@
<?php
/**
* FuzeWorks ObjectStorage Component.
*
* The FuzeWorks PHP FrameWork
*
* Copyright (C) 2013-2020 i15
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* @author i15
* @copyright Copyright (c) 2013 - 2020, i15. (https://i15.nl)
* @license https://opensource.org/licenses/MIT MIT License
*
* @since Version 1.3.0
*
* @version Version 1.3.0
*/
namespace FuzeWorks\Storage\Provider;
use FuzeWorks\Exception\StorageException;
use FuzeWorks\Storage\iStorageProvider;
use Redis;
use RedisException;
class RedisProvider implements iStorageProvider
{
/**
* @var Redis
*/
protected Redis $conn;
/**
* Initializes the RedisProvider, by connecting to the Redis Server.
*
* $providerConfig can contain the following keys:
* 'socket_type', being either 'socket' or 'tcp'
* 'socket', when socket_type is socket, contains a handle for the socket
* 'host', when socket_type is tcp, contains the hostname or ip of the server
* 'port', when socket_type is tcp, contains the port of the server
* 'timeout', when socket_type is tcp, contains the amount of time to attempt connecting before failure
* 'db_index', the specific database number to use on the Redis Server
*
* Throws any StorageException on failure.
*
* @param array $providerConfig
* @return bool
* @throws StorageException
*/
public function init(array $providerConfig): bool
{
try {
$this->conn = new Redis();
// Afterwards we attempt to connect to the server
$socketType = $providerConfig['socket_type'];
if ($socketType === 'unix')
$success = $this->conn->connect($providerConfig['socket']);
elseif ($socketType === 'tcp')
$success = $this->conn->connect($providerConfig['host'], $providerConfig['port'], $providerConfig['timeout']);
else
$success = false;
// If failed, throw an exception informing so
if (!$success)
throw new StorageException("Could not load RedisProvider Storage. Unable to connect to server.");
// If authentication is required, attempt to do so with the provided password
if (isset($providerConfig['password']) && !$this->conn->auth($providerConfig['password']))
throw new StorageException("Could not load RedisProvider Storage. Authentication failure.");
// If a db_index is provided, use that one accordingly
if (isset($providerConfig['db_index']) && is_int($providerConfig['db_index']))
$this->conn->select($providerConfig['db_index']);
// And if all goes well, report a true
return true;
// If any sort of failure has occurred along the way,
} catch (RedisException $e) {
throw new StorageException("Could not load RedisProvider Storage. RedisException thrown: '" . $e->getMessage() . "'");
}
}
public function getIndex(): array
{
return $this->conn->sMembers('StorageIndex');
}
public function getItem(string $key)
{
// If the requested key is not part of the index, this item is not tracked and should therefore
// return null.
if (!$this->conn->sIsMember('StorageIndex', $key))
return null;
// If the data doesn't exist, return null
if (!$this->conn->hExists('fwstorage_' . $key, 'data'))
return null;
return unserialize($this->conn->hGet('fwstorage_' . $key, 'data'));
}
public function getItemMeta(string $key): ?array
{
// If the requested key is not part of the index, this item is not tracked and should therefore
// return null.
if (!$this->conn->sIsMember('StorageIndex', $key))
return null;
// If the data doesn't exist, return null
if (!$this->conn->hExists('fwstorage_' . $key, 'meta'))
return null;
return unserialize($this->conn->hGet('fwstorage_' . $key, 'meta'));
}
public function getItems(array $keys = []): array
{
$output = [];
foreach ($keys as $key)
$output[$key] = $this->getItem($key);
return $output;
}
public function hasItem(string $key): bool
{
return $this->conn->sIsMember('StorageIndex', $key);
}
public function clear(): bool
{
return $this->deleteItems($this->getIndex());
}
public function deleteItem(string $key): bool
{
// If the requested key is not part of the index, this item is not tracked and should therefore
// return null.
if ($this->conn->sIsMember('StorageIndex', $key))
$this->conn->sRem('StorageIndex', $key);
if ($this->conn->exists('fwstorage_' . $key))
$this->conn->del('fwstorage_' . $key);
return true;
}
public function deleteItems(array $keys): bool
{
foreach ($keys as $key)
$this->deleteItem($key);
return true;
}
public function save(string $key, $value, array $metaData = []): bool
{
// If the requested key is not part of the index, this item is not tracked and should therefore
// return null.
if (!$this->conn->sIsMember('StorageIndex', $key))
$this->conn->sAdd('StorageIndex', $key);
// Write to the hash
$this->conn->hSet('fwstorage_' . $key, 'data', serialize($value));
$this->conn->hSet('fwstorage_' . $key, 'meta', serialize($metaData));
return true;
}
}

View File

@ -0,0 +1,128 @@
<?php
/**
* FuzeWorks ObjectStorage Component.
*
* The FuzeWorks PHP FrameWork
*
* Copyright (C) 2013-2020 i15
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* @author i15
* @copyright Copyright (c) 2013 - 2020, i15. (https://i15.nl)
* @license https://opensource.org/licenses/MIT MIT License
*
* @since Version 1.3.0
*
* @version Version 1.3.0
*/
namespace FuzeWorks\Storage;
use Psr\SimpleCache\CacheInterface;
class StorageCache implements CacheInterface
{
private iStorageProvider $provider;
public function __construct(iStorageProvider $provider)
{
$this->provider = $provider;
}
private function testTTL(string $key)
{
$meta = $this->provider->getItemMeta('fwcache_' . $key);
if (!is_null($meta) && $meta['ttl'] > 0 && time() > $meta['time'] + $meta['ttl'])
$this->provider->deleteItem('fwcache_' . $key);
}
public function get($key, $default = null)
{
// Remove the item if its TTL has expired
$this->testTTL($key);
// Fetch the value
$res = $this->provider->getItem('fwcache_' . $key);
// If there is no value, return the default
return is_null($res) ? $default : $res;
}
public function set($key, $value, $ttl = null): bool
{
$meta = [
'time' => time(),
'ttl' => is_int($ttl) ? $ttl : 0
];
return $this->provider->save('fwcache_' . $key, $value, $meta);
}
public function delete($key): bool
{
return $this->provider->deleteItem('fwcache_' . $key);
}
public function clear(): bool
{
// Fetch the index set
$index = $this->provider->getIndex();
foreach ($index as $entry)
{
if (substr($entry, 0, 8) === 'fwcache_')
$this->provider->deleteItem($entry);
}
return true;
}
public function getMultiple($keys, $default = null): array
{
$out = [];
foreach ($keys as $key)
{
$out[$key] = $this->get($key, $default);
}
return $out;
}
public function setMultiple($values, $ttl = null): bool
{
foreach ($values as $key => $value)
$this->set($key, $value, $ttl);
return true;
}
public function deleteMultiple($keys): bool
{
foreach ($keys as $key)
$this->delete($key);
return true;
}
public function has($key): bool
{
$this->testTTL($key);
return $this->provider->hasItem('fwcache_' . $key);
}
}

View File

@ -0,0 +1,52 @@
<?php
/**
* FuzeWorks ObjectStorage Component.
*
* The FuzeWorks PHP FrameWork
*
* Copyright (C) 2013-2020 i15
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* @author i15
* @copyright Copyright (c) 2013 - 2020, i15. (https://i15.nl)
* @license https://opensource.org/licenses/MIT MIT License
*
* @since Version 1.3.0
*
* @version Version 1.3.0
*/
namespace FuzeWorks\Storage;
interface iStorageProvider
{
public function init(array $providerConfig): bool;
public function getIndex(): array;
public function getItem(string $key);
public function getItemMeta(string $key): ?array;
public function getItems(array $keys = []): array;
public function hasItem(string $key): bool;
public function clear(): bool;
public function deleteItem(string $key): bool;
public function deleteItems(array $keys): bool;
public function save(string $key, $value, array $metaData = []): bool;
}

View File

@ -1,328 +1,329 @@
<?php <?php
/** /**
* FuzeWorks Framework Core. * FuzeWorks Framework Core.
* *
* The FuzeWorks PHP FrameWork * The FuzeWorks PHP FrameWork
* *
* Copyright (C) 2013-2019 TechFuze * Copyright (C) 2013-2019 TechFuze
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights * in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is * copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions: * furnished to do so, subject to the following conditions:
* *
* The above copyright notice and this permission notice shall be included in all * The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software. * copies or substantial portions of the Software.
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. * SOFTWARE.
* *
* @author TechFuze * @author TechFuze
* @copyright Copyright (c) 2013 - 2019, TechFuze. (http://techfuze.net) * @copyright Copyright (c) 2013 - 2019, TechFuze. (http://techfuze.net)
* @license https://opensource.org/licenses/MIT MIT License * @license https://opensource.org/licenses/MIT MIT License
* *
* @link http://techfuze.net/fuzeworks * @link http://techfuze.net/fuzeworks
* @since Version 0.0.1 * @since Version 0.0.1
* *
* @version Version 1.3.0 * @version Version 1.3.0
*/ */
use FuzeWorks\Factory; use FuzeWorks\Factory;
use FuzeWorks\Exception\FactoryException; use FuzeWorks\Exception\FactoryException;
/** /**
* Class FactoryTest. * Class FactoryTest.
* *
* Will test the FuzeWorks Factory. * Will test the FuzeWorks Factory.
* @coversDefaultClass \FuzeWorks\Factory * @coversDefaultClass \FuzeWorks\Factory
*/ */
class factoryTest extends CoreTestAbstract class factoryTest extends CoreTestAbstract
{ {
/** /**
* @covers ::getInstance * @covers ::getInstance
*/ */
public function testCanLoadFactory() public function testCanLoadFactory()
{ {
$this->assertInstanceOf('FuzeWorks\Factory', Factory::getInstance()); $this->assertInstanceOf('FuzeWorks\Factory', Factory::getInstance());
} }
/** /**
* @covers ::getInstance * @covers ::getInstance
*/ */
public function testGetInstance() public function testGetInstance()
{ {
// Add the mock // Add the mock
$mock = $this->getMockBuilder(MockFactory::class)->getMock(); $mock = $this->getMockBuilder(MockFactory::class)->getMock();
Factory::getInstance()->setInstance('Mock', $mock); Factory::getInstance()->setInstance('Mock', $mock);
// First test a global getInstance Factory // First test a global getInstance Factory
$this->assertInstanceOf('\FuzeWorks\Factory', Factory::getInstance()); $this->assertInstanceOf('\FuzeWorks\Factory', Factory::getInstance());
// Second, test retrieving a component // Second, test retrieving a component
$this->assertInstanceOf(get_class($mock), Factory::getInstance('Mock')); $this->assertInstanceOf(get_class($mock), Factory::getInstance('Mock'));
} }
/** /**
* @depends testGetInstance * @depends testGetInstance
* @covers ::getInstance * @covers ::getInstance
*/ */
public function testGetInstanceNotFound() public function testGetInstanceNotFound()
{ {
$this->expectException(FactoryException::class); $this->expectException(FactoryException::class);
Factory::getInstance('NotFound'); Factory::getInstance('NotFound');
} }
/** /**
* @depends testCanLoadFactory * @depends testCanLoadFactory
* @covers ::getInstance * @covers ::getInstance
*/ */
public function testLoadSameInstance() public function testLoadSameInstance()
{ {
$this->assertSame(Factory::getInstance(), Factory::getInstance()); $this->assertSame(Factory::getInstance(), Factory::getInstance());
} }
/** /**
* @depends testCanLoadFactory * @depends testCanLoadFactory
* @covers ::getInstance * @covers ::getInstance
* @covers ::cloneInstance * @covers ::cloneInstance
*/ */
public function testLoadDifferentInstance() public function testLoadDifferentInstance()
{ {
// Add the mock // Add the mock
$mock = $this->getMockBuilder(MockFactory::class)->getMock(); $mock = $this->getMockBuilder(MockFactory::class)->getMock();
Factory::getInstance()->setInstance('Mock', $mock); Factory::getInstance()->setInstance('Mock', $mock);
// First a situation where one is the shared instance and one is a cloned instance // First a situation where one is the shared instance and one is a cloned instance
$a = Factory::getInstance('Mock'); $a = Factory::getInstance('Mock');
$b = Factory::cloneInstance('Mock'); $b = Factory::cloneInstance('Mock');
$this->assertInstanceOf(get_class($mock), $a); $this->assertInstanceOf(get_class($mock), $a);
$this->assertInstanceOf(get_class($mock), $b); $this->assertInstanceOf(get_class($mock), $b);
$this->assertNotSame($a,$b); $this->assertNotSame($a,$b);
// And a situation where both are cloned instances // And a situation where both are cloned instances
$a = Factory::cloneInstance('Mock'); $a = Factory::cloneInstance('Mock');
$b = Factory::cloneInstance('Mock'); $b = Factory::cloneInstance('Mock');
$this->assertInstanceOf(get_class($mock), $a); $this->assertInstanceOf(get_class($mock), $a);
$this->assertInstanceOf(get_class($mock), $b); $this->assertInstanceOf(get_class($mock), $b);
$this->assertNotSame($a,$b); $this->assertNotSame($a,$b);
} }
/** /**
* @depends testCanLoadFactory * @depends testCanLoadFactory
* @covers ::getInstance * @covers ::getInstance
* @covers ::setInstance * @covers ::setInstance
*/ */
public function testObjectsSameInstance() public function testObjectsSameInstance()
{ {
// Create mock // Create mock
$mock = $this->getMockBuilder(MockFactory::class)->setMethods(['mockListener'])->getMock(); $mock = $this->getMockBuilder(MockFactory::class)->setMethods(['mockListener'])->getMock();
// Test not set // Test not set
$this->assertFalse(isset(Factory::getInstance()->mock)); $this->assertFalse(isset(Factory::getInstance()->mock));
// Same instance factories // Same instance factories
/** @var Factory $factory1 */ /** @var Factory $factory1 */
/** @var Factory $factory2 */ /** @var Factory $factory2 */
$factory1 = Factory::getInstance()->setInstance('Mock', $mock); $factory1 = Factory::getInstance()->setInstance('Mock', $mock);
$factory2 = Factory::getInstance()->setInstance('Mock', $mock); $factory2 = Factory::getInstance()->setInstance('Mock', $mock);
// Return the mocks // Return the mocks
$this->assertSame($factory1->mock, $factory2->mock); $this->assertSame($factory1->mock, $factory2->mock);
// Different instance factories // Different instance factories
$factory3 = Factory::getInstance()->setInstance('Mock', $mock); $factory3 = Factory::getInstance()->setInstance('Mock', $mock);
$factory4 = Factory::getInstance()->setInstance('Mock', $mock); $factory4 = Factory::getInstance()->setInstance('Mock', $mock);
// Return the mocks // Return the mocks
$this->assertSame($factory3->mock, $factory4->mock); $this->assertSame($factory3->mock, $factory4->mock);
} }
/** /**
* @depends testObjectsSameInstance * @depends testObjectsSameInstance
* @covers ::getInstance * @covers ::getInstance
* @covers ::setInstance * @covers ::setInstance
* @covers ::cloneInstance * @covers ::cloneInstance
*/ */
public function testObjectsDifferentInstance() public function testObjectsDifferentInstance()
{ {
// Create mock // Create mock
$mock = $this->getMockBuilder(MockFactory::class)->getMock(); $mock = $this->getMockBuilder(MockFactory::class)->getMock();
// Same instance factories // Same instance factories
$factory1 = Factory::getInstance()->setInstance('Mock', $mock); $factory1 = Factory::getInstance()->setInstance('Mock', $mock);
$factory2 = Factory::getInstance()->setInstance('Mock', $mock); $factory2 = Factory::getInstance()->setInstance('Mock', $mock);
// Clone the instance in factory2 // Clone the instance in factory2
$factory2mock = $factory2->cloneInstance('Mock'); $factory2mock = $factory2->cloneInstance('Mock');
// Should be true, since both Factories use the same Mock instance // Should be true, since both Factories use the same Mock instance
$this->assertSame($factory1->mock, $factory2mock); $this->assertSame($factory1->mock, $factory2mock);
// Different instance factories // Different instance factories
$factory3 = Factory::getInstance()->setInstance('Mock', $mock); $factory3 = Factory::getInstance()->setInstance('Mock', $mock);
$factory4 = Factory::getInstance()->setInstance('Mock', $mock); $factory4 = Factory::getInstance()->setInstance('Mock', $mock);
// Should be same for now // Should be same for now
$this->assertSame($factory3->mock, $factory4->mock); $this->assertSame($factory3->mock, $factory4->mock);
// Clone the instance in factory4 // Clone the instance in factory4
$factory4mock = $factory4->cloneInstance('Mock', true); $factory4mock = $factory4->cloneInstance('Mock', true);
// Should be false, since both Factories use a different Mock instance // Should be false, since both Factories use a different Mock instance
$this->assertNotSame($factory3->mock, $factory4mock); $this->assertNotSame($factory3->mock, $factory4mock);
} }
/** /**
* @depends testCanLoadFactory * @depends testCanLoadFactory
* @covers ::cloneInstance * @covers ::cloneInstance
*/ */
public function testCloneInstanceWrongClassname() public function testCloneInstanceWrongClassname()
{ {
// Get factory // Get factory
$factory = new Factory; $factory = new Factory;
// Attempt // Attempt
$this->expectException(FactoryException::class); $this->expectException(FactoryException::class);
$factory->cloneInstance('fake'); $factory->cloneInstance('fake');
} }
/** /**
* @depends testCanLoadFactory * @depends testCanLoadFactory
* @covers ::getInstance * @covers ::getInstance
* @covers ::newInstance * @covers ::newInstance
*/ */
public function testNewFactoryInstance() public function testNewFactoryInstance()
{ {
// Load the different factories // Load the different factories
$factory = new Factory(); $factory = new Factory();
$factory2 = Factory::getInstance(); $factory2 = Factory::getInstance();
// Test if the objects are different factory instances // Test if the objects are different factory instances
$this->assertNotSame($factory, $factory2); $this->assertNotSame($factory, $factory2);
// And test if all ClassInstances are the same // And test if all ClassInstances are the same
$this->assertSame($factory->config, $factory2->config); $this->assertSame($factory->config, $factory2->config);
$this->assertSame($factory->logger, $factory2->logger); $this->assertSame($factory->logger, $factory2->logger);
$this->assertSame($factory->events, $factory2->events); $this->assertSame($factory->events, $factory2->events);
$this->assertSame($factory->libraries, $factory2->libraries); $this->assertSame($factory->libraries, $factory2->libraries);
$this->assertSame($factory->helpers, $factory2->helpers); $this->assertSame($factory->helpers, $factory2->helpers);
$this->assertSame($factory->storage, $factory2->storage);
// And test when changing one classInstance
$factory->newInstance('Helpers'); // And test when changing one classInstance
$this->assertNotSame($factory->helpers, $factory2->helpers); $factory->newInstance('Helpers');
} $this->assertNotSame($factory->helpers, $factory2->helpers);
}
/**
* @depends testNewFactoryInstance /**
* @covers ::newInstance * @depends testNewFactoryInstance
*/ * @covers ::newInstance
public function testFactoryNewInstanceNotExist() */
{ public function testFactoryNewInstanceNotExist()
// Load the factory {
$factory = new Factory; // Load the factory
$factory = new Factory;
// First, it does not exist
$this->expectException(FactoryException::class); // First, it does not exist
$factory->newInstance('fake'); $this->expectException(FactoryException::class);
} $factory->newInstance('fake');
}
/**
* @depends testNewFactoryInstance /**
* @covers ::newInstance * @depends testNewFactoryInstance
*/ * @covers ::newInstance
public function testFactoryNewInstanceWrongNamespace() */
{ public function testFactoryNewInstanceWrongNamespace()
// Load the factory {
$factory = new Factory; // Load the factory
$factory = new Factory;
// Second, it just fails
$this->expectException(FactoryException::class); // Second, it just fails
$factory->newInstance('helpers', 'Test\\'); $this->expectException(FactoryException::class);
} $factory->newInstance('helpers', 'Test\\');
}
/**
* @depends testNewFactoryInstance /**
* @covers ::setInstance * @depends testNewFactoryInstance
* @covers ::removeInstance * @covers ::setInstance
*/ * @covers ::removeInstance
public function testRemoveInstance() */
{ public function testRemoveInstance()
// Load the factory {
$factory = new Factory; // Load the factory
$factory = new Factory;
// Create the object
$object = new MockObject; // Create the object
$object = new MockObject;
// Add it to the factory
$factory->setInstance('test', $object); // Add it to the factory
$factory->setInstance('test', $object);
// Test if it is there
$this->assertObjectHasAttribute('test', $factory); // Test if it is there
$this->assertSame($object, $factory->test); $this->assertObjectHasAttribute('test', $factory);
$this->assertSame($object, $factory->test);
// Now remove it
$factory->removeInstance('test'); // Now remove it
$factory->removeInstance('test');
// Assert that it's gone
$this->assertObjectNotHasAttribute('test', $factory); // Assert that it's gone
} $this->assertObjectNotHasAttribute('test', $factory);
}
/**
* @depends testRemoveInstance /**
* @covers ::removeInstance * @depends testRemoveInstance
*/ * @covers ::removeInstance
public function testRemoveInstanceNotExist() */
{ public function testRemoveInstanceNotExist()
// Load the factory {
$factory = new Factory; // Load the factory
$factory = new Factory;
// Test
$this->expectException(FactoryException::class); // Test
$factory->removeInstance('fake'); $this->expectException(FactoryException::class);
} $factory->removeInstance('fake');
}
/**
* @depends testCanLoadFactory /**
* @covers ::instanceIsset * @depends testCanLoadFactory
* @covers ::setInstance * @covers ::instanceIsset
*/ * @covers ::setInstance
public function testInstanceIsset() */
{ public function testInstanceIsset()
// Load the factory {
$factory = new Factory; // Load the factory
$factory = new Factory;
// Test if not set and add instance
$this->assertFalse($factory->instanceIsset('test')); // Test if not set and add instance
$factory->setInstance('test', 5); $this->assertFalse($factory->instanceIsset('test'));
$factory->setInstance('test', 5);
// Test if isset and value
$this->assertTrue($factory->instanceIsset('test')); // Test if isset and value
$this->assertEquals(5, $factory->test); $this->assertTrue($factory->instanceIsset('test'));
} $this->assertEquals(5, $factory->test);
}
public function tearDown(): void
{ public function tearDown(): void
parent::tearDown(); {
parent::tearDown();
$factory = Factory::getInstance();
if (isset($factory->mock)) $factory = Factory::getInstance();
$factory->removeInstance('mock'); if (isset($factory->mock))
} $factory->removeInstance('mock');
}
}
}
class MockFactory {
class MockFactory {
}
}
class MockObject {
class MockObject {
} }

View File

@ -1,19 +1,23 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd" bootstrap="autoload.php" convertErrorsToExceptions="true" convertNoticesToExceptions="true" convertWarningsToExceptions="true" stopOnError="false" stopOnFailure="false" stopOnIncomplete="false" stopOnSkipped="false" colors="false"> <phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd" bootstrap="autoload.php" convertErrorsToExceptions="true" convertNoticesToExceptions="true" convertWarningsToExceptions="true" stopOnError="false" stopOnFailure="false" stopOnIncomplete="false" stopOnSkipped="false" colors="false">
<coverage processUncoveredFiles="false"> <coverage processUncoveredFiles="false">
<include> <include>
<directory suffix=".php">../</directory> <directory suffix=".php">../</directory>
</include> </include>
<exclude> <exclude>
<directory suffix=".php">../vendor/</directory> <directory suffix=".php">../vendor/</directory>
<directory suffix=".php">../test/</directory> <directory suffix=".php">../test/</directory>
<directory suffix=".php">../src/Layout/</directory> <directory suffix=".php">../src/Layout/</directory>
<directory suffix=".php">../src/Config/</directory> <directory suffix=".php">../src/Config/</directory>
</exclude> </exclude>
</coverage> </coverage>
<testsuites> <testsuites>
<testsuite name="Core Suite"> <testsuite name="core">
<directory>./</directory> <directory>./core</directory>
</testsuite> <directory>./events</directory>
</testsuites> </testsuite>
<testsuite name="storage">
<directory>./storage</directory>
</testsuite>
</testsuites>
</phpunit> </phpunit>

View File

@ -0,0 +1,200 @@
<?php
/**
* FuzeWorks ObjectStorage Component.
*
* The FuzeWorks PHP FrameWork
*
* Copyright (C) 2013-2020 i15
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* @author i15
* @copyright Copyright (c) 2013 - 2020, i15. (https://i15.nl)
* @license https://opensource.org/licenses/MIT MIT License
*
* @since Version 1.3.0
*
* @version Version 1.3.0
*/
namespace storage;
use FuzeWorks\Factory;
use FuzeWorks\Storage;
use PHPUnit\Framework\TestCase;
use Psr\SimpleCache\CacheInterface;
class StorageCacheTest extends TestCase
{
private CacheInterface $cache;
public function setUp(): void
{
parent::setUp();
$this->loadProvider();
}
public function tearDown(): void
{
parent::tearDown();
// Always clear the cache after every test
$this->cache->clear();
}
private function loadProvider()
{
/** @var Storage $objectStorageComponent */
$objectStorageComponent = Factory::getInstance('storage');
$this->cache = $objectStorageComponent->getCache();
}
public function testFoundation()
{
$this->assertInstanceOf('\Psr\SimpleCache\CacheInterface', $this->cache);
$this->assertInstanceOf('\FuzeWorks\Storage\StorageCache', $this->cache);
}
/**
* @depends testFoundation
*/
public function testSetGetAndHas()
{
$testData = ['hello', 'world'];
// First check the data isn't there
$this->assertFalse($this->cache->has('testData'));
// Then write it
$this->assertTrue($this->cache->set('testData', $testData));
// Assert it is there and check its contents
$this->assertTrue($this->cache->has('testData'));
$this->assertEquals(['hello', 'world'], $this->cache->get('testData'));
}
/**
* @depends testSetGetAndHas
*/
public function testGetDefaultValue()
{
// Verify that no value exists
$this->assertFalse($this->cache->has('testData'));
$this->assertNull($this->cache->get('testData'));
// And check if the default value is returned
$this->assertEquals('default!', $this->cache->get('testData', 'default!'));
}
/**
* @depends testSetGetAndHas
*/
public function testDeleteValue()
{
// Verify that none exist
$this->assertFalse($this->cache->has('testData'));
// Write some data
$this->assertTrue($this->cache->set('testData', 'someValue'));
$this->assertEquals('someValue', $this->cache->get('testData'));
$this->assertTrue($this->cache->has('testData'));
// Delete it
$this->assertTrue($this->cache->delete('testData'));
$this->assertFalse($this->cache->has('testData'));
}
/**
* @depends testDeleteValue
*/
public function testClear()
{
// Write some data
$this->assertTrue($this->cache->set('testData1', 'value1'));
$this->assertTrue($this->cache->set('testData2', 'value2'));
// Then clear it off
$this->assertTrue($this->cache->clear());
$this->assertFalse($this->cache->has('testData1'));
$this->assertFalse($this->cache->has('testData2'));
}
/**
* @depends testDeleteValue
*/
public function testMultiple()
{
// First check that none of the variables exist
$this->assertFalse($this->cache->has('testData1'));
$this->assertFalse($this->cache->has('testData2'));
$this->assertFalse($this->cache->has('testData3'));
// With a get multiple, and default
$this->assertEquals([
'testData1' => 'default',
'testData2' => 'default',
'testData3' => 'default'
], $this->cache->getMultiple(['testData1', 'testData2', 'testData3'], 'default'));
// Write multiple
$this->assertTrue($this->cache->setMultiple([
'testData1' => 'value1',
'testData2' => 'value2',
'testData3' => 'value3'
]));
// Test the contents
$this->assertEquals([
'testData1' => 'value1',
'testData2' => 'value2',
'testData3' => 'value3'
], $this->cache->getMultiple(['testData1', 'testData2', 'testData3'], 'default'));
// And also delete them all
$this->assertTrue($this->cache->deleteMultiple(['testData1', 'testData2', 'testData3']));
$this->assertFalse($this->cache->has('testData1'));
$this->assertFalse($this->cache->has('testData2'));
$this->assertFalse($this->cache->has('testData3'));
}
/**
* @depends testSetGetAndHas
*/
public function testTTL()
{
$testData = ['hello', 'world'];
// First check the data isn't there
$this->assertFalse($this->cache->has('testData'));
// Then write it
$this->assertTrue($this->cache->set('testData', $testData, 1));
// Assert it is there and check its contents
$this->assertTrue($this->cache->has('testData'));
$this->assertEquals(['hello', 'world'], $this->cache->get('testData'));
// Then wait 2 secs
sleep(2);
// And check again
$this->assertFalse($this->cache->has('testData'));
}
}

View File

@ -0,0 +1,218 @@
<?php
/**
* FuzeWorks ObjectStorage Component.
*
* The FuzeWorks PHP FrameWork
*
* Copyright (C) 2013-2020 i15
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* @author i15
* @copyright Copyright (c) 2013 - 2020, i15. (https://i15.nl)
* @license https://opensource.org/licenses/MIT MIT License
*
* @since Version 1.3.0
*
* @version Version 1.3.0
*/
namespace storage;
use FuzeWorks\Factory;
use FuzeWorks\Storage\iStorageProvider;
use FuzeWorks\Storage;
use PHPUnit\Framework\TestCase;
/**
* Class ObjectStorageProviderTest
*
* @todo getIndex() method
*/
class StorageProviderTest extends TestCase
{
private iStorageProvider $provider;
public function setUp(): void
{
parent::setUp();
$this->loadProvider();
}
public function tearDown(): void
{
parent::tearDown();
// Always clear the provider at the end
$this->provider->clear();
}
private function loadProvider()
{
/** @var Storage $objectStorageComponent */
$objectStorageComponent = Factory::getInstance('storage');
$this->provider = $objectStorageComponent->getStorage();
}
public function testFoundation()
{
$this->assertInstanceOf('\FuzeWorks\Storage\iStorageProvider', $this->provider);
}
/**
* @depends testFoundation
*/
public function testSave()
{
$testData = ['hello', 'world', 'foo' => 'bar'];
// First assert it does not exist yet
$this->assertNull($this->provider->getItem('testData'));
$this->assertFalse($this->provider->hasItem('testData'));
// Write the data
$this->assertTrue($this->provider->save('testData', $testData));
// Read the data
$this->assertTrue($this->provider->hasItem('testData'));
$this->assertEquals(['hello', 'world', 'foo' => 'bar'], $this->provider->getItem('testData'));
}
/**
* @depends testSave
*/
public function testDeleteItem()
{
$testData = ['o', 'm', 'g'];
// First assert that the data does not exist yet
$this->assertNull($this->provider->getItem('testDeleteData'));
// Write the data
$this->assertTrue($this->provider->save('testDeleteData', $testData));
// Read the data
$this->assertEquals(['o', 'm', 'g'], $this->provider->getItem('testDeleteData'));
// Delete the data
$this->assertTrue($this->provider->deleteItem('testDeleteData'));
// And test that it is truly gone
$this->assertNull($this->provider->getItem('testDeleteData'));
}
/**
* @depends testDeleteItem
*/
public function testDeleteItems()
{
$testData = 'lord';
$testData2 = 'almighty';
// First assert that the data does not exist yet
$this->assertNull($this->provider->getItem('testDeleteData1'));
$this->assertNull($this->provider->getItem('testDeleteData2'));
// Write the data
$this->assertTrue($this->provider->save('testDeleteData1', $testData));
$this->assertTrue($this->provider->save('testDeleteData2', $testData2));
// Read the data
$this->assertEquals(
['testDeleteData1' => 'lord', 'testDeleteData2' => 'almighty'],
$this->provider->getItems(['testDeleteData1', 'testDeleteData2'])
);
// Delete the data
$this->assertTrue($this->provider->deleteItems(['testDeleteData1', 'testDeleteData2']));
// And test that it is truly gone
$this->assertNull($this->provider->getItem('testDeleteData1'));
$this->assertNull($this->provider->getItem('testDeleteData2'));
}
/**
* @depends testDeleteItems
*/
public function testClear()
{
$testData = ['not', 'my', 'department'];
// First assert it does not exist yet
$this->assertNull($this->provider->getItem('testClearData'));
$this->provider->save('testClearData', $testData);
// Test that it can be read
$this->assertEquals(['not', 'my', 'department'], $this->provider->getItem('testClearData'));
// Then attempt to clean it
$this->assertTrue($this->provider->clear());
// And check that it cannot be read
$this->assertNull($this->provider->getItem('testClearData'));
}
public function testItemNotExist()
{
$this->assertNull($this->provider->getItem('doesNotExist'));
}
public function testGetMultipleItems()
{
$testData1 = ['tao', 'te', 'ching'];
$testData2 = ['plato', 'aristotle'];
// First assert they do not exist
$this->assertNull($this->provider->getItem('philo1'));
$this->assertNull($this->provider->getItem('philo2'));
$this->assertEquals(['philo1' => null, 'philo2' => null], $this->provider->getItems(['philo1', 'philo2']));
// Then write both
$this->assertTrue($this->provider->save('philo1', $testData1));
$this->assertTrue($this->provider->save('philo2', $testData2));
// Then read
$this->assertEquals([
'philo1' => ['tao', 'te', 'ching'],
'philo2' => ['plato', 'aristotle']
], $this->provider->getItems(['philo1', 'philo2']));
}
public function testItemMetaData()
{
$testData = ['meine', 'gute'];
$metaData = ['someKey' => 'someValue'];
// First assert that the data does not exist
$this->assertNull($this->provider->getItem('testData'));
$this->assertNull($this->provider->getItemMeta('testData'));
// Then save the data
$this->assertTrue($this->provider->save('testData', $testData, $metaData));
// Check the metaData
$this->assertEquals(['someKey' => 'someValue'], $this->provider->getItemMeta('testData'));
// Remove the key
$this->provider->deleteItem('testData');
$this->assertNull($this->provider->getItemMeta('testData'));
}
}