Browse Source

Fixes #879: Caching implementation refactored according to PSR-16 'Simple Cache' specification

tags/3.0.0-alpha1
Paul Klimov 7 years ago committed by Alexander Makarov
parent
commit
4d9204d9f3
  1. 1
      composer.json
  2. 349
      composer.lock
  3. 81
      docs/guide/caching-data.md
  4. 1
      framework/CHANGELOG.md
  5. 11
      framework/UPGRADE.md
  6. 106
      framework/caching/ApcCache.php
  7. 50
      framework/caching/ArrayCache.php
  8. 363
      framework/caching/Cache.php
  9. 101
      framework/caching/CacheInterface.php
  10. 83
      framework/caching/DbCache.php
  11. 84
      framework/caching/DummyCache.php
  12. 25
      framework/caching/Exception.php
  13. 100
      framework/caching/FileCache.php
  14. 70
      framework/caching/MemCached.php
  15. 270
      framework/caching/SimpleCache.php
  16. 26
      framework/caching/TagDependency.php
  17. 106
      framework/caching/WinCache.php
  18. 66
      framework/caching/ZendDataCache.php
  19. 1
      framework/composer.json
  20. 79
      framework/console/controllers/CacheController.php
  21. 4
      framework/web/CacheSession.php
  22. 5
      tests/framework/base/ViewTest.php
  23. 7
      tests/framework/caching/ApcCacheTest.php
  24. 11
      tests/framework/caching/ArrayCacheTest.php
  25. 50
      tests/framework/caching/CacheTestCase.php
  26. 17
      tests/framework/caching/DbCacheTest.php
  27. 5
      tests/framework/caching/DependencyTest.php
  28. 11
      tests/framework/caching/FileCacheTest.php
  29. 7
      tests/framework/caching/MemCachedTest.php
  30. 64
      tests/framework/caching/SimpleCacheTest.php
  31. 37
      tests/framework/caching/TagDependencyTest.php
  32. 7
      tests/framework/caching/WinCacheTest.php
  33. 8
      tests/framework/console/UnkownCommandExceptionTest.php
  34. 28
      tests/framework/console/controllers/CacheControllerTest.php
  35. 6
      tests/framework/console/controllers/HelpControllerTest.php
  36. 4
      tests/framework/db/CommandTest.php
  37. 23
      tests/framework/filters/PageCacheTest.php
  38. 3
      tests/framework/rbac/MySQLManagerCacheTest.php
  39. 3
      tests/framework/rbac/PgSQLManagerCacheTest.php
  40. 5
      tests/framework/web/CacheSessionTest.php
  41. 4
      tests/framework/widgets/FragmentCacheTest.php

1
composer.json

@ -73,6 +73,7 @@
"ext-ctype": "*", "ext-ctype": "*",
"lib-pcre": "*", "lib-pcre": "*",
"yiisoft/yii2-composer": "~2.0.4", "yiisoft/yii2-composer": "~2.0.4",
"psr/simple-cache": "~1.0.0",
"ezyang/htmlpurifier": "~4.6", "ezyang/htmlpurifier": "~4.6",
"cebe/markdown": "~1.0.0 | ~1.1.0", "cebe/markdown": "~1.0.0 | ~1.1.0",
"bower-asset/jquery": "2.2.*@stable | 2.1.*@stable | 1.11.*@stable | 1.12.*@stable", "bower-asset/jquery": "2.2.*@stable | 2.1.*@stable | 1.11.*@stable | 1.12.*@stable",

349
composer.lock generated

@ -4,7 +4,8 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "1e1c5caae60d6d8d5b4a3d28d9667f31", "hash": "81cb8a6aa01acac345059695e795fd68",
"content-hash": "b36161ae5a97ecec89951d7fd5b2aa6a",
"packages": [ "packages": [
{ {
"name": "bower-asset/inputmask", "name": "bower-asset/inputmask",
@ -33,18 +34,30 @@
"version": "2.2.4", "version": "2.2.4",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/jquery/jquery-dist.git", "url": "https://github.com/components/jquery.git",
"reference": "c0185ab7c75aab88762c5aae780b9d83b80eda72" "reference": "981036fcb56668433a7eb0d1e71190324b4574df"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/jquery/jquery-dist/zipball/c0185ab7c75aab88762c5aae780b9d83b80eda72", "url": "https://api.github.com/repos/components/jquery/zipball/981036fcb56668433a7eb0d1e71190324b4574df",
"reference": "c0185ab7c75aab88762c5aae780b9d83b80eda72", "reference": "981036fcb56668433a7eb0d1e71190324b4574df",
"shasum": null "shasum": ""
},
"type": "bower-asset-library",
"extra": {
"bower-asset-main": "dist/jquery.js",
"bower-asset-ignore": [
"package.json"
]
}, },
"type": "bower-asset",
"license": [ "license": [
"MIT" "MIT"
],
"keywords": [
"browser",
"javascript",
"jquery",
"library"
] ]
}, },
{ {
@ -59,9 +72,21 @@
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/bestiejs/punycode.js/zipball/38c8d3131a82567bfef18da09f7f4db68c84f8a3", "url": "https://api.github.com/repos/bestiejs/punycode.js/zipball/38c8d3131a82567bfef18da09f7f4db68c84f8a3",
"reference": "38c8d3131a82567bfef18da09f7f4db68c84f8a3", "reference": "38c8d3131a82567bfef18da09f7f4db68c84f8a3",
"shasum": null "shasum": ""
}, },
"type": "bower-asset" "type": "bower-asset-library",
"extra": {
"bower-asset-main": "punycode.js",
"bower-asset-ignore": [
"coverage",
"tests",
".*",
"component.json",
"Gruntfile.js",
"node_modules",
"package.json"
]
}
}, },
{ {
"name": "bower-asset/yii2-pjax", "name": "bower-asset/yii2-pjax",
@ -75,12 +100,24 @@
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/yiisoft/jquery-pjax/zipball/60728da6ade5879e807a49ce59ef9a72039b8978", "url": "https://api.github.com/repos/yiisoft/jquery-pjax/zipball/60728da6ade5879e807a49ce59ef9a72039b8978",
"reference": "60728da6ade5879e807a49ce59ef9a72039b8978", "reference": "60728da6ade5879e807a49ce59ef9a72039b8978",
"shasum": null "shasum": ""
}, },
"require": { "require": {
"bower-asset/jquery": ">=1.8" "bower-asset/jquery": ">=1.8"
}, },
"type": "bower-asset", "type": "bower-asset-library",
"extra": {
"bower-asset-main": "./jquery.pjax.js",
"bower-asset-ignore": [
".travis.yml",
"Gemfile",
"Gemfile.lock",
"CONTRIBUTING.md",
"vendor/",
"script/",
"test/"
]
},
"license": [ "license": [
"MIT" "MIT"
] ]
@ -143,7 +180,7 @@
"markdown", "markdown",
"markdown-extra" "markdown-extra"
], ],
"time": "2017-07-16T21:13:23+00:00" "time": "2017-07-16 21:13:23"
}, },
{ {
"name": "ezyang/htmlpurifier", "name": "ezyang/htmlpurifier",
@ -190,7 +227,55 @@
"keywords": [ "keywords": [
"html" "html"
], ],
"time": "2017-06-03T02:28:16+00:00" "time": "2017-06-03 02:28:16"
},
{
"name": "psr/simple-cache",
"version": "1.0.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/simple-cache.git",
"reference": "753fa598e8f3b9966c886fe13f370baa45ef0e24"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/simple-cache/zipball/753fa598e8f3b9966c886fe13f370baa45ef0e24",
"reference": "753fa598e8f3b9966c886fe13f370baa45ef0e24",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\SimpleCache\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common interfaces for simple caching",
"keywords": [
"cache",
"caching",
"psr",
"psr-16",
"simple-cache"
],
"time": "2017-01-02 13:31:39"
}, },
{ {
"name": "yiisoft/yii2-composer", "name": "yiisoft/yii2-composer",
@ -240,7 +325,7 @@
"extension installer", "extension installer",
"yii2" "yii2"
], ],
"time": "2016-12-20T13:26:02+00:00" "time": "2016-12-20 13:26:02"
} }
], ],
"packages-dev": [ "packages-dev": [
@ -275,25 +360,25 @@
} }
], ],
"description": "a small tool to convert text file indentation", "description": "a small tool to convert text file indentation",
"time": "2014-05-23T14:40:08+00:00" "time": "2014-05-23 14:40:08"
}, },
{ {
"name": "doctrine/annotations", "name": "doctrine/annotations",
"version": "v1.4.0", "version": "v1.5.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/doctrine/annotations.git", "url": "https://github.com/doctrine/annotations.git",
"reference": "54cacc9b81758b14e3ce750f205a393d52339e97" "reference": "5beebb01b025c94e93686b7a0ed3edae81fe3e7f"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/doctrine/annotations/zipball/54cacc9b81758b14e3ce750f205a393d52339e97", "url": "https://api.github.com/repos/doctrine/annotations/zipball/5beebb01b025c94e93686b7a0ed3edae81fe3e7f",
"reference": "54cacc9b81758b14e3ce750f205a393d52339e97", "reference": "5beebb01b025c94e93686b7a0ed3edae81fe3e7f",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"doctrine/lexer": "1.*", "doctrine/lexer": "1.*",
"php": "^5.6 || ^7.0" "php": "^7.1"
}, },
"require-dev": { "require-dev": {
"doctrine/cache": "1.*", "doctrine/cache": "1.*",
@ -302,7 +387,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "1.4.x-dev" "dev-master": "1.5.x-dev"
} }
}, },
"autoload": { "autoload": {
@ -343,36 +428,36 @@
"docblock", "docblock",
"parser" "parser"
], ],
"time": "2017-02-24T16:22:25+00:00" "time": "2017-07-22 10:58:02"
}, },
{ {
"name": "doctrine/instantiator", "name": "doctrine/instantiator",
"version": "1.0.5", "version": "1.1.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/doctrine/instantiator.git", "url": "https://github.com/doctrine/instantiator.git",
"reference": "8e884e78f9f0eb1329e445619e04456e64d8051d" "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d", "url": "https://api.github.com/repos/doctrine/instantiator/zipball/185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda",
"reference": "8e884e78f9f0eb1329e445619e04456e64d8051d", "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=5.3,<8.0-DEV" "php": "^7.1"
}, },
"require-dev": { "require-dev": {
"athletic/athletic": "~0.1.8", "athletic/athletic": "~0.1.8",
"ext-pdo": "*", "ext-pdo": "*",
"ext-phar": "*", "ext-phar": "*",
"phpunit/phpunit": "~4.0", "phpunit/phpunit": "^6.2.3",
"squizlabs/php_codesniffer": "~2.0" "squizlabs/php_codesniffer": "^3.0.2"
}, },
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "1.0.x-dev" "dev-master": "1.2.x-dev"
} }
}, },
"autoload": { "autoload": {
@ -397,7 +482,7 @@
"constructor", "constructor",
"instantiate" "instantiate"
], ],
"time": "2015-06-14T21:17:01+00:00" "time": "2017-07-22 11:58:36"
}, },
{ {
"name": "doctrine/lexer", "name": "doctrine/lexer",
@ -451,7 +536,7 @@
"lexer", "lexer",
"parser" "parser"
], ],
"time": "2014-09-09T13:34:57+00:00" "time": "2014-09-09 13:34:57"
}, },
{ {
"name": "friendsofphp/php-cs-fixer", "name": "friendsofphp/php-cs-fixer",
@ -535,7 +620,7 @@
} }
], ],
"description": "A tool to automatically fix PHP code style", "description": "A tool to automatically fix PHP code style",
"time": "2017-07-18T15:16:38+00:00" "time": "2017-07-18 15:16:38"
}, },
{ {
"name": "gecko-packages/gecko-php-unit", "name": "gecko-packages/gecko-php-unit",
@ -574,7 +659,7 @@
"filesystem", "filesystem",
"phpunit" "phpunit"
], ],
"time": "2017-06-20T11:22:48+00:00" "time": "2017-06-20 11:22:48"
}, },
{ {
"name": "ircmaxell/password-compat", "name": "ircmaxell/password-compat",
@ -616,7 +701,7 @@
"hashing", "hashing",
"password" "password"
], ],
"time": "2014-11-20T16:49:30+00:00" "time": "2014-11-20 16:49:30"
}, },
{ {
"name": "myclabs/deep-copy", "name": "myclabs/deep-copy",
@ -658,7 +743,7 @@
"object", "object",
"object graph" "object graph"
], ],
"time": "2017-04-12T18:52:22+00:00" "time": "2017-04-12 18:52:22"
}, },
{ {
"name": "paragonie/random_compat", "name": "paragonie/random_compat",
@ -706,7 +791,7 @@
"pseudorandom", "pseudorandom",
"random" "random"
], ],
"time": "2017-03-13T16:27:32+00:00" "time": "2017-03-13 16:27:32"
}, },
{ {
"name": "phar-io/manifest", "name": "phar-io/manifest",
@ -761,7 +846,7 @@
} }
], ],
"description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
"time": "2017-03-05T18:14:27+00:00" "time": "2017-03-05 18:14:27"
}, },
{ {
"name": "phar-io/version", "name": "phar-io/version",
@ -808,7 +893,7 @@
} }
], ],
"description": "Library for handling version information and constraints", "description": "Library for handling version information and constraints",
"time": "2017-03-05T17:38:23+00:00" "time": "2017-03-05 17:38:23"
}, },
{ {
"name": "phpdocumentor/reflection-common", "name": "phpdocumentor/reflection-common",
@ -862,26 +947,26 @@
"reflection", "reflection",
"static analysis" "static analysis"
], ],
"time": "2015-12-27T11:43:31+00:00" "time": "2015-12-27 11:43:31"
}, },
{ {
"name": "phpdocumentor/reflection-docblock", "name": "phpdocumentor/reflection-docblock",
"version": "3.2.0", "version": "3.2.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
"reference": "46f7e8bb075036c92695b15a1ddb6971c751e585" "reference": "4aada1f93c72c35e22fb1383b47fee43b8f1d157"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/46f7e8bb075036c92695b15a1ddb6971c751e585", "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/4aada1f93c72c35e22fb1383b47fee43b8f1d157",
"reference": "46f7e8bb075036c92695b15a1ddb6971c751e585", "reference": "4aada1f93c72c35e22fb1383b47fee43b8f1d157",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=5.5", "php": ">=5.5",
"phpdocumentor/reflection-common": "^1.0@dev", "phpdocumentor/reflection-common": "^1.0@dev",
"phpdocumentor/type-resolver": "^0.4.0", "phpdocumentor/type-resolver": "^0.3.0",
"webmozart/assert": "^1.0" "webmozart/assert": "^1.0"
}, },
"require-dev": { "require-dev": {
@ -907,20 +992,20 @@
} }
], ],
"description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
"time": "2017-07-15T11:38:20+00:00" "time": "2017-08-08 06:39:58"
}, },
{ {
"name": "phpdocumentor/type-resolver", "name": "phpdocumentor/type-resolver",
"version": "0.4.0", "version": "0.3.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpDocumentor/TypeResolver.git", "url": "https://github.com/phpDocumentor/TypeResolver.git",
"reference": "9c977708995954784726e25d0cd1dddf4e65b0f7" "reference": "fb3933512008d8162b3cdf9e18dba9309b7c3773"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/9c977708995954784726e25d0cd1dddf4e65b0f7", "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/fb3933512008d8162b3cdf9e18dba9309b7c3773",
"reference": "9c977708995954784726e25d0cd1dddf4e65b0f7", "reference": "fb3933512008d8162b3cdf9e18dba9309b7c3773",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -954,7 +1039,7 @@
"email": "me@mikevanriel.com" "email": "me@mikevanriel.com"
} }
], ],
"time": "2017-07-14T14:27:02+00:00" "time": "2017-06-03 08:32:36"
}, },
{ {
"name": "phpspec/prophecy", "name": "phpspec/prophecy",
@ -1017,32 +1102,32 @@
"spy", "spy",
"stub" "stub"
], ],
"time": "2017-03-02T20:05:34+00:00" "time": "2017-03-02 20:05:34"
}, },
{ {
"name": "phpunit/php-code-coverage", "name": "phpunit/php-code-coverage",
"version": "5.2.1", "version": "5.2.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "dc421f9ca5082a0c0cb04afb171c765f79add85b" "reference": "8ed1902a57849e117b5651fc1a5c48110946c06b"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/dc421f9ca5082a0c0cb04afb171c765f79add85b", "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/8ed1902a57849e117b5651fc1a5c48110946c06b",
"reference": "dc421f9ca5082a0c0cb04afb171c765f79add85b", "reference": "8ed1902a57849e117b5651fc1a5c48110946c06b",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"ext-dom": "*", "ext-dom": "*",
"ext-xmlwriter": "*", "ext-xmlwriter": "*",
"php": "^7.0", "php": "^7.0",
"phpunit/php-file-iterator": "^1.3", "phpunit/php-file-iterator": "^1.4.2",
"phpunit/php-text-template": "^1.2", "phpunit/php-text-template": "^1.2.1",
"phpunit/php-token-stream": "^1.4.11 || ^2.0", "phpunit/php-token-stream": "^1.4.11 || ^2.0",
"sebastian/code-unit-reverse-lookup": "^1.0", "sebastian/code-unit-reverse-lookup": "^1.0.1",
"sebastian/environment": "^3.0", "sebastian/environment": "^3.0",
"sebastian/version": "^2.0", "sebastian/version": "^2.0.1",
"theseer/tokenizer": "^1.1" "theseer/tokenizer": "^1.1"
}, },
"require-dev": { "require-dev": {
@ -1050,7 +1135,7 @@
"phpunit/phpunit": "^6.0" "phpunit/phpunit": "^6.0"
}, },
"suggest": { "suggest": {
"ext-xdebug": "^2.5.3" "ext-xdebug": "^2.5.5"
}, },
"type": "library", "type": "library",
"extra": { "extra": {
@ -1081,7 +1166,7 @@
"testing", "testing",
"xunit" "xunit"
], ],
"time": "2017-04-21T08:03:57+00:00" "time": "2017-08-03 12:40:43"
}, },
{ {
"name": "phpunit/php-file-iterator", "name": "phpunit/php-file-iterator",
@ -1128,7 +1213,7 @@
"filesystem", "filesystem",
"iterator" "iterator"
], ],
"time": "2016-10-03T07:40:28+00:00" "time": "2016-10-03 07:40:28"
}, },
{ {
"name": "phpunit/php-text-template", "name": "phpunit/php-text-template",
@ -1169,7 +1254,7 @@
"keywords": [ "keywords": [
"template" "template"
], ],
"time": "2015-06-21T13:50:34+00:00" "time": "2015-06-21 13:50:34"
}, },
{ {
"name": "phpunit/php-timer", "name": "phpunit/php-timer",
@ -1218,33 +1303,33 @@
"keywords": [ "keywords": [
"timer" "timer"
], ],
"time": "2017-02-26T11:10:40+00:00" "time": "2017-02-26 11:10:40"
}, },
{ {
"name": "phpunit/php-token-stream", "name": "phpunit/php-token-stream",
"version": "1.4.11", "version": "2.0.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/php-token-stream.git", "url": "https://github.com/sebastianbergmann/php-token-stream.git",
"reference": "e03f8f67534427a787e21a385a67ec3ca6978ea7" "reference": "ecb0b2cdaa0add708fe6f329ef65ae0c5225130b"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/e03f8f67534427a787e21a385a67ec3ca6978ea7", "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/ecb0b2cdaa0add708fe6f329ef65ae0c5225130b",
"reference": "e03f8f67534427a787e21a385a67ec3ca6978ea7", "reference": "ecb0b2cdaa0add708fe6f329ef65ae0c5225130b",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"ext-tokenizer": "*", "ext-tokenizer": "*",
"php": ">=5.3.3" "php": "^7.0"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "~4.2" "phpunit/phpunit": "^6.2.4"
}, },
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "1.4-dev" "dev-master": "2.0-dev"
} }
}, },
"autoload": { "autoload": {
@ -1267,20 +1352,20 @@
"keywords": [ "keywords": [
"tokenizer" "tokenizer"
], ],
"time": "2017-02-27T10:12:30+00:00" "time": "2017-08-03 14:17:41"
}, },
{ {
"name": "phpunit/phpunit", "name": "phpunit/phpunit",
"version": "6.2.3", "version": "6.2.4",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git", "url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "fa5711d0559fc4b64deba0702be52d41434cbcb7" "reference": "ff3a76a58ac293657808aefd58c8aaf05945f4d9"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/fa5711d0559fc4b64deba0702be52d41434cbcb7", "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/ff3a76a58ac293657808aefd58c8aaf05945f4d9",
"reference": "fa5711d0559fc4b64deba0702be52d41434cbcb7", "reference": "ff3a76a58ac293657808aefd58c8aaf05945f4d9",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1300,7 +1385,7 @@
"phpunit/php-timer": "^1.0.6", "phpunit/php-timer": "^1.0.6",
"phpunit/phpunit-mock-objects": "^4.0", "phpunit/phpunit-mock-objects": "^4.0",
"sebastian/comparator": "^2.0", "sebastian/comparator": "^2.0",
"sebastian/diff": "^1.4.3 || ^2.0", "sebastian/diff": "^1.4.3",
"sebastian/environment": "^3.0.2", "sebastian/environment": "^3.0.2",
"sebastian/exporter": "^3.1", "sebastian/exporter": "^3.1",
"sebastian/global-state": "^1.1 || ^2.0", "sebastian/global-state": "^1.1 || ^2.0",
@ -1351,26 +1436,26 @@
"testing", "testing",
"xunit" "xunit"
], ],
"time": "2017-07-03T15:54:24+00:00" "time": "2017-08-03 13:59:28"
}, },
{ {
"name": "phpunit/phpunit-mock-objects", "name": "phpunit/phpunit-mock-objects",
"version": "4.0.2", "version": "4.0.4",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git",
"reference": "d8833b396dce9162bb2eb5d59aee5a3ab3cfa5b4" "reference": "2f789b59ab89669015ad984afa350c4ec577ade0"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/d8833b396dce9162bb2eb5d59aee5a3ab3cfa5b4", "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/2f789b59ab89669015ad984afa350c4ec577ade0",
"reference": "d8833b396dce9162bb2eb5d59aee5a3ab3cfa5b4", "reference": "2f789b59ab89669015ad984afa350c4ec577ade0",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"doctrine/instantiator": "^1.0.2", "doctrine/instantiator": "^1.0.5",
"php": "^7.0", "php": "^7.0",
"phpunit/php-text-template": "^1.2", "phpunit/php-text-template": "^1.2.1",
"sebastian/exporter": "^3.0" "sebastian/exporter": "^3.0"
}, },
"conflict": { "conflict": {
@ -1410,7 +1495,7 @@
"mock", "mock",
"xunit" "xunit"
], ],
"time": "2017-06-30T08:15:21+00:00" "time": "2017-08-03 14:08:16"
}, },
{ {
"name": "psr/log", "name": "psr/log",
@ -1457,7 +1542,7 @@
"psr", "psr",
"psr-3" "psr-3"
], ],
"time": "2016-10-10T12:19:37+00:00" "time": "2016-10-10 12:19:37"
}, },
{ {
"name": "sebastian/code-unit-reverse-lookup", "name": "sebastian/code-unit-reverse-lookup",
@ -1502,7 +1587,7 @@
], ],
"description": "Looks up which function or method a line of code belongs to", "description": "Looks up which function or method a line of code belongs to",
"homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/",
"time": "2017-03-04T06:30:41+00:00" "time": "2017-03-04 06:30:41"
}, },
{ {
"name": "sebastian/comparator", "name": "sebastian/comparator",
@ -1566,7 +1651,7 @@
"compare", "compare",
"equality" "equality"
], ],
"time": "2017-03-03T06:26:08+00:00" "time": "2017-03-03 06:26:08"
}, },
{ {
"name": "sebastian/diff", "name": "sebastian/diff",
@ -1618,7 +1703,7 @@
"keywords": [ "keywords": [
"diff" "diff"
], ],
"time": "2017-05-22T07:24:03+00:00" "time": "2017-05-22 07:24:03"
}, },
{ {
"name": "sebastian/environment", "name": "sebastian/environment",
@ -1668,7 +1753,7 @@
"environment", "environment",
"hhvm" "hhvm"
], ],
"time": "2017-07-01T08:51:00+00:00" "time": "2017-07-01 08:51:00"
}, },
{ {
"name": "sebastian/exporter", "name": "sebastian/exporter",
@ -1735,7 +1820,7 @@
"export", "export",
"exporter" "exporter"
], ],
"time": "2017-04-03T13:19:02+00:00" "time": "2017-04-03 13:19:02"
}, },
{ {
"name": "sebastian/global-state", "name": "sebastian/global-state",
@ -1786,25 +1871,25 @@
"keywords": [ "keywords": [
"global state" "global state"
], ],
"time": "2017-04-27T15:39:26+00:00" "time": "2017-04-27 15:39:26"
}, },
{ {
"name": "sebastian/object-enumerator", "name": "sebastian/object-enumerator",
"version": "3.0.2", "version": "3.0.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/object-enumerator.git", "url": "https://github.com/sebastianbergmann/object-enumerator.git",
"reference": "31dd3379d16446c5d86dec32ab1ad1f378581ad8" "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/31dd3379d16446c5d86dec32ab1ad1f378581ad8", "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/7cfd9e65d11ffb5af41198476395774d4c8a84c5",
"reference": "31dd3379d16446c5d86dec32ab1ad1f378581ad8", "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": "^7.0", "php": "^7.0",
"sebastian/object-reflector": "^1.0", "sebastian/object-reflector": "^1.1.1",
"sebastian/recursion-context": "^3.0" "sebastian/recursion-context": "^3.0"
}, },
"require-dev": { "require-dev": {
@ -1833,7 +1918,7 @@
], ],
"description": "Traverses array structures and object graphs to enumerate all referenced objects", "description": "Traverses array structures and object graphs to enumerate all referenced objects",
"homepage": "https://github.com/sebastianbergmann/object-enumerator/", "homepage": "https://github.com/sebastianbergmann/object-enumerator/",
"time": "2017-03-12T15:17:29+00:00" "time": "2017-08-03 12:35:26"
}, },
{ {
"name": "sebastian/object-reflector", "name": "sebastian/object-reflector",
@ -1878,7 +1963,7 @@
], ],
"description": "Allows reflection of object attributes, including inherited and non-public ones", "description": "Allows reflection of object attributes, including inherited and non-public ones",
"homepage": "https://github.com/sebastianbergmann/object-reflector/", "homepage": "https://github.com/sebastianbergmann/object-reflector/",
"time": "2017-03-29T09:07:27+00:00" "time": "2017-03-29 09:07:27"
}, },
{ {
"name": "sebastian/recursion-context", "name": "sebastian/recursion-context",
@ -1931,7 +2016,7 @@
], ],
"description": "Provides functionality to recursively process PHP variables", "description": "Provides functionality to recursively process PHP variables",
"homepage": "http://www.github.com/sebastianbergmann/recursion-context", "homepage": "http://www.github.com/sebastianbergmann/recursion-context",
"time": "2017-03-03T06:23:57+00:00" "time": "2017-03-03 06:23:57"
}, },
{ {
"name": "sebastian/resource-operations", "name": "sebastian/resource-operations",
@ -1973,7 +2058,7 @@
], ],
"description": "Provides a list of PHP built-in functions that operate on resources", "description": "Provides a list of PHP built-in functions that operate on resources",
"homepage": "https://www.github.com/sebastianbergmann/resource-operations", "homepage": "https://www.github.com/sebastianbergmann/resource-operations",
"time": "2015-07-28T20:34:47+00:00" "time": "2015-07-28 20:34:47"
}, },
{ {
"name": "sebastian/version", "name": "sebastian/version",
@ -2016,20 +2101,20 @@
], ],
"description": "Library that helps with managing the version number of Git-hosted PHP projects", "description": "Library that helps with managing the version number of Git-hosted PHP projects",
"homepage": "https://github.com/sebastianbergmann/version", "homepage": "https://github.com/sebastianbergmann/version",
"time": "2016-10-03T07:35:21+00:00" "time": "2016-10-03 07:35:21"
}, },
{ {
"name": "symfony/console", "name": "symfony/console",
"version": "v3.3.5", "version": "v3.3.6",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/console.git", "url": "https://github.com/symfony/console.git",
"reference": "a97e45d98c59510f085fa05225a1acb74dfe0546" "reference": "b0878233cb5c4391347e5495089c7af11b8e6201"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/a97e45d98c59510f085fa05225a1acb74dfe0546", "url": "https://api.github.com/repos/symfony/console/zipball/b0878233cb5c4391347e5495089c7af11b8e6201",
"reference": "a97e45d98c59510f085fa05225a1acb74dfe0546", "reference": "b0878233cb5c4391347e5495089c7af11b8e6201",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -2085,20 +2170,20 @@
], ],
"description": "Symfony Console Component", "description": "Symfony Console Component",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"time": "2017-07-03T13:19:36+00:00" "time": "2017-07-29 21:27:59"
}, },
{ {
"name": "symfony/debug", "name": "symfony/debug",
"version": "v3.3.5", "version": "v3.3.6",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/debug.git", "url": "https://github.com/symfony/debug.git",
"reference": "63b85a968486d95ff9542228dc2e4247f16f9743" "reference": "7c13ae8ce1e2adbbd574fc39de7be498e1284e13"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/debug/zipball/63b85a968486d95ff9542228dc2e4247f16f9743", "url": "https://api.github.com/repos/symfony/debug/zipball/7c13ae8ce1e2adbbd574fc39de7be498e1284e13",
"reference": "63b85a968486d95ff9542228dc2e4247f16f9743", "reference": "7c13ae8ce1e2adbbd574fc39de7be498e1284e13",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -2141,11 +2226,11 @@
], ],
"description": "Symfony Debug Component", "description": "Symfony Debug Component",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"time": "2017-07-05T13:02:37+00:00" "time": "2017-07-28 15:27:31"
}, },
{ {
"name": "symfony/event-dispatcher", "name": "symfony/event-dispatcher",
"version": "v3.3.5", "version": "v3.3.6",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/event-dispatcher.git", "url": "https://github.com/symfony/event-dispatcher.git",
@ -2204,11 +2289,11 @@
], ],
"description": "Symfony EventDispatcher Component", "description": "Symfony EventDispatcher Component",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"time": "2017-06-09T14:53:08+00:00" "time": "2017-06-09 14:53:08"
}, },
{ {
"name": "symfony/filesystem", "name": "symfony/filesystem",
"version": "v3.3.5", "version": "v3.3.6",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/filesystem.git", "url": "https://github.com/symfony/filesystem.git",
@ -2253,11 +2338,11 @@
], ],
"description": "Symfony Filesystem Component", "description": "Symfony Filesystem Component",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"time": "2017-07-11T07:17:58+00:00" "time": "2017-07-11 07:17:58"
}, },
{ {
"name": "symfony/finder", "name": "symfony/finder",
"version": "v3.3.5", "version": "v3.3.6",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/finder.git", "url": "https://github.com/symfony/finder.git",
@ -2302,11 +2387,11 @@
], ],
"description": "Symfony Finder Component", "description": "Symfony Finder Component",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"time": "2017-06-01T21:01:25+00:00" "time": "2017-06-01 21:01:25"
}, },
{ {
"name": "symfony/options-resolver", "name": "symfony/options-resolver",
"version": "v3.3.5", "version": "v3.3.6",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/options-resolver.git", "url": "https://github.com/symfony/options-resolver.git",
@ -2356,7 +2441,7 @@
"configuration", "configuration",
"options" "options"
], ],
"time": "2017-04-12T14:14:56+00:00" "time": "2017-04-12 14:14:56"
}, },
{ {
"name": "symfony/polyfill-mbstring", "name": "symfony/polyfill-mbstring",
@ -2415,7 +2500,7 @@
"portable", "portable",
"shim" "shim"
], ],
"time": "2017-06-09T14:24:12+00:00" "time": "2017-06-09 14:24:12"
}, },
{ {
"name": "symfony/polyfill-php54", "name": "symfony/polyfill-php54",
@ -2473,7 +2558,7 @@
"portable", "portable",
"shim" "shim"
], ],
"time": "2017-06-09T08:25:21+00:00" "time": "2017-06-09 08:25:21"
}, },
{ {
"name": "symfony/polyfill-php55", "name": "symfony/polyfill-php55",
@ -2529,7 +2614,7 @@
"portable", "portable",
"shim" "shim"
], ],
"time": "2017-06-09T08:25:21+00:00" "time": "2017-06-09 08:25:21"
}, },
{ {
"name": "symfony/polyfill-php70", "name": "symfony/polyfill-php70",
@ -2588,7 +2673,7 @@
"portable", "portable",
"shim" "shim"
], ],
"time": "2017-06-09T14:24:12+00:00" "time": "2017-06-09 14:24:12"
}, },
{ {
"name": "symfony/polyfill-php72", "name": "symfony/polyfill-php72",
@ -2643,11 +2728,11 @@
"portable", "portable",
"shim" "shim"
], ],
"time": "2017-06-09T08:25:21+00:00" "time": "2017-06-09 08:25:21"
}, },
{ {
"name": "symfony/process", "name": "symfony/process",
"version": "v3.3.5", "version": "v3.3.6",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/process.git", "url": "https://github.com/symfony/process.git",
@ -2692,11 +2777,11 @@
], ],
"description": "Symfony Process Component", "description": "Symfony Process Component",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"time": "2017-07-13T13:05:09+00:00" "time": "2017-07-13 13:05:09"
}, },
{ {
"name": "symfony/stopwatch", "name": "symfony/stopwatch",
"version": "v3.3.5", "version": "v3.3.6",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/stopwatch.git", "url": "https://github.com/symfony/stopwatch.git",
@ -2741,7 +2826,7 @@
], ],
"description": "Symfony Stopwatch Component", "description": "Symfony Stopwatch Component",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"time": "2017-04-12T14:14:56+00:00" "time": "2017-04-12 14:14:56"
}, },
{ {
"name": "theseer/tokenizer", "name": "theseer/tokenizer",
@ -2781,7 +2866,7 @@
} }
], ],
"description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
"time": "2017-04-07T12:08:54+00:00" "time": "2017-04-07 12:08:54"
}, },
{ {
"name": "webmozart/assert", "name": "webmozart/assert",
@ -2831,7 +2916,7 @@
"check", "check",
"validate" "validate"
], ],
"time": "2016-11-23T20:04:58+00:00" "time": "2016-11-23 20:04:58"
} }
], ],
"aliases": [], "aliases": [],

81
docs/guide/caching-data.md

@ -12,7 +12,7 @@ a [cache component](#cache-components):
// try retrieving $data from cache // try retrieving $data from cache
$data = $cache->get($key); $data = $cache->get($key);
if ($data === false) { if ($data === null) {
// $data is not found in cache, calculate it from scratch // $data is not found in cache, calculate it from scratch
$data = $this->calculateSomething(); $data = $this->calculateSomething();
@ -58,12 +58,14 @@ such as memory, files, databases.
Cache components are usually registered as [application components](structure-application-components.md) so Cache components are usually registered as [application components](structure-application-components.md) so
that they can be globally configurable that they can be globally configurable
and accessible. The following code shows how to configure the `cache` application component to use and accessible. The following code shows how to configure the `cache` application component to use
[memcached](http://memcached.org/) with two cache servers: [memcached](http://memcached.org/) handler with two cache servers:
```php ```php
'components' => [ 'components' => [
'cache' => [ 'cache' => [
'class' => 'yii\caching\MemCache', 'class' => yii\caching\Cache::class,
'handler' => [
'class' => yii\caching\MemCache::class,
'servers' => [ 'servers' => [
[ [
'host' => 'server1', 'host' => 'server1',
@ -77,12 +79,13 @@ and accessible. The following code shows how to configure the `cache` applicatio
], ],
], ],
], ],
],
], ],
``` ```
You can then access the above cache component using the expression `Yii::$app->cache`. You can then access the above cache component using the expression `Yii::$app->cache`.
Because all cache components support the same set of APIs, you can swap the underlying cache component Because all cache handlers support the same set of APIs, you can swap the underlying cache component
with a different one by reconfiguring it in the application configuration without modifying the code that uses the cache. with a different one by reconfiguring it in the application configuration without modifying the code that uses the cache.
For example, you can modify the above configuration to use [[yii\caching\ApcCache|APC cache]]: For example, you can modify the above configuration to use [[yii\caching\ApcCache|APC cache]]:
@ -90,7 +93,10 @@ For example, you can modify the above configuration to use [[yii\caching\ApcCach
```php ```php
'components' => [ 'components' => [
'cache' => [ 'cache' => [
'class' => 'yii\caching\ApcCache', 'class' => yii\caching\Cache::class,
'handler' => [
'class' => yii\caching\ApcCache::class,
],
], ],
], ],
``` ```
@ -101,7 +107,7 @@ For example, you can modify the above configuration to use [[yii\caching\ApcCach
### Supported Cache Storage <span id="supported-cache-storage"></span> ### Supported Cache Storage <span id="supported-cache-storage"></span>
Yii supports a wide range of cache storage. The following is a summary: Yii supports a wide range of cache handlers. The following is a summary:
* [[yii\caching\ApcCache]]: uses PHP [APC](http://php.net/manual/en/book.apc.php) extension. This option can be * [[yii\caching\ApcCache]]: uses PHP [APC](http://php.net/manual/en/book.apc.php) extension. This option can be
considered as the fastest one when dealing with cache for a centralized thick application (e.g. one considered as the fastest one when dealing with cache for a centralized thick application (e.g. one
@ -117,10 +123,9 @@ Yii supports a wide range of cache storage. The following is a summary:
`Yii::$app->cache` might be `null`. `Yii::$app->cache` might be `null`.
* [[yii\caching\FileCache]]: uses standard files to store cached data. This is particularly suitable * [[yii\caching\FileCache]]: uses standard files to store cached data. This is particularly suitable
to cache large chunk of data, such as page content. to cache large chunk of data, such as page content.
* [[yii\caching\MemCache]]: uses PHP [memcache](http://php.net/manual/en/book.memcache.php) * [[yii\caching\MemCached]]: uses PHP [memcached](http://php.net/manual/en/book.memcached.php) extension.
and [memcached](http://php.net/manual/en/book.memcached.php) extensions. This option can be considered as This option can be considered as the fastest one when dealing with cache in a distributed applications
the fastest one when dealing with cache in a distributed applications (e.g. with several servers, load (e.g. with several servers, load balancers, etc.)
balancers, etc.)
* [[yii\redis\Cache]]: implements a cache component based on [Redis](http://redis.io/) key-value store * [[yii\redis\Cache]]: implements a cache component based on [Redis](http://redis.io/) key-value store
(redis version 2.6.12 or higher is required). (redis version 2.6.12 or higher is required).
* [[yii\caching\WinCache]]: uses PHP [WinCache](http://iis.net/downloads/microsoft/wincache-extension) * [[yii\caching\WinCache]]: uses PHP [WinCache](http://iis.net/downloads/microsoft/wincache-extension)
@ -136,27 +141,31 @@ Yii supports a wide range of cache storage. The following is a summary:
All cache components have the same base class [[yii\caching\Cache]] and thus support the following APIs: All cache components have the same base class [[yii\caching\Cache]] and thus support the following APIs:
* [[yii\caching\Cache::get()|get()]]: retrieves a data item from cache with a specified key. A `false` * [[yii\caching\Cache::get()|get()]]: retrieves a data item from cache with a specified key. A `null`
value will be returned if the data item is not found in the cache or is expired/invalidated. value will be returned if the data item is not found in the cache or is expired/invalidated. Alternatively you can specify
default value to return by passing it as a second argument.
* [[yii\caching\Cache::getMultiple()|getMultiple()]]: retrieves multiple data items from cache with the specified keys. For each
key if the data item is not found in the cache or is expired/invalidated, `null` is returned. Alternatively you can specify
default value to return by passing it as a second argument.
* [[yii\caching\Cache::set()|set()]]: stores a data item identified by a key in cache. * [[yii\caching\Cache::set()|set()]]: stores a data item identified by a key in cache.
* [[yii\caching\Cache::setMultiple()|setMultiple()]]: stores multiple data items in cache. Each item is identified by a key.
* [[yii\caching\Cache::add()|add()]]: stores a data item identified by a key in cache if the key is not found in the cache. * [[yii\caching\Cache::add()|add()]]: stores a data item identified by a key in cache if the key is not found in the cache.
* [[yii\caching\Cache::addMultiple()|addMultiple()]]: stores multiple data items in cache. Each item is identified by a key.
If a key already exists in the cache, the data item will be skipped.
* [[yii\caching\Cache::getOrSet()|getOrSet()]]: retrieves a data item from cache with a specified key or executes passed * [[yii\caching\Cache::getOrSet()|getOrSet()]]: retrieves a data item from cache with a specified key or executes passed
callback, stores return of the callback in a cache by a key and returns that data. callback, stores return of the callback in a cache by a key and returns that data.
* [[yii\caching\Cache::multiGet()|multiGet()]]: retrieves multiple data items from cache with the specified keys. * [[yii\caching\Cache::has()|has()]]: returns a value indicating whether the specified key is found in the cache.
* [[yii\caching\Cache::multiSet()|multiSet()]]: stores multiple data items in cache. Each item is identified by a key.
* [[yii\caching\Cache::multiAdd()|multiAdd()]]: stores multiple data items in cache. Each item is identified by a key.
If a key already exists in the cache, the data item will be skipped.
* [[yii\caching\Cache::exists()|exists()]]: returns a value indicating whether the specified key is found in the cache.
* [[yii\caching\Cache::delete()|delete()]]: removes a data item identified by a key from the cache. * [[yii\caching\Cache::delete()|delete()]]: removes a data item identified by a key from the cache.
* [[yii\caching\Cache::flush()|flush()]]: removes all data items from the cache. * [[yii\caching\Cache::deleteMultiple()|deleteMultiple()]]: removes multiple data items identified by array of keys from cache.
* [[yii\caching\Cache::clear()|clear()]]: removes all data items from the cache.
> Note: Do not cache a `false` boolean value directly because the [[yii\caching\Cache::get()|get()]] method uses > Note: Do not cache a `null` value directly because the [[yii\caching\Cache::get()|get()]] method uses
`false` return value to indicate the data item is not found in the cache. You may put `false` in an array and cache `null` return value to indicate the data item is not found in the cache. You may put `null` in an array and cache
this array instead to avoid this problem. this array instead to avoid this problem.
Some cache storage, such as MemCache, APC, support retrieving multiple cached values in a batch mode, Some cache storage, such as MemCache, APC, support retrieving multiple cached values in a batch mode,
which may reduce the overhead involved in retrieving cached data. The APIs [[yii\caching\Cache::multiGet()|multiGet()]] which may reduce the overhead involved in retrieving cached data. The APIs [[yii\caching\Cache::getMultiple()|getMultiple()]]
and [[yii\caching\Cache::multiAdd()|multiAdd()]] are provided to exploit this feature. In case the underlying cache storage and [[yii\caching\Cache::addMultiple()|addMultiple()]] are provided to exploit this feature. In case the underlying cache storage
does not support this feature, it will be simulated. does not support this feature, it will be simulated.
Because [[yii\caching\Cache]] implements `ArrayAccess`, a cache component can be used like an array. The following Because [[yii\caching\Cache]] implements `ArrayAccess`, a cache component can be used like an array. The following
@ -191,20 +200,23 @@ For example, [[yii\db\Schema]] uses the following key to cache schema informatio
As you can see, the key includes all necessary information needed to uniquely specify a database table. As you can see, the key includes all necessary information needed to uniquely specify a database table.
> Note: Values stored in cache via [[yii\caching\Cache::multiSet()|multiSet()]] or [[yii\caching\Cache::multiAdd()|multiAdd()]] can > Note: Values stored in cache via [[yii\caching\Cache::setMultiple()|setMultiple()]] or [[yii\caching\Cache::addMultiple()|addMultiple()]] can
have only string or integer keys. If you need to set more complex key store the value separately via have only string or integer keys. If you need to set more complex key store the value separately via
[[yii\caching\Cache::set()|set()]] or [[yii\caching\Cache::add()|add()]]. [[yii\caching\Cache::set()|set()]] or [[yii\caching\Cache::add()|add()]].
When the same cache storage is used by different applications, you should specify a unique cache key prefix When the same cache storage is used by different applications, you should specify a unique cache key prefix
for each application to avoid conflicts of cache keys. This can be done by configuring the [[yii\caching\Cache::keyPrefix]] for each application to avoid conflicts of cache keys. This can be done by configuring the [[yii\caching\SimpleCache::keyPrefix]]
property. For example, in the application configuration you can write the following code: property. For example, in the application configuration you can write the following code:
```php ```php
'components' => [ 'components' => [
'cache' => [ 'cache' => [
'class' => 'yii\caching\Cache',
'handler' => [
'class' => 'yii\caching\ApcCache', 'class' => 'yii\caching\ApcCache',
'keyPrefix' => 'myapp', // a unique cache key prefix 'keyPrefix' => 'myapp', // a unique cache key prefix
], ],
],
], ],
``` ```
@ -227,14 +239,13 @@ $cache->set($key, $data, 45);
sleep(50); sleep(50);
$data = $cache->get($key); $data = $cache->get($key);
if ($data === false) { if ($data === null) {
// $data is expired or is not found in the cache // $data is expired or is not found in the cache
} }
``` ```
Since 2.0.11 you may set [[yii\caching\Cache::$defaultDuration|defaultDuration]] value in your cache component configuration if you prefer a custom cache duration Since 2.0.11 you may set [[yii\caching\SimpleCache::$defaultTtl|defaultTtl]] value in your cache component handler configuration if you prefer a custom cache duration over the default unlimited duration.
over the default unlimited duration. This will allow you not to pass custom `ttl` parameter to [[yii\caching\Cache::set()|set()]] each time.
This will allow you not to pass custom `duration` parameter to [[yii\caching\Cache::set()|set()]] each time.
### Cache Dependencies <span id="cache-dependencies"></span> ### Cache Dependencies <span id="cache-dependencies"></span>
@ -272,9 +283,9 @@ Below is a summary of the available cache dependencies:
- [[yii\caching\TagDependency]]: associates a cached data item with one or multiple tags. You may invalidate - [[yii\caching\TagDependency]]: associates a cached data item with one or multiple tags. You may invalidate
the cached data items with the specified tag(s) by calling [[yii\caching\TagDependency::invalidate()]]. the cached data items with the specified tag(s) by calling [[yii\caching\TagDependency::invalidate()]].
> Note: Avoid using [[yii\caching\Cache::exists()|exists()]] method along with dependencies. It does not check whether > Note: Avoid using [[yii\caching\Cache::has()|has()]] method along with dependencies. It does not check whether
the dependency associated with the cached data, if there is any, has changed. So a call to the dependency associated with the cached data, if there is any, has changed. So a call to
[[yii\caching\Cache::get()|get()]] may return `false` while [[yii\caching\Cache::exists()|exists()]] returns `true`. [[yii\caching\Cache::get()|get()]] may return `false` while [[yii\caching\Cache::has()|has()]] returns `true`.
## Query Caching <span id="query-caching"></span> ## Query Caching <span id="query-caching"></span>
@ -309,15 +320,15 @@ $result = Customer::getDb()->cache(function ($db) {
and are potentially more efficient. and are potentially more efficient.
### Cache Flushing <span id="cache-flushing"> ### Clearing Cache <span id="clearing-cache">
When you need to invalidate all the stored cache data, you can call [[yii\caching\Cache::flush()]]. When you need to invalidate all the stored cache data, you can call [[yii\caching\Cache::clear()]].
You can flush the cache from the console by calling `yii cache/flush` as well. You can flush the cache from the console by calling `yii cache/clear` as well.
- `yii cache`: lists the available caches in application - `yii cache`: lists the available caches in application
- `yii cache/flush cache1 cache2`: flushes the cache components `cache1`, `cache2` (you can pass multiple component - `yii cache/clear cache1 cache2`: clears the cache components `cache1`, `cache2` (you can pass multiple component
names separated with space) names separated with space)
- `yii cache/flush-all`: flushes all cache components in the application - `yii cache/clear-all`: clears all cache components in the application
> Info: Console application uses a separate configuration file by default. Ensure, that you have the same caching > Info: Console application uses a separate configuration file by default. Ensure, that you have the same caching
components in your web and console application configs to reach the proper effect. components in your web and console application configs to reach the proper effect.

1
framework/CHANGELOG.md

@ -4,6 +4,7 @@ Yii Framework 2 Change Log
2.1.0 under development 2.1.0 under development
----------------------- -----------------------
- Enh #879: Caching implementation refactored according to PSR-16 'Simple Cache' specification (klimov-paul)
- Enh #13799: CAPTCHA rendering logic extracted into `yii\captcha\DriverInterface`, which instance is available via `yii\captcha\CaptchaAction::$driver` field (vladis84, klimov-paul) - Enh #13799: CAPTCHA rendering logic extracted into `yii\captcha\DriverInterface`, which instance is available via `yii\captcha\CaptchaAction::$driver` field (vladis84, klimov-paul)
- Enh #9260: Mail view rendering encapsulated into `yii\mail\Template` class allowing rendering in isolation and access to `yii\mail\MessageInterface` instance via `$this->context->message` inside the view (klimov-paul) - Enh #9260: Mail view rendering encapsulated into `yii\mail\Template` class allowing rendering in isolation and access to `yii\mail\MessageInterface` instance via `$this->context->message` inside the view (klimov-paul)
- Enh #11058: Add `$checkAjax` parameter to method `yii\web\Controller::redirect()` which controls redirection in AJAX and PJAX requests (ivanovyordan) - Enh #11058: Add `$checkAjax` parameter to method `yii\web\Controller::redirect()` which controls redirection in AJAX and PJAX requests (ivanovyordan)

11
framework/UPGRADE.md

@ -73,6 +73,17 @@ Upgrade from Yii 2.0.x
instance is available via `yii\captcha\CaptchaAction::$driver` field. All image settings now should be passed to instance is available via `yii\captcha\CaptchaAction::$driver` field. All image settings now should be passed to
the driver fields instead of action. Automatic detection of the rendering driver is no longer supported. the driver fields instead of action. Automatic detection of the rendering driver is no longer supported.
* `yii\captcha\Captcha::checkRequirements()` method has been removed. * `yii\captcha\Captcha::checkRequirements()` method has been removed.
* All cache related classes interface has been changed according to PSR-16 "Simple Cache" specification. Make sure you
change your invocations for the cache methods accordingly. The most notable changes affects methods `get()` and `getMultiple()`
as they now accept `$default` argument, which value will be returned in case there is no value in the cache. This makes
the default return value to be `null` instead of `false`.
* Particular cache implementation should now be configured as `yii\caching\Cache::$handler` property instead of the
component itself. Properties `$defaultTtl`, `$serializer` and `$keyPrefix` has been moved to cache handler and should
be configured there. Creating your own cache implementation you should implement `\Psr\SimpleCache\CacheInterface` or
extend `yii\caching\SimpleCache` abstract class. Use `yii\caching\CacheInterface` only if you wish to replace `yii\caching\Cache`
component providing your own solution for cache dependency handling.
* Console command used to clear cache now calls related actions "clear" instead of "flush".
Upgrade from Yii 2.0.12 Upgrade from Yii 2.0.12
----------------------- -----------------------

106
framework/caching/ApcCache.php

@ -15,14 +15,31 @@ use yii\base\InvalidConfigException;
* To use this application component, the [APCu PHP extension](http://www.php.net/apcu) must be loaded. * To use this application component, the [APCu PHP extension](http://www.php.net/apcu) must be loaded.
* In order to enable APCu for CLI you should add "apc.enable_cli = 1" to your php.ini. * In order to enable APCu for CLI you should add "apc.enable_cli = 1" to your php.ini.
* *
* See [[Cache]] for common cache operations that ApcCache supports. * Application configuration example:
*
* ```php
* return [
* 'components' => [
* 'cache' => [
* 'class' => yii\caching\Cache::class,
* 'handler' => [
* 'class' => yii\caching\ApcCache::class,
* ],
* ],
* // ...
* ],
* // ...
* ];
* ```
*
* See [[\Psr\SimpleCache\CacheInterface]] for common cache operations that ApcCache supports.
* *
* For more details and usage information on Cache, see the [guide article on caching](guide:caching-overview). * For more details and usage information on Cache, see the [guide article on caching](guide:caching-overview).
* *
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
*/ */
class ApcCache extends Cache class ApcCache extends SimpleCache
{ {
/** /**
* Initializes this application component. * Initializes this application component.
@ -38,27 +55,15 @@ class ApcCache extends Cache
} }
/** /**
* Checks whether a specified key exists in the cache. * {@inheritdoc}
* This can be faster than getting the value from the cache if the data is big.
* Note that this method does not check whether the dependency associated
* with the cached data, if there is any, has changed. So a call to [[get]]
* may return false while exists returns true.
* @param mixed $key a key identifying the cached value. This can be a simple string or
* a complex data structure consisting of factors representing the key.
* @return bool true if a value exists in cache, false if the value is not in the cache or expired.
*/ */
public function exists($key) public function has($key)
{ {
$key = $this->buildKey($key); return apcu_exists($this->normalizeKey($key));
return apcu_exists($key);
} }
/** /**
* Retrieves a value from cache with a specified key. * {@inheritdoc}
* This is the implementation of the method declared in the parent class.
* @param string $key a unique key identifying the cached value
* @return mixed|false the value stored in cache, false if the value is not in the cache or expired.
*/ */
protected function getValue($key) protected function getValue($key)
{ {
@ -66,9 +71,7 @@ class ApcCache extends Cache
} }
/** /**
* Retrieves multiple values from cache with the specified keys. * {@inheritdoc}
* @param array $keys a list of keys identifying the cached values
* @return array a list of cached values indexed by the keys
*/ */
protected function getValues($keys) protected function getValues($keys)
{ {
@ -77,63 +80,24 @@ class ApcCache extends Cache
} }
/** /**
* Stores a value identified by a key in cache. * {@inheritdoc}
* This is the implementation of the method declared in the parent class.
*
* @param string $key the key identifying the value to be cached
* @param mixed $value the value to be cached. Most often it's a string. If you have disabled [[serializer]],
* it could be something else.
* @param int $duration the number of seconds in which the cached value will expire. 0 means never expire.
* @return bool true if the value is successfully stored into cache, false otherwise.
*/
protected function setValue($key, $value, $duration)
{
return apcu_store($key, $value, $duration);
}
/**
* Stores multiple key-value pairs in cache.
* @param array $data array where key corresponds to cache key while value
* @param int $duration the number of seconds in which the cached values will expire. 0 means never expire.
* @return array array of failed keys
*/
protected function setValues($data, $duration)
{
$result = apcu_store($data, null, $duration);
return is_array($result) ? array_keys($result) : [];
}
/**
* Stores a value identified by a key into cache if the cache does not contain this key.
* This is the implementation of the method declared in the parent class.
* @param string $key the key identifying the value to be cached
* @param mixed $value the value to be cached. Most often it's a string. If you have disabled [[serializer]],
* it could be something else.
* @param int $duration the number of seconds in which the cached value will expire. 0 means never expire.
* @return bool true if the value is successfully stored into cache, false otherwise
*/ */
protected function addValue($key, $value, $duration) protected function setValue($key, $value, $ttl)
{ {
return apcu_add($key, $value, $duration); return apcu_store($key, $value, $ttl);
} }
/** /**
* Adds multiple key-value pairs to cache. * {@inheritdoc}
* @param array $data array where key corresponds to cache key while value is the value stored
* @param int $duration the number of seconds in which the cached values will expire. 0 means never expire.
* @return array array of failed keys
*/ */
protected function addValues($data, $duration) protected function setValues($values, $ttl)
{ {
$result = apcu_add($data, null, $duration); $result = apcu_store($values, null, $ttl);
return is_array($result) ? array_keys($result) : []; return is_array($result);
} }
/** /**
* Deletes a value with the specified key from cache * {@inheritdoc}
* This is the implementation of the method declared in the parent class.
* @param string $key the key of the value to be deleted
* @return bool if no error happens during deletion
*/ */
protected function deleteValue($key) protected function deleteValue($key)
{ {
@ -141,11 +105,9 @@ class ApcCache extends Cache
} }
/** /**
* Deletes all values from cache. * {@inheritdoc}
* This is the implementation of the method declared in the parent class.
* @return bool whether the flush operation was successful.
*/ */
protected function flushValues() public function clear()
{ {
return apcu_clear_cache(); return apcu_clear_cache();
} }

50
framework/caching/ArrayCache.php

@ -10,9 +10,26 @@ namespace yii\caching;
/** /**
* ArrayCache provides caching for the current request only by storing the values in an array. * ArrayCache provides caching for the current request only by storing the values in an array.
* *
* See [[Cache]] for common cache operations that ArrayCache supports. * Application configuration example:
* *
* Unlike the [[Cache]], ArrayCache allows the expire parameter of [[set]], [[add]], [[multiSet]] and [[multiAdd]] to * ```php
* return [
* 'components' => [
* 'cache' => [
* 'class' => yii\caching\Cache::class,
* 'handler' => [
* 'class' => yii\caching\ArrayCache::class,
* ],
* ],
* // ...
* ],
* // ...
* ];
* ```
*
* See [[\Psr\SimpleCache\CacheInterface]] for common cache operations that ArrayCache supports.
*
* Unlike the [[Cache]], ArrayCache allows the expire parameter of [[set()]] and [[setMultiple()]] to
* be a floating point number, so you may specify the time in milliseconds (e.g. 0.1 will be 100 milliseconds). * be a floating point number, so you may specify the time in milliseconds (e.g. 0.1 will be 100 milliseconds).
* *
* For enhanced performance of ArrayCache, you can disable serialization of the stored data by setting [[$serializer]] to `false`. * For enhanced performance of ArrayCache, you can disable serialization of the stored data by setting [[$serializer]] to `false`.
@ -22,17 +39,20 @@ namespace yii\caching;
* @author Carsten Brandt <mail@cebe.cc> * @author Carsten Brandt <mail@cebe.cc>
* @since 2.0 * @since 2.0
*/ */
class ArrayCache extends Cache class ArrayCache extends SimpleCache
{ {
private $_cache; /**
* @var array cached values.
*/
private $_cache = [];
/** /**
* @inheritdoc * @inheritdoc
*/ */
public function exists($key) public function has($key)
{ {
$key = $this->buildKey($key); $key = $this->normalizeKey($key);
return isset($this->_cache[$key]) && ($this->_cache[$key][1] === 0 || $this->_cache[$key][1] > microtime(true)); return isset($this->_cache[$key]) && ($this->_cache[$key][1] === 0 || $this->_cache[$key][1] > microtime(true));
} }
@ -50,21 +70,9 @@ class ArrayCache extends Cache
/** /**
* @inheritdoc * @inheritdoc
*/ */
protected function setValue($key, $value, $duration) protected function setValue($key, $value, $ttl)
{
$this->_cache[$key] = [$value, $duration === 0 ? 0 : microtime(true) + $duration];
return true;
}
/**
* @inheritdoc
*/
protected function addValue($key, $value, $duration)
{ {
if (isset($this->_cache[$key]) && ($this->_cache[$key][1] === 0 || $this->_cache[$key][1] > microtime(true))) { $this->_cache[$key] = [$value, $ttl === 0 ? 0 : microtime(true) + $ttl];
return false;
}
$this->_cache[$key] = [$value, $duration === 0 ? 0 : microtime(true) + $duration];
return true; return true;
} }
@ -80,7 +88,7 @@ class ArrayCache extends Cache
/** /**
* @inheritdoc * @inheritdoc
*/ */
protected function flushValues() public function clear()
{ {
$this->_cache = []; $this->_cache = [];
return true; return true;

363
framework/caching/Cache.php

@ -9,10 +9,31 @@ namespace yii\caching;
use Yii; use Yii;
use yii\base\Component; use yii\base\Component;
use yii\di\Instance;
use yii\helpers\StringHelper; use yii\helpers\StringHelper;
/** /**
* Cache is the base class for cache classes supporting different cache storage implementations. * Cache provides support for the data caching, including cache key composition and dependencies.
* The actual data caching is performed via [[handler]], which should be configured to be [[\Psr\SimpleCache\CacheInterface]]
* instance.
*
* Application configuration example:
*
* ```php
* return [
* 'components' => [
* 'cache' => [
* 'class' => yii\caching\Cache::class,
* 'handler' => [
* 'class' => yii\caching\FileCache::class,
* 'cachePath' => '@runtime/cache',
* ],
* ],
* // ...
* ],
* // ...
* ];
* ```
* *
* A data item can be stored in the cache by calling [[set()]] and be retrieved back * A data item can be stored in the cache by calling [[set()]] and be retrieved back
* later (in the same or different request) by [[get()]]. In both operations, * later (in the same or different request) by [[get()]]. In both operations,
@ -25,7 +46,7 @@ use yii\helpers\StringHelper;
* ```php * ```php
* $key = 'demo'; * $key = 'demo';
* $data = $cache->get($key); * $data = $cache->get($key);
* if ($data === false) { * if ($data === null) {
* // ...generate $data here... * // ...generate $data here...
* $cache->set($key, $data, $duration, $dependency); * $cache->set($key, $data, $duration, $dependency);
* } * }
@ -38,112 +59,79 @@ use yii\helpers\StringHelper;
* echo $cache['foo']; * echo $cache['foo'];
* ``` * ```
* *
* Derived classes should implement the following methods which do the actual cache storage operations: * For more details and usage information on Cache, see the [guide article on caching](guide:caching-overview)
* * and [PSR-16 specification](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-16-simple-cache.md).
* - [[getValue()]]: retrieve the value with a key (if any) from cache
* - [[setValue()]]: store the value with a key into cache
* - [[addValue()]]: store the value only if the cache does not have this key before
* - [[deleteValue()]]: delete the value with the specified key from cache
* - [[flushValues()]]: delete all values from cache
*
* For more details and usage information on Cache, see the [guide article on caching](guide:caching-overview).
* *
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
*/ */
abstract class Cache extends Component implements CacheInterface class Cache extends Component implements CacheInterface
{ {
/** /**
* @var string a string prefixed to every cache key so that it is unique globally in the whole cache storage. * @var \Psr\SimpleCache\CacheInterface|array|\Closure|string actual cache handler or its DI compatible configuration.
* It is recommended that you set a unique cache key prefix for each application if the same cache * After the Cache object is created, if you want to change this property, you should only assign it
* storage is being used by different applications. * with a [[\Psr\SimpleCache\CacheInterface]] instance.
* * @since 2.1.0
* To ensure interoperability, only alphanumeric characters should be used.
*/ */
public $keyPrefix; public $handler;
/**
* @var null|array|false the functions used to serialize and unserialize cached data. Defaults to null, meaning
* using the default PHP `serialize()` and `unserialize()` functions. If you want to use some more efficient
* serializer (e.g. [igbinary](http://pecl.php.net/package/igbinary)), you may configure this property with
* a two-element array. The first element specifies the serialization function, and the second the deserialization
* function. If this property is set false, data will be directly sent to and retrieved from the underlying
* cache component without any serialization or deserialization. You should not turn off serialization if
* you are using [[Dependency|cache dependency]], because it relies on data serialization. Also, some
* implementations of the cache can not correctly save and retrieve data different from a string type.
*/
public $serializer;
/** /**
* @var int default duration in seconds before a cache entry will expire. Default value is 0, meaning infinity. * {@inheritdoc}
* This value is used by [[set()]] if the duration is not explicitly given.
* @since 2.0.11
*/ */
public $defaultDuration = 0; public function init()
{
parent::init();
$this->handler = Instance::ensure($this->handler instanceof \Closure ? call_user_func($this->handler) : $this->handler, \Psr\SimpleCache\CacheInterface::class);
}
/** /**
* Builds a normalized cache key from a given key. * Builds a normalized cache key from a given key.
* *
* If the given key is a string containing alphanumeric characters only and no more than 32 characters, * If the given key is a string containing alphanumeric characters only and no more than 32 characters,
* then the key will be returned back prefixed with [[keyPrefix]]. Otherwise, a normalized key * then the key will be returned back as it is. Otherwise, a normalized key is generated by serializing
* is generated by serializing the given key, applying MD5 hashing, and prefixing with [[keyPrefix]]. * the given key and applying MD5 hashing.
* *
* @param mixed $key the key to be normalized * @param mixed $key the key to be normalized
* @return string the generated cache key * @return string the generated cache key
*/ */
public function buildKey($key) protected function buildKey($key)
{ {
if (is_string($key)) { if (is_string($key)) {
$key = ctype_alnum($key) && StringHelper::byteLength($key) <= 32 ? $key : md5($key); return ctype_alnum($key) && StringHelper::byteLength($key) <= 32 ? $key : md5($key);
} else {
$key = md5(json_encode($key));
} }
return md5(json_encode($key));
return $this->keyPrefix . $key;
} }
/** /**
* Retrieves a value from cache with a specified key. * {@inheritdoc}
* @param mixed $key a key identifying the cached value. This can be a simple string or
* a complex data structure consisting of factors representing the key.
* @return mixed the value stored in cache, false if the value is not in the cache, expired,
* or the dependency associated with the cached data has changed.
*/ */
public function get($key) public function get($key, $default = null)
{ {
$key = $this->buildKey($key); $key = $this->buildKey($key);
$value = $this->getValue($key); $value = $this->handler->get($key);
if ($value === false || $this->serializer === false) {
return $value; if ($value === null) {
} elseif ($this->serializer === null) { return $default;
$value = unserialize($value); }
} else {
$value = call_user_func($this->serializer[1], $value); if (is_array($value) && isset($value[1]) && $value[1] instanceof Dependency) {
if ($value[1]->isChanged($this)) {
return $default;
} }
if (is_array($value) && !($value[1] instanceof Dependency && $value[1]->isChanged($this))) {
return $value[0]; return $value[0];
} }
return false; return $value;
} }
/** /**
* Checks whether a specified key exists in the cache. * {@inheritdoc}
* This can be faster than getting the value from the cache if the data is big.
* In case a cache does not support this feature natively, this method will try to simulate it
* but has no performance improvement over getting it.
* Note that this method does not check whether the dependency associated
* with the cached data, if there is any, has changed. So a call to [[get]]
* may return false while exists returns true.
* @param mixed $key a key identifying the cached value. This can be a simple string or
* a complex data structure consisting of factors representing the key.
* @return bool true if a value exists in cache, false if the value is not in the cache or expired.
*/ */
public function exists($key) public function has($key)
{ {
$key = $this->buildKey($key); $key = $this->buildKey($key);
$value = $this->getValue($key); return $this->handler->has($key);
return $value !== false;
} }
/** /**
@ -152,32 +140,32 @@ abstract class Cache extends Component implements CacheInterface
* which may improve the performance. In case a cache does not support this feature natively, * which may improve the performance. In case a cache does not support this feature natively,
* this method will try to simulate it. * this method will try to simulate it.
* @param string[] $keys list of string keys identifying the cached values * @param string[] $keys list of string keys identifying the cached values
* @param mixed $default Default value to return for keys that do not exist.
* @return array list of cached values corresponding to the specified keys. The array * @return array list of cached values corresponding to the specified keys. The array
* is returned in terms of (key, value) pairs. * is returned in terms of (key, value) pairs.
* If a value is not cached or expired, the corresponding array value will be false. * If a value is not cached or expired, the corresponding array value will be false.
* @since 2.0.7 * @since 2.0.7
*/ */
public function multiGet($keys) public function getMultiple($keys, $default = null)
{ {
$keyMap = []; $keyMap = [];
foreach ($keys as $key) { foreach ($keys as $key) {
$keyMap[$key] = $this->buildKey($key); $keyMap[$key] = $this->buildKey($key);
} }
$values = $this->getValues(array_values($keyMap)); $values = $this->handler->getMultiple(array_values($keyMap));
$results = []; $results = [];
foreach ($keyMap as $key => $newKey) { foreach ($keyMap as $key => $newKey) {
$results[$key] = false; $results[$key] = $default;
if (isset($values[$newKey])) { if (isset($values[$newKey])) {
if ($this->serializer === false) { $value = $values[$newKey];
$results[$key] = $values[$newKey]; if (is_array($value) && isset($value[1]) && $value[1] instanceof Dependency) {
if ($value[1]->isChanged($this)) {
continue;
} else { } else {
$value = $this->serializer === null ? unserialize($values[$newKey]) $value = $value[0];
: call_user_func($this->serializer[1], $values[$newKey]);
if (is_array($value) && !($value[1] instanceof Dependency && $value[1]->isChanged($this))) {
$results[$key] = $value[0];
} }
} }
$results[$key] = $value;
} }
} }
@ -192,30 +180,20 @@ abstract class Cache extends Component implements CacheInterface
* @param mixed $key a key identifying the value to be cached. This can be a simple string or * @param mixed $key a key identifying the value to be cached. This can be a simple string or
* a complex data structure consisting of factors representing the key. * a complex data structure consisting of factors representing the key.
* @param mixed $value the value to be cached * @param mixed $value the value to be cached
* @param int $duration default duration in seconds before the cache will expire. If not set, * @param null|int|\DateInterval $ttl the TTL value of this item. If not set, default value is used.
* default [[defaultDuration]] value is used.
* @param Dependency $dependency dependency of the cached item. If the dependency changes, * @param Dependency $dependency dependency of the cached item. If the dependency changes,
* the corresponding value in the cache will be invalidated when it is fetched via [[get()]]. * the corresponding value in the cache will be invalidated when it is fetched via [[get()]].
* This parameter is ignored if [[serializer]] is false. * This parameter is ignored if [[serializer]] is false.
* @return bool whether the value is successfully stored into cache * @return bool whether the value is successfully stored into cache
*/ */
public function set($key, $value, $duration = null, $dependency = null) public function set($key, $value, $ttl = null, $dependency = null)
{ {
if ($duration === null) { if ($dependency !== null) {
$duration = $this->defaultDuration;
}
if ($dependency !== null && $this->serializer !== false) {
$dependency->evaluateDependency($this); $dependency->evaluateDependency($this);
} $value = [$value, $dependency];
if ($this->serializer === null) {
$value = serialize([$value, $dependency]);
} elseif ($this->serializer !== false) {
$value = call_user_func($this->serializer[0], [$value, $dependency]);
} }
$key = $this->buildKey($key); $key = $this->buildKey($key);
return $this->handler->set($key, $value, $ttl);
return $this->setValue($key, $value, $duration);
} }
/** /**
@ -224,65 +202,79 @@ abstract class Cache extends Component implements CacheInterface
* expiration time will be replaced with the new ones, respectively. * expiration time will be replaced with the new ones, respectively.
* *
* @param array $items the items to be cached, as key-value pairs. * @param array $items the items to be cached, as key-value pairs.
* @param int $duration default number of seconds in which the cached values will expire. 0 means never expire. * @param null|int|\DateInterval $ttl the TTL value of this item. If not set, default value is used.
* @param Dependency $dependency dependency of the cached items. If the dependency changes, * @param Dependency $dependency dependency of the cached items. If the dependency changes,
* the corresponding values in the cache will be invalidated when it is fetched via [[get()]]. * the corresponding values in the cache will be invalidated when it is fetched via [[get()]].
* This parameter is ignored if [[serializer]] is false. * This parameter is ignored if [[serializer]] is false.
* @return array array of failed keys * @return array array of failed keys
* @since 2.0.7 * @since 2.0.7
*/ */
public function multiSet($items, $duration = 0, $dependency = null) public function setMultiple($items, $ttl = 0, $dependency = null)
{ {
if ($dependency !== null && $this->serializer !== false) { if ($dependency !== null) {
$dependency->evaluateDependency($this); $dependency->evaluateDependency($this);
} }
$data = []; $data = [];
foreach ($items as $key => $value) { foreach ($items as $key => $value) {
if ($this->serializer === null) { if ($dependency !== null) {
$value = serialize([$value, $dependency]); $value = [$value, $dependency];
} elseif ($this->serializer !== false) {
$value = call_user_func($this->serializer[0], [$value, $dependency]);
} }
$key = $this->buildKey($key); $key = $this->buildKey($key);
$data[$key] = $value; $data[$key] = $value;
} }
return $this->setValues($data, $duration); return $this->handler->setMultiple($data, $ttl);
}
/**
* {@inheritdoc}
* @since 2.1
*/
public function deleteMultiple($keys)
{
$actualKeys = [];
foreach ($keys as $key) {
$actualKeys[] = $this->buildKey($key);
}
return $this->handler->deleteMultiple($actualKeys);
} }
/** /**
* Stores multiple items in cache. Each item contains a value identified by a key. * Stores multiple items in cache. Each item contains a value identified by a key.
* If the cache already contains such a key, the existing value and expiration time will be preserved. * If the cache already contains such a key, the existing value and expiration time will be preserved.
* *
* @param array $items the items to be cached, as key-value pairs. * @param array $values the items to be cached, as key-value pairs.
* @param int $duration default number of seconds in which the cached values will expire. 0 means never expire. * @param null|int|\DateInterval $ttl the TTL value of this item. If not set, default value is used.
* @param Dependency $dependency dependency of the cached items. If the dependency changes, * @param Dependency $dependency dependency of the cached items. If the dependency changes,
* the corresponding values in the cache will be invalidated when it is fetched via [[get()]]. * the corresponding values in the cache will be invalidated when it is fetched via [[get()]].
* This parameter is ignored if [[serializer]] is false. * This parameter is ignored if [[serializer]] is false.
* @return array array of failed keys * @return array array of failed keys
* @since 2.0.7 * @since 2.0.7
*/ */
public function multiAdd($items, $duration = 0, $dependency = null) public function addMultiple($values, $ttl = 0, $dependency = null)
{ {
if ($dependency !== null && $this->serializer !== false) { if ($dependency !== null) {
$dependency->evaluateDependency($this); $dependency->evaluateDependency($this);
} }
$data = []; $data = [];
foreach ($items as $key => $value) { foreach ($values as $key => $value) {
if ($this->serializer === null) { if ($dependency !== null) {
$value = serialize([$value, $dependency]); $value = [$value, $dependency];
} elseif ($this->serializer !== false) {
$value = call_user_func($this->serializer[0], [$value, $dependency]);
} }
$key = $this->buildKey($key); $key = $this->buildKey($key);
$data[$key] = $value; $data[$key] = $value;
} }
return $this->addValues($data, $duration); $existingValues = $this->handler->getMultiple(array_keys($data));
foreach ($existingValues as $key => $value) {
if ($value !== null) {
unset($data[$key]);
}
}
return $this->handler->setMultiple($data, $ttl);
} }
/** /**
@ -291,25 +283,26 @@ abstract class Cache extends Component implements CacheInterface
* @param mixed $key a key identifying the value to be cached. This can be a simple string or * @param mixed $key a key identifying the value to be cached. This can be a simple string or
* a complex data structure consisting of factors representing the key. * a complex data structure consisting of factors representing the key.
* @param mixed $value the value to be cached * @param mixed $value the value to be cached
* @param int $duration the number of seconds in which the cached value will expire. 0 means never expire. * @param null|int|\DateInterval $ttl the TTL value of this item. If not set, default value is used.
* @param Dependency $dependency dependency of the cached item. If the dependency changes, * @param Dependency $dependency dependency of the cached item. If the dependency changes,
* the corresponding value in the cache will be invalidated when it is fetched via [[get()]]. * the corresponding value in the cache will be invalidated when it is fetched via [[get()]].
* This parameter is ignored if [[serializer]] is false. * This parameter is ignored if [[serializer]] is false.
* @return bool whether the value is successfully stored into cache * @return bool whether the value is successfully stored into cache
*/ */
public function add($key, $value, $duration = 0, $dependency = null) public function add($key, $value, $ttl = null, $dependency = null)
{ {
if ($dependency !== null && $this->serializer !== false) { if ($dependency !== null) {
$dependency->evaluateDependency($this); $dependency->evaluateDependency($this);
$value = [$value, $dependency];
} }
if ($this->serializer === null) {
$value = serialize([$value, $dependency]);
} elseif ($this->serializer !== false) {
$value = call_user_func($this->serializer[0], [$value, $dependency]);
}
$key = $this->buildKey($key); $key = $this->buildKey($key);
return $this->addValue($key, $value, $duration); if ($this->handler->has($key)) {
return false;
}
return $this->handler->set($key, $value, $ttl);
} }
/** /**
@ -322,7 +315,7 @@ abstract class Cache extends Component implements CacheInterface
{ {
$key = $this->buildKey($key); $key = $this->buildKey($key);
return $this->deleteValue($key); return $this->handler->delete($key);
} }
/** /**
@ -330,116 +323,9 @@ abstract class Cache extends Component implements CacheInterface
* Be careful of performing this operation if the cache is shared among multiple applications. * Be careful of performing this operation if the cache is shared among multiple applications.
* @return bool whether the flush operation was successful. * @return bool whether the flush operation was successful.
*/ */
public function flush() public function clear()
{ {
return $this->flushValues(); return $this->handler->clear();
}
/**
* Retrieves a value from cache with a specified key.
* This method should be implemented by child classes to retrieve the data
* from specific cache storage.
* @param string $key a unique key identifying the cached value
* @return mixed|false the value stored in cache, false if the value is not in the cache or expired. Most often
* value is a string. If you have disabled [[serializer]], it could be something else.
*/
abstract protected function getValue($key);
/**
* Stores a value identified by a key in cache.
* This method should be implemented by child classes to store the data
* in specific cache storage.
* @param string $key the key identifying the value to be cached
* @param mixed $value the value to be cached. Most often it's a string. If you have disabled [[serializer]],
* it could be something else.
* @param int $duration the number of seconds in which the cached value will expire. 0 means never expire.
* @return bool true if the value is successfully stored into cache, false otherwise
*/
abstract protected function setValue($key, $value, $duration);
/**
* Stores a value identified by a key into cache if the cache does not contain this key.
* This method should be implemented by child classes to store the data
* in specific cache storage.
* @param string $key the key identifying the value to be cached
* @param mixed $value the value to be cached. Most often it's a string. If you have disabled [[serializer]],
* it could be something else.
* @param int $duration the number of seconds in which the cached value will expire. 0 means never expire.
* @return bool true if the value is successfully stored into cache, false otherwise
*/
abstract protected function addValue($key, $value, $duration);
/**
* Deletes a value with the specified key from cache
* This method should be implemented by child classes to delete the data from actual cache storage.
* @param string $key the key of the value to be deleted
* @return bool if no error happens during deletion
*/
abstract protected function deleteValue($key);
/**
* Deletes all values from cache.
* Child classes may implement this method to realize the flush operation.
* @return bool whether the flush operation was successful.
*/
abstract protected function flushValues();
/**
* Retrieves multiple values from cache with the specified keys.
* The default implementation calls [[getValue()]] multiple times to retrieve
* the cached values one by one. If the underlying cache storage supports multiget,
* this method should be overridden to exploit that feature.
* @param array $keys a list of keys identifying the cached values
* @return array a list of cached values indexed by the keys
*/
protected function getValues($keys)
{
$results = [];
foreach ($keys as $key) {
$results[$key] = $this->getValue($key);
}
return $results;
}
/**
* Stores multiple key-value pairs in cache.
* The default implementation calls [[setValue()]] multiple times store values one by one. If the underlying cache
* storage supports multi-set, this method should be overridden to exploit that feature.
* @param array $data array where key corresponds to cache key while value is the value stored
* @param int $duration the number of seconds in which the cached values will expire. 0 means never expire.
* @return array array of failed keys
*/
protected function setValues($data, $duration)
{
$failedKeys = [];
foreach ($data as $key => $value) {
if ($this->setValue($key, $value, $duration) === false) {
$failedKeys[] = $key;
}
}
return $failedKeys;
}
/**
* Adds multiple key-value pairs to cache.
* The default implementation calls [[addValue()]] multiple times add values one by one. If the underlying cache
* storage supports multi-add, this method should be overridden to exploit that feature.
* @param array $data array where key corresponds to cache key while value is the value stored.
* @param int $duration the number of seconds in which the cached values will expire. 0 means never expire.
* @return array array of failed keys
*/
protected function addValues($data, $duration)
{
$failedKeys = [];
foreach ($data as $key => $value) {
if ($this->addValue($key, $value, $duration) === false) {
$failedKeys[] = $key;
}
}
return $failedKeys;
} }
/** /**
@ -506,22 +392,21 @@ abstract class Cache extends Component implements CacheInterface
* a complex data structure consisting of factors representing the key. * a complex data structure consisting of factors representing the key.
* @param callable|\Closure $callable the callable or closure that will be used to generate a value to be cached. * @param callable|\Closure $callable the callable or closure that will be used to generate a value to be cached.
* In case $callable returns `false`, the value will not be cached. * In case $callable returns `false`, the value will not be cached.
* @param int $duration default duration in seconds before the cache will expire. If not set, * @param null|int|\DateInterval $ttl the TTL value of this item. If not set, default value is used.
* [[defaultDuration]] value will be used.
* @param Dependency $dependency dependency of the cached item. If the dependency changes, * @param Dependency $dependency dependency of the cached item. If the dependency changes,
* the corresponding value in the cache will be invalidated when it is fetched via [[get()]]. * the corresponding value in the cache will be invalidated when it is fetched via [[get()]].
* This parameter is ignored if [[serializer]] is `false`. * This parameter is ignored if [[serializer]] is `false`.
* @return mixed result of $callable execution * @return mixed result of $callable execution
* @since 2.0.11 * @since 2.0.11
*/ */
public function getOrSet($key, $callable, $duration = null, $dependency = null) public function getOrSet($key, $callable, $ttl = null, $dependency = null)
{ {
if (($value = $this->get($key)) !== false) { if (($value = $this->get($key)) !== null) {
return $value; return $value;
} }
$value = call_user_func($callable, $this); $value = call_user_func($callable, $this);
if (!$this->set($key, $value, $duration, $dependency)) { if (!$this->set($key, $value, $ttl, $dependency)) {
Yii::warning('Failed to set cache value for key ' . json_encode($key), __METHOD__); Yii::warning('Failed to set cache value for key ' . json_encode($key), __METHOD__);
} }

101
framework/caching/CacheInterface.php

@ -8,7 +8,8 @@
namespace yii\caching; namespace yii\caching;
/** /**
* CacheInterface is the base interface for cache. * CacheInterface defines the common interface to be implemented by cache classes.
* It extends [[\Psr\SimpleCache\CacheInterface]] adding ability for cache dependency specification.
* *
* A data item can be stored in the cache by calling [[set()]] and be retrieved back * A data item can be stored in the cache by calling [[set()]] and be retrieved back
* later (in the same or different request) by [[get()]]. In both operations, * later (in the same or different request) by [[get()]]. In both operations,
@ -21,7 +22,7 @@ namespace yii\caching;
* ```php * ```php
* $key = 'demo'; * $key = 'demo';
* $data = $cache->get($key); * $data = $cache->get($key);
* if ($data === false) { * if ($data === null) {
* // ...generate $data here... * // ...generate $data here...
* $cache->set($key, $data, $duration, $dependency); * $cache->set($key, $data, $duration, $dependency);
* } * }
@ -34,62 +35,19 @@ namespace yii\caching;
* echo $cache['foo']; * echo $cache['foo'];
* ``` * ```
* *
* For more details and usage information on Cache, see the [guide article on caching](guide:caching-overview). * For more details and usage information on Cache, see the [guide article on caching](guide:caching-overview)
* and [PSR-16 specification](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-16-simple-cache.md).
*
* @see \Psr\SimpleCache\CacheInterface
* *
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @author Dmitry Naumenko <d.naumenko.a@gmail.com> * @author Dmitry Naumenko <d.naumenko.a@gmail.com>
* @since 2.0.13. Previous framework versions used abstract class [[yii\caching\Cache]] as interface. * @author Paul Klimov <klimov.paul@gmail.com>
* @since 2.0.13. Previous framework versions used abstract class [[\yii\caching\Cache]] as interface.
*/ */
interface CacheInterface extends \ArrayAccess interface CacheInterface extends \Psr\SimpleCache\CacheInterface, \ArrayAccess
{ {
/** /**
* Builds a normalized cache key from a given key.
*
* If the given key is a string containing alphanumeric characters only and no more than 32 characters,
* then the key will be returned back prefixed with [[keyPrefix]]. Otherwise, a normalized key
* is generated by serializing the given key, applying MD5 hashing, and prefixing with [[keyPrefix]].
*
* @param mixed $key the key to be normalized
* @return string the generated cache key
*/
public function buildKey($key);
/**
* Retrieves a value from cache with a specified key.
* @param mixed $key a key identifying the cached value. This can be a simple string or
* a complex data structure consisting of factors representing the key.
* @return mixed the value stored in cache, false if the value is not in the cache, expired,
* or the dependency associated with the cached data has changed.
*/
public function get($key);
/**
* Checks whether a specified key exists in the cache.
* This can be faster than getting the value from the cache if the data is big.
* In case a cache does not support this feature natively, this method will try to simulate it
* but has no performance improvement over getting it.
* Note that this method does not check whether the dependency associated
* with the cached data, if there is any, has changed. So a call to [[get]]
* may return false while exists returns true.
* @param mixed $key a key identifying the cached value. This can be a simple string or
* a complex data structure consisting of factors representing the key.
* @return bool true if a value exists in cache, false if the value is not in the cache or expired.
*/
public function exists($key);
/**
* Retrieves multiple values from cache with the specified keys.
* Some caches (such as memcache, apc) allow retrieving multiple cached values at the same time,
* which may improve the performance. In case a cache does not support this feature natively,
* this method will try to simulate it.
* @param string[] $keys list of string keys identifying the cached values
* @return array list of cached values corresponding to the specified keys. The array
* is returned in terms of (key, value) pairs.
* If a value is not cached or expired, the corresponding array value will be false.
*/
public function multiGet($keys);
/**
* Stores a value identified by a key into cache. * Stores a value identified by a key into cache.
* If the cache already contains such a key, the existing value and * If the cache already contains such a key, the existing value and
* expiration time will be replaced with the new ones, respectively. * expiration time will be replaced with the new ones, respectively.
@ -97,14 +55,13 @@ interface CacheInterface extends \ArrayAccess
* @param mixed $key a key identifying the value to be cached. This can be a simple string or * @param mixed $key a key identifying the value to be cached. This can be a simple string or
* a complex data structure consisting of factors representing the key. * a complex data structure consisting of factors representing the key.
* @param mixed $value the value to be cached * @param mixed $value the value to be cached
* @param int $duration default duration in seconds before the cache will expire. If not set, * @param null|int|\DateInterval $ttl the TTL value of this item. If not set, default value is used.
* default [[defaultDuration]] value is used.
* @param Dependency $dependency dependency of the cached item. If the dependency changes, * @param Dependency $dependency dependency of the cached item. If the dependency changes,
* the corresponding value in the cache will be invalidated when it is fetched via [[get()]]. * the corresponding value in the cache will be invalidated when it is fetched via [[get()]].
* This parameter is ignored if [[serializer]] is false. * This parameter is ignored if [[serializer]] is false.
* @return bool whether the value is successfully stored into cache * @return bool whether the value is successfully stored into cache
*/ */
public function set($key, $value, $duration = null, $dependency = null); public function set($key, $value, $ttl = null, $dependency = null);
/** /**
* Stores multiple items in cache. Each item contains a value identified by a key. * Stores multiple items in cache. Each item contains a value identified by a key.
@ -112,13 +69,13 @@ interface CacheInterface extends \ArrayAccess
* expiration time will be replaced with the new ones, respectively. * expiration time will be replaced with the new ones, respectively.
* *
* @param array $items the items to be cached, as key-value pairs. * @param array $items the items to be cached, as key-value pairs.
* @param int $duration default number of seconds in which the cached values will expire. 0 means never expire. * @param null|int|\DateInterval $ttl the TTL value of this item. If not set, default value is used.
* @param Dependency $dependency dependency of the cached items. If the dependency changes, * @param Dependency $dependency dependency of the cached items. If the dependency changes,
* the corresponding values in the cache will be invalidated when it is fetched via [[get()]]. * the corresponding values in the cache will be invalidated when it is fetched via [[get()]].
* This parameter is ignored if [[serializer]] is false. * This parameter is ignored if [[serializer]] is false.
* @return array array of failed keys * @return array array of failed keys
*/ */
public function multiSet($items, $duration = 0, $dependency = null); public function setMultiple($items, $ttl = null, $dependency = null);
/** /**
* Stores a value identified by a key into cache if the cache does not contain this key. * Stores a value identified by a key into cache if the cache does not contain this key.
@ -126,41 +83,26 @@ interface CacheInterface extends \ArrayAccess
* @param mixed $key a key identifying the value to be cached. This can be a simple string or * @param mixed $key a key identifying the value to be cached. This can be a simple string or
* a complex data structure consisting of factors representing the key. * a complex data structure consisting of factors representing the key.
* @param mixed $value the value to be cached * @param mixed $value the value to be cached
* @param int $duration the number of seconds in which the cached value will expire. 0 means never expire. * @param null|int|\DateInterval $ttl the TTL value of this item. If not set, default value is used.
* @param Dependency $dependency dependency of the cached item. If the dependency changes, * @param Dependency $dependency dependency of the cached item. If the dependency changes,
* the corresponding value in the cache will be invalidated when it is fetched via [[get()]]. * the corresponding value in the cache will be invalidated when it is fetched via [[get()]].
* This parameter is ignored if [[serializer]] is false. * This parameter is ignored if [[serializer]] is false.
* @return bool whether the value is successfully stored into cache * @return bool whether the value is successfully stored into cache
*/ */
public function add($key, $value, $duration = 0, $dependency = null); public function add($key, $value, $ttl = 0, $dependency = null);
/** /**
* Stores multiple items in cache. Each item contains a value identified by a key. * Stores multiple items in cache. Each item contains a value identified by a key.
* If the cache already contains such a key, the existing value and expiration time will be preserved. * If the cache already contains such a key, the existing value and expiration time will be preserved.
* *
* @param array $items the items to be cached, as key-value pairs. * @param array $values the items to be cached, as key-value pairs.
* @param int $duration default number of seconds in which the cached values will expire. 0 means never expire. * @param null|int|\DateInterval $ttl the TTL value of this item. If not set, default value is used.
* @param Dependency $dependency dependency of the cached items. If the dependency changes, * @param Dependency $dependency dependency of the cached items. If the dependency changes,
* the corresponding values in the cache will be invalidated when it is fetched via [[get()]]. * the corresponding values in the cache will be invalidated when it is fetched via [[get()]].
* This parameter is ignored if [[serializer]] is false. * This parameter is ignored if [[serializer]] is false.
* @return array array of failed keys * @return array array of failed keys
*/ */
public function multiAdd($items, $duration = 0, $dependency = null); public function addMultiple($values, $ttl = 0, $dependency = null);
/**
* Deletes a value with the specified key from cache
* @param mixed $key a key identifying the value to be deleted from cache. This can be a simple string or
* a complex data structure consisting of factors representing the key.
* @return bool if no error happens during deletion
*/
public function delete($key);
/**
* Deletes all values from cache.
* Be careful of performing this operation if the cache is shared among multiple applications.
* @return bool whether the flush operation was successful.
*/
public function flush();
/** /**
* Method combines both [[set()]] and [[get()]] methods to retrieve value identified by a $key, * Method combines both [[set()]] and [[get()]] methods to retrieve value identified by a $key,
@ -181,12 +123,11 @@ interface CacheInterface extends \ArrayAccess
* a complex data structure consisting of factors representing the key. * a complex data structure consisting of factors representing the key.
* @param callable|\Closure $callable the callable or closure that will be used to generate a value to be cached. * @param callable|\Closure $callable the callable or closure that will be used to generate a value to be cached.
* In case $callable returns `false`, the value will not be cached. * In case $callable returns `false`, the value will not be cached.
* @param int $duration default duration in seconds before the cache will expire. If not set, * @param null|int|\DateInterval $ttl the TTL value of this item. If not set, default value is used.
* [[defaultDuration]] value will be used.
* @param Dependency $dependency dependency of the cached item. If the dependency changes, * @param Dependency $dependency dependency of the cached item. If the dependency changes,
* the corresponding value in the cache will be invalidated when it is fetched via [[get()]]. * the corresponding value in the cache will be invalidated when it is fetched via [[get()]].
* This parameter is ignored if [[serializer]] is `false`. * This parameter is ignored if [[serializer]] is `false`.
* @return mixed result of $callable execution * @return mixed result of $callable execution
*/ */
public function getOrSet($key, $callable, $duration = null, $dependency = null); public function getOrSet($key, $callable, $ttl = null, $dependency = null);
} }

83
framework/caching/DbCache.php

@ -19,16 +19,25 @@ use yii\di\Instance;
* By default, DbCache stores session data in a DB table named 'cache'. This table * By default, DbCache stores session data in a DB table named 'cache'. This table
* must be pre-created. The table name can be changed by setting [[cacheTable]]. * must be pre-created. The table name can be changed by setting [[cacheTable]].
* *
* Please refer to [[Cache]] for common cache operations that are supported by DbCache. * Please refer to [[\Psr\SimpleCache\CacheInterface]] for common cache operations that are supported by DbCache.
* *
* The following example shows how you can configure the application to use DbCache: * The following example shows how you can configure the application to use DbCache:
* *
* ```php * ```php
* return [
* 'components' => [
* 'cache' => [ * 'cache' => [
* 'class' => \yii\caching\DbCache::class, * 'class' => yii\caching\Cache:class,
* 'handler' => [
* 'class' => yii\caching\DbCache::class,
* // 'db' => 'mydb', * // 'db' => 'mydb',
* // 'cacheTable' => 'my_cache', * // 'cacheTable' => 'my_cache',
* ] * ],
* ],
* // ...
* ],
* // ...
* ];
* ``` * ```
* *
* For more details and usage information on Cache, see the [guide article on caching](guide:caching-overview). * For more details and usage information on Cache, see the [guide article on caching](guide:caching-overview).
@ -36,7 +45,7 @@ use yii\di\Instance;
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
*/ */
class DbCache extends Cache class DbCache extends SimpleCache
{ {
/** /**
* @var Connection|array|string the DB connection object or the application component ID of the DB connection. * @var Connection|array|string the DB connection object or the application component ID of the DB connection.
@ -88,18 +97,11 @@ class DbCache extends Cache
} }
/** /**
* Checks whether a specified key exists in the cache. * {@inheritdoc}
* This can be faster than getting the value from the cache if the data is big.
* Note that this method does not check whether the dependency associated
* with the cached data, if there is any, has changed. So a call to [[get]]
* may return false while exists returns true.
* @param mixed $key a key identifying the cached value. This can be a simple string or
* a complex data structure consisting of factors representing the key.
* @return bool true if a value exists in cache, false if the value is not in the cache or expired.
*/ */
public function exists($key) public function has($key)
{ {
$key = $this->buildKey($key); $key = $this->normalizeKey($key);
$query = new Query(); $query = new Query();
$query->select(['COUNT(*)']) $query->select(['COUNT(*)'])
@ -118,40 +120,36 @@ class DbCache extends Cache
} }
/** /**
* Retrieves a value from cache with a specified key. * {@inheritdoc}
* This is the implementation of the method declared in the parent class.
* @param string $key a unique key identifying the cached value
* @return string|false the value stored in cache, false if the value is not in the cache or expired.
*/ */
protected function getValue($key) protected function getValue($key)
{ {
$query = new Query(); $query = (new Query())
$query->select(['data']) ->select(['data'])
->from($this->cacheTable) ->from($this->cacheTable)
->where('[[id]] = :id AND ([[expire]] = 0 OR [[expire]] >' . time() . ')', [':id' => $key]); ->where('[[id]] = :id AND ([[expire]] = 0 OR [[expire]] >' . time() . ')', [':id' => $key]);
if ($this->db->enableQueryCache) { if ($this->db->enableQueryCache) {
// temporarily disable and re-enable query caching // temporarily disable and re-enable query caching
$this->db->enableQueryCache = false; $this->db->enableQueryCache = false;
$result = $query->createCommand($this->db)->queryScalar(); $result = $query->createCommand($this->db)->queryScalar();
$this->db->enableQueryCache = true; $this->db->enableQueryCache = true;
return $result; return $result;
} }
return $query->createCommand($this->db)->queryScalar(); return $query->createCommand($this->db)->queryScalar();
} }
/** /**
* Retrieves multiple values from cache with the specified keys. * {@inheritdoc}
* @param array $keys a list of keys identifying the cached values
* @return array a list of cached values indexed by the keys
*/ */
protected function getValues($keys) protected function getValues($keys)
{ {
if (empty($keys)) { if (empty($keys)) {
return []; return [];
} }
$query = new Query(); $query = (new Query())
$query->select(['id', 'data']) ->select(['id', 'data'])
->from($this->cacheTable) ->from($this->cacheTable)
->where(['id' => $keys]) ->where(['id' => $keys])
->andWhere('([[expire]] = 0 OR [[expire]] > ' . time() . ')'); ->andWhere('([[expire]] = 0 OR [[expire]] > ' . time() . ')');
@ -164,10 +162,7 @@ class DbCache extends Cache
$rows = $query->createCommand($this->db)->queryAll(); $rows = $query->createCommand($this->db)->queryAll();
} }
$results = []; $results = array_fill_keys($keys, false);
foreach ($keys as $key) {
$results[$key] = false;
}
foreach ($rows as $row) { foreach ($rows as $row) {
$results[$row['id']] = $row['data']; $results[$row['id']] = $row['data'];
} }
@ -176,20 +171,14 @@ class DbCache extends Cache
} }
/** /**
* Stores a value identified by a key in cache. * {@inheritdoc}
* This is the implementation of the method declared in the parent class.
*
* @param string $key the key identifying the value to be cached
* @param string $value the value to be cached. Other types (if you have disabled [[serializer]]) cannot be saved.
* @param int $duration the number of seconds in which the cached value will expire. 0 means never expire.
* @return bool true if the value is successfully stored into cache, false otherwise
*/ */
protected function setValue($key, $value, $duration) protected function setValue($key, $value, $ttl)
{ {
$result = $this->db->noCache(function (Connection $db) use ($key, $value, $duration) { $result = $this->db->noCache(function (Connection $db) use ($key, $value, $ttl) {
$command = $db->createCommand() $command = $db->createCommand()
->update($this->cacheTable, [ ->update($this->cacheTable, [
'expire' => $duration > 0 ? $duration + time() : 0, 'expire' => $ttl > 0 ? $ttl + time() : 0,
'data' => [$value, \PDO::PARAM_LOB], 'data' => [$value, \PDO::PARAM_LOB],
], ['id' => $key]); ], ['id' => $key]);
return $command->execute(); return $command->execute();
@ -197,10 +186,9 @@ class DbCache extends Cache
if ($result) { if ($result) {
$this->gc(); $this->gc();
return true; return true;
} }
return $this->addValue($key, $value, $duration); return $this->addValue($key, $value, $ttl);
} }
/** /**
@ -233,10 +221,7 @@ class DbCache extends Cache
} }
/** /**
* Deletes a value with the specified key from cache * {@inheritdoc}
* This is the implementation of the method declared in the parent class.
* @param string $key the key of the value to be deleted
* @return bool if no error happens during deletion
*/ */
protected function deleteValue($key) protected function deleteValue($key)
{ {
@ -264,11 +249,9 @@ class DbCache extends Cache
} }
/** /**
* Deletes all values from cache. * {@inheritdoc}
* This is the implementation of the method declared in the parent class.
* @return bool whether the flush operation was successful.
*/ */
protected function flushValues() public function clear()
{ {
$this->db->createCommand() $this->db->createCommand()
->delete($this->cacheTable) ->delete($this->cacheTable)

84
framework/caching/DummyCache.php

@ -7,9 +7,28 @@
namespace yii\caching; namespace yii\caching;
use yii\base\Component;
/** /**
* DummyCache is a placeholder cache component. * DummyCache is a placeholder cache component.
* *
* Application configuration example:
*
* ```php
* return [
* 'components' => [
* 'cache' => [
* 'class' => yii\caching\Cache::class,
* 'handler' => [
* 'class' => yii\caching\DummyCache::class,
* ],
* ],
* // ...
* ],
* // ...
* ];
* ```
*
* DummyCache does not cache anything. It is provided so that one can always configure * DummyCache does not cache anything. It is provided so that one can always configure
* a 'cache' application component and save the check of existence of `\Yii::$app->cache`. * a 'cache' application component and save the check of existence of `\Yii::$app->cache`.
* By replacing DummyCache with some other cache component, one can quickly switch from * By replacing DummyCache with some other cache component, one can quickly switch from
@ -20,63 +39,68 @@ namespace yii\caching;
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
*/ */
class DummyCache extends Cache class DummyCache extends Component implements \Psr\SimpleCache\CacheInterface
{ {
/** /**
* Retrieves a value from cache with a specified key. * {@inheritdoc}
* This is the implementation of the method declared in the parent class.
* @param string $key a unique key identifying the cached value
* @return mixed|false the value stored in cache, false if the value is not in the cache or expired.
*/ */
protected function getValue($key) public function has($key)
{ {
return false; return false;
} }
/** /**
* Stores a value identified by a key in cache. * {@inheritdoc}
* This is the implementation of the method declared in the parent class. */
* public function get($key, $default = null)
* @param string $key the key identifying the value to be cached {
* @param mixed $value the value to be cached return $default;
* @param int $duration the number of seconds in which the cached value will expire. 0 means never expire. }
* @return bool true if the value is successfully stored into cache, false otherwise
/**
* {@inheritdoc}
*/
public function set($key, $value, $ttl = null)
{
return true;
}
/**
* {@inheritdoc}
*/ */
protected function setValue($key, $value, $duration) public function delete($key)
{ {
return true; return true;
} }
/** /**
* Stores a value identified by a key into cache if the cache does not contain this key. * {@inheritdoc}
* This is the implementation of the method declared in the parent class.
* @param string $key the key identifying the value to be cached
* @param mixed $value the value to be cached
* @param int $duration the number of seconds in which the cached value will expire. 0 means never expire.
* @return bool true if the value is successfully stored into cache, false otherwise
*/ */
protected function addValue($key, $value, $duration) public function clear()
{ {
return true; return true;
} }
/** /**
* Deletes a value with the specified key from cache * {@inheritdoc}
* This is the implementation of the method declared in the parent class. */
* @param string $key the key of the value to be deleted public function getMultiple($keys, $default = null)
* @return bool if no error happens during deletion {
return array_fill_keys($keys, $default);
}
/**
* {@inheritdoc}
*/ */
protected function deleteValue($key) public function setMultiple($values, $ttl = null)
{ {
return true; return true;
} }
/** /**
* Deletes all values from cache. * {@inheritdoc}
* This is the implementation of the method declared in the parent class.
* @return bool whether the flush operation was successful.
*/ */
protected function flushValues() public function deleteMultiple($keys)
{ {
return true; return true;
} }

25
framework/caching/Exception.php

@ -0,0 +1,25 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\caching;
/**
* Exception represents an exception that is caused by some Caching-related operations.
*
* @author Paul Klimov <klimov.paul@gmail.com>
* @since 2.1.0
*/
class Exception extends \yii\base\Exception implements \Psr\SimpleCache\CacheException
{
/**
* {@inheritdoc}
*/
public function getName()
{
return 'Cache Exception';
}
}

100
framework/caching/FileCache.php

@ -11,30 +11,40 @@ use Yii;
use yii\helpers\FileHelper; use yii\helpers\FileHelper;
/** /**
* FileCache implements a cache component using files. * FileCache implements a cache handler using files.
* *
* For each data value being cached, FileCache will store it in a separate file. * For each data value being cached, FileCache will store it in a separate file.
* The cache files are placed under [[cachePath]]. FileCache will perform garbage collection * The cache files are placed under [[cachePath]]. FileCache will perform garbage collection
* automatically to remove expired cache files. * automatically to remove expired cache files.
* *
* Please refer to [[Cache]] for common cache operations that are supported by FileCache. * Application configuration example:
*
* ```php
* return [
* 'components' => [
* 'cache' => [
* 'class' => yii\caching\Cache::class,
* 'handler' => [
* 'class' => yii\caching\FileCache::class,
* // 'cachePath' => '@runtime/cache',
* ],
* ],
* // ...
* ],
* // ...
* ];
* ```
*
* Please refer to [[\Psr\SimpleCache\CacheInterface]] for common cache operations that are supported by FileCache.
* *
* For more details and usage information on Cache, see the [guide article on caching](guide:caching-overview). * For more details and usage information on Cache, see the [guide article on caching](guide:caching-overview).
* *
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
*/ */
class FileCache extends Cache class FileCache extends SimpleCache
{ {
/** /**
* @var string a string prefixed to every cache key. This is needed when you store
* cache data under the same [[cachePath]] for different applications to avoid
* conflict.
*
* To ensure interoperability, only alphanumeric characters should be used.
*/
public $keyPrefix = '';
/**
* @var string the directory to store cache files. You may use [path alias](guide:concept-aliases) here. * @var string the directory to store cache files. You may use [path alias](guide:concept-aliases) here.
* If not set, it will use the "cache" subdirectory under the application runtime path. * If not set, it will use the "cache" subdirectory under the application runtime path.
*/ */
@ -84,27 +94,17 @@ class FileCache extends Cache
} }
/** /**
* Checks whether a specified key exists in the cache. * {@inheritdoc}
* This can be faster than getting the value from the cache if the data is big.
* Note that this method does not check whether the dependency associated
* with the cached data, if there is any, has changed. So a call to [[get]]
* may return false while exists returns true.
* @param mixed $key a key identifying the cached value. This can be a simple string or
* a complex data structure consisting of factors representing the key.
* @return bool true if a value exists in cache, false if the value is not in the cache or expired.
*/ */
public function exists($key) public function has($key)
{ {
$cacheFile = $this->getCacheFile($this->buildKey($key)); $cacheFile = $this->getCacheFile($this->normalizeKey($key));
return @filemtime($cacheFile) > time(); return @filemtime($cacheFile) > time();
} }
/** /**
* Retrieves a value from cache with a specified key. * {@inheritdoc}
* This is the implementation of the method declared in the parent class.
* @param string $key a unique key identifying the cached value
* @return string|false the value stored in cache, false if the value is not in the cache or expired.
*/ */
protected function getValue($key) protected function getValue($key)
{ {
@ -125,16 +125,9 @@ class FileCache extends Cache
} }
/** /**
* Stores a value identified by a key in cache. * {@inheritdoc}
* This is the implementation of the method declared in the parent class.
*
* @param string $key the key identifying the value to be cached
* @param string $value the value to be cached. Other types (If you have disabled [[serializer]]) unable to get is
* correct in [[getValue()]].
* @param int $duration the number of seconds in which the cached value will expire. 0 means never expire.
* @return bool true if the value is successfully stored into cache, false otherwise
*/ */
protected function setValue($key, $value, $duration) protected function setValue($key, $value, $ttl)
{ {
$this->gc(); $this->gc();
$cacheFile = $this->getCacheFile($key); $cacheFile = $this->getCacheFile($key);
@ -145,11 +138,11 @@ class FileCache extends Cache
if ($this->fileMode !== null) { if ($this->fileMode !== null) {
@chmod($cacheFile, $this->fileMode); @chmod($cacheFile, $this->fileMode);
} }
if ($duration <= 0) { if ($ttl <= 0) {
$duration = 31536000; // 1 year $ttl = 31536000; // 1 year
} }
return @touch($cacheFile, $duration + time()); return @touch($cacheFile, $ttl + time());
} }
$error = error_get_last(); $error = error_get_last();
@ -158,35 +151,11 @@ class FileCache extends Cache
} }
/** /**
* Stores a value identified by a key into cache if the cache does not contain this key. * {@inheritdoc}
* This is the implementation of the method declared in the parent class.
*
* @param string $key the key identifying the value to be cached
* @param string $value the value to be cached. Other types (if you have disabled [[serializer]]) unable to get is
* correct in [[getValue()]].
* @param int $duration the number of seconds in which the cached value will expire. 0 means never expire.
* @return bool true if the value is successfully stored into cache, false otherwise
*/
protected function addValue($key, $value, $duration)
{
$cacheFile = $this->getCacheFile($key);
if (@filemtime($cacheFile) > time()) {
return false;
}
return $this->setValue($key, $value, $duration);
}
/**
* Deletes a value with the specified key from cache
* This is the implementation of the method declared in the parent class.
* @param string $key the key of the value to be deleted
* @return bool if no error happens during deletion
*/ */
protected function deleteValue($key) protected function deleteValue($key)
{ {
$cacheFile = $this->getCacheFile($key); $cacheFile = $this->getCacheFile($key);
return @unlink($cacheFile); return @unlink($cacheFile);
} }
@ -212,14 +181,11 @@ class FileCache extends Cache
} }
/** /**
* Deletes all values from cache. * {@inheritdoc}
* This is the implementation of the method declared in the parent class.
* @return bool whether the flush operation was successful.
*/ */
protected function flushValues() public function clear()
{ {
$this->gc(true, false); $this->gc(true, false);
return true; return true;
} }

70
framework/caching/MemCached.php

@ -17,7 +17,7 @@ use yii\base\InvalidConfigException;
* MemCached can be configured with a list of memcached servers by settings its [[servers]] property. * MemCached can be configured with a list of memcached servers by settings its [[servers]] property.
* By default, MemCached assumes there is a memcached server running on localhost at port 11211. * By default, MemCached assumes there is a memcached server running on localhost at port 11211.
* *
* See [[Cache]] for common cache operations that MemCached supports. * See [[\Psr\SimpleCache\CacheInterface]] for common cache operations that MemCached supports.
* *
* Note, there is no security measure to protected data in memcached. * Note, there is no security measure to protected data in memcached.
* All data in memcached can be accessed by any process running in the system. * All data in memcached can be accessed by any process running in the system.
@ -28,6 +28,8 @@ use yii\base\InvalidConfigException;
* [ * [
* 'components' => [ * 'components' => [
* 'cache' => [ * 'cache' => [
* 'class' => \yii\caching\Cache::class,
* 'handler' => [
* 'class' => \yii\caching\MemCached::class, * 'class' => \yii\caching\MemCached::class,
* 'servers' => [ * 'servers' => [
* [ * [
@ -43,6 +45,7 @@ use yii\base\InvalidConfigException;
* ], * ],
* ], * ],
* ], * ],
* ],
* ] * ]
* ``` * ```
* *
@ -59,7 +62,7 @@ use yii\base\InvalidConfigException;
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
*/ */
class MemCached extends Cache class MemCached extends SimpleCache
{ {
/** /**
* @var string an ID that identifies a Memcached instance. * @var string an ID that identifies a Memcached instance.
@ -187,10 +190,7 @@ class MemCached extends Cache
} }
/** /**
* Retrieves a value from cache with a specified key. * {@inheritdoc}
* This is the implementation of the method declared in the parent class.
* @param string $key a unique key identifying the cached value
* @return mixed|false the value stored in cache, false if the value is not in the cache or expired.
*/ */
protected function getValue($key) protected function getValue($key)
{ {
@ -198,9 +198,7 @@ class MemCached extends Cache
} }
/** /**
* Retrieves multiple values from cache with the specified keys. * {@inheritdoc}
* @param array $keys a list of keys identifying the cached values
* @return array a list of cached values indexed by the keys
*/ */
protected function getValues($keys) protected function getValues($keys)
{ {
@ -208,65 +206,33 @@ class MemCached extends Cache
} }
/** /**
* Stores a value identified by a key in cache. * {@inheritdoc}
* This is the implementation of the method declared in the parent class.
*
* @param string $key the key identifying the value to be cached
* @param mixed $value the value to be cached.
* @see [Memcached::set()](http://php.net/manual/en/memcached.set.php)
* @param int $duration the number of seconds in which the cached value will expire. 0 means never expire.
* @return bool true if the value is successfully stored into cache, false otherwise
*/ */
protected function setValue($key, $value, $duration) protected function setValue($key, $value, $ttl)
{ {
// Use UNIX timestamp since it doesn't have any limitation // Use UNIX timestamp since it doesn't have any limitation
// @see http://php.net/manual/en/memcached.expiration.php // @see http://php.net/manual/en/memcached.expiration.php
$expire = $duration > 0 ? $duration + time() : 0; $expire = $ttl > 0 ? $ttl + time() : 0;
return $this->_cache->set($key, $value, $expire); return $this->_cache->set($key, $value, $expire);
} }
/** /**
* Stores multiple key-value pairs in cache. * {@inheritdoc}
* @param array $data array where key corresponds to cache key while value is the value stored
* @param int $duration the number of seconds in which the cached values will expire. 0 means never expire.
* @return array array of failed keys.
*/ */
protected function setValues($data, $duration) protected function setValues($values, $ttl)
{ {
// Use UNIX timestamp since it doesn't have any limitation // Use UNIX timestamp since it doesn't have any limitation
// @see http://php.net/manual/en/memcached.expiration.php // @see http://php.net/manual/en/memcached.expiration.php
$expire = $duration > 0 ? $duration + time() : 0; $expire = $ttl > 0 ? $ttl + time() : 0;
// Memcached::setMulti() returns boolean // Memcached::setMulti() returns boolean
// @see http://php.net/manual/en/memcached.setmulti.php // @see http://php.net/manual/en/memcached.setmulti.php
return $this->_cache->setMulti($data, $expire) ? [] : array_keys($data); return $this->_cache->setMulti($values, $expire) ? [] : array_keys($values);
}
/**
* Stores a value identified by a key into cache if the cache does not contain this key.
* This is the implementation of the method declared in the parent class.
*
* @param string $key the key identifying the value to be cached
* @param mixed $value the value to be cached
* @see [Memcached::set()](http://php.net/manual/en/memcached.set.php)
* @param int $duration the number of seconds in which the cached value will expire. 0 means never expire.
* @return bool true if the value is successfully stored into cache, false otherwise
*/
protected function addValue($key, $value, $duration)
{
// Use UNIX timestamp since it doesn't have any limitation
// @see http://php.net/manual/en/memcached.expiration.php
$expire = $duration > 0 ? $duration + time() : 0;
return $this->_cache->add($key, $value, $expire);
} }
/** /**
* Deletes a value with the specified key from cache * {@inheritdoc}
* This is the implementation of the method declared in the parent class.
* @param string $key the key of the value to be deleted
* @return bool if no error happens during deletion
*/ */
protected function deleteValue($key) protected function deleteValue($key)
{ {
@ -274,11 +240,9 @@ class MemCached extends Cache
} }
/** /**
* Deletes all values from cache. * {@inheritdoc}
* This is the implementation of the method declared in the parent class.
* @return bool whether the flush operation was successful.
*/ */
protected function flushValues() public function clear()
{ {
return $this->_cache->flush(); return $this->_cache->flush();
} }

270
framework/caching/SimpleCache.php

@ -0,0 +1,270 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\caching;
use Psr\SimpleCache\CacheInterface;
use yii\base\Component;
use yii\helpers\StringHelper;
/**
* SimpleCache is the base class for cache classes implementing pure PSR-16 [[CacheInterface]].
* This class handles cache key normalization, default TTL specification normalization, data serialization.
*
* Derived classes should implement the following methods which do the actual cache storage operations:
*
* - [[getValue()]]: retrieve the value with a key (if any) from cache
* - [[setValue()]]: store the value with a key into cache
* - [[deleteValue()]]: delete the value with the specified key from cache
* - [[clear()]]: delete all values from cache
*
* For more details and usage information on Cache, see the [guide article on caching](guide:caching-overview)
* and [PSR-16 specification](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-16-simple-cache.md).
*
* @see CacheInterface
*
* @author Paul Klimov <klimov.paul@gmail.com>
* @since 2.1.0
*/
abstract class SimpleCache extends Component implements CacheInterface
{
/**
* @var int default TTL for a cache entry. Default value is 0, meaning infinity.
* This value is used by [[set()]] and [[setMultiple()]], if the duration is not explicitly given.
*/
public $defaultTtl = 0;
/**
* @var string a string prefixed to every cache key so that it is unique globally in the whole cache storage.
* It is recommended that you set a unique cache key prefix for each application if the same cache
* storage is being used by different applications.
*
* To ensure interoperability, only alphanumeric characters should be used.
*/
public $keyPrefix = '';
/**
* @var null|array|false the functions used to serialize and unserialize cached data. Defaults to null, meaning
* using the default PHP `serialize()` and `unserialize()` functions. If you want to use some more efficient
* serializer (e.g. [igbinary](http://pecl.php.net/package/igbinary)), you may configure this property with
* a two-element array. The first element specifies the serialization function, and the second the deserialization
* function. If this property is set false, data will be directly sent to and retrieved from the underlying
* cache component without any serialization or deserialization. You should not turn off serialization if
* you are using [[Dependency|cache dependency]], because it relies on data serialization. Also, some
* implementations of the cache can not correctly save and retrieve data different from a string type.
*/
public $serializer;
/**
* {@inheritdoc}
*/
public function get($key, $default = null)
{
$key = $this->normalizeKey($key);
$value = $this->getValue($key);
if ($value === false || $this->serializer === false) {
return $default;
} elseif ($this->serializer === null) {
return unserialize($value);
}
return call_user_func($this->serializer[1], $value);
}
/**
* {@inheritdoc}
*/
public function getMultiple($keys, $default = null)
{
$keyMap = [];
foreach ($keys as $key) {
$keyMap[$key] = $this->normalizeKey($key);
}
$values = $this->getValues(array_values($keyMap));
$results = [];
foreach ($keyMap as $key => $newKey) {
$results[$key] = $default;
if (isset($values[$newKey]) && $values[$newKey] !== false) {
if ($this->serializer === false) {
$results[$key] = $values[$newKey];
} else {
$results[$key] = $this->serializer === null ? unserialize($values[$newKey])
: call_user_func($this->serializer[1], $values[$newKey]);
}
}
}
return $results;
}
/**
* {@inheritdoc}
*/
public function has($key)
{
$key = $this->normalizeKey($key);
$value = $this->getValue($key);
return $value !== false;
}
/**
* {@inheritdoc}
*/
public function set($key, $value, $ttl = null)
{
if ($this->serializer === null) {
$value = serialize($value);
} elseif ($this->serializer !== false) {
$value = call_user_func($this->serializer[0], $value);
}
$key = $this->normalizeKey($key);
$ttl = $this->normalizeTtl($ttl);
return $this->setValue($key, $value, $ttl);
}
/**
* {@inheritdoc}
*/
public function setMultiple($values, $ttl = null)
{
$data = [];
foreach ($values as $key => $value) {
if ($this->serializer === null) {
$value = serialize($value);
} elseif ($this->serializer !== false) {
$value = call_user_func($this->serializer[0], $value);
}
$key = $this->normalizeKey($key);
$data[$key] = $value;
}
return $this->setValues($data, $this->normalizeTtl($ttl));
}
/**
* {@inheritdoc}
*/
public function delete($key)
{
$key = $this->normalizeKey($key);
return $this->deleteValue($key);
}
/**
* {@inheritdoc}
*/
public function deleteMultiple($keys)
{
$result = true;
foreach ($keys as $key) {
if (!$this->delete($key)) {
$result = false;
}
}
return $result;
}
/**
* Builds a normalized cache key from a given key.
*
* The given key will be type-casted to string.
* If the result string does not contain alphanumeric characters only or has more than 32 characters,
* then the hash of the key will be used.
* The result key will be returned back prefixed with [[keyPrefix]].
*
* @param mixed $key the key to be normalized
* @return string the generated cache key
*/
protected function normalizeKey($key)
{
$key = (string)$key;
$key = ctype_alnum($key) && StringHelper::byteLength($key) <= 32 ? $key : md5($key);
return $this->keyPrefix . $key;
}
/**
* Normalizes cache TTL handling `null` value and [[\DateInterval]] objects.
* @param int|\DateInterval $ttl raw TTL.
* @return int TTL value as UNIX timestamp.
*/
protected function normalizeTtl($ttl)
{
if ($ttl === null) {
return $this->defaultTtl;
}
if ($ttl instanceof \DateInterval) {
return (new \DateTime('@0'))->add($ttl)->getTimestamp();
}
return (int)$ttl;
}
/**
* Retrieves a value from cache with a specified key.
* This method should be implemented by child classes to retrieve the data
* from specific cache storage.
* @param string $key a unique key identifying the cached value
* @return mixed|false the value stored in cache, `false` if the value is not in the cache or expired. Most often
* value is a string. If you have disabled [[serializer]], it could be something else.
*/
abstract protected function getValue($key);
/**
* Stores a value identified by a key in cache.
* This method should be implemented by child classes to store the data
* in specific cache storage.
* @param string $key the key identifying the value to be cached
* @param mixed $value the value to be cached. Most often it's a string. If you have disabled [[serializer]],
* it could be something else.
* @param int $ttl the number of seconds in which the cached value will expire.
* @return bool true if the value is successfully stored into cache, false otherwise
*/
abstract protected function setValue($key, $value, $ttl);
/**
* Deletes a value with the specified key from cache
* This method should be implemented by child classes to delete the data from actual cache storage.
* @param string $key the key of the value to be deleted
* @return bool if no error happens during deletion
*/
abstract protected function deleteValue($key);
/**
* Retrieves multiple values from cache with the specified keys.
* The default implementation calls [[getValue()]] multiple times to retrieve
* the cached values one by one. If the underlying cache storage supports multiget,
* this method should be overridden to exploit that feature.
* @param array $keys a list of keys identifying the cached values
* @return array a list of cached values indexed by the keys
*/
protected function getValues($keys)
{
$results = [];
foreach ($keys as $key) {
$value = $this->getValue($key);
if ($value !== false) {
$results[$key] = $value;
}
}
return $results;
}
/**
* Stores multiple key-value pairs in cache.
* The default implementation calls [[setValue()]] multiple times store values one by one. If the underlying cache
* storage supports multi-set, this method should be overridden to exploit that feature.
* @param array $values array where key corresponds to cache key while value is the value stored
* @param int $ttl the number of seconds in which the cached values will expire.
* @return bool `true` on success and `false` on failure.
*/
protected function setValues($values, $ttl)
{
$result = true;
foreach ($values as $key => $value) {
if ($this->setValue($key, $value, $ttl) === false) {
$result = false;
}
}
return $result;
}
}

26
framework/caching/TagDependency.php

@ -68,21 +68,21 @@ class TagDependency extends Dependency
/** /**
* Invalidates all of the cached data items that are associated with any of the specified [[tags]]. * Invalidates all of the cached data items that are associated with any of the specified [[tags]].
* @param CacheInterface $cache the cache component that caches the data items * @param \Psr\SimpleCache\CacheInterface $cache the cache component that caches the data items
* @param string|array $tags * @param string|array $tags
*/ */
public static function invalidate($cache, $tags) public static function invalidate($cache, $tags)
{ {
$keys = []; $keys = [];
foreach ((array) $tags as $tag) { foreach ((array) $tags as $tag) {
$keys[] = $cache->buildKey([__CLASS__, $tag]); $keys[] = static::buildCacheKey($tag);
} }
static::touchKeys($cache, $keys); static::touchKeys($cache, $keys);
} }
/** /**
* Generates the timestamp for the specified cache keys. * Generates the timestamp for the specified cache keys.
* @param CacheInterface $cache * @param \Psr\SimpleCache\CacheInterface $cache
* @param string[] $keys * @param string[] $keys
* @return array the timestamp indexed by cache keys * @return array the timestamp indexed by cache keys
*/ */
@ -93,13 +93,13 @@ class TagDependency extends Dependency
foreach ($keys as $key) { foreach ($keys as $key) {
$items[$key] = $time; $items[$key] = $time;
} }
$cache->multiSet($items); $cache->setMultiple($items);
return $items; return $items;
} }
/** /**
* Returns the timestamps for the specified tags. * Returns the timestamps for the specified tags.
* @param CacheInterface $cache * @param \Psr\SimpleCache\CacheInterface $cache
* @param string[] $tags * @param string[] $tags
* @return array the timestamps indexed by the specified tags. * @return array the timestamps indexed by the specified tags.
*/ */
@ -111,9 +111,21 @@ class TagDependency extends Dependency
$keys = []; $keys = [];
foreach ($tags as $tag) { foreach ($tags as $tag) {
$keys[] = $cache->buildKey([__CLASS__, $tag]); $keys[] = static::buildCacheKey($tag);
} }
return $cache->multiGet($keys); return $cache->getMultiple($keys);
}
/**
* Builds a normalized cache key from a given tag, making sure it is short enough and safe
* for any particular cache storage.
* @param string $tag tag name.
* @return string cache key.
* @since 2.1.0
*/
protected static function buildCacheKey($tag)
{
return md5(json_encode([__CLASS__, $tag]));
} }
} }

106
framework/caching/WinCache.php

@ -13,37 +13,42 @@ namespace yii\caching;
* To use this application component, the [WinCache PHP extension](http://www.iis.net/expand/wincacheforphp) * To use this application component, the [WinCache PHP extension](http://www.iis.net/expand/wincacheforphp)
* must be loaded. Also note that "wincache.ucenabled" should be set to "On" in your php.ini file. * must be loaded. Also note that "wincache.ucenabled" should be set to "On" in your php.ini file.
* *
* See [[Cache]] manual for common cache operations that are supported by WinCache. * Application configuration example:
*
* ```php
* return [
* 'components' => [
* 'cache' => [
* 'class' => yii\caching\Cache::class,
* 'handler' => [
* 'class' => yii\caching\WinCache::class,
* ],
* ],
* // ...
* ],
* // ...
* ];
* ```
*
* See [[\Psr\SimpleCache\CacheInterface]] for common cache operations that are supported by WinCache.
* *
* For more details and usage information on Cache, see the [guide article on caching](guide:caching-overview). * For more details and usage information on Cache, see the [guide article on caching](guide:caching-overview).
* *
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
*/ */
class WinCache extends Cache class WinCache extends SimpleCache
{ {
/** /**
* Checks whether a specified key exists in the cache. * {@inheritdoc}
* This can be faster than getting the value from the cache if the data is big.
* Note that this method does not check whether the dependency associated
* with the cached data, if there is any, has changed. So a call to [[get]]
* may return false while exists returns true.
* @param mixed $key a key identifying the cached value. This can be a simple string or
* a complex data structure consisting of factors representing the key.
* @return bool true if a value exists in cache, false if the value is not in the cache or expired.
*/ */
public function exists($key) public function has($key)
{ {
$key = $this->buildKey($key); return wincache_ucache_exists($this->normalizeKey($key));
return wincache_ucache_exists($key);
} }
/** /**
* Retrieves a value from cache with a specified key. * {@inheritdoc}
* This is the implementation of the method declared in the parent class.
* @param string $key a unique key identifying the cached value
* @return string|bool the value stored in cache, false if the value is not in the cache or expired.
*/ */
protected function getValue($key) protected function getValue($key)
{ {
@ -51,9 +56,7 @@ class WinCache extends Cache
} }
/** /**
* Retrieves multiple values from cache with the specified keys. * {@inheritdoc}
* @param array $keys a list of keys identifying the cached values
* @return array a list of cached values indexed by the keys
*/ */
protected function getValues($keys) protected function getValues($keys)
{ {
@ -61,64 +64,23 @@ class WinCache extends Cache
} }
/** /**
* Stores a value identified by a key in cache. * {@inheritdoc}
* This is the implementation of the method declared in the parent class.
*
* @param string $key the key identifying the value to be cached
* @param mixed $value the value to be cached. Most often it's a string. If you have disabled [[serializer]],
* it could be something else.
* @param int $duration the number of seconds in which the cached value will expire. 0 means never expire.
* @return bool true if the value is successfully stored into cache, false otherwise
*/
protected function setValue($key, $value, $duration)
{
return wincache_ucache_set($key, $value, $duration);
}
/**
* Stores multiple key-value pairs in cache.
* @param array $data array where key corresponds to cache key while value is the value stored
* @param int $duration the number of seconds in which the cached values will expire. 0 means never expire.
* @return array array of failed keys
*/
protected function setValues($data, $duration)
{
return wincache_ucache_set($data, null, $duration);
}
/**
* Stores a value identified by a key into cache if the cache does not contain this key.
* This is the implementation of the method declared in the parent class.
*
* @param string $key the key identifying the value to be cached
* @param mixed $value the value to be cached. Most often it's a string. If you have disabled [[serializer]],
* it could be something else.
* @param int $duration the number of seconds in which the cached value will expire. 0 means never expire.
* @return bool true if the value is successfully stored into cache, false otherwise
*/ */
protected function addValue($key, $value, $duration) protected function setValue($key, $value, $ttl)
{ {
return wincache_ucache_add($key, $value, $duration); return wincache_ucache_set($key, $value, $ttl);
} }
/** /**
* Adds multiple key-value pairs to cache. * {@inheritdoc}
* The default implementation calls [[addValue()]] multiple times add values one by one. If the underlying cache
* storage supports multiadd, this method should be overridden to exploit that feature.
* @param array $data array where key corresponds to cache key while value is the value stored
* @param int $duration the number of seconds in which the cached values will expire. 0 means never expire.
* @return array array of failed keys
*/ */
protected function addValues($data, $duration) protected function setValues($values, $ttl)
{ {
return wincache_ucache_add($data, null, $duration); return wincache_ucache_set($values, null, $ttl);
} }
/** /**
* Deletes a value with the specified key from cache * {@inheritdoc}
* This is the implementation of the method declared in the parent class.
* @param string $key the key of the value to be deleted
* @return bool if no error happens during deletion
*/ */
protected function deleteValue($key) protected function deleteValue($key)
{ {
@ -126,11 +88,9 @@ class WinCache extends Cache
} }
/** /**
* Deletes all values from cache. * {@inheritdoc}
* This is the implementation of the method declared in the parent class.
* @return bool whether the flush operation was successful.
*/ */
protected function flushValues() public function clear()
{ {
return wincache_ucache_clear(); return wincache_ucache_clear();
} }

66
framework/caching/ZendDataCache.php

@ -13,63 +13,51 @@ namespace yii\caching;
* To use this application component, the [Zend Data Cache PHP extension](http://www.zend.com/en/products/server/) * To use this application component, the [Zend Data Cache PHP extension](http://www.zend.com/en/products/server/)
* must be loaded. * must be loaded.
* *
* See [[Cache]] for common cache operations that ZendDataCache supports. * Application configuration example:
*
* ```php
* return [
* 'components' => [
* 'cache' => [
* 'class' => yii\caching\Cache::class,
* 'handler' => [
* 'class' => yii\caching\ZendDataCache::class,
* ],
* ],
* // ...
* ],
* // ...
* ];
* ```
*
* See [[\Psr\SimpleCache\CacheInterface]] for common cache operations that ZendDataCache supports.
* *
* For more details and usage information on Cache, see the [guide article on caching](guide:caching-overview). * For more details and usage information on Cache, see the [guide article on caching](guide:caching-overview).
* *
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
*/ */
class ZendDataCache extends Cache class ZendDataCache extends SimpleCache
{ {
/** /**
* Retrieves a value from cache with a specified key. * {@inheritdoc}
* This is the implementation of the method declared in the parent class.
* @param string $key a unique key identifying the cached value
* @return mixed|false the value stored in cache, false if the value is not in the cache or expired.
*/ */
protected function getValue($key) protected function getValue($key)
{ {
$result = zend_shm_cache_fetch($key); $result = zend_shm_cache_fetch($key);
return $result === null ? false : $result; return $result === null ? false : $result;
} }
/** /**
* Stores a value identified by a key in cache. * {@inheritdoc}
* This is the implementation of the method declared in the parent class.
*
* @param string $key the key identifying the value to be cached
* @param mixed $value the value to be cached. Most often it's a string. If you have disabled [[serializer]],
* it could be something else.
* @param int $duration the number of seconds in which the cached value will expire. 0 means never expire.
* @return bool true if the value is successfully stored into cache, false otherwise
*/
protected function setValue($key, $value, $duration)
{
return zend_shm_cache_store($key, $value, $duration);
}
/**
* Stores a value identified by a key into cache if the cache does not contain this key.
* This is the implementation of the method declared in the parent class.
*
* @param string $key the key identifying the value to be cached
* @param mixed $value the value to be cached. Most often it's a string. If you have disabled [[serializer]],
* it could be something else.
* @param int $duration the number of seconds in which the cached value will expire. 0 means never expire.
* @return bool true if the value is successfully stored into cache, false otherwise
*/ */
protected function addValue($key, $value, $duration) protected function setValue($key, $value, $ttl)
{ {
return zend_shm_cache_fetch($key) === null ? $this->setValue($key, $value, $duration) : false; return zend_shm_cache_store($key, $value, $ttl);
} }
/** /**
* Deletes a value with the specified key from cache * {@inheritdoc}
* This is the implementation of the method declared in the parent class.
* @param string $key the key of the value to be deleted
* @return bool if no error happens during deletion
*/ */
protected function deleteValue($key) protected function deleteValue($key)
{ {
@ -77,11 +65,9 @@ class ZendDataCache extends Cache
} }
/** /**
* Deletes all values from cache. * {@inheritdoc}
* This is the implementation of the method declared in the parent class.
* @return bool whether the flush operation was successful.
*/ */
protected function flushValues() public function clear()
{ {
return zend_shm_cache_clear(); return zend_shm_cache_clear();
} }

1
framework/composer.json

@ -68,6 +68,7 @@
"ext-ctype": "*", "ext-ctype": "*",
"lib-pcre": "*", "lib-pcre": "*",
"yiisoft/yii2-composer": "~2.0.4", "yiisoft/yii2-composer": "~2.0.4",
"psr/simple-cache": "~1.0.0",
"ezyang/htmlpurifier": "~4.6", "ezyang/htmlpurifier": "~4.6",
"cebe/markdown": "~1.0.0 | ~1.1.0", "cebe/markdown": "~1.0.0 | ~1.1.0",
"bower-asset/jquery": "2.2.*@stable | 2.1.*@stable | 1.11.*@stable | 1.12.*@stable", "bower-asset/jquery": "2.2.*@stable | 2.1.*@stable | 1.11.*@stable | 1.12.*@stable",

79
framework/console/controllers/CacheController.php

@ -7,35 +7,36 @@
namespace yii\console\controllers; namespace yii\console\controllers;
use Psr\SimpleCache\CacheInterface;
use Yii; use Yii;
use yii\caching\ApcCache; use yii\caching\ApcCache;
use yii\caching\CacheInterface; use yii\caching\Cache;
use yii\console\Controller; use yii\console\Controller;
use yii\console\Exception; use yii\console\Exception;
use yii\console\ExitCode; use yii\console\ExitCode;
use yii\helpers\Console; use yii\helpers\Console;
/** /**
* Allows you to flush cache. * Allows you to clear cache.
* *
* see list of available components to flush: * see list of available components to clear:
* *
* yii cache * yii cache
* *
* flush particular components specified by their names: * clear particular components specified by their names:
* *
* yii cache/flush first second third * yii cache/clear first second third
* *
* flush all cache components that can be found in the system * clear all cache components that can be found in the system
* *
* yii cache/flush-all * yii cache/clear-all
* *
* Note that the command uses cache components defined in your console application configuration file. If components * Note that the command uses cache components defined in your console application configuration file. If components
* configured are different from web application, web application cache won't be cleared. In order to fix it please * configured are different from web application, web application cache won't be cleared. In order to fix it please
* duplicate web application cache components in console config. You can use any component names. * duplicate web application cache components in console config. You can use any component names.
* *
* APC is not shared between PHP processes so flushing cache from command line has no effect on web. * APC is not shared between PHP processes so clearing cache from command line has no effect on web.
* Flushing web cache could be either done by: * Clearing web cache could be either done by:
* *
* - Putting a php file under web root and calling it via HTTP * - Putting a php file under web root and calling it via HTTP
* - Using [Cachetool](http://gordalina.github.io/cachetool/) * - Using [Cachetool](http://gordalina.github.io/cachetool/)
@ -47,29 +48,29 @@ use yii\helpers\Console;
class CacheController extends Controller class CacheController extends Controller
{ {
/** /**
* Lists the caches that can be flushed. * Lists the caches that can be cleared.
*/ */
public function actionIndex() public function actionIndex()
{ {
$caches = $this->findCaches(); $caches = $this->findCaches();
if (!empty($caches)) { if (!empty($caches)) {
$this->notifyCachesCanBeFlushed($caches); $this->notifyCachesCanBeCleared($caches);
} else { } else {
$this->notifyNoCachesFound(); $this->notifyNoCachesFound();
} }
} }
/** /**
* Flushes given cache components. * Clears given cache components.
* For example, * For example,
* *
* ``` * ```
* # flushes caches specified by their id: "first", "second", "third" * # clears caches specified by their id: "first", "second", "third"
* yii cache/flush first second third * yii cache/clear first second third
* ``` * ```
*/ */
public function actionFlush() public function actionClear()
{ {
$cachesInput = func_get_args(); $cachesInput = func_get_args();
@ -92,7 +93,7 @@ class CacheController extends Controller
return ExitCode::OK; return ExitCode::OK;
} }
if (!$this->confirmFlush($foundCaches)) { if (!$this->confirmClear($foundCaches)) {
return ExitCode::OK; return ExitCode::OK;
} }
@ -100,17 +101,17 @@ class CacheController extends Controller
$cachesInfo[] = [ $cachesInfo[] = [
'name' => $name, 'name' => $name,
'class' => $class, 'class' => $class,
'is_flushed' => $this->canBeFlushed($class) ? Yii::$app->get($name)->flush() : false, 'is_cleared' => $this->canBeCleared($class) ? Yii::$app->get($name)->clear() : false,
]; ];
} }
$this->notifyFlushed($cachesInfo); $this->notifyCleared($cachesInfo);
} }
/** /**
* Flushes all caches registered in the system. * Clears all caches registered in the system.
*/ */
public function actionFlushAll() public function actionClearAll()
{ {
$caches = $this->findCaches(); $caches = $this->findCaches();
$cachesInfo = []; $cachesInfo = [];
@ -124,11 +125,11 @@ class CacheController extends Controller
$cachesInfo[] = [ $cachesInfo[] = [
'name' => $name, 'name' => $name,
'class' => $class, 'class' => $class,
'is_flushed' => $this->canBeFlushed($class) ? Yii::$app->get($name)->flush() : false, 'is_cleared' => $this->canBeCleared($class) ? Yii::$app->get($name)->clear() : false,
]; ];
} }
$this->notifyFlushed($cachesInfo); $this->notifyCleared($cachesInfo);
} }
/** /**
@ -136,7 +137,7 @@ class CacheController extends Controller
* *
* ``` * ```
* # clears cache schema specified by component id: "db" * # clears cache schema specified by component id: "db"
* yii cache/flush-schema db * yii cache/clear-schema db
* ``` * ```
* *
* @param string $db id connection component * @param string $db id connection component
@ -146,7 +147,7 @@ class CacheController extends Controller
* *
* @since 2.0.1 * @since 2.0.1
*/ */
public function actionFlushSchema($db = 'db') public function actionClearSchema($db = 'db')
{ {
$connection = Yii::$app->get($db, false); $connection = Yii::$app->get($db, false);
if ($connection === null) { if ($connection === null) {
@ -157,32 +158,32 @@ class CacheController extends Controller
if (!$connection instanceof \yii\db\Connection) { if (!$connection instanceof \yii\db\Connection) {
$this->stdout("\"$db\" component doesn't inherit \\yii\\db\\Connection.\n", Console::FG_RED); $this->stdout("\"$db\" component doesn't inherit \\yii\\db\\Connection.\n", Console::FG_RED);
return ExitCode::UNSPECIFIED_ERROR; return ExitCode::UNSPECIFIED_ERROR;
} elseif (!$this->confirm("Flush cache schema for \"$db\" connection?")) { } elseif (!$this->confirm("Clear cache schema for \"$db\" connection?")) {
return ExitCode::OK; return ExitCode::OK;
} }
try { try {
$schema = $connection->getSchema(); $schema = $connection->getSchema();
$schema->refresh(); $schema->refresh();
$this->stdout("Schema cache for component \"$db\", was flushed.\n\n", Console::FG_GREEN); $this->stdout("Schema cache for component \"$db\", was cleared.\n\n", Console::FG_GREEN);
} catch (\Exception $e) { } catch (\Exception $e) {
$this->stdout($e->getMessage() . "\n\n", Console::FG_RED); $this->stdout($e->getMessage() . "\n\n", Console::FG_RED);
} }
} }
/** /**
* Notifies user that given caches are found and can be flushed. * Notifies user that given caches are found and can be cleared.
* @param array $caches array of cache component classes * @param array $caches array of cache component classes
*/ */
private function notifyCachesCanBeFlushed($caches) private function notifyCachesCanBeCleared($caches)
{ {
$this->stdout("The following caches were found in the system:\n\n", Console::FG_YELLOW); $this->stdout("The following caches were found in the system:\n\n", Console::FG_YELLOW);
foreach ($caches as $name => $class) { foreach ($caches as $name => $class) {
if ($this->canBeFlushed($class)) { if ($this->canBeCleared($class)) {
$this->stdout("\t* $name ($class)\n", Console::FG_GREEN); $this->stdout("\t* $name ($class)\n", Console::FG_GREEN);
} else { } else {
$this->stdout("\t* $name ($class) - can not be flushed via console\n", Console::FG_YELLOW); $this->stdout("\t* $name ($class) - can not be cleared via console\n", Console::FG_YELLOW);
} }
} }
@ -215,15 +216,15 @@ class CacheController extends Controller
/** /**
* @param array $caches * @param array $caches
*/ */
private function notifyFlushed($caches) private function notifyCleared($caches)
{ {
$this->stdout("The following cache components were processed:\n\n", Console::FG_YELLOW); $this->stdout("The following cache components were processed:\n\n", Console::FG_YELLOW);
foreach ($caches as $cache) { foreach ($caches as $cache) {
$this->stdout("\t* " . $cache['name'] . ' (' . $cache['class'] . ')', Console::FG_GREEN); $this->stdout("\t* " . $cache['name'] . ' (' . $cache['class'] . ')', Console::FG_GREEN);
if (!$cache['is_flushed']) { if (!$cache['is_cleared']) {
$this->stdout(" - not flushed\n", Console::FG_RED); $this->stdout(" - not cleared\n", Console::FG_RED);
} else { } else {
$this->stdout("\n"); $this->stdout("\n");
} }
@ -233,19 +234,19 @@ class CacheController extends Controller
} }
/** /**
* Prompts user with confirmation if caches should be flushed. * Prompts user with confirmation if caches should be cleared.
* @param array $cachesNames * @param array $cachesNames
* @return bool * @return bool
*/ */
private function confirmFlush($cachesNames) private function confirmClear($cachesNames)
{ {
$this->stdout("The following cache components will be flushed:\n\n", Console::FG_YELLOW); $this->stdout("The following cache components will be cleared:\n\n", Console::FG_YELLOW);
foreach ($cachesNames as $name) { foreach ($cachesNames as $name) {
$this->stdout("\t* $name \n", Console::FG_GREEN); $this->stdout("\t* $name \n", Console::FG_GREEN);
} }
return $this->confirm("\nFlush above cache components?"); return $this->confirm("\nClear above cache components?");
} }
/** /**
@ -287,11 +288,11 @@ class CacheController extends Controller
} }
/** /**
* Checks if cache of a certain class can be flushed * Checks if cache of a certain class can be cleared
* @param string $className class name. * @param string $className class name.
* @return bool * @return bool
*/ */
private function canBeFlushed($className) private function canBeCleared($className)
{ {
return !is_a($className, ApcCache::class, true) || php_sapi_name() !== 'cli'; return !is_a($className, ApcCache::class, true) || php_sapi_name() !== 'cli';
} }

4
framework/web/CacheSession.php

@ -79,7 +79,7 @@ class CacheSession extends Session
{ {
$data = $this->cache->get($this->calculateKey($id)); $data = $this->cache->get($this->calculateKey($id));
return $data === false ? '' : $data; return $data === null ? '' : $data;
} }
/** /**
@ -103,7 +103,7 @@ class CacheSession extends Session
public function destroySession($id) public function destroySession($id)
{ {
$cacheId = $this->calculateKey($id); $cacheId = $this->calculateKey($id);
if ($this->cache->exists($cacheId) === false) { if ($this->cache->has($cacheId) === false) {
return true; return true;
} }

5
tests/framework/base/ViewTest.php

@ -9,6 +9,7 @@ namespace yiiunit\framework\base;
use Yii; use Yii;
use yii\base\View; use yii\base\View;
use yii\caching\Cache;
use yii\caching\FileCache; use yii\caching\FileCache;
use yii\helpers\FileHelper; use yii\helpers\FileHelper;
use yiiunit\TestCase; use yiiunit\TestCase;
@ -71,14 +72,14 @@ PHP
public function testRenderDynamic() public function testRenderDynamic()
{ {
Yii::$app->set('cache', new FileCache(['cachePath' => '@yiiunit/runtime/cache'])); Yii::$app->set('cache', new Cache(['handler' => new FileCache(['cachePath' => '@yiiunit/runtime/cache'])]));
$view = new View(); $view = new View();
$this->assertEquals(1, $view->renderDynamic('return 1;')); $this->assertEquals(1, $view->renderDynamic('return 1;'));
} }
public function testRenderDynamic_DynamicPlaceholders() public function testRenderDynamic_DynamicPlaceholders()
{ {
Yii::$app->set('cache', new FileCache(['cachePath' => '@yiiunit/runtime/cache'])); Yii::$app->set('cache', new Cache(['handler' => new FileCache(['cachePath' => '@yiiunit/runtime/cache'])]));
$statement = "return 1;"; $statement = "return 1;";
$view = new View(); $view = new View();
if ($view->beginCache(__FUNCTION__, ['duration' => 3])) { if ($view->beginCache(__FUNCTION__, ['duration' => 3])) {

7
tests/framework/caching/ApcCacheTest.php

@ -8,6 +8,7 @@
namespace yiiunit\framework\caching; namespace yiiunit\framework\caching;
use yii\caching\ApcCache; use yii\caching\ApcCache;
use yii\caching\Cache;
/** /**
* Class for testing APC cache backend * Class for testing APC cache backend
@ -19,7 +20,7 @@ class ApcCacheTest extends CacheTestCase
private $_cacheInstance = null; private $_cacheInstance = null;
/** /**
* @return ApcCache * @return Cache
*/ */
protected function getCacheInstance() protected function getCacheInstance()
{ {
@ -32,7 +33,9 @@ class ApcCacheTest extends CacheTestCase
} }
if ($this->_cacheInstance === null) { if ($this->_cacheInstance === null) {
$this->_cacheInstance = new ApcCache(); $this->_cacheInstance = new Cache([
'handler' => new ApcCache()
]);
} }
return $this->_cacheInstance; return $this->_cacheInstance;

11
tests/framework/caching/ArrayCacheTest.php

@ -8,6 +8,7 @@
namespace yiiunit\framework\caching; namespace yiiunit\framework\caching;
use yii\caching\ArrayCache; use yii\caching\ArrayCache;
use yii\caching\Cache;
/** /**
* Class for testing file cache backend * Class for testing file cache backend
@ -18,12 +19,14 @@ class ArrayCacheTest extends CacheTestCase
private $_cacheInstance = null; private $_cacheInstance = null;
/** /**
* @return ArrayCache * @return Cache
*/ */
protected function getCacheInstance() protected function getCacheInstance()
{ {
if ($this->_cacheInstance === null) { if ($this->_cacheInstance === null) {
$this->_cacheInstance = new ArrayCache(); $this->_cacheInstance = new Cache([
'handler' => new ArrayCache()
]);
} }
return $this->_cacheInstance; return $this->_cacheInstance;
} }
@ -37,7 +40,7 @@ class ArrayCacheTest extends CacheTestCase
static::$microtime++; static::$microtime++;
$this->assertEquals('expire_test', $cache->get('expire_test')); $this->assertEquals('expire_test', $cache->get('expire_test'));
static::$microtime++; static::$microtime++;
$this->assertFalse($cache->get('expire_test')); $this->assertNull($cache->get('expire_test'));
} }
public function testExpireAdd() public function testExpireAdd()
@ -49,6 +52,6 @@ class ArrayCacheTest extends CacheTestCase
static::$microtime++; static::$microtime++;
$this->assertEquals('expire_testa', $cache->get('expire_testa')); $this->assertEquals('expire_testa', $cache->get('expire_testa'));
static::$microtime++; static::$microtime++;
$this->assertFalse($cache->get('expire_testa')); $this->assertNull($cache->get('expire_testa'));
} }
} }

50
tests/framework/caching/CacheTestCase.php

@ -73,7 +73,7 @@ abstract class CacheTestCase extends TestCase
{ {
$cache = $this->getCacheInstance(); $cache = $this->getCacheInstance();
$cache->flush(); $cache->clear();
$cache->set('string_test', 'string_test'); $cache->set('string_test', 'string_test');
$cache->set('number_test', 42); $cache->set('number_test', 42);
$cache->set('array_test', ['array_test' => 'array_test']); $cache->set('array_test', ['array_test' => 'array_test']);
@ -107,20 +107,20 @@ abstract class CacheTestCase extends TestCase
/** /**
* @return array testing multiSet with and without expiry * @return array testing multiSet with and without expiry
*/ */
public function multiSetExpiry() public function dataProviderSetMultiple()
{ {
return [[0], [2]]; return [[0], [2]];
} }
/** /**
* @dataProvider multiSetExpiry * @dataProvider dataProviderSetMultiple
*/ */
public function testMultiset($expiry) public function testSetMultiple($expiry)
{ {
$cache = $this->getCacheInstance(); $cache = $this->getCacheInstance();
$cache->flush(); $cache->clear();
$cache->multiSet([ $cache->setMultiple([
'string_test' => 'string_test', 'string_test' => 'string_test',
'number_test' => 42, 'number_test' => 42,
'array_test' => ['array_test' => 'array_test'], 'array_test' => ['array_test' => 'array_test'],
@ -135,16 +135,16 @@ abstract class CacheTestCase extends TestCase
$this->assertEquals('array_test', $array['array_test']); $this->assertEquals('array_test', $array['array_test']);
} }
public function testExists() public function testHas()
{ {
$cache = $this->prepare(); $cache = $this->prepare();
$this->assertTrue($cache->exists('string_test')); $this->assertTrue($cache->has('string_test'));
// check whether exists affects the value // check whether exists affects the value
$this->assertEquals('string_test', $cache->get('string_test')); $this->assertEquals('string_test', $cache->get('string_test'));
$this->assertTrue($cache->exists('number_test')); $this->assertTrue($cache->has('number_test'));
$this->assertFalse($cache->exists('not_exists')); $this->assertFalse($cache->has('not_exists'));
} }
public function testArrayAccess() public function testArrayAccess()
@ -159,7 +159,7 @@ abstract class CacheTestCase extends TestCase
{ {
$cache = $this->getCacheInstance(); $cache = $this->getCacheInstance();
$this->assertFalse($cache->get('non_existent_key')); $this->assertNull($cache->get('non_existent_key'));
} }
public function testStoreSpecialValues() public function testStoreSpecialValues()
@ -173,21 +173,21 @@ abstract class CacheTestCase extends TestCase
$this->assertTrue($cache->get('bool_value')); $this->assertTrue($cache->get('bool_value'));
} }
public function testMultiGet() public function testGetMultiple()
{ {
$cache = $this->prepare(); $cache = $this->prepare();
$this->assertEquals(['string_test' => 'string_test', 'number_test' => 42], $cache->multiGet(['string_test', 'number_test'])); $this->assertEquals(['string_test' => 'string_test', 'number_test' => 42], $cache->getMultiple(['string_test', 'number_test']));
// ensure that order does not matter // ensure that order does not matter
$this->assertEquals(['number_test' => 42, 'string_test' => 'string_test'], $cache->multiGet(['number_test', 'string_test'])); $this->assertEquals(['number_test' => 42, 'string_test' => 'string_test'], $cache->getMultiple(['number_test', 'string_test']));
$this->assertEquals(['number_test' => 42, 'non_existent_key' => null], $cache->multiGet(['number_test', 'non_existent_key'])); $this->assertEquals(['number_test' => 42, 'non_existent_key' => null], $cache->getMultiple(['number_test', 'non_existent_key']));
} }
public function testDefaultTtl() public function testDefaultTtl()
{ {
$cache = $this->getCacheInstance(); $cache = $this->getCacheInstance();
$this->assertSame(0, $cache->defaultDuration); $this->assertSame(0, $cache->handler->defaultTtl);
} }
public function testExpire() public function testExpire()
@ -198,7 +198,7 @@ abstract class CacheTestCase extends TestCase
usleep(500000); usleep(500000);
$this->assertEquals('expire_test', $cache->get('expire_test')); $this->assertEquals('expire_test', $cache->get('expire_test'));
usleep(2500000); usleep(2500000);
$this->assertFalse($cache->get('expire_test')); $this->assertNull($cache->get('expire_test'));
} }
public function testExpireAdd() public function testExpireAdd()
@ -209,7 +209,7 @@ abstract class CacheTestCase extends TestCase
usleep(500000); usleep(500000);
$this->assertEquals('expire_testa', $cache->get('expire_testa')); $this->assertEquals('expire_testa', $cache->get('expire_testa'));
usleep(2500000); usleep(2500000);
$this->assertFalse($cache->get('expire_testa')); $this->assertNull($cache->get('expire_testa'));
} }
public function testAdd() public function testAdd()
@ -221,18 +221,18 @@ abstract class CacheTestCase extends TestCase
$this->assertEquals(42, $cache->get('number_test')); $this->assertEquals(42, $cache->get('number_test'));
// should store data if it's not there yet // should store data if it's not there yet
$this->assertFalse($cache->get('add_test')); $this->assertNull($cache->get('add_test'));
$this->assertTrue($cache->add('add_test', 13)); $this->assertTrue($cache->add('add_test', 13));
$this->assertEquals(13, $cache->get('add_test')); $this->assertEquals(13, $cache->get('add_test'));
} }
public function testMultiAdd() public function testAddMultiple()
{ {
$cache = $this->prepare(); $cache = $this->prepare();
$this->assertFalse($cache->get('add_test')); $this->assertNull($cache->get('add_test'));
$cache->multiAdd([ $cache->addMultiple([
'number_test' => 13, 'number_test' => 13,
'add_test' => 13, 'add_test' => 13,
]); ]);
@ -247,14 +247,14 @@ abstract class CacheTestCase extends TestCase
$this->assertNotNull($cache->get('number_test')); $this->assertNotNull($cache->get('number_test'));
$this->assertTrue($cache->delete('number_test')); $this->assertTrue($cache->delete('number_test'));
$this->assertFalse($cache->get('number_test')); $this->assertNull($cache->get('number_test'));
} }
public function testFlush() public function testFlush()
{ {
$cache = $this->prepare(); $cache = $this->prepare();
$this->assertTrue($cache->flush()); $this->assertTrue($cache->clear());
$this->assertFalse($cache->get('number_test')); $this->assertNull($cache->get('number_test'));
} }
public function testGetOrSet() public function testGetOrSet()

17
tests/framework/caching/DbCacheTest.php

@ -7,6 +7,7 @@
namespace yiiunit\framework\caching; namespace yiiunit\framework\caching;
use yii\caching\Cache;
use yii\caching\DbCache; use yii\caching\DbCache;
/** /**
@ -38,6 +39,12 @@ class DbCacheTest extends CacheTestCase
')->execute(); ')->execute();
} }
protected function tearDown()
{
$this->getConnection()->createCommand('DROP TABLE IF EXISTS cache')->execute();
parent::tearDown();
}
/** /**
* @param bool $reset whether to clean up the test database * @param bool $reset whether to clean up the test database
* @return \yii\db\Connection * @return \yii\db\Connection
@ -67,12 +74,14 @@ class DbCacheTest extends CacheTestCase
} }
/** /**
* @return DbCache * @return Cache
*/ */
protected function getCacheInstance() protected function getCacheInstance()
{ {
if ($this->_cacheInstance === null) { if ($this->_cacheInstance === null) {
$this->_cacheInstance = new DbCache(['db' => $this->getConnection()]); $this->_cacheInstance = new Cache([
'handler' => new DbCache(['db' => $this->getConnection()])
]);
} }
return $this->_cacheInstance; return $this->_cacheInstance;
@ -87,7 +96,7 @@ class DbCacheTest extends CacheTestCase
static::$time++; static::$time++;
$this->assertEquals('expire_test', $cache->get('expire_test')); $this->assertEquals('expire_test', $cache->get('expire_test'));
static::$time++; static::$time++;
$this->assertFalse($cache->get('expire_test')); $this->assertNull($cache->get('expire_test'));
} }
public function testExpireAdd() public function testExpireAdd()
@ -99,6 +108,6 @@ class DbCacheTest extends CacheTestCase
static::$time++; static::$time++;
$this->assertEquals('expire_testa', $cache->get('expire_testa')); $this->assertEquals('expire_testa', $cache->get('expire_testa'));
static::$time++; static::$time++;
$this->assertFalse($cache->get('expire_testa')); $this->assertNull($cache->get('expire_testa'));
} }
} }

5
tests/framework/caching/DependencyTest.php

@ -9,6 +9,7 @@ namespace yiiunit\framework\caching;
use yii\caching\Cache; use yii\caching\Cache;
use yii\caching\Dependency; use yii\caching\Dependency;
use yii\caching\SimpleCache;
use yiiunit\data\cache\MockDependency; use yiiunit\data\cache\MockDependency;
use yiiunit\TestCase; use yiiunit\TestCase;
@ -44,8 +45,10 @@ class DependencyTest extends TestCase
public function testIsChanged() public function testIsChanged()
{ {
/* @var $dependency Dependency */
/* @var $cache SimpleCache */
$dependency = $this->getMockForAbstractClass(Dependency::class); $dependency = $this->getMockForAbstractClass(Dependency::class);
$cache = $this->getMockForAbstractClass(Cache::class); $cache = $this->getMockForAbstractClass(SimpleCache::class);
$result = $dependency->isChanged($cache); $result = $dependency->isChanged($cache);
$this->assertFalse($result); $this->assertFalse($result);

11
tests/framework/caching/FileCacheTest.php

@ -7,6 +7,7 @@
namespace yiiunit\framework\caching; namespace yiiunit\framework\caching;
use yii\caching\Cache;
use yii\caching\FileCache; use yii\caching\FileCache;
/** /**
@ -18,12 +19,14 @@ class FileCacheTest extends CacheTestCase
private $_cacheInstance = null; private $_cacheInstance = null;
/** /**
* @return FileCache * @return Cache
*/ */
protected function getCacheInstance() protected function getCacheInstance()
{ {
if ($this->_cacheInstance === null) { if ($this->_cacheInstance === null) {
$this->_cacheInstance = new FileCache(['cachePath' => '@yiiunit/runtime/cache']); $this->_cacheInstance = new Cache([
'handler' => new FileCache(['cachePath' => '@yiiunit/runtime/cache'])
]);
} }
return $this->_cacheInstance; return $this->_cacheInstance;
@ -38,7 +41,7 @@ class FileCacheTest extends CacheTestCase
static::$time++; static::$time++;
$this->assertEquals('expire_test', $cache->get('expire_test')); $this->assertEquals('expire_test', $cache->get('expire_test'));
static::$time++; static::$time++;
$this->assertFalse($cache->get('expire_test')); $this->assertNull($cache->get('expire_test'));
} }
public function testExpireAdd() public function testExpireAdd()
@ -50,6 +53,6 @@ class FileCacheTest extends CacheTestCase
static::$time++; static::$time++;
$this->assertEquals('expire_testa', $cache->get('expire_testa')); $this->assertEquals('expire_testa', $cache->get('expire_testa'));
static::$time++; static::$time++;
$this->assertFalse($cache->get('expire_testa')); $this->assertNull($cache->get('expire_testa'));
} }
} }

7
tests/framework/caching/MemCachedTest.php

@ -7,6 +7,7 @@
namespace yiiunit\framework\caching; namespace yiiunit\framework\caching;
use yii\caching\Cache;
use yii\caching\MemCached; use yii\caching\MemCached;
/** /**
@ -19,7 +20,7 @@ class MemCachedTest extends CacheTestCase
private $_cacheInstance = null; private $_cacheInstance = null;
/** /**
* @return MemCached * @return Cache
*/ */
protected function getCacheInstance() protected function getCacheInstance()
{ {
@ -33,7 +34,9 @@ class MemCachedTest extends CacheTestCase
} }
if ($this->_cacheInstance === null) { if ($this->_cacheInstance === null) {
$this->_cacheInstance = new MemCached(); $this->_cacheInstance = new Cache([
'handler' => new MemCached()
]);
} }
return $this->_cacheInstance; return $this->_cacheInstance;

64
tests/framework/caching/SimpleCacheTest.php

@ -0,0 +1,64 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yiiunit\framework\caching;
use DateInterval;
use yii\caching\SimpleCache;
use yiiunit\TestCase;
/**
* @group caching
*/
class SimpleCacheTest extends TestCase
{
/**
* @var SimpleCache|\PHPUnit_Framework_MockObject_MockObject
*/
protected $cache;
/**
* {@inheritdoc}
*/
protected function setUp()
{
parent::setUp();
$this->cache = $this->getMockBuilder(SimpleCache::class)->getMockForAbstractClass();
}
/**
* Data provider for [[testNormalizeTtl()]]
* @return array test data.
*/
public function dataProviderNormalizeTtl()
{
return [
[123, 123],
['123', 123],
[null, 9999],
[0, 0],
[new DateInterval('PT6H8M'), (6 * 3600 + 8 * 60)],
[new DateInterval('P2Y4D'), (2 * 365 * 24 * 3600 + 4 * 24 * 3600)],
];
}
/**
* @dataProvider dataProviderNormalizeTtl
*
* @covers \yii\caching\SimpleCache::normalizeTtl()
*
* @param mixed $ttl
* @param int $expectedResult
*/
public function testNormalizeTtl($ttl, $expectedResult)
{
$this->cache->defaultTtl = 9999;
$this->assertEquals($expectedResult, $this->invokeMethod($this->cache, 'normalizeTtl', [$ttl]));
}
}

37
tests/framework/caching/TagDependencyTest.php

@ -7,6 +7,7 @@
namespace yiiunit\framework\caching; namespace yiiunit\framework\caching;
use yii\caching\Cache;
use yii\caching\FileCache; use yii\caching\FileCache;
use yii\caching\TagDependency; use yii\caching\TagDependency;
use yiiunit\TestCase; use yiiunit\TestCase;
@ -18,7 +19,7 @@ class TagDependencyTest extends TestCase
{ {
public function testInvalidate() public function testInvalidate()
{ {
$cache = new FileCache(['cachePath' => '@yiiunit/runtime/cache']); $cache = new Cache(['handler' => new FileCache(['cachePath' => '@yiiunit/runtime/cache'])]);
// single tag test // single tag test
$cache->set('a1', 11, 0, new TagDependency(['tags' => 't1'])); $cache->set('a1', 11, 0, new TagDependency(['tags' => 't1']));
@ -32,16 +33,16 @@ class TagDependencyTest extends TestCase
$this->assertEquals(22, $cache->get('b2')); $this->assertEquals(22, $cache->get('b2'));
TagDependency::invalidate($cache, 't1'); TagDependency::invalidate($cache, 't1');
$this->assertFalse($cache->get('a1')); $this->assertNull($cache->get('a1'));
$this->assertFalse($cache->get('a2')); $this->assertNull($cache->get('a2'));
$this->assertEquals(21, $cache->get('b1')); $this->assertEquals(21, $cache->get('b1'));
$this->assertEquals(22, $cache->get('b2')); $this->assertEquals(22, $cache->get('b2'));
TagDependency::invalidate($cache, 't2'); TagDependency::invalidate($cache, 't2');
$this->assertFalse($cache->get('a1')); $this->assertNull($cache->get('a1'));
$this->assertFalse($cache->get('a2')); $this->assertNull($cache->get('a2'));
$this->assertFalse($cache->get('b1')); $this->assertNull($cache->get('b1'));
$this->assertFalse($cache->get('b2')); $this->assertNull($cache->get('b2'));
// multiple tag test // multiple tag test
$cache->set('a1', 11, 0, new TagDependency(['tags' => ['t1', 't2']])); $cache->set('a1', 11, 0, new TagDependency(['tags' => ['t1', 't2']]));
@ -55,16 +56,16 @@ class TagDependencyTest extends TestCase
$this->assertEquals(22, $cache->get('b2')); $this->assertEquals(22, $cache->get('b2'));
TagDependency::invalidate($cache, 't1'); TagDependency::invalidate($cache, 't1');
$this->assertFalse($cache->get('a1')); $this->assertNull($cache->get('a1'));
$this->assertFalse($cache->get('a2')); $this->assertNull($cache->get('a2'));
$this->assertFalse($cache->get('b1')); $this->assertNull($cache->get('b1'));
$this->assertEquals(22, $cache->get('b2')); $this->assertEquals(22, $cache->get('b2'));
TagDependency::invalidate($cache, 't2'); TagDependency::invalidate($cache, 't2');
$this->assertFalse($cache->get('a1')); $this->assertNull($cache->get('a1'));
$this->assertFalse($cache->get('a2')); $this->assertNull($cache->get('a2'));
$this->assertFalse($cache->get('b1')); $this->assertNull($cache->get('b1'));
$this->assertFalse($cache->get('b2')); $this->assertNull($cache->get('b2'));
$cache->set('a1', 11, 0, new TagDependency(['tags' => ['t1', 't2']])); $cache->set('a1', 11, 0, new TagDependency(['tags' => ['t1', 't2']]));
$cache->set('a2', 12, 0, new TagDependency(['tags' => 't1'])); $cache->set('a2', 12, 0, new TagDependency(['tags' => 't1']));
@ -77,9 +78,9 @@ class TagDependencyTest extends TestCase
$this->assertEquals(22, $cache->get('b2')); $this->assertEquals(22, $cache->get('b2'));
TagDependency::invalidate($cache, ['t1', 't2']); TagDependency::invalidate($cache, ['t1', 't2']);
$this->assertFalse($cache->get('a1')); $this->assertNull($cache->get('a1'));
$this->assertFalse($cache->get('a2')); $this->assertNull($cache->get('a2'));
$this->assertFalse($cache->get('b1')); $this->assertNull($cache->get('b1'));
$this->assertFalse($cache->get('b2')); $this->assertNull($cache->get('b2'));
} }
} }

7
tests/framework/caching/WinCacheTest.php

@ -7,6 +7,7 @@
namespace yiiunit\framework\caching; namespace yiiunit\framework\caching;
use yii\caching\Cache;
use yii\caching\WinCache; use yii\caching\WinCache;
/** /**
@ -19,7 +20,7 @@ class WinCacheTest extends CacheTestCase
private $_cacheInstance = null; private $_cacheInstance = null;
/** /**
* @return WinCache * @return Cache
*/ */
protected function getCacheInstance() protected function getCacheInstance()
{ {
@ -32,7 +33,9 @@ class WinCacheTest extends CacheTestCase
} }
if ($this->_cacheInstance === null) { if ($this->_cacheInstance === null) {
$this->_cacheInstance = new WinCache(); $this->_cacheInstance = new Cache([
'handler' => new WinCache()
]);
} }
return $this->_cacheInstance; return $this->_cacheInstance;

8
tests/framework/console/UnkownCommandExceptionTest.php

@ -38,10 +38,10 @@ class UnkownCommandExceptionTest extends TestCase
['mirgte/up', ['migrate/up']], ['mirgte/up', ['migrate/up']],
['mirgte', ['migrate']], ['mirgte', ['migrate']],
['hlp', ['help']], ['hlp', ['help']],
['ca', ['cache', 'cache/flush', 'cache/flush-all', 'cache/flush-schema', 'cache/index']], ['ca', ['cache', 'cache/clear', 'cache/clear-all', 'cache/clear-schema', 'cache/index']],
['cach', ['cache', 'cache/flush', 'cache/flush-all', 'cache/flush-schema', 'cache/index']], ['cach', ['cache', 'cache/clear', 'cache/clear-all', 'cache/clear-schema', 'cache/index']],
['cach/fush', ['cache/flush']], ['cach/clear', ['cache/clear']],
['cach/fushall', ['cache/flush-all']], ['cach/clearall', ['cache/clear-all']],
['what?', []], ['what?', []],
// test UTF 8 chars // test UTF 8 chars
['ёлка', []], ['ёлка', []],

28
tests/framework/console/controllers/CacheControllerTest.php

@ -50,7 +50,7 @@ class CacheControllerTest extends TestCase
'components' => [ 'components' => [
'firstCache' => 'yii\caching\ArrayCache', 'firstCache' => 'yii\caching\ArrayCache',
'secondCache' => 'yii\caching\ArrayCache', 'secondCache' => 'yii\caching\ArrayCache',
'session' => 'yii\web\CacheSession', // should be ignored at `actionFlushAll()` 'session' => 'yii\web\CacheSession', // should be ignored at `actionClearAll()`
'db' => [ 'db' => [
'class' => isset($config['class']) ? $config['class'] : 'yii\db\Connection', 'class' => isset($config['class']) ? $config['class'] : 'yii\db\Connection',
'dsn' => $config['dsn'], 'dsn' => $config['dsn'],
@ -79,10 +79,10 @@ class CacheControllerTest extends TestCase
Yii::$app->firstCache->set('secondKey', 'secondValue'); Yii::$app->firstCache->set('secondKey', 'secondValue');
Yii::$app->secondCache->set('thirdKey', 'thirdValue'); Yii::$app->secondCache->set('thirdKey', 'thirdValue');
$this->_cacheController->actionFlush('firstCache'); $this->_cacheController->actionClear('firstCache');
$this->assertFalse(Yii::$app->firstCache->get('firstKey'), 'first cache data should be flushed'); $this->assertNull(Yii::$app->firstCache->get('firstKey'), 'first cache data should be flushed');
$this->assertFalse(Yii::$app->firstCache->get('secondKey'), 'first cache data should be flushed'); $this->assertNull(Yii::$app->firstCache->get('secondKey'), 'first cache data should be flushed');
$this->assertEquals('thirdValue', Yii::$app->secondCache->get('thirdKey'), 'second cache data should not be flushed'); $this->assertEquals('thirdValue', Yii::$app->secondCache->get('thirdKey'), 'second cache data should not be flushed');
} }
@ -99,7 +99,7 @@ class CacheControllerTest extends TestCase
$noCacheSchemas = $schema->getTableSchemas('', true); $noCacheSchemas = $schema->getTableSchemas('', true);
$this->assertNotEquals($noCacheSchemas, $cacheSchema, 'Schemas should be different.'); $this->assertNotEquals($noCacheSchemas, $cacheSchema, 'Schemas should be different.');
$this->_cacheController->actionFlushSchema('db'); $this->_cacheController->actionClearSchema('db');
$cacheSchema = $schema->getTableSchemas('', false); $cacheSchema = $schema->getTableSchemas('', false);
$this->assertEquals($noCacheSchemas, $cacheSchema, 'Schema cache should be flushed.'); $this->assertEquals($noCacheSchemas, $cacheSchema, 'Schema cache should be flushed.');
} }
@ -110,18 +110,18 @@ class CacheControllerTest extends TestCase
Yii::$app->firstCache->set('secondKey', 'secondValue'); Yii::$app->firstCache->set('secondKey', 'secondValue');
Yii::$app->secondCache->set('thirdKey', 'secondValue'); Yii::$app->secondCache->set('thirdKey', 'secondValue');
$this->_cacheController->actionFlush('firstCache', 'secondCache'); $this->_cacheController->actionClear('firstCache', 'secondCache');
$this->assertFalse(Yii::$app->firstCache->get('firstKey'), 'first cache data should be flushed'); $this->assertNull(Yii::$app->firstCache->get('firstKey'), 'first cache data should be flushed');
$this->assertFalse(Yii::$app->firstCache->get('secondKey'), 'first cache data should be flushed'); $this->assertNull(Yii::$app->firstCache->get('secondKey'), 'first cache data should be flushed');
$this->assertFalse(Yii::$app->secondCache->get('thirdKey'), 'second cache data should be flushed'); $this->assertNull(Yii::$app->secondCache->get('thirdKey'), 'second cache data should be flushed');
} }
public function testNotFoundFlush() public function testNotFoundFlush()
{ {
Yii::$app->firstCache->set('firstKey', 'firstValue'); Yii::$app->firstCache->set('firstKey', 'firstValue');
$this->_cacheController->actionFlush('notExistingCache'); $this->_cacheController->actionClear('notExistingCache');
$this->assertEquals('firstValue', Yii::$app->firstCache->get('firstKey'), 'first cache data should not be flushed'); $this->assertEquals('firstValue', Yii::$app->firstCache->get('firstKey'), 'first cache data should not be flushed');
} }
@ -131,7 +131,7 @@ class CacheControllerTest extends TestCase
*/ */
public function testNothingToFlushException() public function testNothingToFlushException()
{ {
$this->_cacheController->actionFlush(); $this->_cacheController->actionClear();
} }
public function testFlushAll() public function testFlushAll()
@ -139,9 +139,9 @@ class CacheControllerTest extends TestCase
Yii::$app->firstCache->set('firstKey', 'firstValue'); Yii::$app->firstCache->set('firstKey', 'firstValue');
Yii::$app->secondCache->set('thirdKey', 'secondValue'); Yii::$app->secondCache->set('thirdKey', 'secondValue');
$this->_cacheController->actionFlushAll(); $this->_cacheController->actionClearAll();
$this->assertFalse(Yii::$app->firstCache->get('firstKey'), 'first cache data should be flushed'); $this->assertNull(Yii::$app->firstCache->get('firstKey'), 'first cache data should be flushed');
$this->assertFalse(Yii::$app->secondCache->get('thirdKey'), 'second cache data should be flushed'); $this->assertNull(Yii::$app->secondCache->get('thirdKey'), 'second cache data should be flushed');
} }
} }

6
tests/framework/console/controllers/HelpControllerTest.php

@ -65,9 +65,9 @@ class HelpControllerTest extends TestCase
$result = Console::stripAnsiFormat($this->runControllerAction('list')); $result = Console::stripAnsiFormat($this->runControllerAction('list'));
$this->assertEqualsWithoutLE(<<<'STRING' $this->assertEqualsWithoutLE(<<<'STRING'
cache cache
cache/flush cache/clear
cache/flush-all cache/clear-all
cache/flush-schema cache/clear-schema
cache/index cache/index
help help
help/index help/index

4
tests/framework/db/CommandTest.php

@ -7,6 +7,8 @@
namespace yiiunit\framework\db; namespace yiiunit\framework\db;
use yii\caching\ArrayCache;
use yii\caching\Cache;
use yii\caching\FileCache; use yii\caching\FileCache;
use yii\db\Connection; use yii\db\Connection;
use yii\db\DataReader; use yii\db\DataReader;
@ -861,7 +863,7 @@ SQL;
{ {
$db = $this->getConnection(); $db = $this->getConnection();
$db->enableQueryCache = true; $db->enableQueryCache = true;
$db->queryCache = new FileCache(['cachePath' => '@yiiunit/runtime/cache']); $db->queryCache = new Cache(['handler' => new ArrayCache()]);
$command = $db->createCommand('SELECT [[name]] FROM {{customer}} WHERE [[id]] = :id'); $command = $db->createCommand('SELECT [[name]] FROM {{customer}} WHERE [[id]] = :id');
$this->assertEquals('user1', $command->bindValue(':id', 1)->queryScalar()); $this->assertEquals('user1', $command->bindValue(':id', 1)->queryScalar());

23
tests/framework/filters/PageCacheTest.php

@ -10,6 +10,7 @@ namespace yiiunit\framework\filters;
use Yii; use Yii;
use yii\base\Action; use yii\base\Action;
use yii\caching\ArrayCache; use yii\caching\ArrayCache;
use yii\caching\Cache;
use yii\caching\ExpressionDependency; use yii\caching\ExpressionDependency;
use yii\filters\PageCache; use yii\filters\PageCache;
use yii\helpers\ArrayHelper; use yii\helpers\ArrayHelper;
@ -153,7 +154,7 @@ class PageCacheTest extends TestCase
$controller = new Controller('test', Yii::$app); $controller = new Controller('test', Yii::$app);
$action = new Action('test', $controller); $action = new Action('test', $controller);
$filter = new PageCache(array_merge([ $filter = new PageCache(array_merge([
'cache' => $cache = new ArrayCache(), 'cache' => $cache = new Cache(['handler' => new ArrayCache()]),
'view' => new View(), 'view' => new View(),
], $testCase['properties'])); ], $testCase['properties']));
$this->assertTrue($filter->beforeAction($action), $testCase['name']); $this->assertTrue($filter->beforeAction($action), $testCase['name']);
@ -195,9 +196,9 @@ class PageCacheTest extends TestCase
'statusText' => Yii::$app->response->statusText, 'statusText' => Yii::$app->response->statusText,
]; ];
if ($testCase['cacheable']) { if ($testCase['cacheable']) {
$this->assertNotEmpty($this->getInaccessibleProperty($filter->cache, '_cache'), $testCase['name']); $this->assertNotEmpty($this->getInaccessibleProperty($filter->cache->handler, '_cache'), $testCase['name']);
} else { } else {
$this->assertEmpty($this->getInaccessibleProperty($filter->cache, '_cache'), $testCase['name']); $this->assertEmpty($this->getInaccessibleProperty($filter->cache->handler, '_cache'), $testCase['name']);
return; return;
} }
@ -251,7 +252,7 @@ class PageCacheTest extends TestCase
$controller = new Controller('test', Yii::$app); $controller = new Controller('test', Yii::$app);
$action = new Action('test', $controller); $action = new Action('test', $controller);
$filter = new PageCache([ $filter = new PageCache([
'cache' => $cache = new ArrayCache(), 'cache' => $cache = new Cache(['handler' => new ArrayCache()]),
'view' => new View(), 'view' => new View(),
'duration' => 1, 'duration' => 1,
]); ]);
@ -264,7 +265,7 @@ class PageCacheTest extends TestCase
Yii::$app->response->send(); Yii::$app->response->send();
ob_end_clean(); ob_end_clean();
$this->assertNotEmpty($this->getInaccessibleProperty($filter->cache, '_cache')); $this->assertNotEmpty($this->getInaccessibleProperty($filter->cache->handler, '_cache'));
// mock sleep(2); // mock sleep(2);
CacheTestCase::$time += 2; CacheTestCase::$time += 2;
@ -303,7 +304,7 @@ class PageCacheTest extends TestCase
$action = new Action('test', $controller); $action = new Action('test', $controller);
Yii::$app->requestedRoute = $action->uniqueId; Yii::$app->requestedRoute = $action->uniqueId;
$filter = new PageCache([ $filter = new PageCache([
'cache' => $cache = new ArrayCache(), 'cache' => $cache = new Cache(['handler' => new ArrayCache()]),
'view' => new View(), 'view' => new View(),
'varyByRoute' => $enabled, 'varyByRoute' => $enabled,
]); ]);
@ -316,7 +317,7 @@ class PageCacheTest extends TestCase
Yii::$app->response->send(); Yii::$app->response->send();
ob_end_clean(); ob_end_clean();
$this->assertNotEmpty($this->getInaccessibleProperty($filter->cache, '_cache')); $this->assertNotEmpty($this->getInaccessibleProperty($filter->cache->handler, '_cache'));
// Verifies the cached response // Verifies the cached response
$this->destroyApplication(); $this->destroyApplication();
@ -356,7 +357,7 @@ class PageCacheTest extends TestCase
$originalVariations = $testCases[0]; $originalVariations = $testCases[0];
array_shift($originalVariations); array_shift($originalVariations);
$filter = new PageCache([ $filter = new PageCache([
'cache' => $cache = new ArrayCache(), 'cache' => $cache = new Cache(['handler' => new ArrayCache()]),
'view' => new View(), 'view' => new View(),
'variations' => $originalVariations, 'variations' => $originalVariations,
]); ]);
@ -369,7 +370,7 @@ class PageCacheTest extends TestCase
Yii::$app->response->send(); Yii::$app->response->send();
ob_end_clean(); ob_end_clean();
$this->assertNotEmpty($this->getInaccessibleProperty($filter->cache, '_cache')); $this->assertNotEmpty($this->getInaccessibleProperty($filter->cache->handler, '_cache'));
// Verifies the cached response // Verifies the cached response
$this->destroyApplication(); $this->destroyApplication();
@ -405,7 +406,7 @@ class PageCacheTest extends TestCase
$controller = new Controller('test', Yii::$app); $controller = new Controller('test', Yii::$app);
$action = new Action('test', $controller); $action = new Action('test', $controller);
$filter = new PageCache([ $filter = new PageCache([
'cache' => $cache = new ArrayCache(), 'cache' => $cache = new Cache(['handler' => new ArrayCache()]),
'view' => new View(), 'view' => new View(),
'dependency' => [ 'dependency' => [
'class' => ExpressionDependency::class, 'class' => ExpressionDependency::class,
@ -422,7 +423,7 @@ class PageCacheTest extends TestCase
Yii::$app->response->send(); Yii::$app->response->send();
ob_end_clean(); ob_end_clean();
$this->assertNotEmpty($this->getInaccessibleProperty($filter->cache, '_cache')); $this->assertNotEmpty($this->getInaccessibleProperty($filter->cache->handler, '_cache'));
// Verifies the cached response // Verifies the cached response
$this->destroyApplication(); $this->destroyApplication();

3
tests/framework/rbac/MySQLManagerCacheTest.php

@ -7,6 +7,7 @@
namespace yiiunit\framework\rbac; namespace yiiunit\framework\rbac;
use yii\caching\Cache;
use yii\caching\FileCache; use yii\caching\FileCache;
use yii\rbac\DbManager; use yii\rbac\DbManager;
@ -25,7 +26,7 @@ class MySQLManagerCacheTest extends MySQLManagerTest
{ {
return new DbManager([ return new DbManager([
'db' => $this->getConnection(), 'db' => $this->getConnection(),
'cache' => new FileCache(['cachePath' => '@yiiunit/runtime/cache']), 'cache' => new Cache(['handler' => new FileCache(['cachePath' => '@yiiunit/runtime/cache'])]),
'defaultRoles' => ['myDefaultRole'], 'defaultRoles' => ['myDefaultRole'],
]); ]);
} }

3
tests/framework/rbac/PgSQLManagerCacheTest.php

@ -7,6 +7,7 @@
namespace yiiunit\framework\rbac; namespace yiiunit\framework\rbac;
use yii\caching\Cache;
use yii\caching\FileCache; use yii\caching\FileCache;
use yii\rbac\DbManager; use yii\rbac\DbManager;
@ -27,7 +28,7 @@ class PgSQLManagerCacheTest extends DbManagerTestCase
{ {
return new DbManager([ return new DbManager([
'db' => $this->getConnection(), 'db' => $this->getConnection(),
'cache' => new FileCache(['cachePath' => '@yiiunit/runtime/cache']), 'cache' => new Cache(['handler' => new FileCache(['cachePath' => '@yiiunit/runtime/cache'])]),
'defaultRoles' => ['myDefaultRole'], 'defaultRoles' => ['myDefaultRole'],
]); ]);
} }

5
tests/framework/web/CacheSessionTest.php

@ -8,7 +8,8 @@
namespace yiiunit\framework\web; namespace yiiunit\framework\web;
use Yii; use Yii;
use yii\caching\FileCache; use yii\caching\ArrayCache;
use yii\caching\Cache;
use yii\web\CacheSession; use yii\web\CacheSession;
/** /**
@ -20,7 +21,7 @@ class CacheSessionTest extends \yiiunit\TestCase
{ {
parent::setUp(); parent::setUp();
$this->mockApplication(); $this->mockApplication();
Yii::$app->set('cache', new FileCache()); Yii::$app->set('cache', new Cache(['handler' => new ArrayCache()]));
} }
public function testCacheSession() public function testCacheSession()

4
tests/framework/widgets/FragmentCacheTest.php

@ -10,6 +10,7 @@ namespace yiiunit\framework\widgets;
use Yii; use Yii;
use yii\base\View; use yii\base\View;
use yii\caching\ArrayCache; use yii\caching\ArrayCache;
use yii\caching\Cache;
/** /**
* @group widgets * @group widgets
@ -22,7 +23,8 @@ class FragmentCacheTest extends \yiiunit\TestCase
parent::setUp(); parent::setUp();
$this->mockWebApplication(); $this->mockWebApplication();
Yii::$app->set('cache', [ Yii::$app->set('cache', [
'class' => ArrayCache::class, 'class' => Cache::class,
'handler' => ArrayCache::class,
]); ]);
} }

Loading…
Cancel
Save