Skip to content

Commit 441034b

Browse files
authored
Merge pull request #217 from maxmind/greg/readonly-properties
Use readonly properties for model classes
2 parents b76c914 + e1a9261 commit 441034b

31 files changed

+1159
-834
lines changed

.github/workflows/lint.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414
- name: Setup PHP
1515
uses: shivammathur/setup-php@v2
1616
with:
17-
php-version: 8.1
17+
php-version: 8.2
1818

1919
- name: Checkout
2020
uses: actions/checkout@v4

.github/workflows/test.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212
strategy:
1313
matrix:
1414
operating-system: [ubuntu-latest, windows-latest, macos-latest]
15-
php-versions: ['8.0', '8.1']
15+
php-versions: ['8.1', '8.2']
1616
name: "PHP ${{ matrix.php-versions }} test on ${{ matrix.operating-system }}"
1717
steps:
1818
- name: Setup PHP
@@ -33,4 +33,4 @@ jobs:
3333
run: composer install --no-progress --prefer-dist --optimize-autoloader
3434

3535
- name: Test with phpunit
36-
run: vendor/bin/phpunit --coverage-text
36+
run: vendor/bin/phpunit

CHANGELOG.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,14 @@ CHANGELOG
44
3.0.0
55
-------------------
66

7-
* IMPORTANT: PHP 8.0 or greater is now required.
7+
* IMPORTANT: PHP 8.1 or greater is now required.
8+
* BREAKING: Read-only properties are now used for the model and record
9+
classes rather than magic methods. This significantly improves performance.
10+
* BREAKING: The `raw` property on model classess and the `record` property on
11+
record classes have been removed.
12+
* BREAKING: On `GeoIp2\Record\Traits`, the deprecated `isAnonymousProxy` and
13+
`isSatelliteProvider` properties have been removed.
14+
* BREAKING: The `jsonSerialize` output has changed.
815
* `GeoIp2\WebService\Client` methods now throw an `InvalidArgumentException`
916
if an invalid IP address is passed to them. Previously, they would make
1017
a request to the web service and throw a

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,7 @@ to the client API, please see
430430

431431
## Requirements ##
432432

433-
This library requires PHP 8.0 or greater.
433+
This library requires PHP 8.1 or greater.
434434

435435
This library also relies on the [MaxMind DB Reader](https://github.com/maxmind/MaxMind-DB-Reader-php).
436436

composer.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@
1515
"require": {
1616
"maxmind-db/reader": "~1.8",
1717
"maxmind/web-service-common": "~0.8",
18-
"php": ">=8.0",
18+
"php": ">=8.1",
1919
"ext-json": "*"
2020
},
2121
"require-dev": {
2222
"friendsofphp/php-cs-fixer": "3.*",
23-
"phpunit/phpunit": "^8.0 || ^9.0",
23+
"phpunit/phpunit": "^10.0",
2424
"squizlabs/php_codesniffer": "3.*",
2525
"phpstan/phpstan": "*"
2626
},

phpunit.xml.dist

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,8 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
3-
<phpunit bootstrap="./tests/bootstrap.php" colors="true">
4-
<testsuites>
5-
<testsuite name="GeoIP2 Test Suite">
6-
<directory suffix="Test.php">./tests/GeoIp2/Test/</directory>
7-
</testsuite>
8-
</testsuites>
9-
10-
<filter>
11-
<whitelist>
12-
<directory suffix=".php">./src/GeoIp2/</directory>
13-
</whitelist>
14-
</filter>
15-
16-
<logging>
17-
<log type="coverage-clover" target="build/logs/clover.xml"/>
18-
</logging>
19-
2+
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" bootstrap="./vendor/autoload.php" colors="true" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.4/phpunit.xsd" cacheDirectory=".phpunit.cache">
3+
<testsuites>
4+
<testsuite name="GeoIP2 Test Suite">
5+
<directory suffix="Test.php">./tests/GeoIp2/Test/</directory>
6+
</testsuite>
7+
</testsuites>
208
</phpunit>

src/Database/Reader.php

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
namespace GeoIp2\Database;
66

77
use GeoIp2\Exception\AddressNotFoundException;
8-
use GeoIp2\Model\AbstractModel;
98
use GeoIp2\Model\AnonymousIp;
109
use GeoIp2\Model\Asn;
1110
use GeoIp2\Model\City;
@@ -84,7 +83,6 @@ public function __construct(
8483
*/
8584
public function city(string $ipAddress): City
8685
{
87-
// @phpstan-ignore-next-line
8886
return $this->modelFor(City::class, 'City', $ipAddress);
8987
}
9088

@@ -100,7 +98,6 @@ public function city(string $ipAddress): City
10098
*/
10199
public function country(string $ipAddress): Country
102100
{
103-
// @phpstan-ignore-next-line
104101
return $this->modelFor(Country::class, 'Country', $ipAddress);
105102
}
106103

@@ -116,7 +113,6 @@ public function country(string $ipAddress): Country
116113
*/
117114
public function anonymousIp(string $ipAddress): AnonymousIp
118115
{
119-
// @phpstan-ignore-next-line
120116
return $this->flatModelFor(
121117
AnonymousIp::class,
122118
'GeoIP2-Anonymous-IP',
@@ -136,7 +132,6 @@ public function anonymousIp(string $ipAddress): AnonymousIp
136132
*/
137133
public function asn(string $ipAddress): Asn
138134
{
139-
// @phpstan-ignore-next-line
140135
return $this->flatModelFor(
141136
Asn::class,
142137
'GeoLite2-ASN',
@@ -156,7 +151,6 @@ public function asn(string $ipAddress): Asn
156151
*/
157152
public function connectionType(string $ipAddress): ConnectionType
158153
{
159-
// @phpstan-ignore-next-line
160154
return $this->flatModelFor(
161155
ConnectionType::class,
162156
'GeoIP2-Connection-Type',
@@ -176,7 +170,6 @@ public function connectionType(string $ipAddress): ConnectionType
176170
*/
177171
public function domain(string $ipAddress): Domain
178172
{
179-
// @phpstan-ignore-next-line
180173
return $this->flatModelFor(
181174
Domain::class,
182175
'GeoIP2-Domain',
@@ -196,7 +189,6 @@ public function domain(string $ipAddress): Domain
196189
*/
197190
public function enterprise(string $ipAddress): Enterprise
198191
{
199-
// @phpstan-ignore-next-line
200192
return $this->modelFor(Enterprise::class, 'Enterprise', $ipAddress);
201193
}
202194

@@ -212,15 +204,14 @@ public function enterprise(string $ipAddress): Enterprise
212204
*/
213205
public function isp(string $ipAddress): Isp
214206
{
215-
// @phpstan-ignore-next-line
216207
return $this->flatModelFor(
217208
Isp::class,
218209
'GeoIP2-ISP',
219210
$ipAddress
220211
);
221212
}
222213

223-
private function modelFor(string $class, string $type, string $ipAddress): AbstractModel
214+
private function modelFor(string $class, string $type, string $ipAddress): object
224215
{
225216
[$record, $prefixLen] = $this->getRecord($class, $type, $ipAddress);
226217

@@ -230,7 +221,7 @@ private function modelFor(string $class, string $type, string $ipAddress): Abstr
230221
return new $class($record, $this->locales);
231222
}
232223

233-
private function flatModelFor(string $class, string $type, string $ipAddress): AbstractModel
224+
private function flatModelFor(string $class, string $type, string $ipAddress): object
234225
{
235226
[$record, $prefixLen] = $this->getRecord($class, $type, $ipAddress);
236227

src/Model/AbstractModel.php

Lines changed: 0 additions & 68 deletions
This file was deleted.

src/Model/AnonymousIp.php

Lines changed: 86 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -8,53 +8,100 @@
88

99
/**
1010
* This class provides the GeoIP2 Anonymous IP model.
11-
*
12-
* @property-read bool $isAnonymous This is true if the IP address belongs to
13-
* any sort of anonymous network.
14-
* @property-read bool $isAnonymousVpn This is true if the IP address is
15-
* registered to an anonymous VPN provider. If a VPN provider does not
16-
* register subnets under names associated with them, we will likely only
17-
* flag their IP ranges using the isHostingProvider property.
18-
* @property-read bool $isHostingProvider This is true if the IP address belongs
19-
* to a hosting or VPN provider (see description of isAnonymousVpn property).
20-
* @property-read bool $isPublicProxy This is true if the IP address belongs to
21-
* a public proxy.
22-
* @property-read bool $isResidentialProxy This is true if the IP address is
23-
* on a suspected anonymizing network and belongs to a residential ISP.
24-
* @property-read bool $isTorExitNode This is true if the IP address is a Tor
25-
* exit node.
26-
* @property-read string $ipAddress The IP address that the data in the model is
27-
* for.
28-
* @property-read string $network The network in CIDR notation associated with
29-
* the record. In particular, this is the largest network where all of the
30-
* fields besides $ipAddress have the same value.
3111
*/
32-
class AnonymousIp extends AbstractModel
12+
class AnonymousIp implements \JsonSerializable
3313
{
34-
protected bool $isAnonymous;
35-
protected bool $isAnonymousVpn;
36-
protected bool $isHostingProvider;
37-
protected bool $isPublicProxy;
38-
protected bool $isResidentialProxy;
39-
protected bool $isTorExitNode;
40-
protected string $ipAddress;
41-
protected string $network;
14+
/**
15+
* @var bool this is true if the IP address belongs to
16+
* any sort of anonymous network
17+
*/
18+
public readonly bool $isAnonymous;
19+
20+
/**
21+
* @var bool This is true if the IP address is
22+
* registered to an anonymous VPN provider. If a VPN provider does not
23+
* register subnets under names associated with them, we will likely only
24+
* flag their IP ranges using the isHostingProvider property.
25+
*/
26+
public readonly bool $isAnonymousVpn;
27+
28+
/**
29+
* @var bool this is true if the IP address belongs
30+
* to a hosting or VPN provider (see description of isAnonymousVpn property)
31+
*/
32+
public readonly bool $isHostingProvider;
33+
34+
/**
35+
* @var bool this is true if the IP address belongs to
36+
* a public proxy
37+
*/
38+
public readonly bool $isPublicProxy;
39+
40+
/**
41+
* @var bool this is true if the IP address is
42+
* on a suspected anonymizing network and belongs to a residential ISP
43+
*/
44+
public readonly bool $isResidentialProxy;
45+
46+
/**
47+
* @var bool this is true if the IP address is a Tor
48+
* exit node
49+
*/
50+
public readonly bool $isTorExitNode;
51+
52+
/**
53+
* @var string the IP address that the data in the model is
54+
* for
55+
*/
56+
public readonly string $ipAddress;
57+
58+
/**
59+
* @var string The network in CIDR notation associated with
60+
* the record. In particular, this is the largest network where all of the
61+
* fields besides $ipAddress have the same value.
62+
*/
63+
public readonly string $network;
4264

4365
/**
4466
* @ignore
4567
*/
4668
public function __construct(array $raw)
4769
{
48-
parent::__construct($raw);
49-
50-
$this->isAnonymous = $this->get('is_anonymous');
51-
$this->isAnonymousVpn = $this->get('is_anonymous_vpn');
52-
$this->isHostingProvider = $this->get('is_hosting_provider');
53-
$this->isPublicProxy = $this->get('is_public_proxy');
54-
$this->isResidentialProxy = $this->get('is_residential_proxy');
55-
$this->isTorExitNode = $this->get('is_tor_exit_node');
56-
$ipAddress = $this->get('ip_address');
70+
$this->isAnonymous = $raw['is_anonymous'] ?? false;
71+
$this->isAnonymousVpn = $raw['is_anonymous_vpn'] ?? false;
72+
$this->isHostingProvider = $raw['is_hosting_provider'] ?? false;
73+
$this->isPublicProxy = $raw['is_public_proxy'] ?? false;
74+
$this->isResidentialProxy = $raw['is_residential_proxy'] ?? false;
75+
$this->isTorExitNode = $raw['is_tor_exit_node'] ?? false;
76+
$ipAddress = $raw['ip_address'];
5777
$this->ipAddress = $ipAddress;
58-
$this->network = Util::cidr($ipAddress, $this->get('prefix_len'));
78+
$this->network = Util::cidr($ipAddress, $raw['prefix_len']);
79+
}
80+
81+
public function jsonSerialize(): ?array
82+
{
83+
$js = [];
84+
if ($this->isAnonymous !== null) {
85+
$js['is_anonymous'] = $this->isAnonymous;
86+
}
87+
if ($this->isAnonymousVpn !== null) {
88+
$js['is_anonymous_vpn'] = $this->isAnonymousVpn;
89+
}
90+
if ($this->isHostingProvider !== null) {
91+
$js['is_hosting_provider'] = $this->isHostingProvider;
92+
}
93+
if ($this->isPublicProxy !== null) {
94+
$js['is_public_proxy'] = $this->isPublicProxy;
95+
}
96+
if ($this->isResidentialProxy !== null) {
97+
$js['is_residential_proxy'] = $this->isResidentialProxy;
98+
}
99+
if ($this->isTorExitNode !== null) {
100+
$js['is_tor_exit_node'] = $this->isTorExitNode;
101+
}
102+
$js['ip_address'] = $this->ipAddress;
103+
$js['network'] = $this->network;
104+
105+
return $js;
59106
}
60107
}

0 commit comments

Comments
 (0)