Skip to content

Commit 1a8c668

Browse files
committed
Merge branch '5.1' of github.com:thecodingmachine/tdbm into merge51
2 parents 3273a33 + 12eaeca commit 1a8c668

File tree

7 files changed

+163
-48
lines changed

7 files changed

+163
-48
lines changed

.travis.yml

Lines changed: 42 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
language: php
22
php:
3-
- 7.1
3+
- 7.1
44
cache:
55
directories:
66
- $HOME/.composer/cache
77
matrix:
88
include:
9-
- php: 7.2
9+
- php: 7.4
1010
env: PREFER_LOWEST="" DB=mysql RUN_PHPSTAN=1 RUN_CSCHECK=1 RUN_REQUIRECHECKER=1 RUN_PERF_TEST=1
1111
services:
1212
- mysql
@@ -26,7 +26,7 @@ matrix:
2626
env: PREFER_LOWEST="" DB=mysql8
2727
sudo: required
2828
services:
29-
- docker
29+
- docker
3030
- php: 7.2
3131
env: PREFER_LOWEST="" DB=mariadb
3232
addons:
@@ -64,45 +64,45 @@ matrix:
6464
env: PREFER_LOWEST="--prefer-lowest" DB=oracle PHPUNITFILE="-c phpunit.oracle.xml"
6565
env:
6666
global:
67-
- GIT_NAME: "'Couscous auto deploy'"
68-
- GIT_EMAIL: [email protected]
69-
- GH_REF: github.com/thecodingmachine/tdbm
70-
- secure: pAdXEBkhe0KJbbZEP61lcZzvKKMkVK2RDIZTf1RzjQRgk+PxIG5JLBiHKuvG3MgtFjZbdtl2Vf6nAZbeMyy3H0eCryQCjjqdb5mS3eDekJ4WwviN6hQDc7+Xw6R1saHvDvJs9GQENUzHPWfAfY7LuwUgHXdc+BCLZmV+j0H6liZMNlXIYqP1kdwl7u5a/Y3FvXFws6R7A0giUBCb4HOYkInaXV0yzuAEsB6XBDbTjw3EqI0GBs6746O4tn7NOGaFlFSZan6RZe6jEkw7A+U3xLCfFnIN2q1uk/tk511KkOcSFQyGKRMDSKRDesdMQaOt/ze14+t+ISTqOSn8bUrCBhpj4VsjvzZE0FOS3WWGXpayODqdxuDjacwCZwiOHG7FWbwyQ3APiIrfO82ABbI8HoJURbgOb/Qnl2iPg9tCcvDqhsHxppGq5oOyhBq+GGtucOTW6lO6QnlMaez4nJJ7a3cn8WJB6NxaCZLii3aOXSLMahzFCcQxtq9/WfKwbOtf4GWUSLk28kDMov5h7tzuuHXmzOivzRxztQ9WC2GT7eMCIL8mvWFRMNiLJTE03J0ZbQDZ9N4OU3tdcgjV+d6pU6bu4SrCFtjCJnLaeLfIjoHkx+kK+kyCOQpOcuHMM6zq8l+ztd7VGZ3Br8HJTs1CxiWXrs+JIx2i8V06IE8nLKA=
67+
- GIT_NAME: "'Couscous auto deploy'"
68+
- GIT_EMAIL: [email protected]
69+
- GH_REF: github.com/thecodingmachine/tdbm
70+
- secure: pAdXEBkhe0KJbbZEP61lcZzvKKMkVK2RDIZTf1RzjQRgk+PxIG5JLBiHKuvG3MgtFjZbdtl2Vf6nAZbeMyy3H0eCryQCjjqdb5mS3eDekJ4WwviN6hQDc7+Xw6R1saHvDvJs9GQENUzHPWfAfY7LuwUgHXdc+BCLZmV+j0H6liZMNlXIYqP1kdwl7u5a/Y3FvXFws6R7A0giUBCb4HOYkInaXV0yzuAEsB6XBDbTjw3EqI0GBs6746O4tn7NOGaFlFSZan6RZe6jEkw7A+U3xLCfFnIN2q1uk/tk511KkOcSFQyGKRMDSKRDesdMQaOt/ze14+t+ISTqOSn8bUrCBhpj4VsjvzZE0FOS3WWGXpayODqdxuDjacwCZwiOHG7FWbwyQ3APiIrfO82ABbI8HoJURbgOb/Qnl2iPg9tCcvDqhsHxppGq5oOyhBq+GGtucOTW6lO6QnlMaez4nJJ7a3cn8WJB6NxaCZLii3aOXSLMahzFCcQxtq9/WfKwbOtf4GWUSLk28kDMov5h7tzuuHXmzOivzRxztQ9WC2GT7eMCIL8mvWFRMNiLJTE03J0ZbQDZ9N4OU3tdcgjV+d6pU6bu4SrCFtjCJnLaeLfIjoHkx+kK+kyCOQpOcuHMM6zq8l+ztd7VGZ3Br8HJTs1CxiWXrs+JIx2i8V06IE8nLKA=
7171
before_script:
72-
- composer update --prefer-dist
73-
# For some reason, $PREFER_LOWEST will fail unless a composer update has been run before...
74-
- if [ "$PREFER_LOWEST" = "--prefer-lowest" ] ; then composer update --prefer-dist --prefer-lowest; fi
75-
- if [ -z "$NO_WEAKREF" ] ; then pecl install weakref-beta; fi
72+
- composer update --prefer-dist
73+
# For some reason, $PREFER_LOWEST will fail unless a composer update has been run before...
74+
- if [ "$PREFER_LOWEST" = "--prefer-lowest" ] ; then composer update --prefer-dist --prefer-lowest; fi
75+
- if [ -z "$NO_WEAKREF" ] ; then pecl install weakref-beta; fi
7676
script:
77-
# Let's run the Oracle script only when the password is available (it is not available in forks unfortunately)
78-
- |
79-
if [[ "$COVERALLS" != "true" ]] ; then export NO_COVERAGE="--no-coverage"; fi;
80-
if [ "$DB" == "oracle" ] ; then
81-
docker run -v $(pwd):/app -v $(pwd)/tests/Fixtures/oracle-startup.sql:/docker-entrypoint-initdb.d/oracle-startup.sql moufmouf/oracle-xe-php vendor/bin/phpunit $PHPUNITFILE $NO_COVERAGE;
82-
elif [ "$DB" == "mysql8" ] ; then
83-
sudo /etc/init.d/mysql stop;
84-
tests/phpunit-mysql8.sh
85-
else
86-
echo ./vendor/bin/phpunit $PHPUNITFILE $NO_COVERAGE;
87-
./vendor/bin/phpunit $PHPUNITFILE $NO_COVERAGE;
88-
fi
89-
- |
90-
if [ "$RUN_CSCHECK" == "1" ] ; then
91-
composer cscheck
92-
fi
93-
- |
94-
if [ "$RUN_PHPSTAN" == "1" ] ; then
95-
composer phpstan
96-
fi
97-
- |
98-
if [ "$RUN_REQUIRECHECKER" == "1" ] ; then
99-
composer require-checker
100-
fi
101-
- |
102-
if [ "$RUN_PERF_TEST" == "1" ] ; then
103-
echo "***** Running PHPBENCH on current branch *****" && \
104-
./phpbench.dist.sh run --tag=current_pr --store
105-
fi
77+
# Let's run the Oracle script only when the password is available (it is not available in forks unfortunately)
78+
- |
79+
if [[ "$COVERALLS" != "true" ]] ; then export NO_COVERAGE="--no-coverage"; fi;
80+
if [ "$DB" == "oracle" ] ; then
81+
docker run -v $(pwd):/app -v $(pwd)/tests/Fixtures/oracle-startup.sql:/docker-entrypoint-initdb.d/oracle-startup.sql moufmouf/oracle-xe-php vendor/bin/phpunit $PHPUNITFILE $NO_COVERAGE;
82+
elif [ "$DB" == "mysql8" ] ; then
83+
sudo /etc/init.d/mysql stop;
84+
tests/phpunit-mysql8.sh
85+
else
86+
echo ./vendor/bin/phpunit $PHPUNITFILE $NO_COVERAGE;
87+
./vendor/bin/phpunit $PHPUNITFILE $NO_COVERAGE;
88+
fi
89+
- |
90+
if [ "$RUN_CSCHECK" == "1" ] ; then
91+
composer cscheck
92+
fi
93+
- |
94+
if [ "$RUN_PHPSTAN" == "1" ] ; then
95+
composer phpstan
96+
fi
97+
- |
98+
if [ "$RUN_REQUIRECHECKER" == "1" ] ; then
99+
composer require-checker
100+
fi
101+
- |
102+
if [ "$RUN_PERF_TEST" == "1" ] ; then
103+
echo "***** Running PHPBENCH on current branch *****" && \
104+
./phpbench.dist.sh run --tag=current_pr --store
105+
fi
106106
after_success:
107107
- |
108108
if [ "$RUN_PERF_TEST" == "1" ] && [ "${TRAVIS_PULL_REQUEST_BRANCH:-$TRAVIS_BRANCH}" != "master" ] ; then
@@ -114,5 +114,5 @@ after_success:
114114
./phpbench.dist.sh report --uuid=tag:current_pr --uuid=tag:master --report='{extends: compare, compare: tag}'
115115
fi
116116
after_script:
117-
- if [ "$COVERALLS" = "true" ] ; then ./vendor/bin/php-coveralls -v; fi
118-
- if [ "$COVERALLS" = "true" ] ; then vendor/bin/couscous travis-auto-deploy --php-version=7.2 -vvv; fi
117+
- if [ "$COVERALLS" = "true" ] ; then ./vendor/bin/php-coveralls -v; fi
118+
- if [ "$COVERALLS" = "true" ] ; then vendor/bin/couscous travis-auto-deploy --php-version=7.2 -vvv; fi

composer-require-checker.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"null", "true", "false",
44
"static", "self", "parent",
55
"array", "string", "int", "float", "bool", "iterable", "callable", "void", "object",
6-
"WeakRef",
6+
"WeakRef", "WeakReference",
77
"TheCodingMachine\\TDBM\\Fixtures\\Interfaces\\TestUserDaoInterface",
88
"TheCodingMachine\\TDBM\\Fixtures\\Traits\\TestUserDaoTrait",
99
"TheCodingMachine\\TDBM\\Fixtures\\Interfaces\\TestUserInterface",

phpstan.neon

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ parameters:
1313
#- "#expects array<string>, array<int, int|string> given.#"
1414
- "/Parameter #. \\$types of method Doctrine\\\\DBAL\\\\Connection::.*() expects array<int|string>, array<int, Doctrine\\\\DBAL\\\\Types\\\\Type> given./"
1515
- "#Method TheCodingMachine\\\\TDBM\\\\Schema\\\\ForeignKey::.*() should return .* but returns array<string>|string.#"
16+
- '#Method TheCodingMachine\\TDBM\\NativeWeakrefObjectStorage::get\(\) should return TheCodingMachine\\TDBM\\DbRow\|null but returns object\|null.#'
17+
-
18+
message: '#WeakRef#'
19+
path: src/WeakrefObjectStorage.php
1620
-
1721
message: '#Result of && is always false.#'
1822
path: src/Test/Dao/Bean/Generated/ArticleBaseBean.php

src/NativeWeakrefObjectStorage.php

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
/*
5+
Copyright (C) 2006-2014 David Négrier - THE CODING MACHINE
6+
7+
This program is free software; you can redistribute it and/or modify
8+
it under the terms of the GNU General Public License as published by
9+
the Free Software Foundation; either version 2 of the License, or
10+
(at your option) any later version.
11+
12+
This program is distributed in the hope that it will be useful,
13+
but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
GNU General Public License for more details.
16+
17+
You should have received a copy of the GNU General Public License
18+
along with this program; if not, write to the Free Software
19+
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20+
*/
21+
22+
namespace TheCodingMachine\TDBM;
23+
24+
use WeakReference;
25+
26+
/**
27+
* The NativeWeakrefObjectStorage class is used to reference all beans that have been fetched from the database.
28+
* If a bean is requested twice from TDBM, the NativeWeakrefObjectStorage is used to "cache" the bean.
29+
* Unlike the StandardObjectStorage, the NativeWeakrefObjectStorage manages memory in a clever way, using WeakReference.
30+
* WeakReference have been added in PHP 7.4.
31+
*
32+
* @author David Negrier
33+
*/
34+
class NativeWeakrefObjectStorage implements ObjectStorageInterface
35+
{
36+
/**
37+
* An array of fetched object, accessible via table name and primary key.
38+
* If the primary key is split on several columns, access is done by an array of columns, serialized.
39+
*
40+
* @var WeakReference[][]
41+
*/
42+
private $objects = array();
43+
44+
/**
45+
* Every 10000 set in the dataset, we perform a cleanup to ensure the WeakRef instances
46+
* are removed if they are no more valid.
47+
* This is to avoid having memory used by dangling WeakRef instances.
48+
*
49+
* @var int
50+
*/
51+
private $garbageCollectorCount = 0;
52+
53+
/**
54+
* Sets an object in the storage.
55+
*
56+
* @param string $tableName
57+
* @param string|int $id
58+
* @param DbRow $dbRow
59+
*/
60+
public function set(string $tableName, $id, DbRow $dbRow): void
61+
{
62+
$this->objects[$tableName][$id] = WeakReference::create($dbRow);
63+
++$this->garbageCollectorCount;
64+
if ($this->garbageCollectorCount === 10000) {
65+
$this->garbageCollectorCount = 0;
66+
$this->cleanupDanglingWeakRefs();
67+
}
68+
}
69+
70+
/**
71+
* Returns an object from the storage (or null if no object is set).
72+
*
73+
* @param string $tableName
74+
* @param string|int $id
75+
*
76+
* @return DbRow|null
77+
*/
78+
public function get(string $tableName, $id) : ?DbRow
79+
{
80+
if (isset($this->objects[$tableName][$id])) {
81+
return $this->objects[$tableName][$id]->get();
82+
}
83+
return null;
84+
}
85+
86+
/**
87+
* Removes an object from the storage.
88+
*
89+
* @param string $tableName
90+
* @param string|int $id
91+
*/
92+
public function remove(string $tableName, $id): void
93+
{
94+
unset($this->objects[$tableName][$id]);
95+
}
96+
97+
private function cleanupDanglingWeakRefs(): void
98+
{
99+
foreach ($this->objects as $tableName => $table) {
100+
foreach ($table as $id => $obj) {
101+
if ($obj->get() === null) {
102+
unset($this->objects[$tableName][$id]);
103+
}
104+
}
105+
}
106+
}
107+
}

src/TDBMService.php

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
namespace TheCodingMachine\TDBM;
2323

24+
use function class_exists;
2425
use Doctrine\Common\Cache\Cache;
2526
use Doctrine\Common\Cache\ClearableCache;
2627
use Doctrine\Common\Cache\VoidCache;
@@ -46,7 +47,7 @@
4647
use Psr\Log\LoggerInterface;
4748
use Psr\Log\LogLevel;
4849
use Psr\Log\NullLogger;
49-
use function var_export;
50+
use WeakReference;
5051

5152
/**
5253
* The TDBMService class is the main TDBM class. It provides methods to retrieve TDBMObject instances
@@ -101,7 +102,7 @@ class TDBMService
101102
* Access is done by table name and then by primary key.
102103
* If the primary key is split on several columns, access is done by an array of columns, serialized.
103104
*
104-
* @var StandardObjectStorage|WeakrefObjectStorage
105+
* @var ObjectStorageInterface
105106
*/
106107
private $objectStorage;
107108

@@ -179,7 +180,9 @@ class TDBMService
179180
*/
180181
public function __construct(ConfigurationInterface $configuration)
181182
{
182-
if (extension_loaded('weakref')) {
183+
if (class_exists(WeakReference::class)) {
184+
$this->objectStorage = new NativeWeakrefObjectStorage();
185+
} elseif (extension_loaded('weakref')) {
183186
$this->objectStorage = new WeakrefObjectStorage();
184187
} else {
185188
$this->objectStorage = new StandardObjectStorage();

src/WeakrefObjectStorage.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@
2626
* If a bean is requested twice from TDBM, the WeakrefObjectStorage is used to "cache" the bean.
2727
* Unlike the StandardObjectStorage, the WeakrefObjectStorage manages memory in a clever way, using the weakref
2828
* PHP extension. It is used if the "weakref" extension is available.
29-
* Otherwise, the StandardObjectStorage is used instead.
29+
* Otherwise, the StandardObjectStorage or NativeWeakrefObjectStorage (in PHP 7.4+) is used instead.
30+
*
31+
* Note: the weakref extension is available until PHP 7.2, but not available in PHP 7.3+
3032
*
3133
* @author David Negrier
3234
*/

tests/TDBMDaoGeneratorTest.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1852,7 +1852,6 @@ public function testFilterBag(): void
18521852
public function testDecimalIsMappedToString(): void
18531853
{
18541854
$reflectionClass = new \ReflectionClass(BoatBaseBean::class);
1855-
/** @var ReflectionNamedType $nameParam */
18561855
$this->assertSame('string', $reflectionClass->getMethod('getLength')->getReturnType()->getName());
18571856
}
18581857

0 commit comments

Comments
 (0)