Implemented ObjectStorage into Core.
continuous-integration/drone/push Build is failing Details

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
type: docker
name: test
steps:
- name: composer
image: composer:latest
commands:
- composer install
- name: php81test
image: registry.i15.nl/i15/fuzephp:8.1-alpine
commands:
- docker-php-ext-enable xdebug
- vendor/bin/phpunit -c test/phpunit.xml
- name: coverage
image: registry.i15.nl/i15/fuzephp:8.1-alpine
commands:
- docker-php-ext-enable xdebug
- vendor/bin/phpunit -c test/phpunit.xml --coverage-text
image_pull_secrets:
kind: pipeline
type: docker
name: test
services:
- name: cache
image: redis
steps:
- name: composer
image: composer:latest
commands:
- composer install
- name: PHP81CoreTest
image: registry.i15.nl/i15/fuzephp:8.1-alpine
commands:
- docker-php-ext-enable xdebug
- vendor/bin/phpunit -c test/phpunit.xml --testsuite core
- name: PHP81DummyProviderTest
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: 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

View File

@ -10,7 +10,8 @@
}
],
"require": {
"php": ">=8.1.0"
"php": ">=8.1.0",
"psr/simple-cache": "1.0.1"
},
"require-dev": {
"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
/**
* FuzeWorks Framework Core.
*
* The FuzeWorks PHP FrameWork
*
* Copyright (C) 2013-2019 TechFuze
*
* 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 TechFuze
* @copyright Copyright (c) 2013 - 2019, TechFuze. (http://techfuze.net)
* @license https://opensource.org/licenses/MIT MIT License
*
* @link http://techfuze.net/fuzeworks
* @since Version 0.0.1
*
* @version Version 1.3.0
*/
namespace FuzeWorks;
use FuzeWorks\Exception\ConfigException;
use FuzeWorks\Exception\CoreException;
use FuzeWorks\Exception\EventException;
use FuzeWorks\Exception\FactoryException;
/**
* Factory Class.
*
* 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:
* $factory = Factory::getInstance();
* $layout = $factory->layout;
*
* 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
* $factory->setInstance('Logger', $object); This allows for creative ways to do dependency injection, or keep classes
* separated.
*
* 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.
*
* The Factory class is also extendible. This allows classes that extend Factory to access all it's properties.
*
* @author TechFuze <contact@techfuze.net>
* @copyright Copyright (c) 2013 - 2019, TechFuze. (http://techfuze.net)
*/
class Factory
{
/**
* The Factory instance that is shared by default when calling Factory::getInstance();
*
* @var Factory|null Default shared instance
*/
private static ?Factory $sharedFactoryInstance = null;
/**
* Whether the Factory has been initialized or not
*
* @var bool $initialized
*/
private bool $initialized = false;
/**
* Config Object
* @var Config
*/
public Config $config;
/**
* Logger Object
* @var Logger
*/
public Logger $logger;
/**
* Events Object
* @var Events
*/
public Events $events;
/**
* Libraries Object
* @var Libraries
*/
public Libraries $libraries;
/**
* Helpers Object
* @var Helpers
*/
public Helpers $helpers;
/**
* Plugins Object
* @var Plugins
*/
public Plugins $plugins;
/**
* Factory instance constructor. Should only really be called once
* @throws FactoryException
*/
public function __construct()
{
// If there is no sharedFactoryInstance, prepare it
if (is_null(self::$sharedFactoryInstance))
{
// @codeCoverageIgnoreStart
self::$sharedFactoryInstance = $this;
$this->config = new Config();
$this->logger = new Logger();
$this->events = new Events();
$this->libraries = new Libraries();
$this->helpers = new Helpers();
$this->plugins = new Plugins();
return;
}
// @codeCoverageIgnoreEnd
// Otherwise, copy the existing instances
$x = self::getInstance();
foreach ($x as $key => $value)
$this->{$key} = $value;
}
/**
* Finalizes the Factory and sends out a coreStartEvent
*
* @return Factory
* @throws CoreException
*/
public function initFactory(): Factory
{
// If already initialized, cancel
if ($this->initialized)
return $this;
// Load the config file of the FuzeWorks core
try {
$cfg = $this->config->get('core');
} catch (ConfigException) {
throw new CoreException("Could not initiate Factory. Config 'core' could not be found.");
}
// Disable events if requested to do so
if (!$cfg->get('enable_events'))
Events::disable();
// Initialize all components
foreach ($this as $component)
{
if (!is_object($component))
continue;
if (method_exists($component, 'init'))
$component->init();
}
// Initialize all plugins
$this->plugins->loadHeadersFromPluginPaths();
// Log actions
Logger::logInfo("FuzeWorks initialized. Firing coreStartEvent.");
// And fire the coreStartEvent
try {
Events::fireEvent('coreStartEvent');
} catch (EventException $e) {
throw new CoreException("Could not initiate Factory. coreStartEvent threw exception: ".$e->getMessage());
}
return $this;
}
/**
* Get an instance of a componentClass.
*
* @param string|null $instanceName
* @return mixed
* @throws FactoryException
*/
public static function getInstance(string $instanceName = null): mixed
{
if (is_null($instanceName))
return self::$sharedFactoryInstance;
// Determine the instance name
$instanceName = strtolower($instanceName);
if (!isset(self::$sharedFactoryInstance->{$instanceName}))
throw new FactoryException("Could not get instance. Instance was not found.");
return self::$sharedFactoryInstance->{$instanceName};
}
/**
* Create a new instance of one of the loaded classes.
* It reloads the class. It does NOT clone it.
*
* @param string $className The name of the loaded class, WITHOUT the namespace
* @param string $namespace Optional namespace. Defaults to 'FuzeWorks\'
* @return Factory Instance
* @throws FactoryException
*/
public function newInstance(string $className, string $namespace = 'FuzeWorks\\'): self
{
// Determine the class to load
$instanceName = strtolower($className);
$className = $namespace.ucfirst($className);
if (!isset($this->{$instanceName}))
{
throw new FactoryException("Could not load new instance of '".$instanceName."'. Instance was not found.", 1);
}
elseif (!class_exists($className, false))
{
throw new FactoryException("Could not load new instance of '".$instanceName."'. Class not found.", 1);
}
// Remove the current instance
unset($this->{$instanceName});
// And set the new one
$this->{$instanceName} = new $className();
// Return itself
return $this;
}
/**
* Clone an instance of one of the loaded classes.
* It clones the class. It does NOT re-create it.
*
* If the $onlyReturn = true is provided, the cloned instance will only be returned, and not set to the factory.
*
* @param string $className The name of the loaded class, WITHOUT the namespace
* @param bool $onlyReturn
* @return mixed
* @throws FactoryException
*/
public static function cloneInstance(string $className, bool $onlyReturn = false): mixed
{
// Determine the class to load
$instanceName = strtolower($className);
if (!isset(self::$sharedFactoryInstance->{$instanceName}))
throw new FactoryException("Could not clone instance of '".$instanceName."'. Instance was not found.", 1);
if ($onlyReturn)
return clone self::$sharedFactoryInstance->{$instanceName};
// Clone the instance
self::$sharedFactoryInstance->{$instanceName} = clone self::$sharedFactoryInstance->{$instanceName};
// Return itself
return self::$sharedFactoryInstance->{$instanceName};
}
/**
* Set an instance of one of the loaded classes with your own $object.
* Replace the existing class with one of your own.
*
* @param string $objectName The name of the loaded class, WITHOUT the namespace
* @param mixed $object Object to replace the class with
* @return Factory Instance
*/
public function setInstance(string $objectName, mixed $object): self
{
// Determine the instance name
$instanceName = strtolower($objectName);
// Unset and set
unset($this->{$instanceName});
$this->{$instanceName} = $object;
// Return itself
return $this;
}
/**
* Remove an instance of one of the loaded classes.
*
* @param string $className The name of the loaded class, WITHOUT the namespace
* @return Factory Factory Instance
* @throws FactoryException
*/
public function removeInstance(string $className): self
{
// Determine the instance name
$instanceName = strtolower($className);
if (!isset($this->{$instanceName}))
{
throw new FactoryException("Could not remove instance of '".$instanceName."'. Instance was not found.", 1);
}
// Unset
unset($this->{$instanceName});
// Return itself
return $this;
}
/**
* Returns true if component is part of this Factory.
*
* @param $componentName
* @return bool
*/
public function instanceIsset($componentName): bool
{
return isset($this->{$componentName});
}
}
<?php
/**
* FuzeWorks Framework Core.
*
* The FuzeWorks PHP FrameWork
*
* Copyright (C) 2013-2019 TechFuze
*
* 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 TechFuze
* @copyright Copyright (c) 2013 - 2019, TechFuze. (http://techfuze.net)
* @license https://opensource.org/licenses/MIT MIT License
*
* @link http://techfuze.net/fuzeworks
* @since Version 0.0.1
*
* @version Version 1.3.0
*/
namespace FuzeWorks;
use FuzeWorks\Exception\ConfigException;
use FuzeWorks\Exception\CoreException;
use FuzeWorks\Exception\EventException;
use FuzeWorks\Exception\FactoryException;
/**
* Factory Class.
*
* 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:
* $factory = Factory::getInstance();
* $layout = $factory->layout;
*
* 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
* $factory->setInstance('Logger', $object); This allows for creative ways to do dependency injection, or keep classes
* separated.
*
* 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.
*
* The Factory class is also extendible. This allows classes that extend Factory to access all it's properties.
*
* @author TechFuze <contact@techfuze.net>
* @copyright Copyright (c) 2013 - 2019, TechFuze. (http://techfuze.net)
*/
class Factory
{
/**
* The Factory instance that is shared by default when calling Factory::getInstance();
*
* @var Factory|null Default shared instance
*/
private static ?Factory $sharedFactoryInstance = null;
/**
* Whether the Factory has been initialized or not
*
* @var bool $initialized
*/
private bool $initialized = false;
/**
* Config Object
* @var Config
*/
public Config $config;
/**
* Logger Object
* @var Logger
*/
public Logger $logger;
/**
* Events Object
* @var Events
*/
public Events $events;
/**
* Libraries Object
* @var Libraries
*/
public Libraries $libraries;
/**
* Helpers Object
* @var Helpers
*/
public Helpers $helpers;
/**
* Plugins Object
* @var Plugins
*/
public Plugins $plugins;
/**
* Storage Object
*
* @var Storage
*/
public Storage $storage;
/**
* Factory instance constructor. Should only really be called once
* @throws FactoryException
*/
public function __construct()
{
// If there is no sharedFactoryInstance, prepare it
if (is_null(self::$sharedFactoryInstance))
{
// @codeCoverageIgnoreStart
self::$sharedFactoryInstance = $this;
$this->config = new Config();
$this->logger = new Logger();
$this->events = new Events();
$this->libraries = new Libraries();
$this->helpers = new Helpers();
$this->plugins = new Plugins();
$this->storage = new Storage();
return;
}
// @codeCoverageIgnoreEnd
// Otherwise, copy the existing instances
$x = self::getInstance();
foreach ($x as $key => $value)
$this->{$key} = $value;
}
/**
* Finalizes the Factory and sends out a coreStartEvent
*
* @return Factory
* @throws CoreException
*/
public function initFactory(): Factory
{
// If already initialized, cancel
if ($this->initialized)
return $this;
// Load the config file of the FuzeWorks core
try {
$cfg = $this->config->get('core');
} catch (ConfigException) {
throw new CoreException("Could not initiate Factory. Config 'core' could not be found.");
}
// Disable events if requested to do so
if (!$cfg->get('enable_events'))
Events::disable();
// Initialize all components
foreach ($this as $component)
{
if (!is_object($component))
continue;
if (method_exists($component, 'init'))
$component->init();
}
// Initialize all plugins
$this->plugins->loadHeadersFromPluginPaths();
// Log actions
Logger::logInfo("FuzeWorks initialized. Firing coreStartEvent.");
// And fire the coreStartEvent
try {
Events::fireEvent('coreStartEvent');
} catch (EventException $e) {
throw new CoreException("Could not initiate Factory. coreStartEvent threw exception: ".$e->getMessage());
}
return $this;
}
/**
* Get an instance of a componentClass.
*
* @param string|null $instanceName
* @return mixed
* @throws FactoryException
*/
public static function getInstance(string $instanceName = null): mixed
{
if (is_null($instanceName))
return self::$sharedFactoryInstance;
// Determine the instance name
$instanceName = strtolower($instanceName);
if (!isset(self::$sharedFactoryInstance->{$instanceName}))
throw new FactoryException("Could not get instance. Instance was not found.");
return self::$sharedFactoryInstance->{$instanceName};
}
/**
* Create a new instance of one of the loaded classes.
* It reloads the class. It does NOT clone it.
*
* @param string $className The name of the loaded class, WITHOUT the namespace
* @param string $namespace Optional namespace. Defaults to 'FuzeWorks\'
* @return Factory Instance
* @throws FactoryException
*/
public function newInstance(string $className, string $namespace = 'FuzeWorks\\'): self
{
// Determine the class to load
$instanceName = strtolower($className);
$className = $namespace.ucfirst($className);
if (!isset($this->{$instanceName}))
{
throw new FactoryException("Could not load new instance of '".$instanceName."'. Instance was not found.", 1);
}
elseif (!class_exists($className, false))
{
throw new FactoryException("Could not load new instance of '".$instanceName."'. Class not found.", 1);
}
// Remove the current instance
unset($this->{$instanceName});
// And set the new one
$this->{$instanceName} = new $className();
// Return itself
return $this;
}
/**
* Clone an instance of one of the loaded classes.
* It clones the class. It does NOT re-create it.
*
* If the $onlyReturn = true is provided, the cloned instance will only be returned, and not set to the factory.
*
* @param string $className The name of the loaded class, WITHOUT the namespace
* @param bool $onlyReturn
* @return mixed
* @throws FactoryException
*/
public static function cloneInstance(string $className, bool $onlyReturn = false): mixed
{
// Determine the class to load
$instanceName = strtolower($className);
if (!isset(self::$sharedFactoryInstance->{$instanceName}))
throw new FactoryException("Could not clone instance of '".$instanceName."'. Instance was not found.", 1);
if ($onlyReturn)
return clone self::$sharedFactoryInstance->{$instanceName};
// Clone the instance
self::$sharedFactoryInstance->{$instanceName} = clone self::$sharedFactoryInstance->{$instanceName};
// Return itself
return self::$sharedFactoryInstance->{$instanceName};
}
/**
* Set an instance of one of the loaded classes with your own $object.
* Replace the existing class with one of your own.
*
* @param string $objectName The name of the loaded class, WITHOUT the namespace
* @param mixed $object Object to replace the class with
* @return Factory Instance
*/
public function setInstance(string $objectName, mixed $object): self
{
// Determine the instance name
$instanceName = strtolower($objectName);
// Unset and set
unset($this->{$instanceName});
$this->{$instanceName} = $object;
// Return itself
return $this;
}
/**
* Remove an instance of one of the loaded classes.
*
* @param string $className The name of the loaded class, WITHOUT the namespace
* @return Factory Factory Instance
* @throws FactoryException
*/
public function removeInstance(string $className): self
{
// Determine the instance name
$instanceName = strtolower($className);
if (!isset($this->{$instanceName}))
{
throw new FactoryException("Could not remove instance of '".$instanceName."'. Instance was not found.", 1);
}
// Unset
unset($this->{$instanceName});
// Return itself
return $this;
}
/**
* 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
/**
* FuzeWorks Framework Core.
*
* The FuzeWorks PHP FrameWork
*
* Copyright (C) 2013-2019 TechFuze
*
* 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 TechFuze
* @copyright Copyright (c) 2013 - 2019, TechFuze. (http://techfuze.net)
* @license https://opensource.org/licenses/MIT MIT License
*
* @link http://techfuze.net/fuzeworks
* @since Version 0.0.1
*
* @version Version 1.3.0
*/
use FuzeWorks\Factory;
use FuzeWorks\Exception\FactoryException;
/**
* Class FactoryTest.
*
* Will test the FuzeWorks Factory.
* @coversDefaultClass \FuzeWorks\Factory
*/
class factoryTest extends CoreTestAbstract
{
/**
* @covers ::getInstance
*/
public function testCanLoadFactory()
{
$this->assertInstanceOf('FuzeWorks\Factory', Factory::getInstance());
}
/**
* @covers ::getInstance
*/
public function testGetInstance()
{
// Add the mock
$mock = $this->getMockBuilder(MockFactory::class)->getMock();
Factory::getInstance()->setInstance('Mock', $mock);
// First test a global getInstance Factory
$this->assertInstanceOf('\FuzeWorks\Factory', Factory::getInstance());
// Second, test retrieving a component
$this->assertInstanceOf(get_class($mock), Factory::getInstance('Mock'));
}
/**
* @depends testGetInstance
* @covers ::getInstance
*/
public function testGetInstanceNotFound()
{
$this->expectException(FactoryException::class);
Factory::getInstance('NotFound');
}
/**
* @depends testCanLoadFactory
* @covers ::getInstance
*/
public function testLoadSameInstance()
{
$this->assertSame(Factory::getInstance(), Factory::getInstance());
}
/**
* @depends testCanLoadFactory
* @covers ::getInstance
* @covers ::cloneInstance
*/
public function testLoadDifferentInstance()
{
// Add the mock
$mock = $this->getMockBuilder(MockFactory::class)->getMock();
Factory::getInstance()->setInstance('Mock', $mock);
// First a situation where one is the shared instance and one is a cloned instance
$a = Factory::getInstance('Mock');
$b = Factory::cloneInstance('Mock');
$this->assertInstanceOf(get_class($mock), $a);
$this->assertInstanceOf(get_class($mock), $b);
$this->assertNotSame($a,$b);
// And a situation where both are cloned instances
$a = Factory::cloneInstance('Mock');
$b = Factory::cloneInstance('Mock');
$this->assertInstanceOf(get_class($mock), $a);
$this->assertInstanceOf(get_class($mock), $b);
$this->assertNotSame($a,$b);
}
/**
* @depends testCanLoadFactory
* @covers ::getInstance
* @covers ::setInstance
*/
public function testObjectsSameInstance()
{
// Create mock
$mock = $this->getMockBuilder(MockFactory::class)->setMethods(['mockListener'])->getMock();
// Test not set
$this->assertFalse(isset(Factory::getInstance()->mock));
// Same instance factories
/** @var Factory $factory1 */
/** @var Factory $factory2 */
$factory1 = Factory::getInstance()->setInstance('Mock', $mock);
$factory2 = Factory::getInstance()->setInstance('Mock', $mock);
// Return the mocks
$this->assertSame($factory1->mock, $factory2->mock);
// Different instance factories
$factory3 = Factory::getInstance()->setInstance('Mock', $mock);
$factory4 = Factory::getInstance()->setInstance('Mock', $mock);
// Return the mocks
$this->assertSame($factory3->mock, $factory4->mock);
}
/**
* @depends testObjectsSameInstance
* @covers ::getInstance
* @covers ::setInstance
* @covers ::cloneInstance
*/
public function testObjectsDifferentInstance()
{
// Create mock
$mock = $this->getMockBuilder(MockFactory::class)->getMock();
// Same instance factories
$factory1 = Factory::getInstance()->setInstance('Mock', $mock);
$factory2 = Factory::getInstance()->setInstance('Mock', $mock);
// Clone the instance in factory2
$factory2mock = $factory2->cloneInstance('Mock');
// Should be true, since both Factories use the same Mock instance
$this->assertSame($factory1->mock, $factory2mock);
// Different instance factories
$factory3 = Factory::getInstance()->setInstance('Mock', $mock);
$factory4 = Factory::getInstance()->setInstance('Mock', $mock);
// Should be same for now
$this->assertSame($factory3->mock, $factory4->mock);
// Clone the instance in factory4
$factory4mock = $factory4->cloneInstance('Mock', true);
// Should be false, since both Factories use a different Mock instance
$this->assertNotSame($factory3->mock, $factory4mock);
}
/**
* @depends testCanLoadFactory
* @covers ::cloneInstance
*/
public function testCloneInstanceWrongClassname()
{
// Get factory
$factory = new Factory;
// Attempt
$this->expectException(FactoryException::class);
$factory->cloneInstance('fake');
}
/**
* @depends testCanLoadFactory
* @covers ::getInstance
* @covers ::newInstance
*/
public function testNewFactoryInstance()
{
// Load the different factories
$factory = new Factory();
$factory2 = Factory::getInstance();
// Test if the objects are different factory instances
$this->assertNotSame($factory, $factory2);
// And test if all ClassInstances are the same
$this->assertSame($factory->config, $factory2->config);
$this->assertSame($factory->logger, $factory2->logger);
$this->assertSame($factory->events, $factory2->events);
$this->assertSame($factory->libraries, $factory2->libraries);
$this->assertSame($factory->helpers, $factory2->helpers);
// And test when changing one classInstance
$factory->newInstance('Helpers');
$this->assertNotSame($factory->helpers, $factory2->helpers);
}
/**
* @depends testNewFactoryInstance
* @covers ::newInstance
*/
public function testFactoryNewInstanceNotExist()
{
// Load the factory
$factory = new Factory;
// First, it does not exist
$this->expectException(FactoryException::class);
$factory->newInstance('fake');
}
/**
* @depends testNewFactoryInstance
* @covers ::newInstance
*/
public function testFactoryNewInstanceWrongNamespace()
{
// Load the factory
$factory = new Factory;
// Second, it just fails
$this->expectException(FactoryException::class);
$factory->newInstance('helpers', 'Test\\');
}
/**
* @depends testNewFactoryInstance
* @covers ::setInstance
* @covers ::removeInstance
*/
public function testRemoveInstance()
{
// Load the factory
$factory = new Factory;
// Create the object
$object = new MockObject;
// Add it to the factory
$factory->setInstance('test', $object);
// Test if it is there
$this->assertObjectHasAttribute('test', $factory);
$this->assertSame($object, $factory->test);
// Now remove it
$factory->removeInstance('test');
// Assert that it's gone
$this->assertObjectNotHasAttribute('test', $factory);
}
/**
* @depends testRemoveInstance
* @covers ::removeInstance
*/
public function testRemoveInstanceNotExist()
{
// Load the factory
$factory = new Factory;
// Test
$this->expectException(FactoryException::class);
$factory->removeInstance('fake');
}
/**
* @depends testCanLoadFactory
* @covers ::instanceIsset
* @covers ::setInstance
*/
public function testInstanceIsset()
{
// Load the factory
$factory = new Factory;
// Test if not set and add instance
$this->assertFalse($factory->instanceIsset('test'));
$factory->setInstance('test', 5);
// Test if isset and value
$this->assertTrue($factory->instanceIsset('test'));
$this->assertEquals(5, $factory->test);
}
public function tearDown(): void
{
parent::tearDown();
$factory = Factory::getInstance();
if (isset($factory->mock))
$factory->removeInstance('mock');
}
}
class MockFactory {
}
class MockObject {
<?php
/**
* FuzeWorks Framework Core.
*
* The FuzeWorks PHP FrameWork
*
* Copyright (C) 2013-2019 TechFuze
*
* 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 TechFuze
* @copyright Copyright (c) 2013 - 2019, TechFuze. (http://techfuze.net)
* @license https://opensource.org/licenses/MIT MIT License
*
* @link http://techfuze.net/fuzeworks
* @since Version 0.0.1
*
* @version Version 1.3.0
*/
use FuzeWorks\Factory;
use FuzeWorks\Exception\FactoryException;
/**
* Class FactoryTest.
*
* Will test the FuzeWorks Factory.
* @coversDefaultClass \FuzeWorks\Factory
*/
class factoryTest extends CoreTestAbstract
{
/**
* @covers ::getInstance
*/
public function testCanLoadFactory()
{
$this->assertInstanceOf('FuzeWorks\Factory', Factory::getInstance());
}
/**
* @covers ::getInstance
*/
public function testGetInstance()
{
// Add the mock
$mock = $this->getMockBuilder(MockFactory::class)->getMock();
Factory::getInstance()->setInstance('Mock', $mock);
// First test a global getInstance Factory
$this->assertInstanceOf('\FuzeWorks\Factory', Factory::getInstance());
// Second, test retrieving a component
$this->assertInstanceOf(get_class($mock), Factory::getInstance('Mock'));
}
/**
* @depends testGetInstance
* @covers ::getInstance
*/
public function testGetInstanceNotFound()
{
$this->expectException(FactoryException::class);
Factory::getInstance('NotFound');
}
/**
* @depends testCanLoadFactory
* @covers ::getInstance
*/
public function testLoadSameInstance()
{
$this->assertSame(Factory::getInstance(), Factory::getInstance());
}
/**
* @depends testCanLoadFactory
* @covers ::getInstance
* @covers ::cloneInstance
*/
public function testLoadDifferentInstance()
{
// Add the mock
$mock = $this->getMockBuilder(MockFactory::class)->getMock();
Factory::getInstance()->setInstance('Mock', $mock);
// First a situation where one is the shared instance and one is a cloned instance
$a = Factory::getInstance('Mock');
$b = Factory::cloneInstance('Mock');
$this->assertInstanceOf(get_class($mock), $a);
$this->assertInstanceOf(get_class($mock), $b);
$this->assertNotSame($a,$b);
// And a situation where both are cloned instances
$a = Factory::cloneInstance('Mock');
$b = Factory::cloneInstance('Mock');
$this->assertInstanceOf(get_class($mock), $a);
$this->assertInstanceOf(get_class($mock), $b);
$this->assertNotSame($a,$b);
}
/**
* @depends testCanLoadFactory
* @covers ::getInstance
* @covers ::setInstance
*/
public function testObjectsSameInstance()
{
// Create mock
$mock = $this->getMockBuilder(MockFactory::class)->setMethods(['mockListener'])->getMock();
// Test not set
$this->assertFalse(isset(Factory::getInstance()->mock));
// Same instance factories
/** @var Factory $factory1 */
/** @var Factory $factory2 */
$factory1 = Factory::getInstance()->setInstance('Mock', $mock);
$factory2 = Factory::getInstance()->setInstance('Mock', $mock);
// Return the mocks
$this->assertSame($factory1->mock, $factory2->mock);
// Different instance factories
$factory3 = Factory::getInstance()->setInstance('Mock', $mock);
$factory4 = Factory::getInstance()->setInstance('Mock', $mock);
// Return the mocks
$this->assertSame($factory3->mock, $factory4->mock);
}
/**
* @depends testObjectsSameInstance
* @covers ::getInstance
* @covers ::setInstance
* @covers ::cloneInstance
*/
public function testObjectsDifferentInstance()
{
// Create mock
$mock = $this->getMockBuilder(MockFactory::class)->getMock();
// Same instance factories
$factory1 = Factory::getInstance()->setInstance('Mock', $mock);
$factory2 = Factory::getInstance()->setInstance('Mock', $mock);
// Clone the instance in factory2
$factory2mock = $factory2->cloneInstance('Mock');
// Should be true, since both Factories use the same Mock instance
$this->assertSame($factory1->mock, $factory2mock);
// Different instance factories
$factory3 = Factory::getInstance()->setInstance('Mock', $mock);
$factory4 = Factory::getInstance()->setInstance('Mock', $mock);
// Should be same for now
$this->assertSame($factory3->mock, $factory4->mock);
// Clone the instance in factory4
$factory4mock = $factory4->cloneInstance('Mock', true);
// Should be false, since both Factories use a different Mock instance
$this->assertNotSame($factory3->mock, $factory4mock);
}
/**
* @depends testCanLoadFactory
* @covers ::cloneInstance
*/
public function testCloneInstanceWrongClassname()
{
// Get factory
$factory = new Factory;
// Attempt
$this->expectException(FactoryException::class);
$factory->cloneInstance('fake');
}
/**
* @depends testCanLoadFactory
* @covers ::getInstance
* @covers ::newInstance
*/
public function testNewFactoryInstance()
{
// Load the different factories
$factory = new Factory();
$factory2 = Factory::getInstance();
// Test if the objects are different factory instances
$this->assertNotSame($factory, $factory2);
// And test if all ClassInstances are the same
$this->assertSame($factory->config, $factory2->config);
$this->assertSame($factory->logger, $factory2->logger);
$this->assertSame($factory->events, $factory2->events);
$this->assertSame($factory->libraries, $factory2->libraries);
$this->assertSame($factory->helpers, $factory2->helpers);
$this->assertSame($factory->storage, $factory2->storage);
// And test when changing one classInstance
$factory->newInstance('Helpers');
$this->assertNotSame($factory->helpers, $factory2->helpers);
}
/**
* @depends testNewFactoryInstance
* @covers ::newInstance
*/
public function testFactoryNewInstanceNotExist()
{
// Load the factory
$factory = new Factory;
// First, it does not exist
$this->expectException(FactoryException::class);
$factory->newInstance('fake');
}
/**
* @depends testNewFactoryInstance
* @covers ::newInstance
*/
public function testFactoryNewInstanceWrongNamespace()
{
// Load the factory
$factory = new Factory;
// Second, it just fails
$this->expectException(FactoryException::class);
$factory->newInstance('helpers', 'Test\\');
}
/**
* @depends testNewFactoryInstance
* @covers ::setInstance
* @covers ::removeInstance
*/
public function testRemoveInstance()
{
// Load the factory
$factory = new Factory;
// Create the object
$object = new MockObject;
// Add it to the factory
$factory->setInstance('test', $object);
// Test if it is there
$this->assertObjectHasAttribute('test', $factory);
$this->assertSame($object, $factory->test);
// Now remove it
$factory->removeInstance('test');
// Assert that it's gone
$this->assertObjectNotHasAttribute('test', $factory);
}
/**
* @depends testRemoveInstance
* @covers ::removeInstance
*/
public function testRemoveInstanceNotExist()
{
// Load the factory
$factory = new Factory;
// Test
$this->expectException(FactoryException::class);
$factory->removeInstance('fake');
}
/**
* @depends testCanLoadFactory
* @covers ::instanceIsset
* @covers ::setInstance
*/
public function testInstanceIsset()
{
// Load the factory
$factory = new Factory;
// Test if not set and add instance
$this->assertFalse($factory->instanceIsset('test'));
$factory->setInstance('test', 5);
// Test if isset and value
$this->assertTrue($factory->instanceIsset('test'));
$this->assertEquals(5, $factory->test);
}
public function tearDown(): void
{
parent::tearDown();
$factory = Factory::getInstance();
if (isset($factory->mock))
$factory->removeInstance('mock');
}
}
class MockFactory {
}
class MockObject {
}

View File

@ -1,19 +1,23 @@
<?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">
<coverage processUncoveredFiles="false">
<include>
<directory suffix=".php">../</directory>
</include>
<exclude>
<directory suffix=".php">../vendor/</directory>
<directory suffix=".php">../test/</directory>
<directory suffix=".php">../src/Layout/</directory>
<directory suffix=".php">../src/Config/</directory>
</exclude>
</coverage>
<testsuites>
<testsuite name="Core Suite">
<directory>./</directory>
</testsuite>
</testsuites>
<?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">
<coverage processUncoveredFiles="false">
<include>
<directory suffix=".php">../</directory>
</include>
<exclude>
<directory suffix=".php">../vendor/</directory>
<directory suffix=".php">../test/</directory>
<directory suffix=".php">../src/Layout/</directory>
<directory suffix=".php">../src/Config/</directory>
</exclude>
</coverage>
<testsuites>
<testsuite name="core">
<directory>./core</directory>
<directory>./events</directory>
</testsuite>
<testsuite name="storage">
<directory>./storage</directory>
</testsuite>
</testsuites>
</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'));
}
}