From 79e68d3d1c1d9849679e8d1f2e8f7559d8774824 Mon Sep 17 00:00:00 2001 From: Tobias Sette Date: Fri, 4 May 2018 11:45:23 -0300 Subject: [PATCH 1/7] Add NullCache for backend cache --- Library/Phalcon/Cache/Backend/NullCache.php | 72 +++++++++++++++++++++ Library/Phalcon/Cache/Backend/README.md | 5 ++ 2 files changed, 77 insertions(+) create mode 100644 Library/Phalcon/Cache/Backend/NullCache.php diff --git a/Library/Phalcon/Cache/Backend/NullCache.php b/Library/Phalcon/Cache/Backend/NullCache.php new file mode 100644 index 000000000..3a8d3c31f --- /dev/null +++ b/Library/Phalcon/Cache/Backend/NullCache.php @@ -0,0 +1,72 @@ + Date: Thu, 17 May 2018 04:13:28 -0300 Subject: [PATCH 2/7] Fix problems pointed out by Sergey --- Library/Phalcon/Cache/Backend/NullCache.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Library/Phalcon/Cache/Backend/NullCache.php b/Library/Phalcon/Cache/Backend/NullCache.php index 3a8d3c31f..8d42fba14 100644 --- a/Library/Phalcon/Cache/Backend/NullCache.php +++ b/Library/Phalcon/Cache/Backend/NullCache.php @@ -3,6 +3,7 @@ namespace Phalcon\Cache\Backend; use Phalcon\Cache\BackendInterface; +use Phalcon\Cache\Frontend\None as NoneFrontend; /** * A cache adapter that does nothing. @@ -11,6 +12,7 @@ final class NullCache implements BackendInterface { public function start($keyName, $lifetime = null) { + return true; } public function stop($stopBuffer = true) @@ -19,6 +21,7 @@ public function stop($stopBuffer = true) public function getFrontend() { + return NoneFrontend; } public function getOptions() From c5587471b6a42c0e5f96a506ba9a1bd3e665dc6b Mon Sep 17 00:00:00 2001 From: Tobias Sette Date: Fri, 25 May 2018 19:15:25 -0300 Subject: [PATCH 3/7] Fix NullCache::getFrontend and description in README.md --- Library/Phalcon/Cache/Backend/NullCache.php | 2 +- Library/Phalcon/Cache/Backend/README.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Library/Phalcon/Cache/Backend/NullCache.php b/Library/Phalcon/Cache/Backend/NullCache.php index 8d42fba14..3deb61450 100644 --- a/Library/Phalcon/Cache/Backend/NullCache.php +++ b/Library/Phalcon/Cache/Backend/NullCache.php @@ -21,7 +21,7 @@ public function stop($stopBuffer = true) public function getFrontend() { - return NoneFrontend; + return NoneFrontend(); } public function getOptions() diff --git a/Library/Phalcon/Cache/Backend/README.md b/Library/Phalcon/Cache/Backend/README.md index ec452f979..a48dc0c05 100644 --- a/Library/Phalcon/Cache/Backend/README.md +++ b/Library/Phalcon/Cache/Backend/README.md @@ -97,9 +97,9 @@ echo $time; This adapter uses [windows cache extension](http://pecl.php.net/package/wincache) for PHP -## Null +## NullCache -Null adapter can be useful when you have dependency injection and wants to provider an Adapter that does nothing. +NullCache adapter can be useful when you have dependency injection and wants to provider an Adapter that does nothing. [1]: http://www.aerospike.com/ [2]: http://www.aerospike.com/docs/client/php/install/ From 5d751253039c4b80b0c07bde4ab896936a0bff38 Mon Sep 17 00:00:00 2001 From: Tobias Sette Date: Wed, 30 May 2018 20:25:57 -0300 Subject: [PATCH 4/7] Fix NullCache::getFrontend() and add tests --- Library/Phalcon/Cache/Backend/NullCache.php | 2 +- tests/unit/Cache/Backend/NullCacheTest.php | 135 ++++++++++++++++++++ 2 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 tests/unit/Cache/Backend/NullCacheTest.php diff --git a/Library/Phalcon/Cache/Backend/NullCache.php b/Library/Phalcon/Cache/Backend/NullCache.php index 3deb61450..f24a3caf6 100644 --- a/Library/Phalcon/Cache/Backend/NullCache.php +++ b/Library/Phalcon/Cache/Backend/NullCache.php @@ -21,7 +21,7 @@ public function stop($stopBuffer = true) public function getFrontend() { - return NoneFrontend(); + return new NoneFrontend(); } public function getOptions() diff --git a/tests/unit/Cache/Backend/NullCacheTest.php b/tests/unit/Cache/Backend/NullCacheTest.php new file mode 100644 index 000000000..27a15da4d --- /dev/null +++ b/tests/unit/Cache/Backend/NullCacheTest.php @@ -0,0 +1,135 @@ + + * @package Phalcon\Test\Cache\Backend + * @group db + * + * The contents of this file are subject to the New BSD License that is + * bundled with this package in the file docs/LICENSE.txt + * + * If you did not receive a copy of the license and are unable to obtain it + * through the world-wide-web, please send an email to license@phalconphp.com + * so that we can send you a copy immediately. + */ +class NullCacheTest extends Test +{ + public function testStartShouldAlwaysReturnTrue() + { + $nullCache = new NullCache(); + + $this->assertTrue($nullCache->start('fooBar')); + $this->assertTrue($nullCache->start('fooBar'), 1000); + } + + public function testFrontendShouldBeNone() + { + $nullCache = new NullCache(); + + $this->assertInstanceOf(NoneFrontend::class, $nullCache->getFrontend()); + } + + public function testGetOptionsShouldReturnEmptyArray() + { + $nullCache = new NullCache(); + + $this->assertEquals([], $nullCache->getOptions()); + } + + public function testCacheShouldAlwaysBeFresh() + { + $nullCache = new NullCache(); + + $this->assertTrue($nullCache->isFresh()); + } + + public function testCacheShouldAlwaysBeStarted() + { + $nullCache = new NullCache(); + + $this->assertTrue($nullCache->isStarted()); + + $nullCache->start('fooBar'); + $this->assertTrue($nullCache->isStarted()); + + $nullCache->stop(); + $this->assertTrue($nullCache->isStarted()); + } + + public function testLastKeyShouldBeEmpty() + { + $nullCache = new NullCache(); + + $this->assertEquals('', $nullCache->getLastKey()); + } + + public function testGetSomethingFromCacheShouldAlwaysReturnNull() + { + $nullCache = new NullCache(); + + $this->assertEquals(null, $nullCache->get('fooBar')); + $this->assertEquals(null, $nullCache->get('fooBar', 1000)); + $this->assertEquals(null, $nullCache->get('fooBar', 0)); + + $nullCache->save('fooBar', 'baz', 1000); + $this->assertEquals(null, $nullCache->get('fooBar')); + $this->assertEquals(null, $nullCache->get('fooBar', 1000)); + $this->assertEquals(null, $nullCache->get('fooBar', 0)); + } + + public function testSaveSomethingToCacheShouldAlwaysReturnTrue() + { + $nullCache = new NullCache(); + + $this->assertTrue($nullCache->save('fooBar', null)); + $this->assertTrue($nullCache->save('fooBar', 'baz')); + $this->assertTrue($nullCache->save('fooBar', 'baz', 1000)); + $this->assertTrue($nullCache->save('fooBar', 'baz', 1000, true)); + $this->assertTrue($nullCache->save('fooBar', 'baz', 1000, false)); + } + + public function testDeleteSomethingFromCacheShouldAlwaysReturnTrue() + { + $nullCache = new NullCache(); + + $this->assertTrue($nullCache->delete('fooBar')); + $this->assertFalse($nullCache->exists('fooBar')); + + $randomKey = 'randomKey' . uniqid('NullCache', true); + $this->assertTrue($nullCache->delete($randomKey)); + $this->assertFalse($nullCache->exists($randomKey)); + } + + public function testQueryKeysShouldReturnEmptyArray() + { + $nullCache = new NullCache(); + + $this->assertEquals([], $nullCache->queryKeys()); + $this->assertEquals([], $nullCache->queryKeys('fooBar')); + } + + public function testNoKeyWillEverExistsInTheCache() + { + $nullCache = new NullCache(); + + $this->assertFalse($nullCache->exists('fooBar')); + + $this->assertTrue($nullCache->save('fooBar', 'baz')); + $this->assertFalse($nullCache->exists('fooBar')); + + $randomKey = 'randomKey' . uniqid('NullCache', true); + $this->assertTrue($nullCache->save('fooBar', $randomKey)); + $this->assertFalse($nullCache->exists($randomKey)); + } +} From 3617a1ccd7d508870b691a824d548a0f866bcff0 Mon Sep 17 00:00:00 2001 From: fabioviana Date: Wed, 20 Jun 2018 18:09:33 +0100 Subject: [PATCH 5/7] JSON_EXTRACT to extended MySQL dialect --- Library/Phalcon/Db/Dialect/MysqlExtended.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Library/Phalcon/Db/Dialect/MysqlExtended.php b/Library/Phalcon/Db/Dialect/MysqlExtended.php index fb553971f..f320bf95d 100644 --- a/Library/Phalcon/Db/Dialect/MysqlExtended.php +++ b/Library/Phalcon/Db/Dialect/MysqlExtended.php @@ -128,6 +128,22 @@ public function getSqlExpression(array $expression, $escapeChar = null, $bindCou return $this->getSqlExpression($expression['arguments'][0]) . ' REGEXP (' . $this->getSqlExpression($expression['arguments'][1]) . ')'; break; + + case 'JSON_EXTRACT': + if (count($expression["arguments"]) < 2) { + throw new Exception('JSON_EXTRACT requires 2 parameters'); + } + + $arguments = []; + $length = count($expression["arguments"]); + for ($i = 0; $i < $length; $i++) { + $arguments[] = $i === 0 ? + $this->getSqlExpression($expression["arguments"][$i]) : + $expression["arguments"][$i]['value']; + } + + return 'JSON_EXTRACT(' . join(', ', $arguments) . ')'; + break; } } From c268f3e8713d77dce392a0e26c119b5bd6c1efda Mon Sep 17 00:00:00 2001 From: Kevin Andrews Date: Tue, 16 Oct 2018 15:40:45 +0100 Subject: [PATCH 6/7] Prevent session data from being re-persisted if closed or destroyed --- Library/Phalcon/Session/Adapter/Database.php | 42 ++++++++++++-------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/Library/Phalcon/Session/Adapter/Database.php b/Library/Phalcon/Session/Adapter/Database.php index d8a73e659..1bd8ae366 100644 --- a/Library/Phalcon/Session/Adapter/Database.php +++ b/Library/Phalcon/Session/Adapter/Database.php @@ -87,7 +87,8 @@ public function __construct($options = null) */ public function open() { - return true; + $this->_started = true; + return $this->isStarted(); } /** @@ -97,7 +98,8 @@ public function open() */ public function close() { - return false; + $this->_started = false; + return $this->isStarted(); } /** @@ -109,7 +111,11 @@ public function close() public function read($sessionId) { $maxLifetime = (int) ini_get('session.gc_maxlifetime'); - + + if (!$this->isStarted()) { + return false; + } + $options = $this->getOptions(); $row = $this->connection->fetchOne( sprintf( @@ -152,7 +158,7 @@ public function write($sessionId, $data) Db::FETCH_NUM, [$sessionId] ); - + if ($row[0] > 0) { return $this->connection->execute( sprintf( @@ -164,19 +170,23 @@ public function write($sessionId, $data) ), [$data, time(), $sessionId] ); - } else { - return $this->connection->execute( - sprintf( - 'INSERT INTO %s (%s, %s, %s, %s) VALUES (?, ?, ?, NULL)', - $this->connection->escapeIdentifier($options['table']), - $this->connection->escapeIdentifier($options['column_session_id']), - $this->connection->escapeIdentifier($options['column_data']), - $this->connection->escapeIdentifier($options['column_created_at']), - $this->connection->escapeIdentifier($options['column_modified_at']) - ), - [$sessionId, $data, time()] - ); } + + if (!$this->isStarted()) { + return false; + } + + return $this->connection->execute( + sprintf( + 'INSERT INTO %s (%s, %s, %s, %s) VALUES (?, ?, ?, NULL)', + $this->connection->escapeIdentifier($options['table']), + $this->connection->escapeIdentifier($options['column_session_id']), + $this->connection->escapeIdentifier($options['column_data']), + $this->connection->escapeIdentifier($options['column_created_at']), + $this->connection->escapeIdentifier($options['column_modified_at']) + ), + [$sessionId, $data, time()] + ); } /** From 278c360c344f986d99d30ad4c2faaf979eeb819a Mon Sep 17 00:00:00 2001 From: David Date: Fri, 16 Nov 2018 12:45:45 +0100 Subject: [PATCH 7/7] Add arrayFilter option (#868) --- .../Db/Adapter/MongoDB/Operation/Update.php | 76 +++++++++++-------- 1 file changed, 46 insertions(+), 30 deletions(-) diff --git a/Library/Phalcon/Db/Adapter/MongoDB/Operation/Update.php b/Library/Phalcon/Db/Adapter/MongoDB/Operation/Update.php index 7caf394c5..f58b74510 100644 --- a/Library/Phalcon/Db/Adapter/MongoDB/Operation/Update.php +++ b/Library/Phalcon/Db/Adapter/MongoDB/Operation/Update.php @@ -36,7 +36,7 @@ */ class Update implements Executable { - private static $wireVersionForDocumentLevelValidation=4; + private static $wireVersionForDocumentLevelValidation = 4; private $databaseName; private $collectionName; @@ -61,31 +61,31 @@ class Update implements Executable * * * writeConcern (MongoDB\Driver\WriteConcern): Write concern. * - * @param string $databaseName Database name - * @param string $collectionName Collection name + * @param string $databaseName Database name + * @param string $collectionName Collection name * @param array|object $filter Query by which to delete documents * @param array|object $update Update to apply to the matched * document(s) or a replacement document - * @param array $options Command options + * @param array $options Command options * * @throws InvalidArgumentException */ public function __construct($databaseName, $collectionName, $filter, $update, array $options = []) { - if (!is_array($filter)&&!is_object($filter)) { + if (! is_array($filter) && ! is_object($filter)) { throw InvalidArgumentException::invalidType('$filter', $filter, 'array or object'); } - if (!is_array($update)&&!is_object($update)) { + if (! is_array($update) && ! is_object($update)) { throw InvalidArgumentException::invalidType('$update', $filter, 'array or object'); } - $options+=[ - 'multi' =>false, - 'upsert'=>false, + $options += [ + 'multi' => false, + 'upsert' => false, ]; - if (isset($options['bypassDocumentValidation'])&&!is_bool($options['bypassDocumentValidation'])) { + if (isset($options['bypassDocumentValidation']) && ! is_bool($options['bypassDocumentValidation'])) { throw InvalidArgumentException::invalidType( '"bypassDocumentValidation" option', $options['bypassDocumentValidation'], @@ -93,19 +93,27 @@ public function __construct($databaseName, $collectionName, $filter, $update, ar ); } - if (!is_bool($options['multi'])) { - throw InvalidArgumentException::invalidType('"multi" option', $options['multi'], 'boolean'); + if (! is_bool($options['multi'])) { + throw InvalidArgumentException::invalidType( + '"multi" option', + $options['multi'], + 'boolean' + ); } - if ($options['multi']&&!Functions::isFirstKeyOperator($update)) { + if ($options['multi'] && ! Functions::isFirstKeyOperator($update)) { throw new InvalidArgumentException('"multi" option cannot be true if $update is a replacement document'); } - if (!is_bool($options['upsert'])) { - throw InvalidArgumentException::invalidType('"upsert" option', $options['upsert'], 'boolean'); + if (! is_bool($options['upsert'])) { + throw InvalidArgumentException::invalidType( + '"upsert" option', + $options['upsert'], + 'boolean' + ); } - if (isset($options['writeConcern'])&&!$options['writeConcern'] instanceof WriteConcern) { + if (isset($options['writeConcern']) && ! $options['writeConcern'] instanceof WriteConcern) { throw InvalidArgumentException::invalidType( '"writeConcern" option', $options['writeConcern'], @@ -113,11 +121,11 @@ public function __construct($databaseName, $collectionName, $filter, $update, ar ); } - $this->databaseName =(string)$databaseName; - $this->collectionName=(string)$collectionName; - $this->filter =$filter; - $this->update =$update; - $this->options =$options; + $this->databaseName = (string)$databaseName; + $this->collectionName = (string)$collectionName; + $this->filter = $filter; + $this->update = $update; + $this->options = $options; } /** @@ -131,26 +139,34 @@ public function __construct($databaseName, $collectionName, $filter, $update, ar */ public function execute(Server $server) { - $updateOptions=[ - 'multi' =>$this->options['multi'], - 'upsert'=>$this->options['upsert'], + $updateOptions = [ + 'multi' => $this->options['multi'], + 'upsert' => $this->options['upsert'] ]; - $bulkOptions=[]; + if (isset($this->options['arrayFilters'])) { + $updateOptions['arrayFilters'] = $this->options['arrayFilters']; + } + + $bulkOptions = []; - if (isset($this->options['bypassDocumentValidation'])&&Functions::serverSupportsFeature( + if (isset($this->options['bypassDocumentValidation']) && Functions::serverSupportsFeature( $server, self::$wireVersionForDocumentLevelValidation ) ) { - $bulkOptions['bypassDocumentValidation']=$this->options['bypassDocumentValidation']; + $bulkOptions['bypassDocumentValidation'] = $this->options['bypassDocumentValidation']; } - $bulk=new Bulk($bulkOptions); + $bulk = new Bulk($bulkOptions); $bulk->update($this->filter, $this->update, $updateOptions); - $writeConcern=isset($this->options['writeConcern'])?$this->options['writeConcern']:null; - $writeResult =$server->executeBulkWrite($this->databaseName.'.'.$this->collectionName, $bulk, $writeConcern); + $writeConcern = isset($this->options['writeConcern']) ? $this->options['writeConcern'] : null; + $writeResult = $server->executeBulkWrite( + $this->databaseName . '.' . $this->collectionName, + $bulk, + $writeConcern + ); return new UpdateResult($writeResult); }