├── .env.example ├── .gitignore ├── .scrutinizer.yml ├── Examples ├── example01.php ├── example02.php ├── example03.php ├── example04.php ├── example05.php ├── example06.php ├── example07.php └── example08.php ├── README.md ├── composer.json ├── docs ├── API-Reference │ ├── FuncoesCache │ │ └── README.md │ ├── OptionBuilder │ │ └── TimeBuilder.md │ ├── compression_encryption.md │ ├── optionBuilder.md │ ├── setConfig.md │ └── setDriver.md ├── api-reference.md ├── cacheer_php_logo.png ├── cacheer_php_logo__.png ├── example01.md ├── example02.md ├── example03.md ├── example04.md ├── example05.md ├── example06.md ├── example07.md ├── example08.md ├── example09.md └── guia2.0.0.md ├── phpunit.xml ├── src ├── Boot │ └── Configs.php ├── CacheStore │ ├── ArrayCacheStore.php │ ├── CacheManager │ │ ├── FileCacheManager.php │ │ ├── OptionBuilders │ │ │ └── FileOptionBuilder.php │ │ └── RedisCacheManager.php │ ├── DatabaseCacheStore.php │ ├── FileCacheStore.php │ └── RedisCacheStore.php ├── Cacheer.php ├── Config │ ├── .gitignore │ └── Option │ │ ├── .gitignore │ │ └── Builder │ │ └── OptionBuilder.php ├── Core │ ├── Connect.php │ ├── ConnectionFactory.php │ └── MigrationManager.php ├── Exceptions │ ├── BaseException.php │ ├── CacheDatabaseException.php │ ├── CacheFileException.php │ ├── CacheRedisException.php │ └── ConnectionException.php ├── Helpers │ ├── CacheConfig.php │ ├── CacheDatabaseHelper.php │ ├── CacheFileHelper.php │ ├── CacheRedisHelper.php │ ├── CacheerHelper.php │ ├── EnvHelper.php │ └── SqliteHelper.php ├── Interface │ └── CacheerInterface.php ├── Repositories │ └── CacheDatabaseRepository.php ├── Support │ └── TimeBuilder.php └── Utils │ ├── CacheDataFormatter.php │ ├── CacheDriver.php │ └── CacheLogger.php └── tests ├── Feature └── OptionBuildTest.php └── Unit ├── ArrayCacheStoreTest.php ├── DatabaseCacheStoreTest.php ├── FileCacheStoreTest.php ├── RedisCacheStoreTest.php └── SecurityFeatureTest.php /.env.example: -------------------------------------------------------------------------------- 1 | DB_CONNECTION=sqlite 2 | # DB_HOST=localhost 3 | # DB_PORT=3306 4 | # DB_DATABASE=cacheer_db 5 | # DB_USERNAME=root 6 | # DB_PASSWORD= 7 | 8 | REDIS_CLIENT= 9 | REDIS_HOST=localhost 10 | REDIS_PASSWORD= 11 | REDIS_PORT=6379 12 | REDIS_NAMESPACE= -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | 3 | .phpunit.result.cache 4 | .env 5 | /composer.lock 6 | /database 7 | /CacheerPHP 8 | cacheer.log 9 | /tests/Unit/cache 10 | /Examples/InternalTests/ -------------------------------------------------------------------------------- /.scrutinizer.yml: -------------------------------------------------------------------------------- 1 | build: 2 | environment: 3 | php: 4 | version: 8.2 5 | dependencies: 6 | before: 7 | - sudo apt-get update 8 | - sudo apt-get install -y software-properties-common 9 | - sudo add-apt-repository ppa:ondrej/php -y 10 | - sudo DEBIAN_FRONTEND=noninteractive apt-get install -y openssl libssl-dev 11 | - openssl version 12 | - export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH 13 | - export OPENSSL_CFLAGS="-I/usr/local/include" 14 | - export OPENSSL_LIBS="-L/usr/local/lib -lssl -lcrypto" 15 | tests: 16 | override: 17 | - echo "Skipping tests" 18 | tools: 19 | php_analyzer: 20 | enabled: true 21 | php_cs_fixer: 22 | enabled: true 23 | -------------------------------------------------------------------------------- /Examples/example01.php: -------------------------------------------------------------------------------- 1 | __DIR__ . "/cache", 9 | ]; 10 | 11 | $Cacheer = new Cacheer($options); 12 | 13 | // Dados a serem armazenados no cache 14 | $cacheKey = 'user_profile_1234'; 15 | $userProfile = [ 16 | 'id' => 123, 17 | 'name' => 'John Doe', 18 | 'email' => 'john.doe@example.com', 19 | ]; 20 | 21 | // Armazenando dados no cache 22 | $Cacheer->putCache($cacheKey, $userProfile); 23 | 24 | // Recuperando dados do cache 25 | $cachedProfile = $Cacheer->getCache($cacheKey); 26 | 27 | if ($Cacheer->isSuccess()) { 28 | echo "Cache Found: "; 29 | print_r($cachedProfile); 30 | } else { 31 | echo $Cacheer->getMessage(); 32 | } 33 | 34 | 35 | -------------------------------------------------------------------------------- /Examples/example02.php: -------------------------------------------------------------------------------- 1 | __DIR__ . "/cache", 8 | "expirationTime" => "2 hour" 9 | ]; 10 | 11 | $Cacheer = new Cacheer($options); 12 | 13 | // Dados a serem armazenados no cache 14 | $cacheKey = 'daily_stats'; 15 | $dailyStats = [ 16 | 'visits' => 1500, 17 | 'signups' => 35, 18 | 'revenue' => 500.75, 19 | ]; 20 | 21 | // Armazenando dados no cache 22 | $Cacheer->putCache($cacheKey, $dailyStats); 23 | 24 | // Recuperando dados do cache por 2 horas 25 | $cachedStats = $Cacheer->getCache($cacheKey); 26 | 27 | if ($Cacheer->isSuccess()) { 28 | echo "Cache Found: "; 29 | print_r($cachedStats); 30 | } else { 31 | echo $Cacheer->getMessage(); 32 | } 33 | -------------------------------------------------------------------------------- /Examples/example03.php: -------------------------------------------------------------------------------- 1 | __DIR__ . "/cache", 9 | ]; 10 | 11 | $Cacheer = new Cacheer($options); 12 | 13 | // Chave do cache a ser limpo 14 | $cacheKey = 'user_profile_123'; 15 | 16 | // Limpando um item específico do cache 17 | 18 | $Cacheer->clearCache($cacheKey); 19 | 20 | if ($Cacheer->isSuccess()) { 21 | echo $Cacheer->getMessage(); 22 | } else { 23 | echo $Cacheer->getMessage(); 24 | } 25 | 26 | $Cacheer->flushCache(); 27 | 28 | if ($Cacheer->isSuccess()) { 29 | echo $Cacheer->getMessage(); 30 | } else { 31 | echo $Cacheer->getMessage(); 32 | } 33 | -------------------------------------------------------------------------------- /Examples/example04.php: -------------------------------------------------------------------------------- 1 | __DIR__ . "/cache", 8 | ]; 9 | 10 | $Cacheer = new Cacheer($options); 11 | 12 | // Dados a serem armazenados no cache com namespace 13 | $namespace = 'session_data_01'; 14 | $cacheKey = 'session_456'; 15 | $sessionData = [ 16 | 'user_id' => 456, 17 | 'login_time' => time(), 18 | ]; 19 | 20 | // Armazenando dados no cache com namespace 21 | $Cacheer->putCache($cacheKey, $sessionData, $namespace); 22 | 23 | // Recuperando dados do cache 24 | $cachedSessionData = $Cacheer->getCache($cacheKey, $namespace); 25 | 26 | if ($Cacheer->isSuccess()) { 27 | echo "Cache Found: "; 28 | print_r($cachedSessionData); 29 | } else { 30 | echo $Cacheer->getMessage(); 31 | } 32 | -------------------------------------------------------------------------------- /Examples/example05.php: -------------------------------------------------------------------------------- 1 | __DIR__ . "/cache", 9 | ]; 10 | 11 | $Cacheer = new Cacheer($options); 12 | 13 | // URL da API e chave de cache 14 | $apiUrl = 'https://jsonplaceholder.typicode.com/posts'; 15 | $cacheKey = 'api_response_' . md5($apiUrl); 16 | 17 | // Verificando se a resposta da API já está no cache 18 | $cachedResponse = $Cacheer->getCache($cacheKey); 19 | 20 | if ($Cacheer->isSuccess()) { 21 | // Use a resposta do cache 22 | $response = $cachedResponse; 23 | } else { 24 | // Faça a chamada à API e armazene a resposta no cache 25 | $response = file_get_contents($apiUrl); 26 | $Cacheer->putCache($cacheKey, $response); 27 | } 28 | 29 | // Usando a resposta da API (do cache ou da chamada) 30 | $data = json_decode($response, true); 31 | print_r($data); 32 | -------------------------------------------------------------------------------- /Examples/example06.php: -------------------------------------------------------------------------------- 1 | setDriver()->useRedisDriver(); 9 | 10 | // Dados a serem armazenados no cache 11 | $cacheKey = 'user_profile_1234'; 12 | $userProfile = [ 13 | 'id' => 1, 14 | 'name' => 'Sílvio Silva', 15 | 'email' => 'gasparsilvio7@gmail.com', 16 | 'role' => 'Developer' 17 | ]; 18 | $cacheNamespace = 'userData'; 19 | 20 | // Armazenando dados no cache 21 | //$Cacheer->putCache($cacheKey, $userProfile, $cacheNamespace); 22 | 23 | $Cacheer->has($cacheKey, $cacheNamespace); 24 | 25 | // Verificando se o cache existe e recuperando os dados 26 | if ($Cacheer->isSuccess()) { 27 | $cachedProfile = $Cacheer->getCache($cacheKey, $cacheNamespace); 28 | echo "Perfil de Usuário Encontrado:\n"; 29 | print_r($cachedProfile); 30 | } else { 31 | echo "Cache não encontrado: " . $Cacheer->getMessage(); 32 | } 33 | 34 | -------------------------------------------------------------------------------- /Examples/example07.php: -------------------------------------------------------------------------------- 1 | setDriver()->useRedisDriver(); 9 | 10 | // Dados a serem armazenados no cache 11 | $cacheKey = 'user_profile_1'; 12 | $userProfile = [ 13 | 'id' => 1, 14 | 'name' => 'Sílvio Silva', 15 | 'email' => 'gasparsilvio7@gmail.com', 16 | ]; 17 | 18 | $userProfile02 = [ 19 | 'casaNº' => 2130, 20 | 'telefone' => "(999)999-9999" 21 | ]; 22 | 23 | 24 | // Armazenando dados no cache 25 | $Cacheer->putCache($cacheKey, $userProfile); 26 | 27 | // Recuperando dados do cache 28 | if($Cacheer->isSuccess()){ 29 | echo "Cache Found: "; 30 | print_r($Cacheer->getCache($cacheKey)); 31 | } else { 32 | echo $Cacheer->getMessage(); 33 | } 34 | 35 | 36 | // Mesclando os dados 37 | $Cacheer->appendCache($cacheKey, $userProfile02); 38 | 39 | if($Cacheer->isSuccess()){ 40 | echo $Cacheer->getMessage() . PHP_EOL; 41 | print_r($Cacheer->getCache($cacheKey)); 42 | } else { 43 | echo $Cacheer->getMessage(); 44 | } 45 | 46 | -------------------------------------------------------------------------------- /Examples/example08.php: -------------------------------------------------------------------------------- 1 | setDriver()->useRedisDriver(); 9 | 10 | // Dados a serem armazenados no cache 11 | $cacheKey = 'user_profile_01'; 12 | $userProfile = [ 13 | 'id' => 1, 14 | 'name' => 'Sílvio Silva', 15 | 'email' => 'gasparsilvio7@gmail.com', 16 | ]; 17 | 18 | // Armazenando dados no cache 19 | $Cacheer->putCache($cacheKey, $userProfile, ttl: 300); 20 | 21 | // Recuperando dados do cache 22 | if($Cacheer->isSuccess()){ 23 | echo "Cache Found: "; 24 | print_r($Cacheer->getCache($cacheKey)); 25 | } else { 26 | echo $Cacheer->getMessage(); 27 | } 28 | 29 | // Renovando os dados do cache 30 | $Cacheer->renewCache($cacheKey, 3600); 31 | 32 | if($Cacheer->isSuccess()){ 33 | echo $Cacheer->getMessage() . PHP_EOL; 34 | } else { 35 | echo $Cacheer->getMessage() . PHP_EOL; 36 | 37 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CacheerPHP 2 | 3 |

4 | 5 | [![Maintainer](https://img.shields.io/badge/maintainer-@silviooosilva-blue.svg?style=for-the-badge&color=blue)](https://github.com/silviooosilva) 6 | ![Packagist Dependency Version](https://img.shields.io/packagist/dependency-v/silviooosilva/cacheer-php/PHP?style=for-the-badge&color=blue) 7 | [![Latest Version](https://img.shields.io/github/release/silviooosilva/CacheerPHP.svg?style=for-the-badge&color=blue)](https://github.com/silviooosilva/CacheerPHP/releases) 8 | [![Quality Score](https://img.shields.io/scrutinizer/g/silviooosilva/CacheerPHP.svg?style=for-the-badge&color=blue)](https://scrutinizer-ci.com/g/silviooosilva/CacheerPHP) 9 | ![Packagist Downloads](https://img.shields.io/packagist/dt/silviooosilva/cacheer-php?style=for-the-badge&color=blue) 10 | 11 | CacheerPHP is a minimalist package for PHP caching. Now, in version 3.0.0, you get even more flexibility, support for multiple backends (files, database and Redis), as well as new features for monitoring, compression and encryption and a more robust API design. 12 | 13 | --- 14 | 15 | ## Features 16 | 17 | - **Cache Storage and Retrieval:** Support for file storage, databases (MySQL, PostgreSQL, SQLite) and Redis. 18 | - **Customizable expiration:** Set the TTL (Time To Live) of the cache precisely. 19 | - **Cache cleaning and flushing:** Support for manual and automatic cleaning (via `flushAfter`). 20 | - **Namespace support:** Organize your cache entries by category. 21 | - **Customized Data Output:** Options to return data in `JSON`, `Array`, `String` or `Object`. 22 | - **Compression and Encryption:** Reduce storage space and increase the security of cached data. 23 | - **Cache Statistics and Monitoring:** Track hit and miss statistics and average read/write times (Coming Soon). 24 | - **Advanced Logging:** Detailed monitoring of the operation of the caching system. 25 | 26 | --- 27 | 28 | ## Installation 29 | 30 | CacheerPHP 3.0.0 is available via Composer. Add the following line to your **composer.json** file: 31 | 32 | ```sh 33 | "silviooosilva/cacheer-php": "^3.0" 34 | ``` 35 | 36 | Or run the command: 37 | 38 | ```sh 39 | composer require silviooosilva/cacheer-php 40 | ``` 41 | 42 | ## IMPORTANT WARNING!!! 43 | 44 | Don't forget to set your environment variables in the .env.example file. 45 | 46 | Remember that they must be set in the .env file, not in .env.example. 47 | To do this, do the following on your command line: 48 | 49 | ```sh 50 | cp .env.example .env 51 | ``` 52 | 53 | ## Documentation 54 | 55 | 1. [Storing and retrieving cached data](docs/example01.md) 56 | 2. [Customizable cache expiration](docs/example02.md) 57 | 3. [Cache flushing and cleaning](docs/example03.md) 58 | 4. [Namespace support for cache organization](docs/example04.md) 59 | 5. [Automatic cleaning of the `flushAfter` cache directory](docs/example09.md) 60 | 6. [API Response Cache](docs/example05.md) 61 | 7. [Custom Data Output (`JSON`)](docs/example06.md) 62 | 8. [Custom Data Output (`Array`)](docs/example07.md) 63 | 9. [Custom Data Output (`String`)](docs/example08.md) 64 | 10. [Upgrade Guide for Version 2.0.0](docs/guide2.0.0.md) 65 | 11. [API Reference](docs/api-reference.md) 66 | 12. [API Reference - Cache Functions](docs/API-Reference/FuncoesCache/README.md) 67 | 68 | Several practical examples are also available in the **Examples** folder in the root of the project. 69 | 70 | ## Compatibility 71 | 72 | - PHP: 8.0 or higher. 73 | - Database Drivers: MySQL, PostgreSQL, SQLite. 74 | - Redis 75 | 76 | ### Tests 77 | 78 | To run the tests, go to the root of the project and type the command: 79 | 80 | ```sh 81 | vendor/bin/phpunit 82 | ``` 83 | 84 |

Support:

85 |

silviooosilva



86 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "silviooosilva/cacheer-php", 3 | "description": "CacheerPHP is a minimalist package for caching in PHP, offering a simple interface for storing and retrieving cached data using multiple backends.", 4 | "keywords": [ 5 | "cache", 6 | "optimizer", 7 | "performance", 8 | "PHP", 9 | "caching", 10 | "cache-manager", 11 | "Silviooosilva", 12 | "speed", 13 | "optimization", 14 | "file-cache", 15 | "database", 16 | "database-cache", 17 | "mysql", 18 | "sqlite", 19 | "pgsql", 20 | "redis", 21 | "predis", 22 | "nosql" 23 | ], 24 | "homepage": "https://github.com/silviooosilva", 25 | "type": "library", 26 | "license": "MIT", 27 | "version": "v3.6.1", 28 | "autoload": { 29 | "files": [ 30 | "src/Boot/Configs.php" 31 | ], 32 | "psr-4": { 33 | "Silviooosilva\\CacheerPhp\\": "src/" 34 | } 35 | }, 36 | "scripts": { 37 | "post-install-cmd": [ 38 | "@php -r \"require 'src/Helpers/EnvHelper.php'; \\Silviooosilva\\CacheerPhp\\Helpers\\EnvHelper::copyEnv();\"" 39 | ], 40 | "post-update-cmd": [ 41 | "@php -r \"require 'src/Helpers/EnvHelper.php'; \\Silviooosilva\\CacheerPhp\\Helpers\\EnvHelper::copyEnv();\"" 42 | ] 43 | }, 44 | "authors": [ 45 | { 46 | "name": "Sílvio Silva", 47 | "email": "gasparsilvio7@gmail.com", 48 | "role": "Developer" 49 | } 50 | ], 51 | "require": { 52 | "php": ">=8.0", 53 | "vlucas/phpdotenv": "^5.6", 54 | "predis/predis": "^2.3" 55 | }, 56 | "require-dev": { 57 | "phpunit/phpunit": "^11.2" 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /docs/API-Reference/FuncoesCache/README.md: -------------------------------------------------------------------------------- 1 | ## Cache functions - CacheerPHP 2 | 3 | CacheerPHP offers a robust set of functions for managing caching in your PHP application. Below is the detailed documentation for each method available: 4 | 5 | --- 6 | 7 | ## Basic Cache Operations 8 | 9 | ### `getCache()` - Retrieves data from the cache 10 | 11 | ```php 12 | 13 | /** 14 | * Gets an item from the cache. If the item doesn't exist or is expired, returns null. 15 | * @param string $cacheKey Unique item key 16 | * @param string $namespace Namespace for organization 17 | * @param string|int $ttl Lifetime in seconds (default: 3600) 18 | * @return CacheDataFormatter|mixed Returns data in special format or raw value 19 | */ 20 | $Cacheer->getCache(string $cacheKey, string $namespace, string|int $ttl = 3600); 21 | ``` 22 | 23 | ### `putCache()` - Stores data in the cache 24 | 25 | ```php 26 | 27 | /** 28 | * Stores an item in the cache with a specific TTL. 29 | * @param string $cacheKey Unique item key 30 | * @param mixed $cacheData Data to be stored (serializable) 31 | * @param string|int $ttl Lifetime in seconds (default: 3600) 32 | * @return void 33 | */ 34 | $Cacheer->putCache(string $cacheKey, mixed $cacheData, string|int $ttl = 3600); 35 | ``` 36 | 37 | ### `putMany()` - Mass operations 38 | 39 | ```php 40 | 41 | /** 42 | * Stores multiple cache items at once with shared TTL. 43 | * @param array $items Associative array [key => value] 44 | * @param string $namespace Common namespace for all items 45 | * @param int $batchSize Number of operations per time 46 | * @return void 47 | */ 48 | $Cacheer->putMany(array $items, string $namespace, int $batchSize = 100); 49 | ``` 50 | 51 | ### `appendCache()` - Adding to existing cache 52 | 53 | ```php 54 | /** 55 | * Adds data to an existing cache item (useful for arrays or strings). 56 | * @param string $cacheKey Existing item key 57 | * @param mixed $cacheData Data to be added 58 | * @param string $namespace Item namespace 59 | * @return void 60 | */ 61 | $Cacheer->appendCache(string $cacheKey, mixed $cacheData, string $namespace); 62 | ``` 63 | 64 | ### `has()` - Checks if a key exists in the cache and is still valid (has not expired). 65 | 66 | ```php 67 | /** 68 | * Checks whether a particular cache key exists, and whether it is still valid. 69 | * @param string $cacheKey 70 | * @param string $namespace 71 | * @return void 72 | */ 73 | $Cacheer->has(string $cacheKey, string $namespace); 74 | ``` 75 | 76 | ### `renewCache()` - Renew cache TTL 77 | 78 | 79 | ```php 80 | /** 81 | * Updates the lifetime of an existing item without modifying its data. 82 | * @param string $cacheKey Item key 83 | * @param string|int $ttl New TTL in seconds (default: 3600) 84 | * @param string $namespace Item namespace 85 | * @return mixed Returns the item data or false if it fails 86 | */ 87 | $Cacheer->renewCache(string $cacheKey, string|int $ttl = 3600, string $namespace); 88 | ``` 89 | 90 | ### `increment()` - Numeric increment 91 | 92 | ```php 93 | /** 94 | * Increments a numeric value in the cache. 95 | * @param string $cacheKey Item key 96 | * @param int $amount Value to increment (default: 1) 97 | * @param string $namespace Item namespace 98 | * @return bool True if successful 99 | */ 100 | $Cacheer->increment(string $cacheKey, int $amount, string $namespace); 101 | ``` 102 | 103 | ### `decrement()` - Numerical decrement 104 | 105 | ```php 106 | /** 107 | * Decrements a numeric value in the cache. 108 | * @param string $cacheKey Item key 109 | * @param int $amount Value to decrement (default: 1) 110 | * @param string $namespace Item namespace 111 | * @return bool True if successful 112 | */ 113 | $Cacheer->decrement(string $cacheKey, int $amount, string $namespace); 114 | ``` 115 | 116 | ### `forever()` - Permanent storage 117 | 118 | ```php 119 | /** 120 | * Stores an item in the cache with no expiration time. 121 | * @param string $cacheKey Unique key 122 | * @param mixed $cacheData Data to be stored 123 | * @return void 124 | */ 125 | $Cacheer->forever(string $cacheKey, mixed $cacheData); 126 | ``` 127 | 128 | ### `remember()` - Standard “Get or Calculate” 129 | 130 | ```php 131 | /** 132 | * Gets the item from the cache or executes the closure and stores the result. 133 | * @param string $cacheKey Item key 134 | * @param int|string $ttl Lifetime in seconds 135 | * @param Closure $callback Function that returns the data if the cache does not exist 136 | * @return mixed 137 | */ 138 | $Cacheer->remember(string $cacheKey, int|string $ttl, Closure $callback); 139 | ``` 140 | 141 | ### `rememberForever()` - Standard “Get or Calculate” forever 142 | 143 | ```php 144 | /** 145 | * Similar to remember, but stores the result without expiration. 146 | * @param string $cacheKey Item key 147 | * @param int|string $ttl Lifetime in seconds 148 | * @param Closure $callback Function that returns the data if the cache does not exist 149 | * @return mixed 150 | */ 151 | $Cacheer->rememberForever(string $cacheKey, int|string $ttl, Closure $callback); 152 | ``` 153 | 154 | ### `getAndForget()` - Retrieve and remove 155 | 156 | 157 | ```php 158 | /** 159 | * Gets an item from the cache and immediately removes it. 160 | * @param string $cacheKey Item key 161 | * @param string $namespace Item namespace 162 | * @return mixed Item data or null if it doesn't exist 163 | */ 164 | $Cacheer->getAndForget(string $cacheKey, string $namespace); 165 | ``` 166 | 167 | ### `add()` - Conditional addition 168 | 169 | ```php 170 | /** 171 | * Adds an item to the cache only if the key does not exist. 172 | * @param string $cacheKey Item key 173 | * @param mixed $cacheData Data to be stored 174 | * @param string $namespace Item namespace 175 | * @param int|string $ttl Lifetime in seconds 176 | * @return bool True if the item was added, false if it already existed 177 | */ 178 | $Cacheer->add(string $cacheKey, mixed $cacheData, string $namespace, int|string $ttl); 179 | ``` 180 | 181 | ### `clearCache()` - Selective cleaning 182 | 183 | 184 | ```php 185 | /** 186 | * Removes a specific item from the cache. 187 | * @param string $cacheKey Item key 188 | * @param string $namespace Item namespace 189 | * @return void 190 | */ 191 | $Cacheer->clearCache(string $cacheKey, string $namespace); 192 | ``` 193 | 194 | ### `flushCache()` - Total cleaning 195 | 196 | ```php 197 | /** 198 | * Removes all items from the cache (complete cleaning). 199 | * @return void 200 | */ 201 | $Cacheer->flushCache(); 202 | ``` 203 | ### `useCompression()` - Enable or disable compression 204 | 205 | ```php 206 | $Cacheer->useCompression(); 207 | $Cacheer->useCompression(false); 208 | ``` 209 | 210 | ### `useEncryption()` - Enable AES encryption 211 | 212 | ```php 213 | $Cacheer->useEncryption('secret-key'); 214 | ``` 215 | --- 216 | 217 | Each of the functions below allows you to interact with the cache in different ways. Functions that “return void” actually set the status of the operation internally, which can be checked via: 218 | 219 | ```php 220 | $Cacheer->isSuccess(); // Returns true ou false 221 | $Cacheer->getMessage(); // Returns a message 222 | ``` -------------------------------------------------------------------------------- /docs/API-Reference/OptionBuilder/TimeBuilder.md: -------------------------------------------------------------------------------- 1 | ## API Reference 2 | 3 | TimeBuilder provides a fluid and chainable way of defining time periods in a more intuitive way and without typing errors. 4 | 5 | It allows expirationTime and flushAfter values to be passed directly as integers or defined using chained methods such as day(1), week(2), etc. 6 | 7 | #### Simple use 8 | 9 | ```php 10 | OptionBuilder::forFile() 11 | ->expirationTime('1 day') 12 | ->build(); 13 | ``` 14 | Or use TimeBuilder's chained approach: 15 | 16 | ```php 17 | OptionBuilder::forFile() 18 | ->expirationTime()->day(1) 19 | ->build(); 20 | ``` 21 | 22 | #### Available methods 23 | 24 | Each method allows you to set a specific time interval. 25 | 26 | | Method | Description | Example | 27 | |--------------|--------------------------------|--------------| 28 | | `second($value)` | Define o tempo em segundos | `->second(30)` | 29 | | `minute($value)` | Define o tempo em minutos | `->minute(15)` | 30 | | `hour($value)` | Define o tempo em horas | `->hour(3)` | 31 | | `day($value)` | Define o tempo em dias | `->day(7)` | 32 | | `week($value)` | Define o tempo em semanas | `->week(2)` | 33 | | `month($value)` | Define o tempo em meses | `->month(1)` | 34 | | `year($value)` | Define o tempo em anos | `->year(1)` | 35 | 36 | #### Full Example 37 | 38 | ```php 39 | $Options = OptionBuilder::forFile() 40 | ->dir(__DIR__ . '/cache') 41 | ->expirationTime()->week(1) 42 | ->flushAfter()->minute(30) 43 | ->build(); 44 | 45 | var_dump($Options); 46 | ``` 47 | 48 | **Expected Output** 49 | 50 | ```php 51 | [ 52 | "cacheDir" => "/path/to/cache", 53 | "expirationTime" => "1 week", 54 | "flushAfter" => "30 minutes" 55 | ] 56 | ``` 57 | 58 | Now you can set expiration and flush times without having to remember exact strings. 🚀 -------------------------------------------------------------------------------- /docs/API-Reference/compression_encryption.md: -------------------------------------------------------------------------------- 1 | ## API Reference - Compression & Encryption 2 | 3 | #### `useCompression()` 4 | Enables or disables data compression before storage. When enabled, data is serialized and compressed using `gzcompress`. 5 | 6 | ```php 7 | $Cacheer->useCompression(); // enable 8 | $Cacheer->useCompression(false); // disable 9 | ``` 10 | 11 | #### `useEncryption()` 12 | Activates encryption using AES-256-CBC. Provide a secret key to encrypt and decrypt cached data. 13 | 14 | ```php 15 | $Cacheer->useEncryption('your-secret-key'); 16 | ``` 17 | 18 | You can combine both features for smaller and secure payloads: 19 | 20 | ```php 21 | $Cacheer->useCompression()->useEncryption('your-secret-key'); 22 | ``` 23 | -------------------------------------------------------------------------------- /docs/API-Reference/optionBuilder.md: -------------------------------------------------------------------------------- 1 | ## API Reference 2 | 3 | The **OptionBuilder** allows you to define different parameters for configuring CacheerPHP, giving it more security, robustness and speed of execution, as well as excluding possible errors, such as typos, for example. 4 | 5 | Also check out the **TimeBuilder**: [TimeBuilder - Introduction](./OptionBuilder/TimeBuilder.md) 6 | 7 | Currently, it is only compatible with **FileCacheStore**, as this is the driver that requires a set of configurations in advance for it to work. 8 | 9 | Here are some examples: 10 | 11 | [FileCacheStore - Example01](../example01.md) 12 | 13 | [FileCacheStore - Example02](../example02.md) 14 | 15 | You've seen that parameters are very susceptible to typing errors, right? 16 | The **OptionBuilder** arises from the need to eliminate these possible errors. 17 | 18 | #### `OptionBuilder()` 19 | 20 | The **OptionBuilder** has specific methods for configuring each type of cache driver supported. 21 | Each one initializes the configuration for a given driver and returns an instance of the corresponding builder. 22 | 23 | `forFile()` 24 | 25 | ```php 26 | dir(__DIR__ . "/cache") 48 | ->expirationTime("2 hours") 49 | ->flushAfter("1 day") 50 | ->build(); 51 | 52 | $Cacheer = new Cacheer($Options); 53 | $Cacheer->setDriver()->useFileDriver(); //File Driver 54 | ``` 55 | 56 | #### Coming soon 57 | 58 | ```php 59 | OptionBuilder::forRedis(); 60 | OptionBuilder::forDatabase(); 61 | ``` 62 | 63 | The **OptionBuilder** simplifies the configuration of the **CacheerPHP** by eliminating typing errors and making the process more intuitive. 64 | Now all you have to do is choose the method corresponding to the desired driver and set the necessary parameters to ensure efficient and optimized caching. 🚀 -------------------------------------------------------------------------------- /docs/API-Reference/setConfig.md: -------------------------------------------------------------------------------- 1 | ## API Reference 2 | 3 | Always define the driver to be used in the first instance, and only then define the settings using **setConfig()**. 4 | 5 | Check it out below: 6 | [API Reference - setDriver()](setDriver.md) 7 | 8 | #### `setConfig()` 9 | 10 | ```php 11 | setConfig(); 17 | ``` 18 | 19 | Configures the database for storing the cache. 20 | ```php 21 | setConfig()->setDatabaseConnection(string $driver) 27 | ``` 28 | 29 | - Parameters: 30 | 31 | ```php 32 | $driver: Database driver. Possible values: 'mysql', 'pgsql', 'sqlite'. 33 | ``` 34 | 35 | **Example:** 36 | 37 | ```php 38 | setConfig()->setDatabaseConnection('mysql'); 44 | ``` 45 | 46 | There is also an alternative, which is to define the driver in the .env file, through the DB_CONNECTION variable, passing the same values. 47 | 48 | Timezone 49 | --- 50 | 51 | ```php 52 | setConfig()->setTimeZone(string $timezone); 58 | ``` 59 | 60 | Sets the time zone for cache operations. 61 | - Parameters 62 | 63 | ```php 64 | $timezone: Time zone in PHP format (example: 'UTC', 'Africa/Luanda'). 65 | ``` 66 | 67 | **Example:** 68 | 69 | ```php 70 | $Cacheer->setConfig()->setTimeZone('UTC'); 71 | ``` 72 | 73 | Check out the timezones supported by PHP here: 74 | https://www.php.net/manual/en/timezones.php 75 | 76 | Logger 77 | --- 78 | 79 | ```php 80 | $Cacheer->setConfig()->setLoggerPath(string $path); 81 | ``` 82 | Defines the path where the logs will be stored. 83 | 84 | - Parameters 85 | 86 | ```php 87 | $path: Caminho completo para o arquivo de logs. 88 | ``` 89 | 90 | **Example:** 91 | 92 | ```php 93 | $Cacheer->setConfig()->setLoggerPath('/path/to/logs/CacheerPHP.log'); 94 | ``` -------------------------------------------------------------------------------- /docs/API-Reference/setDriver.md: -------------------------------------------------------------------------------- 1 | ## API Reference 2 | 3 | #### 2. **Drivers** 4 | 5 | ```php 6 | setDriver(); 12 | ``` 13 | 14 | Defines the cache driver as file-based: 15 | ```php 16 | setDriver()->useFileDriver(); 22 | ``` 23 | 24 | Defines the cache driver as database-based: 25 | ```php 26 | setDriver()->useDatabaseDriver(); 32 | ``` 33 | 34 | Sets the cache driver to be based on Redis: 35 | ```php 36 | setDriver()->useRedisDriver(); 42 | ``` 43 | 44 | Sets the cache driver to be based on Arrays (Memory): 45 | ```php 46 | setDriver()->useArrayDriver(); 52 | ``` -------------------------------------------------------------------------------- /docs/api-reference.md: -------------------------------------------------------------------------------- 1 | ## API Reference 2 | 3 | ## **Classes Principais** 4 | 5 | ```bash 6 | Silviooosilva\CacheerPhp\Cacheer 7 | ``` 8 | 9 | The package's main class, used for all caching operations. 10 | 11 | 12 | ## **Methods** 13 | 14 | ### 1. **Configuration** 15 | 16 | #### `setConfig()` 17 | Starts a customized configuration for CacheerPHP. 18 | 19 | [API Reference - setConfig()](API-Reference/setConfig.md) 20 | 21 | ### 2. **Drivers** 22 | It allows you to define the different backends available for use. 23 | 24 | [API Reference - setDriver()](API-Reference/setDriver.md) 25 | 26 | ### 3. **OptionBuilder** 27 | The **OptionBuilder** simplifies the configuration of CacheerPHP by eliminating typing errors and making the process more intuitive. 28 | 29 | [API Reference - OptionBuilder](API-Reference/optionBuilder.md) 30 | ### 4. **Compression & Encryption** 31 | Built-in methods to reduce storage space and secure cached data. 32 | 33 | [API Reference - Compression & Encryption](API-Reference/compression_encryption.md) 34 | -------------------------------------------------------------------------------- /docs/cacheer_php_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silviooosilva/CacheerPHP/29b1f60e2032cabd5048ef0b40c389f2be3d4384/docs/cacheer_php_logo.png -------------------------------------------------------------------------------- /docs/cacheer_php_logo__.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silviooosilva/CacheerPHP/29b1f60e2032cabd5048ef0b40c389f2be3d4384/docs/cacheer_php_logo__.png -------------------------------------------------------------------------------- /docs/example01.md: -------------------------------------------------------------------------------- 1 | ## Exemplo 01 2 |

Simple Data Cache

3 | 4 | ```php 5 | __DIR__ . "/cache", 13 | ]; 14 | 15 | $Cacheer = new Cacheer($options); 16 | 17 | // Data to be stored in the cache 18 | $cacheKey = 'user_profile_1234'; 19 | $userProfile = [ 20 | 'id' => 123, 21 | 'name' => 'John Doe', 22 | 'email' => 'john.doe@example.com', 23 | ]; 24 | 25 | // Storing data in the cache 26 | $Cacheer->putCache($cacheKey, $userProfile); 27 | 28 | // Retrieving data from the cache 29 | $cachedProfile = $Cacheer->getCache($cacheKey); 30 | 31 | if ($Cacheer->isSuccess()) { 32 | echo "Cache Found: "; 33 | print_r($cachedProfile); 34 | } else { 35 | echo $Cacheer->getMessage(); 36 | } 37 | 38 | ``` 39 | -------------------------------------------------------------------------------- /docs/example02.md: -------------------------------------------------------------------------------- 1 | w## Exemplo 02 2 | 3 |

Cache com tempo de expiração Personalizado

4 | 5 | ```php 6 | __DIR__ . "/cache", 13 | "expirationTime" => "2 hour" //Primeira opção (definição global) 14 | ]; 15 | 16 | $Cacheer = new Cacheer($options); 17 | 18 | // Dados a serem armazenados no cache 19 | $cacheKey = 'daily_stats'; 20 | $dailyStats = [ 21 | 'visits' => 1500, 22 | 'signups' => 35, 23 | 'revenue' => 500.75, 24 | ]; 25 | 26 | // Armazenando dados no cache 27 | $Cacheer->putCache($cacheKey, $dailyStats); 28 | 29 | // Recuperando dados do cache por 2 horas 30 | $cachedStats = $Cacheer->getCache($cacheKey, 'namespace', '2 hours'); //Segunda opção (definição no método) 31 | 32 | if ($Cacheer->isSuccess()) { 33 | echo "Cache Found: "; 34 | print_r($cachedStats); 35 | } else { 36 | echo $Cacheer->getMessage(); 37 | } 38 | 39 | ``` 40 | 41 | Pode configurar o tempo de expiração do cache em: 42 | 43 | ```php 44 | Minutos: minute(s) 45 | Horas: hour(s) 46 | Segundos: second(s) 47 | ``` 48 | -------------------------------------------------------------------------------- /docs/example03.md: -------------------------------------------------------------------------------- 1 | ## Exemplo 03 2 |

Cache cleaning and flushing

3 | 4 | ```php 5 | __DIR__ . "/cache", 13 | ]; 14 | 15 | $Cacheer = new Cacheer($options); 16 | 17 | // Key of the cache to be cleared 18 | $cacheKey = 'user_profile_123'; 19 | 20 | // Clearing a specific item from the cache 21 | 22 | $Cacheer->clearCache($cacheKey); 23 | 24 | if ($Cacheer->isSuccess()) { 25 | echo $Cacheer->getMessage(); 26 | } else { 27 | echo $Cacheer->getMessage(); 28 | } 29 | 30 | $Cacheer->flushCache(); 31 | 32 | if ($Cacheer->isSuccess()) { 33 | echo $Cacheer->getMessage(); 34 | } else { 35 | echo $Cacheer->getMessage(); 36 | } 37 | 38 | 39 | ``` 40 | -------------------------------------------------------------------------------- /docs/example04.md: -------------------------------------------------------------------------------- 1 | ## Exemplo 04 2 |

Use of Namespaces

3 | 4 | ```php 5 | __DIR__ . "/cache", 12 | ]; 13 | 14 | $Cacheer = new Cacheer($options); 15 | 16 | // Data to be stored in the namespace cache 17 | $namespace = 'session_data_01'; 18 | $cacheKey = 'session_456'; 19 | $sessionData = [ 20 | 'user_id' => 456, 21 | 'login_time' => time(), 22 | ]; 23 | 24 | // Caching data with namespace 25 | $Cacheer->putCache($cacheKey, $sessionData, $namespace); 26 | 27 | // Retrieving data from the cache 28 | $cachedSessionData = $Cacheer->getCache($cacheKey, $namespace); 29 | 30 | if ($Cacheer->isSuccess()) { 31 | echo "Cache Found: "; 32 | print_r($cachedSessionData); 33 | } else { 34 | echo $Cacheer->getMessage(); 35 | } 36 | ``` -------------------------------------------------------------------------------- /docs/example05.md: -------------------------------------------------------------------------------- 1 | ## Exemplo 05 2 |

API Response Cache

3 | 4 | ```php 5 | __DIR__ . "/cache", 13 | ]; 14 | 15 | $Cacheer = new Cacheer($options); 16 | 17 | // API URL and cache key 18 | $apiUrl = 'https://jsonplaceholder.typicode.com/posts'; 19 | $cacheKey = 'api_response_' . md5($apiUrl); 20 | 21 | // Checking if the API response is already in the cache 22 | $cachedResponse = $Cacheer->getCache($cacheKey); 23 | 24 | if ($Cacheer->isSuccess()) { 25 | // Use the cache response 26 | $response = $cachedResponse; 27 | } else { 28 | // Call the API and store the response in the cache 29 | $response = file_get_contents($apiUrl); 30 | $Cacheer->putCache($cacheKey, $response); 31 | } 32 | 33 | // Using the API response (from cache or call) 34 | $data = json_decode($response, true); 35 | print_r($data); 36 | 37 | ``` 38 | -------------------------------------------------------------------------------- /docs/example06.md: -------------------------------------------------------------------------------- 1 | ## Exemplo 06 2 | 3 |

JSON type data output

4 | To configure the output type you want, you have to enable it when you instantiate the class, passing the last parameter as true.: 5 | 6 | ```php 7 | 8 | __DIR__ . "/cache", 15 | ]; 16 | 17 | $Cacheer = new Cacheer($options, $formatted = true); // True last parameter 18 | 19 | // Data to be stored in the cache 20 | $cacheKey = 'user_profile_1234'; 21 | 22 | $userProfile = [ 23 | 'id' => 123, 24 | 'name' => 'John Doe', 25 | 'email' => 'john.doe@example.com', 26 | ]; 27 | 28 | // Storing data in the cache 29 | 30 | $Cacheer->putCache($cacheKey, $userProfile); 31 | 32 | // Retrieving data from the cache in JSON format 33 | 34 | $cachedProfile = $Cacheer->getCache( 35 | $cacheKey, 36 | $namespace, 37 | $ttl)->toJson(); 38 | 39 | if ($Cacheer->isSuccess()) { 40 | echo "Cache Found: "; 41 | print_r($cachedProfile); 42 | } else { 43 | echo $Cacheer->getMessage(); 44 | } 45 | 46 | ``` -------------------------------------------------------------------------------- /docs/example07.md: -------------------------------------------------------------------------------- 1 | ## Exemplo 07 2 | 3 |

Array Data Output

4 | To configure the output type you want, you have to enable it when you instantiate the class, passing the last parameter as true.: 5 | 6 | ```php 7 | 8 | __DIR__ . "/cache", 15 | ]; 16 | 17 | $Cacheer = new Cacheer($options, $formatted = true); // True last parameter 18 | 19 | // Data to be stored in the cache 20 | 21 | $cacheKey = 'user_profile_1234'; 22 | 23 | $userProfile = [ 24 | 'id' => 123, 25 | 'name' => 'John Doe', 26 | 'email' => 'john.doe@example.com', 27 | ]; 28 | 29 | // Storing data in the cache 30 | 31 | $Cacheer->putCache($cacheKey, $userProfile); 32 | 33 | // Retrieving data from the cache in JSON format 34 | 35 | $cachedProfile = $Cacheer->getCache( 36 | $cacheKey, 37 | $namespace, 38 | $ttl)->toArray(); 39 | 40 | if ($Cacheer->isSuccess()) { 41 | echo "Cache Found: "; 42 | print_r($cachedProfile); 43 | } else { 44 | echo $Cacheer->getMessage(); 45 | } 46 | 47 | ``` -------------------------------------------------------------------------------- /docs/example08.md: -------------------------------------------------------------------------------- 1 | ## Exemplo 08 2 | 3 |

String Data Output

4 | To configure the output type you want, you have to enable it when you instantiate the class, passing the last parameter as true.: 5 | 6 | ```php 7 | 8 | __DIR__ . "/cache", 15 | ]; 16 | 17 | $Cacheer = new Cacheer($options, $formatted = true); // True last parameter 18 | 19 | // Data to be stored in the cache 20 | 21 | $cacheKey = 'user_profile_1234'; 22 | 23 | $userProfile = [ 24 | 'id' => 123, 25 | 'name' => 'John Doe', 26 | 'email' => 'john.doe@example.com', 27 | ]; 28 | 29 | // Storing data in the cache 30 | 31 | $Cacheer->putCache($cacheKey, $userProfile); 32 | 33 | // Retrieving data from the cache in JSON format 34 | 35 | $cachedProfile = $Cacheer->getCache( 36 | $cacheKey, 37 | $namespace, 38 | $ttl)->toString(); 39 | 40 | if ($Cacheer->isSuccess()) { 41 | echo "Cache Found: "; 42 | print_r($cachedProfile); 43 | } else { 44 | echo $Cacheer->getMessage(); 45 | } 46 | 47 | ``` -------------------------------------------------------------------------------- /docs/example09.md: -------------------------------------------------------------------------------- 1 | ## Exemplo 09 2 | 3 |

Automatic cleaning of the cache directory (flushAfter)

4 | 5 | To use automatic cleaning of the cache directory, you will need to configure the options: 6 | 7 | ```php 8 | 9 | __DIR__ . "/cache", 16 | "flushAfter" => "1 week" //string 17 | ]; 18 | 19 | $Cacheer = new Cacheer($options); 20 | 21 | // Data to be stored in the cache 22 | 23 | $cacheKey = 'user_profile_1234'; 24 | 25 | $userProfile = [ 26 | 'id' => 123, 27 | 'name' => 'John Doe', 28 | 'email' => 'john.doe@example.com', 29 | ]; 30 | 31 | // Storing data in the cache 32 | 33 | $Cacheer->putCache($cacheKey, $userProfile); 34 | 35 | // Retrieving data from the cache 36 | 37 | $cachedProfile = $Cacheer->getCache($cacheKey); 38 | 39 | if ($Cacheer->isSuccess()) { 40 | echo "Cache Found: "; 41 | print_r($cachedProfile); 42 | } else { 43 | echo $Cacheer->getMessage(); 44 | } 45 | 46 | 47 | ``` 48 | The accepted time formats for `flushAfter` are: 49 | 50 | ```php 51 | Segundos: second(s) 52 | Minutos: minute(s) 53 | Horas: hour(s) 54 | Dias: day(s) 55 | Semanas: week(s) 56 | Meses: month(s) 57 | Anos: year(s) 58 | 59 | ``` 60 | -------------------------------------------------------------------------------- /docs/guia2.0.0.md: -------------------------------------------------------------------------------- 1 | # Release of Version 2.0.0 of CacheerPHP 2 | 3 | We are excited to announce the release of **version 2.0.0** of **CacheerPHP**! This release brings a number of new features and improvements that increase flexibility and choice for developers looking to manage caching efficiently. 4 | 5 | ## Main New Features of Version 2.0.0 6 | 7 | - **Database Support**: CacheerPHP now supports cache storage in **databases** with options for `MySQL`, `SQLite`, and `PostgreSQL`. This allows for greater flexibility, scalability, and performance in various usage scenarios. 8 | - **Performance Improvements**: Additional optimizations for cache retrieval and insertion, ensuring greater efficiency, especially in systems with high data volume. 9 | - **New Features**: It is now possible to monitor the operation of the cache system with the new logging feature. Errors, warnings, information, and debug messages are recorded and stored, providing a clear view of system performance and making it easier to identify and solve potential issues. 10 | 11 | ## Benefits of the Update 12 | 13 | With **version 2.0.0**, you get: 14 | 15 | - **Flexibility** to choose the best cache storage solution for your application. 16 | - **Better performance**, with improvements in the process of retrieving and storing cached data. 17 | 18 | --- 19 | 20 | # Upgrade Guide for CacheerPHP 2.0.0 21 | 22 | To ensure a smooth transition to version 2.0.0, follow this detailed upgrade manual. 23 | 24 | ## System Requirements 25 | 26 | - **PHP** version 8.0 or higher. 27 | - **Database (optional)**: MySQL, PostgreSQL, or SQLite (for using the database-based cache driver). 28 | 29 | ## Step-by-Step Upgrade 30 | 31 | ### 1. Backup Current Cache Data 32 | 33 | Before starting the upgrade, it is recommended to back up any relevant cache data. If you are using file-based cache, save the cache directory. 34 | 35 | ### 2. Update the Package via Composer 36 | 37 | Run the command below to update to the latest version of CacheerPHP: 38 | 39 | ```bash 40 | composer require silviooosilva/cacheer-php:^2.0.0 41 | ``` 42 | 43 | ### 3. Configuration 44 | 45 | After the update, follow the instructions below to configure the new version. 46 | 47 | **Keep File-Based Cache** 48 | 49 | If you already use file-based cache and want to keep this configuration, no further action is needed. 50 | 51 | **Migrate to Database-Based Cache** 52 | 53 | #### 1) Configure Connection Data 54 | 55 | - Edit the CacheerPHP configuration file, located in the ```Boot/config.php``` folder, and enter your database details. 56 | 57 | #### 2) Enable the Database Driver 58 | 59 | - Example usage in code: 60 | 61 | ```php 62 | setConfig()->setDatabaseConnection('mysql'); 69 | $Cacheer->setDriver()->useDatabaseDriver(); 70 | 71 | ``` 72 | 73 | #### 3) Configure Timezone 74 | 75 | - To avoid issues with cache expiration, set the timezone: 76 | 77 | ```php 78 | $Cacheer->setConfig()->setTimeZone('Africa/Luanda'); 79 | ``` 80 | **NB: Make sure the provided timezone is valid** 81 | - https://www.php.net/manual/en/timezones.php 82 | 83 | #### 4) Logging System 84 | 85 | - Set the path to save the logs: 86 | 87 | ```php 88 | $Cacheer->setConfig()->setLoggerPath('/path/CacheerPHP.log'); 89 | ``` -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | tests 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/Boot/Configs.php: -------------------------------------------------------------------------------- 1 | load(); 12 | 13 | 14 | $Connection = $_ENV['DB_CONNECTION'] ?? 'mysql'; 15 | $Host = $_ENV['DB_HOST'] ?? 'localhost'; 16 | $Port = $_ENV['DB_PORT'] ?? '3306'; 17 | $DBName = $_ENV['DB_DATABASE'] ?? 'cacheer_db'; 18 | $User = $_ENV['DB_USERNAME'] ?? 'root'; 19 | $Password = $_ENV['DB_PASSWORD'] ?? ''; 20 | 21 | // Retrieve Redis environment variables 22 | $redisClient = $_ENV['REDIS_CLIENT'] ?? ''; 23 | $redisHost = $_ENV['REDIS_HOST'] ?? 'localhost'; 24 | $redisPassword = $_ENV['REDIS_PASSWORD'] ?? ''; 25 | $redisPort = $_ENV['REDIS_PORT'] ?? '6379'; 26 | $redisNamespace = $_ENV['REDIS_NAMESPACE'] ?? ''; 27 | 28 | Connect::setConnection($Connection); 29 | 30 | // Database configuration array 31 | define('CACHEER_DATABASE_CONFIG', [ 32 | "mysql" => [ 33 | "driver" => $Connection, 34 | "host" => $Host, 35 | "port" => $Port, 36 | "dbname" => $DBName, 37 | "username"=> $User, 38 | "passwd" => $Password, 39 | "options" => [ 40 | PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8", 41 | PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, 42 | PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_OBJ, 43 | PDO::ATTR_CASE => PDO::CASE_NATURAL 44 | ] 45 | ], 46 | "sqlite" => [ 47 | "driver" => $Connection, 48 | "dbname" => SqliteHelper::database(), 49 | "options" => [ 50 | PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, 51 | PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_OBJ, 52 | PDO::ATTR_CASE => PDO::CASE_NATURAL 53 | ] 54 | ], 55 | "pgsql" => [ 56 | "driver" => $Connection, 57 | "host" => $Host, 58 | "port" => $Port, 59 | "dbname" => $DBName, 60 | "username"=> $User, 61 | "passwd" => $Password, 62 | "options" => [ 63 | PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, 64 | PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_OBJ, 65 | PDO::ATTR_CASE => PDO::CASE_NATURAL 66 | ] 67 | ], 68 | ]); 69 | 70 | // Redis configuration array 71 | define('REDIS_CONNECTION_CONFIG', [ 72 | 'REDIS_CLIENT' => $redisClient, 73 | 'REDIS_HOST' => $redisHost, 74 | 'REDIS_PASSWORD' => $redisPassword, 75 | 'REDIS_PORT' => $redisPort, 76 | 'REDIS_NAMESPACE'=> $redisNamespace 77 | ]); 78 | 79 | -------------------------------------------------------------------------------- /src/CacheStore/ArrayCacheStore.php: -------------------------------------------------------------------------------- 1 | 11 | * @package Silviooosilva\CacheerPhp 12 | */ 13 | class ArrayCacheStore implements CacheerInterface 14 | { 15 | 16 | /** 17 | * @param array $arrayStore 18 | */ 19 | private array $arrayStore = []; 20 | 21 | /** 22 | * @param boolean 23 | */ 24 | private bool $success = false; 25 | 26 | /** 27 | * @param string 28 | */ 29 | private string $message = ''; 30 | 31 | /** 32 | * @var CacheLogger 33 | */ 34 | private $logger = null; 35 | 36 | public function __construct(string $logPath) 37 | { 38 | $this->logger = new CacheLogger($logPath); 39 | } 40 | 41 | /** 42 | * @param string $cacheKey 43 | * @param mixed $cacheData 44 | * @param string $namespace 45 | * @return bool 46 | */ 47 | public function appendCache(string $cacheKey, mixed $cacheData, string $namespace = '') 48 | { 49 | $arrayStoreKey = $this->buildArrayKey($cacheKey, $namespace); 50 | 51 | if (!$this->has($cacheKey, $namespace)) { 52 | $this->setMessage("cacheData can't be appended, because doesn't exist or expired", false); 53 | $this->logger->debug("{$this->getMessage()} from array driver."); 54 | return false; 55 | } 56 | 57 | $this->arrayStore[$arrayStoreKey]['cacheData'] = serialize($cacheData); 58 | $this->setMessage("Cache appended successfully", true); 59 | return true; 60 | } 61 | 62 | /** 63 | * @param string $cacheKey 64 | * @param string $namespace 65 | * @return string 66 | */ 67 | private function buildArrayKey(string $cacheKey, string $namespace = '') 68 | { 69 | return !empty($namespace) ? ($namespace . ':' . $cacheKey) : $cacheKey; 70 | } 71 | 72 | /** 73 | * @param string $cacheKey 74 | * @param string $namespace 75 | * @return void 76 | */ 77 | public function clearCache(string $cacheKey, string $namespace = '') 78 | { 79 | $arrayStoreKey = $this->buildArrayKey($cacheKey, $namespace); 80 | unset($this->arrayStore[$arrayStoreKey]); 81 | $this->setMessage("Cache cleared successfully", true); 82 | $this->logger->debug("{$this->getMessage()} from array driver."); 83 | } 84 | 85 | /** 86 | * @param string $cacheKey 87 | * @param int $amount 88 | * @param string $namespace 89 | * @return bool 90 | */ 91 | public function decrement(string $cacheKey, int $amount = 1, string $namespace = '') 92 | { 93 | return $this->increment($cacheKey, ($amount * -1), $namespace); 94 | } 95 | 96 | /** 97 | * @return void 98 | */ 99 | public function flushCache() 100 | { 101 | unset($this->arrayStore); 102 | $this->arrayStore = []; 103 | $this->setMessage("Cache flushed successfully", true); 104 | $this->logger->debug("{$this->getMessage()} from array driver."); 105 | } 106 | 107 | /** 108 | * @param string $cacheKey 109 | * @param mixed $cacheData 110 | * @param string $namespace 111 | * @param int|string $ttl 112 | * @return void 113 | */ 114 | public function forever(string $cacheKey, mixed $cacheData) 115 | { 116 | $this->putCache($cacheKey, $cacheData, ttl: 31536000 * 1000); 117 | $this->setMessage($this->getMessage(), $this->isSuccess()); 118 | } 119 | 120 | /** 121 | * @param string $cacheKey 122 | * @param string $namespace 123 | * @param int|string $ttl 124 | * @return mixed 125 | */ 126 | public function getCache(string $cacheKey, string $namespace = '', string|int $ttl = 3600) 127 | { 128 | $arrayStoreKey = $this->buildArrayKey($cacheKey, $namespace); 129 | 130 | if (!$this->has($cacheKey, $namespace)) { 131 | $this->setMessage("cacheData not found, does not exists or expired", false); 132 | $this->logger->debug("{$this->getMessage()} from array driver."); 133 | return false; 134 | } 135 | 136 | $cacheData = $this->arrayStore[$arrayStoreKey]; 137 | $expirationTime = $cacheData['expirationTime'] ?? 0; 138 | $now = time(); 139 | 140 | if($expirationTime !== 0 && $now >= $expirationTime) { 141 | list($np, $key) = explode(':', $arrayStoreKey); 142 | $this->clearCache($key, $np); 143 | $this->setMessage("cacheKey: {$key} has expired.", false); 144 | $this->logger->debug("{$this->getMessage()} from array driver."); 145 | return false; 146 | } 147 | 148 | $this->setMessage("Cache retrieved successfully", true); 149 | $this->logger->debug("{$this->getMessage()} from array driver."); 150 | return $this->serialize($cacheData['cacheData'], false); 151 | } 152 | 153 | /** 154 | * @param string $cacheKey 155 | * @param string $namespace 156 | * @return bool 157 | */ 158 | public function has(string $cacheKey, string $namespace = '') 159 | { 160 | $arrayStoreKey = $this->buildArrayKey($cacheKey, $namespace); 161 | return isset($this->arrayStore[$arrayStoreKey]) && time() < $this->arrayStore[$arrayStoreKey]['expirationTime']; 162 | } 163 | 164 | /** 165 | * @param string $cacheKey 166 | * @param int $amount 167 | * @param string $namespace 168 | * @return bool 169 | */ 170 | public function increment(string $cacheKey, int $amount = 1, string $namespace = '') 171 | { 172 | $cacheData = $this->getCache($cacheKey, $namespace); 173 | 174 | if(!empty($cacheData) && is_numeric($cacheData)) { 175 | $this->putCache($cacheKey, (int)($cacheData + $amount), $namespace); 176 | $this->setMessage($this->getMessage(), $this->isSuccess()); 177 | return true; 178 | } 179 | 180 | return false; 181 | } 182 | 183 | /** 184 | * @return boolean 185 | */ 186 | public function isSuccess() 187 | { 188 | return $this->success; 189 | } 190 | 191 | /** 192 | * @return string 193 | */ 194 | public function getMessage() 195 | { 196 | return $this->message; 197 | } 198 | 199 | /** 200 | * @param string $cacheKey 201 | * @param mixed $cacheData 202 | * @param string $namespace 203 | * @param int|string $ttl 204 | * @return bool 205 | */ 206 | public function putCache(string $cacheKey, mixed $cacheData, string $namespace = '', int|string $ttl = 3600) 207 | { 208 | $arrayStoreKey = $this->buildArrayKey($cacheKey, $namespace); 209 | 210 | $this->arrayStore[$arrayStoreKey] = [ 211 | 'cacheData' => serialize($cacheData), 212 | 'expirationTime' => time() + $ttl 213 | ]; 214 | 215 | $this->setMessage("Cache stored successfully", true); 216 | $this->logger->debug("{$this->getMessage()} from Array driver."); 217 | return true; 218 | } 219 | 220 | /** 221 | * @param array $items 222 | * @param string $namespace 223 | * @param int $batchSize 224 | * @return void 225 | */ 226 | public function putMany(array $items, string $namespace = '', int $batchSize = 100) 227 | { 228 | $chunks = array_chunk($items, $batchSize, true); 229 | 230 | foreach ($chunks as $chunk) { 231 | foreach ($chunk as $key => $data) { 232 | $this->putCache($data['cacheKey'], $data['cacheData'], $namespace); 233 | } 234 | } 235 | $this->setMessage("{$this->getMessage()}", $this->isSuccess()); 236 | $this->logger->debug("{$this->getMessage()} from Array driver."); 237 | } 238 | 239 | /** 240 | * @param string $cacheKey 241 | * @param string|int $ttl 242 | * @param string $namespace 243 | * @return void 244 | */ 245 | public function renewCache(string $cacheKey, int|string $ttl = 3600, string $namespace = '') 246 | { 247 | $arrayStoreKey = $this->buildArrayKey($cacheKey, $namespace); 248 | 249 | if (isset($this->arrayStore[$arrayStoreKey])) { 250 | $ttlSeconds = is_numeric($ttl) ? (int) $ttl : strtotime($ttl) - time(); 251 | $this->arrayStore[$arrayStoreKey]['expirationTime'] = time() + $ttlSeconds; 252 | $this->setMessage("cacheKey: {$cacheKey} renewed successfully", true); 253 | $this->logger->debug("{$this->getMessage()} from array driver."); 254 | } 255 | } 256 | 257 | /** 258 | * @param string $message 259 | * @param boolean $success 260 | * @return void 261 | */ 262 | private function setMessage(string $message, bool $success) 263 | { 264 | $this->message = $message; 265 | $this->success = $success; 266 | } 267 | 268 | /** 269 | * @param mixed $data 270 | * @param bool $serialize 271 | * @return mixed 272 | */ 273 | private function serialize(mixed $data, bool $serialize = true) 274 | { 275 | return $serialize ? serialize($data) : unserialize($data); 276 | } 277 | } 278 | -------------------------------------------------------------------------------- /src/CacheStore/CacheManager/FileCacheManager.php: -------------------------------------------------------------------------------- 1 | 12 | * @package Silviooosilva\CacheerPhp 13 | */ 14 | class FileCacheManager 15 | { 16 | 17 | /** 18 | * @param string $dir 19 | * @return void 20 | */ 21 | public function createDirectory(string $dir) 22 | { 23 | if ((!file_exists($dir) || !is_dir($dir)) && !mkdir($dir, 0755, true)) { 24 | throw CacheFileException::create("Could not create directory: {$dir}"); 25 | } 26 | } 27 | 28 | /** 29 | * @param string $filename 30 | * @param string $data 31 | * @return void 32 | */ 33 | public function writeFile(string $filename, string $data) 34 | { 35 | if (!@file_put_contents($filename, $data, LOCK_EX)) { 36 | throw CacheFileException::create("Could not write file: {$filename}"); 37 | } 38 | } 39 | 40 | /** 41 | * @param string $filename 42 | * @return string 43 | */ 44 | public function readFile(string $filename) 45 | { 46 | if (!$this->fileExists($filename)) { 47 | throw CacheFileException::create("File not found: {$filename}"); 48 | } 49 | return file_get_contents($filename); 50 | } 51 | 52 | /** 53 | * @param string $filename 54 | * @return bool 55 | */ 56 | public function fileExists(string $filename) 57 | { 58 | return file_exists($filename); 59 | } 60 | 61 | /** 62 | * @param string $filename 63 | * @return void 64 | */ 65 | public function removeFile(string $filename) 66 | { 67 | if (file_exists($filename)) { 68 | unlink($filename); 69 | } 70 | } 71 | 72 | /** 73 | * @param string $dir 74 | * @return void 75 | */ 76 | public function clearDirectory(string $dir) 77 | { 78 | $iterator = new RecursiveIteratorIterator( 79 | new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS), 80 | RecursiveIteratorIterator::CHILD_FIRST 81 | ); 82 | foreach ($iterator as $file) { 83 | $path = $file->getPathname(); 84 | $file->isDir() ? rmdir($path) : unlink($path); 85 | } 86 | } 87 | 88 | /** 89 | * @param mixed $data 90 | * @param bool $serialize 91 | */ 92 | public function serialize(mixed $data, bool $serialize = true) 93 | { 94 | if($serialize) { 95 | return serialize($data); 96 | } 97 | return unserialize($data); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/CacheStore/CacheManager/OptionBuilders/FileOptionBuilder.php: -------------------------------------------------------------------------------- 1 | 12 | * @package Silviooosilva\CacheerPhp 13 | */ 14 | class FileOptionBuilder 15 | { 16 | /** @param null|string $cacheDir */ 17 | private ?string $cacheDir = null; 18 | 19 | /** @param null|string $expirationTime */ 20 | private ?string $expirationTime = null; 21 | 22 | /** @param null|string $flushAfter */ 23 | private ?string $flushAfter = null; 24 | 25 | /** @param array $options */ 26 | private array $options = []; 27 | 28 | /** 29 | * @param string $cacheDir 30 | * @return $this 31 | */ 32 | public function dir(string $cacheDir) 33 | { 34 | $this->cacheDir = $cacheDir; 35 | return $this; 36 | } 37 | 38 | /** 39 | * @param ?string $expirationTime 40 | * @return $this|TimeBuilder 41 | */ 42 | public function expirationTime(?string $expirationTime = null) 43 | { 44 | 45 | if (!is_null($expirationTime)) { 46 | $this->expirationTime = $expirationTime; 47 | return $this; 48 | } 49 | 50 | return new TimeBuilder(function ($formattedTime){ 51 | $this->expirationTime = $formattedTime; 52 | }, $this); 53 | } 54 | 55 | /** 56 | * @param ?string $flushAfter 57 | * @return $this|TimeBuilder 58 | */ 59 | public function flushAfter(?string $flushAfter = null) 60 | { 61 | 62 | if (!is_null($flushAfter)) { 63 | $this->flushAfter = mb_strtolower($flushAfter, 'UTF-8'); 64 | return $this; 65 | } 66 | 67 | return new TimeBuilder(function ($formattedTime){ 68 | $this->flushAfter = $formattedTime; 69 | }, $this); 70 | } 71 | 72 | /** 73 | * @return array 74 | */ 75 | public function build() 76 | { 77 | return $this->validated(); 78 | } 79 | 80 | /** 81 | * @return array 82 | */ 83 | private function validated() 84 | { 85 | foreach ($this->properties() as $key => $value) { 86 | if ($this->isValidAndNotNull($value)) { 87 | $this->options[$key] = $value; 88 | } 89 | } 90 | return $this->options; 91 | } 92 | 93 | /** 94 | * @param mixed $data 95 | * @return bool 96 | */ 97 | private function isValidAndNotNull(mixed $data) 98 | { 99 | return !empty($data) ? true : false; 100 | } 101 | 102 | /** 103 | * @return array 104 | */ 105 | private function properties() 106 | { 107 | $properties = [ 108 | 'cacheDir' => $this->cacheDir, 109 | 'expirationTime' => $this->expirationTime, 110 | 'flushAfter' => $this->flushAfter 111 | ]; 112 | 113 | return $properties; 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/CacheStore/CacheManager/RedisCacheManager.php: -------------------------------------------------------------------------------- 1 | 12 | * @package Silviooosilva\CacheerPhp 13 | */ 14 | class RedisCacheManager 15 | { 16 | 17 | /** @var Predis\Client */ 18 | private static $redis; 19 | 20 | /** @param string $namespace */ 21 | private static $namespace; 22 | 23 | /** 24 | * @return Client 25 | */ 26 | public static function connect() 27 | { 28 | Autoloader::register(); 29 | self::$redis = new Client([ 30 | 'scheme' => 'tcp', 31 | 'host' => REDIS_CONNECTION_CONFIG['REDIS_HOST'], 32 | 'port' => REDIS_CONNECTION_CONFIG['REDIS_PORT'], 33 | 'password' => REDIS_CONNECTION_CONFIG['REDIS_PASSWORD'], 34 | 'database' => 0 35 | ]); 36 | self::auth(); 37 | self::$namespace = REDIS_CONNECTION_CONFIG['REDIS_NAMESPACE'] ?? 'Cache'; 38 | return self::$redis; 39 | } 40 | 41 | /** 42 | * @return void 43 | */ 44 | private static function auth() 45 | { 46 | if(is_string(REDIS_CONNECTION_CONFIG['REDIS_PASSWORD']) && REDIS_CONNECTION_CONFIG['REDIS_PASSWORD'] !== '') { 47 | self::$redis->auth(REDIS_CONNECTION_CONFIG['REDIS_PASSWORD']); 48 | } 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/CacheStore/DatabaseCacheStore.php: -------------------------------------------------------------------------------- 1 | 13 | * @package Silviooosilva\CacheerPhp 14 | */ 15 | class DatabaseCacheStore implements CacheerInterface 16 | { 17 | /** 18 | * @param boolean 19 | */ 20 | private bool $success = false; 21 | 22 | /** 23 | * @param string 24 | */ 25 | private string $message = ''; 26 | 27 | /** 28 | * @var CacheLogger 29 | */ 30 | private $logger = null; 31 | 32 | /** 33 | * @var CacheDatabaseRepository 34 | */ 35 | private $cacheRepository; 36 | 37 | public function __construct(string $logPath) 38 | { 39 | $this->logger = new CacheLogger($logPath); 40 | $this->cacheRepository = new CacheDatabaseRepository(); 41 | } 42 | 43 | /** 44 | * @param string $cacheKey 45 | * @param mixed $cacheData 46 | * @param string $namespace 47 | * @return bool 48 | */ 49 | public function appendCache(string $cacheKey, mixed $cacheData, string $namespace = '') 50 | { 51 | $currentCacheData = $this->getCache($cacheKey, $namespace); 52 | $mergedCacheData = CacheDatabaseHelper::arrayIdentifier($currentCacheData, $cacheData); 53 | 54 | if ($this->updateCache($cacheKey, $mergedCacheData, $namespace)) { 55 | $this->logger->debug("{$this->getMessage()} from database driver."); 56 | return true; 57 | } 58 | 59 | $this->logger->error("{$this->getMessage()} from database driver."); 60 | return false; 61 | } 62 | 63 | /** 64 | * @param string $cacheKey 65 | * @param string $namespace 66 | * @return void 67 | */ 68 | public function clearCache(string $cacheKey, string $namespace = '') 69 | { 70 | $data = $this->cacheRepository->clear($cacheKey, $namespace); 71 | if($data) { 72 | $this->setMessage("Cache deleted successfully!", true); 73 | } else { 74 | $this->setMessage("Cache does not exists!", false); 75 | } 76 | 77 | $this->logger->debug("{$this->getMessage()} from database driver."); 78 | } 79 | 80 | /** 81 | * @return void 82 | */ 83 | public function flushCache() 84 | { 85 | if($this->cacheRepository->flush()){ 86 | $this->setMessage("Flush finished successfully", true); 87 | } else { 88 | $this->setMessage("Something went wrong. Please, try again.", false); 89 | } 90 | 91 | $this->logger->info("{$this->getMessage()} from database driver."); 92 | 93 | } 94 | 95 | /** 96 | * @param string $cacheKey 97 | * @param string $namespace 98 | * @param string|int $ttl 99 | * @return mixed 100 | */ 101 | public function getCache(string $cacheKey, string $namespace = '', string|int $ttl = 3600) 102 | { 103 | $cacheData = $this->retrieveCache($cacheKey, $namespace); 104 | if ($cacheData) { 105 | $this->setMessage("Cache retrieved successfully", true); 106 | $this->logger->debug("{$this->getMessage()} from database driver."); 107 | return $cacheData; 108 | } 109 | $this->setMessage("CacheData not found, does not exists or expired", false); 110 | $this->logger->info("{$this->getMessage()} from database driver."); 111 | return null; 112 | } 113 | 114 | /** 115 | * @return string 116 | */ 117 | public function getMessage() 118 | { 119 | return $this->message; 120 | } 121 | 122 | /** 123 | * @param string $cacheKey 124 | * @param string $namespace 125 | * @return void 126 | */ 127 | public function has(string $cacheKey, string $namespace = '') 128 | { 129 | $cacheData = $this->getCache($cacheKey, $namespace); 130 | if ($cacheData) { 131 | $this->logger->debug("Cache key: {$cacheKey} exists and it's available from database driver."); 132 | } 133 | $this->logger->warning("{$this->getMessage()} from database driver."); 134 | } 135 | 136 | /** 137 | * @return boolean 138 | */ 139 | public function isSuccess() 140 | { 141 | return $this->success; 142 | } 143 | 144 | /** 145 | * @param array $items 146 | * @param string $namespace 147 | * @param integer $batchSize 148 | * @return void 149 | */ 150 | public function putMany(array $items, string $namespace = '', int $batchSize = 100) 151 | { 152 | $processedCount = 0; 153 | $itemCount = count($items); 154 | while ($processedCount < $itemCount) { 155 | $batchItems = array_slice($items, $processedCount, $batchSize); 156 | $this->processBatchItems($batchItems, $namespace); 157 | $processedCount += count($batchItems); 158 | } 159 | } 160 | 161 | /** 162 | * @param string $cacheKey 163 | * @param mixed $cacheData 164 | * @param string $namespace 165 | * @param string|int $ttl 166 | * @return bool 167 | */ 168 | public function putCache(string $cacheKey, mixed $cacheData, string $namespace = '', string|int $ttl = 3600) 169 | { 170 | if($this->storeCache($cacheKey, $cacheData, $namespace, $ttl)){ 171 | $this->logger->debug("{$this->getMessage()} from database driver."); 172 | return true; 173 | } 174 | $this->logger->error("{$this->getMessage()} from database driver."); 175 | return false; 176 | } 177 | 178 | /** 179 | * @param string $cacheKey 180 | * @param string|int $ttl 181 | * @param string $namespace 182 | * @return void 183 | */ 184 | public function renewCache(string $cacheKey, int | string $ttl, string $namespace = '') 185 | { 186 | $cacheData = $this->getCache($cacheKey, $namespace); 187 | if ($cacheData) { 188 | $this->renew($cacheKey, $ttl, $namespace); 189 | $this->setMessage("Cache with key {$cacheKey} renewed successfully", true); 190 | $this->logger->debug("{$this->getMessage()} from database driver."); 191 | } 192 | } 193 | 194 | /** 195 | * @param array $batchItems 196 | * @param string $namespace 197 | * @return void 198 | */ 199 | private function processBatchItems(array $batchItems, string $namespace) 200 | { 201 | foreach($batchItems as $item) { 202 | CacheDatabaseHelper::validateCacheItem($item); 203 | $cacheKey = $item['cacheKey']; 204 | $cacheData = $item['cacheData']; 205 | $mergedData = CacheDatabaseHelper::mergeCacheData($cacheData); 206 | $this->putCache($cacheKey, $mergedData, $namespace); 207 | } 208 | } 209 | 210 | /** 211 | * @param string $cacheKey 212 | * @param string|int $ttl 213 | * @param string $namespace 214 | * @return bool 215 | */ 216 | private function renew(string $cacheKey, string|int $ttl = 3600, string $namespace = '') 217 | { 218 | $cacheData = $this->getCache($cacheKey, $namespace); 219 | if ($cacheData) { 220 | $renewedCache = $this->cacheRepository->renew($cacheKey, $ttl, $namespace); 221 | if ($renewedCache) { 222 | $this->setMessage("Cache with key {$cacheKey} renewed successfully", true); 223 | $this->logger->debug("{$this->getMessage()} from database driver."); 224 | return true; 225 | } 226 | return false; 227 | } 228 | return false; 229 | } 230 | 231 | /** 232 | * @param string $message 233 | * @param boolean $success 234 | * @return void 235 | */ 236 | private function setMessage(string $message, bool $success) 237 | { 238 | $this->message = $message; 239 | $this->success = $success; 240 | } 241 | 242 | /** 243 | * @param string $cacheKey 244 | * @param string $namespace 245 | * @return mixed 246 | */ 247 | private function retrieveCache(string $cacheKey, string $namespace = '') 248 | { 249 | return $this->cacheRepository->retrieve($cacheKey, $namespace); 250 | } 251 | 252 | /** 253 | * @param string $cacheKey 254 | * @param mixed $cacheData 255 | * @param string $namespace 256 | * @param integer $ttl 257 | * @return bool 258 | */ 259 | private function storeCache(string $cacheKey, mixed $cacheData, string $namespace = '', string|int $ttl = 3600) 260 | { 261 | $data = $this->cacheRepository->store($cacheKey, $cacheData, $namespace, $ttl); 262 | if($data) { 263 | $this->setMessage("Cache Stored Successfully", true); 264 | return true; 265 | } 266 | $this->setMessage("Already exists a cache with this key...", false); 267 | return false; 268 | } 269 | 270 | /** 271 | * @param string $cacheKey 272 | * @param mixed $cacheData 273 | * @param string $namespace 274 | * @return bool 275 | */ 276 | private function updateCache(string $cacheKey, mixed $cacheData, string $namespace = '') 277 | { 278 | $data = $this->cacheRepository->update($cacheKey, $cacheData, $namespace); 279 | if($data) { 280 | $this->setMessage("Cache updated successfully.", true); 281 | return true; 282 | } 283 | $this->setMessage("Cache does not exist or update failed!", false); 284 | return false; 285 | } 286 | } 287 | -------------------------------------------------------------------------------- /src/CacheStore/FileCacheStore.php: -------------------------------------------------------------------------------- 1 | 14 | * @package Silviooosilva\CacheerPhp 15 | */ 16 | class FileCacheStore implements CacheerInterface 17 | { 18 | /** 19 | * @param string $cacheDir 20 | */ 21 | private string $cacheDir; 22 | 23 | /** 24 | * @param array $options 25 | */ 26 | private array $options = []; 27 | 28 | /** 29 | * @param string $message 30 | */ 31 | private string $message = ''; 32 | 33 | /** 34 | * @param integer $defaultTTL 35 | */ 36 | private int $defaultTTL = 3600; // 1 hora por padrão 37 | 38 | /** 39 | * @param boolean $success 40 | */ 41 | private bool $success = false; 42 | 43 | /** 44 | * @param string $lastFlushTimeFile 45 | */ 46 | private string $lastFlushTimeFile; 47 | 48 | /** 49 | * @var CacheLogger 50 | */ 51 | private $logger = null; 52 | 53 | /** 54 | * @var FileCacheManager 55 | */ 56 | private FileCacheManager $fileManager; 57 | 58 | public function __construct(array $options = []) 59 | { 60 | $this->validateOptions($options); 61 | $this->fileManager = new FileCacheManager(); 62 | $this->initializeCacheDir($options['cacheDir']); 63 | $this->defaultTTL = $this->getExpirationTime($options); 64 | $this->lastFlushTimeFile = "{$this->cacheDir}/last_flush_time"; 65 | $this->handleAutoFlush($options); 66 | $this->logger = new CacheLogger($options['loggerPath']); 67 | } 68 | 69 | /** 70 | * @param string $cacheKey 71 | * @param mixed $cacheData 72 | * @param string $namespace 73 | * @return void 74 | */ 75 | public function appendCache(string $cacheKey, mixed $cacheData, string $namespace = '') 76 | { 77 | $currentCacheFileData = $this->getCache($cacheKey, $namespace); 78 | 79 | if (!$this->isSuccess()) { 80 | return $this->getMessage(); 81 | } 82 | 83 | $mergedCacheData = CacheFileHelper::arrayIdentifier($currentCacheFileData, $cacheData); 84 | 85 | 86 | $this->putCache($cacheKey, $mergedCacheData, $namespace); 87 | if ($this->isSuccess()) { 88 | $this->setMessage("Cache updated successfully", true); 89 | $this->logger->debug("{$this->getMessage()} from file driver."); 90 | } 91 | } 92 | 93 | /** 94 | * @param string $cacheKey 95 | * @param string $namespace 96 | * @return string 97 | */ 98 | private function buildCacheFilePath(string $cacheKey, string $namespace) 99 | { 100 | $namespace = $namespace ? md5($namespace) . '/' : ''; 101 | $cacheDir = "{$this->cacheDir}/"; 102 | 103 | if (!empty($namespace)) { 104 | $cacheDir = "{$this->cacheDir}/{$namespace}"; 105 | $this->fileManager->createDirectory($cacheDir); 106 | } 107 | return $cacheDir . md5($cacheKey) . ".cache"; 108 | } 109 | 110 | /** 111 | * @param string $cacheKey 112 | * @param string $namespace 113 | * @return void 114 | */ 115 | public function clearCache(string $cacheKey, string $namespace = '') 116 | { 117 | $cacheFile = $this->buildCacheFilePath($cacheKey, $namespace); 118 | if ($this->fileManager->readFile($cacheFile)) { 119 | $this->fileManager->removeFile($cacheFile); 120 | $this->setMessage("Cache file deleted successfully!", true); 121 | } else { 122 | $this->setMessage("Cache file does not exist!", false); 123 | } 124 | $this->logger->debug("{$this->getMessage()} from file driver."); 125 | } 126 | 127 | /** 128 | * @return void 129 | */ 130 | public function flushCache() 131 | { 132 | $this->fileManager->clearDirectory($this->cacheDir); 133 | file_put_contents($this->lastFlushTimeFile, time()); 134 | } 135 | 136 | /** 137 | * @param array $options 138 | * @return integer 139 | */ 140 | private function getExpirationTime(array $options) 141 | { 142 | return isset($options['expirationTime']) 143 | ? CacheFileHelper::convertExpirationToSeconds($options['expirationTime']) 144 | : $this->defaultTTL; 145 | } 146 | 147 | /** 148 | * @return string 149 | */ 150 | public function getMessage() 151 | { 152 | return $this->message; 153 | } 154 | 155 | /** 156 | * @param string $cacheKey 157 | * @param string $namespace 158 | * @param string|int $ttl 159 | * @return string 160 | */ 161 | public function getCache(string $cacheKey, string $namespace = '', string|int $ttl = 3600) 162 | { 163 | 164 | $ttl = CacheFileHelper::ttl($ttl, $this->defaultTTL); 165 | $cacheFile = $this->buildCacheFilePath($cacheKey, $namespace); 166 | if ($this->isCacheValid($cacheFile, $ttl)) { 167 | $cacheData = $this->fileManager->serialize($this->fileManager->readFile($cacheFile), false); 168 | 169 | $this->setMessage("Cache retrieved successfully", true); 170 | $this->logger->debug("{$this->getMessage()} from file driver."); 171 | return $cacheData; 172 | } 173 | 174 | $this->setMessage("cacheFile not found, does not exists or expired", false); 175 | $this->logger->info("{$this->getMessage()} from file driver."); 176 | } 177 | 178 | /** 179 | * @param array $items 180 | * @param string $namespace 181 | * @param integer $batchSize 182 | * @return void 183 | */ 184 | public function putMany(array $items, string $namespace = '', int $batchSize = 100) 185 | { 186 | $processedCount = 0; 187 | $itemCount = count($items); 188 | 189 | while ($processedCount < $itemCount) { 190 | $batchItems = array_slice($items, $processedCount, $batchSize); 191 | $this->processBatchItems($batchItems, $namespace); 192 | $processedCount += count($batchItems); 193 | } 194 | } 195 | 196 | /** 197 | * @param string $cacheKey 198 | * @param mixed $cacheData 199 | * @param string $namespace 200 | * @param string|int $ttl 201 | * @return void 202 | */ 203 | public function putCache(string $cacheKey, mixed $cacheData, string $namespace = '', string|int $ttl = 3600) 204 | { 205 | $cacheFile = $this->buildCacheFilePath($cacheKey, $namespace); 206 | $data = $this->fileManager->serialize($cacheData); 207 | 208 | $this->fileManager->writeFile($cacheFile, $data); 209 | $this->setMessage("Cache file created successfully", true); 210 | 211 | $this->logger->debug("{$this->getMessage()} from file driver."); 212 | } 213 | 214 | /** 215 | * @param string $cacheKey 216 | * @param string $namespace 217 | * @return void 218 | */ 219 | public function has(string $cacheKey, string $namespace = '') 220 | { 221 | $this->getCache($cacheKey, $namespace); 222 | 223 | if ($this->isSuccess()) { 224 | $this->setMessage("Cache key: {$cacheKey} exists and it's available! from file driver", true); 225 | } else { 226 | $this->setMessage("Cache key: {$cacheKey} does not exists or it's expired! from file driver", false); 227 | } 228 | } 229 | 230 | /** 231 | * @param string $cacheKey 232 | * @param string|int $ttl 233 | * @param string $namespace 234 | * @return void 235 | */ 236 | public function renewCache(string $cacheKey, string|int $ttl, string $namespace = '') 237 | { 238 | $cacheData = $this->getCache($cacheKey, $namespace); 239 | if ($cacheData) { 240 | $this->putCache($cacheKey, $cacheData, $namespace, $ttl); 241 | $this->setMessage("Cache with key {$cacheKey} renewed successfully", true); 242 | $this->logger->debug("{$this->getMessage()} from file driver."); 243 | return; 244 | } 245 | $this->setMessage("Failed to renew Cache with key {$cacheKey}", false); 246 | $this->logger->debug("{$this->getMessage()} from file driver."); 247 | } 248 | 249 | /** 250 | * @param array $batchItems 251 | * @param string $namespace 252 | * @return void 253 | */ 254 | private function processBatchItems(array $batchItems, string $namespace) 255 | { 256 | foreach ($batchItems as $item) { 257 | CacheFileHelper::validateCacheItem($item); 258 | $cacheKey = $item['cacheKey']; 259 | $cacheData = $item['cacheData']; 260 | $mergedData = CacheFileHelper::mergeCacheData($cacheData); 261 | $this->putCache($cacheKey, $mergedData, $namespace); 262 | } 263 | } 264 | 265 | /** 266 | * @return boolean 267 | */ 268 | public function isSuccess() 269 | { 270 | return $this->success; 271 | } 272 | 273 | /** 274 | * @param string $message 275 | * @param boolean $success 276 | * @return void 277 | */ 278 | private function setMessage(string $message, bool $success) 279 | { 280 | $this->message = $message; 281 | $this->success = $success; 282 | } 283 | 284 | /** 285 | * @param array $options 286 | * @return void 287 | */ 288 | private function validateOptions(array $options) 289 | { 290 | if (!isset($options['cacheDir']) && $options['drive'] === 'file') { 291 | $this->logger->debug("The 'cacheDir' option is required from file driver."); 292 | throw CacheFileException::create("The 'cacheDir' option is required."); 293 | } 294 | $this->options = $options; 295 | } 296 | 297 | /** 298 | * @param string $cacheDir 299 | * @return void 300 | */ 301 | private function initializeCacheDir(string $cacheDir) 302 | { 303 | $this->cacheDir = realpath($cacheDir) ?: ""; 304 | $this->fileManager->createDirectory($cacheDir); 305 | } 306 | 307 | /** 308 | * @param array $options 309 | * @return void 310 | */ 311 | private function handleAutoFlush(array $options) 312 | { 313 | if (isset($options['flushAfter'])) { 314 | $this->scheduleFlush($options['flushAfter']); 315 | } 316 | } 317 | 318 | /** 319 | * @param string $flushAfter 320 | * @return void 321 | */ 322 | private function scheduleFlush(string $flushAfter) 323 | { 324 | $flushAfterSeconds = CacheFileHelper::convertExpirationToSeconds($flushAfter); 325 | 326 | if(!$this->fileManager->fileExists($this->lastFlushTimeFile)) { 327 | $this->fileManager->writeFile($this->lastFlushTimeFile, time()); 328 | return; 329 | } 330 | 331 | $lastFlushTime = (int) $this->fileManager->readFile($this->lastFlushTimeFile); 332 | 333 | if ((time() - $lastFlushTime) >= $flushAfterSeconds) { 334 | $this->flushCache(); 335 | $this->fileManager->writeFile($this->lastFlushTimeFile, time()); 336 | } 337 | } 338 | 339 | /** 340 | * @param string $cacheFile 341 | * @param integer $ttl 342 | * @return boolean 343 | */ 344 | private function isCacheValid(string $cacheFile, int $ttl) 345 | { 346 | return file_exists($cacheFile) && (filemtime($cacheFile) > (time() - $ttl)); 347 | } 348 | } -------------------------------------------------------------------------------- /src/CacheStore/RedisCacheStore.php: -------------------------------------------------------------------------------- 1 | 15 | * @package Silviooosilva\CacheerPhp 16 | */ 17 | class RedisCacheStore implements CacheerInterface 18 | { 19 | /** @var */ 20 | private $redis; 21 | 22 | /** @param string $namespace */ 23 | private string $namespace = ''; 24 | 25 | /** 26 | * @var CacheLogger 27 | */ 28 | private $logger = null; 29 | 30 | /** 31 | * @var string 32 | */ 33 | private string $message = ''; 34 | 35 | /** 36 | * @var boolean 37 | */ 38 | private bool $success = false; 39 | 40 | /** 41 | * @return void 42 | */ 43 | public function __construct(string $logPath) 44 | { 45 | $this->redis = RedisCacheManager::connect(); 46 | $this->logger = new CacheLogger($logPath); 47 | } 48 | 49 | /** 50 | * @param string $cacheKey 51 | * @param mixed $cacheData 52 | * @param string $namespace 53 | * @return void 54 | */ 55 | public function appendCache(string $cacheKey, mixed $cacheData, string $namespace = '') 56 | { 57 | $cacheFullKey = $this->buildKey($cacheKey, $namespace); 58 | $existingData = $this->getCache($cacheFullKey); 59 | 60 | $mergedCacheData = CacheRedisHelper::arrayIdentifier($existingData, $cacheData); 61 | 62 | $serializedData = CacheRedisHelper::serialize($mergedCacheData); 63 | 64 | if ($this->redis->set($cacheFullKey, $serializedData)) { 65 | $this->setMessage("Cache appended successfully", true); 66 | } else { 67 | $this->setMessage("Something went wrong. Please, try again.", false); 68 | } 69 | 70 | $this->logger->debug("{$this->getMessage()} from redis driver."); 71 | } 72 | 73 | /** 74 | * @param string $key 75 | * @param string $namespace 76 | * @return string 77 | */ 78 | private function buildKey(string $key, string $namespace) 79 | { 80 | return $this->namespace . ($namespace ? $namespace . ':' : '') . $key; 81 | } 82 | 83 | /** 84 | * @param string $cacheKey 85 | * @param string $namespace 86 | * @return void 87 | */ 88 | public function clearCache(string $cacheKey, string $namespace = '') 89 | { 90 | $cacheFullKey = $this->buildKey($cacheKey, $namespace); 91 | 92 | if ($this->redis->del($cacheFullKey) > 0) { 93 | $this->setMessage("Cache cleared successfully", true); 94 | } else { 95 | $this->setMessage("Something went wrong. Please, try again.", false); 96 | } 97 | 98 | $this->logger->debug("{$this->getMessage()} from redis driver."); 99 | } 100 | 101 | /** 102 | * @return void 103 | */ 104 | public function flushCache() 105 | { 106 | if ($this->redis->flushall()) { 107 | $this->setMessage("Cache flushed successfully", true); 108 | } else { 109 | $this->setMessage("Something went wrong. Please, try again.", false); 110 | } 111 | 112 | $this->logger->debug("{$this->getMessage()} from redis driver."); 113 | } 114 | 115 | /** 116 | * @param string $cacheKey 117 | * @param string $namespace 118 | * @param string|int $ttl 119 | * @return mixed 120 | */ 121 | public function getCache(string $cacheKey, string $namespace = '', string|int $ttl = 3600) 122 | { 123 | $fullCacheKey = $this->buildKey($cacheKey, $namespace); 124 | $cacheData = $this->redis->get($fullCacheKey); 125 | 126 | if ($cacheData) { 127 | $this->setMessage("Cache retrieved successfully", true); 128 | $this->logger->debug("{$this->getMessage()} from redis driver."); 129 | return CacheRedisHelper::serialize($cacheData, false); 130 | } 131 | 132 | $this->setMessage("CacheData not found, does not exists or expired", false); 133 | $this->logger->info("{$this->getMessage()} from redis driver."); 134 | } 135 | 136 | /** 137 | * @return string 138 | */ 139 | public function getMessage() 140 | { 141 | return $this->message; 142 | } 143 | 144 | /** 145 | * @param string $fullKey 146 | * @return string|null 147 | */ 148 | private function getDump(string $fullKey) 149 | { 150 | return $this->redis->dump($fullKey); 151 | } 152 | 153 | /** 154 | * @param string $cacheKey 155 | * @param string $namespace 156 | * @return void 157 | */ 158 | public function has(string $cacheKey, string $namespace = '') 159 | { 160 | $cacheFullKey = $this->buildKey($cacheKey, $namespace); 161 | 162 | if ($this->redis->exists($cacheFullKey) > 0) { 163 | $this->setMessage("Cache Key: {$cacheKey} exists!", true); 164 | } else { 165 | $this->setMessage("Cache Key: {$cacheKey} does not exists!", false); 166 | } 167 | 168 | $this->logger->debug("{$this->getMessage()} from redis driver."); 169 | } 170 | 171 | /** 172 | * @return boolean 173 | */ 174 | public function isSuccess() 175 | { 176 | return $this->success; 177 | } 178 | 179 | /** 180 | * @param array $batchItems 181 | * @param string $namespace 182 | * @return void 183 | */ 184 | private function processBatchItems(array $batchItems, string $namespace) 185 | { 186 | foreach ($batchItems as $item) { 187 | CacheRedisHelper::validateCacheItem($item); 188 | $cacheKey = $item['cacheKey']; 189 | $cacheData = $item['cacheData']; 190 | $mergedData = CacheRedisHelper::mergeCacheData($cacheData); 191 | $this->putCache($cacheKey, $mergedData, $namespace); 192 | } 193 | } 194 | 195 | /** 196 | * Armazena um item no cache Redis, com suporte a namespace e TTL opcional. 197 | * 198 | * @param string $cacheKey 199 | * @param mixed $cacheData 200 | * @param string $namespace 201 | * @param string|int|null $ttl 202 | * @return mixed 203 | */ 204 | public function putCache(string $cacheKey, mixed $cacheData, string $namespace = '', string|int|null $ttl = null) 205 | { 206 | $cacheFullKey = $this->buildKey($cacheKey, $namespace); 207 | $serializedData = CacheRedisHelper::serialize($cacheData); 208 | 209 | $result = $ttl ? $this->redis->setex($cacheFullKey, (int) $ttl, $serializedData) 210 | : $this->redis->set($cacheFullKey, $serializedData); 211 | 212 | if ($result) { 213 | $this->setMessage("Cache stored successfully", true); 214 | } else { 215 | $this->setMessage("Failed to store cache", false); 216 | } 217 | 218 | $this->logger->debug("{$this->getMessage()} from Redis driver."); 219 | return $result; 220 | } 221 | 222 | /** 223 | * @param array $items 224 | * @param string $namespace 225 | * @param int $batchSize 226 | * @return void 227 | */ 228 | public function putMany(array $items, string $namespace = '', int $batchSize = 100) 229 | { 230 | $processedCount = 0; 231 | $itemCount = count($items); 232 | 233 | while ($processedCount < $itemCount) { 234 | $batchItems = array_slice($items, $processedCount, $batchSize); 235 | $this->processBatchItems($batchItems, $namespace); 236 | $processedCount += count($batchItems); 237 | } 238 | } 239 | 240 | /** 241 | * @param string $cacheKey 242 | * @param string|int $ttl 243 | * @param string $namespace 244 | * @return void 245 | */ 246 | public function renewCache(string $cacheKey, string|int $ttl, string $namespace = '') 247 | { 248 | $cacheFullKey = $this->buildKey($cacheKey, $namespace); 249 | $dump = $this->getDump($cacheFullKey); 250 | 251 | if (!$dump) { 252 | $this->setMessage("Cache Key: {$cacheKey} not found.", false); 253 | $this->logger->warning("{$this->getMessage()} from Redis driver."); 254 | return; 255 | } 256 | 257 | $this->clearCache($cacheFullKey); 258 | 259 | if ($this->restoreKey($cacheFullKey, $ttl, $dump)) { 260 | $this->setMessage("Cache Key: {$cacheKey} renewed successfully.", true); 261 | $this->logger->debug("{$this->getMessage()} from Redis driver."); 262 | } else { 263 | $this->setMessage("Failed to renew cache key: {$cacheKey}.", false); 264 | $this->logger->error("{$this->getMessage()} from Redis driver."); 265 | } 266 | } 267 | 268 | /** 269 | * @param string $fullKey 270 | * @param string|int $ttl 271 | * @param mixed $dump 272 | * @return bool 273 | */ 274 | private function restoreKey(string $fullKey, string|int $ttl, mixed $dump) 275 | { 276 | try { 277 | $this->redis->restore($fullKey, $ttl * 1000, $dump, 'REPLACE'); 278 | return true; 279 | } catch (Exception $e) { 280 | throw CacheRedisException::create($e->getMessage()); 281 | } 282 | } 283 | 284 | /** 285 | * @param string $message 286 | * @param boolean $success 287 | * @return void 288 | */ 289 | private function setMessage(string $message, bool $success) 290 | { 291 | $this->message = $message; 292 | $this->success = $success; 293 | } 294 | } -------------------------------------------------------------------------------- /src/Cacheer.php: -------------------------------------------------------------------------------- 1 | 20 | * @package Silviooosilva\CacheerPhp 21 | */ 22 | final class Cacheer implements CacheerInterface 23 | { 24 | /** 25 | * @var string 26 | */ 27 | private string $message; 28 | 29 | /** 30 | * @var boolean 31 | */ 32 | private bool $success; 33 | 34 | /** 35 | * @var boolean 36 | */ 37 | private bool $formatted = false; 38 | 39 | /** 40 | * @var bool 41 | */ 42 | private bool $compression = false; 43 | 44 | /** 45 | * @var string|null 46 | */ 47 | private ?string $encryptionKey = null; 48 | 49 | /** 50 | * @var FileCacheStore|DatabaseCacheStore|RedisCacheStore|ArrayCacheStore 51 | */ 52 | public $cacheStore; 53 | 54 | /** 55 | * @var array 56 | */ 57 | public array $options = []; 58 | 59 | public function __construct(array $options = [], $formatted = false) 60 | { 61 | $this->formatted = $formatted; 62 | $this->validateOptions($options); 63 | $this->setDriver()->useDefaultDriver(); 64 | } 65 | 66 | /** 67 | * @param string $cacheKey 68 | * @param mixed $cacheData 69 | * @param string $namespace 70 | * @param int|string $ttl 71 | * @return bool 72 | */ 73 | public function add(string $cacheKey, mixed $cacheData, string $namespace = '', int|string $ttl = 3600) 74 | { 75 | if (!empty($this->getCache($cacheKey, $namespace))) { 76 | return true; 77 | } 78 | 79 | $this->putCache($cacheKey, $cacheData, $namespace, $ttl); 80 | $this->setMessage($this->getMessage(), $this->isSuccess()); 81 | 82 | return false; 83 | } 84 | 85 | /** 86 | * @param string $cacheKey 87 | * @param mixed $cacheData 88 | * @param string $namespace 89 | * @return void 90 | */ 91 | public function appendCache(string $cacheKey, mixed $cacheData, string $namespace = '') 92 | { 93 | $this->cacheStore->appendCache($cacheKey, $cacheData, $namespace); 94 | $this->setMessage($this->cacheStore->getMessage(), $this->cacheStore->isSuccess()); 95 | } 96 | 97 | /** 98 | * @param string $cacheKey 99 | * @param string $namespace 100 | * @return void 101 | */ 102 | public function clearCache(string $cacheKey, string $namespace = '') 103 | { 104 | $this->cacheStore->clearCache($cacheKey, $namespace); 105 | $this->setMessage($this->cacheStore->getMessage(), $this->cacheStore->isSuccess()); 106 | } 107 | 108 | /** 109 | * @param string $cacheKey 110 | * @param int $amount 111 | * @param string $namespace 112 | * @return bool 113 | */ 114 | public function decrement(string $cacheKey, int $amount = 1, string $namespace = '') 115 | { 116 | return $this->increment($cacheKey, ($amount * -1), $namespace); 117 | } 118 | 119 | /** 120 | * @param string $cacheKey 121 | * @param mixed $cacheData 122 | * @return void 123 | */ 124 | public function forever(string $cacheKey, mixed $cacheData) 125 | { 126 | $this->putCache($cacheKey, $cacheData, ttl: 31536000 * 1000); 127 | $this->setMessage($this->getMessage(), $this->isSuccess()); 128 | } 129 | 130 | /** 131 | * @return void 132 | */ 133 | public function flushCache() 134 | { 135 | $this->cacheStore->flushCache(); 136 | $this->setMessage($this->cacheStore->getMessage(), $this->cacheStore->isSuccess()); 137 | } 138 | 139 | /** 140 | * @param string $cacheKey 141 | * @param string $namespace 142 | * @return mixed 143 | */ 144 | public function getAndForget(string $cacheKey, string $namespace = '') 145 | { 146 | $cachedData = $this->getCache($cacheKey, $namespace); 147 | 148 | if (!empty($cachedData)) { 149 | $this->setMessage("Cache retrieved and deleted successfully!", true); 150 | $this->clearCache($cacheKey, $namespace); 151 | return $cachedData; 152 | } 153 | 154 | return null; 155 | } 156 | 157 | /** 158 | * @param string $cacheKey 159 | * @param string $namespace 160 | * @param string|int $ttl 161 | * @return CacheDataFormatter|mixed 162 | */ 163 | public function getCache(string $cacheKey, string $namespace = '', string|int $ttl = 3600) 164 | { 165 | $cacheData = $this->cacheStore->getCache($cacheKey, $namespace, $ttl); 166 | $this->setMessage($this->cacheStore->getMessage(), $this->cacheStore->isSuccess()); 167 | 168 | if ($this->cacheStore->isSuccess() && ($this->compression || $this->encryptionKey !== null)) { 169 | $cacheData = CacheerHelper::recoverFromStorage($cacheData, $this->compression, $this->encryptionKey); 170 | } 171 | 172 | return $this->formatted ? new CacheDataFormatter($cacheData) : $cacheData; 173 | } 174 | 175 | /** 176 | * @param string $cacheKey 177 | * @param string $namespace 178 | * @return void 179 | */ 180 | public function has(string $cacheKey, string $namespace = '') 181 | { 182 | $this->cacheStore->has($cacheKey, $namespace); 183 | $this->setMessage($this->cacheStore->getMessage(), $this->cacheStore->isSuccess()); 184 | } 185 | 186 | /** 187 | * @param string $cacheKey 188 | * @param int $amount 189 | * @param string $namespace 190 | * @return bool 191 | */ 192 | public function increment(string $cacheKey, int $amount = 1, string $namespace = '') 193 | { 194 | $cacheData = $this->getCache($cacheKey, $namespace); 195 | 196 | if(!empty($cacheData) && is_numeric($cacheData)) { 197 | $this->putCache($cacheKey, (int)($cacheData + $amount), $namespace); 198 | $this->setMessage($this->getMessage(), $this->isSuccess()); 199 | return true; 200 | } 201 | 202 | return false; 203 | } 204 | 205 | /** 206 | * @return boolean 207 | */ 208 | public function isSuccess() 209 | { 210 | return $this->success; 211 | } 212 | 213 | /** 214 | * @param string $cacheKey 215 | * @param mixed $cacheData 216 | * @param string $namespace 217 | * @param string|int $ttl 218 | * @return void 219 | */ 220 | public function putCache(string $cacheKey, mixed $cacheData, string $namespace = '', string|int $ttl = 3600) 221 | { 222 | $data = CacheerHelper::prepareForStorage($cacheData, $this->compression, $this->encryptionKey); 223 | $this->cacheStore->putCache($cacheKey, $data, $namespace, $ttl); 224 | $this->setMessage($this->cacheStore->getMessage(), $this->cacheStore->isSuccess()); 225 | } 226 | 227 | /** 228 | * @param array $items 229 | * @param string $namespace 230 | * @param integer $batchSize 231 | * @return void 232 | */ 233 | public function putMany(array $items, string $namespace = '', int $batchSize = 100) 234 | { 235 | $this->cacheStore->putMany($items, $namespace, $batchSize); 236 | } 237 | 238 | /** 239 | * @param string $cacheKey 240 | * @param string|int $ttl 241 | * @param string $namespace 242 | * @return void 243 | */ 244 | public function renewCache(string $cacheKey, string|int $ttl = 3600, string $namespace = '') 245 | { 246 | $this->cacheStore->renewCache($cacheKey, $ttl, $namespace); 247 | 248 | if ($this->cacheStore->isSuccess()) { 249 | $this->setMessage($this->cacheStore->getMessage(), $this->cacheStore->isSuccess()); 250 | } else { 251 | $this->setMessage($this->cacheStore->getMessage(), $this->cacheStore->isSuccess()); 252 | } 253 | } 254 | 255 | /** 256 | * @param string $cacheKey 257 | * @param int|string $ttl 258 | * @param Closure $callback 259 | * @return mixed 260 | */ 261 | public function remember(string $cacheKey, int|string $ttl, Closure $callback) 262 | { 263 | $cachedData = $this->getCache($cacheKey, ttl: $ttl); 264 | 265 | if(!empty($cachedData)) { 266 | return $cachedData; 267 | } 268 | 269 | $cacheData = $callback(); 270 | $this->putCache($cacheKey, $cacheData, ttl: $ttl); 271 | $this->setMessage($this->getMessage(), $this->isSuccess()); 272 | 273 | return $cacheData; 274 | } 275 | 276 | /** 277 | * @param string $cacheKey 278 | * @param Closure $callback 279 | * @return mixed 280 | */ 281 | public function rememberForever(string $cacheKey, Closure $callback) 282 | { 283 | return $this->remember($cacheKey, 31536000 * 1000, $callback); 284 | } 285 | 286 | /** 287 | * @return CacheConfig 288 | */ 289 | public function setConfig() 290 | { 291 | return new CacheConfig($this); 292 | } 293 | 294 | /** 295 | * @return CacheDriver 296 | */ 297 | public function setDriver() 298 | { 299 | return new CacheDriver($this); 300 | } 301 | 302 | /** 303 | * @param string $message 304 | * @param boolean $success 305 | * @return void 306 | */ 307 | private function setMessage(string $message, bool $success) 308 | { 309 | $this->message = $message; 310 | $this->success = $success; 311 | } 312 | 313 | /** 314 | * @return string 315 | */ 316 | public function getMessage() 317 | { 318 | return $this->message; 319 | } 320 | 321 | /** 322 | * @return void 323 | */ 324 | public function useFormatter() 325 | { 326 | $this->formatted = !$this->formatted; 327 | } 328 | 329 | /** 330 | * @param array $options 331 | * @return void 332 | */ 333 | private function validateOptions(array $options) 334 | { 335 | $this->options = $options; 336 | } 337 | 338 | /** 339 | * Enable or disable data compression 340 | * 341 | * @param bool $status 342 | * @return $this 343 | */ 344 | public function useCompression(bool $status = true) 345 | { 346 | $this->compression = $status; 347 | return $this; 348 | } 349 | 350 | /** 351 | * Enable encryption for cached data 352 | * 353 | * @param string $key 354 | * @return $this 355 | */ 356 | public function useEncryption(string $key) 357 | { 358 | $this->encryptionKey = $key; 359 | return $this; 360 | } 361 | } 362 | -------------------------------------------------------------------------------- /src/Config/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silviooosilva/CacheerPHP/29b1f60e2032cabd5048ef0b40c389f2be3d4384/src/Config/.gitignore -------------------------------------------------------------------------------- /src/Config/Option/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silviooosilva/CacheerPHP/29b1f60e2032cabd5048ef0b40c389f2be3d4384/src/Config/Option/.gitignore -------------------------------------------------------------------------------- /src/Config/Option/Builder/OptionBuilder.php: -------------------------------------------------------------------------------- 1 | 10 | * @package Silviooosilva\CacheerPhp 11 | */ 12 | class OptionBuilder 13 | { 14 | /** 15 | * @return FileOptionBuilder 16 | */ 17 | public static function forFile() 18 | { 19 | return new FileOptionBuilder(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Core/Connect.php: -------------------------------------------------------------------------------- 1 | 12 | * @package Silviooosilva\CacheerPhp 13 | */ 14 | class Connect 15 | { 16 | public static string $connection = 'sqlite'; 17 | private static ?PDOException $error = null; 18 | 19 | 20 | /** 21 | * @param array|null $database 22 | * @return PDO|null 23 | */ 24 | public static function getInstance(?array $database = null) 25 | { 26 | $pdo = ConnectionFactory::createConnection($database); 27 | if ($pdo) { 28 | MigrationManager::migrate($pdo); 29 | } 30 | return $pdo; 31 | } 32 | 33 | /** 34 | * @param string $connection 35 | * @return void 36 | */ 37 | public static function setConnection(string $connection) 38 | { 39 | $drivers = ['mysql', 'sqlite', 'pgsql']; 40 | if (!in_array($connection, $drivers)) { 41 | throw ConnectionException::create("Only ['MySQL(mysql)', 'SQLite(sqlite)', 'PgSQL(pgsql)'] are available at the moment..."); 42 | } 43 | self::$connection = $connection; 44 | } 45 | 46 | /** 47 | * @return string 48 | */ 49 | public static function getConnection() 50 | { 51 | return self::$connection; 52 | } 53 | 54 | /** 55 | * @return PDOException|null 56 | */ 57 | public static function getError() 58 | { 59 | return self::$error; 60 | } 61 | 62 | private function __construct() {} 63 | private function __clone() {} 64 | } 65 | -------------------------------------------------------------------------------- /src/Core/ConnectionFactory.php: -------------------------------------------------------------------------------- 1 | 12 | * @package Silviooosilva\CacheerPhp 13 | */ 14 | class ConnectionFactory 15 | { 16 | 17 | /** 18 | * @param array|null $database 19 | * @return PDO|null 20 | */ 21 | public static function createConnection(?array $database = null) 22 | { 23 | $dbConf = $database ?? CACHEER_DATABASE_CONFIG[Connect::getConnection()]; 24 | 25 | if ($dbConf['driver'] === 'sqlite') { 26 | $dbName = $dbConf['dbname']; 27 | $dbDsn = $dbConf['driver'] . ':' . $dbName; 28 | } else { 29 | $dbName = "{$dbConf['driver']}-{$dbConf['dbname']}@{$dbConf['host']}"; 30 | $dbDsn = "{$dbConf['driver']}:host={$dbConf['host']};dbname={$dbConf['dbname']};port={$dbConf['port']}"; 31 | } 32 | 33 | try { 34 | $options = $dbConf['options'] ?? []; 35 | foreach ($options as $key => $value) { 36 | if (is_string($value) && defined($value)) { 37 | $options[$key] = constant($value); 38 | } 39 | } 40 | return new PDO($dbDsn, $dbConf['username'] ?? null, $dbConf['passwd'] ?? null, $options); 41 | } catch (PDOException $exception) { 42 | throw ConnectionException::create($exception->getMessage(), $exception->getCode(), $exception->getPrevious()); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Core/MigrationManager.php: -------------------------------------------------------------------------------- 1 | 11 | * @package Silviooosilva\CacheerPhp 12 | */ 13 | class MigrationManager 14 | { 15 | /** 16 | * @param PDO $connection 17 | * @return void 18 | */ 19 | public static function migrate(PDO $connection) 20 | { 21 | try { 22 | self::prepareDatabase($connection); 23 | $queries = self::getMigrationQueries($connection); 24 | foreach ($queries as $query) { 25 | if (trim($query)) { 26 | $connection->exec($query); 27 | } 28 | } 29 | } catch (PDOException $exception) { 30 | throw new PDOException($exception->getMessage(), $exception->getCode()); 31 | } 32 | } 33 | 34 | /** 35 | * @param PDO $connection 36 | * @return void 37 | */ 38 | private static function prepareDatabase(PDO $connection): void 39 | { 40 | $driver = $connection->getAttribute(PDO::ATTR_DRIVER_NAME); 41 | if ($driver !== 'sqlite') { 42 | $dbname = CACHEER_DATABASE_CONFIG[Connect::getConnection()]['dbname']; 43 | $connection->exec("USE $dbname"); 44 | } 45 | } 46 | 47 | /** 48 | * @param PDO $connection 49 | * @return array 50 | */ 51 | private static function getMigrationQueries(PDO $connection): array 52 | { 53 | $driver = $connection->getAttribute(PDO::ATTR_DRIVER_NAME); 54 | $createdAtDefault = ($driver === 'pgsql') ? 'DEFAULT NOW()' : 'DEFAULT CURRENT_TIMESTAMP'; 55 | 56 | if ($driver === 'sqlite') { 57 | $query = " 58 | CREATE TABLE IF NOT EXISTS cacheer_table ( 59 | id INTEGER PRIMARY KEY AUTOINCREMENT, 60 | cacheKey VARCHAR(255) NOT NULL, 61 | cacheData TEXT NOT NULL, 62 | cacheNamespace VARCHAR(255), 63 | expirationTime DATETIME NOT NULL, 64 | created_at DATETIME $createdAtDefault, 65 | UNIQUE(cacheKey, cacheNamespace) 66 | ); 67 | CREATE INDEX IF NOT EXISTS idx_cacheer_cacheKey ON cacheer_table (cacheKey); 68 | CREATE INDEX IF NOT EXISTS idx_cacheer_cacheNamespace ON cacheer_table (cacheNamespace); 69 | CREATE INDEX IF NOT EXISTS idx_cacheer_expirationTime ON cacheer_table (expirationTime); 70 | CREATE INDEX IF NOT EXISTS idx_cacheer_key_namespace ON cacheer_table (cacheKey, cacheNamespace); 71 | "; 72 | } elseif ($driver === 'pgsql') { 73 | $query = " 74 | CREATE TABLE IF NOT EXISTS cacheer_table ( 75 | id SERIAL PRIMARY KEY, 76 | cacheKey VARCHAR(255) NOT NULL, 77 | cacheData TEXT NOT NULL, 78 | cacheNamespace VARCHAR(255), 79 | expirationTime TIMESTAMP NOT NULL, 80 | created_at TIMESTAMP $createdAtDefault, 81 | UNIQUE(cacheKey, cacheNamespace) 82 | ); 83 | CREATE INDEX IF NOT EXISTS idx_cacheer_cacheKey ON cacheer_table (cacheKey); 84 | CREATE INDEX IF NOT EXISTS idx_cacheer_cacheNamespace ON cacheer_table (cacheNamespace); 85 | CREATE INDEX IF NOT EXISTS idx_cacheer_expirationTime ON cacheer_table (expirationTime); 86 | CREATE INDEX IF NOT EXISTS idx_cacheer_key_namespace ON cacheer_table (cacheKey, cacheNamespace); 87 | "; 88 | } else { 89 | $query = " 90 | CREATE TABLE IF NOT EXISTS cacheer_table ( 91 | id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, 92 | cacheKey VARCHAR(255) NOT NULL, 93 | cacheData LONGTEXT NOT NULL, 94 | cacheNamespace VARCHAR(255) NULL, 95 | expirationTime DATETIME NOT NULL, 96 | created_at TIMESTAMP $createdAtDefault, 97 | UNIQUE KEY unique_cache_key_namespace (cacheKey, cacheNamespace), 98 | KEY idx_cacheer_cacheKey (cacheKey), 99 | KEY idx_cacheer_cacheNamespace (cacheNamespace), 100 | KEY idx_cacheer_expirationTime (expirationTime), 101 | KEY idx_cacheer_key_namespace (cacheKey, cacheNamespace) 102 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; 103 | "; 104 | } 105 | return array_filter(array_map('trim', explode(';', $query))); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/Exceptions/BaseException.php: -------------------------------------------------------------------------------- 1 | details = $details; 21 | } 22 | 23 | /** 24 | * @return array 25 | * */ 26 | public function getDetails() 27 | { 28 | return $this->details; 29 | } 30 | 31 | /** 32 | * @param array $details 33 | * */ 34 | public function setDetails(array $details) 35 | { 36 | $this->details = $details; 37 | } 38 | 39 | /** 40 | * @return array 41 | * */ 42 | public function toArray() 43 | { 44 | return [ 45 | 'type' => static::class, 46 | 'message' => $this->getMessage(), 47 | 'code' => $this->getCode(), 48 | 'details' => $this->getDetails(), 49 | 'file' => $this->getFile(), 50 | 'line' => $this->getLine(), 51 | 'trace' => $this->getTrace() 52 | ]; 53 | } 54 | 55 | /** 56 | * @return array 57 | * */ 58 | public function jsonSerialize(): array 59 | { 60 | return $this->toArray(); 61 | } 62 | 63 | /** 64 | * @return string 65 | * */ 66 | public function toJson(int $options = 0) 67 | { 68 | return json_encode($this->toArray(), $options | JSON_THROW_ON_ERROR); 69 | } 70 | 71 | /** 72 | * @return string 73 | * */ 74 | public function __toString() 75 | { 76 | return sprintf( 77 | "[%s] %s in %s on line %d\nDetails: %s", 78 | $this->getCode(), 79 | $this->getMessage(), 80 | $this->getFile(), 81 | $this->getLine(), 82 | json_encode($this->getDetails(), JSON_PRETTY_PRINT) 83 | ); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/Exceptions/CacheDatabaseException.php: -------------------------------------------------------------------------------- 1 | "; 12 | 13 | /** 14 | * @param string $message 15 | * @param int $code 16 | * @param Exception|null $previous 17 | * @param array $details 18 | * @return self 19 | */ 20 | public static function create(string $message = "", int $code = 0, ?Exception $previous = null, array $details = []) 21 | { 22 | return new self(self::getBefore() . ": " .$message, $code, $previous, $details); 23 | } 24 | 25 | 26 | /** 27 | * @return string 28 | */ 29 | public static function getBefore(): string 30 | { 31 | return self::$before; 32 | } 33 | 34 | /** 35 | * @return void 36 | */ 37 | public static function setBefore(string $text): void 38 | { 39 | self::$before = $text; 40 | } 41 | 42 | /* 43 | * @return array 44 | */ 45 | public function toArray() 46 | { 47 | return parent::toArray(); 48 | } 49 | 50 | /** 51 | * @return string 52 | */ 53 | public function jsonSerialize(): array 54 | { 55 | return parent::jsonSerialize(); 56 | } 57 | 58 | /** 59 | * @param int $options 60 | * @return string 61 | */ 62 | public function toJson(int $options = 0) 63 | { 64 | return parent::toJson($options); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/Exceptions/CacheFileException.php: -------------------------------------------------------------------------------- 1 | "; 10 | 11 | /** 12 | * @param string $message 13 | * @param int $code 14 | * @param Exception|null $previous 15 | * @param array $details 16 | * @return self 17 | */ 18 | public static function create(string $message = "", int $code = 0, ?Exception $previous = null, array $details = []) 19 | { 20 | return new self(self::getBefore() . ": " . $message, $code, $previous, $details); 21 | } 22 | 23 | /** 24 | * @return string 25 | */ 26 | public static function getBefore() 27 | { 28 | return self::$before; 29 | } 30 | 31 | /** 32 | * @param string $text 33 | */ 34 | public static function setBefore(string $text) 35 | { 36 | self::$before = $text; 37 | } 38 | 39 | /* 40 | * @return array 41 | */ 42 | public function toArray() 43 | { 44 | return parent::toArray(); 45 | } 46 | 47 | /** 48 | * @return string 49 | */ 50 | public function jsonSerialize(): array 51 | { 52 | return parent::jsonSerialize(); 53 | } 54 | 55 | /** 56 | * @param int $options 57 | * @return string 58 | */ 59 | public function toJson(int $options = 0) 60 | { 61 | return parent::toJson($options); 62 | } 63 | } 64 | 65 | -------------------------------------------------------------------------------- /src/Exceptions/CacheRedisException.php: -------------------------------------------------------------------------------- 1 | "; 10 | 11 | /** 12 | * @param string $message 13 | * @param int $code 14 | * @param Exception|null $previous 15 | * @param array $details 16 | * @return self 17 | */ 18 | public static function create(string $message = "", int $code = 0, ?Exception $previous = null, array $details = []) 19 | { 20 | return new self(self::getBefore() . ": " . $message, $code, $previous, $details); 21 | } 22 | 23 | /** 24 | * @return string 25 | */ 26 | public static function getBefore(): string 27 | { 28 | return self::$before; 29 | } 30 | 31 | /** 32 | * @param string $text 33 | */ 34 | public static function setBefore(string $text): void 35 | { 36 | self::$before = $text; 37 | } 38 | 39 | /* 40 | * @return array 41 | */ 42 | public function toArray() 43 | { 44 | return parent::toArray(); 45 | } 46 | 47 | /** 48 | * @return string 49 | */ 50 | public function jsonSerialize(): array 51 | { 52 | return parent::jsonSerialize(); 53 | } 54 | 55 | /** 56 | * @param int $options 57 | * @return string 58 | */ 59 | public function toJson(int $options = 0) 60 | { 61 | return parent::toJson($options); 62 | } 63 | } 64 | 65 | -------------------------------------------------------------------------------- /src/Exceptions/ConnectionException.php: -------------------------------------------------------------------------------- 1 | "; 10 | 11 | /** 12 | * @param string $message 13 | * @param int $code 14 | * @param Exception|null $previous 15 | * @param array $details 16 | * @return self 17 | */ 18 | public static function create(string $message = "", int $code = 0, ?Exception $previous = null, array $details = []) 19 | { 20 | return new self(self::getBefore() . ": " . $message, $code, $previous, $details); 21 | } 22 | 23 | /** 24 | * @return string 25 | */ 26 | public static function getBefore(): string 27 | { 28 | return self::$before; 29 | } 30 | 31 | /** 32 | * @param string $text 33 | */ 34 | public static function setBefore(string $text): void 35 | { 36 | self::$before = $text; 37 | } 38 | 39 | /* 40 | * @return array 41 | */ 42 | public function toArray() 43 | { 44 | return parent::toArray(); 45 | } 46 | 47 | /** 48 | * @return string 49 | */ 50 | public function jsonSerialize(): array 51 | { 52 | return parent::jsonSerialize(); 53 | } 54 | 55 | /** 56 | * @param int $options 57 | * @return string 58 | */ 59 | public function toJson(int $options = 0) 60 | { 61 | return parent::toJson($options); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/Helpers/CacheConfig.php: -------------------------------------------------------------------------------- 1 | 16 | * @package Silviooosilva\CacheerPhp 17 | */ 18 | class CacheConfig 19 | { 20 | 21 | /** 22 | * @var Cacheer 23 | */ 24 | protected $cacheer; 25 | 26 | public function __construct(Cacheer $cacheer) 27 | { 28 | $this->cacheer = $cacheer; 29 | $this->setTimeZone(date_default_timezone_get()); 30 | } 31 | 32 | /** 33 | * @param string $timezone 34 | * @return $this 35 | */ 36 | public function setTimeZone($timezone) 37 | { 38 | /** 39 | * Certifique-se de que o timezone fornecido é válido * 40 | * https://www.php.net/manual/en/timezones.php 41 | * */ 42 | 43 | if (in_array($timezone, timezone_identifiers_list())) { 44 | date_default_timezone_set($timezone); 45 | } 46 | return $this; 47 | } 48 | 49 | /** 50 | * @return CacheDriver 51 | */ 52 | public function setDriver() 53 | { 54 | return new CacheDriver($this->cacheer); 55 | } 56 | 57 | /** 58 | * @param string $path 59 | * @return mixed 60 | */ 61 | public function setLoggerPath(string $path) 62 | { 63 | 64 | $cacheDriver = $this->setDriver(); 65 | $cacheDriver->logPath = $path; 66 | 67 | $cacheDriverInstance = $this->cacheer->cacheStore; 68 | 69 | return match (get_class($cacheDriverInstance)) { 70 | FileCacheStore::class => $cacheDriver->useFileDriver(), 71 | RedisCacheStore::class => $cacheDriver->useRedisDriver(), 72 | ArrayCacheStore::class => $cacheDriver->useArrayDriver(), 73 | DatabaseCacheStore::class => $cacheDriver->useDatabaseDriver(), 74 | default => $cacheDriver->useDatabaseDriver(), 75 | }; 76 | } 77 | 78 | /** 79 | * @param string $driver 80 | * @return void 81 | */ 82 | public function setDatabaseConnection(string $driver) 83 | { 84 | Connect::setConnection($driver); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/Helpers/CacheDatabaseHelper.php: -------------------------------------------------------------------------------- 1 | 11 | * @package Silviooosilva\CacheerPhp 12 | */ 13 | class CacheDatabaseHelper 14 | { 15 | /** 16 | * @param array $item 17 | * @return void 18 | */ 19 | public static function validateCacheItem(array $item) 20 | { 21 | CacheerHelper::validateCacheItem( 22 | $item, 23 | fn($msg) => CacheDatabaseException::create($msg) 24 | ); 25 | } 26 | 27 | /** 28 | * @param array $options 29 | * @return array 30 | */ 31 | public static function mergeCacheData($cacheData) 32 | { 33 | return CacheerHelper::mergeCacheData($cacheData); 34 | } 35 | 36 | /** 37 | * @param mixed $currentCacheData 38 | * @param mixed $cacheData 39 | * @return array 40 | */ 41 | public static function arrayIdentifier(mixed $currentCacheData, mixed $cacheData) 42 | { 43 | return CacheerHelper::arrayIdentifier($currentCacheData, $cacheData); 44 | } 45 | } 46 | 47 | -------------------------------------------------------------------------------- /src/Helpers/CacheFileHelper.php: -------------------------------------------------------------------------------- 1 | 11 | * @package Silviooosilva\CacheerPhp 12 | */ 13 | class CacheFileHelper 14 | { 15 | 16 | /** 17 | * @param string $expiration 18 | * @return int 19 | */ 20 | public static function convertExpirationToSeconds(string $expiration) 21 | { 22 | $units = [ 23 | 'second' => 1, 24 | 'minute' => 60, 25 | 'hour' => 3600, 26 | 'day' => 86400, 27 | 'week' => 604800, 28 | 'month' => 2592000, 29 | 'year' => 31536000, 30 | ]; 31 | foreach ($units as $unit => $value) { 32 | if (strpos($expiration, $unit) !== false) { 33 | return (int)$expiration * $value; 34 | } 35 | } 36 | throw CacheFileException::create("Invalid expiration format"); 37 | } 38 | 39 | /** 40 | * @param array $options 41 | * @return array 42 | */ 43 | public static function mergeCacheData($cacheData) 44 | { 45 | return CacheerHelper::mergeCacheData($cacheData); 46 | } 47 | 48 | /** 49 | * @param array $item 50 | * @return void 51 | */ 52 | public static function validateCacheItem(array $item) 53 | { 54 | CacheerHelper::validateCacheItem( 55 | $item, 56 | fn($msg) => CacheFileException::create($msg) 57 | ); 58 | } 59 | 60 | /** 61 | * @param string|int $ttl 62 | * @param int $defaultTTL 63 | * @return mixed 64 | */ 65 | public static function ttl($ttl = null, ?int $defaultTTL = null) { 66 | if ($ttl) { 67 | $ttl = is_string($ttl) ? self::convertExpirationToSeconds($ttl) : $ttl; 68 | } else { 69 | $ttl = $defaultTTL; 70 | } 71 | return $ttl; 72 | } 73 | 74 | /** 75 | * @param mixed $currentCacheData 76 | * @param mixed $cacheData 77 | * @return array 78 | */ 79 | public static function arrayIdentifier(mixed $currentCacheData, mixed $cacheData) 80 | { 81 | return CacheerHelper::arrayIdentifier($currentCacheData, $cacheData); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/Helpers/CacheRedisHelper.php: -------------------------------------------------------------------------------- 1 | 11 | * @package Silviooosilva\CacheerPhp 12 | */ 13 | class CacheRedisHelper 14 | { 15 | 16 | /** 17 | * @param mixed $data 18 | * @param bool $serialize 19 | * @return mixed 20 | */ 21 | public static function serialize(mixed $data, bool $serialize = true) 22 | { 23 | if($serialize) { 24 | return serialize($data); 25 | } 26 | 27 | return unserialize($data); 28 | 29 | } 30 | 31 | /** 32 | * @param array $item 33 | * @return void 34 | */ 35 | public static function validateCacheItem(array $item) 36 | { 37 | CacheerHelper::validateCacheItem( 38 | $item, 39 | fn($msg) => CacheRedisException::create($msg) 40 | ); 41 | } 42 | 43 | /** 44 | * @param array $options 45 | * @return array 46 | */ 47 | public static function mergeCacheData($cacheData) 48 | { 49 | return CacheerHelper::mergeCacheData($cacheData); 50 | } 51 | 52 | /** 53 | * @param mixed $currentCacheData 54 | * @param mixed $cacheData 55 | * @return array 56 | */ 57 | public static function arrayIdentifier(mixed $currentCacheData, mixed $cacheData) 58 | { 59 | return CacheerHelper::arrayIdentifier($currentCacheData, $cacheData); 60 | } 61 | 62 | } 63 | 64 | -------------------------------------------------------------------------------- /src/Helpers/CacheerHelper.php: -------------------------------------------------------------------------------- 1 | 10 | * @package Silviooosilva\CacheerPhp 11 | */ 12 | class EnvHelper { 13 | 14 | /** 15 | * @return string 16 | */ 17 | public static function getRootPath() 18 | { 19 | // Tenta obter a raiz do projeto via Composer, se disponível 20 | if (class_exists(InstalledVersions::class)) { 21 | $rootPackage = InstalledVersions::getRootPackage(); 22 | if (!empty($rootPackage['install_path'])) { 23 | return rtrim($rootPackage['install_path'], DIRECTORY_SEPARATOR); 24 | } 25 | } 26 | 27 | // Fallback: sobe os diretórios a partir do __DIR__ procurando o .env.example 28 | $baseDir = __DIR__; 29 | while (!file_exists($baseDir . DIRECTORY_SEPARATOR . '.env.example') && $baseDir !== dirname($baseDir)) { 30 | $baseDir = dirname($baseDir); 31 | } 32 | 33 | return rtrim($baseDir, DIRECTORY_SEPARATOR); 34 | } 35 | 36 | /** 37 | * @return void 38 | */ 39 | public static function copyEnv() 40 | { 41 | $rootDir = self::getRootPath(); 42 | $envFile = $rootDir . '/.env'; 43 | $envExampleFile = $rootDir . '/.env.example'; 44 | 45 | if (!file_exists($envFile) && file_exists($envExampleFile)) { 46 | if (copy($envExampleFile, $envFile)) { 47 | echo ".env file created successfully from .env.example.\n"; 48 | } else { 49 | echo "Failed to create .env file from .env.example.\n"; 50 | } 51 | } 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/Helpers/SqliteHelper.php: -------------------------------------------------------------------------------- 1 | 9 | * @package Silviooosilva\CacheerPhp 10 | */ 11 | class SqliteHelper 12 | { 13 | 14 | /** 15 | * @param string $database 16 | * @param ?string $path 17 | * @return string 18 | */ 19 | public static function database(string $database = 'database.sqlite', ?string $path = null) 20 | { 21 | return self::getDynamicSqliteDbPath($database, $path); 22 | } 23 | 24 | /** 25 | * @param string $database 26 | * @param ?string $path 27 | * @return string 28 | */ 29 | private static function getDynamicSqliteDbPath(string $database, ?string $path = null) 30 | { 31 | $rootPath = EnvHelper::getRootPath(); 32 | $databaseDir = is_null($path) ? $rootPath . '/database' : $rootPath . '/' . $path; 33 | $dbFile = $databaseDir . '/' . self::checkExtension($database); 34 | 35 | if (!is_dir($databaseDir)) { 36 | self::createDatabaseDir($databaseDir); 37 | } 38 | if (!file_exists($dbFile)) { 39 | self::createDatabaseFile($dbFile); 40 | } 41 | 42 | return $dbFile; 43 | } 44 | 45 | /** 46 | * @param string $databaseDir 47 | * @return void 48 | */ 49 | private static function createDatabaseDir(string $databaseDir) 50 | { 51 | if (!is_dir($databaseDir)) { 52 | mkdir($databaseDir, 0755, true); 53 | } 54 | } 55 | 56 | /** 57 | * @param string $dbFile 58 | * @return void 59 | */ 60 | private static function createDatabaseFile(string $dbFile) 61 | { 62 | if (!file_exists($dbFile)) { 63 | file_put_contents($dbFile, ''); 64 | } 65 | } 66 | 67 | /** 68 | * @param string $database 69 | * @return string 70 | */ 71 | private static function checkExtension(string $database) 72 | { 73 | if (strpos($database, '.sqlite') === false) { 74 | return $database . '.sqlite'; 75 | } 76 | return $database; 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /src/Interface/CacheerInterface.php: -------------------------------------------------------------------------------- 1 | 8 | * @package Silviooosilva\CacheerPhp 9 | */ 10 | interface CacheerInterface 11 | { 12 | public function getCache(string $cacheKey, string $namespace = '', string|int $ttl = 3600); 13 | public function putCache(string $cacheKey, mixed $cacheData, string $namespace = '', int|string $ttl = 3600); 14 | public function flushCache(); 15 | public function clearCache(string $cacheKey, string $namespace = ''); 16 | public function has(string $cacheKey, string $namespace = ''); 17 | public function renewCache(string $cacheKey, int | string $ttl, string $namespace = ''); 18 | public function appendCache(string $cacheKey, mixed $cacheData, string $namespace = ''); 19 | public function putMany(array $items, string $namespace = '', int $batchSize = 100); 20 | } 21 | 22 | -------------------------------------------------------------------------------- /src/Repositories/CacheDatabaseRepository.php: -------------------------------------------------------------------------------- 1 | 11 | * @package Silviooosilva\CacheerPhp 12 | */ 13 | class CacheDatabaseRepository 14 | { 15 | 16 | /** @var PDO */ 17 | private $connection = null; 18 | 19 | public function __construct() 20 | { 21 | $this->connection = Connect::getInstance(); 22 | } 23 | 24 | 25 | /** 26 | * @param string $cacheKey 27 | * @param mixed $cacheData 28 | * @param string $namespace 29 | * @param string|int $ttl 30 | * @return bool 31 | */ 32 | public function store(string $cacheKey, mixed $cacheData, string $namespace, string|int $ttl = 3600) 33 | { 34 | if (!empty($this->retrieve($cacheKey, $namespace))) { 35 | return $this->update($cacheKey, $cacheData, $namespace); 36 | } 37 | 38 | $expirationTime = date('Y-m-d H:i:s', time() + $ttl); 39 | $createdAt = date('Y-m-d H:i:s'); 40 | 41 | $stmt = $this->connection->prepare( 42 | "INSERT INTO cacheer_table (cacheKey, cacheData, cacheNamespace, expirationTime, created_at) 43 | VALUES (:cacheKey, :cacheData, :namespace, :expirationTime, :createdAt)" 44 | ); 45 | $stmt->bindValue(':cacheKey', $cacheKey); 46 | $stmt->bindValue(':cacheData', $this->serialize($cacheData)); 47 | $stmt->bindValue(':namespace', $namespace); 48 | $stmt->bindValue(':expirationTime', $expirationTime); 49 | $stmt->bindValue(':createdAt', $createdAt); 50 | 51 | return $stmt->execute() && $stmt->rowCount() > 0; 52 | } 53 | 54 | /** 55 | * @param string $cacheKey 56 | * @param string $namespace 57 | * @return mixed 58 | */ 59 | public function retrieve(string $cacheKey, string $namespace = '') 60 | { 61 | $driver = $this->connection->getAttribute(PDO::ATTR_DRIVER_NAME); 62 | $nowFunction = $this->getCurrentDateTime($driver); 63 | 64 | $stmt = $this->connection->prepare( 65 | "SELECT cacheData FROM cacheer_table 66 | WHERE cacheKey = :cacheKey AND cacheNamespace = :namespace AND expirationTime > $nowFunction 67 | LIMIT 1" 68 | ); 69 | $stmt->bindValue(':cacheKey', $cacheKey); 70 | $stmt->bindValue(':namespace', $namespace); 71 | $stmt->execute(); 72 | 73 | $data = $stmt->fetch(PDO::FETCH_ASSOC); 74 | return (!empty($data)) ? $this->serialize($data['cacheData'], false) : null; 75 | } 76 | 77 | /** 78 | * @return string 79 | */ 80 | private function getUpdateQueryWithDriver() 81 | { 82 | $driver = $this->connection->getAttribute(PDO::ATTR_DRIVER_NAME); 83 | if ($driver === 'mysql' || $driver === 'mariadb') { 84 | return "UPDATE cacheer_table SET cacheData = :cacheData, cacheNamespace = :namespace WHERE cacheKey = :cacheKey LIMIT 1"; 85 | } 86 | return "UPDATE cacheer_table SET cacheData = :cacheData, cacheNamespace = :namespace WHERE cacheKey = :cacheKey"; 87 | } 88 | 89 | /** 90 | * @return string 91 | */ 92 | private function getDeleteQueryWithDriver() 93 | { 94 | $driver = $this->connection->getAttribute(PDO::ATTR_DRIVER_NAME); 95 | if ($driver === 'mysql' || $driver === 'mariadb') { 96 | return "DELETE FROM cacheer_table WHERE cacheKey = :cacheKey AND cacheNamespace = :namespace LIMIT 1"; 97 | } 98 | return "DELETE FROM cacheer_table WHERE cacheKey = :cacheKey AND cacheNamespace = :namespace"; 99 | } 100 | 101 | /** 102 | * @param string $cacheKey 103 | * @param mixed $cacheData 104 | * @param string $namespace 105 | * @return bool 106 | */ 107 | public function update(string $cacheKey, mixed $cacheData, string $namespace = '') 108 | { 109 | $query = $this->getUpdateQueryWithDriver(); 110 | $stmt = $this->connection->prepare($query); 111 | $stmt->bindValue(':cacheData', $this->serialize($cacheData)); 112 | $stmt->bindValue(':namespace', $namespace); 113 | $stmt->bindValue(':cacheKey', $cacheKey); 114 | $stmt->execute(); 115 | 116 | return $stmt->rowCount() > 0; 117 | } 118 | 119 | /** 120 | * @param string $cacheKey 121 | * @param string $namespace 122 | * @return bool 123 | */ 124 | public function clear(string $cacheKey, string $namespace = '') 125 | { 126 | $query = $this->getDeleteQueryWithDriver(); 127 | $stmt = $this->connection->prepare($query); 128 | $stmt->bindValue(':cacheKey', $cacheKey); 129 | $stmt->bindValue(':namespace', $namespace); 130 | $stmt->execute(); 131 | 132 | return $stmt->rowCount() > 0; 133 | } 134 | 135 | /** 136 | * @return string 137 | */ 138 | private function getRenewExpirationQueryWithDriver(): string 139 | { 140 | $driver = $this->connection->getAttribute(PDO::ATTR_DRIVER_NAME); 141 | if ($driver === 'sqlite') { 142 | return "UPDATE cacheer_table 143 | SET expirationTime = DATETIME(expirationTime, '+' || :ttl || ' seconds') 144 | WHERE cacheKey = :cacheKey AND cacheNamespace = :namespace AND expirationTime > :currentTime"; 145 | } 146 | return "UPDATE cacheer_table 147 | SET expirationTime = DATE_ADD(expirationTime, INTERVAL :ttl SECOND) 148 | WHERE cacheKey = :cacheKey AND cacheNamespace = :namespace AND expirationTime > :currentTime"; 149 | } 150 | 151 | /** 152 | * @param string $cacheKey 153 | * @param string $namespace 154 | * @param string $currentTime 155 | * @return bool 156 | */ 157 | private function hasValidCache(string $cacheKey, string $namespace, string $currentTime): bool 158 | { 159 | $stmt = $this->connection->prepare( 160 | "SELECT 1 FROM cacheer_table 161 | WHERE cacheKey = :cacheKey AND cacheNamespace = :namespace AND expirationTime > :currentTime 162 | LIMIT 1" 163 | ); 164 | $stmt->bindValue(':cacheKey', $cacheKey); 165 | $stmt->bindValue(':namespace', $namespace); 166 | $stmt->bindValue(':currentTime', $currentTime); 167 | $stmt->execute(); 168 | return $stmt->fetchColumn() !== false; 169 | } 170 | 171 | /** 172 | * @param string $cacheKey 173 | * @param string|int $ttl 174 | * @param string $namespace 175 | * @return bool 176 | */ 177 | public function renew(string $cacheKey, string|int $ttl, string $namespace = '') 178 | { 179 | $currentTime = date('Y-m-d H:i:s'); 180 | if (!$this->hasValidCache($cacheKey, $namespace, $currentTime)) { 181 | return false; 182 | } 183 | 184 | $query = $this->getRenewExpirationQueryWithDriver(); 185 | $stmt = $this->connection->prepare($query); 186 | $stmt->bindValue(':ttl', (int) $ttl, PDO::PARAM_INT); 187 | $stmt->bindValue(':cacheKey', $cacheKey); 188 | $stmt->bindValue(':namespace', $namespace); 189 | $stmt->bindValue(':currentTime', $currentTime); 190 | $stmt->execute(); 191 | 192 | return $stmt->rowCount() > 0; 193 | } 194 | 195 | /** 196 | * @return bool 197 | */ 198 | public function flush() 199 | { 200 | return $this->connection->exec("DELETE FROM cacheer_table") !== false; 201 | } 202 | 203 | /** 204 | * @param mixed $data 205 | * @return string 206 | */ 207 | private function serialize(mixed $data, bool $serialize = true) 208 | { 209 | return $serialize ? serialize($data) : unserialize($data); 210 | } 211 | 212 | /** 213 | * @param string $driver 214 | * @return string 215 | */ 216 | private function getCurrentDateTime(string $driver) 217 | { 218 | return ($driver === 'sqlite') ? "DATETIME('now', 'localtime')" : "NOW()"; 219 | } 220 | } 221 | -------------------------------------------------------------------------------- /src/Support/TimeBuilder.php: -------------------------------------------------------------------------------- 1 | 11 | * @package Silviooosilva\CacheerPhp 12 | */ 13 | class TimeBuilder 14 | { 15 | 16 | /** @param string $unit */ 17 | private string $unit; 18 | 19 | /** @param int $value */ 20 | private int $value; 21 | 22 | /** @param Closure $callback */ 23 | private Closure $callback; 24 | 25 | /** @param FileOptionBuilder */ 26 | private $builder = null; 27 | 28 | public function __construct(Closure $callback, $builder) 29 | { 30 | $this->callback = $callback; 31 | $this->builder = $builder; 32 | } 33 | 34 | /** 35 | * @param int $value 36 | * @return FileOptionBuilder|mixed 37 | */ 38 | public function second(int $value) 39 | { 40 | return $this->setTime($value, "seconds"); 41 | } 42 | 43 | /** 44 | * @param int $value 45 | * @return FileOptionBuilder|mixed 46 | */ 47 | public function minute(int $value) 48 | { 49 | return $this->setTime($value, "minutes"); 50 | } 51 | 52 | /** 53 | * @param int $value 54 | * @return FileOptionBuilder|mixed 55 | */ 56 | public function hour(int $value) 57 | { 58 | return $this->setTime($value, "hours"); 59 | } 60 | 61 | /** 62 | * @param int $value 63 | * @return FileOptionBuilder|mixed 64 | */ 65 | public function day(int $value) 66 | { 67 | return $this->setTime($value, "days"); 68 | } 69 | 70 | /** 71 | * @param int $value 72 | * @return FileOptionBuilder|mixed 73 | */ 74 | public function week(int $value) 75 | { 76 | return $this->setTime($value, "weeks"); 77 | } 78 | 79 | /** 80 | * @param int $value 81 | * @return FileOptionBuilder|mixed 82 | */ 83 | public function month(int $value) 84 | { 85 | return $this->setTime($value, "months"); 86 | } 87 | 88 | 89 | /** 90 | * @param int $value 91 | * @param string $unit 92 | * @return FileOptionBuilder 93 | */ 94 | private function setTime(int $value, string $unit) 95 | { 96 | 97 | $this->value = $value; 98 | $this->unit = $unit; 99 | ($this->callback)("{$value} {$unit}"); 100 | return $this->builder; 101 | } 102 | 103 | } 104 | -------------------------------------------------------------------------------- /src/Utils/CacheDataFormatter.php: -------------------------------------------------------------------------------- 1 | 8 | * @package Silviooosilva\CacheerPhp 9 | */ 10 | class CacheDataFormatter 11 | { 12 | /** @param mixed $data */ 13 | private mixed $data; 14 | 15 | public function __construct(mixed $data) 16 | { 17 | $this->data = $data; 18 | } 19 | 20 | /** 21 | * @return string|false 22 | */ 23 | public function toJson() 24 | { 25 | return json_encode( 26 | $this->data, 27 | JSON_PRETTY_PRINT | 28 | JSON_UNESCAPED_UNICODE | 29 | JSON_UNESCAPED_SLASHES 30 | ); 31 | } 32 | 33 | /** 34 | * @return array 35 | */ 36 | public function toArray() 37 | { 38 | return (array)$this->data; 39 | } 40 | 41 | /** 42 | * @return string 43 | */ 44 | public function toString() 45 | { 46 | return (string)$this->data; 47 | } 48 | 49 | /** 50 | * @return object 51 | */ 52 | public function toObject() 53 | { 54 | return (object)$this->data; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Utils/CacheDriver.php: -------------------------------------------------------------------------------- 1 | 17 | * @package Silviooosilva\CacheerPhp 18 | */ 19 | class CacheDriver 20 | { 21 | 22 | /** 23 | * @var Cacheer 24 | */ 25 | protected $cacheer; 26 | 27 | /** @param string $logPath */ 28 | public string $logPath = 'cacheer.log'; 29 | 30 | public function __construct(Cacheer $cacheer) 31 | { 32 | $this->cacheer = $cacheer; 33 | } 34 | 35 | /** 36 | * @return Cacheer 37 | */ 38 | public function useDatabaseDriver() 39 | { 40 | $this->cacheer->cacheStore = new DatabaseCacheStore($this->logPath); 41 | return $this->cacheer; 42 | } 43 | 44 | /** 45 | * @throws \Exception 46 | * @return Cacheer 47 | */ 48 | public function useFileDriver() 49 | { 50 | $this->cacheer->options['loggerPath'] = $this->logPath; 51 | $this->cacheer->cacheStore = new FileCacheStore($this->cacheer->options); 52 | return $this->cacheer; 53 | } 54 | 55 | /** 56 | * @return Cacheer 57 | */ 58 | public function useRedisDriver() 59 | { 60 | $this->cacheer->cacheStore = new RedisCacheStore($this->logPath); 61 | return $this->cacheer; 62 | } 63 | 64 | /** 65 | * @return Cacheer 66 | */ 67 | public function useArrayDriver() 68 | { 69 | $this->cacheer->cacheStore = new ArrayCacheStore($this->logPath); 70 | return $this->cacheer; 71 | } 72 | 73 | /** 74 | * @return Cacheer 75 | */ 76 | public function useDefaultDriver() 77 | { 78 | if (!isset($this->cacheer->options['cacheDir'])) { 79 | $projectRoot = EnvHelper::getRootPath(); 80 | $cacheDir = $projectRoot . DIRECTORY_SEPARATOR . "CacheerPHP" . DIRECTORY_SEPARATOR . "Cache"; 81 | if ($this->isDir($cacheDir)) { 82 | $this->cacheer->options['cacheDir'] = $cacheDir; 83 | } else { 84 | throw CacheFileException::create("Failed to create cache directory: " . $cacheDir); 85 | } 86 | } 87 | $this->useFileDriver(); 88 | return $this->cacheer; 89 | } 90 | 91 | /** 92 | * @param mixed $dirName 93 | * @return bool 94 | */ 95 | private function isDir(mixed $dirName) 96 | { 97 | if (is_dir($dirName)) { 98 | return true; 99 | } 100 | return mkdir($dirName, 0755, true); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/Utils/CacheLogger.php: -------------------------------------------------------------------------------- 1 | 9 | * @package Silviooosilva\CacheerPhp 10 | */ 11 | class CacheLogger 12 | { 13 | private $logFile; 14 | private $maxFileSize; // Tamanho máximo do arquivo em bytes (5MB) 15 | private $logLevel; 16 | private $logLevels = ['DEBUG', 'INFO', 'WARNING', 'ERROR']; 17 | 18 | public function __construct($logFile = 'cacheer.log', $maxFileSize = 5 * 1024 * 1024, $logLevel = 'DEBUG') 19 | { 20 | $this->logFile = $logFile; 21 | $this->maxFileSize = $maxFileSize; 22 | $this->logLevel = strtoupper($logLevel); 23 | } 24 | 25 | /** 26 | * @return void 27 | */ 28 | public function info($message) 29 | { 30 | $this->log('INFO', $message); 31 | } 32 | 33 | /** 34 | * @return void 35 | */ 36 | public function warning($message) 37 | { 38 | $this->log('WARNING', $message); 39 | } 40 | 41 | /** 42 | * @return void 43 | */ 44 | public function error($message) 45 | { 46 | $this->log('ERROR', $message); 47 | } 48 | 49 | /** 50 | * @return void 51 | */ 52 | public function debug($message) 53 | { 54 | $this->log('DEBUG', $message); 55 | } 56 | 57 | /** 58 | * @param mixed $level 59 | * @return string|int|false 60 | */ 61 | private function shouldLog(mixed $level) 62 | { 63 | return array_search($level, $this->logLevels) >= array_search($this->logLevel, $this->logLevels); 64 | } 65 | 66 | /** 67 | * @return void 68 | */ 69 | private function rotateLog() 70 | { 71 | if (file_exists($this->logFile) && filesize($this->logFile) >= $this->maxFileSize) { 72 | $date = date('Y-m-d_H-i-s'); 73 | rename($this->logFile, "cacheer_$date.log"); 74 | } 75 | } 76 | 77 | /** 78 | * @param mixed $level 79 | * @param string $message 80 | * @return void 81 | */ 82 | private function log($level, $message) 83 | { 84 | if (!$this->shouldLog($level)) { 85 | return; 86 | } 87 | 88 | $this->rotateLog(); 89 | 90 | $date = date('Y-m-d H:i:s'); 91 | $logMessage = "[$date] [$level] $message" . PHP_EOL; 92 | file_put_contents($this->logFile, $logMessage, FILE_APPEND); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /tests/Feature/OptionBuildTest.php: -------------------------------------------------------------------------------- 1 | cacheDir = __DIR__ . '/cache'; 16 | if (!file_exists($this->cacheDir) || !is_dir($this->cacheDir)) { 17 | mkdir($this->cacheDir, 0755, true); 18 | } 19 | 20 | $this->cache = new Cacheer(); 21 | } 22 | 23 | protected function tearDown(): void 24 | { 25 | $this->cache->flushCache(); 26 | } 27 | 28 | public function test_it_can_set_cache_directory() 29 | { 30 | $cacheDir = __DIR__ . "/cache"; 31 | 32 | $options = OptionBuilder::forFile() 33 | ->dir($cacheDir) 34 | ->build(); 35 | 36 | $this->assertArrayHasKey('cacheDir', $options); 37 | $this->assertEquals($cacheDir, $options['cacheDir']); 38 | } 39 | 40 | 41 | public function test_it_can_set_expiration_time() 42 | { 43 | 44 | $options = OptionBuilder::forFile() 45 | ->expirationTime('2 hours') 46 | ->build(); 47 | 48 | $this->assertArrayHasKey('expirationTime', $options); 49 | $this->assertEquals('2 hours', $options['expirationTime']); 50 | } 51 | 52 | public function test_it_can_set_flush_after() 53 | { 54 | $options = OptionBuilder::forFile() 55 | ->flushAfter('11 seconds') 56 | ->build(); 57 | 58 | $this->assertArrayHasKey('flushAfter', $options); 59 | $this->assertEquals('11 seconds', $options['flushAfter']); 60 | } 61 | 62 | public function test_it_can_set_multiple_options_together() 63 | { 64 | $cacheDir = __DIR__ . "/cache"; 65 | 66 | $options = OptionBuilder::forFile() 67 | ->dir($cacheDir) 68 | ->expirationTime('1 day') 69 | ->flushAfter('30 minutes') 70 | ->build(); 71 | 72 | $this->assertEquals([ 73 | 'cacheDir' => $cacheDir, 74 | 'expirationTime' => '1 day', 75 | 'flushAfter' => '30 minutes', 76 | ], $options); 77 | } 78 | 79 | public function test_it_allows_setting_expiration_time_with_timebuilder() 80 | { 81 | $options = OptionBuilder::forFile()->expirationTime()->week(1)->build(); 82 | $this->assertArrayHasKey('expirationTime', $options); 83 | $this->assertEquals('1 weeks', $options['expirationTime']); 84 | } 85 | 86 | public function test_it_allows_setting_flush_after_with_timebuilder() 87 | { 88 | $options = OptionBuilder::forFile()->flushAfter()->second(10)->build(); 89 | $this->assertArrayHasKey('flushAfter', $options); 90 | $this->assertEquals('10 seconds', $options['flushAfter']); 91 | } 92 | 93 | public function test_it_can_set_multiple_options_together_with_timebuilder() 94 | { 95 | $cacheDir = __DIR__ . "/cache"; 96 | $options = OptionBuilder::forFile() 97 | ->dir($cacheDir) 98 | ->expirationTime()->week(1) 99 | ->flushAfter()->minute(10) 100 | ->build(); 101 | 102 | $this->assertEquals([ 103 | 'cacheDir' => $cacheDir, 104 | 'expirationTime' => '1 weeks', 105 | 'flushAfter' => '10 minutes', 106 | ], $options); 107 | } 108 | 109 | public function test_it_returns_empty_array_when_no_options_are_set() 110 | { 111 | $options = OptionBuilder::forFile()->build(); 112 | $this->assertIsArray($options); 113 | $this->assertEmpty($options); 114 | } 115 | 116 | } 117 | -------------------------------------------------------------------------------- /tests/Unit/ArrayCacheStoreTest.php: -------------------------------------------------------------------------------- 1 | cache = new Cacheer(); 15 | $this->cache->setDriver()->useArrayDriver(); 16 | $this->cache->setConfig()->setTimeZone('America/Toronto'); 17 | } 18 | 19 | protected function tearDown(): void 20 | { 21 | $this->cache->flushCache(); 22 | } 23 | 24 | public function testUsingArrayDriverSetsProperInstance() 25 | { 26 | $this->assertInstanceOf(ArrayCacheStore::class, $this->cache->cacheStore); 27 | } 28 | 29 | public function testPutAndGetCacheInArray() 30 | { 31 | $cacheKey = 'test_key'; 32 | $cacheData = ['name' => 'John Doe', 'email' => 'john@example.com']; 33 | 34 | $this->cache->putCache($cacheKey, $cacheData, '', 3600); 35 | 36 | $result = $this->cache->getCache($cacheKey); 37 | 38 | $this->assertNotEmpty($result); 39 | $this->assertEquals($cacheData, $result); 40 | } 41 | 42 | public function testExpiredCacheInArray() 43 | { 44 | $cacheKey = 'expired_key'; 45 | $cacheData = ['name' => 'Expired User', 'email' => 'expired@example.com']; 46 | 47 | $this->cache->putCache($cacheKey, $cacheData, '', 1); 48 | sleep(3); 49 | 50 | $this->assertEquals("Cache stored successfully", $this->cache->getMessage()); 51 | $this->assertEmpty($this->cache->getCache($cacheKey)); 52 | $this->assertFalse($this->cache->isSuccess()); 53 | } 54 | 55 | 56 | public function testOverwriteExistingCacheInArray() 57 | { 58 | $cacheKey = 'overwrite_key'; 59 | $initialCacheData = ['name' => 'Initial Data', 'email' => 'initial@example.com']; 60 | $newCacheData = ['name' => 'New Data', 'email' => 'new@example.com']; 61 | 62 | $this->cache->putCache($cacheKey, $initialCacheData); 63 | $this->assertEquals("Cache stored successfully", $this->cache->getMessage()); 64 | 65 | $this->cache->appendCache($cacheKey, $newCacheData); 66 | $this->assertEquals("Cache appended successfully", $this->cache->getMessage()); 67 | $this->assertEquals($newCacheData, $this->cache->getCache($cacheKey)); 68 | } 69 | 70 | 71 | public function testPutManyCacheItemsInArray() 72 | { 73 | $items = [ 74 | [ 75 | 'cacheKey' => 'user_1_profile', 76 | 'cacheData' => [ 77 | ['name' => 'John Doe', 'email' => 'john@example.com'], 78 | ['name' => 'John Doe', 'email' => 'john@example.com'], 79 | ['name' => 'John Doe', 'email' => 'john@example.com'], 80 | ['name' => 'John Doe', 'email' => 'john@example.com'] 81 | ] 82 | ], 83 | [ 84 | 'cacheKey' => 'user_2_profile', 85 | 'cacheData' => [ 86 | ['name' => 'Jane Doe', 'email' => 'jane@example.com'], 87 | ['name' => 'Jane Doe', 'email' => 'jane@example.com'], 88 | ['name' => 'Jane Doe', 'email' => 'jane@example.com'], 89 | ['name' => 'Jane Doe', 'email' => 'jane@example.com'] 90 | ] 91 | ] 92 | ]; 93 | 94 | $this->cache->putMany($items); 95 | foreach ($items as $item) { 96 | 97 | $this->assertEquals($item['cacheData'], $this->cache->getCache($item['cacheKey'])); 98 | } 99 | } 100 | 101 | public function testHasCacheFromArray() 102 | { 103 | $cacheKey = 'test_key'; 104 | $cacheData = ['name' => 'Sílvio Silva', 'role' => 'Developer']; 105 | 106 | $this->cache->putCache($cacheKey, $cacheData); 107 | 108 | $this->assertEquals("Cache stored successfully", $this->cache->getMessage()); 109 | $this->assertTrue($this->cache->isSuccess()); 110 | 111 | $this->cache->has($cacheKey); 112 | $this->assertTrue($this->cache->isSuccess()); 113 | } 114 | 115 | public function testRenewCacheFromArray() 116 | { 117 | $cacheKey = 'expired_key'; 118 | $cacheData = ['name' => 'Expired User', 'email' => 'expired@example.com']; 119 | 120 | // Define TTL de 10 seg para que a chave ainda exista quando renovarmos 121 | $this->cache->putCache($cacheKey, $cacheData, '', 120); 122 | $this->assertEquals("Cache stored successfully", $this->cache->getMessage()); 123 | sleep(2); 124 | 125 | // Verifica que a chave existe antes de renovar 126 | $this->assertNotEmpty($this->cache->getCache($cacheKey)); 127 | 128 | $this->cache->renewCache($cacheKey, 7200); 129 | $this->assertTrue($this->cache->isSuccess()); 130 | $this->assertNotEmpty($this->cache->getCache($cacheKey)); 131 | } 132 | 133 | public function testRenewCacheWithNamespaceFromArray() 134 | { 135 | $cacheKey = 'expired_key'; 136 | $namespace = 'expired_namespace'; 137 | $cacheData = ['name' => 'Expired User', 'email' => 'expired@example.com']; 138 | 139 | $this->cache->putCache($cacheKey, $cacheData, $namespace, 120); 140 | $this->assertEquals("Cache stored successfully", $this->cache->getMessage()); 141 | sleep(2); 142 | 143 | $this->assertNotEmpty($this->cache->getCache($cacheKey, $namespace)); 144 | 145 | $this->cache->renewCache($cacheKey, 7200, $namespace); 146 | $this->assertTrue($this->cache->isSuccess()); 147 | $this->assertNotEmpty($this->cache->getCache($cacheKey, $namespace)); 148 | } 149 | 150 | public function testClearCacheDataFromArray() 151 | { 152 | $cacheKey = 'test_key'; 153 | $data = 'test_data'; 154 | 155 | $this->cache->putCache($cacheKey, $data); 156 | $this->assertEquals("Cache stored successfully", $this->cache->getMessage()); 157 | 158 | $this->cache->clearCache($cacheKey); 159 | $this->assertTrue($this->cache->isSuccess()); 160 | $this->assertEquals("Cache cleared successfully", $this->cache->getMessage()); 161 | 162 | $this->assertEmpty($this->cache->getCache($cacheKey)); 163 | } 164 | 165 | public function testFlushCacheDataFromArray() 166 | { 167 | $key1 = 'test_key1'; 168 | $data1 = 'test_data1'; 169 | 170 | $key2 = 'test_key2'; 171 | $data2 = 'test_data2'; 172 | 173 | $this->cache->putCache($key1, $data1); 174 | $this->cache->putCache($key2, $data2); 175 | $this->assertTrue($this->cache->isSuccess()); 176 | $this->assertTrue($this->cache->isSuccess()); 177 | 178 | $this->cache->flushCache(); 179 | 180 | $this->assertTrue($this->cache->isSuccess()); 181 | $this->assertEquals("Cache flushed successfully", $this->cache->getMessage()); 182 | } 183 | 184 | public function test_remember_saves_and_recover_values() 185 | { 186 | $this->cache->flushCache(); 187 | 188 | $value = $this->cache->remember('remember_test_key', 60, function () { 189 | return 'valor_teste'; 190 | }); 191 | 192 | $this->assertEquals('valor_teste', $value); 193 | 194 | $cachedValue = $this->cache->remember('remember_test_key', 60, function (){ 195 | return 'novo_valor'; 196 | }); 197 | 198 | 199 | $this->assertEquals('valor_teste', $cachedValue); 200 | } 201 | 202 | public function test_remember_forever_saves_value_indefinitely() 203 | { 204 | $this->cache->flushCache(); 205 | 206 | $value = $this->cache->rememberForever('remember_forever_key', function () { 207 | return 'valor_eterno'; 208 | }); 209 | $this->assertEquals('valor_eterno', $value); 210 | 211 | $cachedValue = $this->cache->rememberForever('remember_forever_key', function () { 212 | return 'novo_valor'; 213 | }); 214 | 215 | $this->assertEquals('valor_eterno', $cachedValue); 216 | } 217 | 218 | 219 | public function test_get_and_forget() 220 | { 221 | $cacheKey = 'cache_key_test'; 222 | $this->cache->putCache($cacheKey, 10); 223 | 224 | $this->assertTrue($this->cache->isSuccess()); 225 | 226 | $cacheData = $this->cache->getAndForget($cacheKey); 227 | 228 | $this->assertTrue($this->cache->isSuccess()); 229 | $this->assertEquals(10, $cacheData); 230 | 231 | $oldCacheData = $this->cache->getAndForget($cacheKey); 232 | 233 | $this->assertNull($oldCacheData); 234 | $this->assertFalse($this->cache->isSuccess()); 235 | 236 | $noCacheData = $this->cache->getAndForget('non_existent_cache_key'); 237 | $this->assertNull($noCacheData); 238 | } 239 | 240 | public function test_store_if_not_present_with_add_function() 241 | { 242 | $existentKey = 'cache_key_test'; 243 | 244 | $nonExistentKey = 'non_existent_key'; 245 | 246 | $this->cache->putCache($existentKey, 'existent_data'); 247 | 248 | $this->assertTrue($this->cache->isSuccess()); 249 | $this->assertEquals('existent_data', $this->cache->getCache($existentKey)); 250 | 251 | $addCache = $this->cache->add($existentKey, 100); 252 | 253 | $this->assertTrue($addCache); 254 | $this->assertNotEquals(100, 'existent_data'); 255 | 256 | $addNonExistentKey = $this->cache->add($nonExistentKey, 'non_existent_data'); 257 | 258 | $this->assertFalse($addNonExistentKey); 259 | $this->assertEquals('non_existent_data', $this->cache->getCache($nonExistentKey)); 260 | $this->assertTrue($this->cache->isSuccess()); 261 | 262 | } 263 | 264 | public function test_increment_function() { 265 | 266 | $cacheKey = 'test_increment'; 267 | $cacheData = 2025; 268 | 269 | $this->cache->putCache($cacheKey, $cacheData); 270 | 271 | $this->assertTrue($this->cache->isSuccess()); 272 | $this->assertEquals($cacheData, $this->cache->getCache($cacheKey)); 273 | $this->assertIsNumeric($this->cache->getCache($cacheKey)); 274 | 275 | $increment = $this->cache->increment($cacheKey, 2); 276 | $this->assertTrue($increment); 277 | 278 | $this->assertEquals(2027, $this->cache->getCache($cacheKey)); 279 | 280 | } 281 | 282 | public function test_decrement_function() { 283 | 284 | $cacheKey = 'test_decrement'; 285 | $cacheData = 2027; 286 | 287 | $this->cache->putCache($cacheKey, $cacheData); 288 | 289 | $this->assertTrue($this->cache->isSuccess()); 290 | $this->assertEquals($cacheData, $this->cache->getCache($cacheKey)); 291 | $this->assertIsNumeric($this->cache->getCache($cacheKey)); 292 | 293 | $increment = $this->cache->decrement($cacheKey, 2); 294 | $this->assertTrue($increment); 295 | 296 | $this->assertEquals(2025, $this->cache->getCache($cacheKey)); 297 | 298 | } 299 | 300 | } -------------------------------------------------------------------------------- /tests/Unit/DatabaseCacheStoreTest.php: -------------------------------------------------------------------------------- 1 | cache = new Cacheer(); 14 | $this->cache->setConfig()->setDatabaseConnection(Connect::getInstance()->getAttribute(PDO::ATTR_DRIVER_NAME)); 15 | $this->cache->setDriver()->useDatabaseDriver(); 16 | $this->cache->setConfig()->setTimeZone('America/Toronto'); 17 | } 18 | 19 | protected function tearDown(): void 20 | { 21 | $this->cache->flushCache(); 22 | } 23 | 24 | public function testPutCacheInDatabase() 25 | { 26 | $cacheKey = 'test_key'; 27 | $cacheData = ['name' => 'John Doe', 'email' => 'john@example.com']; 28 | 29 | $this->cache->putCache($cacheKey, $cacheData, '', 3600); 30 | 31 | $result = $this->cache->getCache($cacheKey); 32 | 33 | $this->assertNotEmpty($result); 34 | $this->assertEquals($cacheData, $result); 35 | } 36 | 37 | public function testGetCacheFromDatabase() 38 | { 39 | $cacheKey = 'test_key02'; 40 | $cacheData = ['name' => 'Jane Doe', 'email' => 'jane@example.com']; 41 | 42 | $this->cache->putCache($cacheKey, $cacheData, '', 3600); 43 | $this->assertEquals("Cache Stored Successfully", $this->cache->getMessage()); 44 | 45 | $result = $this->cache->getCache($cacheKey); 46 | 47 | $this->assertNotEmpty($result); 48 | $this->assertEquals($cacheData, $result); 49 | } 50 | 51 | public function testExpiredCacheInDatabase() 52 | { 53 | $cacheKey = 'expired_key'; 54 | $cacheData = ['name' => 'Expired User', 'email' => 'expired@example.com']; 55 | 56 | $this->cache->putCache($cacheKey, $cacheData, '', -3600); 57 | $this->assertEquals("Cache Stored Successfully", $this->cache->getMessage()); 58 | 59 | $this->assertEmpty($this->cache->getCache($cacheKey)); 60 | $this->assertFalse($this->cache->isSuccess()); 61 | } 62 | public function testOverwriteExistingCacheInDatabase() 63 | { 64 | 65 | $cacheKey = 'overwrite_key'; 66 | $initialCacheData = ['name' => 'Initial Data', 'email' => 'initial@example.com']; 67 | $newCacheData = ['name' => 'New Data', 'email' => 'new@example.com']; 68 | 69 | $expirationTime = date('Y-m-d H:i:s', time() + 3600); 70 | 71 | 72 | $db = Connect::getInstance(); 73 | $query = $db->prepare("INSERT INTO cacheer_table (cacheKey, cacheData, cacheNamespace, expirationTime) VALUES (?, ?, ?, ?)"); 74 | $query->bindValue(1, $cacheKey); 75 | $query->bindValue(2, serialize($initialCacheData)); 76 | $query->bindValue(3, ''); 77 | $query->bindValue(4, $expirationTime); 78 | 79 | $this->assertTrue($query->execute()); 80 | 81 | $this->cache->appendCache($cacheKey, $newCacheData); 82 | $this->assertEquals("Cache updated successfully.", $this->cache->getMessage()); 83 | 84 | $driver = Connect::getInstance()->getAttribute(PDO::ATTR_DRIVER_NAME); 85 | $nowFunction = ($driver === 'sqlite') ? "DATETIME('now', 'localtime')" : "NOW()"; 86 | 87 | $query = $db->prepare("SELECT cacheData FROM cacheer_table WHERE cacheKey = ? AND cacheNamespace = ? AND expirationTime > $nowFunction"); 88 | $query->bindValue(1, $cacheKey); 89 | $query->bindValue(2, ''); 90 | 91 | $this->assertTrue($query->execute()); 92 | 93 | $result = $query->fetch(PDO::FETCH_ASSOC); 94 | 95 | $this->assertEquals($newCacheData, unserialize($result['cacheData'])); 96 | } 97 | 98 | public function testPutManyCacheItemsInDatabase(): void 99 | { 100 | 101 | $items = [ 102 | [ 103 | 'cacheKey' => 'user_1_profile', 104 | 'cacheData' => [ 105 | ['name' => 'John Doe', 'email' => 'john@example.com'], 106 | ['name' => 'John Doe', 'email' => 'john@example.com'], 107 | ['name' => 'John Doe', 'email' => 'john@example.com'], 108 | ['name' => 'John Doe', 'email' => 'john@example.com'] 109 | ] 110 | ], 111 | [ 112 | 'cacheKey' => 'user_2_profile', 113 | 'cacheData' => [ 114 | ['name' => 'Jane Doe', 'email' => 'jane@example.com'], 115 | ['name' => 'Jane Doe', 'email' => 'jane@example.com'], 116 | ['name' => 'Jane Doe', 'email' => 'jane@example.com'], 117 | ['name' => 'Jane Doe', 'email' => 'jane@example.com'] 118 | ] 119 | ] 120 | ]; 121 | 122 | $this->cache->putMany($items); 123 | 124 | foreach ($items as $item) { 125 | $this->assertEquals($item['cacheData'], $this->cache->getCache($item['cacheKey'])); 126 | } 127 | } 128 | 129 | public function testAppendCacheWithNamespaceInDatabase(): void 130 | { 131 | $cacheKey = 'test_append_key_ns'; 132 | $namespace = 'test_namespace'; 133 | 134 | $initialData = ['initial' => 'data']; 135 | $additionalData = ['new' => 'data']; 136 | 137 | $expectedData = array_merge($initialData, $additionalData); 138 | 139 | // Armazena os dados iniciais no cache com namespace 140 | $this->cache->putCache($cacheKey, $initialData, $namespace); 141 | $this->assertTrue($this->cache->isSuccess()); 142 | 143 | // Adiciona novos dados ao cache existente com namespace 144 | $this->cache->appendCache($cacheKey, $additionalData, $namespace); 145 | $this->assertTrue($this->cache->isSuccess()); 146 | 147 | // Verifica se os dados no cache são os esperados 148 | $cachedData = $this->cache->getCache($cacheKey, $namespace); 149 | $this->assertEquals($expectedData, $cachedData); 150 | } 151 | 152 | public function testDataOutputShouldBeOfTypeJson() 153 | { 154 | $this->cache->useFormatter(); 155 | 156 | $cacheKey = "key_json"; 157 | $cacheData = "data_json"; 158 | 159 | $this->cache->putCache($cacheKey, $cacheData); 160 | $this->assertTrue($this->cache->isSuccess()); 161 | 162 | $cacheOutput = $this->cache->getCache($cacheKey)->toJson(); 163 | $this->assertTrue($this->cache->isSuccess()); 164 | $this->assertJson($cacheOutput); 165 | } 166 | 167 | public function testDataOutputShouldBeOfTypeArray() 168 | { 169 | 170 | $this->cache->useFormatter(); 171 | 172 | $cacheKey = "key_array"; 173 | $cacheData = "data_array"; 174 | 175 | $this->cache->putCache($cacheKey, $cacheData); 176 | $this->assertTrue($this->cache->isSuccess()); 177 | 178 | $cacheOutput = $this->cache->getCache($cacheKey)->toArray(); 179 | $this->assertTrue($this->cache->isSuccess()); 180 | $this->assertIsArray($cacheOutput); 181 | } 182 | 183 | public function testDataOutputShouldBeOfTypeObject() 184 | { 185 | $this->cache->useFormatter(); 186 | 187 | $cacheKey = "key_object"; 188 | $cacheData = ["id" => 123]; 189 | 190 | $this->cache->putCache($cacheKey, $cacheData); 191 | $this->assertTrue($this->cache->isSuccess()); 192 | 193 | $cacheOutput = $this->cache->getCache($cacheKey)->toObject(); 194 | $this->assertTrue($this->cache->isSuccess()); 195 | $this->assertIsObject($cacheOutput); 196 | } 197 | 198 | 199 | public function testClearCacheDataFromDatabase(): void 200 | { 201 | $cacheKey = 'test_key'; 202 | $data = 'test_data'; 203 | 204 | $this->cache->putCache($cacheKey, $data); 205 | $this->assertEquals("Cache Stored Successfully", $this->cache->getMessage()); 206 | 207 | $this->cache->clearCache($cacheKey); 208 | $this->assertTrue($this->cache->isSuccess()); 209 | $this->assertEquals("Cache deleted successfully!", $this->cache->getMessage()); 210 | 211 | $this->assertEmpty($this->cache->getCache($cacheKey)); 212 | } 213 | 214 | 215 | public function testFlushCacheDataFromDatabase(): void 216 | { 217 | $key1 = 'test_key1'; 218 | $data1 = 'test_data1'; 219 | 220 | $key2 = 'test_key2'; 221 | $data2 = 'test_data2'; 222 | 223 | $this->cache->putCache($key1, $data1); 224 | $this->cache->putCache($key2, $data2); 225 | $this->assertTrue($this->cache->isSuccess()); 226 | $this->assertTrue($this->cache->isSuccess()); 227 | 228 | $this->cache->flushCache(); 229 | $this->assertTrue($this->cache->isSuccess()); 230 | $this->assertEquals("Flush finished successfully", $this->cache->getMessage()); 231 | } 232 | 233 | public function test_remember_saves_and_recover_values() 234 | { 235 | $value = $this->cache->remember('remember_test_key', 60, function () { 236 | return 'valor_teste'; 237 | }); 238 | 239 | $this->assertEquals('valor_teste', $value); 240 | 241 | $cachedValue = $this->cache->remember('remember_test_key', 60, function (){ 242 | return 'novo_valor'; 243 | }); 244 | 245 | 246 | $this->assertEquals('valor_teste', $cachedValue); 247 | } 248 | 249 | public function test_remember_forever_saves_value_indefinitely() 250 | { 251 | 252 | $value = $this->cache->rememberForever('remember_forever_key', function () { 253 | return 'valor_eterno'; 254 | }); 255 | $this->assertEquals('valor_eterno', $value); 256 | 257 | $cachedValue = $this->cache->rememberForever('remember_forever_key', function () { 258 | return 'novo_valor'; 259 | }); 260 | 261 | $this->assertEquals('valor_eterno', $cachedValue); 262 | } 263 | 264 | public function test_get_and_forget() 265 | { 266 | $cacheKey = 'cache_key_test'; 267 | $this->cache->putCache($cacheKey, 10); 268 | 269 | $this->assertTrue($this->cache->isSuccess()); 270 | 271 | $cacheData = $this->cache->getAndForget($cacheKey); 272 | 273 | $this->assertTrue($this->cache->isSuccess()); 274 | $this->assertEquals(10, $cacheData); 275 | 276 | $oldCacheData = $this->cache->getAndForget($cacheKey); 277 | 278 | $this->assertNull($oldCacheData); 279 | $this->assertFalse($this->cache->isSuccess()); 280 | 281 | $noCacheData = $this->cache->getAndForget('non_existent_cache_key'); 282 | $this->assertNull($noCacheData); 283 | } 284 | 285 | public function test_store_if_not_present_with_add_function() 286 | { 287 | $existentKey = 'cache_key_test'; 288 | 289 | $nonExistentKey = 'non_existent_key'; 290 | 291 | $this->cache->putCache($existentKey, 'existent_data'); 292 | 293 | $this->assertTrue($this->cache->isSuccess()); 294 | $this->assertEquals('existent_data', $this->cache->getCache($existentKey)); 295 | 296 | $addCache = $this->cache->add($existentKey, 100); 297 | 298 | $this->assertTrue($addCache); 299 | $this->assertNotEquals(100, 'existent_data'); 300 | 301 | $addNonExistentKey = $this->cache->add($nonExistentKey, 'non_existent_data'); 302 | 303 | $this->assertFalse($addNonExistentKey); 304 | $this->assertEquals('non_existent_data', $this->cache->getCache($nonExistentKey)); 305 | $this->assertTrue($this->cache->isSuccess()); 306 | } 307 | 308 | 309 | public function test_increment_function() { 310 | 311 | $cacheKey = 'test_increment'; 312 | $cacheData = 2025; 313 | 314 | $this->cache->putCache($cacheKey, $cacheData); 315 | 316 | $this->assertTrue($this->cache->isSuccess()); 317 | $this->assertEquals($cacheData, $this->cache->getCache($cacheKey)); 318 | $this->assertIsNumeric($this->cache->getCache($cacheKey)); 319 | 320 | $increment = $this->cache->increment($cacheKey, 2); 321 | $this->assertTrue($increment); 322 | 323 | $this->assertEquals(2027, $this->cache->getCache($cacheKey)); 324 | 325 | } 326 | 327 | public function test_decrement_function() { 328 | 329 | $cacheKey = 'test_decrement'; 330 | $cacheData = 2027; 331 | 332 | $this->cache->putCache($cacheKey, $cacheData); 333 | 334 | $this->assertTrue($this->cache->isSuccess()); 335 | $this->assertEquals($cacheData, $this->cache->getCache($cacheKey)); 336 | $this->assertIsNumeric($this->cache->getCache($cacheKey)); 337 | 338 | $increment = $this->cache->decrement($cacheKey, 2); 339 | $this->assertTrue($increment); 340 | 341 | $this->assertEquals(2025, $this->cache->getCache($cacheKey)); 342 | 343 | } 344 | 345 | 346 | } 347 | -------------------------------------------------------------------------------- /tests/Unit/FileCacheStoreTest.php: -------------------------------------------------------------------------------- 1 | cacheDir = __DIR__ . '/cache'; 16 | if (!file_exists($this->cacheDir) || !is_dir($this->cacheDir)) { 17 | mkdir($this->cacheDir, 0755, true); 18 | } 19 | 20 | $options = [ 21 | 'cacheDir' => $this->cacheDir, 22 | ]; 23 | 24 | $this->cache = new Cacheer($options); 25 | } 26 | 27 | protected function tearDown(): void 28 | { 29 | $this->cache->flushCache(); 30 | } 31 | 32 | public function testPutCache() 33 | { 34 | $cacheKey = 'test_key'; 35 | $data = 'test_data'; 36 | 37 | $this->cache->putCache($cacheKey, $data); 38 | $this->assertTrue($this->cache->isSuccess()); 39 | $this->assertEquals('Cache file created successfully', $this->cache->getMessage()); 40 | 41 | $cacheFile = $this->cacheDir . '/' . md5($cacheKey) . '.cache'; 42 | $this->assertFileExists($cacheFile); 43 | $this->assertEquals($data, $this->cache->getCache($cacheKey)); 44 | } 45 | 46 | public function testGetCache() 47 | { 48 | $cacheKey = 'test_key'; 49 | $data = 'test_data'; 50 | 51 | $this->cache->putCache($cacheKey, $data); 52 | 53 | $cachedData = $this->cache->getCache($cacheKey); 54 | $this->assertTrue($this->cache->isSuccess()); 55 | $this->assertEquals($data, $cachedData); 56 | 57 | // Recuperar cache fora do período de expiração 58 | sleep(2); 59 | $cachedData = $this->cache->getCache($cacheKey, '', '2 seconds'); 60 | $this->assertFalse($this->cache->isSuccess()); 61 | $this->assertEquals('cacheFile not found, does not exists or expired', $this->cache->getMessage()); 62 | } 63 | 64 | public function testClearCache() 65 | { 66 | $cacheKey = 'test_key'; 67 | $data = 'test_data'; 68 | 69 | $this->cache->putCache($cacheKey, $data); 70 | $this->cache->clearCache($cacheKey); 71 | 72 | $this->assertTrue($this->cache->isSuccess()); 73 | $this->assertEquals('Cache file deleted successfully!', $this->cache->getMessage()); 74 | 75 | $cacheFile = $this->cacheDir . '/' . md5($cacheKey) . '.cache'; 76 | $this->assertFileDoesNotExist($cacheFile); 77 | } 78 | 79 | public function testFlushCache() 80 | { 81 | $key1 = 'test_key1'; 82 | $data1 = 'test_data1'; 83 | 84 | $key2 = 'test_key2'; 85 | $data2 = 'test_data2'; 86 | 87 | $this->cache->putCache($key1, $data1); 88 | $this->cache->putCache($key2, $data2); 89 | $this->cache->flushCache(); 90 | 91 | $cacheFile1 = $this->cacheDir . '/' . md5($key1) . '.cache'; 92 | $cacheFile2 = $this->cacheDir . '/' . md5($key2) . '.cache'; 93 | 94 | $this->assertFileDoesNotExist($cacheFile1); 95 | $this->assertFileDoesNotExist($cacheFile2); 96 | } 97 | 98 | public function testAutoFlush() 99 | { 100 | $options = [ 101 | 'cacheDir' => $this->cacheDir, 102 | 'flushAfter' => '10 seconds' 103 | ]; 104 | 105 | $this->cache = new Cacheer($options); 106 | $this->cache->putCache('test_key', 'test_data'); 107 | 108 | // Verifica se o cache foi criado com sucesso 109 | $this->assertEquals('test_data', $this->cache->getCache('test_key')); 110 | $this->assertTrue($this->cache->isSuccess()); 111 | 112 | // Espera 11 segundos para o cache ser limpo automaticamente 113 | sleep(11); 114 | 115 | $this->cache = new Cacheer($options); 116 | 117 | // Verifica se o cache foi limpo automaticamente 118 | $cachedData = $this->cache->getCache('test_key'); 119 | $this->assertFalse($this->cache->isSuccess()); 120 | $this->assertEquals('cacheFile not found, does not exists or expired', $this->cache->getMessage()); 121 | } 122 | 123 | public function testAppendCache() 124 | { 125 | $cacheKey = 'test_append_key'; 126 | $initialData = ['initial' => 'data']; 127 | $additionalData = ['new' => 'data']; 128 | $expectedData = array_merge($initialData, $additionalData); 129 | 130 | // Armazena os dados iniciais no cache 131 | $this->cache->putCache($cacheKey, $initialData); 132 | $this->assertTrue($this->cache->isSuccess()); 133 | 134 | // Adiciona novos dados ao cache existente 135 | $this->cache->appendCache($cacheKey, $additionalData); 136 | $this->assertTrue($this->cache->isSuccess()); 137 | 138 | // Verifica se os dados no cache são os esperados 139 | $cachedData = $this->cache->getCache($cacheKey); 140 | $this->assertEquals($expectedData, $cachedData); 141 | 142 | // Testa adicionar dados como string 143 | $additionalData = ['string_data' => 'string data']; 144 | $expectedData = array_merge($expectedData, $additionalData); 145 | $this->cache->appendCache($cacheKey, $additionalData); 146 | $cachedData = $this->cache->getCache($cacheKey); 147 | $this->assertEquals($expectedData, $cachedData); 148 | } 149 | 150 | public function testAppendCacheFileNotExists() 151 | { 152 | $cacheKey = 'non_existing_key'; 153 | $data = ['data']; 154 | 155 | // Tenta adicionar dados a um arquivo de cache que não existe 156 | $this->cache->appendCache($cacheKey, $data); 157 | $this->assertFalse($this->cache->isSuccess()); 158 | $this->assertEquals('cacheFile not found, does not exists or expired', $this->cache->getMessage()); 159 | } 160 | 161 | public function testAppendCacheWithNamespace() 162 | { 163 | $cacheKey = 'test_append_key_ns'; 164 | $namespace = 'test_namespace'; 165 | 166 | $initialData = ['initial' => 'data']; 167 | $additionalData = ['new' => 'data']; 168 | 169 | $expectedData = array_merge($initialData, $additionalData); 170 | 171 | // Armazena os dados iniciais no cache com namespace 172 | $this->cache->putCache($cacheKey, $initialData, $namespace); 173 | $this->assertTrue($this->cache->isSuccess()); 174 | 175 | // Adiciona novos dados ao cache existente com namespace 176 | $this->cache->appendCache($cacheKey, $additionalData, $namespace); 177 | $this->assertTrue($this->cache->isSuccess()); 178 | 179 | // Verifica se os dados no cache são os esperados 180 | $cachedData = $this->cache->getCache($cacheKey, $namespace); 181 | $this->assertEquals($expectedData, $cachedData); 182 | } 183 | 184 | public function testDataOutputShouldBeOfTypeJson() 185 | { 186 | $options = [ 187 | 'cacheDir' => $this->cacheDir 188 | ]; 189 | $this->cache = new Cacheer($options, true); 190 | 191 | $cacheKey = "key_json"; 192 | $cacheData = "data_json"; 193 | 194 | $this->cache->putCache($cacheKey, $cacheData); 195 | $this->assertTrue($this->cache->isSuccess()); 196 | 197 | $cacheOutput = $this->cache->getCache($cacheKey)->toJson(); 198 | $this->assertTrue($this->cache->isSuccess()); 199 | $this->assertJson($cacheOutput); 200 | } 201 | 202 | public function testDataOutputShouldBeOfTypeArray() 203 | { 204 | $options = [ 205 | 'cacheDir' => $this->cacheDir 206 | ]; 207 | $this->cache = new Cacheer($options, true); 208 | 209 | $cacheKey = "key_array"; 210 | $cacheData = "data_array"; 211 | 212 | $this->cache->putCache($cacheKey, $cacheData); 213 | $this->assertTrue($this->cache->isSuccess()); 214 | 215 | $cacheOutput = $this->cache->getCache($cacheKey)->toArray(); 216 | $this->assertTrue($this->cache->isSuccess()); 217 | $this->assertIsArray($cacheOutput); 218 | } 219 | 220 | public function testDataOutputShouldBeOfTypeObject() 221 | { 222 | $options = [ 223 | 'cacheDir' => $this->cacheDir 224 | ]; 225 | $this->cache = new Cacheer($options, true); 226 | 227 | $cacheKey = "key_object"; 228 | $cacheData = ["id" => 123]; 229 | 230 | $this->cache->putCache($cacheKey, $cacheData); 231 | $this->assertTrue($this->cache->isSuccess()); 232 | 233 | $cacheOutput = $this->cache->getCache($cacheKey)->toObject(); 234 | $this->assertTrue($this->cache->isSuccess()); 235 | $this->assertIsObject($cacheOutput); 236 | } 237 | 238 | public function testPutMany() 239 | { 240 | $cacheer = new Cacheer(['cacheDir' => __DIR__ . '/cache']); 241 | $items = [ 242 | [ 243 | 'cacheKey' => 'user_1_profile', 244 | 'cacheData' => ['name' => 'John Doe', 'email' => 'john@example.com'] 245 | ], 246 | [ 247 | 'cacheKey' => 'user_2_profile', 248 | 'cacheData' => ['name' => 'Jane Doe', 'email' => 'jane@example.com'] 249 | ], 250 | ]; 251 | 252 | $cacheer->putMany($items); 253 | 254 | foreach ($items as $item) { 255 | $this->assertEquals($item['cacheData'], $cacheer->getCache($item['cacheKey'])); 256 | } 257 | } 258 | 259 | public function test_remember_saves_and_recover_values() 260 | { 261 | $this->cache->flushCache(); 262 | 263 | $value = $this->cache->remember('remember_test_key', 60, function () { 264 | return 'valor_teste'; 265 | }); 266 | 267 | $this->assertEquals('valor_teste', $value); 268 | 269 | $cachedValue = $this->cache->remember('remember_test_key', 60, function (){ 270 | return 'novo_valor'; 271 | }); 272 | 273 | 274 | $this->assertEquals('valor_teste', $cachedValue); 275 | } 276 | 277 | public function test_remember_forever_saves_value_indefinitely() 278 | { 279 | $this->cache->flushCache(); 280 | 281 | $value = $this->cache->rememberForever('remember_forever_key', function () { 282 | return 'valor_eterno'; 283 | }); 284 | $this->assertEquals('valor_eterno', $value); 285 | 286 | $cachedValue = $this->cache->rememberForever('remember_forever_key', function () { 287 | return 'novo_valor'; 288 | }); 289 | 290 | $this->assertEquals('valor_eterno', $cachedValue); 291 | } 292 | 293 | public function test_get_and_forget() 294 | { 295 | $cacheKey = 'cache_key_test'; 296 | $this->cache->putCache($cacheKey, 10); 297 | 298 | $this->assertTrue($this->cache->isSuccess()); 299 | 300 | $cacheData = $this->cache->getAndForget($cacheKey); 301 | 302 | $this->assertTrue($this->cache->isSuccess()); 303 | $this->assertEquals(10, $cacheData); 304 | 305 | $oldCacheData = $this->cache->getAndForget($cacheKey); 306 | 307 | $this->assertNull($oldCacheData); 308 | $this->assertFalse($this->cache->isSuccess()); 309 | 310 | $noCacheData = $this->cache->getAndForget('non_existent_cache_key'); 311 | $this->assertNull($noCacheData); 312 | } 313 | 314 | public function test_store_if_not_present_with_add_function() 315 | { 316 | $existentKey = 'cache_key_test'; 317 | 318 | $nonExistentKey = 'non_existent_key'; 319 | 320 | $this->cache->putCache($existentKey, 'existent_data'); 321 | 322 | $this->assertTrue($this->cache->isSuccess()); 323 | $this->assertEquals('existent_data', $this->cache->getCache($existentKey)); 324 | 325 | $addCache = $this->cache->add($existentKey, 100); 326 | 327 | $this->assertTrue($addCache); 328 | $this->assertNotEquals(100, 'existent_data'); 329 | 330 | $addNonExistentKey = $this->cache->add($nonExistentKey, 'non_existent_data'); 331 | 332 | $this->assertFalse($addNonExistentKey); 333 | $this->assertEquals('non_existent_data', $this->cache->getCache($nonExistentKey)); 334 | $this->assertTrue($this->cache->isSuccess()); 335 | 336 | } 337 | 338 | public function test_increment_function() { 339 | 340 | $cacheKey = 'test_increment'; 341 | $cacheData = 2025; 342 | 343 | $this->cache->putCache($cacheKey, $cacheData); 344 | 345 | $this->assertTrue($this->cache->isSuccess()); 346 | $this->assertEquals($cacheData, $this->cache->getCache($cacheKey)); 347 | $this->assertIsNumeric($this->cache->getCache($cacheKey)); 348 | 349 | $increment = $this->cache->increment($cacheKey, 2); 350 | $this->assertTrue($increment); 351 | 352 | $this->assertEquals(2027, $this->cache->getCache($cacheKey)); 353 | 354 | } 355 | 356 | public function test_decrement_function() { 357 | 358 | $cacheKey = 'test_decrement'; 359 | $cacheData = 2027; 360 | 361 | $this->cache->putCache($cacheKey, $cacheData); 362 | 363 | $this->assertTrue($this->cache->isSuccess()); 364 | $this->assertEquals($cacheData, $this->cache->getCache($cacheKey)); 365 | $this->assertIsNumeric($this->cache->getCache($cacheKey)); 366 | 367 | $increment = $this->cache->decrement($cacheKey, 2); 368 | $this->assertTrue($increment); 369 | 370 | $this->assertEquals(2025, $this->cache->getCache($cacheKey)); 371 | 372 | } 373 | 374 | private function removeDirectoryRecursively($dir) 375 | { 376 | if (!is_dir($dir)) { 377 | return; 378 | } 379 | $items = scandir($dir); 380 | foreach ($items as $item) { 381 | if ($item === '.' || $item === '..') { 382 | continue; 383 | } 384 | $path = $dir . DIRECTORY_SEPARATOR . $item; 385 | if (is_dir($path)) { 386 | $this->removeDirectoryRecursively($path); 387 | } else { 388 | unlink($path); 389 | } 390 | } 391 | rmdir($dir); 392 | } 393 | 394 | public function testUseDefaultDriverCreatesCacheDirInProjectRoot() 395 | { 396 | $cacheer = new Cacheer(); 397 | $driver = new CacheDriver($cacheer); 398 | 399 | $projectRoot = EnvHelper::getRootPath(); 400 | $expectedCacheDir = $projectRoot . DIRECTORY_SEPARATOR . "CacheerPHP" . DIRECTORY_SEPARATOR . "Cache"; 401 | 402 | if (is_dir($expectedCacheDir)) { 403 | $this->removeDirectoryRecursively($expectedCacheDir); 404 | } 405 | 406 | $driver->useDefaultDriver(); 407 | 408 | $this->assertDirectoryExists($expectedCacheDir); 409 | 410 | if (is_dir($expectedCacheDir)) { 411 | $this->removeDirectoryRecursively($expectedCacheDir); 412 | } 413 | } 414 | 415 | public function testPutCacheWithNamespace() 416 | { 417 | $cacheKey = 'namespace_key'; 418 | $data = 'namespace_data'; 419 | $namespace = 'my_namespace'; 420 | 421 | $this->cache->putCache($cacheKey, $data, $namespace); 422 | $this->assertTrue($this->cache->isSuccess()); 423 | 424 | $cachedData = $this->cache->getCache($cacheKey, $namespace); 425 | $this->assertEquals($data, $cachedData); 426 | } 427 | 428 | public function testClearCacheWithNamespace() 429 | { 430 | $cacheKey = 'namespace_key_clear'; 431 | $data = 'namespace_data_clear'; 432 | $namespace = 'clear_namespace'; 433 | 434 | $this->cache->putCache($cacheKey, $data, $namespace); 435 | $this->assertTrue($this->cache->isSuccess()); 436 | 437 | $this->cache->clearCache($cacheKey, $namespace); 438 | $this->assertTrue($this->cache->isSuccess()); 439 | 440 | $cachedData = $this->cache->getCache($cacheKey, $namespace); 441 | $this->assertFalse($this->cache->isSuccess()); 442 | $this->assertNull($cachedData); 443 | } 444 | 445 | public function testFlushCacheRemovesNamespacedFiles() 446 | { 447 | $cacheKey = 'ns_flush_key'; 448 | $data = 'ns_flush_data'; 449 | $namespace = 'flush_namespace'; 450 | 451 | $this->cache->putCache($cacheKey, $data, $namespace); 452 | $this->assertTrue($this->cache->isSuccess()); 453 | 454 | $this->cache->flushCache(); 455 | 456 | $cachedData = $this->cache->getCache($cacheKey, $namespace); 457 | $this->assertFalse($this->cache->isSuccess()); 458 | $this->assertNull($cachedData); 459 | } 460 | 461 | public function testAppendCacheWithDifferentTypes() 462 | { 463 | $cacheKey = 'append_type_key'; 464 | $initialData = ['a' => 1]; 465 | $additionalData = ['b' => 2]; 466 | $expectedData = ['a' => 1, 'b' => 2]; 467 | 468 | $this->cache->putCache($cacheKey, $initialData); 469 | $this->cache->appendCache($cacheKey, $additionalData); 470 | $this->assertEquals($expectedData, $this->cache->getCache($cacheKey)); 471 | 472 | $this->cache->appendCache($cacheKey, ['c' => 'string']); 473 | $expectedData['c'] = 'string'; 474 | $this->assertEquals($expectedData, $this->cache->getCache($cacheKey)); 475 | } 476 | 477 | } 478 | -------------------------------------------------------------------------------- /tests/Unit/RedisCacheStoreTest.php: -------------------------------------------------------------------------------- 1 | cache = new Cacheer(); 16 | $this->cache->setDriver()->useRedisDriver(); 17 | } 18 | 19 | protected function tearDown(): void 20 | { 21 | $this->cache->flushCache(); 22 | } 23 | 24 | public function testUsingRedisDriverSetsProperInstance() 25 | { 26 | $this->assertInstanceOf(RedisCacheStore::class, $this->cache->cacheStore); 27 | } 28 | 29 | public function testPutCacheInRedis() 30 | { 31 | $cacheKey = 'test_key'; 32 | $cacheData = ['name' => 'Sílvio Silva', 'role' => 'Developer']; 33 | 34 | $this->cache->putCache($cacheKey, $cacheData); 35 | 36 | $this->assertEquals("Cache stored successfully", $this->cache->getMessage()); 37 | $this->assertNotEmpty($this->cache->getCache($cacheKey)); 38 | $this->assertEquals($cacheData, $this->cache->getCache($cacheKey)); 39 | 40 | } 41 | 42 | public function testGetCacheFromRedis() 43 | { 44 | $cacheKey = 'test_key'; 45 | $cacheData = ['name' => 'Sílvio Silva', 'role' => 'Developer']; 46 | 47 | $this->cache->putCache($cacheKey, $cacheData); 48 | 49 | $this->assertEquals("Cache stored successfully", $this->cache->getMessage()); 50 | 51 | $data = $this->cache->getCache($cacheKey); 52 | $this->assertNotEmpty($data); 53 | $this->assertEquals($cacheData, $data); 54 | } 55 | 56 | public function testExpiredCacheInRedis() 57 | { 58 | $cacheKey = 'expired_key'; 59 | $cacheData = ['name' => 'Expired User', 'email' => 'expired@example.com']; 60 | 61 | $this->cache->putCache($cacheKey, $cacheData, '', 1); 62 | sleep(3); 63 | 64 | $this->assertEquals("Cache stored successfully", $this->cache->getMessage()); 65 | $this->assertEmpty($this->cache->getCache($cacheKey)); 66 | $this->assertFalse($this->cache->isSuccess()); 67 | } 68 | 69 | public function testOverwriteExistingCacheInRedis() 70 | { 71 | $cacheKey = 'overwrite_key'; 72 | $initialCacheData = ['name' => 'Initial Data', 'email' => 'initial@example.com']; 73 | $newCacheData = ['name' => 'New Data', 'email' => 'new@example.com']; 74 | 75 | $this->cache->putCache($cacheKey, $initialCacheData); 76 | $this->assertEquals("Cache stored successfully", $this->cache->getMessage()); 77 | 78 | $this->cache->appendCache($cacheKey, $newCacheData); 79 | $this->assertEquals("Cache appended successfully", $this->cache->getMessage()); 80 | $this->assertEquals($newCacheData, $this->cache->getCache($cacheKey)); 81 | } 82 | 83 | public function testPutManyCacheItemsInRedis() 84 | { 85 | $items = [ 86 | [ 87 | 'cacheKey' => 'user_1_profile', 88 | 'cacheData' => [ 89 | ['name' => 'John Doe', 'email' => 'john@example.com'], 90 | ['name' => 'John Doe', 'email' => 'john@example.com'], 91 | ['name' => 'John Doe', 'email' => 'john@example.com'], 92 | ['name' => 'John Doe', 'email' => 'john@example.com'] 93 | ] 94 | ], 95 | [ 96 | 'cacheKey' => 'user_2_profile', 97 | 'cacheData' => [ 98 | ['name' => 'Jane Doe', 'email' => 'jane@example.com'], 99 | ['name' => 'Jane Doe', 'email' => 'jane@example.com'], 100 | ['name' => 'Jane Doe', 'email' => 'jane@example.com'], 101 | ['name' => 'Jane Doe', 'email' => 'jane@example.com'] 102 | ] 103 | ] 104 | ]; 105 | 106 | $this->cache->putMany($items); 107 | foreach ($items as $item) { 108 | $this->assertEquals($item['cacheData'], $this->cache->getCache($item['cacheKey'])); 109 | } 110 | } 111 | 112 | public function testAppendCacheWithNamespaceInRedis() 113 | { 114 | $cacheKey = 'test_append_key_ns'; 115 | $namespace = 'test_namespace'; 116 | 117 | $initialData = ['initial' => 'data']; 118 | $additionalData = ['new' => 'data']; 119 | 120 | $expectedData = array_merge($initialData, $additionalData); 121 | 122 | 123 | $this->cache->putCache($cacheKey, $initialData, $namespace); 124 | $this->assertTrue($this->cache->isSuccess()); 125 | 126 | 127 | $this->cache->appendCache($cacheKey, $additionalData, $namespace); 128 | $this->assertTrue($this->cache->isSuccess()); 129 | 130 | 131 | $cachedData = $this->cache->getCache($cacheKey, $namespace); 132 | $this->assertEquals($expectedData, $cachedData); 133 | } 134 | 135 | public function testDataOutputShouldBeOfTypeArray() 136 | { 137 | 138 | $this->cache->useFormatter(); 139 | 140 | $cacheKey = "key_array"; 141 | $cacheData = "data_array"; 142 | 143 | $this->cache->putCache($cacheKey, $cacheData); 144 | $this->assertTrue($this->cache->isSuccess()); 145 | 146 | $cacheOutput = $this->cache->getCache($cacheKey)->toArray(); 147 | $this->assertTrue($this->cache->isSuccess()); 148 | $this->assertIsArray($cacheOutput); 149 | } 150 | 151 | public function testDataOutputShouldBeOfTypeObject() 152 | { 153 | $this->cache->useFormatter(); 154 | 155 | $cacheKey = "key_object"; 156 | $cacheData = ["id" => 123]; 157 | 158 | $this->cache->putCache($cacheKey, $cacheData); 159 | $this->assertTrue($this->cache->isSuccess()); 160 | 161 | $cacheOutput = $this->cache->getCache($cacheKey)->toObject(); 162 | $this->assertTrue($this->cache->isSuccess()); 163 | $this->assertIsObject($cacheOutput); 164 | } 165 | 166 | public function testDataOutputShouldBeOfTypeJson() 167 | { 168 | $this->cache->useFormatter(); 169 | 170 | $cacheKey = "key_json"; 171 | $cacheData = "data_json"; 172 | 173 | $this->cache->putCache($cacheKey, $cacheData); 174 | $this->assertTrue($this->cache->isSuccess()); 175 | 176 | $cacheOutput = $this->cache->getCache($cacheKey)->toJson(); 177 | $this->assertTrue($this->cache->isSuccess()); 178 | $this->assertJson($cacheOutput); 179 | } 180 | 181 | public function testClearCacheDataFromRedis() 182 | { 183 | $cacheKey = 'test_key'; 184 | $data = 'test_data'; 185 | 186 | $this->cache->putCache($cacheKey, $data); 187 | $this->assertEquals("Cache stored successfully", $this->cache->getMessage()); 188 | 189 | $this->cache->clearCache($cacheKey); 190 | $this->assertTrue($this->cache->isSuccess()); 191 | $this->assertEquals("Cache cleared successfully", $this->cache->getMessage()); 192 | 193 | $this->assertEmpty($this->cache->getCache($cacheKey)); 194 | } 195 | 196 | public function testFlushCacheDataFromRedis() 197 | { 198 | $key1 = 'test_key1'; 199 | $data1 = 'test_data1'; 200 | 201 | $key2 = 'test_key2'; 202 | $data2 = 'test_data2'; 203 | 204 | $this->cache->putCache($key1, $data1); 205 | $this->cache->putCache($key2, $data2); 206 | $this->assertTrue($this->cache->isSuccess()); 207 | $this->assertTrue($this->cache->isSuccess()); 208 | 209 | $this->cache->flushCache(); 210 | 211 | $this->assertTrue($this->cache->isSuccess()); 212 | $this->assertEquals("Cache flushed successfully", $this->cache->getMessage()); 213 | } 214 | 215 | public function testHasCacheFromRedis() 216 | { 217 | $cacheKey = 'test_key'; 218 | $cacheData = ['name' => 'Sílvio Silva', 'role' => 'Developer']; 219 | 220 | $this->cache->putCache($cacheKey, $cacheData); 221 | 222 | $this->assertEquals("Cache stored successfully", $this->cache->getMessage()); 223 | $this->assertTrue($this->cache->isSuccess()); 224 | } 225 | 226 | public function testRenewCacheFromRedis() 227 | { 228 | $cacheKey = 'expired_key'; 229 | $cacheData = ['name' => 'Expired User', 'email' => 'expired@example.com']; 230 | 231 | // Define TTL de 10 seg para que a chave ainda exista quando renovarmos 232 | $this->cache->putCache($cacheKey, $cacheData, '', 120); 233 | $this->assertEquals("Cache stored successfully", $this->cache->getMessage()); 234 | sleep(2); 235 | 236 | // Verifica que a chave existe antes de renovar 237 | $this->assertNotEmpty($this->cache->getCache($cacheKey)); 238 | 239 | $this->cache->renewCache($cacheKey, 7200); 240 | $this->assertTrue($this->cache->isSuccess()); 241 | $this->assertNotEmpty($this->cache->getCache($cacheKey)); 242 | } 243 | 244 | public function testRenewCacheWithNamespaceFromRedis() 245 | { 246 | $cacheKey = 'expired_key'; 247 | $namespace = 'expired_namespace'; 248 | $cacheData = ['name' => 'Expired User', 'email' => 'expired@example.com']; 249 | 250 | $this->cache->putCache($cacheKey, $cacheData, $namespace, 120); 251 | $this->assertEquals("Cache stored successfully", $this->cache->getMessage()); 252 | sleep(2); 253 | 254 | $this->assertNotEmpty($this->cache->getCache($cacheKey, $namespace)); 255 | 256 | $this->cache->renewCache($cacheKey, 7200, $namespace); 257 | $this->assertTrue($this->cache->isSuccess()); 258 | $this->assertNotEmpty($this->cache->getCache($cacheKey, $namespace)); 259 | } 260 | 261 | public function test_remember_saves_and_recover_values() 262 | { 263 | $this->cache->flushCache(); 264 | 265 | $value = $this->cache->remember('remember_test_key', 60, function () { 266 | return 'valor_teste'; 267 | }); 268 | 269 | $this->assertEquals('valor_teste', $value); 270 | 271 | $cachedValue = $this->cache->remember('remember_test_key', 60, function (){ 272 | return 'novo_valor'; 273 | }); 274 | 275 | 276 | $this->assertEquals('valor_teste', $cachedValue); 277 | } 278 | 279 | public function test_remember_forever_saves_value_indefinitely() 280 | { 281 | $this->cache->flushCache(); 282 | 283 | $value = $this->cache->rememberForever('remember_forever_key', function () { 284 | return 'valor_eterno'; 285 | }); 286 | $this->assertEquals('valor_eterno', $value); 287 | 288 | $cachedValue = $this->cache->rememberForever('remember_forever_key', function () { 289 | return 'novo_valor'; 290 | }); 291 | 292 | $this->assertEquals('valor_eterno', $cachedValue); 293 | } 294 | 295 | 296 | public function test_get_and_forget() 297 | { 298 | $cacheKey = 'cache_key_test'; 299 | $this->cache->putCache($cacheKey, 10); 300 | 301 | $this->assertTrue($this->cache->isSuccess()); 302 | 303 | $cacheData = $this->cache->getAndForget($cacheKey); 304 | 305 | $this->assertTrue($this->cache->isSuccess()); 306 | $this->assertEquals(10, $cacheData); 307 | 308 | $oldCacheData = $this->cache->getAndForget($cacheKey); 309 | 310 | $this->assertNull($oldCacheData); 311 | $this->assertFalse($this->cache->isSuccess()); 312 | 313 | $noCacheData = $this->cache->getAndForget('non_existent_cache_key'); 314 | $this->assertNull($noCacheData); 315 | } 316 | 317 | public function test_store_if_not_present_with_add_function() 318 | { 319 | $existentKey = 'cache_key_test'; 320 | 321 | $nonExistentKey = 'non_existent_key'; 322 | 323 | $this->cache->putCache($existentKey, 'existent_data'); 324 | 325 | $this->assertTrue($this->cache->isSuccess()); 326 | $this->assertEquals('existent_data', $this->cache->getCache($existentKey)); 327 | 328 | $addCache = $this->cache->add($existentKey, 100); 329 | 330 | $this->assertTrue($addCache); 331 | $this->assertNotEquals(100, 'existent_data'); 332 | 333 | $addNonExistentKey = $this->cache->add($nonExistentKey, 'non_existent_data'); 334 | 335 | $this->assertFalse($addNonExistentKey); 336 | $this->assertEquals('non_existent_data', $this->cache->getCache($nonExistentKey)); 337 | $this->assertTrue($this->cache->isSuccess()); 338 | 339 | } 340 | 341 | public function test_increment_function() { 342 | 343 | $cacheKey = 'test_increment'; 344 | $cacheData = 2025; 345 | 346 | $this->cache->putCache($cacheKey, $cacheData); 347 | 348 | $this->assertTrue($this->cache->isSuccess()); 349 | $this->assertEquals($cacheData, $this->cache->getCache($cacheKey)); 350 | $this->assertIsNumeric($this->cache->getCache($cacheKey)); 351 | 352 | $increment = $this->cache->increment($cacheKey, 2); 353 | $this->assertTrue($increment); 354 | 355 | $this->assertEquals(2027, $this->cache->getCache($cacheKey)); 356 | 357 | } 358 | 359 | public function test_decrement_function() { 360 | 361 | $cacheKey = 'test_decrement'; 362 | $cacheData = 2027; 363 | 364 | $this->cache->putCache($cacheKey, $cacheData); 365 | 366 | $this->assertTrue($this->cache->isSuccess()); 367 | $this->assertEquals($cacheData, $this->cache->getCache($cacheKey)); 368 | $this->assertIsNumeric($this->cache->getCache($cacheKey)); 369 | 370 | $increment = $this->cache->decrement($cacheKey, 2); 371 | $this->assertTrue($increment); 372 | 373 | $this->assertEquals(2025, $this->cache->getCache($cacheKey)); 374 | 375 | } 376 | 377 | } 378 | -------------------------------------------------------------------------------- /tests/Unit/SecurityFeatureTest.php: -------------------------------------------------------------------------------- 1 | cacheDir = __DIR__ . '/cache'; 14 | if (!is_dir($this->cacheDir)) { 15 | mkdir($this->cacheDir, 0755, true); 16 | } 17 | 18 | $this->cache = new Cacheer(['cacheDir' => $this->cacheDir]); 19 | } 20 | 21 | protected function tearDown(): void 22 | { 23 | $this->cache->flushCache(); 24 | } 25 | 26 | public function testCompressionFeature() 27 | { 28 | $this->cache->useCompression(); 29 | $data = ['foo' => 'bar']; 30 | 31 | $this->cache->putCache('compression_key', $data); 32 | $this->assertTrue($this->cache->isSuccess()); 33 | 34 | $cached = $this->cache->getCache('compression_key'); 35 | $this->assertEquals($data, $cached); 36 | } 37 | 38 | public function testEncryptionFeature() 39 | { 40 | $this->cache->useEncryption('secret'); 41 | $data = ['foo' => 'bar']; 42 | 43 | $this->cache->putCache('encryption_key', $data); 44 | $this->assertTrue($this->cache->isSuccess()); 45 | 46 | $cached = $this->cache->getCache('encryption_key'); 47 | $this->assertEquals($data, $cached); 48 | } 49 | 50 | public function testCompressionAndEncryptionTogether() 51 | { 52 | $this->cache->useCompression(); 53 | $this->cache->useEncryption('secret'); 54 | $data = ['foo' => 'bar']; 55 | 56 | $this->cache->putCache('secure_key', $data); 57 | $this->assertTrue($this->cache->isSuccess()); 58 | 59 | $cached = $this->cache->getCache('secure_key'); 60 | $this->assertEquals($data, $cached); 61 | } 62 | } 63 | --------------------------------------------------------------------------------