├── .vscode └── settings.json ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── composer.json └── src ├── Duration.php ├── Exceptions ├── BadMethodException.php └── InvalidMethodNameException.php ├── Helpers └── Str.php └── Traits └── SupportsDynamicCalls.php /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cSpell.words": [ 3 | "fourty" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to `php-timer` will be documented in this file. 4 | 5 | ## 1.0.0 - 202X-XX-XX 6 | 7 | - initial release 8 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) ajimoti 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PHP Cache Duration 2 | ![Banner](https://banners.beyondco.de/Cache%20Duration%20Package.png?theme=dark&packageManager=composer+require&packageName=ajimoti%2Fcache-duration&pattern=charlieBrown&style=style_1&description=A+more+readable+way+to+get+time+in+seconds+while+caching&md=1&showWatermark=1&fontSize=100px&images=clock) 3 | 4 | ## Introduction 5 | A readable and fluent way to generate PHP cache time. 6 | 7 | Built and written by [Ajimoti Ibukun](https://www.linkedin.com/in/ibukun-ajimoti-3420a786/) 8 | 9 | ## Quick Samples 10 | Instead of this: 11 | ```php 12 | $cacheDuration = 25 * 60 * 60; // twenty five hours 13 | Redis::expire($userData, $cacheDuration); 14 | ``` 15 | 16 | You can do this 17 | ```php 18 | $cacheDuration = Duration::twentyFiveHours(); // returns 25 hours in seconds (25 * 60 * 60) 19 | Redis::expire($userData, $cacheDuration); 20 | 21 | // or 22 | $cacheDuration = Duration::hours(25); // returns 25 hours in seconds (25 * 60 * 60) 23 | Redis::expire($userData, $cacheDuration); 24 | ``` 25 | 26 | You can also do this: 27 | ```php 28 | $cacheDuration = Duration::at('first day of January 2023'); // returns the time difference between the present time and the first of january 2023 in seconds 29 | 30 | Redis::expire($userData, $cacheDuration); 31 | ``` 32 | 33 | ## Requirements 34 | - PHP 8.0 or higher 35 | 36 | ## Installation 37 | You can install the package via composer: 38 | ```bash 39 | composer require ajimoti/cache-duration --with-all-dependencies 40 | ``` 41 | 42 | ## Documentation 43 | After installing the package via composer, import the `Duration` trait inside your class, then you are set. 44 | ```php 45 | **Note:** The number in words **MUST** be in `camel-case`. Any other case will throw an `InvalidArgumentException`. Additionally, it must be followed by a `title-case` of the unit. The available units are `Seconds`, `Minutes`, `Hours`, and `Days`. 75 | 76 | 77 | ## Usage 78 | ### `seconds($value)` 79 | Get time in seconds. It basically returns the same value passed into it. 80 | ```php 81 | use Ajimoti\CacheDuration\Duration; 82 | 83 | $cacheDuration = Duration::seconds(30); // returns 30 84 | 85 | // or dynamically 86 | $cacheDuration = Duration::thirtySeconds(); // returns 30 87 | ``` 88 | 89 | ### `minutes($value)` 90 | Converts time in minutes into seconds. 91 | ```php 92 | use Ajimoti\CacheDuration\Duration; 93 | 94 | $cacheDuration = Duration::minutes(55); // returns 55 minutes in seconds (55 * 60) 95 | 96 | // or dynamically 97 | $cacheDuration = Duration::fiftyFiveMinutes(); // returns 55 minutes in seconds (55 * 60) 98 | ``` 99 | 100 | ### `hours($value)` 101 | Converts time in hours into seconds. 102 | ```php 103 | use Ajimoti\CacheDuration\Duration; 104 | 105 | $cacheDuration = Duration::hours(7); // returns 7 hours in seconds (7 * 60 * 60) 106 | 107 | // or dynamically 108 | $cacheDuration = Duration::sevenHours(); // returns 7 hours in seconds (7 * 60 * 60) 109 | ``` 110 | 111 | ### `days($value)` 112 | Converts time in days into seconds. 113 | ```php 114 | use Ajimoti\CacheDuration\Duration; 115 | 116 | $cacheDuration = Duration::days(22); // returns 22 days in seconds (22 * 24 * 60 * 60) 117 | 118 | // or dynamically 119 | $cacheDuration = Duration::twentyTwoDays(); // returns 22 days in seconds (22 * 24 * 60 * 60) 120 | ``` 121 | 122 | ### `at($value)` 123 | This method allows you to convert a `Carbon\Carbon` instance, `DateTime` instance or `string` of date into seconds. 124 | 125 | It returns the difference in seconds between the argument passed and the current `timestamp`. 126 | 127 | > The date passed into this method **MUST** be a date in the future. When a string is passed, the text **MUST** be compatible with `Carbon::parse()` method, else an exception will be thrown 128 | 129 | #### Examples 130 | ```php 131 | use Date; 132 | use Carbon\Carbon; 133 | use Ajimoti\CacheDuration\Duration; 134 | 135 | // Carbon instance 136 | $cacheDuration = Duration::at(Carbon::now()->addMonths(3)); // returns time in seconds between the present timestamp and three months time 137 | 138 | // Datetime instance 139 | $cacheDuration = Duration::at(new DateTime('2039-09-30')); // returns time in seconds between the present timestamp and the date passed (2039-09-30). 140 | 141 | // String 142 | $cacheDuration = Duration::at('first day of January 2023'); // returns time in seconds between the present timestamp and the first of January 2023. 143 | ``` 144 | 145 | ## Testing 146 | 147 | ```bash 148 | composer test 149 | ``` 150 | 151 | ## Changelog 152 | 153 | Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently. 154 | 155 | ## Contributing 156 | 157 | Please see [CONTRIBUTING](.github/CONTRIBUTING.md) for details. 158 | 159 | ## Security Vulnerabilities 160 | 161 | Please review [our security policy](../../security/policy) on how to report security vulnerabilities. 162 | 163 | ## Credits 164 | 165 | - [ajimoti](https://github.com/ajimoti) 166 | - [All Contributors](../../contributors) 167 | 168 | ## License 169 | 170 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information. 171 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ajimoti/cache-duration", 3 | "description": "This package provides a more readable way to get time in seconds while caching.", 4 | "keywords": [ 5 | "ajimoti", 6 | "cache-duration", 7 | "cache", 8 | "duration" 9 | ], 10 | "homepage": "https://github.com/ajimoti/cache-duration", 11 | "license": "MIT", 12 | "authors": [ 13 | { 14 | "name": "ajimoti", 15 | "email": "ibukunajmoti@gmail.com", 16 | "role": "Developer" 17 | } 18 | ], 19 | "require": { 20 | "php": "^8.0", 21 | "nesbot/carbon": "^2.55" 22 | }, 23 | "require-dev": { 24 | "friendsofphp/php-cs-fixer": "^3.0", 25 | "pestphp/pest": "^1.20", 26 | "spatie/ray": "^1.28" 27 | }, 28 | "autoload": { 29 | "psr-4": { 30 | "Ajimoti\\CacheDuration\\": "src" 31 | } 32 | }, 33 | "autoload-dev": { 34 | "psr-4": { 35 | "Ajimoti\\CacheDuration\\Tests\\": "tests" 36 | } 37 | }, 38 | "scripts": { 39 | "test": "vendor/bin/pest", 40 | "test-coverage": "vendor/bin/pest --coverage", 41 | "format": "vendor/bin/php-cs-fixer fix --allow-risky=yes" 42 | }, 43 | "config": { 44 | "sort-packages": true 45 | }, 46 | "minimum-stability": "dev", 47 | "prefer-stable": true 48 | } 49 | -------------------------------------------------------------------------------- /src/Duration.php: -------------------------------------------------------------------------------- 1 | lte($now)) { 65 | throw new InvalidArgumentException("The value provided [{$value}] must be greater than [{$now}]."); 66 | } 67 | 68 | return $value->diffInSeconds(Carbon::now()); 69 | } 70 | 71 | if ($value instanceof DateTime) { 72 | return static::at(Carbon::instance($value)); 73 | } 74 | 75 | if (is_string($value)) { 76 | return static::at(Carbon::parse($value)); 77 | } 78 | 79 | throw new InvalidArgumentException('Invalid value provided.'); 80 | } 81 | 82 | /** 83 | * Handle dynamic static method calls on the class. 84 | * 85 | * @var int 86 | */ 87 | public static function __callStatic($methodName, $arguments) 88 | { 89 | return static::dynamicCall($methodName); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/Exceptions/BadMethodException.php: -------------------------------------------------------------------------------- 1 | message = sprintf( 15 | 'Call to undefined method %s::%s()', 16 | $class, 17 | $methodName 18 | ); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Exceptions/InvalidMethodNameException.php: -------------------------------------------------------------------------------- 1 | message = "Could not retrieve number from method name, ensure method name [{$methodName}] is in camel case format"; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Helpers/Str.php: -------------------------------------------------------------------------------- 1 | '0', 50 | 'a' => '1', 51 | 'one' => '1', 52 | 'two' => '2', 53 | 'three' => '3', 54 | 'four' => '4', 55 | 'five' => '5', 56 | 'six' => '6', 57 | 'seven' => '7', 58 | 'eight' => '8', 59 | 'nine' => '9', 60 | 'ten' => '10', 61 | 'eleven' => '11', 62 | 'twelve' => '12', 63 | 'thirteen' => '13', 64 | 'fourteen' => '14', 65 | 'fifteen' => '15', 66 | 'sixteen' => '16', 67 | 'seventeen' => '17', 68 | 'eighteen' => '18', 69 | 'nineteen' => '19', 70 | 'twenty' => '20', 71 | 'thirty' => '30', 72 | 'forty' => '40', 73 | 'fourty' => '40', // common misspelling 74 | 'fifty' => '50', 75 | 'sixty' => '60', 76 | 'seventy' => '70', 77 | 'eighty' => '80', 78 | 'ninety' => '90', 79 | 'hundred' => '100', 80 | 'thousand' => '1000', 81 | 'million' => '1000000', 82 | 'billion' => '1000000000', 83 | 'and' => '', 84 | ]; 85 | 86 | $data = strtolower($data); 87 | $validWords = array_keys($wordsToValue); 88 | 89 | // Ensure every word provided is valid 90 | foreach (explode(' ', $data) as $word) { 91 | if (! in_array($word, $validWords)) { 92 | throw new InvalidArgumentException(sprintf( 93 | 'Invalid word "%s" in number "%s". Ensure words are in camel case format', 94 | $word, 95 | $data 96 | )); 97 | } 98 | } 99 | 100 | // Replace all number words with an equivalent numeric value 101 | $data = strtr($data, $wordsToValue); 102 | 103 | // Coerce all tokens to numbers 104 | $parts = array_map( 105 | function ($val) { 106 | return floatval($val); 107 | }, 108 | preg_split('/[\s-]+/', $data) 109 | ); 110 | 111 | $stack = new SplStack(); // Current work stack 112 | $sum = 0; // Running total 113 | $last = null; 114 | 115 | foreach ($parts as $part) { 116 | if (! $stack->isEmpty()) { 117 | // We're part way through a phrase 118 | if ($stack->top() > $part) { 119 | // Decreasing step, e.g. from hundreds to ones 120 | if ($last >= 1000) { 121 | // If we drop from more than 1000 then we've finished the phrase 122 | $sum += $stack->pop(); 123 | // This is the first element of a new phrase 124 | $stack->push($part); 125 | } else { 126 | // Drop down from less than 1000, just addition 127 | // e.g. "seventy one" -> "70 1" -> "70 + 1" 128 | $stack->push($stack->pop() + $part); 129 | } 130 | } else { 131 | // Increasing step, e.g ones to hundreds 132 | $stack->push($stack->pop() * $part); 133 | } 134 | } else { 135 | // This is the first element of a new phrase 136 | $stack->push($part); 137 | } 138 | 139 | // Store the last processed part 140 | $last = $part; 141 | } 142 | 143 | return static::$wordsToNumberCache[$key] = (int) ($sum + $stack->pop()); 144 | } 145 | 146 | /** 147 | * Convert a camel case string to space separated words. 148 | * 149 | * @param string $string 150 | * 151 | * @return string 152 | */ 153 | public static function camelToSpaceSeparated(string $string): string 154 | { 155 | $words = array_map(function ($word) { 156 | return strtolower($word); 157 | }, preg_split('/(?=[A-Z])/', $string)); 158 | 159 | return implode(' ', $words); 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /src/Traits/SupportsDynamicCalls.php: -------------------------------------------------------------------------------- 1 | 'seconds', 46 | 'minute' => 'minutes', 47 | 'hour' => 'hours', 48 | 'day' => 'days', 49 | default => $suffix 50 | }; 51 | 52 | return static::$method($value); 53 | } 54 | } 55 | --------------------------------------------------------------------------------