Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use readonly properties for model classes #217

Merged
merged 10 commits into from
Nov 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: 8.1
php-version: 8.2

- name: Checkout
uses: actions/checkout@v4
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
strategy:
matrix:
operating-system: [ubuntu-latest, windows-latest, macos-latest]
php-versions: ['8.0', '8.1']
php-versions: ['8.1', '8.2']
name: "PHP ${{ matrix.php-versions }} test on ${{ matrix.operating-system }}"
steps:
- name: Setup PHP
Expand All @@ -33,4 +33,4 @@ jobs:
run: composer install --no-progress --prefer-dist --optimize-autoloader

- name: Test with phpunit
run: vendor/bin/phpunit --coverage-text
run: vendor/bin/phpunit
9 changes: 8 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,14 @@ CHANGELOG
3.0.0
-------------------

* IMPORTANT: PHP 8.0 or greater is now required.
* IMPORTANT: PHP 8.1 or greater is now required.
* BREAKING: Read-only properties are now used for the model and record
classes rather than magic methods. This significantly improves performance.
* BREAKING: The `raw` property on model classess and the `record` property on
record classes have been removed.
* BREAKING: On `GeoIp2\Record\Traits`, the deprecated `isAnonymousProxy` and
`isSatelliteProvider` properties have been removed.
* BREAKING: The `jsonSerialize` output has changed.
* `GeoIp2\WebService\Client` methods now throw an `InvalidArgumentException`
if an invalid IP address is passed to them. Previously, they would make
a request to the web service and throw a
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,7 @@ to the client API, please see

## Requirements ##

This library requires PHP 8.0 or greater.
This library requires PHP 8.1 or greater.

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

Expand Down
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@
"require": {
"maxmind-db/reader": "~1.8",
"maxmind/web-service-common": "~0.8",
"php": ">=8.0",
"php": ">=8.1",
"ext-json": "*"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "3.*",
"phpunit/phpunit": "^8.0 || ^9.0",
"phpunit/phpunit": "^10.0",
"squizlabs/php_codesniffer": "3.*",
"phpstan/phpstan": "*"
},
Expand Down
24 changes: 6 additions & 18 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
@@ -1,20 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>

<phpunit bootstrap="./tests/bootstrap.php" colors="true">
<testsuites>
<testsuite name="GeoIP2 Test Suite">
<directory suffix="Test.php">./tests/GeoIp2/Test/</directory>
</testsuite>
</testsuites>

<filter>
<whitelist>
<directory suffix=".php">./src/GeoIp2/</directory>
</whitelist>
</filter>

<logging>
<log type="coverage-clover" target="build/logs/clover.xml"/>
</logging>

<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">
<testsuites>
<testsuite name="GeoIP2 Test Suite">
<directory suffix="Test.php">./tests/GeoIp2/Test/</directory>
</testsuite>
</testsuites>
</phpunit>
13 changes: 2 additions & 11 deletions src/Database/Reader.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
namespace GeoIp2\Database;

use GeoIp2\Exception\AddressNotFoundException;
use GeoIp2\Model\AbstractModel;
use GeoIp2\Model\AnonymousIp;
use GeoIp2\Model\Asn;
use GeoIp2\Model\City;
Expand Down Expand Up @@ -84,7 +83,6 @@ public function __construct(
*/
public function city(string $ipAddress): City
{
// @phpstan-ignore-next-line
return $this->modelFor(City::class, 'City', $ipAddress);
}

Expand All @@ -100,7 +98,6 @@ public function city(string $ipAddress): City
*/
public function country(string $ipAddress): Country
{
// @phpstan-ignore-next-line
return $this->modelFor(Country::class, 'Country', $ipAddress);
}

Expand All @@ -116,7 +113,6 @@ public function country(string $ipAddress): Country
*/
public function anonymousIp(string $ipAddress): AnonymousIp
{
// @phpstan-ignore-next-line
return $this->flatModelFor(
AnonymousIp::class,
'GeoIP2-Anonymous-IP',
Expand All @@ -136,7 +132,6 @@ public function anonymousIp(string $ipAddress): AnonymousIp
*/
public function asn(string $ipAddress): Asn
{
// @phpstan-ignore-next-line
return $this->flatModelFor(
Asn::class,
'GeoLite2-ASN',
Expand All @@ -156,7 +151,6 @@ public function asn(string $ipAddress): Asn
*/
public function connectionType(string $ipAddress): ConnectionType
{
// @phpstan-ignore-next-line
return $this->flatModelFor(
ConnectionType::class,
'GeoIP2-Connection-Type',
Expand All @@ -176,7 +170,6 @@ public function connectionType(string $ipAddress): ConnectionType
*/
public function domain(string $ipAddress): Domain
{
// @phpstan-ignore-next-line
return $this->flatModelFor(
Domain::class,
'GeoIP2-Domain',
Expand All @@ -196,7 +189,6 @@ public function domain(string $ipAddress): Domain
*/
public function enterprise(string $ipAddress): Enterprise
{
// @phpstan-ignore-next-line
return $this->modelFor(Enterprise::class, 'Enterprise', $ipAddress);
}

Expand All @@ -212,15 +204,14 @@ public function enterprise(string $ipAddress): Enterprise
*/
public function isp(string $ipAddress): Isp
{
// @phpstan-ignore-next-line
return $this->flatModelFor(
Isp::class,
'GeoIP2-ISP',
$ipAddress
);
}

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

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

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

Expand Down
68 changes: 0 additions & 68 deletions src/Model/AbstractModel.php

This file was deleted.

125 changes: 86 additions & 39 deletions src/Model/AnonymousIp.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,53 +8,100 @@

/**
* This class provides the GeoIP2 Anonymous IP model.
*
* @property-read bool $isAnonymous This is true if the IP address belongs to
* any sort of anonymous network.
* @property-read bool $isAnonymousVpn This is true if the IP address is
* registered to an anonymous VPN provider. If a VPN provider does not
* register subnets under names associated with them, we will likely only
* flag their IP ranges using the isHostingProvider property.
* @property-read bool $isHostingProvider This is true if the IP address belongs
* to a hosting or VPN provider (see description of isAnonymousVpn property).
* @property-read bool $isPublicProxy This is true if the IP address belongs to
* a public proxy.
* @property-read bool $isResidentialProxy This is true if the IP address is
* on a suspected anonymizing network and belongs to a residential ISP.
* @property-read bool $isTorExitNode This is true if the IP address is a Tor
* exit node.
* @property-read string $ipAddress The IP address that the data in the model is
* for.
* @property-read string $network The network in CIDR notation associated with
* the record. In particular, this is the largest network where all of the
* fields besides $ipAddress have the same value.
*/
class AnonymousIp extends AbstractModel
class AnonymousIp implements \JsonSerializable
{
protected bool $isAnonymous;
protected bool $isAnonymousVpn;
protected bool $isHostingProvider;
protected bool $isPublicProxy;
protected bool $isResidentialProxy;
protected bool $isTorExitNode;
protected string $ipAddress;
protected string $network;
/**
* @var bool this is true if the IP address belongs to
* any sort of anonymous network
*/
public readonly bool $isAnonymous;

/**
* @var bool This is true if the IP address is
* registered to an anonymous VPN provider. If a VPN provider does not
* register subnets under names associated with them, we will likely only
* flag their IP ranges using the isHostingProvider property.
*/
public readonly bool $isAnonymousVpn;

/**
* @var bool this is true if the IP address belongs
* to a hosting or VPN provider (see description of isAnonymousVpn property)
*/
public readonly bool $isHostingProvider;

/**
* @var bool this is true if the IP address belongs to
* a public proxy
*/
public readonly bool $isPublicProxy;

/**
* @var bool this is true if the IP address is
* on a suspected anonymizing network and belongs to a residential ISP
*/
public readonly bool $isResidentialProxy;

/**
* @var bool this is true if the IP address is a Tor
* exit node
*/
public readonly bool $isTorExitNode;

/**
* @var string the IP address that the data in the model is
* for
*/
public readonly string $ipAddress;

/**
* @var string The network in CIDR notation associated with
* the record. In particular, this is the largest network where all of the
* fields besides $ipAddress have the same value.
*/
public readonly string $network;

/**
* @ignore
*/
public function __construct(array $raw)
{
parent::__construct($raw);

$this->isAnonymous = $this->get('is_anonymous');
$this->isAnonymousVpn = $this->get('is_anonymous_vpn');
$this->isHostingProvider = $this->get('is_hosting_provider');
$this->isPublicProxy = $this->get('is_public_proxy');
$this->isResidentialProxy = $this->get('is_residential_proxy');
$this->isTorExitNode = $this->get('is_tor_exit_node');
$ipAddress = $this->get('ip_address');
$this->isAnonymous = $raw['is_anonymous'] ?? false;
$this->isAnonymousVpn = $raw['is_anonymous_vpn'] ?? false;
$this->isHostingProvider = $raw['is_hosting_provider'] ?? false;
$this->isPublicProxy = $raw['is_public_proxy'] ?? false;
$this->isResidentialProxy = $raw['is_residential_proxy'] ?? false;
$this->isTorExitNode = $raw['is_tor_exit_node'] ?? false;
$ipAddress = $raw['ip_address'];
$this->ipAddress = $ipAddress;
$this->network = Util::cidr($ipAddress, $this->get('prefix_len'));
$this->network = Util::cidr($ipAddress, $raw['prefix_len']);
}

public function jsonSerialize(): ?array
{
$js = [];
if ($this->isAnonymous !== null) {
$js['is_anonymous'] = $this->isAnonymous;
}
if ($this->isAnonymousVpn !== null) {
$js['is_anonymous_vpn'] = $this->isAnonymousVpn;
}
if ($this->isHostingProvider !== null) {
$js['is_hosting_provider'] = $this->isHostingProvider;
}
if ($this->isPublicProxy !== null) {
$js['is_public_proxy'] = $this->isPublicProxy;
}
if ($this->isResidentialProxy !== null) {
$js['is_residential_proxy'] = $this->isResidentialProxy;
}
if ($this->isTorExitNode !== null) {
$js['is_tor_exit_node'] = $this->isTorExitNode;
}
$js['ip_address'] = $this->ipAddress;
$js['network'] = $this->network;

return $js;
}
}
Loading