diff --git a/.travis.yml b/.travis.yml index 964ca188b05..c4725b9eeb9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -38,7 +38,7 @@ services: env: global: - CC="gcc" - - ZEPHIR_VERSION="0.12.19" + - ZEPHIR_VERSION="0.12.21" - ZEPHIR_PARSER_VERSION="v1.3.6" - REPORT_COVERAGE=0 - PATH="${HOME}/.composer/vendor/bin:${PATH}" diff --git a/CHANGELOG-4.1.md b/CHANGELOG-4.1.md index 209508b18d8..cb38dd8de9e 100644 --- a/CHANGELOG-4.1.md +++ b/CHANGELOG-4.1.md @@ -1,4 +1,21 @@ -# [4.1.1](https://github.com/phalcon/cphalcon/releases/tag/v4.1.0) (xxxx-xx-xx) +# [4.1.4](https://github.com/phalcon/cphalcon/releases/tag/v4.1.3) (xxxx-xx-xx) + +# [4.1.3](https://github.com/phalcon/cphalcon/releases/tag/v4.1.3) (2022-01-06) + +## Fixed + +- Fixed `Phalcon\Mvc\Model::getRelated()` to correctly return relationships (cached or not) when the foreign key has changed [#15649](https://github.com/phalcon/cphalcon/issues/15649) + + +# [4.1.2](https://github.com/phalcon/cphalcon/releases/tag/v4.1.2) (2021-04-22) + +## Changed +- Corrected version in package.xml + +# [4.1.1](https://github.com/phalcon/cphalcon/releases/tag/v4.1.1) (2021-04-21) + +## Changed +- Corrected max PHP version for PECL ## Fixed - Fixed `Logger\Log::log()` `log` to recognize all log levels [#15214](https://github.com/phalcon/cphalcon/issues/15214) diff --git a/appveyor.yml b/appveyor.yml index abfd7b2c650..4d891982851 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -5,7 +5,7 @@ # For the full copyright and license information, please view # the LICENSE.txt file that was distributed with this source code. -version: 4.1.0+{build} +version: 4.1.2+{build} environment: matrix: @@ -29,22 +29,12 @@ environment: BUILD_TYPE: nts-Win32 APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - - PHP_VERSION: '7.2' - VC_VERSION: '15' - BUILD_TYPE: Win32 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - - - PHP_VERSION: '7.2' - VC_VERSION: '15' - BUILD_TYPE: nts-Win32 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - PHP_AVM: https://raw.githubusercontent.com/sergeyklay/php-appveyor/master/php-appveyor.psm1 PHP_SDK_VERSION: 2.1.9 ZEPHIR_PARSER_VERSION: 1.3.4 ZEPHIR_PARSER_RELEASE: 526 - ZEPHIR_VERSION: 0.12.19 + ZEPHIR_VERSION: 0.12.21 TEST_PHP_EXECUTABLE: C:\php\php.exe NO_INTERACTION: 1 diff --git a/boxfile.7.4.yml b/boxfile.7.4.yml new file mode 100644 index 00000000000..4d7813dcb8a --- /dev/null +++ b/boxfile.7.4.yml @@ -0,0 +1,159 @@ +run.config: + engine: php + engine.config: + runtime: php-7.4 + extensions: + - apcu + - ctype + - curl + - dom + - fileinfo + - gd + - gmp + - gettext + - imagick + - iconv + - intl + - json + - mbstring + - memcached + - phar + - pdo + - pdo_mysql + - pdo_pgsql + - pdo_sqlite + - session + - simplexml + - sqlite3 + - tokenizer + - yaml + - xml + - xmlwriter + - zip + - zlib + - mongodb + - redis + zend_extensions: + - opcache + dev_zend_extensions: + # Removed xdebug (will be back when Xdebug 2.7.0 is stable) + # add: + # - xdebug + rm: + - opcache + extra_packages: + - autoconf + - freefonts + - freetype2 + - fontconfig + - mysql-client + # - postgresql94-client + - re2c + - sqlite3 + extra_steps: + #=========================================================================== + # PSR extension compilation + - | + ( + CURRENT_FOLDER=$(pwd) + rm -fR $CURRENT_FOLDER/build/php-psr + cd $CURRENT_FOLDER/build + git clone --depth=1 https://github.com/jbboehr/php-psr.git + cd php-psr + set -e + phpize + ./configure --with-php-config=$(which php-config) + make -j"$(getconf _NPROCESSORS_ONLN)" + make install + cd $CURRENT_FOLDER + rm -fR $CURRENT_FOLDER/build/php-psr + unset CURRENT_FOLDER + ) + - echo -e 'extension=psr.so' >> "/data/etc/php/dev_php.ini" + #=========================================================================== + # Msgpack extension compilation + - | + ( + CURRENT_FOLDER=$(pwd) + rm -fR $CURRENT_FOLDER/build/msgpack-php + cd $CURRENT_FOLDER/build + git clone --depth=1 https://github.com/msgpack/msgpack-php.git + cd msgpack-php + set -e + phpize + ./configure --with-php-config=$(which php-config) + make -j"$(getconf _NPROCESSORS_ONLN)" + make install + cd $CURRENT_FOLDER + rm -fR $CURRENT_FOLDER/build/msgpack-php + unset CURRENT_FOLDER + ) + - echo -e 'extension=msgpack.so' >> "/data/etc/php/dev_php.ini" + #=========================================================================== + # Igbinary extension compilation + - | + ( + CURRENT_FOLDER=$(pwd) + rm -fR $CURRENT_FOLDER/build/igbinary + cd $CURRENT_FOLDER/build + git clone --depth=1 https://github.com/igbinary/igbinary.git + cd igbinary + set -e + phpize + ./configure --with-php-config=$(which php-config) + make -j"$(getconf _NPROCESSORS_ONLN)" + make install + cd $CURRENT_FOLDER + rm -fR $CURRENT_FOLDER/build/igbinary + unset CURRENT_FOLDER + ) + - echo -e 'extension=igbinary.so' >> "/data/etc/php/dev_php.ini" + #=========================================================================== + # Zephir Parser + - | + ( + CURRENT_FOLDER=$(pwd) + rm -fR $CURRENT_FOLDER/build/php-zephir-parser + cd $CURRENT_FOLDER/build + git clone --depth=1 https://github.com/phalcon/php-zephir-parser.git + cd php-zephir-parser + set -e + phpize + ./configure --with-php-config=$(which php-config) + make -j"$(getconf _NPROCESSORS_ONLN)" + make install + cd $CURRENT_FOLDER + rm -fR $CURRENT_FOLDER/build/php-zephir-parser + unset CURRENT_FOLDER + ) + - echo -e 'extension=zephir_parser.so' >> "/data/etc/php/dev_php.ini" + #=========================================================================== + # This is here so that Phalcon can be used right after compilation + - echo -e 'extension=phalcon.so' >> "/data/etc/php/dev_php.ini" + #=========================================================================== + # Options for session, opcache and apcu + - echo -e 'session.save_path="/tmp"' >> "/data/etc/php/dev_php.ini" + - echo -e 'opcache.enable_cli=1' >> "/data/etc/php/dev_php.ini" + - echo -e 'apcu.enabled=1' >> "/data/etc/php/dev_php.ini" + - echo -e 'apcu.enable_cli=1' >> "/data/etc/php/dev_php.ini" + - echo -e 'apc.enabled=1' >> "/data/etc/php/dev_php.ini" + - echo -e 'apc.enable_cli=1' >> "/data/etc/php/dev_php.ini" + #=========================================================================== + # Get the Zephir phar + - wget --no-clobber -O /data/bin/zephir https://github.com/phalcon/zephir/releases/download/0.12.21/zephir.phar + - chmod +x /data/bin/zephir + +data.memcached: + image: nanobox/memcached:1.4 + +data.mongodb: + image: mongo:4.0 + +data.mysql: + image: nanobox/mysql:5.7 + +data.postgres: + image: nanobox/postgresql:9.5 + +data.redis: + image: nanobox/redis:3.2 diff --git a/build/php7/32bits/phalcon.zep.c b/build/php7/32bits/phalcon.zep.c index 2155c95543d..7a8be1444d9 100644 --- a/build/php7/32bits/phalcon.zep.c +++ b/build/php7/32bits/phalcon.zep.c @@ -30123,7 +30123,7 @@ static PHP_METHOD(Phalcon_Version, getVersion) { ZVAL_LONG(&_0, 1); zephir_array_fast_append(return_value, &_0); ZEPHIR_INIT_NVAR(&_0); - ZVAL_LONG(&_0, 0); + ZVAL_LONG(&_0, 2); zephir_array_fast_append(return_value, &_0); ZEPHIR_INIT_NVAR(&_0); ZVAL_LONG(&_0, 4); diff --git a/build/php7/32bits/phalcon.zep.h b/build/php7/32bits/phalcon.zep.h index 469778f4d14..1b56e072e61 100644 --- a/build/php7/32bits/phalcon.zep.h +++ b/build/php7/32bits/phalcon.zep.h @@ -49919,7 +49919,7 @@ ZEPHIR_INIT_FUNCS(phalcon_security_jwt_builder_method_entry) { PHP_ME(Phalcon_Security_JWT_Builder, setNotBefore, arginfo_phalcon_security_jwt_builder_setnotbefore, ZEND_ACC_PUBLIC) PHP_ME(Phalcon_Security_JWT_Builder, setSubject, arginfo_phalcon_security_jwt_builder_setsubject, ZEND_ACC_PUBLIC) PHP_ME(Phalcon_Security_JWT_Builder, setPassphrase, arginfo_phalcon_security_jwt_builder_setpassphrase, ZEND_ACC_PUBLIC) - PHP_ME(Phalcon_Security_JWT_Builder, setClaim, arginfo_phalcon_security_jwt_builder_setclaim, ZEND_ACC_PRIVATE) + PHP_ME(Phalcon_Security_JWT_Builder, setClaim, arginfo_phalcon_security_jwt_builder_setclaim, ZEND_ACC_PROTECTED) PHP_FE_END }; diff --git a/build/php7/32bits/php_phalcon.h b/build/php7/32bits/php_phalcon.h index 4bb22ae0b9f..598a61eb0d8 100644 --- a/build/php7/32bits/php_phalcon.h +++ b/build/php7/32bits/php_phalcon.h @@ -112,7 +112,7 @@ typedef zend_function zephir_fcall_cache_entry; #define PHP_PHALCON_NAME "phalcon" -#define PHP_PHALCON_VERSION "4.1.0" +#define PHP_PHALCON_VERSION "4.1.2" #define PHP_PHALCON_EXTNAME "phalcon" #define PHP_PHALCON_AUTHOR "Phalcon Team and contributors" #define PHP_PHALCON_ZEPVERSION "0.12.20-5d0f025" diff --git a/build/php7/64bits/phalcon.zep.c b/build/php7/64bits/phalcon.zep.c index 2155c95543d..7a8be1444d9 100644 --- a/build/php7/64bits/phalcon.zep.c +++ b/build/php7/64bits/phalcon.zep.c @@ -30123,7 +30123,7 @@ static PHP_METHOD(Phalcon_Version, getVersion) { ZVAL_LONG(&_0, 1); zephir_array_fast_append(return_value, &_0); ZEPHIR_INIT_NVAR(&_0); - ZVAL_LONG(&_0, 0); + ZVAL_LONG(&_0, 2); zephir_array_fast_append(return_value, &_0); ZEPHIR_INIT_NVAR(&_0); ZVAL_LONG(&_0, 4); diff --git a/build/php7/64bits/phalcon.zep.h b/build/php7/64bits/phalcon.zep.h index 469778f4d14..1b56e072e61 100644 --- a/build/php7/64bits/phalcon.zep.h +++ b/build/php7/64bits/phalcon.zep.h @@ -49919,7 +49919,7 @@ ZEPHIR_INIT_FUNCS(phalcon_security_jwt_builder_method_entry) { PHP_ME(Phalcon_Security_JWT_Builder, setNotBefore, arginfo_phalcon_security_jwt_builder_setnotbefore, ZEND_ACC_PUBLIC) PHP_ME(Phalcon_Security_JWT_Builder, setSubject, arginfo_phalcon_security_jwt_builder_setsubject, ZEND_ACC_PUBLIC) PHP_ME(Phalcon_Security_JWT_Builder, setPassphrase, arginfo_phalcon_security_jwt_builder_setpassphrase, ZEND_ACC_PUBLIC) - PHP_ME(Phalcon_Security_JWT_Builder, setClaim, arginfo_phalcon_security_jwt_builder_setclaim, ZEND_ACC_PRIVATE) + PHP_ME(Phalcon_Security_JWT_Builder, setClaim, arginfo_phalcon_security_jwt_builder_setclaim, ZEND_ACC_PROTECTED) PHP_FE_END }; diff --git a/build/php7/64bits/php_phalcon.h b/build/php7/64bits/php_phalcon.h index 4bb22ae0b9f..598a61eb0d8 100644 --- a/build/php7/64bits/php_phalcon.h +++ b/build/php7/64bits/php_phalcon.h @@ -112,7 +112,7 @@ typedef zend_function zephir_fcall_cache_entry; #define PHP_PHALCON_NAME "phalcon" -#define PHP_PHALCON_VERSION "4.1.0" +#define PHP_PHALCON_VERSION "4.1.2" #define PHP_PHALCON_EXTNAME "phalcon" #define PHP_PHALCON_AUTHOR "Phalcon Team and contributors" #define PHP_PHALCON_ZEPVERSION "0.12.20-5d0f025" diff --git a/build/php7/safe/phalcon.zep.c b/build/php7/safe/phalcon.zep.c index 2155c95543d..7a8be1444d9 100644 --- a/build/php7/safe/phalcon.zep.c +++ b/build/php7/safe/phalcon.zep.c @@ -30123,7 +30123,7 @@ static PHP_METHOD(Phalcon_Version, getVersion) { ZVAL_LONG(&_0, 1); zephir_array_fast_append(return_value, &_0); ZEPHIR_INIT_NVAR(&_0); - ZVAL_LONG(&_0, 0); + ZVAL_LONG(&_0, 2); zephir_array_fast_append(return_value, &_0); ZEPHIR_INIT_NVAR(&_0); ZVAL_LONG(&_0, 4); diff --git a/build/php7/safe/phalcon.zep.h b/build/php7/safe/phalcon.zep.h index 469778f4d14..1b56e072e61 100644 --- a/build/php7/safe/phalcon.zep.h +++ b/build/php7/safe/phalcon.zep.h @@ -49919,7 +49919,7 @@ ZEPHIR_INIT_FUNCS(phalcon_security_jwt_builder_method_entry) { PHP_ME(Phalcon_Security_JWT_Builder, setNotBefore, arginfo_phalcon_security_jwt_builder_setnotbefore, ZEND_ACC_PUBLIC) PHP_ME(Phalcon_Security_JWT_Builder, setSubject, arginfo_phalcon_security_jwt_builder_setsubject, ZEND_ACC_PUBLIC) PHP_ME(Phalcon_Security_JWT_Builder, setPassphrase, arginfo_phalcon_security_jwt_builder_setpassphrase, ZEND_ACC_PUBLIC) - PHP_ME(Phalcon_Security_JWT_Builder, setClaim, arginfo_phalcon_security_jwt_builder_setclaim, ZEND_ACC_PRIVATE) + PHP_ME(Phalcon_Security_JWT_Builder, setClaim, arginfo_phalcon_security_jwt_builder_setclaim, ZEND_ACC_PROTECTED) PHP_FE_END }; diff --git a/build/php7/safe/php_phalcon.h b/build/php7/safe/php_phalcon.h index 4bb22ae0b9f..598a61eb0d8 100644 --- a/build/php7/safe/php_phalcon.h +++ b/build/php7/safe/php_phalcon.h @@ -112,7 +112,7 @@ typedef zend_function zephir_fcall_cache_entry; #define PHP_PHALCON_NAME "phalcon" -#define PHP_PHALCON_VERSION "4.1.0" +#define PHP_PHALCON_VERSION "4.1.2" #define PHP_PHALCON_EXTNAME "phalcon" #define PHP_PHALCON_AUTHOR "Phalcon Team and contributors" #define PHP_PHALCON_ZEPVERSION "0.12.20-5d0f025" diff --git a/config.json b/config.json index d71d895b512..6223e68c4f8 100644 --- a/config.json +++ b/config.json @@ -3,7 +3,7 @@ "name": "phalcon", "description": "Phalcon is a full stack PHP framework, delivered as a PHP extension, offering lower resource consumption and high performance.", "author": "Phalcon Team and contributors", - "version": "4.1.0", + "version": "4.1.2", "verbose": false, "stubs": { "path": "ide\/%version%\/%namespace%\/", diff --git a/ext/phalcon/security/jwt/builder.zep.h b/ext/phalcon/security/jwt/builder.zep.h index ea63c353d5c..5776b1b2324 100644 --- a/ext/phalcon/security/jwt/builder.zep.h +++ b/ext/phalcon/security/jwt/builder.zep.h @@ -140,6 +140,6 @@ ZEPHIR_INIT_FUNCS(phalcon_security_jwt_builder_method_entry) { PHP_ME(Phalcon_Security_JWT_Builder, setNotBefore, arginfo_phalcon_security_jwt_builder_setnotbefore, ZEND_ACC_PUBLIC) PHP_ME(Phalcon_Security_JWT_Builder, setSubject, arginfo_phalcon_security_jwt_builder_setsubject, ZEND_ACC_PUBLIC) PHP_ME(Phalcon_Security_JWT_Builder, setPassphrase, arginfo_phalcon_security_jwt_builder_setpassphrase, ZEND_ACC_PUBLIC) - PHP_ME(Phalcon_Security_JWT_Builder, setClaim, arginfo_phalcon_security_jwt_builder_setclaim, ZEND_ACC_PRIVATE) + PHP_ME(Phalcon_Security_JWT_Builder, setClaim, arginfo_phalcon_security_jwt_builder_setclaim, ZEND_ACC_PROTECTED) PHP_FE_END }; diff --git a/ext/phalcon/version.zep.c b/ext/phalcon/version.zep.c index e232975c4cc..2ee8d14972f 100644 --- a/ext/phalcon/version.zep.c +++ b/ext/phalcon/version.zep.c @@ -152,7 +152,7 @@ PHP_METHOD(Phalcon_Version, getVersion) { ZVAL_LONG(&_0, 1); zephir_array_fast_append(return_value, &_0); ZEPHIR_INIT_NVAR(&_0); - ZVAL_LONG(&_0, 0); + ZVAL_LONG(&_0, 2); zephir_array_fast_append(return_value, &_0); ZEPHIR_INIT_NVAR(&_0); ZVAL_LONG(&_0, 4); diff --git a/ext/php_phalcon.h b/ext/php_phalcon.h index 2bbb0f244d9..8ebf87f861f 100644 --- a/ext/php_phalcon.h +++ b/ext/php_phalcon.h @@ -11,7 +11,7 @@ #include "kernel/globals.h" #define PHP_PHALCON_NAME "phalcon" -#define PHP_PHALCON_VERSION "4.1.0" +#define PHP_PHALCON_VERSION "4.1.2" #define PHP_PHALCON_EXTNAME "phalcon" #define PHP_PHALCON_AUTHOR "Phalcon Team and contributors" #define PHP_PHALCON_ZEPVERSION "0.12.21-5bd5677e" diff --git a/package.xml b/package.xml index 3c0d99161f6..238db83a662 100644 --- a/package.xml +++ b/package.xml @@ -11,8 +11,8 @@ ruud@ruudboon.io yes - 2020-10-31 - + 2021-04-21 + 4.2.0 4.2.0 @@ -25,80 +25,14 @@ Full changelog can be found at: https://github.com/phalcon/cphalcon/blob/master/CHANGELOG-4.1.md - # [4.1.0](https://github.com/phalcon/cphalcon/releases/tag/v4.1.0) (2020-10-31) - ## Added - - Added JWT (JSON Web Tokens) support under `Phalcon\Security\JWT`. Offers support for: - - Token - - Parser - - Builder - - Validator - - Signers (None, HMAC) - - Base64 encode/decodeUrl helper class - [#13856](https://github.com/phalcon/cphalcon/issues/13856) - - Added additional HTML helpers under `Phalcon\Html\Helper`: `Anchor`, `Base`, `Body`, `Button`, `Close`, `Element`, `Form`, `Img`, `Input\Color`, `Input\Date`, `Input\DateTime`, `Input\DateTimeLocal`, `Input\Email`, `Input\File`, `Input\Hidden`, `Input\Image`, `Input\Input`, `Input\Month`, `Input\Numeric`, `Input\Password`, `Input\Range`, `Input\Select`, `Input\Search`, `Input\Submit`, `Input\Tel`, `Input\Text`, `Input\Textarea`, `Input\Time`, `Input\Url`, `Input\Week`, `Label`, `Link`, `Meta`, `Ol`, `Script`, `Style`, `Title`, `Ul` - [#14696](https://github.com/phalcon/cphalcon/issues/14696) - - Added `Phalcon\Http\Request::getPreferredIsoLocaleVariant()` to return the base language if this is a specific one (`en` vs `en-US`) [#3135](https://github.com/phalcon/cphalcon/issues/3135) - - Added `preload` for Volt, which will send a HTTP/2 preload header [#13128](https://github.com/phalcon/cphalcon/issues/13128) - - Added `Phalcon\Helper\Arr::blackList()` to exclude elements of an array by the keys obtained from the elements of a blacklist [#14801](https://github.com/phalcon/cphalcon/issues/14801) [@TimurFlush](https://github.com/TimurFlush) - - Added `Phalcon\Debug::renderHtml()` to get a HTML representation of the exception [#14794](https://github.com/phalcon/cphalcon/issues/14794) [@TimurFlush](https://github.com/TimurFlush) - - Added `Phalcon\Mvc\Router\Annotations->setActionPreformatCallback($callback)` to set a callback which pre-formats actions to custom pattern [#14819](https://github.com/phalcon/cphalcon/pull/14819) - - Added new PDO wrapper for the Data Mapper implementation, with decorated instance, locator and profiler - - `Phalcon\DataMapper\Pdo\Connection` - - `Phalcon\DataMapper\Pdo\Connection\Decorated` - - `Phalcon\DataMapper\Pdo\Profiler\Profiler` - - `Phalcon\DataMapper\Pdo\Profiler\MemoryLogger` - - `Phalcon\DataMapper\Pdo\ConnectionLocator` - This component will be used in the Data Mapper implementation but can be used as a stand alone component for PDO connections. [#14733](https://github.com/phalcon/cphalcon/issues/14733) - - Added new Query Builder, as well as a factory, for the Data Mapper implementation supporting CRUD with bound parameters - - `Phalcon\DataMapper\Query\Bind` - - `Phalcon\DataMapper\Query\Delete` - - `Phalcon\DataMapper\Query\Insert` - - `Phalcon\DataMapper\Query\Select` - - `Phalcon\DataMapper\Query\Update` - - `Phalcon\DataMapper\Query\QueryFactory` - This component can be used to create SQL statements using a fluent interface. Optionally the statements can be executed from the builder itself using the `DataMapper\Pdo` connection. [#14734](https://github.com/phalcon/cphalcon/issues/14734) - - Added `Phalcon\Mvc\Micro\LazyLoader::getHandler()` to return real handler when using lazy loaded controllers for `Phalcon\Mvc\Micro` [#14871](https://github.com/phalcon/cphalcon/issues/14871) [@Jurigag](https://github.com/Jurigag) - - Added `Phalcon\Collection\CollectionInterface` and `Phalcon\Config\ConfigInterface` to use as typehints when extending or implementing custom classes [#15106](https://github.com/phalcon/cphalcon/issues/15106) [@BeMySlaveDarlin](https://github.com/BeMySlaveDarlin) - - Added `Phalcon\Db\Adapter\AdapterInterface::getDefaultValue()` and `supportsDefaultValue()` methods to properly support the `DEFAULT` keyword [#15180](https://github.com/phalcon/cphalcon/issues/15180) - - Added `Phalcon\Db\Adapter\AbstractAdapter::supportsDefaultValue()` method to properly support the `DEFAULT` keyword [#15180](https://github.com/phalcon/cphalcon/issues/15180) + # [4.1.1](https://github.com/phalcon/cphalcon/releases/tag/v4.1.1) (2021-04-21) ## Changed - - Added service checks for the session. Now cookies will be saved in the session only when the `session` service is defined [#11770](https://github.com/phalcon/cphalcon/issues/11770), [#14649](https://github.com/phalcon/cphalcon/pull/14649) - - Changed `Phalcon\Db\Adapter\*::getRawSQLStatement()` to return the full SQL query with parameters [#12196](https://github.com/phalcon/cphalcon/issues/12196) - - Changed `Phalcon\Filter::sanitize` to throw a `E_USER_NOTICE` when a filter does not exist. [#14679](https://github.com/phalcon/cphalcon/issues/14679) - - PHQL now supports the use of any printable characters from the extended ASCII - table for escaped identifiers. The exception characters are `[` and `]`. To - use `[` and `]` escape they (`\[`, `\]`) [#14535](https://github.com/phalcon/cphalcon/issues/14535) - - Removed UTF-8 charset when using `Phalcon\Http\Response::setJsonContent` to apply with rfc7159 - - Changed the visibility of properties in `Phalcon\Http\Message\Uri` to work with `clone`. [#15040](https://github.com/phalcon/cphalcon/issues/15040) - - Change `Phalcon\Validation\AbstractValidator::__construct`. Save custom validator message in options. [#15053](https://github.com/phalcon/cphalcon/issues/15053) [@ivan-zolotavin](https://github.com/ivan-zolotavin) - - Add proxy methods without `_` prefix in methods names: `getRelatedRecords()`, `groupResult()`, `exists()`, `preSaveRelatedRecords()`, `preSave()`, `doLowUpdate()`, `postSaveRelatedRecords()`, `postSave()`, `cancelOperation()`, `doLowInsert()`, `getConnection()`, `getConnectionService()`, `getVersion()`, `getSpecial()` [#14971](https://github.com/phalcon/cphalcon/pull/14971) - - Modified `Phalcon\Mvc\Model\Relation` to accept callable params for model relations. [#15158](https://github.com/phalcon/cphalcon/issues/15158) + - Corrected max PHP version for PECL ## Fixed - - Fixed `Phalcon\Db\Dialect\Mysql::getColumnDefinition` to recognize `size` for `DATETIME`, `TIME` and `TIMESTAMP` columns [#13297](https://github.com/phalcon/cphalcon/issues/13297) - - Fixed `Phalcon\Events\Manager` to provide callable support [#13322](https://github.com/phalcon/cphalcon/issues/13322), [#15045](https://github.com/phalcon/cphalcon/pull/15045) - - Fixed `Phalcon\Validation\Validator\Uniqueness` fixed except query [#15084](https://github.com/phalcon/cphalcon/issues/15084) - - Fixed `Phalcon\Mvc\Model` to also check the params option in cascade relations when deleting [#15098](https://github.com/phalcon/cphalcon/issues/15098) - - Fixed `Phalcon\Mvc\Model` to also check the params option in restricted relations when deleting [#15172](https://github.com/phalcon/cphalcon/issues/15172) - - Fixed `Phalcon\Mvc\Model::findFirst()` to return correct value [#15077](https://github.com/phalcon/cphalcon/issues/15077) - - Fixed `Phalcon\Mvc\Model\CriteriaInterface::where()` parameters [#15144](https://github.com/phalcon/cphalcon/issues/15144) - - Fixed `Phalcon\Http\Response\Cookies::set()` to utilize the options parameter correctly [#15129](https://github.com/phalcon/cphalcon/issues/15129) - - Fixed `Phalcon\Http\Cookie::send()` to define `options` parameter [#15142](https://github.com/phalcon/cphalcon/issues/15142) - - Fixed `Phalcon\Crypt` performance issues. [#15118](https://github.com/phalcon/cphalcon/issues/15118) - - Fixed `Phalcon\Mvc\Router\Route` unicode support in patterns [#15102](https://github.com/phalcon/cphalcon/issues/15102) - - Fixed fatal error in `Phalcon\Mvc\Model::cloneResultMap()` when column map is used with `orm.cast_on_hydrate` turned on. [#14617](https://github.com/phalcon/cphalcon/issues/14617) - - Fixed `Phalcon\Mvc\Model::sum()`, `average()`, `minimum()`, `maxmium()`, `count()` to utilize the transaction parameter. [#15113](https://github.com/phalcon/cphalcon/issues/15113) - - Fixed `Phalcon\Mvc\Model::__set()` to clear `dirtyRelated` when empty array is set. [#14822](https://github.com/phalcon/cphalcon/issues/14822) - - Fixed `Phalcon\Mvc\Model` to skip columns with default values when the `DEFAULT` keyword is not supported by the database adapter (SQLite) [#15180](https://github.com/phalcon/cphalcon/issues/15180) - - Fixed `Phalcon\Mvc\Router` to handle numeric routes properly [#14926](https://github.com/phalcon/cphalcon/issues/14926) - - Fixed `Phalcon\Session\Adapter\Redis` and `Phalcon\Session\Adapter\Libmemcached` to utilize the prefix option [#15184](https://github.com/phalcon/cphalcon/issues/15184) - - Fixed `Phalcon\Mvc\Model` to save the modified properties of previously queried single related records. [#15148](https://github.com/phalcon/cphalcon/issues/15148) - - ## Removed - - Removed `Phalcon\Http\Cookie` binding to session [#11770](https://github.com/phalcon/cphalcon/issues/11770) - - `Phalcon\Http\Cookie` no longer depends on the session service and data will not be duplicated in the session. This made it difficult to use cookies in stateless applications (SPA). - - Removed unused property `Phalcon\Mvc\Router::uriSource`. [#15123](https://github.com/phalcon/cphalcon/issues/15123) + - Fixed `Logger\Log::log()` `log` to recognize all log levels [#15214](https://github.com/phalcon/cphalcon/issues/15214) + - Changed `setClaims` to be protected so that the `Phalcon\Security\JWT\Builder` class can be properly extended. [#15322](https://github.com/phalcon/cphalcon/issues/15322) diff --git a/phalcon/Mvc/Model.zep b/phalcon/Mvc/Model.zep index 9ced5caade9..1d1739d3c4b 100644 --- a/phalcon/Mvc/Model.zep +++ b/phalcon/Mvc/Model.zep @@ -1914,23 +1914,36 @@ abstract class Model extends AbstractInjectionAware implements EntityInterface, * If there are any arguments, Manager with handle the caching of the records */ if arguments === null { +// /** +// * If the related records are already in cache and the relation is reusable, +// * we return the cached records. +// */ +// if relation->isReusable() && this->isRelationshipLoaded(lowerAlias) { +// let result = this->related[lowerAlias]; +// } else { +// /** +// * Call the 'getRelationRecords' in the models manager. +// */ +// let result = manager->getRelationRecords(relation, this, arguments); +// +// /** +// * We store relationship objects in the related cache if there were no arguments. +// */ +// let this->related[lowerAlias] = result; +// } /** - * If the related records are already in cache and the relation is reusable, - * we return the cached records. + * We do not need conditionals here. The models manager stores + * reusable related records so we utilize that and remove complexity + * from here. There is a very small decrease in performance since + * the models manager needs to calculate the unique key from + * the passed arguments and then check its internal cache */ - if relation->isReusable() && this->isRelationshipLoaded(lowerAlias) { - let result = this->related[lowerAlias]; - } else { - /** - * Call the 'getRelationRecords' in the models manager. - */ - let result = manager->getRelationRecords(relation, this, arguments); + let result = manager->getRelationRecords(relation, this, arguments); - /** - * We store relationship objects in the related cache if there were no arguments. - */ - let this->related[lowerAlias] = result; - } + /** + * We store relationship objects in the related cache if there were no arguments. + */ + let this->related[lowerAlias] = result; } else { /** * Individually queried related records are handled by Manager. diff --git a/phalcon/Storage/Adapter/Redis.zep b/phalcon/Storage/Adapter/Redis.zep index 8d8968c1224..ba807e99813 100644 --- a/phalcon/Storage/Adapter/Redis.zep +++ b/phalcon/Storage/Adapter/Redis.zep @@ -32,6 +32,7 @@ class Redis extends AbstractAdapter * 'host' => '127.0.0.1', * 'port' => 6379, * 'index' => 0, + * 'timeout' => 0, * 'persistent' => false, * 'auth' => '', * 'socket' => '', @@ -49,6 +50,7 @@ class Redis extends AbstractAdapter let options["host"] = Arr::get(options, "host", "127.0.0.1"), options["port"] = (int) Arr::get(options, "port", 6379), options["index"] = Arr::get(options, "index", 0), + options["timeout"] = Arr::get(options, "timeout", 0), options["persistent"] = Arr::get(options, "persistent", false), options["auth"] = Arr::get(options, "auth", ""), options["socket"] = Arr::get(options, "socket", ""), @@ -122,7 +124,7 @@ class Redis extends AbstractAdapter */ public function getAdapter() -> var { - var auth, connection, host, index, options, port, result, + var auth, connection, host, index, timeout, options, port, result, persistent, persistentid; if null === this->adapter { @@ -132,13 +134,14 @@ class Redis extends AbstractAdapter host = options["host"], port = options["port"], index = options["index"], + timeout = options["timeout"], persistent = options["persistent"]; if !persistent { - let result = connection->connect(host, port, this->lifetime); + let result = connection->connect(host, port, timeout); } else { let persistentid = "persistentid_" . index; - let result = connection->pconnect(host, port, this->lifetime, persistentid); + let result = connection->pconnect(host, port, timeout, persistentid); } if !result { diff --git a/phalcon/Version.zep b/phalcon/Version.zep index 31ae5a277a0..6b41a068e4b 100644 --- a/phalcon/Version.zep +++ b/phalcon/Version.zep @@ -100,7 +100,7 @@ class Version */ protected static function getVersion() -> array { - return [4, 1, 0, 4, 0]; + return [4, 1, 2, 4, 0]; } /** diff --git a/tests/_ci/nanobox/boxfile.7.2.yml b/tests/_ci/nanobox/boxfile.7.2.yml index 2ba9880bd05..d36f3b1fc56 100644 --- a/tests/_ci/nanobox/boxfile.7.2.yml +++ b/tests/_ci/nanobox/boxfile.7.2.yml @@ -121,7 +121,7 @@ run.config: - echo -e 'apc.enable_cli=1' >> "/data/etc/php/dev_php.ini" #=========================================================================== # Get the Zephir phar - - wget --no-clobber -O /data/bin/zephir https://github.com/phalcon/zephir/releases/download/0.12.19/zephir.phar + - wget --no-clobber -O /data/bin/zephir https://github.com/phalcon/zephir/releases/download/0.12.21/zephir.phar - chmod +x /data/bin/zephir data.memcached: diff --git a/tests/_ci/nanobox/boxfile.7.3.yml b/tests/_ci/nanobox/boxfile.7.3.yml index 9a0f2ee985e..8d1162c29b8 100644 --- a/tests/_ci/nanobox/boxfile.7.3.yml +++ b/tests/_ci/nanobox/boxfile.7.3.yml @@ -140,7 +140,7 @@ run.config: - echo -e 'apc.enable_cli=1' >> "/data/etc/php/dev_php.ini" #=========================================================================== # Get the Zephir phar - - wget --no-clobber -O /data/bin/zephir https://github.com/phalcon/zephir/releases/download/0.12.19/zephir.phar + - wget --no-clobber -O /data/bin/zephir https://github.com/phalcon/zephir/releases/download/0.12.21/zephir.phar - chmod +x /data/bin/zephir data.memcached: diff --git a/tests/_ci/nanobox/boxfile.7.4.yml b/tests/_ci/nanobox/boxfile.7.4.yml index 1229dad01ca..4d7813dcb8a 100644 --- a/tests/_ci/nanobox/boxfile.7.4.yml +++ b/tests/_ci/nanobox/boxfile.7.4.yml @@ -140,7 +140,7 @@ run.config: - echo -e 'apc.enable_cli=1' >> "/data/etc/php/dev_php.ini" #=========================================================================== # Get the Zephir phar - - wget --no-clobber -O /data/bin/zephir https://github.com/phalcon/zephir/releases/download/0.12.19/zephir.phar + - wget --no-clobber -O /data/bin/zephir https://github.com/phalcon/zephir/releases/download/0.12.21/zephir.phar - chmod +x /data/bin/zephir data.memcached: diff --git a/tests/_data/assets/schemas/mysql.sql b/tests/_data/assets/schemas/mysql.sql index 00117cd8763..ef73a3273a3 100644 --- a/tests/_data/assets/schemas/mysql.sql +++ b/tests/_data/assets/schemas/mysql.sql @@ -1,7 +1,7 @@ drop table if exists `complex_default`; - + create table complex_default ( `id` int(10) auto_increment primary key, @@ -9,11 +9,11 @@ create table complex_default `updated` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `updated_null` TIMESTAMP NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP ); - + drop table if exists `co_customers_defaults`; - + create table co_customers_defaults ( `cst_id` int(10) auto_increment primary key, @@ -21,20 +21,20 @@ create table co_customers_defaults `cst_name_last` varchar(100) not null DEFAULT 'cst_default_lastName', `cst_name_first` varchar(50) not null DEFAULT 'cst_default_firstName' ); - + create index co_customers_defaults_cst_status_flag_index on `co_customers_defaults` (`cst_status_flag`); - + create index co_customers_defaults_cst_name_last_index on `co_customers_defaults` (`cst_name_last`); - + create index co_customers_defaults_cst_name_first_index on `co_customers_defaults` (`cst_name_first`); - + drop table if exists `co_customers`; - + create table co_customers ( `cst_id` int(10) auto_increment primary key, @@ -42,20 +42,20 @@ create table co_customers `cst_name_last` varchar(100) null, `cst_name_first` varchar(50) null ); - + create index co_customers_cst_status_flag_index on `co_customers` (`cst_status_flag`); - + create index co_customers_cst_name_last_index on `co_customers` (`cst_name_last`); - + create index co_customers_cst_name_first_index on `co_customers` (`cst_name_first`); - + drop table if exists `fractal_dates`; - + create table fractal_dates ( `id` int(10) auto_increment primary key, @@ -63,11 +63,11 @@ create table fractal_dates `fdatetime` datetime(2) null, `ftimestamp` timestamp(2) null ); - + drop table if exists `co_invoices`; - + create table co_invoices ( `inv_id` int(10) auto_increment primary key, @@ -77,90 +77,100 @@ create table co_invoices `inv_total` float(10, 2) null, `inv_created_at` datetime null ); - + create index co_invoices_inv_cst_id_index on `co_invoices` (`inv_cst_id`); - + create index co_invoices_inv_status_flag_index on `co_invoices` (`inv_status_flag`); - + create index co_invoices_inv_created_at_index on `co_invoices` (`inv_created_at`); - + drop table if exists objects; - + create table objects ( `obj_id` int(10) auto_increment primary key, `obj_name` varchar(100) not null, `obj_type` tinyint(3) unsigned not null ); - + drop table if exists `co_orders`; - + CREATE TABLE `co_orders` ( `ord_id` int(10) unsigned NOT NULL AUTO_INCREMENT, `ord_name` VARCHAR(70) NULL, PRIMARY KEY (`ord_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; - + drop table if exists private.`co_orders_x_products`; - + CREATE TABLE private.`co_orders_x_products` ( `oxp_ord_id` int(10) unsigned NOT NULL, `oxp_prd_id` int(10) unsigned NOT NULL, `oxp_quantity` int(10) unsigned NOT NULL, PRIMARY KEY (`oxp_ord_id`, `oxp_prd_id` ) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; - + drop table if exists `co_products`; - + CREATE TABLE `co_products` ( `prd_id` int(10) unsigned NOT NULL AUTO_INCREMENT, `prd_name` VARCHAR(70) NULL, PRIMARY KEY (`prd_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; - + + +drop table if exists `co_setters`; + +create table co_setters +( + `id` int(10) auto_increment primary key, + `column1` varchar(100) null, + `column2` varchar(100) null, + `column3` varchar(100) null +); drop table if exists `co_sources`; - + create table co_sources ( `id` int(10) auto_increment primary key, `username` varchar(100) null, `source` varchar(100) null ); - + create index co_sources_username_index on co_sources (username); - + drop table if exists `table_with_uuid_primary`; - + create table table_with_uuid_primary ( `uuid` char(36) not null primary key, `int_field` int null ); - + drop table if exists `stuff`; - + create table stuff ( `stf_id` int(10) auto_increment primary key, `stf_name` varchar(100) not null, `stf_type` tinyint(3) unsigned not null ); - + diff --git a/tests/_data/assets/schemas/pgsql.sql b/tests/_data/assets/schemas/pgsql.sql index 2d519f902e9..3f05adfc260 100644 --- a/tests/_data/assets/schemas/pgsql.sql +++ b/tests/_data/assets/schemas/pgsql.sql @@ -1,7 +1,7 @@ drop table if exists complex_default; - + create table complex_default ( id SERIAL PRIMARY KEY, @@ -9,24 +9,24 @@ create table complex_default updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_null TIMESTAMP NULL DEFAULT NULL ); - + CREATE OR REPLACE FUNCTION update_timestamp() RETURNS TRIGGER AS $$ BEGIN - NEW.updated = NOW(); + NEW.updated = NOW(); NEW.updated_null = NOW(); RETURN NEW; END; $$ language 'plpgsql'; - + CREATE TRIGGER update_timestamp BEFORE UPDATE -ON complex_default FOR EACH ROW EXECUTE PROCEDURE +ON complex_default FOR EACH ROW EXECUTE PROCEDURE update_timestamp(); - + drop table if exists co_customers_defaults; - + create table co_customers_defaults ( cst_id serial not null constraint co_customers_defaults_pk primary key, @@ -34,20 +34,20 @@ create table co_customers_defaults cst_name_last varchar(100) not null DEFAULT 'cst_default_lastName', cst_name_first varchar(50) not null DEFAULT 'cst_default_firstName' ); - + create index co_customers_defaults_cst_status_flag_index on co_customers_defaults (cst_status_flag); - + create index co_customers_defaults_cst_name_last_index on co_customers_defaults (cst_name_last); - + create index co_customers_defaults_cst_name_first_index on co_customers_defaults (cst_name_first); - + drop table if exists co_customers; - + create table co_customers ( cst_id serial not null constraint co_customers_pk primary key, @@ -55,22 +55,22 @@ create table co_customers cst_name_last varchar(100) null, cst_name_first varchar(50) null ); - + create index co_customers_cst_status_flag_index on co_customers (cst_status_flag); - + create index co_customers_cst_name_last_index on co_customers (cst_name_last); - + create index co_customers_cst_name_first_index on co_customers (cst_name_first); - + drop table if exists co_invoices; - + create table co_invoices ( inv_id serial constraint co_invoices_pk primary key, @@ -80,31 +80,31 @@ create table co_invoices inv_total numeric(10, 2), inv_created_at timestamp ); - + create index co_invoices_inv_created_at_index on co_invoices (inv_created_at); - + create index co_invoices_inv_cst_id_index on co_invoices (inv_cst_id); - + create index co_invoices_inv_status_flag_index on co_invoices (inv_status_flag); - + drop table if exists objects; - + create table objects ( obj_id serial not null constraint objects_pk primary key, obj_name varchar(100) not null, obj_type smallint not null ); - + drop table if exists co_orders; - + create table co_orders ( ord_id serial not null @@ -112,22 +112,22 @@ create table co_orders primary key, ord_name varchar(70) ); - + drop table if exists private.co_orders_x_products; - + create table private.co_orders_x_products ( oxp_ord_id int not null, oxp_prd_id int not null, oxp_quantity int not null ); - + drop table if exists co_products; - + create table co_products ( prd_id serial not null @@ -135,18 +135,28 @@ create table co_products primary key, prd_name varchar(70) ); - + + +drop table if exists co_setters; + +create table co_setters +( + id SERIAL PRIMARY KEY, + column1 varchar(100) not null, + column2 varchar(100) not null, + column3 varchar(100) not null +); drop table if exists table_with_uuid_primary; - + create table table_with_uuid_primary ( uuid char(36) not null primary key, int_field int null ); - + diff --git a/tests/_data/assets/schemas/sqlite.sql b/tests/_data/assets/schemas/sqlite.sql index b27e1d0ad35..be31c73fda0 100644 --- a/tests/_data/assets/schemas/sqlite.sql +++ b/tests/_data/assets/schemas/sqlite.sql @@ -3,7 +3,7 @@ drop table if exists co_customers_defaults; - + create table co_customers_defaults ( cst_id integer constraint co_customers_defaults_pk primary key autoincrement, @@ -11,20 +11,20 @@ create table co_customers_defaults cst_name_last text not null DEFAULT 'cst_default_lastName', cst_name_first text not null DEFAULT 'cst_default_firstName' ); - + create index co_customers_defaults_cst_status_flag_index on co_customers_defaults (cst_status_flag); - + create index co_customers_defaults_cst_name_last_index on co_customers_defaults (cst_name_last); - + create index co_customers_defaults_cst_name_first_index on co_customers_defaults (cst_name_first); - + drop table if exists co_customers; - + create table co_customers ( cst_id integer constraint co_customers_pk primary key autoincrement, @@ -32,22 +32,22 @@ create table co_customers cst_name_last text null, cst_name_first text null ); - + create index co_customers_cst_status_flag_index on co_customers (cst_status_flag); - + create index co_customers_cst_name_last_index on co_customers (cst_name_last); - + create index co_customers_cst_name_first_index on co_customers (cst_name_first); - + drop table if exists co_invoices; - + create table co_invoices ( inv_id integer constraint co_invoices_pk primary key autoincrement not null, @@ -57,65 +57,75 @@ create table co_invoices inv_total real, inv_created_at text ); - + create index co_invoices_inv_cst_id_index on co_invoices (inv_cst_id); - + create index co_invoices_inv_status_flag_index on co_invoices (inv_status_flag); - + create index co_invoices_inv_created_at_index on co_invoices (inv_created_at); - + drop table if exists `objects`; - + create table objects ( obj_id integer constraint objects_pk primary key autoincrement, obj_name text not null, obj_type integer not null ); - +drop table if exists co_setters; + +create table co_setters +( + id integer constraint co_setters_defaults_pk primary key autoincrement, + column1 text, + column2 text, + column3 text +); + + drop table if exists co_sources; - + create table co_sources ( id integer constraint co_sources_pk primary key autoincrement, username text, source text ); - + create index co_sources_username_index on co_sources (username); - + drop table if exists table_with_uuid_primary; - + create table table_with_uuid_primary ( uuid text constraint uuid_pk primary key, int_field integer ); - + drop table if exists stuff; - + create table stuff ( stf_id integer constraint stf_id_pk primary key autoincrement, stf_name text not null, stf_type integer not null ); - + diff --git a/tests/_data/fixtures/Migrations/SettersMigration.php b/tests/_data/fixtures/Migrations/SettersMigration.php new file mode 100644 index 00000000000..c4cafbe0e7f --- /dev/null +++ b/tests/_data/fixtures/Migrations/SettersMigration.php @@ -0,0 +1,98 @@ + + * + * For the full copyright and license information, please view the LICENSE.txt + * file that was distributed with this source code. + */ + +namespace Phalcon\Test\Fixtures\Migrations; + +/** + * Class SettersMigration + */ +class SettersMigration extends AbstractMigration +{ + protected $table = "co_setters"; + + /** + * @param string $column1 + * @param string $column2 + * @param string $column3 + */ + public function insert( + string $column1, + string $column2, + string $column3 + ) { + $sql = <<connection->exec($sql); + } + + protected function getSqlMysql(): array + { + return [ + " +drop table if exists `co_setters`; + ", + " +create table co_setters +( + `id` int(10) auto_increment primary key, + `column1` varchar(100) null, + `column2` varchar(100) null, + `column3` varchar(100) null +); + ", + // $this->insert($db, 'val1', 'val2', 'val3'); + ]; + } + + protected function getSqlSqlite(): array + { + return [ + " +drop table if exists co_setters; + ", + " +create table co_setters + ( + id integer constraint co_setters_defaults_pk primary key autoincrement, + column1 text, + column2 text, + column3 text +); + ", + ]; + } + + protected function getSqlPgsql(): array + { + return [ + " +drop table if exists co_setters; + ", + " +create table co_setters +( + id SERIAL PRIMARY KEY, + column1 varchar(100) not null, + column2 varchar(100) not null, + column3 varchar(100) not null +); + ", + ]; + } + + protected function getSqlSqlsrv(): array + { + return []; + } +} diff --git a/tests/_data/fixtures/models/Setters.php b/tests/_data/fixtures/models/Setters.php new file mode 100644 index 00000000000..5246d8c29fd --- /dev/null +++ b/tests/_data/fixtures/models/Setters.php @@ -0,0 +1,70 @@ + + * + * For the full copyright and license information, please view the LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Phalcon\Test\Models; + +use Phalcon\Mvc\Model; + +/** + * Class Setters + */ +class Setters extends Model +{ + protected $id; + protected $column1; + protected $column2; + protected $column3; + + public function initialize() + { + $this->setSource('co_setters'); + $this->keepSnapshots(true); + $this->useDynamicUpdate(true); + } + + public function setColumn1($column1): self + { + $this->column1 = $column1; + + return $this; + } + + public function setColumn2($column2): self + { + $this->column2 = $column2; + + return $this; + } + + public function setColumn3($column3): self + { + $this->column3 = $column3; + + return $this; + } + + public function getColumn1(): string + { + return $this->column1; + } + + public function getColumn2(): string + { + return $this->column2; + } + + public function getColumn3(): string + { + return $this->column3; + } +} diff --git a/tests/_support/Helper/Database.php b/tests/_support/Helper/Database.php index 5413e81f4e4..c6d60eca60f 100644 --- a/tests/_support/Helper/Database.php +++ b/tests/_support/Helper/Database.php @@ -12,7 +12,6 @@ use function date; use function env; -use function getenv; use function getOptionsMysql; use function getOptionsPostgresql; use function getOptionsSqlite; diff --git a/tests/database/Mvc/Model/GetRelatedCest.php b/tests/database/Mvc/Model/GetRelatedCest.php index e2fc6c25b01..27e2e24a883 100644 --- a/tests/database/Mvc/Model/GetRelatedCest.php +++ b/tests/database/Mvc/Model/GetRelatedCest.php @@ -30,24 +30,20 @@ class GetRelatedCest { use DiTrait; + /** + * @param DatabaseTester $I + */ public function _before(DatabaseTester $I) { $this->setNewFactoryDefault(); $this->setDatabase($I); - - /** @var PDO $connection */ - $connection = $I->getConnection(); - - $customersMigration = new CustomersMigration($connection); - $customersMigration->clear(); - - $invoicesMigration = new InvoicesMigration($connection); - $invoicesMigration->clear(); } /** * Tests Phalcon\Mvc\Model :: getRelated() * + * @param DatabaseTester $I + * * @author Balázs Németh * @since 2020-08-02 * @@ -93,7 +89,6 @@ public function mvcModelGetRelated(DatabaseTester $I) * @var Customers $customer */ $customer = Customers::findFirst($custId); - $invoices = $customer->getRelated( 'invoices', [ @@ -101,43 +96,147 @@ public function mvcModelGetRelated(DatabaseTester $I) ] ); - $I->assertEquals( - 2, - $invoices->count() - ); + $expected = 2; + $actual = $invoices->count(); + $I->assertEquals($expected, $actual); - $I->assertInstanceOf( - Invoices::class, - $invoices[0] - ); + $expected = Invoices::class; + $actual = $invoices[0]; + $I->assertInstanceOf($expected, $actual); - $I->assertEquals( - $unpaidInvoiceId, - $invoices[0]->inv_id - ); + $expected = $unpaidInvoiceId; + $actual = $invoices[0]->inv_id; + $I->assertEquals($expected, $actual); - $I->assertEquals( - $paidInvoiceId, - $invoices[1]->inv_id - ); + $expected = $paidInvoiceId; + $actual = $invoices[1]->inv_id; + $I->assertEquals($expected, $actual); - $paidInvoices = $customer->getRelated( - 'paidInvoices' - ); + $paidInvoices = $customer->getRelated('paidInvoices'); - $I->assertEquals( - 1, - $paidInvoices->count() - ); + $expected = 1; + $actual = $paidInvoices->count(); + $I->assertEquals($expected, $actual); + + $expected = Invoices::class; + $actual = $paidInvoices[0]; + $I->assertInstanceOf($expected, $actual); + + $expected = $paidInvoiceId; + $actual = $paidInvoices[0]->inv_id; + $I->assertEquals($expected, $actual); + } + + /** + * Tests Phalcon\Mvc\Model :: getRelated() - changing FK + * + * @param DatabaseTester $I + * + * @author Phalcon Team + * @since 2021-10-01 + * + * @group mysql + * @group pgsql + * @group sqlite + */ + public function mvcModelGetRelatedChangeForeignKey(DatabaseTester $I) + { + $I->wantToTest('Mvc\Model - getRelated() - Change Foreign Key'); + + /** @var PDO $connection */ + $connection = $I->getConnection(); - $I->assertInstanceOf( - Invoices::class, - $paidInvoices[0] + + $custIdOne = 10; + $firstNameOne = uniqid('cust-1-', true); + $lastNameOne = uniqid('cust-1-', true); + + $custIdTwo = 20; + $firstNameTwo = uniqid('cust-2-', true); + $lastNameTwo = uniqid('cust-2-', true); + + $customersMigration = new CustomersMigration($connection); + $customersMigration->insert($custIdOne, 0, $firstNameOne, $lastNameOne); + $customersMigration->insert($custIdTwo, 0, $firstNameTwo, $lastNameTwo); + + $invoiceId = 40; + $title = uniqid('inv-'); + $invoicesMigration = new InvoicesMigration($connection); + $invoicesMigration->insert( + $invoiceId, + $custIdOne, + Invoices::STATUS_PAID, + $title . '-paid' ); - $I->assertEquals( - $paidInvoiceId, - $paidInvoices[0]->inv_id + /** + * Find the invoice. Then use `getRelated` to get the customer. It + * should return CustomerOne. + * + * Change the FK to the customer. Call `getRelated` again. It should + * return CustomerTwo + */ + $invoice = Invoices::findFirst( + [ + 'conditions' => 'inv_id = :inv_id:', + 'bind' => [ + 'inv_id' => $invoiceId, + ] + ] ); + + /** + * Assert that the correct customer is stored + */ + $expected = $custIdOne; + $actual = $invoice->inv_cst_id; + $I->assertEquals($expected, $actual); + + /** + * Call get related - We should get CustomerOne + */ + /** @var Customers $customer */ + $customer = $invoice->getRelated('customer'); + + $class = Customers::class; + $I->assertInstanceOf($class, $customer); + + $expected = $custIdOne; + $actual = $customer->cst_id; + $I->assertEquals($expected, $actual); + + $invoice->inv_cst_id = $custIdTwo; + $result = $invoice->save(); + $I->assertTrue($result); + + /** + * Now call getRelated. We should get CustomerTwo + */ + /** @var Customers $customer */ + $customer = $invoice->getRelated('customer'); + + $class = Customers::class; + $I->assertInstanceOf($class, $customer); + + $expected = $custIdTwo; + $actual = $customer->cst_id; + $I->assertEquals($expected, $actual); + + /** + * Delete Customer Two and call getRelated again. We should get + * the cached copy + */ + $result = $customer->delete(); + $I->assertTrue($result); + + /** @var Customers $customer */ + $customer = $invoice->getRelated('customer'); + + $class = Customers::class; + $I->assertInstanceOf($class, $customer); + + $expected = $custIdTwo; + $actual = $customer->cst_id; + $I->assertEquals($expected, $actual); } } diff --git a/tests/database/Mvc/Model/UpdateCest.php b/tests/database/Mvc/Model/UpdateCest.php index a83f926d272..fa8ad9af371 100644 --- a/tests/database/Mvc/Model/UpdateCest.php +++ b/tests/database/Mvc/Model/UpdateCest.php @@ -14,11 +14,15 @@ namespace Phalcon\Test\Database\Mvc\Model; use DatabaseTester; +use PDO; +use Phalcon\Mvc\ModelInterface; use Phalcon\Test\Fixtures\Migrations\CustomersDefaultsMigration; use Phalcon\Test\Fixtures\Migrations\InvoicesMigration; +use Phalcon\Test\Fixtures\Migrations\SettersMigration; use Phalcon\Test\Fixtures\Traits\DiTrait; use Phalcon\Test\Models\CustomersDefaults; use Phalcon\Test\Models\Invoices; +use Phalcon\Test\Models\Setters; use function uniqid; @@ -110,7 +114,7 @@ public function mvcModelSaveAfterWithoutDefaultValues(DatabaseTester $I) { $I->wantToTest('Mvc\Model - update() - with default values'); - /** @var \PDO $connection */ + /** @var PDO $connection */ $connection = $I->getConnection(); $customersMigration = new CustomersDefaultsMigration($connection); @@ -164,4 +168,69 @@ public function mvcModelSaveAfterWithoutDefaultValues(DatabaseTester $I) $ormCustomer->update() ); } + + /** + * Tests Phalcon\Mvc\Model :: update() - via setters and local method + * + * @see https://github.com/phalcon/cphalcon/discussions/15625 + * + * @author Anton Vasiliev + * @since 2021-08-20 + * + * @group mysql + * @group pgsql + * @group sqlite + */ + public function mvcModelSaveViaSettersAndLocalMethod(DatabaseTester $I): void + { + $I->wantToTest('Mvc\Model - update() - via setters and local method'); + + /** @var PDO $connection */ + $connection = $I->getConnection(); + + $settersMigration = new SettersMigration($connection); + $settersMigration->clear(); + $settersMigration->insert('value1', 'value2', 'value3'); + + /** + * Validate initial data + */ + $row = Setters::findFirst(1); + $I->assertEquals('value1', $row->getColumn1()); + $I->assertEquals('value2', $row->getColumn2()); + $I->assertEquals('value3', $row->getColumn3()); + + /** + * First save via local method + */ + $firstValue = 'value2'; + $this->setColumn1($row, $firstValue); + $I->assertEquals($firstValue, $row->getColumn1()); + $I->assertEquals($firstValue, Setters::findFirst(1)->getColumn1()); + + /** + * Second save via model's setter and direct save() call + */ + $secondValue = 'value3'; + $row->setColumn2($secondValue); + $row->save(); + $I->assertEquals($secondValue, $row->getColumn2()); + $I->assertEquals($secondValue, Setters::findFirst(1)->getColumn2()); + + /** + * Final assertions + */ + $I->assertEquals($firstValue, $row->getColumn1()); + $I->assertEquals($secondValue, $row->getColumn2()); + $I->assertEquals('value3', $row->getColumn3()); + $I->assertEquals($firstValue, Setters::findFirst(1)->getColumn1()); + $I->assertEquals($secondValue, Setters::findFirst(1)->getColumn2()); + $I->assertEquals('value3', Setters::findFirst(1)->getColumn3()); + } + + private function setColumn1(ModelInterface $model, string $value): void + { + $model->setColumn1($value); + $model->save(); + } }