Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
Y
yii2
Project
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
PSDI Army
yii2
Commits
392b293d
Commit
392b293d
authored
Mar 25, 2013
by
Qiang Xue
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
FragmentCache WIP
parent
379e48a4
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
137 additions
and
240 deletions
+137
-240
ActionFilter.php
framework/base/ActionFilter.php
+11
-1
View.php
framework/base/View.php
+3
-2
Cache.php
framework/caching/Cache.php
+9
-9
DbDependency.php
framework/caching/DbDependency.php
+20
-17
Command.php
framework/db/Command.php
+7
-1
Schema.php
framework/db/Schema.php
+6
-1
ConsoleColor.php
framework/helpers/ConsoleColor.php
+0
-8
CacheSession.php
framework/web/CacheSession.php
+2
-1
FragmentCache.php
framework/widgets/FragmentCache.php
+79
-200
No files found.
framework/base/ActionFilter.php
View file @
392b293d
...
...
@@ -11,9 +11,19 @@ namespace yii\base;
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class
Filter
extends
Behavior
class
Action
Filter
extends
Behavior
{
/**
* @var array list of action IDs that this filter should apply to. If this property is not set,
* then the filter applies to all actions, unless they are listed in [[except]].
*/
public
$only
;
/**
* @var array list of action IDs that this filter should not apply to.
*/
public
$except
=
array
();
/**
* Declares event handlers for the [[owner]]'s events.
* @return array events (array keys) and the corresponding event handler methods (array values).
*/
...
...
framework/base/View.php
View file @
392b293d
...
...
@@ -337,15 +337,16 @@ class View extends Component
* ~~~
*
* @param string $id a unique ID identifying the fragment to be cached.
* @param array $properties initial property values for [[\yii\widgets\
Outpu
tCache]]
* @param array $properties initial property values for [[\yii\widgets\
Fragmen
tCache]]
* @return boolean whether you should generate the content for caching.
* False if the cached version is available.
*/
public
function
beginCache
(
$id
,
$properties
=
array
())
{
$properties
[
'id'
]
=
$id
;
/** @var $cache \yii\widgets\FragmentCache */
$cache
=
$this
->
beginWidget
(
'yii\widgets\OutputCache'
,
$properties
);
if
(
$cache
->
get
IsContentCached
()
)
{
if
(
$cache
->
get
CachedContent
()
!==
false
)
{
$this
->
endCache
();
return
false
;
}
else
{
...
...
framework/caching/Cache.php
View file @
392b293d
...
...
@@ -8,6 +8,7 @@
namespace
yii\caching
;
use
yii\base\Component
;
use
yii\helpers\StringHelper
;
/**
* Cache is the base class for cache classes supporting different cache storage implementation.
...
...
@@ -70,13 +71,13 @@ abstract class Cache extends Component implements \ArrayAccess
/**
* Builds a normalized cache key from
one or multiple parameters
.
* Builds a normalized cache key from
a given key
.
*
* The generated key contains letters and digits only, and its length is no more than 32.
*
* If
only one parameter is given and it is already a normalized key, then
*
it
will be returned back without change. Otherwise, a normalized key
* is generated by serializing
all given parameters and applying MD5 hashing.
* If
the given key is a string containing alphanumeric characters only and no more than 32 characters,
*
then the key
will be returned back without change. Otherwise, a normalized key
* is generated by serializing
the given key and applying MD5 hashing.
*
* The following example builds a cache key using three parameters:
*
...
...
@@ -84,16 +85,15 @@ abstract class Cache extends Component implements \ArrayAccess
* $key = $cache->buildKey($className, $method, $id);
* ~~~
*
* @param
string $key the first parameter
* @param
array|string $key the key to be normalized
* @return string the generated cache key
*/
public
function
buildKey
(
$key
)
{
if
(
func_num_args
()
===
1
&&
ctype_alnum
(
$key
)
&&
strlen
(
$key
)
<=
32
)
{
return
(
string
)
$key
;
if
(
is_string
(
$key
)
)
{
return
ctype_alnum
(
$key
)
&&
StringHelper
::
strlen
(
$key
)
<=
32
?
$key
:
md5
(
$key
)
;
}
else
{
$params
=
func_get_args
();
return
md5
(
json_encode
(
$params
));
return
md5
(
json_encode
(
$key
));
}
}
...
...
framework/caching/DbDependency.php
View file @
392b293d
...
...
@@ -7,15 +7,15 @@
namespace
yii\caching
;
use
Yii
;
use
yii\base\InvalidConfigException
;
use
yii\db\Connection
;
use
yii\db\Query
;
/**
* DbDependency represents a dependency based on the query result of a SQL statement.
*
* If the query result changes, the dependency is considered as changed.
* The query is specified via the [[
query
]] property.
* The query is specified via the [[
sql
]] property.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
...
...
@@ -27,23 +27,25 @@ class DbDependency extends Dependency
*/
public
$connectionID
=
'db'
;
/**
* @var
Query
the SQL query whose result is used to determine if the dependency has been changed.
* @var
string
the SQL query whose result is used to determine if the dependency has been changed.
* Only the first row of the query result will be used.
*/
public
$
query
;
public
$
sql
;
/**
* @var
Connection the DB connection instance
* @var
array the parameters (name=>value) to be bound to the SQL statement specified by [[sql]].
*/
p
rivate
$_db
;
p
ublic
$params
;
/**
* Constructor.
* @param Query $query the SQL query whose result is used to determine if the dependency has been changed.
* @param string $sql the SQL query whose result is used to determine if the dependency has been changed.
* @param array $params the parameters (name=>value) to be bound to the SQL statement specified by [[sql]].
* @param array $config name-value pairs that will be used to initialize the object properties
*/
public
function
__construct
(
$
query
=
null
,
$config
=
array
())
public
function
__construct
(
$
sql
,
$params
=
array
()
,
$config
=
array
())
{
$this
->
query
=
$query
;
$this
->
sql
=
$sql
;
$this
->
params
=
$params
;
parent
::
__construct
(
$config
);
}
...
...
@@ -66,22 +68,23 @@ class DbDependency extends Dependency
protected
function
generateDependencyData
()
{
$db
=
$this
->
getDb
();
/**
* @var \yii\db\Command $command
*/
$command
=
$this
->
query
->
createCommand
(
$db
);
if
(
$db
->
enableQueryCache
)
{
// temporarily disable and re-enable query caching
$db
->
enableQueryCache
=
false
;
$result
=
$
command
->
queryRow
();
$result
=
$
db
->
createCommand
(
$this
->
sql
,
$this
->
params
)
->
queryRow
();
$db
->
enableQueryCache
=
true
;
}
else
{
$result
=
$
command
->
queryRow
();
$result
=
$
db
->
createCommand
(
$this
->
sql
,
$this
->
params
)
->
queryRow
();
}
return
$result
;
}
/**
* @var Connection the DB connection instance
*/
private
$_db
;
/**
* Returns the DB connection instance used for caching purpose.
* @return Connection the DB connection instance
* @throws InvalidConfigException if [[connectionID]] does not point to a valid application component.
...
...
@@ -89,11 +92,11 @@ class DbDependency extends Dependency
public
function
getDb
()
{
if
(
$this
->
_db
===
null
)
{
$db
=
\
Yii
::
$app
->
getComponent
(
$this
->
connectionID
);
$db
=
Yii
::
$app
->
getComponent
(
$this
->
connectionID
);
if
(
$db
instanceof
Connection
)
{
$this
->
_db
=
$db
;
}
else
{
throw
new
InvalidConfigException
(
"DbCache::connectionID must refer to the ID of a DB application component."
);
throw
new
InvalidConfigException
(
"DbCache
Dependency
::connectionID must refer to the ID of a DB application component."
);
}
}
return
$this
->
_db
;
...
...
framework/db/Command.php
View file @
392b293d
...
...
@@ -389,7 +389,13 @@ class Command extends \yii\base\Component
}
if
(
isset
(
$cache
))
{
$cacheKey
=
$cache
->
buildKey
(
__CLASS__
,
$db
->
dsn
,
$db
->
username
,
$sql
,
$paramLog
);
$cacheKey
=
$cache
->
buildKey
(
array
(
__CLASS__
,
$db
->
dsn
,
$db
->
username
,
$sql
,
$paramLog
,
));
if
((
$result
=
$cache
->
get
(
$cacheKey
))
!==
false
)
{
\Yii
::
trace
(
'Query result found in cache'
,
__CLASS__
);
return
$result
;
...
...
framework/db/Schema.php
View file @
392b293d
...
...
@@ -109,7 +109,12 @@ abstract class Schema extends \yii\base\Object
*/
public
function
getCacheKey
(
$cache
,
$name
)
{
return
$cache
->
buildKey
(
__CLASS__
,
$this
->
db
->
dsn
,
$this
->
db
->
username
,
$name
);
return
$cache
->
buildKey
(
array
(
__CLASS__
,
$this
->
db
->
dsn
,
$this
->
db
->
username
,
$name
,
));
}
/**
...
...
framework/helpers/ConsoleColor.php
View file @
392b293d
...
...
@@ -7,15 +7,7 @@
namespace
yii\helpers
;
// todo define how subclassing will work
// todo add a run() or render() method
// todo test this on all kinds of terminals, especially windows (check out lib ncurses)
// todo not sure if all methods should be static
// todo subclass DetailView
// todo subclass GridView
// todo more subclasses
/**
* Console View is the base class for console view components
...
...
framework/web/CacheSession.php
View file @
392b293d
...
...
@@ -45,6 +45,7 @@ class CacheSession extends Session
{
return
true
;
}
/**
* Returns the cache instance used for storing session data.
* @return Cache the cache instance
...
...
@@ -114,6 +115,6 @@ class CacheSession extends Session
*/
protected
function
calculateKey
(
$id
)
{
return
$this
->
getCache
()
->
buildKey
(
__CLASS__
,
$id
);
return
$this
->
getCache
()
->
buildKey
(
array
(
__CLASS__
,
$id
)
);
}
}
framework/widgets/FragmentCache.php
View file @
392b293d
...
...
@@ -7,7 +7,11 @@
namespace
yii\widgets
;
use
Yii
;
use
yii\base\InvalidConfigException
;
use
yii\base\Widget
;
use
yii\caching\Cache
;
use
yii\caching\Dependency
;
/**
* @author Qiang Xue <qiang.xue@gmail.com>
...
...
@@ -16,81 +20,47 @@ use yii\base\Widget;
class
FragmentCache
extends
Widget
{
/**
* Prefix to the keys for storing cached data
*/
const
CACHE_KEY_PREFIX
=
'Yii.COutputCache.'
;
/**
* @var string the ID of the cache application component. Defaults to 'cache' (the primary cache application component.)
*/
public
$cacheID
=
'cache'
;
/**
* @var integer number of seconds that the data can remain in cache. Defaults to 60 seconds.
* If it is 0, existing cached content would be removed from the cache.
* If it is a negative value, the cache will be disabled (any existing cached content will
* remain in the cache.)
*
* Note, if cache dependency changes or cache space is limited,
* the data may be purged out of cache earlier.
* @var integer number of seconds that the data can remain valid in cache.
* Use 0 to indicate that the cached data will never expire.
*/
public
$duration
=
60
;
/**
* @var mixed the dependency that the cached content depends on.
* This can be either an object implementing {@link ICacheDependency} interface or an array
* specifying the configuration of the dependency object. For example,
* <pre>
* @var array|Dependency the dependency that the cached content depends on.
* This can be either a [[Dependency]] object or a configuration array for creating the dependency object.
* For example,
*
* ~~~
* array(
* 'class'
=>'CDbCache
Dependency',
* 'sql'
=>
'SELECT MAX(lastModified) FROM Post',
* 'class'
=> 'yii\caching\Db
Dependency',
* 'sql'
=>
'SELECT MAX(lastModified) FROM Post',
* )
* </pre>
* ~~~
*
* would make the output cache depends on the last modified time of all posts.
* If any post has its modification time changed, the cached content would be invalidated.
*/
public
$dependency
;
/**
* @var boolean whether the content being cached should be differentiated according to route.
* A route consists of the requested controller ID and action ID.
* Defaults to true.
*/
public
$varyByRoute
=
true
;
/**
* @var boolean whether the content being cached should be differentiated according to user's language.
* A language is retrieved via Yii::app()->language.
* Defaults to false.
* @since 1.1.14
*/
public
$varyByLanguage
=
false
;
/**
* @var array list of GET parameters that should participate in cache key calculation.
* By setting this property, the output cache will use different cached data
* for each different set of GET parameter values.
*/
public
$varyByParam
;
/**
* @var string a PHP expression whose result is used in the cache key calculation.
* By setting this property, the output cache will use different cached data
* for each different expression result.
* The expression can also be a valid PHP callback,
* including class method name (array(ClassName/Object, MethodName)),
* or anonymous function (PHP 5.3.0+). The function/method signature should be as follows:
* <pre>
* function foo($cache) { ... }
* </pre>
* where $cache refers to the output cache component.
* @var array list of factors that would cause the variation of the content being cached.
* Each factor is a string representing a variation (e.g. the language, a GET parameter).
* The following variation setting will cause the content to be cached in different versions
* according to the current application language:
*
* ~~~
* array(
* Yii::$app->language,
* )
*/
public
$var
yByExpression
;
public
$var
iations
;
/**
* @var
array list of request types (e.g. GET, POST) for which the cache should be enabled only.
*
Defaults to null, meaning all request types
.
* @var
boolean whether to enable the fragment cache. You may use this property to turn on and off
*
the fragment cache according to specific setting (e.g. enable fragment cache only for GET requests)
.
*/
public
$requestTypes
;
private
$_key
;
private
$_cache
;
private
$_contentCached
;
private
$_content
;
private
$_actions
;
public
$enabled
=
true
;
/**
* Marks the start of content to be cached.
...
...
@@ -100,10 +70,7 @@ class FragmentCache extends Widget
*/
public
function
init
()
{
if
(
$this
->
getIsContentCached
())
{
$this
->
replayActions
();
}
elseif
(
$this
->
_cache
!==
null
)
{
$this
->
getController
()
->
getCachingStack
()
->
push
(
$this
);
if
(
$this
->
getCachedContent
()
===
false
&&
$this
->
getCache
()
!==
null
)
{
ob_start
();
ob_implicit_flush
(
false
);
}
...
...
@@ -117,178 +84,89 @@ class FragmentCache extends Widget
*/
public
function
run
()
{
if
(
$this
->
getIsContentCached
())
{
if
(
$this
->
getController
()
->
isCachingStackEmpty
())
{
echo
$this
->
getController
()
->
processDynamicOutput
(
$this
->
_content
);
}
else
{
echo
$this
->
_content
;
}
}
elseif
(
$this
->
_cache
!==
null
)
{
$this
->
_content
=
ob_get_clean
();
$this
->
getController
()
->
getCachingStack
()
->
pop
();
$data
=
array
(
$this
->
_content
,
$this
->
_actions
);
if
((
$content
=
$this
->
getCachedContent
())
!==
false
)
{
echo
$content
;
}
elseif
((
$cache
=
$this
->
getCache
())
!==
false
)
{
$content
=
ob_get_clean
();
if
(
is_array
(
$this
->
dependency
))
{
$this
->
dependency
=
Yii
::
createComponent
(
$this
->
dependency
);
}
$this
->
_cache
->
set
(
$this
->
getCacheKey
(),
$data
,
$this
->
duration
,
$this
->
dependency
);
if
(
$this
->
getController
()
->
isCachingStackEmpty
())
{
echo
$this
->
getController
()
->
processDynamicOutput
(
$this
->
_content
);
}
else
{
echo
$this
->
_content
;
$this
->
dependency
=
Yii
::
createObject
(
$this
->
dependency
);
}
$cache
->
set
(
$this
->
calculateKey
(),
$content
,
$this
->
duration
,
$this
->
dependency
);
echo
$content
;
}
}
/**
* @
return boolean whether the content can be found from cache
* @
var string|boolean the cached content. False if the content is not cached.
*/
public
function
getIsContentCached
()
{
if
(
$this
->
_contentCached
!==
null
)
{
return
$this
->
_contentCached
;
}
else
{
return
$this
->
_contentCached
=
$this
->
checkContentCache
();
}
}
private
$_content
;
/**
*
Looks for content in cach
e.
* @return
boolean whether the content is found in
cache.
*
Returns the cached content if availabl
e.
* @return
string|boolean the cached content. False is returned if valid content is not found in the
cache.
*/
p
rotected
function
checkContentCache
()
p
ublic
function
getCachedContent
()
{
if
((
empty
(
$this
->
requestTypes
)
||
in_array
(
Yii
::
app
()
->
getRequest
()
->
getRequestType
(),
$this
->
requestTypes
))
&&
(
$this
->
_cache
=
$this
->
getCache
())
!==
null
)
{
if
(
$this
->
duration
>
0
&&
(
$data
=
$this
->
_cache
->
get
(
$this
->
getCacheKey
()))
!==
false
)
{
$this
->
_content
=
$data
[
0
];
$this
->
_actions
=
$data
[
1
];
return
true
;
}
if
(
$this
->
duration
==
0
)
{
$this
->
_cache
->
delete
(
$this
->
getCacheKey
());
}
if
(
$this
->
duration
<=
0
)
{
$this
->
_cache
=
null
;
if
(
$this
->
_content
===
null
)
{
if
((
$cache
=
$this
->
getCache
())
!==
null
)
{
$key
=
$this
->
calculateKey
();
$this
->
_content
=
$cache
->
get
(
$key
);
}
else
{
$this
->
_content
=
false
;
}
}
return
false
;
return
$this
->
_content
;
}
/**
* @return ICache the cache used for caching the content.
* Generates a unique key used for storing the content in cache.
* The key generated depends on both [[id]] and [[variations]].
* @return string a valid cache key
*/
protected
function
getCache
()
protected
function
calculateKey
()
{
return
Yii
::
app
()
->
getComponent
(
$this
->
cacheID
);
$factors
=
array
(
__CLASS__
,
$this
->
getId
());
if
(
is_array
(
$this
->
variations
))
{
foreach
(
$this
->
variations
as
$factor
)
{
$factors
[]
=
$factor
;
}
}
return
$this
->
getCache
()
->
buildKey
(
$factors
);
}
/**
* Caclulates the base cache key.
* The calculated key will be further variated in {@link getCacheKey}.
* Derived classes may override this method if more variations are needed.
* @return string basic cache key without variations
* @var Cache
*/
protected
function
getBaseCacheKey
()
{
return
self
::
CACHE_KEY_PREFIX
.
$this
->
getId
()
.
'.'
;
}
private
$_cache
;
/**
*
Calculates the cache key
.
*
The key is calculated based on {@link getBaseCacheKey} and other factors, including
*
{@link varyByRoute}, {@link varyByParam}, {@link varyBySession} and {@link varyByLanguage}
.
* @
return string cache key
*
Returns the cache instance used for storing content
.
*
@return Cache the cache instance. Null is returned if the cache component is not available
*
or [[enabled]] is false
.
* @
throws InvalidConfigException if [[cacheID]] does not point to a valid application component.
*/
p
rotected
function
getCacheKey
()
p
ublic
function
getCache
()
{
if
(
$this
->
_key
!==
null
)
{
return
$this
->
_key
;
}
else
{
$key
=
$this
->
getBaseCacheKey
()
.
'.'
;
if
(
$this
->
varyByRoute
)
{
$controller
=
$this
->
getController
();
$key
.=
$controller
->
getUniqueId
()
.
'/'
;
if
((
$action
=
$controller
->
getAction
())
!==
null
)
{
$key
.=
$action
->
getId
();
}
if
(
!
$this
->
enabled
)
{
return
null
;
}
$key
.=
'.'
;
if
(
$this
->
varyBySession
)
{
$key
.=
Yii
::
app
()
->
getSession
()
->
getSessionID
();
}
$key
.=
'.'
;
if
(
is_array
(
$this
->
varyByParam
)
&&
isset
(
$this
->
varyByParam
[
0
]))
{
$params
=
array
();
foreach
(
$this
->
varyByParam
as
$name
)
{
if
(
isset
(
$_GET
[
$name
]))
{
$params
[
$name
]
=
$_GET
[
$name
];
if
(
$this
->
_cache
===
null
)
{
$cache
=
Yii
::
$app
->
getComponent
(
$this
->
cacheID
);
if
(
$cache
instanceof
Cache
)
{
$this
->
_cache
=
$cache
;
}
else
{
$params
[
$name
]
=
''
;
}
throw
new
InvalidConfigException
(
'FragmentCache::cacheID must refer to the ID of a cache application component.'
);
}
$key
.=
serialize
(
$params
);
}
$key
.=
'.'
;
if
(
$this
->
varyByExpression
!==
null
)
{
$key
.=
$this
->
evaluateExpression
(
$this
->
varyByExpression
);
}
$key
.=
'.'
;
if
(
$this
->
varyByLanguage
)
{
$key
.=
Yii
::
app
()
->
language
;
}
$key
.=
'.'
;
return
$this
->
_key
=
$key
;
}
}
/**
* Records a method call when this output cache is in effect.
* When the content is served from the output cache, the recorded
* method will be re-invoked.
* @param string $context a property name of the controller. The property should refer to an object
* whose method is being recorded. If empty it means the controller itself.
* @param string $method the method name
* @param array $params parameters passed to the method
*/
public
function
recordAction
(
$context
,
$method
,
$params
)
{
$this
->
_actions
[]
=
array
(
$context
,
$method
,
$params
);
return
$this
->
_cache
;
}
/**
* Replays the recorded method calls.
* Sets the cache instance used by the session component.
* @param Cache $value the cache instance
*/
p
rotected
function
replayActions
(
)
p
ublic
function
setCache
(
$value
)
{
if
(
empty
(
$this
->
_actions
))
{
return
;
}
$controller
=
$this
->
getController
();
$cs
=
Yii
::
app
()
->
getClientScript
();
foreach
(
$this
->
_actions
as
$action
)
{
if
(
$action
[
0
]
===
'clientScript'
)
{
$object
=
$cs
;
}
elseif
(
$action
[
0
]
===
''
)
{
$object
=
$controller
;
}
else
{
$object
=
$controller
->
{
$action
[
0
]};
}
if
(
method_exists
(
$object
,
$action
[
1
]))
{
call_user_func_array
(
array
(
$object
,
$action
[
1
]),
$action
[
2
]);
}
elseif
(
$action
[
0
]
===
''
&&
function_exists
(
$action
[
1
]))
{
call_user_func_array
(
$action
[
1
],
$action
[
2
]);
}
else
{
throw
new
CException
(
Yii
::
t
(
'yii'
,
'Unable to replay the action "{object}.{method}". The method does not exist.'
,
array
(
'object'
=>
$action
[
0
],
'method'
=>
$action
[
1
])));
}
}
$this
->
_cache
=
$value
;
}
}
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment