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();
+ }
}