From 7aef563dd530636abacedf84088231310c7c7cce Mon Sep 17 00:00:00 2001 From: resurtm Date: Mon, 24 Jun 2013 22:30:50 +0600 Subject: [PATCH 01/16] Proposed mutex extension. --- extensions/mutex/Mutex.php | 76 +++++++++++++++++++++++++++++++++++++ extensions/mutex/db/Mutex.php | 29 ++++++++++++++ extensions/mutex/db/mssql/Mutex.php | 28 ++++++++++++++ extensions/mutex/db/mysql/Mutex.php | 38 +++++++++++++++++++ extensions/mutex/unix/Mutex.php | 59 ++++++++++++++++++++++++++++ 5 files changed, 230 insertions(+) create mode 100644 extensions/mutex/Mutex.php create mode 100644 extensions/mutex/db/Mutex.php create mode 100644 extensions/mutex/db/mssql/Mutex.php create mode 100644 extensions/mutex/db/mysql/Mutex.php create mode 100644 extensions/mutex/unix/Mutex.php diff --git a/extensions/mutex/Mutex.php b/extensions/mutex/Mutex.php new file mode 100644 index 0000000..876bc2b --- /dev/null +++ b/extensions/mutex/Mutex.php @@ -0,0 +1,76 @@ +autoRelease) { + register_shutdown_function(array($this, 'shutdownFunction')); + } + } + + /** + * NEVER CALL THIS METHOD UNDER ANY CIRCUMSTANCES + */ + public function shutdownFunction() + { + foreach ($this->_locks as $lock) { + $this->release($lock); + } + } + + public function acquireLock($name, $timeout = 0) + { + if ($this->acquire($name, $timeout)) { + $this->_locks[] = $name; + return true; + } else { + return false; + } + } + + public function releaseLock($name) + { + if ($this->release($name)) { + unset($this->_locks[array_search($name, $this->_locks)]); + return true; + } else { + return false; + } + } + + public function getIsLockAcquired($name) + { + if (in_array($name, $this->_locks)) { + return true; + } else { + return $this->getIsAcquired($name); + } + } + + public function getIsLockLocal($name) + { + return in_array($name, $this->_locks); + } + + abstract protected function acquire($name, $timeout = 0); + + abstract protected function release($name); + + protected function getIsAcquired($name) + { + return null; + } + + abstract public function getIsDistributed(); +} diff --git a/extensions/mutex/db/Mutex.php b/extensions/mutex/db/Mutex.php new file mode 100644 index 0000000..2fae641 --- /dev/null +++ b/extensions/mutex/db/Mutex.php @@ -0,0 +1,29 @@ +db = Yii::$app->getComponent($this->db); + if (!$this->db instanceof Connection) { + throw new InvalidConfigException(''); + } + } + + public function getIsDistributed() + { + return true; + } +} diff --git a/extensions/mutex/db/mssql/Mutex.php b/extensions/mutex/db/mssql/Mutex.php new file mode 100644 index 0000000..0b67305 --- /dev/null +++ b/extensions/mutex/db/mssql/Mutex.php @@ -0,0 +1,28 @@ +db->driverName; + if ($driverName !== 'sqlsrv' && $driverName !== 'dblib' && $driverName !== 'mssql') { + throw new InvalidConfigException(''); + } + } + + protected function acquire($name, $timeout = 0) + { + // http://msdn.microsoft.com/en-us/library/ms189823.aspx + } + + protected function release($name) + { + // http://msdn.microsoft.com/en-us/library/ms178602.aspx + } +} diff --git a/extensions/mutex/db/mysql/Mutex.php b/extensions/mutex/db/mysql/Mutex.php new file mode 100644 index 0000000..07ab7e2 --- /dev/null +++ b/extensions/mutex/db/mysql/Mutex.php @@ -0,0 +1,38 @@ +db->driverName !== 'mysql') { + throw new InvalidConfigException(''); + } + } + + protected function acquire($name, $timeout = 0) + { + return (boolean)$this->db + ->createCommand('SELECT GET_LOCK(:name, :timeout)', array(':name' => $name, ':timeout' => $timeout)) + ->queryScalar(); + } + + protected function release($name) + { + return (boolean)$this->db + ->createCommand('SELECT RELEASE_LOCK(:name)', array(':name' => $name)) + ->queryScalar(); + } + + protected function getIsAcquired($name) + { + return (boolean)$this->db + ->createCommand('SELECT IS_FREE_LOCK(:name)', array(':name' => $name)) + ->queryScalar(); + } +} diff --git a/extensions/mutex/unix/Mutex.php b/extensions/mutex/unix/Mutex.php new file mode 100644 index 0000000..3e3d530 --- /dev/null +++ b/extensions/mutex/unix/Mutex.php @@ -0,0 +1,59 @@ +getRuntimePath() . '/mutex.' . md5($name) . '.lock', 'w+'); + if ($file === false) { + return false; + } + $waitTime = 0; + while (!flock($file, LOCK_EX | LOCK_NB)) { + $waitTime++; + if ($waitTime > $timeout) { + fclose($file); + return false; + } + sleep(1); + } + $this->_files[$name] = $file; + return true; + } + + protected function release($name) + { + if (!isset($this->_files[$name]) || !flock($this->_files[$name], LOCK_UN)) { + return false; + } else { + fclose($this->_files[$name]); + unset($this->_files[$name]); + return true; + } + } + + protected function getIsAcquired($name) + { + return false; + } + + public function getIsDistributed() + { + return false; + } +} From dd48e8a71b1f35f505c2876697f6893d7c27b3d8 Mon Sep 17 00:00:00 2001 From: resurtm Date: Mon, 24 Jun 2013 22:34:40 +0600 Subject: [PATCH 02/16] Uncomment UNIX Mutex. --- extensions/mutex/unix/Mutex.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/extensions/mutex/unix/Mutex.php b/extensions/mutex/unix/Mutex.php index 3e3d530..c95baa8 100644 --- a/extensions/mutex/unix/Mutex.php +++ b/extensions/mutex/unix/Mutex.php @@ -12,9 +12,9 @@ class Mutex extends \yii\mutex\Mutex public function init() { -// if (stripos(php_uname('s'), 'win') === 0) { -// throw new InvalidConfigException(''); -// } + if (stripos(php_uname('s'), 'win') === 0) { + throw new InvalidConfigException(''); + } } protected function acquire($name, $timeout = 0) From 421e2eb960a13cfb95fa70a1d2afc17a28e12749 Mon Sep 17 00:00:00 2001 From: resurtm Date: Mon, 24 Jun 2013 23:34:57 +0600 Subject: [PATCH 03/16] Mutex extension docblocks and several minor fixes. --- extensions/mutex/Mutex.php | 68 +++++++++++++++++++++++++++++++++++-- extensions/mutex/db/Mutex.php | 28 +++++++++++++-- extensions/mutex/db/mssql/Mutex.php | 32 +++++++++++++++-- extensions/mutex/db/mysql/Mutex.php | 34 +++++++++++++++++++ extensions/mutex/unix/Mutex.php | 40 ++++++++++++++++++++++ 5 files changed, 195 insertions(+), 7 deletions(-) diff --git a/extensions/mutex/Mutex.php b/extensions/mutex/Mutex.php index 876bc2b..5268d86 100644 --- a/extensions/mutex/Mutex.php +++ b/extensions/mutex/Mutex.php @@ -1,17 +1,35 @@ + * @since 2.0 + */ abstract class Mutex extends Component { + /** + * @var boolean whether all locks acquired in this process (i.e. local locks) must be released automagically + * before finishing script execution. Defaults to true. Setting this property to true + */ public $autoRelease = true; - + /** + * @var string[] names of the locks acquired in the current PHP process. + */ private $_locks = array(); + /** + * Initializes the mutex component. + */ public function init() { if ($this->autoRelease) { @@ -20,7 +38,7 @@ abstract class Mutex extends Component } /** - * NEVER CALL THIS METHOD UNDER ANY CIRCUMSTANCES + * Never call this method directly under any circumstances. This method is intended for internal use only. */ public function shutdownFunction() { @@ -29,6 +47,12 @@ abstract class Mutex extends Component } } + /** + * @param string $name of the lock to be acquired. Must be unique. + * @param integer $timeout to wait for lock to be released. Defaults to zero meaning that method will return + * false immediately in case lock was already acquired. + * @return boolean lock acquiring result. + */ public function acquireLock($name, $timeout = 0) { if ($this->acquire($name, $timeout)) { @@ -39,6 +63,11 @@ abstract class Mutex extends Component } } + /** + * Release acquired lock. + * @param string $name of the lock to be released. This lock must be already created. + * @return boolean lock release result. + */ public function releaseLock($name) { if ($this->release($name)) { @@ -49,6 +78,12 @@ abstract class Mutex extends Component } } + /** + * Checks whether named lock was already opened. + * @param string $name of the lock to be checked. This lock must be already created. + * @return boolean|null whether named lock was already opened. Returns `null` value in case concrete + * mutex implementation does not support this operation. + */ public function getIsLockAcquired($name) { if (in_array($name, $this->_locks)) { @@ -58,19 +93,48 @@ abstract class Mutex extends Component } } + /** + * Checks whether given lock is local. In other words local lock means that it was opened in the current + * PHP process. + * @param string $name of the lock to be checked. This lock must be already created. + * @return boolean whether named lock was locally acquired. + */ public function getIsLockLocal($name) { return in_array($name, $this->_locks); } + /** + * This method should be extended by concrete mutex implementations. Acquires lock by given name. + * @param string $name of the lock to be acquired. + * @param integer $timeout to wait for lock to become released. + * @return boolean acquiring result. + */ abstract protected function acquire($name, $timeout = 0); + /** + * This method should be extended by concrete mutex implementations. Releases lock by given name. + * @param string $name of the lock to be released. + * @return boolean release result. + */ abstract protected function release($name); + /** + * This method may optionally be extended by concrete mutex implementations. Checks whether lock has been + * already acquired by given name. + * @param string $name of the lock to be released. + * @return null|boolean whether lock has been already acquired. Returns `null` in case this feature + * is not supported by concrete mutex implementation. + */ protected function getIsAcquired($name) { return null; } + /** + * This method should be extended by concrete mutex implementations. Returns whether current mutex + * implementation can be used in a distributed environment. + * @return boolean whether current mutex implementation can be used in a distributed environment. + */ abstract public function getIsDistributed(); } diff --git a/extensions/mutex/db/Mutex.php b/extensions/mutex/db/Mutex.php index 2fae641..17dd68a 100644 --- a/extensions/mutex/db/Mutex.php +++ b/extensions/mutex/db/Mutex.php @@ -1,4 +1,9 @@ + * @since 2.0 + */ abstract class Mutex extends \yii\mutex\Mutex { /** - * @var string|Connection + * @var Connection|string the DB connection object or the application component ID of the DB connection. + * After the Mutex object is created, if you want to change this property, you should only assign + * it with a DB connection object. */ public $db = 'db'; + /** + * Initializes generic database table based mutex implementation. + * @throws InvalidConfigException if [[db]] is invalid. + */ public function init() { parent::init(); - $this->db = Yii::$app->getComponent($this->db); + if (is_string($this->db)) { + $this->db = Yii::$app->getComponent($this->db); + } if (!$this->db instanceof Connection) { - throw new InvalidConfigException(''); + throw new InvalidConfigException('Mutex::db must be either a DB connection instance or the application component ID of a DB connection.'); } } + /** + * This method should be extended by concrete mutex implementations. Returns whether current mutex + * implementation can be used in a distributed environment. + * @return boolean whether current mutex implementation can be used in a distributed environment. + */ public function getIsDistributed() { return true; diff --git a/extensions/mutex/db/mssql/Mutex.php b/extensions/mutex/db/mssql/Mutex.php index 0b67305..374100a 100644 --- a/extensions/mutex/db/mssql/Mutex.php +++ b/extensions/mutex/db/mssql/Mutex.php @@ -1,12 +1,25 @@ + * @since 2.0 + */ class Mutex extends \yii\mutex\db\Mutex { + /** + * Initializes Microsoft SQL Server specific mutex component implementation. + * @throws InvalidConfigException if [[db]] is not Microsoft SQL Server connection. + */ public function init() { parent::init(); @@ -16,13 +29,28 @@ class Mutex extends \yii\mutex\db\Mutex } } + /** + * This method should be extended by concrete mutex implementations. Acquires lock by given name. + * @param string $name of the lock to be acquired. + * @param integer $timeout to wait for lock to become released. + * @return boolean acquiring result. + * @throws \BadMethodCallException + * @see http://msdn.microsoft.com/en-us/library/ms189823.aspx + */ protected function acquire($name, $timeout = 0) { - // http://msdn.microsoft.com/en-us/library/ms189823.aspx + throw new \BadMethodCallException('Not implemented yet.'); } + /** + * This method should be extended by concrete mutex implementations. Releases lock by given name. + * @param string $name of the lock to be released. + * @return boolean release result. + * @throws \BadMethodCallException + * @see http://msdn.microsoft.com/en-us/library/ms178602.aspx + */ protected function release($name) { - // http://msdn.microsoft.com/en-us/library/ms178602.aspx + throw new \BadMethodCallException('Not implemented yet.'); } } diff --git a/extensions/mutex/db/mysql/Mutex.php b/extensions/mutex/db/mysql/Mutex.php index 07ab7e2..7153d38 100644 --- a/extensions/mutex/db/mysql/Mutex.php +++ b/extensions/mutex/db/mysql/Mutex.php @@ -1,12 +1,25 @@ + * @since 2.0 + */ class Mutex extends \yii\mutex\db\Mutex { + /** + * Initializes MySQL specific mutex component implementation. + * @throws InvalidConfigException if [[db]] is not MySQL connection. + */ public function init() { parent::init(); @@ -15,6 +28,13 @@ class Mutex extends \yii\mutex\db\Mutex } } + /** + * This method should be extended by concrete mutex implementations. Acquires lock by given name. + * @param string $name of the lock to be acquired. + * @param integer $timeout to wait for lock to become released. + * @return boolean acquiring result. + * @see http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_get-lock + */ protected function acquire($name, $timeout = 0) { return (boolean)$this->db @@ -22,6 +42,12 @@ class Mutex extends \yii\mutex\db\Mutex ->queryScalar(); } + /** + * This method should be extended by concrete mutex implementations. Releases lock by given name. + * @param string $name of the lock to be released. + * @return boolean release result. + * @see http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_release-lock + */ protected function release($name) { return (boolean)$this->db @@ -29,6 +55,14 @@ class Mutex extends \yii\mutex\db\Mutex ->queryScalar(); } + /** + * This method may optionally be extended by concrete mutex implementations. Checks whether lock has been + * already acquired by given name. + * @param string $name of the lock to be released. + * @return null|boolean whether lock has been already acquired. Returns `null` in case this feature + * is not supported by concrete mutex implementation. + * @see http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_is-free-lock + */ protected function getIsAcquired($name) { return (boolean)$this->db diff --git a/extensions/mutex/unix/Mutex.php b/extensions/mutex/unix/Mutex.php index c95baa8..ca18a49 100644 --- a/extensions/mutex/unix/Mutex.php +++ b/extensions/mutex/unix/Mutex.php @@ -1,15 +1,32 @@ + * @since 2.0 + */ class Mutex extends \yii\mutex\Mutex { + /** + * @var resource[] stores all opened lock files. Keys are lock names and values are file handles. + */ private $_files = array(); + /** + * Initializes mutex component implementation dedicated for UNIX, GNU/Linux, Mac OS X, and other UNIX-like + * operating systems. + * @throws InvalidConfigException + */ public function init() { if (stripos(php_uname('s'), 'win') === 0) { @@ -17,6 +34,12 @@ class Mutex extends \yii\mutex\Mutex } } + /** + * This method should be extended by concrete mutex implementations. Acquires lock by given name. + * @param string $name of the lock to be acquired. + * @param integer $timeout to wait for lock to become released. + * @return boolean acquiring result. + */ protected function acquire($name, $timeout = 0) { $file = fopen(Yii::$app->getRuntimePath() . '/mutex.' . md5($name) . '.lock', 'w+'); @@ -36,6 +59,11 @@ class Mutex extends \yii\mutex\Mutex return true; } + /** + * This method should be extended by concrete mutex implementations. Releases lock by given name. + * @param string $name of the lock to be released. + * @return boolean release result. + */ protected function release($name) { if (!isset($this->_files[$name]) || !flock($this->_files[$name], LOCK_UN)) { @@ -47,11 +75,23 @@ class Mutex extends \yii\mutex\Mutex } } + /** + * This method may optionally be extended by concrete mutex implementations. Checks whether lock has been + * already acquired by given name. + * @param string $name of the lock to be released. + * @return null|boolean whether lock has been already acquired. Returns `null` in case this feature + * is not supported by concrete mutex implementation. + */ protected function getIsAcquired($name) { return false; } + /** + * This method should be extended by concrete mutex implementations. Returns whether current mutex + * implementation can be used in a distributed environment. + * @return boolean whether current mutex implementation can be used in a distributed environment. + */ public function getIsDistributed() { return false; From a15c70f414c67ca0bc46fc8148af988432d594ea Mon Sep 17 00:00:00 2001 From: resurtm Date: Mon, 24 Jun 2013 23:42:11 +0600 Subject: [PATCH 04/16] composer.json file and proper class files location. --- extensions/mutex/Mutex.php | 140 -------------------------------- extensions/mutex/composer.json | 27 ++++++ extensions/mutex/db/Mutex.php | 51 ------------ extensions/mutex/db/mssql/Mutex.php | 56 ------------- extensions/mutex/db/mysql/Mutex.php | 72 ---------------- extensions/mutex/unix/Mutex.php | 99 ---------------------- extensions/mutex/yii/Mutex.php | 140 ++++++++++++++++++++++++++++++++ extensions/mutex/yii/db/Mutex.php | 51 ++++++++++++ extensions/mutex/yii/db/mssql/Mutex.php | 56 +++++++++++++ extensions/mutex/yii/db/mysql/Mutex.php | 72 ++++++++++++++++ extensions/mutex/yii/unix/Mutex.php | 99 ++++++++++++++++++++++ 11 files changed, 445 insertions(+), 418 deletions(-) delete mode 100644 extensions/mutex/Mutex.php create mode 100644 extensions/mutex/composer.json delete mode 100644 extensions/mutex/db/Mutex.php delete mode 100644 extensions/mutex/db/mssql/Mutex.php delete mode 100644 extensions/mutex/db/mysql/Mutex.php delete mode 100644 extensions/mutex/unix/Mutex.php create mode 100644 extensions/mutex/yii/Mutex.php create mode 100644 extensions/mutex/yii/db/Mutex.php create mode 100644 extensions/mutex/yii/db/mssql/Mutex.php create mode 100644 extensions/mutex/yii/db/mysql/Mutex.php create mode 100644 extensions/mutex/yii/unix/Mutex.php diff --git a/extensions/mutex/Mutex.php b/extensions/mutex/Mutex.php deleted file mode 100644 index 5268d86..0000000 --- a/extensions/mutex/Mutex.php +++ /dev/null @@ -1,140 +0,0 @@ - - * @since 2.0 - */ -abstract class Mutex extends Component -{ - /** - * @var boolean whether all locks acquired in this process (i.e. local locks) must be released automagically - * before finishing script execution. Defaults to true. Setting this property to true - */ - public $autoRelease = true; - /** - * @var string[] names of the locks acquired in the current PHP process. - */ - private $_locks = array(); - - - /** - * Initializes the mutex component. - */ - public function init() - { - if ($this->autoRelease) { - register_shutdown_function(array($this, 'shutdownFunction')); - } - } - - /** - * Never call this method directly under any circumstances. This method is intended for internal use only. - */ - public function shutdownFunction() - { - foreach ($this->_locks as $lock) { - $this->release($lock); - } - } - - /** - * @param string $name of the lock to be acquired. Must be unique. - * @param integer $timeout to wait for lock to be released. Defaults to zero meaning that method will return - * false immediately in case lock was already acquired. - * @return boolean lock acquiring result. - */ - public function acquireLock($name, $timeout = 0) - { - if ($this->acquire($name, $timeout)) { - $this->_locks[] = $name; - return true; - } else { - return false; - } - } - - /** - * Release acquired lock. - * @param string $name of the lock to be released. This lock must be already created. - * @return boolean lock release result. - */ - public function releaseLock($name) - { - if ($this->release($name)) { - unset($this->_locks[array_search($name, $this->_locks)]); - return true; - } else { - return false; - } - } - - /** - * Checks whether named lock was already opened. - * @param string $name of the lock to be checked. This lock must be already created. - * @return boolean|null whether named lock was already opened. Returns `null` value in case concrete - * mutex implementation does not support this operation. - */ - public function getIsLockAcquired($name) - { - if (in_array($name, $this->_locks)) { - return true; - } else { - return $this->getIsAcquired($name); - } - } - - /** - * Checks whether given lock is local. In other words local lock means that it was opened in the current - * PHP process. - * @param string $name of the lock to be checked. This lock must be already created. - * @return boolean whether named lock was locally acquired. - */ - public function getIsLockLocal($name) - { - return in_array($name, $this->_locks); - } - - /** - * This method should be extended by concrete mutex implementations. Acquires lock by given name. - * @param string $name of the lock to be acquired. - * @param integer $timeout to wait for lock to become released. - * @return boolean acquiring result. - */ - abstract protected function acquire($name, $timeout = 0); - - /** - * This method should be extended by concrete mutex implementations. Releases lock by given name. - * @param string $name of the lock to be released. - * @return boolean release result. - */ - abstract protected function release($name); - - /** - * This method may optionally be extended by concrete mutex implementations. Checks whether lock has been - * already acquired by given name. - * @param string $name of the lock to be released. - * @return null|boolean whether lock has been already acquired. Returns `null` in case this feature - * is not supported by concrete mutex implementation. - */ - protected function getIsAcquired($name) - { - return null; - } - - /** - * This method should be extended by concrete mutex implementations. Returns whether current mutex - * implementation can be used in a distributed environment. - * @return boolean whether current mutex implementation can be used in a distributed environment. - */ - abstract public function getIsDistributed(); -} diff --git a/extensions/mutex/composer.json b/extensions/mutex/composer.json new file mode 100644 index 0000000..4499543 --- /dev/null +++ b/extensions/mutex/composer.json @@ -0,0 +1,27 @@ +{ + "name": "yiisoft/yii2-mutex", + "description": "Mutual exclusion extension for the Yii framework", + "keywords": ["yii", "mutex"], + "type": "library", + "license": "BSD-3-Clause", + "support": { + "issues": "https://github.com/yiisoft/yii2/issues?state=open", + "forum": "http://www.yiiframework.com/forum/", + "wiki": "http://www.yiiframework.com/wiki/", + "irc": "irc://irc.freenode.net/yii", + "source": "https://github.com/yiisoft/yii2" + }, + "authors": [ + { + "name": "resurtm", + "email": "resurtm@gmail.com" + } + ], + "minimum-stability": "dev", + "require": { + "yiisoft/yii2": "*" + }, + "autoload": { + "psr-0": { "yii\\smarty": "" } + } +} diff --git a/extensions/mutex/db/Mutex.php b/extensions/mutex/db/Mutex.php deleted file mode 100644 index 17dd68a..0000000 --- a/extensions/mutex/db/Mutex.php +++ /dev/null @@ -1,51 +0,0 @@ - - * @since 2.0 - */ -abstract class Mutex extends \yii\mutex\Mutex -{ - /** - * @var Connection|string the DB connection object or the application component ID of the DB connection. - * After the Mutex object is created, if you want to change this property, you should only assign - * it with a DB connection object. - */ - public $db = 'db'; - - /** - * Initializes generic database table based mutex implementation. - * @throws InvalidConfigException if [[db]] is invalid. - */ - public function init() - { - parent::init(); - if (is_string($this->db)) { - $this->db = Yii::$app->getComponent($this->db); - } - if (!$this->db instanceof Connection) { - throw new InvalidConfigException('Mutex::db must be either a DB connection instance or the application component ID of a DB connection.'); - } - } - - /** - * This method should be extended by concrete mutex implementations. Returns whether current mutex - * implementation can be used in a distributed environment. - * @return boolean whether current mutex implementation can be used in a distributed environment. - */ - public function getIsDistributed() - { - return true; - } -} diff --git a/extensions/mutex/db/mssql/Mutex.php b/extensions/mutex/db/mssql/Mutex.php deleted file mode 100644 index 374100a..0000000 --- a/extensions/mutex/db/mssql/Mutex.php +++ /dev/null @@ -1,56 +0,0 @@ - - * @since 2.0 - */ -class Mutex extends \yii\mutex\db\Mutex -{ - /** - * Initializes Microsoft SQL Server specific mutex component implementation. - * @throws InvalidConfigException if [[db]] is not Microsoft SQL Server connection. - */ - public function init() - { - parent::init(); - $driverName = $this->db->driverName; - if ($driverName !== 'sqlsrv' && $driverName !== 'dblib' && $driverName !== 'mssql') { - throw new InvalidConfigException(''); - } - } - - /** - * This method should be extended by concrete mutex implementations. Acquires lock by given name. - * @param string $name of the lock to be acquired. - * @param integer $timeout to wait for lock to become released. - * @return boolean acquiring result. - * @throws \BadMethodCallException - * @see http://msdn.microsoft.com/en-us/library/ms189823.aspx - */ - protected function acquire($name, $timeout = 0) - { - throw new \BadMethodCallException('Not implemented yet.'); - } - - /** - * This method should be extended by concrete mutex implementations. Releases lock by given name. - * @param string $name of the lock to be released. - * @return boolean release result. - * @throws \BadMethodCallException - * @see http://msdn.microsoft.com/en-us/library/ms178602.aspx - */ - protected function release($name) - { - throw new \BadMethodCallException('Not implemented yet.'); - } -} diff --git a/extensions/mutex/db/mysql/Mutex.php b/extensions/mutex/db/mysql/Mutex.php deleted file mode 100644 index 7153d38..0000000 --- a/extensions/mutex/db/mysql/Mutex.php +++ /dev/null @@ -1,72 +0,0 @@ - - * @since 2.0 - */ -class Mutex extends \yii\mutex\db\Mutex -{ - /** - * Initializes MySQL specific mutex component implementation. - * @throws InvalidConfigException if [[db]] is not MySQL connection. - */ - public function init() - { - parent::init(); - if ($this->db->driverName !== 'mysql') { - throw new InvalidConfigException(''); - } - } - - /** - * This method should be extended by concrete mutex implementations. Acquires lock by given name. - * @param string $name of the lock to be acquired. - * @param integer $timeout to wait for lock to become released. - * @return boolean acquiring result. - * @see http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_get-lock - */ - protected function acquire($name, $timeout = 0) - { - return (boolean)$this->db - ->createCommand('SELECT GET_LOCK(:name, :timeout)', array(':name' => $name, ':timeout' => $timeout)) - ->queryScalar(); - } - - /** - * This method should be extended by concrete mutex implementations. Releases lock by given name. - * @param string $name of the lock to be released. - * @return boolean release result. - * @see http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_release-lock - */ - protected function release($name) - { - return (boolean)$this->db - ->createCommand('SELECT RELEASE_LOCK(:name)', array(':name' => $name)) - ->queryScalar(); - } - - /** - * This method may optionally be extended by concrete mutex implementations. Checks whether lock has been - * already acquired by given name. - * @param string $name of the lock to be released. - * @return null|boolean whether lock has been already acquired. Returns `null` in case this feature - * is not supported by concrete mutex implementation. - * @see http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_is-free-lock - */ - protected function getIsAcquired($name) - { - return (boolean)$this->db - ->createCommand('SELECT IS_FREE_LOCK(:name)', array(':name' => $name)) - ->queryScalar(); - } -} diff --git a/extensions/mutex/unix/Mutex.php b/extensions/mutex/unix/Mutex.php deleted file mode 100644 index ca18a49..0000000 --- a/extensions/mutex/unix/Mutex.php +++ /dev/null @@ -1,99 +0,0 @@ - - * @since 2.0 - */ -class Mutex extends \yii\mutex\Mutex -{ - /** - * @var resource[] stores all opened lock files. Keys are lock names and values are file handles. - */ - private $_files = array(); - - - /** - * Initializes mutex component implementation dedicated for UNIX, GNU/Linux, Mac OS X, and other UNIX-like - * operating systems. - * @throws InvalidConfigException - */ - public function init() - { - if (stripos(php_uname('s'), 'win') === 0) { - throw new InvalidConfigException(''); - } - } - - /** - * This method should be extended by concrete mutex implementations. Acquires lock by given name. - * @param string $name of the lock to be acquired. - * @param integer $timeout to wait for lock to become released. - * @return boolean acquiring result. - */ - protected function acquire($name, $timeout = 0) - { - $file = fopen(Yii::$app->getRuntimePath() . '/mutex.' . md5($name) . '.lock', 'w+'); - if ($file === false) { - return false; - } - $waitTime = 0; - while (!flock($file, LOCK_EX | LOCK_NB)) { - $waitTime++; - if ($waitTime > $timeout) { - fclose($file); - return false; - } - sleep(1); - } - $this->_files[$name] = $file; - return true; - } - - /** - * This method should be extended by concrete mutex implementations. Releases lock by given name. - * @param string $name of the lock to be released. - * @return boolean release result. - */ - protected function release($name) - { - if (!isset($this->_files[$name]) || !flock($this->_files[$name], LOCK_UN)) { - return false; - } else { - fclose($this->_files[$name]); - unset($this->_files[$name]); - return true; - } - } - - /** - * This method may optionally be extended by concrete mutex implementations. Checks whether lock has been - * already acquired by given name. - * @param string $name of the lock to be released. - * @return null|boolean whether lock has been already acquired. Returns `null` in case this feature - * is not supported by concrete mutex implementation. - */ - protected function getIsAcquired($name) - { - return false; - } - - /** - * This method should be extended by concrete mutex implementations. Returns whether current mutex - * implementation can be used in a distributed environment. - * @return boolean whether current mutex implementation can be used in a distributed environment. - */ - public function getIsDistributed() - { - return false; - } -} diff --git a/extensions/mutex/yii/Mutex.php b/extensions/mutex/yii/Mutex.php new file mode 100644 index 0000000..5268d86 --- /dev/null +++ b/extensions/mutex/yii/Mutex.php @@ -0,0 +1,140 @@ + + * @since 2.0 + */ +abstract class Mutex extends Component +{ + /** + * @var boolean whether all locks acquired in this process (i.e. local locks) must be released automagically + * before finishing script execution. Defaults to true. Setting this property to true + */ + public $autoRelease = true; + /** + * @var string[] names of the locks acquired in the current PHP process. + */ + private $_locks = array(); + + + /** + * Initializes the mutex component. + */ + public function init() + { + if ($this->autoRelease) { + register_shutdown_function(array($this, 'shutdownFunction')); + } + } + + /** + * Never call this method directly under any circumstances. This method is intended for internal use only. + */ + public function shutdownFunction() + { + foreach ($this->_locks as $lock) { + $this->release($lock); + } + } + + /** + * @param string $name of the lock to be acquired. Must be unique. + * @param integer $timeout to wait for lock to be released. Defaults to zero meaning that method will return + * false immediately in case lock was already acquired. + * @return boolean lock acquiring result. + */ + public function acquireLock($name, $timeout = 0) + { + if ($this->acquire($name, $timeout)) { + $this->_locks[] = $name; + return true; + } else { + return false; + } + } + + /** + * Release acquired lock. + * @param string $name of the lock to be released. This lock must be already created. + * @return boolean lock release result. + */ + public function releaseLock($name) + { + if ($this->release($name)) { + unset($this->_locks[array_search($name, $this->_locks)]); + return true; + } else { + return false; + } + } + + /** + * Checks whether named lock was already opened. + * @param string $name of the lock to be checked. This lock must be already created. + * @return boolean|null whether named lock was already opened. Returns `null` value in case concrete + * mutex implementation does not support this operation. + */ + public function getIsLockAcquired($name) + { + if (in_array($name, $this->_locks)) { + return true; + } else { + return $this->getIsAcquired($name); + } + } + + /** + * Checks whether given lock is local. In other words local lock means that it was opened in the current + * PHP process. + * @param string $name of the lock to be checked. This lock must be already created. + * @return boolean whether named lock was locally acquired. + */ + public function getIsLockLocal($name) + { + return in_array($name, $this->_locks); + } + + /** + * This method should be extended by concrete mutex implementations. Acquires lock by given name. + * @param string $name of the lock to be acquired. + * @param integer $timeout to wait for lock to become released. + * @return boolean acquiring result. + */ + abstract protected function acquire($name, $timeout = 0); + + /** + * This method should be extended by concrete mutex implementations. Releases lock by given name. + * @param string $name of the lock to be released. + * @return boolean release result. + */ + abstract protected function release($name); + + /** + * This method may optionally be extended by concrete mutex implementations. Checks whether lock has been + * already acquired by given name. + * @param string $name of the lock to be released. + * @return null|boolean whether lock has been already acquired. Returns `null` in case this feature + * is not supported by concrete mutex implementation. + */ + protected function getIsAcquired($name) + { + return null; + } + + /** + * This method should be extended by concrete mutex implementations. Returns whether current mutex + * implementation can be used in a distributed environment. + * @return boolean whether current mutex implementation can be used in a distributed environment. + */ + abstract public function getIsDistributed(); +} diff --git a/extensions/mutex/yii/db/Mutex.php b/extensions/mutex/yii/db/Mutex.php new file mode 100644 index 0000000..17dd68a --- /dev/null +++ b/extensions/mutex/yii/db/Mutex.php @@ -0,0 +1,51 @@ + + * @since 2.0 + */ +abstract class Mutex extends \yii\mutex\Mutex +{ + /** + * @var Connection|string the DB connection object or the application component ID of the DB connection. + * After the Mutex object is created, if you want to change this property, you should only assign + * it with a DB connection object. + */ + public $db = 'db'; + + /** + * Initializes generic database table based mutex implementation. + * @throws InvalidConfigException if [[db]] is invalid. + */ + public function init() + { + parent::init(); + if (is_string($this->db)) { + $this->db = Yii::$app->getComponent($this->db); + } + if (!$this->db instanceof Connection) { + throw new InvalidConfigException('Mutex::db must be either a DB connection instance or the application component ID of a DB connection.'); + } + } + + /** + * This method should be extended by concrete mutex implementations. Returns whether current mutex + * implementation can be used in a distributed environment. + * @return boolean whether current mutex implementation can be used in a distributed environment. + */ + public function getIsDistributed() + { + return true; + } +} diff --git a/extensions/mutex/yii/db/mssql/Mutex.php b/extensions/mutex/yii/db/mssql/Mutex.php new file mode 100644 index 0000000..374100a --- /dev/null +++ b/extensions/mutex/yii/db/mssql/Mutex.php @@ -0,0 +1,56 @@ + + * @since 2.0 + */ +class Mutex extends \yii\mutex\db\Mutex +{ + /** + * Initializes Microsoft SQL Server specific mutex component implementation. + * @throws InvalidConfigException if [[db]] is not Microsoft SQL Server connection. + */ + public function init() + { + parent::init(); + $driverName = $this->db->driverName; + if ($driverName !== 'sqlsrv' && $driverName !== 'dblib' && $driverName !== 'mssql') { + throw new InvalidConfigException(''); + } + } + + /** + * This method should be extended by concrete mutex implementations. Acquires lock by given name. + * @param string $name of the lock to be acquired. + * @param integer $timeout to wait for lock to become released. + * @return boolean acquiring result. + * @throws \BadMethodCallException + * @see http://msdn.microsoft.com/en-us/library/ms189823.aspx + */ + protected function acquire($name, $timeout = 0) + { + throw new \BadMethodCallException('Not implemented yet.'); + } + + /** + * This method should be extended by concrete mutex implementations. Releases lock by given name. + * @param string $name of the lock to be released. + * @return boolean release result. + * @throws \BadMethodCallException + * @see http://msdn.microsoft.com/en-us/library/ms178602.aspx + */ + protected function release($name) + { + throw new \BadMethodCallException('Not implemented yet.'); + } +} diff --git a/extensions/mutex/yii/db/mysql/Mutex.php b/extensions/mutex/yii/db/mysql/Mutex.php new file mode 100644 index 0000000..7153d38 --- /dev/null +++ b/extensions/mutex/yii/db/mysql/Mutex.php @@ -0,0 +1,72 @@ + + * @since 2.0 + */ +class Mutex extends \yii\mutex\db\Mutex +{ + /** + * Initializes MySQL specific mutex component implementation. + * @throws InvalidConfigException if [[db]] is not MySQL connection. + */ + public function init() + { + parent::init(); + if ($this->db->driverName !== 'mysql') { + throw new InvalidConfigException(''); + } + } + + /** + * This method should be extended by concrete mutex implementations. Acquires lock by given name. + * @param string $name of the lock to be acquired. + * @param integer $timeout to wait for lock to become released. + * @return boolean acquiring result. + * @see http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_get-lock + */ + protected function acquire($name, $timeout = 0) + { + return (boolean)$this->db + ->createCommand('SELECT GET_LOCK(:name, :timeout)', array(':name' => $name, ':timeout' => $timeout)) + ->queryScalar(); + } + + /** + * This method should be extended by concrete mutex implementations. Releases lock by given name. + * @param string $name of the lock to be released. + * @return boolean release result. + * @see http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_release-lock + */ + protected function release($name) + { + return (boolean)$this->db + ->createCommand('SELECT RELEASE_LOCK(:name)', array(':name' => $name)) + ->queryScalar(); + } + + /** + * This method may optionally be extended by concrete mutex implementations. Checks whether lock has been + * already acquired by given name. + * @param string $name of the lock to be released. + * @return null|boolean whether lock has been already acquired. Returns `null` in case this feature + * is not supported by concrete mutex implementation. + * @see http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_is-free-lock + */ + protected function getIsAcquired($name) + { + return (boolean)$this->db + ->createCommand('SELECT IS_FREE_LOCK(:name)', array(':name' => $name)) + ->queryScalar(); + } +} diff --git a/extensions/mutex/yii/unix/Mutex.php b/extensions/mutex/yii/unix/Mutex.php new file mode 100644 index 0000000..ca18a49 --- /dev/null +++ b/extensions/mutex/yii/unix/Mutex.php @@ -0,0 +1,99 @@ + + * @since 2.0 + */ +class Mutex extends \yii\mutex\Mutex +{ + /** + * @var resource[] stores all opened lock files. Keys are lock names and values are file handles. + */ + private $_files = array(); + + + /** + * Initializes mutex component implementation dedicated for UNIX, GNU/Linux, Mac OS X, and other UNIX-like + * operating systems. + * @throws InvalidConfigException + */ + public function init() + { + if (stripos(php_uname('s'), 'win') === 0) { + throw new InvalidConfigException(''); + } + } + + /** + * This method should be extended by concrete mutex implementations. Acquires lock by given name. + * @param string $name of the lock to be acquired. + * @param integer $timeout to wait for lock to become released. + * @return boolean acquiring result. + */ + protected function acquire($name, $timeout = 0) + { + $file = fopen(Yii::$app->getRuntimePath() . '/mutex.' . md5($name) . '.lock', 'w+'); + if ($file === false) { + return false; + } + $waitTime = 0; + while (!flock($file, LOCK_EX | LOCK_NB)) { + $waitTime++; + if ($waitTime > $timeout) { + fclose($file); + return false; + } + sleep(1); + } + $this->_files[$name] = $file; + return true; + } + + /** + * This method should be extended by concrete mutex implementations. Releases lock by given name. + * @param string $name of the lock to be released. + * @return boolean release result. + */ + protected function release($name) + { + if (!isset($this->_files[$name]) || !flock($this->_files[$name], LOCK_UN)) { + return false; + } else { + fclose($this->_files[$name]); + unset($this->_files[$name]); + return true; + } + } + + /** + * This method may optionally be extended by concrete mutex implementations. Checks whether lock has been + * already acquired by given name. + * @param string $name of the lock to be released. + * @return null|boolean whether lock has been already acquired. Returns `null` in case this feature + * is not supported by concrete mutex implementation. + */ + protected function getIsAcquired($name) + { + return false; + } + + /** + * This method should be extended by concrete mutex implementations. Returns whether current mutex + * implementation can be used in a distributed environment. + * @return boolean whether current mutex implementation can be used in a distributed environment. + */ + public function getIsDistributed() + { + return false; + } +} From b8541df0882c208831aa2a03a56fe9e991e7c7fa Mon Sep 17 00:00:00 2001 From: resurtm Date: Mon, 24 Jun 2013 23:44:02 +0600 Subject: [PATCH 05/16] Proper files location. --- extensions/mutex/yii/Mutex.php | 140 -------------------------- extensions/mutex/yii/db/Mutex.php | 51 ---------- extensions/mutex/yii/db/mssql/Mutex.php | 56 ----------- extensions/mutex/yii/db/mysql/Mutex.php | 72 ------------- extensions/mutex/yii/mutex/Mutex.php | 140 ++++++++++++++++++++++++++ extensions/mutex/yii/mutex/db/Mutex.php | 51 ++++++++++ extensions/mutex/yii/mutex/db/mssql/Mutex.php | 56 +++++++++++ extensions/mutex/yii/mutex/db/mysql/Mutex.php | 72 +++++++++++++ extensions/mutex/yii/mutex/unix/Mutex.php | 99 ++++++++++++++++++ extensions/mutex/yii/unix/Mutex.php | 99 ------------------ 10 files changed, 418 insertions(+), 418 deletions(-) delete mode 100644 extensions/mutex/yii/Mutex.php delete mode 100644 extensions/mutex/yii/db/Mutex.php delete mode 100644 extensions/mutex/yii/db/mssql/Mutex.php delete mode 100644 extensions/mutex/yii/db/mysql/Mutex.php create mode 100644 extensions/mutex/yii/mutex/Mutex.php create mode 100644 extensions/mutex/yii/mutex/db/Mutex.php create mode 100644 extensions/mutex/yii/mutex/db/mssql/Mutex.php create mode 100644 extensions/mutex/yii/mutex/db/mysql/Mutex.php create mode 100644 extensions/mutex/yii/mutex/unix/Mutex.php delete mode 100644 extensions/mutex/yii/unix/Mutex.php diff --git a/extensions/mutex/yii/Mutex.php b/extensions/mutex/yii/Mutex.php deleted file mode 100644 index 5268d86..0000000 --- a/extensions/mutex/yii/Mutex.php +++ /dev/null @@ -1,140 +0,0 @@ - - * @since 2.0 - */ -abstract class Mutex extends Component -{ - /** - * @var boolean whether all locks acquired in this process (i.e. local locks) must be released automagically - * before finishing script execution. Defaults to true. Setting this property to true - */ - public $autoRelease = true; - /** - * @var string[] names of the locks acquired in the current PHP process. - */ - private $_locks = array(); - - - /** - * Initializes the mutex component. - */ - public function init() - { - if ($this->autoRelease) { - register_shutdown_function(array($this, 'shutdownFunction')); - } - } - - /** - * Never call this method directly under any circumstances. This method is intended for internal use only. - */ - public function shutdownFunction() - { - foreach ($this->_locks as $lock) { - $this->release($lock); - } - } - - /** - * @param string $name of the lock to be acquired. Must be unique. - * @param integer $timeout to wait for lock to be released. Defaults to zero meaning that method will return - * false immediately in case lock was already acquired. - * @return boolean lock acquiring result. - */ - public function acquireLock($name, $timeout = 0) - { - if ($this->acquire($name, $timeout)) { - $this->_locks[] = $name; - return true; - } else { - return false; - } - } - - /** - * Release acquired lock. - * @param string $name of the lock to be released. This lock must be already created. - * @return boolean lock release result. - */ - public function releaseLock($name) - { - if ($this->release($name)) { - unset($this->_locks[array_search($name, $this->_locks)]); - return true; - } else { - return false; - } - } - - /** - * Checks whether named lock was already opened. - * @param string $name of the lock to be checked. This lock must be already created. - * @return boolean|null whether named lock was already opened. Returns `null` value in case concrete - * mutex implementation does not support this operation. - */ - public function getIsLockAcquired($name) - { - if (in_array($name, $this->_locks)) { - return true; - } else { - return $this->getIsAcquired($name); - } - } - - /** - * Checks whether given lock is local. In other words local lock means that it was opened in the current - * PHP process. - * @param string $name of the lock to be checked. This lock must be already created. - * @return boolean whether named lock was locally acquired. - */ - public function getIsLockLocal($name) - { - return in_array($name, $this->_locks); - } - - /** - * This method should be extended by concrete mutex implementations. Acquires lock by given name. - * @param string $name of the lock to be acquired. - * @param integer $timeout to wait for lock to become released. - * @return boolean acquiring result. - */ - abstract protected function acquire($name, $timeout = 0); - - /** - * This method should be extended by concrete mutex implementations. Releases lock by given name. - * @param string $name of the lock to be released. - * @return boolean release result. - */ - abstract protected function release($name); - - /** - * This method may optionally be extended by concrete mutex implementations. Checks whether lock has been - * already acquired by given name. - * @param string $name of the lock to be released. - * @return null|boolean whether lock has been already acquired. Returns `null` in case this feature - * is not supported by concrete mutex implementation. - */ - protected function getIsAcquired($name) - { - return null; - } - - /** - * This method should be extended by concrete mutex implementations. Returns whether current mutex - * implementation can be used in a distributed environment. - * @return boolean whether current mutex implementation can be used in a distributed environment. - */ - abstract public function getIsDistributed(); -} diff --git a/extensions/mutex/yii/db/Mutex.php b/extensions/mutex/yii/db/Mutex.php deleted file mode 100644 index 17dd68a..0000000 --- a/extensions/mutex/yii/db/Mutex.php +++ /dev/null @@ -1,51 +0,0 @@ - - * @since 2.0 - */ -abstract class Mutex extends \yii\mutex\Mutex -{ - /** - * @var Connection|string the DB connection object or the application component ID of the DB connection. - * After the Mutex object is created, if you want to change this property, you should only assign - * it with a DB connection object. - */ - public $db = 'db'; - - /** - * Initializes generic database table based mutex implementation. - * @throws InvalidConfigException if [[db]] is invalid. - */ - public function init() - { - parent::init(); - if (is_string($this->db)) { - $this->db = Yii::$app->getComponent($this->db); - } - if (!$this->db instanceof Connection) { - throw new InvalidConfigException('Mutex::db must be either a DB connection instance or the application component ID of a DB connection.'); - } - } - - /** - * This method should be extended by concrete mutex implementations. Returns whether current mutex - * implementation can be used in a distributed environment. - * @return boolean whether current mutex implementation can be used in a distributed environment. - */ - public function getIsDistributed() - { - return true; - } -} diff --git a/extensions/mutex/yii/db/mssql/Mutex.php b/extensions/mutex/yii/db/mssql/Mutex.php deleted file mode 100644 index 374100a..0000000 --- a/extensions/mutex/yii/db/mssql/Mutex.php +++ /dev/null @@ -1,56 +0,0 @@ - - * @since 2.0 - */ -class Mutex extends \yii\mutex\db\Mutex -{ - /** - * Initializes Microsoft SQL Server specific mutex component implementation. - * @throws InvalidConfigException if [[db]] is not Microsoft SQL Server connection. - */ - public function init() - { - parent::init(); - $driverName = $this->db->driverName; - if ($driverName !== 'sqlsrv' && $driverName !== 'dblib' && $driverName !== 'mssql') { - throw new InvalidConfigException(''); - } - } - - /** - * This method should be extended by concrete mutex implementations. Acquires lock by given name. - * @param string $name of the lock to be acquired. - * @param integer $timeout to wait for lock to become released. - * @return boolean acquiring result. - * @throws \BadMethodCallException - * @see http://msdn.microsoft.com/en-us/library/ms189823.aspx - */ - protected function acquire($name, $timeout = 0) - { - throw new \BadMethodCallException('Not implemented yet.'); - } - - /** - * This method should be extended by concrete mutex implementations. Releases lock by given name. - * @param string $name of the lock to be released. - * @return boolean release result. - * @throws \BadMethodCallException - * @see http://msdn.microsoft.com/en-us/library/ms178602.aspx - */ - protected function release($name) - { - throw new \BadMethodCallException('Not implemented yet.'); - } -} diff --git a/extensions/mutex/yii/db/mysql/Mutex.php b/extensions/mutex/yii/db/mysql/Mutex.php deleted file mode 100644 index 7153d38..0000000 --- a/extensions/mutex/yii/db/mysql/Mutex.php +++ /dev/null @@ -1,72 +0,0 @@ - - * @since 2.0 - */ -class Mutex extends \yii\mutex\db\Mutex -{ - /** - * Initializes MySQL specific mutex component implementation. - * @throws InvalidConfigException if [[db]] is not MySQL connection. - */ - public function init() - { - parent::init(); - if ($this->db->driverName !== 'mysql') { - throw new InvalidConfigException(''); - } - } - - /** - * This method should be extended by concrete mutex implementations. Acquires lock by given name. - * @param string $name of the lock to be acquired. - * @param integer $timeout to wait for lock to become released. - * @return boolean acquiring result. - * @see http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_get-lock - */ - protected function acquire($name, $timeout = 0) - { - return (boolean)$this->db - ->createCommand('SELECT GET_LOCK(:name, :timeout)', array(':name' => $name, ':timeout' => $timeout)) - ->queryScalar(); - } - - /** - * This method should be extended by concrete mutex implementations. Releases lock by given name. - * @param string $name of the lock to be released. - * @return boolean release result. - * @see http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_release-lock - */ - protected function release($name) - { - return (boolean)$this->db - ->createCommand('SELECT RELEASE_LOCK(:name)', array(':name' => $name)) - ->queryScalar(); - } - - /** - * This method may optionally be extended by concrete mutex implementations. Checks whether lock has been - * already acquired by given name. - * @param string $name of the lock to be released. - * @return null|boolean whether lock has been already acquired. Returns `null` in case this feature - * is not supported by concrete mutex implementation. - * @see http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_is-free-lock - */ - protected function getIsAcquired($name) - { - return (boolean)$this->db - ->createCommand('SELECT IS_FREE_LOCK(:name)', array(':name' => $name)) - ->queryScalar(); - } -} diff --git a/extensions/mutex/yii/mutex/Mutex.php b/extensions/mutex/yii/mutex/Mutex.php new file mode 100644 index 0000000..5268d86 --- /dev/null +++ b/extensions/mutex/yii/mutex/Mutex.php @@ -0,0 +1,140 @@ + + * @since 2.0 + */ +abstract class Mutex extends Component +{ + /** + * @var boolean whether all locks acquired in this process (i.e. local locks) must be released automagically + * before finishing script execution. Defaults to true. Setting this property to true + */ + public $autoRelease = true; + /** + * @var string[] names of the locks acquired in the current PHP process. + */ + private $_locks = array(); + + + /** + * Initializes the mutex component. + */ + public function init() + { + if ($this->autoRelease) { + register_shutdown_function(array($this, 'shutdownFunction')); + } + } + + /** + * Never call this method directly under any circumstances. This method is intended for internal use only. + */ + public function shutdownFunction() + { + foreach ($this->_locks as $lock) { + $this->release($lock); + } + } + + /** + * @param string $name of the lock to be acquired. Must be unique. + * @param integer $timeout to wait for lock to be released. Defaults to zero meaning that method will return + * false immediately in case lock was already acquired. + * @return boolean lock acquiring result. + */ + public function acquireLock($name, $timeout = 0) + { + if ($this->acquire($name, $timeout)) { + $this->_locks[] = $name; + return true; + } else { + return false; + } + } + + /** + * Release acquired lock. + * @param string $name of the lock to be released. This lock must be already created. + * @return boolean lock release result. + */ + public function releaseLock($name) + { + if ($this->release($name)) { + unset($this->_locks[array_search($name, $this->_locks)]); + return true; + } else { + return false; + } + } + + /** + * Checks whether named lock was already opened. + * @param string $name of the lock to be checked. This lock must be already created. + * @return boolean|null whether named lock was already opened. Returns `null` value in case concrete + * mutex implementation does not support this operation. + */ + public function getIsLockAcquired($name) + { + if (in_array($name, $this->_locks)) { + return true; + } else { + return $this->getIsAcquired($name); + } + } + + /** + * Checks whether given lock is local. In other words local lock means that it was opened in the current + * PHP process. + * @param string $name of the lock to be checked. This lock must be already created. + * @return boolean whether named lock was locally acquired. + */ + public function getIsLockLocal($name) + { + return in_array($name, $this->_locks); + } + + /** + * This method should be extended by concrete mutex implementations. Acquires lock by given name. + * @param string $name of the lock to be acquired. + * @param integer $timeout to wait for lock to become released. + * @return boolean acquiring result. + */ + abstract protected function acquire($name, $timeout = 0); + + /** + * This method should be extended by concrete mutex implementations. Releases lock by given name. + * @param string $name of the lock to be released. + * @return boolean release result. + */ + abstract protected function release($name); + + /** + * This method may optionally be extended by concrete mutex implementations. Checks whether lock has been + * already acquired by given name. + * @param string $name of the lock to be released. + * @return null|boolean whether lock has been already acquired. Returns `null` in case this feature + * is not supported by concrete mutex implementation. + */ + protected function getIsAcquired($name) + { + return null; + } + + /** + * This method should be extended by concrete mutex implementations. Returns whether current mutex + * implementation can be used in a distributed environment. + * @return boolean whether current mutex implementation can be used in a distributed environment. + */ + abstract public function getIsDistributed(); +} diff --git a/extensions/mutex/yii/mutex/db/Mutex.php b/extensions/mutex/yii/mutex/db/Mutex.php new file mode 100644 index 0000000..17dd68a --- /dev/null +++ b/extensions/mutex/yii/mutex/db/Mutex.php @@ -0,0 +1,51 @@ + + * @since 2.0 + */ +abstract class Mutex extends \yii\mutex\Mutex +{ + /** + * @var Connection|string the DB connection object or the application component ID of the DB connection. + * After the Mutex object is created, if you want to change this property, you should only assign + * it with a DB connection object. + */ + public $db = 'db'; + + /** + * Initializes generic database table based mutex implementation. + * @throws InvalidConfigException if [[db]] is invalid. + */ + public function init() + { + parent::init(); + if (is_string($this->db)) { + $this->db = Yii::$app->getComponent($this->db); + } + if (!$this->db instanceof Connection) { + throw new InvalidConfigException('Mutex::db must be either a DB connection instance or the application component ID of a DB connection.'); + } + } + + /** + * This method should be extended by concrete mutex implementations. Returns whether current mutex + * implementation can be used in a distributed environment. + * @return boolean whether current mutex implementation can be used in a distributed environment. + */ + public function getIsDistributed() + { + return true; + } +} diff --git a/extensions/mutex/yii/mutex/db/mssql/Mutex.php b/extensions/mutex/yii/mutex/db/mssql/Mutex.php new file mode 100644 index 0000000..374100a --- /dev/null +++ b/extensions/mutex/yii/mutex/db/mssql/Mutex.php @@ -0,0 +1,56 @@ + + * @since 2.0 + */ +class Mutex extends \yii\mutex\db\Mutex +{ + /** + * Initializes Microsoft SQL Server specific mutex component implementation. + * @throws InvalidConfigException if [[db]] is not Microsoft SQL Server connection. + */ + public function init() + { + parent::init(); + $driverName = $this->db->driverName; + if ($driverName !== 'sqlsrv' && $driverName !== 'dblib' && $driverName !== 'mssql') { + throw new InvalidConfigException(''); + } + } + + /** + * This method should be extended by concrete mutex implementations. Acquires lock by given name. + * @param string $name of the lock to be acquired. + * @param integer $timeout to wait for lock to become released. + * @return boolean acquiring result. + * @throws \BadMethodCallException + * @see http://msdn.microsoft.com/en-us/library/ms189823.aspx + */ + protected function acquire($name, $timeout = 0) + { + throw new \BadMethodCallException('Not implemented yet.'); + } + + /** + * This method should be extended by concrete mutex implementations. Releases lock by given name. + * @param string $name of the lock to be released. + * @return boolean release result. + * @throws \BadMethodCallException + * @see http://msdn.microsoft.com/en-us/library/ms178602.aspx + */ + protected function release($name) + { + throw new \BadMethodCallException('Not implemented yet.'); + } +} diff --git a/extensions/mutex/yii/mutex/db/mysql/Mutex.php b/extensions/mutex/yii/mutex/db/mysql/Mutex.php new file mode 100644 index 0000000..7153d38 --- /dev/null +++ b/extensions/mutex/yii/mutex/db/mysql/Mutex.php @@ -0,0 +1,72 @@ + + * @since 2.0 + */ +class Mutex extends \yii\mutex\db\Mutex +{ + /** + * Initializes MySQL specific mutex component implementation. + * @throws InvalidConfigException if [[db]] is not MySQL connection. + */ + public function init() + { + parent::init(); + if ($this->db->driverName !== 'mysql') { + throw new InvalidConfigException(''); + } + } + + /** + * This method should be extended by concrete mutex implementations. Acquires lock by given name. + * @param string $name of the lock to be acquired. + * @param integer $timeout to wait for lock to become released. + * @return boolean acquiring result. + * @see http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_get-lock + */ + protected function acquire($name, $timeout = 0) + { + return (boolean)$this->db + ->createCommand('SELECT GET_LOCK(:name, :timeout)', array(':name' => $name, ':timeout' => $timeout)) + ->queryScalar(); + } + + /** + * This method should be extended by concrete mutex implementations. Releases lock by given name. + * @param string $name of the lock to be released. + * @return boolean release result. + * @see http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_release-lock + */ + protected function release($name) + { + return (boolean)$this->db + ->createCommand('SELECT RELEASE_LOCK(:name)', array(':name' => $name)) + ->queryScalar(); + } + + /** + * This method may optionally be extended by concrete mutex implementations. Checks whether lock has been + * already acquired by given name. + * @param string $name of the lock to be released. + * @return null|boolean whether lock has been already acquired. Returns `null` in case this feature + * is not supported by concrete mutex implementation. + * @see http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_is-free-lock + */ + protected function getIsAcquired($name) + { + return (boolean)$this->db + ->createCommand('SELECT IS_FREE_LOCK(:name)', array(':name' => $name)) + ->queryScalar(); + } +} diff --git a/extensions/mutex/yii/mutex/unix/Mutex.php b/extensions/mutex/yii/mutex/unix/Mutex.php new file mode 100644 index 0000000..ca18a49 --- /dev/null +++ b/extensions/mutex/yii/mutex/unix/Mutex.php @@ -0,0 +1,99 @@ + + * @since 2.0 + */ +class Mutex extends \yii\mutex\Mutex +{ + /** + * @var resource[] stores all opened lock files. Keys are lock names and values are file handles. + */ + private $_files = array(); + + + /** + * Initializes mutex component implementation dedicated for UNIX, GNU/Linux, Mac OS X, and other UNIX-like + * operating systems. + * @throws InvalidConfigException + */ + public function init() + { + if (stripos(php_uname('s'), 'win') === 0) { + throw new InvalidConfigException(''); + } + } + + /** + * This method should be extended by concrete mutex implementations. Acquires lock by given name. + * @param string $name of the lock to be acquired. + * @param integer $timeout to wait for lock to become released. + * @return boolean acquiring result. + */ + protected function acquire($name, $timeout = 0) + { + $file = fopen(Yii::$app->getRuntimePath() . '/mutex.' . md5($name) . '.lock', 'w+'); + if ($file === false) { + return false; + } + $waitTime = 0; + while (!flock($file, LOCK_EX | LOCK_NB)) { + $waitTime++; + if ($waitTime > $timeout) { + fclose($file); + return false; + } + sleep(1); + } + $this->_files[$name] = $file; + return true; + } + + /** + * This method should be extended by concrete mutex implementations. Releases lock by given name. + * @param string $name of the lock to be released. + * @return boolean release result. + */ + protected function release($name) + { + if (!isset($this->_files[$name]) || !flock($this->_files[$name], LOCK_UN)) { + return false; + } else { + fclose($this->_files[$name]); + unset($this->_files[$name]); + return true; + } + } + + /** + * This method may optionally be extended by concrete mutex implementations. Checks whether lock has been + * already acquired by given name. + * @param string $name of the lock to be released. + * @return null|boolean whether lock has been already acquired. Returns `null` in case this feature + * is not supported by concrete mutex implementation. + */ + protected function getIsAcquired($name) + { + return false; + } + + /** + * This method should be extended by concrete mutex implementations. Returns whether current mutex + * implementation can be used in a distributed environment. + * @return boolean whether current mutex implementation can be used in a distributed environment. + */ + public function getIsDistributed() + { + return false; + } +} diff --git a/extensions/mutex/yii/unix/Mutex.php b/extensions/mutex/yii/unix/Mutex.php deleted file mode 100644 index ca18a49..0000000 --- a/extensions/mutex/yii/unix/Mutex.php +++ /dev/null @@ -1,99 +0,0 @@ - - * @since 2.0 - */ -class Mutex extends \yii\mutex\Mutex -{ - /** - * @var resource[] stores all opened lock files. Keys are lock names and values are file handles. - */ - private $_files = array(); - - - /** - * Initializes mutex component implementation dedicated for UNIX, GNU/Linux, Mac OS X, and other UNIX-like - * operating systems. - * @throws InvalidConfigException - */ - public function init() - { - if (stripos(php_uname('s'), 'win') === 0) { - throw new InvalidConfigException(''); - } - } - - /** - * This method should be extended by concrete mutex implementations. Acquires lock by given name. - * @param string $name of the lock to be acquired. - * @param integer $timeout to wait for lock to become released. - * @return boolean acquiring result. - */ - protected function acquire($name, $timeout = 0) - { - $file = fopen(Yii::$app->getRuntimePath() . '/mutex.' . md5($name) . '.lock', 'w+'); - if ($file === false) { - return false; - } - $waitTime = 0; - while (!flock($file, LOCK_EX | LOCK_NB)) { - $waitTime++; - if ($waitTime > $timeout) { - fclose($file); - return false; - } - sleep(1); - } - $this->_files[$name] = $file; - return true; - } - - /** - * This method should be extended by concrete mutex implementations. Releases lock by given name. - * @param string $name of the lock to be released. - * @return boolean release result. - */ - protected function release($name) - { - if (!isset($this->_files[$name]) || !flock($this->_files[$name], LOCK_UN)) { - return false; - } else { - fclose($this->_files[$name]); - unset($this->_files[$name]); - return true; - } - } - - /** - * This method may optionally be extended by concrete mutex implementations. Checks whether lock has been - * already acquired by given name. - * @param string $name of the lock to be released. - * @return null|boolean whether lock has been already acquired. Returns `null` in case this feature - * is not supported by concrete mutex implementation. - */ - protected function getIsAcquired($name) - { - return false; - } - - /** - * This method should be extended by concrete mutex implementations. Returns whether current mutex - * implementation can be used in a distributed environment. - * @return boolean whether current mutex implementation can be used in a distributed environment. - */ - public function getIsDistributed() - { - return false; - } -} From 397004c8f6695cc8f041c570b2f0e212c790d727 Mon Sep 17 00:00:00 2001 From: resurtm Date: Tue, 25 Jun 2013 00:14:42 +0600 Subject: [PATCH 06/16] Mutex cache backend WIP. --- extensions/mutex/yii/mutex/cache/Mutex.php | 89 ++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 extensions/mutex/yii/mutex/cache/Mutex.php diff --git a/extensions/mutex/yii/mutex/cache/Mutex.php b/extensions/mutex/yii/mutex/cache/Mutex.php new file mode 100644 index 0000000..67b6445 --- /dev/null +++ b/extensions/mutex/yii/mutex/cache/Mutex.php @@ -0,0 +1,89 @@ + + * @since 2.0 + */ +class Mutex extends \yii\mutex\Mutex +{ + /** + * @var Cache|string the cache object or the application component ID of the cache object. + * The messages data will be cached using this cache object. Note, this property has meaning only + * in case [[cachingDuration]] set to non-zero value. + * After the Mutex object is created, if you want to change this property, you should only assign + * it with a cache object. + */ + public $cache = 'cache'; + + + /** + * Initializes the DbMessageSource component. Configured [[cache]] component will be initialized. + * @throws InvalidConfigException if [[cache]] is invalid. + */ + public function init() + { + parent::init(); + if (is_string($this->cache)) { + $this->cache = Yii::$app->getComponent($this->cache); + } + if (!$this->cache instanceof Cache) { + throw new InvalidConfigException('Mutex::cache must be either a cache object or the application component ID of the cache object.'); + } + } + + /** + * This method should be extended by concrete mutex implementations. Acquires lock by given name. + * @param string $name of the lock to be acquired. + * @param integer $timeout to wait for lock to become released. + * @return boolean acquiring result. + */ + protected function acquire($name, $timeout = 0) + { + + } + + /** + * This method should be extended by concrete mutex implementations. Releases lock by given name. + * @param string $name of the lock to be released. + * @return boolean release result. + */ + protected function release($name) + { + return $this->cache->delete("mutex.{$name}"); + } + + /** + * This method may optionally be extended by concrete mutex implementations. Checks whether lock has been + * already acquired by given name. + * @param string $name of the lock to be released. + * @return null|boolean whether lock has been already acquired. Returns `null` in case this feature + * is not supported by concrete mutex implementation. + */ + protected function getIsAcquired($name) + { + + } + + /** + * This method should be extended by concrete mutex implementations. Returns whether current mutex + * implementation can be used in a distributed environment. + * @return boolean whether current mutex implementation can be used in a distributed environment. + */ + public function getIsDistributed() + { + return $this->cache instanceof DbCache || $this->cache instanceof MemCache; + } +} From 90227bd3448f31d0b4e847236a6cc9740b6bc7d3 Mon Sep 17 00:00:00 2001 From: resurtm Date: Tue, 25 Jun 2013 07:22:06 +0600 Subject: [PATCH 07/16] Autorelease callback improved, composer.json typo. --- extensions/mutex/composer.json | 2 +- extensions/mutex/yii/mutex/Mutex.php | 12 ++++++++---- extensions/mutex/yii/mutex/cache/Mutex.php | 2 +- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/extensions/mutex/composer.json b/extensions/mutex/composer.json index 4499543..db8cde3 100644 --- a/extensions/mutex/composer.json +++ b/extensions/mutex/composer.json @@ -22,6 +22,6 @@ "yiisoft/yii2": "*" }, "autoload": { - "psr-0": { "yii\\smarty": "" } + "psr-0": { "yii\\mutex": "" } } } diff --git a/extensions/mutex/yii/mutex/Mutex.php b/extensions/mutex/yii/mutex/Mutex.php index 5268d86..14ebf8f 100644 --- a/extensions/mutex/yii/mutex/Mutex.php +++ b/extensions/mutex/yii/mutex/Mutex.php @@ -33,7 +33,13 @@ abstract class Mutex extends Component public function init() { if ($this->autoRelease) { - register_shutdown_function(array($this, 'shutdownFunction')); + $referenceHolder = new stdClass(); + $referenceHolder->locks = &$this->_locks; + register_shutdown_function(function ($ref) { + foreach ($ref->locks as $lock) { + $this->release($lock); + } + }, $referenceHolder); } } @@ -42,9 +48,7 @@ abstract class Mutex extends Component */ public function shutdownFunction() { - foreach ($this->_locks as $lock) { - $this->release($lock); - } + } /** diff --git a/extensions/mutex/yii/mutex/cache/Mutex.php b/extensions/mutex/yii/mutex/cache/Mutex.php index 67b6445..73e277b 100644 --- a/extensions/mutex/yii/mutex/cache/Mutex.php +++ b/extensions/mutex/yii/mutex/cache/Mutex.php @@ -74,7 +74,7 @@ class Mutex extends \yii\mutex\Mutex */ protected function getIsAcquired($name) { - + } /** From 33adfcea91b45a5287bacfdf26b4bf30e69acd6c Mon Sep 17 00:00:00 2001 From: resurtm Date: Tue, 25 Jun 2013 07:24:57 +0600 Subject: [PATCH 08/16] Autorelease callback. --- extensions/mutex/yii/mutex/Mutex.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/extensions/mutex/yii/mutex/Mutex.php b/extensions/mutex/yii/mutex/Mutex.php index 14ebf8f..c7413a1 100644 --- a/extensions/mutex/yii/mutex/Mutex.php +++ b/extensions/mutex/yii/mutex/Mutex.php @@ -34,10 +34,11 @@ abstract class Mutex extends Component { if ($this->autoRelease) { $referenceHolder = new stdClass(); + $referenceHolder->mutex = &$this; $referenceHolder->locks = &$this->_locks; register_shutdown_function(function ($ref) { foreach ($ref->locks as $lock) { - $this->release($lock); + $ref->mutex->release($lock); } }, $referenceHolder); } From b98a1236bb829f10ae52966e924b54e3ad89fdbb Mon Sep 17 00:00:00 2001 From: resurtm Date: Tue, 25 Jun 2013 09:08:54 +0600 Subject: [PATCH 09/16] Fixes: 1. Proper auto release shutdown callback. 2. Proper Mutex::releaseLock() method. --- extensions/mutex/yii/mutex/Mutex.php | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/extensions/mutex/yii/mutex/Mutex.php b/extensions/mutex/yii/mutex/Mutex.php index c7413a1..9f47501 100644 --- a/extensions/mutex/yii/mutex/Mutex.php +++ b/extensions/mutex/yii/mutex/Mutex.php @@ -33,26 +33,18 @@ abstract class Mutex extends Component public function init() { if ($this->autoRelease) { - $referenceHolder = new stdClass(); - $referenceHolder->mutex = &$this; - $referenceHolder->locks = &$this->_locks; - register_shutdown_function(function ($ref) { - foreach ($ref->locks as $lock) { - $ref->mutex->release($lock); + $references = new stdClass(); + $references->mutex = $this; + $references->locks = &$this->_locks; + register_shutdown_function(function ($refs) { + foreach ($refs->locks as $lock) { + $refs->mutex->release($lock); } - }, $referenceHolder); + }, $references); } } /** - * Never call this method directly under any circumstances. This method is intended for internal use only. - */ - public function shutdownFunction() - { - - } - - /** * @param string $name of the lock to be acquired. Must be unique. * @param integer $timeout to wait for lock to be released. Defaults to zero meaning that method will return * false immediately in case lock was already acquired. @@ -69,14 +61,17 @@ abstract class Mutex extends Component } /** - * Release acquired lock. + * Release acquired lock. This method will return false in case named lock was not found. * @param string $name of the lock to be released. This lock must be already created. - * @return boolean lock release result. + * @return boolean lock release result: false in case named lock was not found.. */ public function releaseLock($name) { if ($this->release($name)) { - unset($this->_locks[array_search($name, $this->_locks)]); + $index = array_search($name, $this->_locks); + if ($index !== false) { + unset($this->_locks[$index]); + } return true; } else { return false; From 733dbbfb8b3a78b749f482005c48464e65d235e4 Mon Sep 17 00:00:00 2001 From: resurtm Date: Tue, 25 Jun 2013 09:54:07 +0600 Subject: [PATCH 10/16] Mutex WIP. --- extensions/mutex/yii/mutex/DbMutex.php | 41 +++++++++++ extensions/mutex/yii/mutex/FileMutex.php | 86 +++++++++++++++++++++++ extensions/mutex/yii/mutex/MssqlMutex.php | 56 +++++++++++++++ extensions/mutex/yii/mutex/Mutex.php | 73 ++++---------------- extensions/mutex/yii/mutex/MysqlMutex.php | 57 +++++++++++++++ extensions/mutex/yii/mutex/cache/Mutex.php | 89 ------------------------ extensions/mutex/yii/mutex/db/Mutex.php | 51 -------------- extensions/mutex/yii/mutex/db/mssql/Mutex.php | 56 --------------- extensions/mutex/yii/mutex/db/mysql/Mutex.php | 72 ------------------- extensions/mutex/yii/mutex/unix/Mutex.php | 99 --------------------------- 10 files changed, 254 insertions(+), 426 deletions(-) create mode 100644 extensions/mutex/yii/mutex/DbMutex.php create mode 100644 extensions/mutex/yii/mutex/FileMutex.php create mode 100644 extensions/mutex/yii/mutex/MssqlMutex.php create mode 100644 extensions/mutex/yii/mutex/MysqlMutex.php delete mode 100644 extensions/mutex/yii/mutex/cache/Mutex.php delete mode 100644 extensions/mutex/yii/mutex/db/Mutex.php delete mode 100644 extensions/mutex/yii/mutex/db/mssql/Mutex.php delete mode 100644 extensions/mutex/yii/mutex/db/mysql/Mutex.php delete mode 100644 extensions/mutex/yii/mutex/unix/Mutex.php diff --git a/extensions/mutex/yii/mutex/DbMutex.php b/extensions/mutex/yii/mutex/DbMutex.php new file mode 100644 index 0000000..3699c36 --- /dev/null +++ b/extensions/mutex/yii/mutex/DbMutex.php @@ -0,0 +1,41 @@ + + * @since 2.0 + */ +abstract class DbMutex extends Mutex +{ + /** + * @var Connection|string the DB connection object or the application component ID of the DB connection. + * After the Mutex object is created, if you want to change this property, you should only assign + * it with a DB connection object. + */ + public $db = 'db'; + + /** + * Initializes generic database table based mutex implementation. + * @throws InvalidConfigException if [[db]] is invalid. + */ + public function init() + { + parent::init(); + if (is_string($this->db)) { + $this->db = Yii::$app->getComponent($this->db); + } + if (!$this->db instanceof Connection) { + throw new InvalidConfigException('Mutex::db must be either a DB connection instance or the application component ID of a DB connection.'); + } + } +} diff --git a/extensions/mutex/yii/mutex/FileMutex.php b/extensions/mutex/yii/mutex/FileMutex.php new file mode 100644 index 0000000..4a949d0 --- /dev/null +++ b/extensions/mutex/yii/mutex/FileMutex.php @@ -0,0 +1,86 @@ + + * @since 2.0 + */ +class FileMutex extends Mutex +{ + /** + * @var string the directory to store mutex files. You may use path alias here. + * If not set, it will use the "mutex" subdirectory under the application runtime path. + */ + public $mutexPath = '@runtime/mutex'; + /** + * @var resource[] stores all opened lock files. Keys are lock names and values are file handles. + */ + private $_files = array(); + + + /** + * Initializes mutex component implementation dedicated for UNIX, GNU/Linux, Mac OS X, and other UNIX-like + * operating systems. + * @throws InvalidConfigException + */ + public function init() + { + if (stripos(php_uname('s'), 'win') === 0) { + throw new InvalidConfigException('FileMutex does not have MS Windows operating system support.'); + } + $this->mutexPath = Yii::getAlias($this->mutexPath); + if (!is_dir($this->mutexPath)) { + mkdir($this->mutexPath, 0777, true); + } + } + + /** + * This method should be extended by concrete mutex implementations. Acquires lock by given name. + * @param string $name of the lock to be acquired. + * @param integer $timeout to wait for lock to become released. + * @return boolean acquiring result. + */ + protected function acquireLock($name, $timeout = 0) + { + $file = fopen($this->mutexPath . '/' . md5($name) . '.lock', 'w+'); + if ($file === false) { + return false; + } + $waitTime = 0; + while (!flock($file, LOCK_EX | LOCK_NB)) { + $waitTime++; + if ($waitTime > $timeout) { + fclose($file); + return false; + } + sleep(1); + } + $this->_files[$name] = $file; + return true; + } + + /** + * This method should be extended by concrete mutex implementations. Releases lock by given name. + * @param string $name of the lock to be released. + * @return boolean release result. + */ + protected function releaseLock($name) + { + if (!isset($this->_files[$name]) || !flock($this->_files[$name], LOCK_UN)) { + return false; + } else { + fclose($this->_files[$name]); + unset($this->_files[$name]); + return true; + } + } +} diff --git a/extensions/mutex/yii/mutex/MssqlMutex.php b/extensions/mutex/yii/mutex/MssqlMutex.php new file mode 100644 index 0000000..d267699 --- /dev/null +++ b/extensions/mutex/yii/mutex/MssqlMutex.php @@ -0,0 +1,56 @@ + + * @since 2.0 + */ +class MssqlMutex extends Mutex +{ + /** + * Initializes Microsoft SQL Server specific mutex component implementation. + * @throws InvalidConfigException if [[db]] is not Microsoft SQL Server connection. + */ + public function init() + { + parent::init(); + $driverName = $this->db->driverName; + if ($driverName !== 'sqlsrv' && $driverName !== 'dblib' && $driverName !== 'mssql') { + throw new InvalidConfigException('In order to use MssqlMutex connection must be configured to use MS SQL Server database.'); + } + } + + /** + * This method should be extended by concrete mutex implementations. Acquires lock by given name. + * @param string $name of the lock to be acquired. + * @param integer $timeout to wait for lock to become released. + * @return boolean acquiring result. + * @throws \BadMethodCallException not implemented yet. + * @see http://msdn.microsoft.com/en-us/library/ms189823.aspx + */ + protected function acquireLock($name, $timeout = 0) + { + throw new \BadMethodCallException('Not implemented yet.'); + } + + /** + * This method should be extended by concrete mutex implementations. Releases lock by given name. + * @param string $name of the lock to be released. + * @return boolean release result. + * @throws \BadMethodCallException not implemented yet. + * @see http://msdn.microsoft.com/en-us/library/ms178602.aspx + */ + protected function releaseLock($name) + { + throw new \BadMethodCallException('Not implemented yet.'); + } +} diff --git a/extensions/mutex/yii/mutex/Mutex.php b/extensions/mutex/yii/mutex/Mutex.php index 9f47501..297abaf 100644 --- a/extensions/mutex/yii/mutex/Mutex.php +++ b/extensions/mutex/yii/mutex/Mutex.php @@ -18,7 +18,8 @@ abstract class Mutex extends Component { /** * @var boolean whether all locks acquired in this process (i.e. local locks) must be released automagically - * before finishing script execution. Defaults to true. Setting this property to true + * before finishing script execution. Defaults to true. Setting this property to true means that all locks + * acquire in this process must be released in any case (regardless any kind of errors or exceptions). */ public $autoRelease = true; /** @@ -33,14 +34,13 @@ abstract class Mutex extends Component public function init() { if ($this->autoRelease) { - $references = new stdClass(); - $references->mutex = $this; - $references->locks = &$this->_locks; - register_shutdown_function(function ($refs) { - foreach ($refs->locks as $lock) { - $refs->mutex->release($lock); + $mutex = $this; + $locks = &$this->_locks; + register_shutdown_function(function () use ($mutex, &$locks) { + foreach ($locks as $lock) { + $mutex->release($lock); } - }, $references); + }); } } @@ -50,9 +50,9 @@ abstract class Mutex extends Component * false immediately in case lock was already acquired. * @return boolean lock acquiring result. */ - public function acquireLock($name, $timeout = 0) + public function acquire($name, $timeout = 0) { - if ($this->acquire($name, $timeout)) { + if ($this->acquireLock($name, $timeout)) { $this->_locks[] = $name; return true; } else { @@ -65,9 +65,9 @@ abstract class Mutex extends Component * @param string $name of the lock to be released. This lock must be already created. * @return boolean lock release result: false in case named lock was not found.. */ - public function releaseLock($name) + public function release($name) { - if ($this->release($name)) { + if ($this->releaseLock($name)) { $index = array_search($name, $this->_locks); if ($index !== false) { unset($this->_locks[$index]); @@ -79,62 +79,17 @@ abstract class Mutex extends Component } /** - * Checks whether named lock was already opened. - * @param string $name of the lock to be checked. This lock must be already created. - * @return boolean|null whether named lock was already opened. Returns `null` value in case concrete - * mutex implementation does not support this operation. - */ - public function getIsLockAcquired($name) - { - if (in_array($name, $this->_locks)) { - return true; - } else { - return $this->getIsAcquired($name); - } - } - - /** - * Checks whether given lock is local. In other words local lock means that it was opened in the current - * PHP process. - * @param string $name of the lock to be checked. This lock must be already created. - * @return boolean whether named lock was locally acquired. - */ - public function getIsLockLocal($name) - { - return in_array($name, $this->_locks); - } - - /** * This method should be extended by concrete mutex implementations. Acquires lock by given name. * @param string $name of the lock to be acquired. * @param integer $timeout to wait for lock to become released. * @return boolean acquiring result. */ - abstract protected function acquire($name, $timeout = 0); + abstract protected function acquireLock($name, $timeout = 0); /** * This method should be extended by concrete mutex implementations. Releases lock by given name. * @param string $name of the lock to be released. * @return boolean release result. */ - abstract protected function release($name); - - /** - * This method may optionally be extended by concrete mutex implementations. Checks whether lock has been - * already acquired by given name. - * @param string $name of the lock to be released. - * @return null|boolean whether lock has been already acquired. Returns `null` in case this feature - * is not supported by concrete mutex implementation. - */ - protected function getIsAcquired($name) - { - return null; - } - - /** - * This method should be extended by concrete mutex implementations. Returns whether current mutex - * implementation can be used in a distributed environment. - * @return boolean whether current mutex implementation can be used in a distributed environment. - */ - abstract public function getIsDistributed(); + abstract protected function releaseLock($name); } diff --git a/extensions/mutex/yii/mutex/MysqlMutex.php b/extensions/mutex/yii/mutex/MysqlMutex.php new file mode 100644 index 0000000..b04427a --- /dev/null +++ b/extensions/mutex/yii/mutex/MysqlMutex.php @@ -0,0 +1,57 @@ + + * @since 2.0 + */ +class MysqlMutex extends Mutex +{ + /** + * Initializes MySQL specific mutex component implementation. + * @throws InvalidConfigException if [[db]] is not MySQL connection. + */ + public function init() + { + parent::init(); + if ($this->db->driverName !== 'mysql') { + throw new InvalidConfigException('In order to use MysqlMutex connection must be configured to use MySQL database.'); + } + } + + /** + * This method should be extended by concrete mutex implementations. Acquires lock by given name. + * @param string $name of the lock to be acquired. + * @param integer $timeout to wait for lock to become released. + * @return boolean acquiring result. + * @see http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_get-lock + */ + protected function acquireLock($name, $timeout = 0) + { + return (boolean)$this->db + ->createCommand('SELECT GET_LOCK(:name, :timeout)', array(':name' => $name, ':timeout' => $timeout)) + ->queryScalar(); + } + + /** + * This method should be extended by concrete mutex implementations. Releases lock by given name. + * @param string $name of the lock to be released. + * @return boolean release result. + * @see http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_release-lock + */ + protected function releaseLock($name) + { + return (boolean)$this->db + ->createCommand('SELECT RELEASE_LOCK(:name)', array(':name' => $name)) + ->queryScalar(); + } +} diff --git a/extensions/mutex/yii/mutex/cache/Mutex.php b/extensions/mutex/yii/mutex/cache/Mutex.php deleted file mode 100644 index 73e277b..0000000 --- a/extensions/mutex/yii/mutex/cache/Mutex.php +++ /dev/null @@ -1,89 +0,0 @@ - - * @since 2.0 - */ -class Mutex extends \yii\mutex\Mutex -{ - /** - * @var Cache|string the cache object or the application component ID of the cache object. - * The messages data will be cached using this cache object. Note, this property has meaning only - * in case [[cachingDuration]] set to non-zero value. - * After the Mutex object is created, if you want to change this property, you should only assign - * it with a cache object. - */ - public $cache = 'cache'; - - - /** - * Initializes the DbMessageSource component. Configured [[cache]] component will be initialized. - * @throws InvalidConfigException if [[cache]] is invalid. - */ - public function init() - { - parent::init(); - if (is_string($this->cache)) { - $this->cache = Yii::$app->getComponent($this->cache); - } - if (!$this->cache instanceof Cache) { - throw new InvalidConfigException('Mutex::cache must be either a cache object or the application component ID of the cache object.'); - } - } - - /** - * This method should be extended by concrete mutex implementations. Acquires lock by given name. - * @param string $name of the lock to be acquired. - * @param integer $timeout to wait for lock to become released. - * @return boolean acquiring result. - */ - protected function acquire($name, $timeout = 0) - { - - } - - /** - * This method should be extended by concrete mutex implementations. Releases lock by given name. - * @param string $name of the lock to be released. - * @return boolean release result. - */ - protected function release($name) - { - return $this->cache->delete("mutex.{$name}"); - } - - /** - * This method may optionally be extended by concrete mutex implementations. Checks whether lock has been - * already acquired by given name. - * @param string $name of the lock to be released. - * @return null|boolean whether lock has been already acquired. Returns `null` in case this feature - * is not supported by concrete mutex implementation. - */ - protected function getIsAcquired($name) - { - - } - - /** - * This method should be extended by concrete mutex implementations. Returns whether current mutex - * implementation can be used in a distributed environment. - * @return boolean whether current mutex implementation can be used in a distributed environment. - */ - public function getIsDistributed() - { - return $this->cache instanceof DbCache || $this->cache instanceof MemCache; - } -} diff --git a/extensions/mutex/yii/mutex/db/Mutex.php b/extensions/mutex/yii/mutex/db/Mutex.php deleted file mode 100644 index 17dd68a..0000000 --- a/extensions/mutex/yii/mutex/db/Mutex.php +++ /dev/null @@ -1,51 +0,0 @@ - - * @since 2.0 - */ -abstract class Mutex extends \yii\mutex\Mutex -{ - /** - * @var Connection|string the DB connection object or the application component ID of the DB connection. - * After the Mutex object is created, if you want to change this property, you should only assign - * it with a DB connection object. - */ - public $db = 'db'; - - /** - * Initializes generic database table based mutex implementation. - * @throws InvalidConfigException if [[db]] is invalid. - */ - public function init() - { - parent::init(); - if (is_string($this->db)) { - $this->db = Yii::$app->getComponent($this->db); - } - if (!$this->db instanceof Connection) { - throw new InvalidConfigException('Mutex::db must be either a DB connection instance or the application component ID of a DB connection.'); - } - } - - /** - * This method should be extended by concrete mutex implementations. Returns whether current mutex - * implementation can be used in a distributed environment. - * @return boolean whether current mutex implementation can be used in a distributed environment. - */ - public function getIsDistributed() - { - return true; - } -} diff --git a/extensions/mutex/yii/mutex/db/mssql/Mutex.php b/extensions/mutex/yii/mutex/db/mssql/Mutex.php deleted file mode 100644 index 374100a..0000000 --- a/extensions/mutex/yii/mutex/db/mssql/Mutex.php +++ /dev/null @@ -1,56 +0,0 @@ - - * @since 2.0 - */ -class Mutex extends \yii\mutex\db\Mutex -{ - /** - * Initializes Microsoft SQL Server specific mutex component implementation. - * @throws InvalidConfigException if [[db]] is not Microsoft SQL Server connection. - */ - public function init() - { - parent::init(); - $driverName = $this->db->driverName; - if ($driverName !== 'sqlsrv' && $driverName !== 'dblib' && $driverName !== 'mssql') { - throw new InvalidConfigException(''); - } - } - - /** - * This method should be extended by concrete mutex implementations. Acquires lock by given name. - * @param string $name of the lock to be acquired. - * @param integer $timeout to wait for lock to become released. - * @return boolean acquiring result. - * @throws \BadMethodCallException - * @see http://msdn.microsoft.com/en-us/library/ms189823.aspx - */ - protected function acquire($name, $timeout = 0) - { - throw new \BadMethodCallException('Not implemented yet.'); - } - - /** - * This method should be extended by concrete mutex implementations. Releases lock by given name. - * @param string $name of the lock to be released. - * @return boolean release result. - * @throws \BadMethodCallException - * @see http://msdn.microsoft.com/en-us/library/ms178602.aspx - */ - protected function release($name) - { - throw new \BadMethodCallException('Not implemented yet.'); - } -} diff --git a/extensions/mutex/yii/mutex/db/mysql/Mutex.php b/extensions/mutex/yii/mutex/db/mysql/Mutex.php deleted file mode 100644 index 7153d38..0000000 --- a/extensions/mutex/yii/mutex/db/mysql/Mutex.php +++ /dev/null @@ -1,72 +0,0 @@ - - * @since 2.0 - */ -class Mutex extends \yii\mutex\db\Mutex -{ - /** - * Initializes MySQL specific mutex component implementation. - * @throws InvalidConfigException if [[db]] is not MySQL connection. - */ - public function init() - { - parent::init(); - if ($this->db->driverName !== 'mysql') { - throw new InvalidConfigException(''); - } - } - - /** - * This method should be extended by concrete mutex implementations. Acquires lock by given name. - * @param string $name of the lock to be acquired. - * @param integer $timeout to wait for lock to become released. - * @return boolean acquiring result. - * @see http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_get-lock - */ - protected function acquire($name, $timeout = 0) - { - return (boolean)$this->db - ->createCommand('SELECT GET_LOCK(:name, :timeout)', array(':name' => $name, ':timeout' => $timeout)) - ->queryScalar(); - } - - /** - * This method should be extended by concrete mutex implementations. Releases lock by given name. - * @param string $name of the lock to be released. - * @return boolean release result. - * @see http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_release-lock - */ - protected function release($name) - { - return (boolean)$this->db - ->createCommand('SELECT RELEASE_LOCK(:name)', array(':name' => $name)) - ->queryScalar(); - } - - /** - * This method may optionally be extended by concrete mutex implementations. Checks whether lock has been - * already acquired by given name. - * @param string $name of the lock to be released. - * @return null|boolean whether lock has been already acquired. Returns `null` in case this feature - * is not supported by concrete mutex implementation. - * @see http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_is-free-lock - */ - protected function getIsAcquired($name) - { - return (boolean)$this->db - ->createCommand('SELECT IS_FREE_LOCK(:name)', array(':name' => $name)) - ->queryScalar(); - } -} diff --git a/extensions/mutex/yii/mutex/unix/Mutex.php b/extensions/mutex/yii/mutex/unix/Mutex.php deleted file mode 100644 index ca18a49..0000000 --- a/extensions/mutex/yii/mutex/unix/Mutex.php +++ /dev/null @@ -1,99 +0,0 @@ - - * @since 2.0 - */ -class Mutex extends \yii\mutex\Mutex -{ - /** - * @var resource[] stores all opened lock files. Keys are lock names and values are file handles. - */ - private $_files = array(); - - - /** - * Initializes mutex component implementation dedicated for UNIX, GNU/Linux, Mac OS X, and other UNIX-like - * operating systems. - * @throws InvalidConfigException - */ - public function init() - { - if (stripos(php_uname('s'), 'win') === 0) { - throw new InvalidConfigException(''); - } - } - - /** - * This method should be extended by concrete mutex implementations. Acquires lock by given name. - * @param string $name of the lock to be acquired. - * @param integer $timeout to wait for lock to become released. - * @return boolean acquiring result. - */ - protected function acquire($name, $timeout = 0) - { - $file = fopen(Yii::$app->getRuntimePath() . '/mutex.' . md5($name) . '.lock', 'w+'); - if ($file === false) { - return false; - } - $waitTime = 0; - while (!flock($file, LOCK_EX | LOCK_NB)) { - $waitTime++; - if ($waitTime > $timeout) { - fclose($file); - return false; - } - sleep(1); - } - $this->_files[$name] = $file; - return true; - } - - /** - * This method should be extended by concrete mutex implementations. Releases lock by given name. - * @param string $name of the lock to be released. - * @return boolean release result. - */ - protected function release($name) - { - if (!isset($this->_files[$name]) || !flock($this->_files[$name], LOCK_UN)) { - return false; - } else { - fclose($this->_files[$name]); - unset($this->_files[$name]); - return true; - } - } - - /** - * This method may optionally be extended by concrete mutex implementations. Checks whether lock has been - * already acquired by given name. - * @param string $name of the lock to be released. - * @return null|boolean whether lock has been already acquired. Returns `null` in case this feature - * is not supported by concrete mutex implementation. - */ - protected function getIsAcquired($name) - { - return false; - } - - /** - * This method should be extended by concrete mutex implementations. Returns whether current mutex - * implementation can be used in a distributed environment. - * @return boolean whether current mutex implementation can be used in a distributed environment. - */ - public function getIsDistributed() - { - return false; - } -} From f6d0b4b2471e0f44cea59f8084d04c7bba9a4054 Mon Sep 17 00:00:00 2001 From: resurtm Date: Thu, 4 Jul 2013 21:01:06 +0600 Subject: [PATCH 11/16] Removed MSSQL mutex. --- extensions/mutex/yii/mutex/MssqlMutex.php | 56 ------------------------------- 1 file changed, 56 deletions(-) delete mode 100644 extensions/mutex/yii/mutex/MssqlMutex.php diff --git a/extensions/mutex/yii/mutex/MssqlMutex.php b/extensions/mutex/yii/mutex/MssqlMutex.php deleted file mode 100644 index d267699..0000000 --- a/extensions/mutex/yii/mutex/MssqlMutex.php +++ /dev/null @@ -1,56 +0,0 @@ - - * @since 2.0 - */ -class MssqlMutex extends Mutex -{ - /** - * Initializes Microsoft SQL Server specific mutex component implementation. - * @throws InvalidConfigException if [[db]] is not Microsoft SQL Server connection. - */ - public function init() - { - parent::init(); - $driverName = $this->db->driverName; - if ($driverName !== 'sqlsrv' && $driverName !== 'dblib' && $driverName !== 'mssql') { - throw new InvalidConfigException('In order to use MssqlMutex connection must be configured to use MS SQL Server database.'); - } - } - - /** - * This method should be extended by concrete mutex implementations. Acquires lock by given name. - * @param string $name of the lock to be acquired. - * @param integer $timeout to wait for lock to become released. - * @return boolean acquiring result. - * @throws \BadMethodCallException not implemented yet. - * @see http://msdn.microsoft.com/en-us/library/ms189823.aspx - */ - protected function acquireLock($name, $timeout = 0) - { - throw new \BadMethodCallException('Not implemented yet.'); - } - - /** - * This method should be extended by concrete mutex implementations. Releases lock by given name. - * @param string $name of the lock to be released. - * @return boolean release result. - * @throws \BadMethodCallException not implemented yet. - * @see http://msdn.microsoft.com/en-us/library/ms178602.aspx - */ - protected function releaseLock($name) - { - throw new \BadMethodCallException('Not implemented yet.'); - } -} From 33ca13e4982b161d2961a56b9272b67c9ed5e323 Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Thu, 4 Jul 2013 19:38:09 +0400 Subject: [PATCH 12/16] fixed method name --- framework/yii/helpers/base/SecurityHelper.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/yii/helpers/base/SecurityHelper.php b/framework/yii/helpers/base/SecurityHelper.php index f646a24..546ed21 100644 --- a/framework/yii/helpers/base/SecurityHelper.php +++ b/framework/yii/helpers/base/SecurityHelper.php @@ -186,7 +186,7 @@ class SecurityHelper * // ...save $hash in database... * * // during login, validate if the password entered is correct using $hash fetched from database - * if (SecurityHelper::verifyPassword($password, $hash) { + * if (SecurityHelper::validatePassword($password, $hash) { * // password is good * } else { * // password is bad From 8ea5fcb5616b730fd36cdb78e23eb07ebdb8ef0f Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Thu, 4 Jul 2013 20:02:23 +0200 Subject: [PATCH 13/16] Update database-basics.md Database name consistency --- docs/guide/database-basics.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/database-basics.md b/docs/guide/database-basics.md index ade5968..71510f4 100644 --- a/docs/guide/database-basics.md +++ b/docs/guide/database-basics.md @@ -25,7 +25,7 @@ return array( //'dsn' => 'sqlsrv:Server=localhost;Database=mydatabase', // MS SQL Server, sqlsrv driver //'dsn' => 'dblib:host=localhost;dbname=mydatabase', // MS SQL Server, dblib driver //'dsn' => 'mssql:host=localhost;dbname=mydatabase', // MS SQL Server, mssql driver - //'dsn' => 'oci:dbname=//localhost:1521/testdb', // Oracle + //'dsn' => 'oci:dbname=//localhost:1521/mydatabase', // Oracle 'username' => 'root', 'password' => '', 'charset' => 'utf8', From 13f1e7af8a526296377e050734cd85b95b75b358 Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Thu, 4 Jul 2013 22:17:43 +0200 Subject: [PATCH 14/16] added usage example to Response::redirect() --- framework/yii/web/Response.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/framework/yii/web/Response.php b/framework/yii/web/Response.php index 5b15fbb..1e594aa 100644 --- a/framework/yii/web/Response.php +++ b/framework/yii/web/Response.php @@ -557,6 +557,12 @@ class Response extends \yii\base\Response * }); * ~~~ * + * In a controller action you may use this method like this: + * + * ~~~ + * return Yii::$app->getResponse()->redirect($url); + * ~~~ + * * @param array|string $url the URL to be redirected to. [[\yii\helpers\Html::url()]] * will be used to normalize the URL. If the resulting URL is still a relative URL * (one without host info), the current request host info will be used. @@ -584,6 +590,13 @@ class Response extends \yii\base\Response * Refreshes the current page. * The effect of this method call is the same as the user pressing the refresh button of his browser * (without re-posting data). + * + * In a controller action you may use this method like this: + * + * ~~~ + * return Yii::$app->getResponse()->refresh(); + * ~~~ + * * @param string $anchor the anchor that should be appended to the redirection URL. * Defaults to empty. Make sure the anchor starts with '#' if you want to specify it. * @return Response the response object itself From 65cd163c69b169d221cb13b0ff055c7d928db763 Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Fri, 5 Jul 2013 00:52:15 +0400 Subject: [PATCH 15/16] query builder guide --- docs/guide/query-builder.md | 235 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 235 insertions(+) diff --git a/docs/guide/query-builder.md b/docs/guide/query-builder.md index e69de29..c707ddda6 100644 --- a/docs/guide/query-builder.md +++ b/docs/guide/query-builder.md @@ -0,0 +1,235 @@ +Query Builder and Query +======================= + +Yii provides a basic database access layer as was described in [Database basics](database-basics.md) section. Still it's +a bit too much to use SQL directly all the time. To solve the issue Yii provides a query builder that allows you to +work with the database in object-oriented style. + +Basic query builder usage is the following: + +```php +$query = new Query; + +// Define query +$query->select('id, name') + ->from('tbl_user') + ->limit(10); + +// Create a command. You can get the actual SQL using $command->sql +$command = $query->createCommand(); +// Execute command +$rows = $command->queryAll(); +``` + +Basic selects and joins +----------------------- + +In order to form a `SELECT` query you need to specify what to select and where to select it from. + +```php +$query->select('id, name') + ->from('tbl_user'); +``` + +If you want to get IDs of all users with posts you can use `DISTINCT`. With query builder it will look like the following: + +```php +$query->select('user_id')->distinct()->from('tbl_post'); +``` + +Select options can be specified as array. It's especially useful when these are formed dynamically. + +```php +$query->select(array('tbl_user.name AS author', 'tbl_post.title as title')) // <-- specified as array + ->from('tbl_user') + ->leftJoin('tbl_post', 'tbl_post.user_id = tbl_user.id'); // <-- join with another table +``` + +In the code above we've used `leftJoin` method to select from two related tables at the same time. Firsrt parameter +specifies table name and the second is the join condition. Query builder has the following methods to join tables: + +- `innerJoin` +- `leftJoin` +- `rightJoin` + +If your data storage supports more types you can use generic `join` method: + +```php +$query->join('FULL OUTER JOIN', 'tbl_post', 'tbl_post.user_id = tbl_user.id'); +``` + +Specifying conditions +--------------------- + +Usually you need data that matches some conditions. There are some useful methods to specify these and the most powerful +is `where`. There are multiple ways to use it. + +The simplest is to specify condition in a string: + +```php +$query->where('status=:status', array( + ':status' => $status, +)); +``` + +When using this format make sure you're binding parameters and not creating a query by string concatenation. + +Instead of binding status value immediately you can do it using `params` or `addParams`: + +```php +$query->where('status=:status'); + +$query->addParams(array( + ':status' => $status, +)); +``` + +There is another convenient way to use the method called hash format: + +```php +$query->where(array( + 'status' => 10, + 'type' => 2, + 'id' => array(4, 8, 15, 16, 23, 42), +)); +``` + +It will generate the following SQL: + +```sql +WHERE (`status` = 10) AND (`type` = 2) AND (`id` IN (4, 8, 15, 16, 23, 42)) +``` + +If you'll specify value as `null` such as the following: + +```php +$query->where(array( + 'status' => null, +)); +``` + +SQL generated will be: + +```sql +WHERE (`status` IS NULL) +``` + +Another way to use the method is the operand format which is `array(operator, operand1, operand2, ...)`. + +Operator can be one of the following: + +- `and`: the operands should be concatenated together using `AND`. For example, + `array('and', 'id=1', 'id=2')` will generate `id=1 AND id=2`. If an operand is an array, + it will be converted into a string using the rules described here. For example, + `array('and', 'type=1', array('or', 'id=1', 'id=2'))` will generate `type=1 AND (id=1 OR id=2)`. + The method will NOT do any quoting or escaping. +- `or`: similar to the `and` operator except that the operands are concatenated using `OR`. +- `between`: operand 1 should be the column name, and operand 2 and 3 should be the + starting and ending values of the range that the column is in. + For example, `array('between', 'id', 1, 10)` will generate `id BETWEEN 1 AND 10`. +- `not between`: similar to `between` except the `BETWEEN` is replaced with `NOT BETWEEN` + in the generated condition. +- `in`: operand 1 should be a column or DB expression, and operand 2 be an array representing + the range of the values that the column or DB expression should be in. For example, + `array('in', 'id', array(1, 2, 3))` will generate `id IN (1, 2, 3)`. + The method will properly quote the column name and escape values in the range. +- `not in`: similar to the `in` operator except that `IN` is replaced with `NOT IN` in the generated condition. +- `like`: operand 1 should be a column or DB expression, and operand 2 be a string or an array representing + the values that the column or DB expression should be like. + For example, `array('like', 'name', '%tester%')` will generate `name LIKE '%tester%'`. + When the value range is given as an array, multiple `LIKE` predicates will be generated and concatenated + using `AND`. For example, `array('like', 'name', array('%test%', '%sample%'))` will generate + `name LIKE '%test%' AND name LIKE '%sample%'`. + The method will properly quote the column name and escape values in the range. +- `or like`: similar to the `like` operator except that `OR` is used to concatenate the `LIKE` + predicates when operand 2 is an array. +- `not like`: similar to the `like` operator except that `LIKE` is replaced with `NOT LIKE` + in the generated condition. +- `or not like`: similar to the `not like` operator except that `OR` is used to concatenate + the `NOT LIKE` predicates. + +If you are building parts of condition dynamically it's very convenient to use `andWhere` and `orWhere`: + +```php +$status = 10; +$search = 'yii'; + +$query->where(array('status' => $status)); +if (!empty($search)) { + $query->addWhere('like', 'title', $search); +} +``` + +In case `$search` isn't empty the following SQL will be generated: + +```sql +WHERE (`status` = 10) AND (`title` LIKE '%yii%') +``` + +Order +----- + +For odering results `orderBy` and `addOrderBy` could be used: + +```php +$query->orderBy(array( + 'id' => Query::SORT_ASC, + 'name' => Query::SORT_DESC, +)); +``` + +Here we are ordering by `id` ascending and then by `name` descending. + +Group and Having +---------------- + +In order to add `GROUP BY` to generated SQL you can use the following: + +```php +$query->groupBy('id, status'); +``` + +If you want to add another field after using `groupBy`: + +```php +$query->addGroupBy(array('created_at', 'updated_at')); +``` + +To add a `HAVING` condition the corresponding `having` method and its `andHaving` and `orHaving` can be used. Parameters +for these are similar to the ones for `where` methods group: + +```php +$query->having(array('status' => $status)); +``` + +Limit and offset +---------------- + +To limit result to 10 rows `limit` can be used: + +```php +$query->limit(10); +``` + +To skip 100 fist rows use: + +```php +$query->offset(100); +``` + +Union +----- + +`UNION` in SQL adds results of one query to results of another query. Columns returned by both queries should match. +In Yii in order to build it you can first form two query objects and then use `union` method: + +```php +$query = new Query; +$query->select("id, 'post' as type, name")->from('tbl_post')->limit(10); + +$anotherQuery = new Query; +$query->select('id, 'user' as type, name')->from('tbl_user')->limit(10); + +$query->union($anotherQuery); +``` + From 4293c28a2cc7f30c222b55fe920b01d1853c93df Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Fri, 5 Jul 2013 01:09:17 +0400 Subject: [PATCH 16/16] validation draft --- docs/guide/validation.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/docs/guide/validation.md b/docs/guide/validation.md index e69de29..7bfeb96 100644 --- a/docs/guide/validation.md +++ b/docs/guide/validation.md @@ -0,0 +1,28 @@ +Model validation reference +========================== + +This guide section doesn't describe how validation works but instead describes all Yii validators and their parameters. +In order to learn model validation basics please refer to [Model, Validation subsection](model.md#Validation). + +Standard Yii validators +----------------------- + +- `boolean`: [[BooleanValidator]] +- `captcha`: [[CaptchaValidator]] +- `compare`: [[CompareValidator]] +- `date`: [[DateValidator]] +- `default`: [[DefaultValueValidator]] +- `double`: [[NumberValidator]] +- `email`: [[EmailValidator]] +- `exist`: [[ExistValidator]] +- `file`: [[FileValidator]] +- `filter`: [[FilterValidator]] +- `in`: [[RangeValidator]] +- `integer`: [[NumberValidator]] +- `match`: [[RegularExpressionValidator]] +- `required`: [[RequiredValidator]] +- `string`: [[StringValidator]] +- `unique`: [[UniqueValidator]] +- `url`: [[UrlValidator]] + +TBD: refer to http://www.yiiframework.com/wiki/56/ for the format \ No newline at end of file