<pman>Intégration de la branche rel82-0.6.0
This commit is contained in:
		
						commit
						3b17202ace
					
				| @ -5,12 +5,12 @@ composer: | ||||
|   dev: | ||||
|     link: true | ||||
|     require-dev: | ||||
|       nulib/php: ^8.2-dev | ||||
|       nulib/base: ^8.2-dev | ||||
|       nulib/spout: ^8.2-dev | ||||
|       nulib/phpss: ^8.2-dev | ||||
|   dist: | ||||
|     link: false | ||||
|     require-dev: | ||||
|       nulib/php: ^0.5.0p82 | ||||
|       nulib/spout: ^0.5.0p82 | ||||
|       nulib/phpss: ^0.5.0p82 | ||||
|       nulib/base: ^0.6.0p82 | ||||
|       nulib/spout: ^0.6.0p82 | ||||
|       nulib/phpss: ^0.6.0p82 | ||||
|  | ||||
							
								
								
									
										12
									
								
								CHANGES.md
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								CHANGES.md
									
									
									
									
									
								
							| @ -1,3 +1,15 @@ | ||||
| ## Release 0.6.0p82 du 30/05/2025-23:39 | ||||
| 
 | ||||
| ## Release 0.6.0p74 du 30/05/2025-23:35 | ||||
| 
 | ||||
| migrer de nulib/php à nulib/base | ||||
| 
 | ||||
| * `3ea51e7` gestion des fichiers de cache | ||||
| * `c80d99e` suite implémentation cache | ||||
| * `ec0c0ee` début implémentation cache | ||||
| * `4c91327` db/cache doit encore être travaillé | ||||
| * `ba0ad15` renommer *storage.php | ||||
| 
 | ||||
| ## Release 0.5.1p82 du 12/05/2025-15:37 | ||||
| 
 | ||||
| ## Release 0.5.1p74 du 12/05/2025-15:34 | ||||
|  | ||||
| @ -7,7 +7,7 @@ Exemple: release de la version 0.6.0 | ||||
| 
 | ||||
| Avant de faire une release majeure sur nur/ture, faire d'abord la release | ||||
| majeure correspondante sur | ||||
| * nulib/php | ||||
| * nulib/base | ||||
| * nulib/spout | ||||
| * nulib/phpss | ||||
| 
 | ||||
| @ -39,8 +39,11 @@ pci "maj projet" | ||||
| 
 | ||||
| prel -C | ||||
| 
 | ||||
| commit="$(git log --grep="Init changelog . version ${version}p82" --format=%H)" | ||||
| commit="$(git log --grep="Init changelog . version ${version}p82" --format=%H)" && | ||||
| echo "commit=$commit" | ||||
| 
 | ||||
| git checkout dev74 | ||||
| 
 | ||||
| git cherry-pick "$commit" | ||||
| pp -a | ||||
| ~~~ | ||||
|  | ||||
| @ -1 +1 @@ | ||||
| 0.5.1 | ||||
| 0.6.0 | ||||
|  | ||||
							
								
								
									
										7
									
								
								bin/nucache.php
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										7
									
								
								bin/nucache.php
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,7 @@ | ||||
| #!/usr/bin/php
 | ||||
| <?php | ||||
| require $_composer_autoload_path?? __DIR__.'/../vendor/autoload.php'; | ||||
| 
 | ||||
| use nulib\tools\NucacheApp; | ||||
| 
 | ||||
| NucacheApp::run(); | ||||
| @ -18,9 +18,9 @@ | ||||
| 		"php": "^8.2" | ||||
| 	}, | ||||
| 	"require-dev": { | ||||
| 		"nulib/php": "^0.5.0p82", | ||||
| 		"nulib/spout": "^0.5.0p82", | ||||
| 		"nulib/phpss": "^0.5.0p82", | ||||
| 		"nulib/base": "^0.6.0p82", | ||||
| 		"nulib/spout": "^0.6.0p82", | ||||
| 		"nulib/phpss": "^0.6.0p82", | ||||
| 		"nulib/tests": "^8.2", | ||||
| 		"ext-posix": "*", | ||||
| 		"ext-pcntl": "*", | ||||
| @ -78,12 +78,9 @@ | ||||
| 		"nur_bin/ldap-delete.php", | ||||
| 		"nur_bin/ldap-get-infos.php", | ||||
| 		"nur_bin/ldap-search.php", | ||||
| 		"nur_bin/sqlite-storage.php", | ||||
| 		"nur_bin/mysql-storage.php" | ||||
| 		"nur_bin/storage.sqlite.php", | ||||
| 		"nur_bin/storage.mysql.php" | ||||
| 	], | ||||
| 	"scripts": { | ||||
| 		"uc": "@php sbin/update_classes.php" | ||||
| 	}, | ||||
| 	"authors": [ | ||||
| 		{ | ||||
| 			"name": "Jephte Clain", | ||||
|  | ||||
							
								
								
									
										57
									
								
								composer.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										57
									
								
								composer.lock
									
									
									
										generated
									
									
									
								
							| @ -4,7 +4,7 @@ | ||||
|         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", | ||||
|         "This file is @generated automatically" | ||||
|     ], | ||||
|     "content-hash": "20d80ba2a043b1e083f352300c19da0f", | ||||
|     "content-hash": "1b96ec20ad4777cbbf2aa1a62c386266", | ||||
|     "packages": [], | ||||
|     "packages-dev": [ | ||||
|         { | ||||
| @ -390,18 +390,21 @@ | ||||
|             "time": "2024-12-30T11:07:19+00:00" | ||||
|         }, | ||||
|         { | ||||
|             "name": "nulib/php", | ||||
|             "version": "0.5.1p82", | ||||
|             "name": "nulib/base", | ||||
|             "version": "0.6.0p82", | ||||
|             "source": { | ||||
|                 "type": "git", | ||||
|                 "url": "https://git.univ-reunion.fr/sda-php/nulib.git", | ||||
|                 "reference": "bd8cdcafbeee9a786200672a022493441582b177" | ||||
|                 "url": "https://git.univ-reunion.fr/sda-php/nulib-base.git", | ||||
|                 "reference": "34ef2b7bf55e45c70db2cf8f6bd814f86f47f478" | ||||
|             }, | ||||
|             "require": { | ||||
|                 "ext-json": "*", | ||||
|                 "php": "^8.2", | ||||
|                 "symfony/yaml": "^7.1" | ||||
|             }, | ||||
|             "replace": { | ||||
|                 "nulib/php": "<0.6.0" | ||||
|             }, | ||||
|             "require-dev": { | ||||
|                 "ext-curl": "*", | ||||
|                 "ext-pcntl": "*", | ||||
| @ -435,18 +438,18 @@ | ||||
|                 } | ||||
|             ], | ||||
|             "description": "fonctions et classes essentielles", | ||||
|             "time": "2025-05-12T11:31:32+00:00" | ||||
|             "time": "2025-05-30T18:38:04+00:00" | ||||
|         }, | ||||
|         { | ||||
|             "name": "nulib/phpss", | ||||
|             "version": "0.5.0p82", | ||||
|             "version": "0.6.0p82", | ||||
|             "source": { | ||||
|                 "type": "git", | ||||
|                 "url": "https://git.univ-reunion.fr/sda-php/nulib-phpss.git", | ||||
|                 "reference": "620e1b8eab68afc8bae94b5a936b7929c03bc734" | ||||
|                 "reference": "303506ac3658c77fbb40e76b09f38d2f4541f581" | ||||
|             }, | ||||
|             "require": { | ||||
|                 "nulib/php": "^0.5.0p82", | ||||
|                 "nulib/base": "^0.6.0p82", | ||||
|                 "php": "^8.2", | ||||
|                 "phpoffice/phpspreadsheet": "^3.3.0" | ||||
|             }, | ||||
| @ -477,15 +480,15 @@ | ||||
|                 } | ||||
|             ], | ||||
|             "description": "wrapper pour phpoffice/phpspreadsheet", | ||||
|             "time": "2025-04-30T00:48:34+00:00" | ||||
|             "time": "2025-05-30T19:30:08+00:00" | ||||
|         }, | ||||
|         { | ||||
|             "name": "nulib/spout", | ||||
|             "version": "0.5.0p82", | ||||
|             "version": "0.6.0p82", | ||||
|             "source": { | ||||
|                 "type": "git", | ||||
|                 "url": "https://git.univ-reunion.fr/sda-php/nulib-spout.git", | ||||
|                 "reference": "32fbed599e2e3cfc616df70fe51ba8ec4cb3aefd" | ||||
|                 "reference": "1fb53cae4241be42e0c86bdfebb895fdfa6e2200" | ||||
|             }, | ||||
|             "require": { | ||||
|                 "ext-dom": "*", | ||||
| @ -494,7 +497,7 @@ | ||||
|                 "ext-libxml": "*", | ||||
|                 "ext-xmlreader": "*", | ||||
|                 "ext-zip": "*", | ||||
|                 "nulib/php": "^0.5.0p82", | ||||
|                 "nulib/base": "^0.6.0p82", | ||||
|                 "php": "^8.2" | ||||
|             }, | ||||
|             "replace": { | ||||
| @ -535,7 +538,7 @@ | ||||
|                 } | ||||
|             ], | ||||
|             "description": "wrapper pour openspout/openspout", | ||||
|             "time": "2025-04-30T00:43:21+00:00" | ||||
|             "time": "2025-05-30T19:01:51+00:00" | ||||
|         }, | ||||
|         { | ||||
|             "name": "nulib/tests", | ||||
| @ -2357,16 +2360,16 @@ | ||||
|         }, | ||||
|         { | ||||
|             "name": "symfony/deprecation-contracts", | ||||
|             "version": "v3.5.1", | ||||
|             "version": "v3.6.0", | ||||
|             "source": { | ||||
|                 "type": "git", | ||||
|                 "url": "https://github.com/symfony/deprecation-contracts.git", | ||||
|                 "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6" | ||||
|                 "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62" | ||||
|             }, | ||||
|             "dist": { | ||||
|                 "type": "zip", | ||||
|                 "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", | ||||
|                 "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", | ||||
|                 "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62", | ||||
|                 "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62", | ||||
|                 "shasum": "" | ||||
|             }, | ||||
|             "require": { | ||||
| @ -2379,7 +2382,7 @@ | ||||
|                     "name": "symfony/contracts" | ||||
|                 }, | ||||
|                 "branch-alias": { | ||||
|                     "dev-main": "3.5-dev" | ||||
|                     "dev-main": "3.6-dev" | ||||
|                 } | ||||
|             }, | ||||
|             "autoload": { | ||||
| @ -2404,7 +2407,7 @@ | ||||
|             "description": "A generic function and convention to trigger deprecation notices", | ||||
|             "homepage": "https://symfony.com", | ||||
|             "support": { | ||||
|                 "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.1" | ||||
|                 "source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0" | ||||
|             }, | ||||
|             "funding": [ | ||||
|                 { | ||||
| @ -2420,7 +2423,7 @@ | ||||
|                     "type": "tidelift" | ||||
|                 } | ||||
|             ], | ||||
|             "time": "2024-09-25T14:20:29+00:00" | ||||
|             "time": "2024-09-25T14:21:43+00:00" | ||||
|         }, | ||||
|         { | ||||
|             "name": "symfony/polyfill-ctype", | ||||
| @ -2503,16 +2506,16 @@ | ||||
|         }, | ||||
|         { | ||||
|             "name": "symfony/yaml", | ||||
|             "version": "v7.2.6", | ||||
|             "version": "v7.3.0", | ||||
|             "source": { | ||||
|                 "type": "git", | ||||
|                 "url": "https://github.com/symfony/yaml.git", | ||||
|                 "reference": "0feafffb843860624ddfd13478f481f4c3cd8b23" | ||||
|                 "reference": "cea40a48279d58dc3efee8112634cb90141156c2" | ||||
|             }, | ||||
|             "dist": { | ||||
|                 "type": "zip", | ||||
|                 "url": "https://api.github.com/repos/symfony/yaml/zipball/0feafffb843860624ddfd13478f481f4c3cd8b23", | ||||
|                 "reference": "0feafffb843860624ddfd13478f481f4c3cd8b23", | ||||
|                 "url": "https://api.github.com/repos/symfony/yaml/zipball/cea40a48279d58dc3efee8112634cb90141156c2", | ||||
|                 "reference": "cea40a48279d58dc3efee8112634cb90141156c2", | ||||
|                 "shasum": "" | ||||
|             }, | ||||
|             "require": { | ||||
| @ -2555,7 +2558,7 @@ | ||||
|             "description": "Loads and dumps YAML files", | ||||
|             "homepage": "https://symfony.com", | ||||
|             "support": { | ||||
|                 "source": "https://github.com/symfony/yaml/tree/v7.2.6" | ||||
|                 "source": "https://github.com/symfony/yaml/tree/v7.3.0" | ||||
|             }, | ||||
|             "funding": [ | ||||
|                 { | ||||
| @ -2571,7 +2574,7 @@ | ||||
|                     "type": "tidelift" | ||||
|                 } | ||||
|             ], | ||||
|             "time": "2025-04-04T10:10:11+00:00" | ||||
|             "time": "2025-04-04T10:10:33+00:00" | ||||
|         }, | ||||
|         { | ||||
|             "name": "theseer/tokenizer", | ||||
|  | ||||
							
								
								
									
										116
									
								
								src/cache/CacheChannel.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								src/cache/CacheChannel.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,116 @@ | ||||
| <?php | ||||
| namespace nulib\cache; | ||||
| 
 | ||||
| use nulib\cl; | ||||
| use nulib\db\CapacitorChannel; | ||||
| use nulib\php\time\DateTime; | ||||
| use nulib\php\time\Delay; | ||||
| 
 | ||||
| class CacheChannel extends CapacitorChannel { | ||||
|   /** @var int durée de vie par défaut du cache */ | ||||
|   const DURATION = "1D"; // jusqu'au lendemain
 | ||||
| 
 | ||||
|   const INCLUDES = null; | ||||
| 
 | ||||
|   const EXCLUDES = null; | ||||
| 
 | ||||
|   const COLUMN_DEFINITIONS = [ | ||||
|     "group_id" => "varchar(64) not null", | ||||
|     "id" => "varchar(64) not null", | ||||
|     "date_start" => "datetime", | ||||
|     "duration_" => "text", | ||||
|     "primary key (group_id, id)", | ||||
|   ]; | ||||
| 
 | ||||
|   static function get_cache_ids($id): array { | ||||
|     if (is_array($id)) { | ||||
|       $keys = array_keys($id); | ||||
|       if (array_key_exists("group_id", $id)) $groupIdKey = "group_id"; | ||||
|       else $groupIdKey = $keys[1] ?? null; | ||||
|       $groupId = $id[$groupIdKey] ?? ""; | ||||
|       if (array_key_exists("id", $id)) $idKey = "id"; | ||||
|       else $idKey = $keys[0] ?? null; | ||||
|       $id = $id[$idKey] ?? ""; | ||||
|     } else { | ||||
|       $groupId = ""; | ||||
|     } | ||||
|     if (preg_match('/^(.*\\\\)?([^\\\\]+)$/', $groupId, $ms)) { | ||||
|       # si le groupe est une classe, faire un hash du package pour limiter la
 | ||||
|       # longueur du groupe
 | ||||
|       [$package, $groupId] = [$ms[1], $ms[2]]; | ||||
|       $package = substr(md5($package), 0, 4); | ||||
|       $groupId = "${groupId}_$package"; | ||||
|     } | ||||
|     return ["group_id" => $groupId, "id" => $id]; | ||||
|   } | ||||
| 
 | ||||
|   function __construct(?string $duration=null, ?string $name=null) { | ||||
|     parent::__construct($name); | ||||
|     $this->duration = $duration ?? static::DURATION; | ||||
|     $this->includes = static::INCLUDES; | ||||
|     $this->excludes = static::EXCLUDES; | ||||
|   } | ||||
| 
 | ||||
|   protected string $duration; | ||||
| 
 | ||||
|   protected ?array $includes; | ||||
| 
 | ||||
|   protected ?array $excludes; | ||||
| 
 | ||||
|   function getItemValues($item): ?array { | ||||
|     return cl::merge(self::get_cache_ids($item), [ | ||||
|       "item" => null, | ||||
|     ]); | ||||
|   } | ||||
| 
 | ||||
|   function onCreate($item, array $values, ?array $alwaysNull, ?string $duration=null): ?array { | ||||
|     $now = new DateTime(); | ||||
|     $duration ??= $this->duration; | ||||
|     return [ | ||||
|       "date_start" => $now, | ||||
|       "duration" => new Delay($duration, $now), | ||||
|     ]; | ||||
|   } | ||||
| 
 | ||||
|   function onUpdate($item, array $values, array $pvalues, ?string $duration=null): ?array { | ||||
|     $now = new DateTime(); | ||||
|     $duration ??= $this->duration; | ||||
|     return [ | ||||
|       "date_start" => $now, | ||||
|       "duration" => new Delay($duration, $now), | ||||
|     ]; | ||||
|   } | ||||
| 
 | ||||
|   function shouldUpdate($id, bool $noCache=false): bool { | ||||
|     if ($noCache) return true; | ||||
| 
 | ||||
|     $cacheIds = self::get_cache_ids($id); | ||||
|     $groupId = $cacheIds["group_id"]; | ||||
|     if ($groupId) { | ||||
|       $includes = $this->includes; | ||||
|       $shouldInclude = $includes !== null && in_array($groupId, $includes); | ||||
|       $excludes = $this->excludes; | ||||
|       $shouldExclude = $excludes !== null && in_array($groupId, $excludes); | ||||
|       if (!$shouldInclude || $shouldExclude) return true; | ||||
|     } | ||||
| 
 | ||||
|     $found = false; | ||||
|     $expired = false; | ||||
|     $this->each($cacheIds, | ||||
|       function($item, $values) use (&$found, &$expired) { | ||||
|         $found = true; | ||||
|         $expired = $values["duration"]->isElapsed(); | ||||
|       }); | ||||
|     return !$found || $expired; | ||||
|   } | ||||
| 
 | ||||
|   function setCached($id, ?string $duration=null): void { | ||||
|     $cacheIds = self::get_cache_ids($id); | ||||
|     $this->charge($cacheIds, null, [$duration]); | ||||
|   } | ||||
| 
 | ||||
|   function resetCached($id) { | ||||
|     $cacheIds = self::get_cache_ids($id); | ||||
|     $this->delete($cacheIds); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										50
									
								
								src/cache/CacheData.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								src/cache/CacheData.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,50 @@ | ||||
| <?php | ||||
| namespace nulib\cache; | ||||
| 
 | ||||
| use nulib\cl; | ||||
| use nulib\php\func; | ||||
| use Traversable; | ||||
| 
 | ||||
| class CacheData { | ||||
|   /** @var string identifiant de cette donnée */ | ||||
|   const NAME = null; | ||||
| 
 | ||||
|   /** @var callable une fonction permettant de calculer la donnée */ | ||||
|   const COMPUTE = null; | ||||
| 
 | ||||
|   function __construct($compute=null, ?string $name=null) { | ||||
|     $this->name = $name ?? static::NAME ?? ""; | ||||
|     $this->compute = func::withn($compute ?? static::COMPUTE); | ||||
|   } | ||||
| 
 | ||||
|   protected string $name; | ||||
| 
 | ||||
|   protected ?func $compute; | ||||
| 
 | ||||
|   protected function compute() { | ||||
|     $compute = $this->compute; | ||||
|     return $compute !== null? $compute->invoke(): null; | ||||
|   } | ||||
| 
 | ||||
|   function getName() : string { | ||||
|     return $this->name; | ||||
|   } | ||||
| 
 | ||||
|   /** obtenir la donnée, en l'itérant au préalable si elle est traversable */ | ||||
|   function get($compute=null) { | ||||
|     $this->compute ??= func::withn($compute); | ||||
|     $data = $this->compute(); | ||||
|     if ($data instanceof Traversable) { | ||||
|       $data = cl::all($data); | ||||
|     } | ||||
|     return $data; | ||||
|   } | ||||
| 
 | ||||
|   /** obtenir un itérateur sur la donnée ou null s'il n'y a pas de données */ | ||||
|   function all($compute=null): ?iterable { | ||||
|     $this->compute ??= func::withn($compute); | ||||
|     $data = $this->compute(); | ||||
|     if ($data !== null && !is_iterable($data)) $data = [$data]; | ||||
|     return $data; | ||||
|   } | ||||
| } | ||||
							
								
								
									
										53
									
								
								src/cache/CacheDataChannel.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								src/cache/CacheDataChannel.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,53 @@ | ||||
| <?php | ||||
| namespace nulib\cache; | ||||
| 
 | ||||
| use Closure; | ||||
| use IteratorAggregate; | ||||
| use nulib\cache\CacheChannel; | ||||
| use nulib\cache\storage_cache; | ||||
| use nulib\cl; | ||||
| use nulib\db\CapacitorChannel; | ||||
| use Traversable; | ||||
| 
 | ||||
| class CacheDataChannel extends CapacitorChannel implements IteratorAggregate { | ||||
|   const COLUMN_DEFINITIONS = [ | ||||
|     "key" => "varchar(128) primary key not null", | ||||
|     "all_values" => "mediumtext", | ||||
|   ]; | ||||
| 
 | ||||
|   function __construct($id, callable $builder, ?string $duration=null) { | ||||
|     $this->cacheIds = $cacheIds = CacheChannel::get_cache_ids($id); | ||||
|     $this->builder = Closure::fromCallable($builder); | ||||
|     $this->duration = $duration; | ||||
|     $name = "{$cacheIds["group_id"]}-{$cacheIds["id"]}"; | ||||
|     parent::__construct($name); | ||||
|   } | ||||
| 
 | ||||
|   protected array $cacheIds; | ||||
| 
 | ||||
|   protected Closure $builder; | ||||
| 
 | ||||
|   protected ?string $duration = null; | ||||
| 
 | ||||
|   function getItemValues($item): ?array { | ||||
|     $key = array_keys($item)[0]; | ||||
|     $row = $item[$key]; | ||||
|     return [ | ||||
|       "key" => $key, | ||||
|       "item" => $row, | ||||
|       "all_values" => implode(" ", cl::filter_n(cl::with($row))), | ||||
|     ]; | ||||
|   } | ||||
| 
 | ||||
|   function getIterator(): Traversable { | ||||
|     $cm = storage_cache::get(); | ||||
|     if ($cm->shouldUpdate($this->cacheIds)) { | ||||
|       $this->capacitor->reset(); | ||||
|       foreach (($this->builder)() as $key => $row) { | ||||
|         $this->charge([$key => $row]); | ||||
|       } | ||||
|       $cm->setCached($this->cacheIds, $this->duration); | ||||
|     } | ||||
|     return $this->discharge(false); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										368
									
								
								src/cache/CacheFile.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										368
									
								
								src/cache/CacheFile.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,368 @@ | ||||
| <?php | ||||
| namespace nulib\cache; | ||||
| 
 | ||||
| use Exception; | ||||
| use nulib\cv; | ||||
| use nulib\file; | ||||
| use nulib\file\SharedFile; | ||||
| use nulib\os\path; | ||||
| use nulib\php\func; | ||||
| use nulib\php\time\DateTime; | ||||
| use nulib\php\time\Delay; | ||||
| use nulib\str; | ||||
| use nulib\ValueException; | ||||
| 
 | ||||
| class CacheFile extends SharedFile { | ||||
|   /** @var string|int durée de vie par défaut des données mises en cache  */ | ||||
|   const DURATION = "1D"; // jusqu'au lendemain
 | ||||
| 
 | ||||
|   const EXT = ".cache"; | ||||
| 
 | ||||
|   protected function ensure_source($source): CacheData { | ||||
|     if ($source instanceof CacheData) return $source; | ||||
|     if (cv::subclass_of($source, CacheData::class)) return new $source(); | ||||
|     if (func::is_callable($source)) return new CacheData($source); | ||||
|     throw ValueException::invalid_type($source, CacheData::class); | ||||
|   } | ||||
| 
 | ||||
|   function __construct($file, ?array $params=null) { | ||||
|     if ($file === null) { | ||||
|       $rand = bin2hex(random_bytes(8)); | ||||
|       $file = path::join(sys_get_temp_dir(), $rand); | ||||
|     } | ||||
|     $file = path::ensure_ext($file, self::EXT); | ||||
|     $this->basedir = path::dirname($file); | ||||
|     $basename = path::filename($file); | ||||
|     $this->basename = str::without_suffix(self::EXT, $basename); | ||||
|     $this->initialDuration = Delay::with($params["duration"] ?? static::DURATION); | ||||
|     $this->overrideDuration = $params["override_duration"] ?? false; | ||||
|     $this->readonly = $params["readonly"] ?? false; | ||||
|     $this->cacheNull = $params["cache_null"] ?? false; | ||||
|     $data = $params["data"] ?? null; | ||||
|     $this->sources = null; | ||||
|     if ($data === null) { | ||||
|       $this->source = null; | ||||
|     } elseif ($data instanceof CacheData) { | ||||
|       $this->source = $data; | ||||
|     } elseif (func::is_callable($data)) { | ||||
|       $this->source = new CacheData($data); | ||||
|     } elseif (!is_array($data)) { | ||||
|       $this->source = self::ensure_source($data); | ||||
|     } else { | ||||
|       $sources = []; | ||||
|       $index = 0; | ||||
|       foreach ($data as $key => $source) { | ||||
|         $source = self::ensure_source($source); | ||||
|         if ($key === $index) { | ||||
|           $index++; | ||||
|           $key = $source->getName(); | ||||
|         } | ||||
|         $sources[$key] = $source; | ||||
|       } | ||||
|       $this->sources = $sources; | ||||
|       $this->source = null; | ||||
|     } | ||||
|     parent::__construct($file); | ||||
|   } | ||||
| 
 | ||||
|   /** @var string répertoire de base des fichiers de cache */ | ||||
|   protected string $basedir; | ||||
| 
 | ||||
|   /** @var string nom de base des fichiers de cache */ | ||||
|   protected string $basename; | ||||
| 
 | ||||
|   protected Delay $initialDuration; | ||||
| 
 | ||||
|   protected bool $overrideDuration; | ||||
| 
 | ||||
|   protected bool $readonly; | ||||
| 
 | ||||
|   protected bool $cacheNull; | ||||
| 
 | ||||
|   protected ?array $sources; | ||||
| 
 | ||||
|   protected ?CacheData $source; | ||||
| 
 | ||||
|   protected function getSource($data): CacheData { | ||||
|     if ($data === null) { | ||||
|       return $this->source ??= new CacheData(function() { | ||||
|         return $this->compute(); | ||||
|       }); | ||||
|     } | ||||
|     $source = $data; | ||||
|     if (is_string($source) || is_int($source)) { | ||||
|       $source = $this->sources[$source] ?? null; | ||||
|       if ($source === null) throw ValueException::invalid_key($data); | ||||
|     } | ||||
|     if ($source instanceof CacheData) return $source; | ||||
|     throw ValueException::invalid_type($data, CacheData::class); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * vérifier si le fichier est valide. s'il est invalide, il faut le recréer. | ||||
|    * | ||||
|    * on assume que le fichier existe, vu qu'il a été ouvert en c+b | ||||
|    */ | ||||
|   function isValid(): bool { | ||||
|     # considèrer que le fichier est invalide s'il est de taille nulle
 | ||||
|     return $this->getSize() > 0; | ||||
|   } | ||||
| 
 | ||||
|   protected ?DateTime $start; | ||||
| 
 | ||||
|   protected ?Delay $duration; | ||||
| 
 | ||||
|   protected ?array $datafilenames; | ||||
| 
 | ||||
|   /** charger les données. le fichier a déjà été verrouillé en lecture */ | ||||
|   protected function loadMetadata(): void { | ||||
|     if ($this->isValid()) { | ||||
|       $this->rewind(); | ||||
|       [ | ||||
|         "start" => $start, | ||||
|         "duration" => $duration, | ||||
|         "datafiles" => $datafilenames, | ||||
|       ] = $this->unserialize(null, false, true); | ||||
|       if ($this->overrideDuration) { | ||||
|         $duration = Delay::with($this->initialDuration, $start); | ||||
|       } | ||||
|       $datafilenames = array_fill_keys($datafilenames, true); | ||||
|     } else { | ||||
|       $start = null; | ||||
|       $duration = null; | ||||
|       $datafilenames = []; | ||||
|     } | ||||
|     $this->start = $start; | ||||
|     $this->duration = $duration; | ||||
|     $this->datafilenames = $datafilenames; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * tester s'il faut mettre les données à jour. le fichier a déjà été | ||||
|    * verrouillé en lecture | ||||
|    */ | ||||
|   protected function shouldUpdate(bool $noCache=false): bool { | ||||
|     if ($this->isValid()) { | ||||
|       $expired = $this->duration->isElapsed(); | ||||
|     } else { | ||||
|       $expired = false; | ||||
|       $noCache = true; | ||||
|     } | ||||
|     return $noCache || $expired; | ||||
|   } | ||||
| 
 | ||||
|   /** sauvegarder les données. le fichier a déjà été verrouillé en écriture */ | ||||
|   protected function saveMetadata(): void { | ||||
|     $this->duration ??= $this->initialDuration; | ||||
|     if ($this->start === null) { | ||||
|       $this->start = new DateTime(); | ||||
|       $this->duration = Delay::with($this->duration, $this->start); | ||||
|     } | ||||
|     $datafilenames = array_keys($this->datafilenames); | ||||
|     $this->ftruncate(); | ||||
|     $this->serialize([ | ||||
|       "start" => $this->start, | ||||
|       "duration" => $this->duration, | ||||
|       "datafiles" => $datafilenames, | ||||
|     ], false, true); | ||||
|   } | ||||
| 
 | ||||
|   protected function loadData(string $datafile) { | ||||
|     return file::reader($datafile)->unserialize(); | ||||
|   } | ||||
| 
 | ||||
|   protected function saveData(string $datafile, $data): void { | ||||
|     file::writer($datafile)->serialize($data); | ||||
|   } | ||||
| 
 | ||||
|   protected function unlinkDatafile(string $datafilename): void { | ||||
|     $datafile = path::join($this->basedir, $datafilename); | ||||
|     @unlink($datafile); | ||||
|     unset($this->datafilenames[$datafilename]); | ||||
|   } | ||||
| 
 | ||||
|   protected function unlinkFiles(bool $datafilesOnly=false): void { | ||||
|     if (!$datafilesOnly) @unlink($this->file); | ||||
|     foreach ($this->datafilenames as $datafilename) { | ||||
|       $this->unlinkDatafile($datafilename); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** tester si $value peut être mis en cache */ | ||||
|   protected function shouldCache($value): bool { | ||||
|     return $this->cacheNull || $value !== null; | ||||
|   } | ||||
| 
 | ||||
|   protected ?DateTime $ostart; | ||||
| 
 | ||||
|   protected ?Delay $oduration; | ||||
| 
 | ||||
|   protected ?array $odatafilenames; | ||||
| 
 | ||||
|   protected function beforeAction() { | ||||
|     $this->loadMetadata(); | ||||
|     $this->ostart = cv::clone($this->start); | ||||
|     $this->oduration = cv::clone($this->duration); | ||||
|     $this->odatafilenames = cv::clone($this->datafilenames); | ||||
|   } | ||||
| 
 | ||||
|   protected function afterAction() { | ||||
|     $start = $this->start; | ||||
|     $duration = $this->duration; | ||||
|     $oduration = $this->oduration; | ||||
|     $datafilenames = $this->datafilenames; | ||||
|     $modified = false; | ||||
|     if ($start != $this->ostart) $modified = true; | ||||
|     if ($duration === null || $oduration === null) $modified = true; | ||||
|     elseif ($duration->getDest() != $oduration->getDest()) $modified = true; | ||||
|     # égalité stricte uniquement pour $datafiles qui est un array
 | ||||
|     if ($datafilenames !== $this->odatafilenames) $modified = true; | ||||
|     if ($modified && !$this->readonly) { | ||||
|       $this->lockWrite(); | ||||
|       $this->saveMetadata(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   protected function action(callable $callback, bool $willWrite=false) { | ||||
|     if ($willWrite && !$this->readonly) $this->lockWrite(); | ||||
|     else $this->lockRead(); | ||||
|     try { | ||||
|       $this->beforeAction(); | ||||
|       $result = $callback(); | ||||
|       $this->afterAction(); | ||||
|       return $result; | ||||
|     } finally { | ||||
|       $this->start = null; | ||||
|       $this->duration = null; | ||||
|       $this->datafilenames = null; | ||||
|       $this->unlock(true); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   protected function compute() { | ||||
|     return null; | ||||
|   } | ||||
| 
 | ||||
|   function get($data=null, bool $noCache=false) { | ||||
|     return $this->action(function () use ($data, $noCache) { | ||||
|       $source = $this->getSource($data); | ||||
|       $dataname = $source->getName(); | ||||
|       $datafilename = ".{$this->basename}.{$dataname}".self::EXT; | ||||
|       $datafile = path::join($this->basedir, $datafilename); | ||||
| 
 | ||||
|       $updateMetadata = $this->shouldUpdate($noCache); | ||||
|       $updateData = !array_key_exists($datafilename, $this->datafilenames); | ||||
|       if (!$this->readonly && ($updateMetadata || $updateData)) { | ||||
|         $this->lockWrite(); | ||||
|         if ($updateMetadata) { | ||||
|           # il faut refaire tout le cache
 | ||||
|           $this->unlinkFiles(true); | ||||
|           $this->start = null; | ||||
|           $this->duration = null; | ||||
|           $updateData = true; | ||||
|         } | ||||
|         if ($updateData) { | ||||
|           # calculer un fichier
 | ||||
|           try { | ||||
|             $data = $source->get(); | ||||
|           } catch (Exception $e) { | ||||
|             # ne pas garder le fichier en cas d'exception
 | ||||
|             $this->unlinkDatafile($datafile); | ||||
|             throw $e; | ||||
|           } | ||||
|         } elseif (file_exists($datafile)) { | ||||
|           $data = $this->loadData($datafile); | ||||
|         } else { | ||||
|           $data = null; | ||||
|         } | ||||
|         if ($this->shouldCache($data)) { | ||||
|           $this->saveData($datafile, $data); | ||||
|           $this->datafilenames[$datafilename] = true; | ||||
|         } else { | ||||
|           # ne pas garder le fichier s'il ne faut pas mettre en cache
 | ||||
|           $this->unlinkDatafile($datafile); | ||||
|         } | ||||
|       } elseif (file_exists($datafile)) { | ||||
|         $data = $this->loadData($datafile); | ||||
|       } else { | ||||
|         $data = null; | ||||
|       } | ||||
|       return $data; | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   function all($data=null, bool $noCache=false): ?iterable { | ||||
|     $data = $this->get($data, $noCache); | ||||
|     if ($data !== null && !is_iterable($data)) $data = [$data]; | ||||
|     return $data; | ||||
|   } | ||||
| 
 | ||||
|   function delete($data=null): void { | ||||
|     $source = $this->getSource($data); | ||||
|     $dataname = $source->getName(); | ||||
|     $datafilename = ".{$this->basename}.{$dataname}".self::EXT; | ||||
|     $this->unlinkDatafile($datafilename); | ||||
|   } | ||||
| 
 | ||||
|   /** obtenir les informations sur le fichier */ | ||||
|   function getInfos(): array { | ||||
|     return $this->action(function () { | ||||
|       if (!$this->isValid()) { | ||||
|         return ["valid" => false]; | ||||
|       } | ||||
|       $start = $this->start; | ||||
|       $duration = $this->duration; | ||||
|       $datafilenames = $this->datafilenames; | ||||
|       $datafiles = []; | ||||
|       foreach (array_keys($datafilenames) as $datafilename) { | ||||
|         $datafile = path::join($this->basedir, $datafilename); | ||||
|         $name = $datafilename; | ||||
|         str::del_prefix($name, ".{$this->basename}."); | ||||
|         str::del_suffix($name, self::EXT); | ||||
|         if (file_exists($datafile)) { | ||||
|           $size = filesize($datafile); | ||||
|         } else { | ||||
|           $size = null; | ||||
|         } | ||||
|         $datafiles[$name] = $size; | ||||
|       } | ||||
|       return [ | ||||
|         "valid" => true, | ||||
|         "start" => $start, | ||||
|         "duration" => strval($duration), | ||||
|         "date_start" => $start->format(), | ||||
|         "date_end" => $duration->getDest()->format(), | ||||
|         "datafiles" => $datafiles, | ||||
|       ]; | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   const UPDATE_SUB = -1, UPDATE_SET = 0, UPDATE_ADD = 1; | ||||
| 
 | ||||
|   /** | ||||
|    * mettre à jour la durée de validité du fichier | ||||
|    * | ||||
|    * XXX UPDATE_SET n'est pas implémenté | ||||
|    */ | ||||
|   function updateDuration($nduration, int $action=self::UPDATE_ADD): void { | ||||
|     if ($this->readonly) return; | ||||
|     $this->action(function () use ($nduration, $action) { | ||||
|       if (!$this->isValid()) return; | ||||
|       $duration = $this->duration; | ||||
|       if ($action < 0) $duration->subDuration($nduration); | ||||
|       elseif ($action > 0) $duration->addDuration($nduration); | ||||
|     }, true); | ||||
|   } | ||||
| 
 | ||||
|   /** supprimer les fichiers s'ils ont expiré */ | ||||
|   function deleteExpired(bool $force=false): bool { | ||||
|     if ($this->readonly) return false; | ||||
|     return $this->action(function () use ($force) { | ||||
|       if ($force || $this->shouldUpdate()) { | ||||
|         $this->unlinkFiles(); | ||||
|         return true; | ||||
|       } | ||||
|       return false; | ||||
|     }, true); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										39
									
								
								src/cache/storage_cache.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								src/cache/storage_cache.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,39 @@ | ||||
| <?php | ||||
| namespace nulib\cache; | ||||
| 
 | ||||
| use nulib\cache\CacheChannel; | ||||
| use nulib\cache\CacheDataChannel; | ||||
| use nulib\db\Capacitor; | ||||
| use nulib\db\CapacitorStorage; | ||||
| use nulib\db\sqlite\SqliteStorage; | ||||
| 
 | ||||
| class storage_cache { | ||||
|   protected static ?CapacitorStorage $storage = null; | ||||
| 
 | ||||
|   static function set_storage(CapacitorStorage $storage): CapacitorStorage { | ||||
|     return self::$storage = $storage; | ||||
|   } | ||||
| 
 | ||||
|   protected static function get_storage(): CapacitorStorage { | ||||
|     return self::$storage ??= new SqliteStorage(""); | ||||
|   } | ||||
| 
 | ||||
|   protected static ?CacheChannel $channel = null; | ||||
| 
 | ||||
|   static function set(?CacheChannel $channel): CacheChannel { | ||||
|     $channel ??= new CacheChannel(); | ||||
|     new Capacitor(self::get_storage(), $channel); | ||||
|     return self::$channel = $channel; | ||||
|   } | ||||
| 
 | ||||
|   static function get(): CacheChannel { | ||||
|     if (self::$channel !== null) return self::$channel; | ||||
|     else return self::set(null); | ||||
|   } | ||||
| 
 | ||||
|   static function new(?CacheDataChannel $channel, $id=null, ?callable $builder=null): CacheDataChannel { | ||||
|     $channel ??= new CacheDataChannel($id, $builder); | ||||
|     new Capacitor(self::get_storage(), $channel); | ||||
|     return $channel; | ||||
|   } | ||||
| } | ||||
							
								
								
									
										129
									
								
								src/tools/NucacheApp.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										129
									
								
								src/tools/NucacheApp.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,129 @@ | ||||
| <?php | ||||
| namespace nulib\tools; | ||||
| 
 | ||||
| use Exception; | ||||
| use nulib\app\cli\Application; | ||||
| use nulib\ext\yaml; | ||||
| use nulib\cache\CacheFile; | ||||
| use nulib\os\path; | ||||
| use nulib\output\msg; | ||||
| 
 | ||||
| class NucacheApp extends Application { | ||||
|   const ACTION_READ = 10, ACTION_INFOS = 20, ACTION_CLEAN = 30; | ||||
|   const ACTION_UPDATE = 40, ACTION_UPDATE_ADD = 41, ACTION_UPDATE_SUB = 42, ACTION_UPDATE_SET = 43; | ||||
| 
 | ||||
|   const ARGS = [ | ||||
|     "merge" => parent::ARGS, | ||||
|     "purpose" => "gestion de fichiers cache", | ||||
|     ["-r", "--read", "name" => "action", "value" => self::ACTION_READ, | ||||
|       "help" => "Afficher le contenu d'un fichier cache", | ||||
|     ], | ||||
|     ["-i", "--infos", "name" => "action", "value" => self::ACTION_INFOS, | ||||
|       "help" => "Afficher des informations sur le fichier cache", | ||||
|     ], | ||||
|     ["-k", "--clean", "name" => "action", "value" => self::ACTION_CLEAN, | ||||
|       "help" => "Supprimer le fichier cache s'il a expiré", | ||||
|     ], | ||||
|     ["-a", "--add-duration", "args" => 1, | ||||
|       "action" => [null, "->setActionUpdate", self::ACTION_UPDATE_ADD], | ||||
|       "help" => "Ajouter le nombre de secondes spécifié à la durée du cache", | ||||
|     ], | ||||
|     ["-b", "--sub-duration", "args" => 1, | ||||
|       "action" => [null, "->setActionUpdate", self::ACTION_UPDATE_SUB], | ||||
|       "help" => "Enlever le nombre de secondes spécifié à la durée du cache", | ||||
|     ], | ||||
|     #XXX pas encore implémenté
 | ||||
|     //["-s", "--set-duration", "args" => 1,
 | ||||
|     //  "action" => [null, "->setActionUpdate", self::ACTION_UPDATE_SET],
 | ||||
|     //  "help" => "Mettre à jour la durée du cache à la valeur spécifiée",
 | ||||
|     //],
 | ||||
|   ]; | ||||
| 
 | ||||
|   protected $action = self::ACTION_READ; | ||||
| 
 | ||||
|   protected $updateAction, $updateDuration; | ||||
| 
 | ||||
|   protected $args; | ||||
| 
 | ||||
|   function setActionUpdate(int $action, $updateDuration): void { | ||||
|     $this->action = self::ACTION_UPDATE; | ||||
|     switch ($action) { | ||||
|     case self::ACTION_UPDATE_SUB: | ||||
|       $this->updateAction = CacheFile::UPDATE_SUB; | ||||
|       break; | ||||
|     case self::ACTION_UPDATE_SET: | ||||
|       $this->updateAction = CacheFile::UPDATE_SET; | ||||
|       break; | ||||
|     case self::ACTION_UPDATE_ADD: | ||||
|       $this->updateAction = CacheFile::UPDATE_ADD; | ||||
|       break; | ||||
|     } | ||||
|     $this->updateDuration = $updateDuration; | ||||
|   } | ||||
| 
 | ||||
|   protected function findCaches(string $dir, ?array &$files): void { | ||||
|     foreach (glob("$dir/*") as $file) { | ||||
|       if (is_dir($file)) { | ||||
|         $this->findCaches($file, $files); | ||||
|       } elseif (is_file($file) && fnmatch("*.cache", $file)) { | ||||
|         $files[] = $file; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   function main() { | ||||
|     $files = []; | ||||
|     foreach ($this->args as $arg) { | ||||
|       if (is_dir($arg)) { | ||||
|         $this->findCaches($arg, $files); | ||||
|       } elseif (is_file($arg)) { | ||||
|         $files[] = $arg; | ||||
|       } else { | ||||
|         msg::warning("$arg: fichier introuvable"); | ||||
|       } | ||||
|     } | ||||
|     $showSection = count($files) > 1; | ||||
|     foreach ($files as $file) { | ||||
|       switch ($this->action) { | ||||
|       case self::ACTION_READ: | ||||
|         if ($showSection) msg::section($file); | ||||
|         $cache = new CacheFile($file, [ | ||||
|           "readonly" => true, | ||||
|           "duration" => "INF", | ||||
|           "override_duration" => true, | ||||
|         ]); | ||||
|         yaml::dump($cache->get()); | ||||
|         break; | ||||
|       case self::ACTION_INFOS: | ||||
|         if ($showSection) msg::section($file); | ||||
|         $cache = new CacheFile($file, [ | ||||
|           "readonly" => true, | ||||
|         ]); | ||||
|         yaml::dump($cache->getInfos()); | ||||
|         break; | ||||
|       case self::ACTION_CLEAN: | ||||
|         msg::action(path::ppath($file)); | ||||
|         $cache = new CacheFile($file); | ||||
|         try { | ||||
|           if ($cache->deleteExpired()) msg::asuccess("fichier supprimé"); | ||||
|           else msg::adone("fichier non expiré"); | ||||
|         } catch (Exception $e) { | ||||
|           msg::afailure($e); | ||||
|         } | ||||
|         break; | ||||
|       case self::ACTION_UPDATE: | ||||
|         msg::action(path::ppath($file)); | ||||
|         $cache = new CacheFile($file); | ||||
|         try { | ||||
|           $cache->updateDuration($this->updateDuration, $this->updateAction); | ||||
|           msg::asuccess("fichier mis à jour"); | ||||
|         } catch (Exception $e) { | ||||
|           msg::afailure($e); | ||||
|         } | ||||
|         break; | ||||
|       default: | ||||
|         self::die("$this->action: action non implémentée"); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
							
								
								
									
										1
									
								
								tbin/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								tbin/.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -1,2 +1,3 @@ | ||||
| /output-forever.log | ||||
| /devel/ | ||||
| /*.cache | ||||
|  | ||||
							
								
								
									
										76
									
								
								tbin/test-nucache.php
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										76
									
								
								tbin/test-nucache.php
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,76 @@ | ||||
| #!/usr/bin/php
 | ||||
| <?php | ||||
| require __DIR__.'/../vendor/autoload.php'; | ||||
| 
 | ||||
| use nulib\cache\CacheData; | ||||
| use nulib\cache\CacheFile; | ||||
| use nulib\ext\yaml; | ||||
| use nulib\os\sh; | ||||
| 
 | ||||
| function show(string $prefix, CacheFile $cache, bool $dumpInfos=true): void { | ||||
|   Txx("$prefix=", $cache->get()); | ||||
|   if ($dumpInfos) { | ||||
|     yaml::dump($cache->getInfos()); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| //system("rm -f *.cache .*.cache");
 | ||||
| 
 | ||||
| $what = [ | ||||
|   //"null",
 | ||||
|   "one", | ||||
|   //"two",
 | ||||
|   //"three",
 | ||||
| ]; | ||||
| $duration = 10; | ||||
| 
 | ||||
| if (in_array("null", $what)) { | ||||
|   $null = new CacheFile("null", [ | ||||
|     "duration" => $duration, | ||||
|   ]); | ||||
|   show("null", $null); | ||||
| } | ||||
| 
 | ||||
| if (in_array("one", $what)) { | ||||
|   $one = new class("one", [ | ||||
|     "duration" => $duration, | ||||
|   ]) extends CacheFile { | ||||
|     protected function compute() { | ||||
|       return 1; | ||||
|     } | ||||
|   }; | ||||
|   show("one", $one); | ||||
| } | ||||
| 
 | ||||
| if (in_array("two", $what)) { | ||||
|   $two = new CacheFile("two", [ | ||||
|     "duration" => $duration, | ||||
|     "data" => new CacheData(function () { | ||||
|       return 2; | ||||
|     }), | ||||
|   ]); | ||||
|   show("two", $two); | ||||
| } | ||||
| 
 | ||||
| if (in_array("three", $what)) { | ||||
|   $data31 = new CacheData(function () { | ||||
|     return 31; | ||||
|   }, "data31name"); | ||||
| 
 | ||||
|   $data32 = new CacheData(function () { | ||||
|     return 32; | ||||
|   }); | ||||
| 
 | ||||
|   $three = new CacheFile("three", [ | ||||
|     "data" => [ | ||||
|       "data31" => $data31, | ||||
|       $data31, # name=data31name
 | ||||
|       "data32" => $data32, | ||||
|       $data32, # name=""
 | ||||
|     ], | ||||
|   ]); | ||||
|   Txx("three.0=", $three->get("data31")); | ||||
|   Txx("three.1=", $three->get("data31name")); | ||||
|   Txx("three.2=", $three->get("data32")); | ||||
|   Txx("three.3=", $three->get("")); | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user