Repository: jmikola/geojson
Branch: master
Commit: e28f3855bb61
Files: 48
Total size: 99.5 KB
Directory structure:
gitextract_kuvb7uxu/
├── .gitattributes
├── .github/
│ └── workflows/
│ ├── coding-standards.yml
│ └── tests.yml
├── .gitignore
├── .scrutinizer.yml
├── LICENSE
├── README.md
├── USAGE.md
├── composer.json
├── phpcs.xml.dist
├── phpunit.xml.dist
├── src/
│ ├── BoundingBox.php
│ ├── CoordinateReferenceSystem/
│ │ ├── CoordinateReferenceSystem.php
│ │ ├── Linked.php
│ │ └── Named.php
│ ├── Exception/
│ │ ├── Exception.php
│ │ ├── InvalidArgumentException.php
│ │ └── UnserializationException.php
│ ├── Feature/
│ │ ├── Feature.php
│ │ └── FeatureCollection.php
│ ├── GeoJson.php
│ ├── Geometry/
│ │ ├── Geometry.php
│ │ ├── GeometryCollection.php
│ │ ├── LineString.php
│ │ ├── LinearRing.php
│ │ ├── MultiLineString.php
│ │ ├── MultiPoint.php
│ │ ├── MultiPolygon.php
│ │ ├── Point.php
│ │ └── Polygon.php
│ └── JsonUnserializable.php
└── tests/
├── BaseGeoJsonTest.php
├── BoundingBoxTest.php
├── CoordinateReferenceSystem/
│ ├── CoordinateReferenceSystemTest.php
│ ├── LinkedTest.php
│ └── NamedTest.php
├── Feature/
│ ├── FeatureCollectionTest.php
│ └── FeatureTest.php
├── GeoJsonTest.php
└── Geometry/
├── GeometryCollectionTest.php
├── GeometryTest.php
├── LineStringTest.php
├── LinearRingTest.php
├── MultiLineStringTest.php
├── MultiPointTest.php
├── MultiPolygonTest.php
├── PointTest.php
└── PolygonTest.php
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitattributes
================================================
*.php diff=php
/tests export-ignore
/.gitattributes export-ignore
/.github export-ignore
/.gitignore export-ignore
/.scrutinizer.yml export-ignore
/phpcs.xml.dist export-ignore
/phpunit.xml.dist export-ignore
================================================
FILE: .github/workflows/coding-standards.yml
================================================
name: "Coding Standards"
on:
pull_request:
branches:
- "v*.*"
- "master"
push:
branches:
- "v*.*"
- "master"
jobs:
coding-standards:
name: "Coding Standards"
runs-on: "ubuntu-20.04"
strategy:
matrix:
php-version:
- "7.4"
steps:
- name: "Checkout"
uses: "actions/checkout@v2"
- name: "Install PHP"
uses: "shivammathur/setup-php@v2"
with:
coverage: "none"
php-version: "${{ matrix.php-version }}"
tools: "cs2pr"
- name: "Cache dependencies installed with Composer"
uses: "actions/cache@v2"
with:
path: "~/.composer/cache"
key: "php-${{ matrix.php-version }}-composer-locked-${{ hashFiles('composer.lock') }}"
restore-keys: "php-${{ matrix.php-version }}-composer-locked-"
- name: "Install dependencies with Composer"
run: "composer install --no-interaction --no-progress --no-suggest"
# The -q option is required until phpcs v4 is released
- name: "Run PHP_CodeSniffer"
run: "vendor/bin/phpcs -q --no-colors --report=checkstyle | cs2pr"
================================================
FILE: .github/workflows/tests.yml
================================================
name: "Tests"
on:
pull_request:
push:
jobs:
phpunit:
name: PHPUnit Tests
runs-on: ubuntu-20.04
strategy:
matrix:
php:
- "7.4"
- "8.0"
- "8.1"
- "8.2"
dependency-versions:
- "highest"
include:
- php: "7.4"
dependency-versions: "lowest"
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 2
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
- name: Install Dependencies
uses: "ramsey/composer-install@v2"
with:
dependency-versions: "${{ matrix.dependency-versions }}"
composer-options: "${{ matrix.composer-options }}"
- name: Run PHPUnit
run: "vendor/bin/phpunit --coverage-clover=coverage.clover"
- name: Upload Coverage
if: github.repository_owner == 'jmikola'
run: "vendor/bin/ocular code-coverage:upload --format=php-clover coverage.clover"
================================================
FILE: .gitignore
================================================
.phpcs-cache
.phpunit.result.cache
composer.lock
phpunit.xml
vendor
================================================
FILE: .scrutinizer.yml
================================================
filter:
excluded_paths: [ "vendor/*", "tests/*" ]
tools:
# https://scrutinizer-ci.com/docs/tools/external-code-coverage/
external_code_coverage: true
# https://scrutinizer-ci.com/docs/tools/php/php-analyzer/
php_analyzer: true
# https://scrutinizer-ci.com/docs/tools/php/change-tracking-analyzer/
php_changetracking: true
# https://scrutinizer-ci.com/docs/tools/php/code-sniffer/
php_code_sniffer:
config:
standard: "PSR1"
# https://scrutinizer-ci.com/docs/tools/php/mess-detector/
php_mess_detector: true
# https://scrutinizer-ci.com/docs/tools/php/pdepend/
php_pdepend: true
# https://scrutinizer-ci.com/docs/tools/php/code-similarity-analyzer/
php_sim: true
sensiolabs_security_checker: true
================================================
FILE: LICENSE
================================================
Copyright (c) 2013-present Jeremy Mikola
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
================================================
FILE: README.md
================================================
# GeoJson PHP Library
[](https://github.com/jmikola/geojson/actions)
[](https://scrutinizer-ci.com/g/jmikola/geojson/?branch=master)
[](https://scrutinizer-ci.com/g/jmikola/geojson/?branch=master)
This library implements the
[GeoJSON format specification](https://geojson.org/).
## Installation
The library is published as a
[package](https://packagist.org/packages/jmikola/geojson) and is installable via
[Composer](https://getcomposer.org/):
```
$ composer require "jmikola/geojson=^1.0"
```
## Additional Resources
* [Usage Documentation](./USAGE.md)
* [License](./LICENSE)
================================================
FILE: USAGE.md
================================================
# GeoJson PHP Library
This library implements the
[GeoJSON format specification](https://geojson.org/).
The `GeoJson` namespace includes classes for each data structure defined in the
GeoJSON specification. Core GeoJSON objects include geometries, features, and
collections. Geometries range from primitive points to more complex polygons.
Classes also exist for bounding boxes and coordinate reference systems.
## Installation
The library is published as a
[package](https://packagist.org/packages/jmikola/geojson) and is installable via
[Composer](https://getcomposer.org/):
```
$ composer require "jmikola/geojson=^1.0"
```
## Usage
Classes in this library are immutable.
### GeoJson Constructors
Geometry objects are constructed using a single coordinates array. This may be
a tuple in the case of a `Point`, an array of tuples for a `LineString`, etc.
Constructors for each class will validate the coordinates array and throw an
`InvalidArgumentException` on error.
More primitive geometry objects may also be used for constructing complex
objects. For instance, a `LineString` may be constructed from an array of
`Point` objects.
Feature objects are constructed from a geometry object, associative properties
array, and an identifier, all of which are optional.
Feature and geometry collection objects are constructed from an array of their
respective types.
#### Specifying a Bounding Box or CRS
All GeoJson constructors support `BoundingBox` and `CoordinateReferenceSystem`
objects as optional arguments beyond those explicitly listed in their prototype.
These objects may appear in any order *after* the explicit arguments.
```php
$crs = new \GeoJson\CoordinateReferenceSystem\Named('urn:ogc:def:crs:OGC:1.3:CRS84');
$box = new \GeoJson\BoundingBox([-180, -90, 180, 90]);
$point = new \GeoJson\Geometry\Point([0, 0], $crs, $box);
```
Note that the `Feature` class is unique in that it has three arguments, all with
default values. In order to construct a `Feature` with a bounding box or CRS,
all three arguments must be explicitly listed (e.g. with `null` placeholders).
```php
$box = new \GeoJson\BoundingBox([-180, -90, 180, 90]);
$feature = new \GeoJson\Feature\Feature(null, null, null, $box);
```
### JSON Serialization
Each class in the library implements the
[JsonSerializable](https://php.net/manual/en/class.jsonserializable.php)
interface, which allows objects to be passed directly to `json_encode()`.
```php
$point = new \GeoJson\Geometry\Point([1, 1]);
$json = json_encode($point);
```
Printing the `$json` variable would yield (sans whitespace):
```json
{
"type": "Point",
"coordinates": [1, 1]
}
```
### JSON Unserialization
The core `GeoJson` class implements an internal `JsonUnserializable` interface,
which defines a static factory method, `jsonUnserialize()`, that can be used to
create objects from the return value of `json_decode()`.
```php
$json = '{ "type": "Point", "coordinates": [1, 1] }';
$json = json_decode($json);
$point = \GeoJson\GeoJson::jsonUnserialize($json);
```
If errors are encountered during unserialization, an `UnserializationException`
will be thrown by `jsonUnserialize()`. Possible errors include:
* Missing properties (e.g. `type` is not present)
* Unexpected values (e.g. `coordinates` property is not an array)
* Unsupported `type` string when parsing a GeoJson object or CRS
================================================
FILE: composer.json
================================================
{
"name": "jmikola/geojson",
"type": "library",
"description": "GeoJSON implementation for PHP",
"keywords": ["geo", "geospatial", "geojson"],
"homepage": "https://github.com/jmikola/geojson",
"license": "MIT",
"authors": [
{ "name": "Jeremy Mikola", "email": "jmikola@gmail.com" }
],
"require": {
"php": "^7.4 || ^8.0",
"ext-json": "*",
"symfony/polyfill-php80": "^1.25"
},
"require-dev": {
"phpunit/phpunit": "^9.5",
"scrutinizer/ocular": "^1.8.1",
"squizlabs/php_codesniffer": "^3.6",
"slevomat/coding-standard": "^8.0"
},
"autoload": {
"psr-4": {
"GeoJson\\": "src"
}
},
"autoload-dev": {
"psr-4": {
"GeoJson\\Tests\\": "tests"
}
},
"extra": {
"branch-alias": {
"dev-master": "1.1-dev"
}
},
"config": {
"allow-plugins": {
"dealerdirect/phpcodesniffer-composer-installer": true
}
}
}
================================================
FILE: phpcs.xml.dist
================================================
<?xml version="1.0"?>
<ruleset>
<arg name="basepath" value="." />
<arg name="extensions" value="php" />
<arg name="cache" value=".phpcs-cache" />
<arg name="colors" />
<!-- Ignore warnings (n), show progress of the run (p), and show sniff names (s) -->
<arg value="nps"/>
<file>src</file>
<file>tests</file>
<rule ref="PSR12">
<!-- ********************************************** -->
<!-- Exclude sniffs that require newer PHP versions -->
<!-- ********************************************** -->
<!-- Requires PHP 8.0 -->
<exclude name="SlevomatCodingStandard.Classes.ModernClassNameReference.ClassNameReferencedViaFunctionCall" />
<!-- *********************************** -->
<!-- Exclude sniffs that cause BC breaks -->
<!-- *********************************** -->
<exclude name="SlevomatCodingStandard.Classes.SuperfluousAbstractClassNaming" />
<exclude name="SlevomatCodingStandard.Classes.SuperfluousExceptionNaming" />
<exclude name="SlevomatCodingStandard.Classes.SuperfluousInterfaceNaming" />
<exclude name="SlevomatCodingStandard.Classes.SuperfluousTraitNaming" />
<!-- **************************************** -->
<!-- Exclude sniffs that force unwanted style -->
<!-- **************************************** -->
<exclude name="Generic.Formatting.MultipleStatementAlignment" />
<exclude name="Squiz.Commenting.FunctionComment.ThrowsNoFullStop" />
<!-- Keep long typehints (for now) -->
<exclude name="SlevomatCodingStandard.PHP.TypeCast.InvalidCastUsed" />
<exclude name="SlevomatCodingStandard.TypeHints.LongTypeHints" />
<!-- ************************************************ -->
<!-- Exclude sniffs that may cause functional changes -->
<!-- ************************************************ -->
<exclude name="Generic.PHP.ForbiddenFunctions.FoundWithAlternative" />
<exclude name="SlevomatCodingStandard.ControlStructures.DisallowYodaComparison" />
<exclude name="SlevomatCodingStandard.ControlStructures.EarlyExit" />
<exclude name="SlevomatCodingStandard.ControlStructures.UselessIfConditionWithReturn" />
<exclude name="SlevomatCodingStandard.Functions.StaticClosure" />
<exclude name="SlevomatCodingStandard.Functions.UnusedInheritedVariablePassedToClosure" />
<exclude name="SlevomatCodingStandard.Operators.DisallowEqualOperators" />
<!-- ********************************************************* -->
<!-- Exclude sniffs that cause a huge diff - enable separately -->
<!-- ********************************************************* -->
<exclude name="SlevomatCodingStandard.Commenting.DocCommentSpacing.IncorrectAnnotationsGroup" />
<exclude name="Squiz.Strings.DoubleQuoteUsage" />
<!-- ********************* -->
<!-- Exclude broken sniffs -->
<!-- ********************* -->
<!-- Sniff currently broken when casting arrays, see https://github.com/squizlabs/PHP_CodeSniffer/issues/2937#issuecomment-615498860 -->
<exclude name="Squiz.Arrays.ArrayDeclaration.ValueNoNewline" />
<!-- Disable forbidden annotation sniff as excluding @api from the list doesn't work -->
<exclude name="SlevomatCodingStandard.Commenting.ForbiddenAnnotations.AnnotationForbidden" />
</rule>
<!-- ***************************************************** -->
<!-- Forbid fully qualified names even for colliding names -->
<!-- ***************************************************** -->
<rule ref="SlevomatCodingStandard.Namespaces.ReferenceUsedNamesOnly">
<properties>
<property name="allowFallbackGlobalConstants" value="false"/>
<property name="allowFallbackGlobalFunctions" value="false"/>
<property name="allowFullyQualifiedGlobalClasses" value="false"/>
<property name="allowFullyQualifiedGlobalConstants" value="false"/>
<property name="allowFullyQualifiedGlobalFunctions" value="false"/>
<property phpcs-only="true" name="allowFullyQualifiedNameForCollidingClasses" value="true"/>
<property phpcs-only="true" name="allowFullyQualifiedNameForCollidingConstants" value="false"/>
<property phpcs-only="true" name="allowFullyQualifiedNameForCollidingFunctions" value="false"/>
<property name="searchAnnotations" value="true"/>
</properties>
</rule>
<rule ref="SlevomatCodingStandard.Namespaces.AlphabeticallySortedUses"/>
<!-- **************************************************************************** -->
<!-- Exclude BC breaking type hints for parameters, properties, and return values -->
<!-- **************************************************************************** -->
<rule ref="SlevomatCodingStandard.TypeHints.ParameterTypeHint">
<properties>
<!-- Requires PHP 8.0 -->
<property name="enableMixedTypeHint" value="false" />
<!-- Requires PHP 8.0 -->
<property name="enableUnionTypeHint" value="false" />
</properties>
<exclude name="SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingTraversableTypeHintSpecification" />
<exclude name="SlevomatCodingStandard.TypeHints.ParameterTypeHint.UselessAnnotation" />
</rule>
<rule ref="SlevomatCodingStandard.TypeHints.PropertyTypeHint">
<properties>
<!-- Requires PHP 8.0 -->
<property name="enableMixedTypeHint" value="false" />
<!-- Requires PHP 8.0 -->
<property name="enableUnionTypeHint" value="false" />
</properties>
<exclude name="SlevomatCodingStandard.TypeHints.PropertyTypeHint.MissingTraversableTypeHintSpecification" />
<exclude name="SlevomatCodingStandard.TypeHints.PropertyTypeHint.UselessAnnotation" />
</rule>
<rule ref="SlevomatCodingStandard.TypeHints.ReturnTypeHint">
<properties>
<!-- Requires PHP 8.0 -->
<property name="enableStaticTypeHint" value="false" />
<!-- Requires PHP 8.0 -->
<property name="enableMixedTypeHint" value="false" />
<!-- Requires PHP 8.0 -->
<property name="enableUnionTypeHint" value="false" />
</properties>
<exclude name="SlevomatCodingStandard.TypeHints.ReturnTypeHint.MissingTraversableTypeHintSpecification" />
<exclude name="SlevomatCodingStandard.TypeHints.ReturnTypeHint.UselessAnnotation" />
</rule>
<!-- ************************************************************************** -->
<!-- Require type hints for all parameters, properties, and return types in src -->
<!-- ************************************************************************** -->
<rule ref="SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingAnyTypeHint">
<exclude-pattern>tests</exclude-pattern>
</rule>
<rule ref="SlevomatCodingStandard.TypeHints.PropertyTypeHint.MissingAnyTypeHint">
<exclude-pattern>tests</exclude-pattern>
</rule>
<rule ref="SlevomatCodingStandard.TypeHints.ReturnTypeHint.MissingAnyTypeHint">
<exclude-pattern>tests</exclude-pattern>
</rule>
<!-- *********************************************************************************** -->
<!-- Require native type hints for all parameters, properties, and return types in tests -->
<!-- *********************************************************************************** -->
<rule ref="SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint">
<exclude-pattern>src</exclude-pattern>
</rule>
<rule ref="SlevomatCodingStandard.TypeHints.PropertyTypeHint.MissingNativeTypeHint">
<exclude-pattern>src</exclude-pattern>
</rule>
<rule ref="SlevomatCodingStandard.TypeHints.ReturnTypeHint.MissingNativeTypeHint">
<exclude-pattern>src</exclude-pattern>
</rule>
<rule ref="SlevomatCodingStandard.TypeHints.DeclareStrictTypes">
<properties>
<property name="newlinesCountBetweenOpenTagAndDeclare" type="int" value="2" />
<property name="spacesCountAroundEqualsSign" type="int" value="0" />
</properties>
</rule>
<rule ref="Generic.Arrays.DisallowLongArraySyntax" />
</ruleset>
================================================
FILE: phpunit.xml.dist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
colors="true"
>
<testsuites>
<testsuite name="GeoJson Test Suite">
<directory>./tests/</directory>
</testsuite>
</testsuites>
<coverage ignoreDeprecatedCodeUnits="true" processUncoveredFiles="true">
<include>
<directory suffix=".php">./src/</directory>
</include>
</coverage>
</phpunit>
================================================
FILE: src/BoundingBox.php
================================================
<?php
declare(strict_types=1);
namespace GeoJson;
use GeoJson\Exception\InvalidArgumentException;
use GeoJson\Exception\UnserializationException;
use JsonSerializable;
use function count;
use function is_array;
use function is_float;
use function is_int;
/**
* BoundingBox object.
*
* @see http://www.geojson.org/geojson-spec.html#bounding-boxes
* @since 1.0
*/
class BoundingBox implements JsonSerializable, JsonUnserializable
{
/**
* @var array<float|int>
*/
protected array $bounds;
/**
* @param array<float|int> $bounds
*/
public function __construct(array $bounds)
{
$count = count($bounds);
if ($count < 4) {
throw new InvalidArgumentException('BoundingBox requires at least four values');
}
if ($count % 2) {
throw new InvalidArgumentException('BoundingBox requires an even number of values');
}
foreach ($bounds as $value) {
if (! is_int($value) && ! is_float($value)) {
throw new InvalidArgumentException('BoundingBox values must be integers or floats');
}
}
for ($i = 0; $i < ($count / 2); $i++) {
if ($bounds[$i] > $bounds[$i + ($count / 2)]) {
throw new InvalidArgumentException('BoundingBox min values must precede max values');
}
}
$this->bounds = $bounds;
}
/**
* Return the bounds for this BoundingBox object.
*
* @return array<float|int>
*/
public function getBounds(): array
{
return $this->bounds;
}
public function jsonSerialize(): array
{
return $this->bounds;
}
/**
* @param array $json
*/
final public static function jsonUnserialize($json): self
{
if (! is_array($json)) {
throw UnserializationException::invalidValue('BoundingBox', $json, 'array');
}
return new self($json);
}
}
================================================
FILE: src/CoordinateReferenceSystem/CoordinateReferenceSystem.php
================================================
<?php
declare(strict_types=1);
namespace GeoJson\CoordinateReferenceSystem;
use ArrayObject;
use BadMethodCallException;
use GeoJson\Exception\UnserializationException;
use GeoJson\JsonUnserializable;
use JsonSerializable;
use function is_array;
use function is_object;
use function sprintf;
/**
* Coordinate reference system object.
*
* @deprecated 1.1 Specification of coordinate reference systems has been removed, i.e.,
* the 'crs' member of [GJ2008] is no longer used.
*
* @see https://www.rfc-editor.org/rfc/rfc7946#appendix-B.1
* @see http://www.geojson.org/geojson-spec.html#coordinate-reference-system-objects
* @since 1.0
*/
abstract class CoordinateReferenceSystem implements JsonSerializable, JsonUnserializable
{
protected array $properties;
protected string $type;
/**
* Return the properties for this CRS object.
*/
public function getProperties(): array
{
return $this->properties;
}
/**
* Return the type for this CRS object.
*/
public function getType(): string
{
return $this->type;
}
public function jsonSerialize(): array
{
return [
'type' => $this->type,
'properties' => $this->properties,
];
}
/**
* @param array|object $json
*/
final public static function jsonUnserialize($json): self
{
if (! is_array($json) && ! is_object($json)) {
throw UnserializationException::invalidValue('CRS', $json, 'array or object');
}
$json = new ArrayObject($json);
if (! $json->offsetExists('type')) {
throw UnserializationException::missingProperty('CRS', 'type', 'string');
}
if (! $json->offsetExists('properties')) {
throw UnserializationException::missingProperty('CRS', 'properties', 'array or object');
}
$type = (string) $json['type'];
$properties = $json['properties'];
switch ($type) {
case 'link':
return Linked::jsonUnserializeFromProperties($properties);
case 'name':
return Named::jsonUnserializeFromProperties($properties);
}
throw UnserializationException::unsupportedType('CRS', $type);
}
/**
* Factory method for creating a CRS object from properties.
*
* This method must be overridden in a child class.
*
* @param array|object $properties
*
* @throws BadMethodCallException
*/
protected static function jsonUnserializeFromProperties($properties): CoordinateReferenceSystem
{
throw new BadMethodCallException(sprintf('%s must be overridden in a child class', __METHOD__));
}
}
================================================
FILE: src/CoordinateReferenceSystem/Linked.php
================================================
<?php
declare(strict_types=1);
namespace GeoJson\CoordinateReferenceSystem;
use ArrayObject;
use GeoJson\Exception\UnserializationException;
use function is_array;
use function is_object;
/**
* Linked coordinate reference system object.
*
* @deprecated 1.1 Specification of coordinate reference systems has been removed, i.e.,
* the 'crs' member of [GJ2008] is no longer used.
*
* @see https://www.rfc-editor.org/rfc/rfc7946#appendix-B.1
* @see http://www.geojson.org/geojson-spec.html#linked-crs
* @since 1.0
*/
class Linked extends CoordinateReferenceSystem
{
protected string $type = 'link';
public function __construct(string $href, ?string $type = null)
{
$this->properties = ['href' => $href];
if ($type !== null) {
$this->properties['type'] = $type;
}
}
/**
* Factory method for creating a Linked CRS object from properties.
*
* @param array|object $properties
*
* @throws UnserializationException
*/
protected static function jsonUnserializeFromProperties($properties): self
{
if (! is_array($properties) && ! is_object($properties)) {
throw UnserializationException::invalidProperty('Linked CRS', 'properties', $properties, 'array or object');
}
$properties = new ArrayObject($properties);
if (! $properties->offsetExists('href')) {
throw UnserializationException::missingProperty('Linked CRS', 'properties.href', 'string');
}
$href = (string) $properties['href'];
$type = isset($properties['type']) ? (string) $properties['type'] : null;
return new self($href, $type);
}
}
================================================
FILE: src/CoordinateReferenceSystem/Named.php
================================================
<?php
declare(strict_types=1);
namespace GeoJson\CoordinateReferenceSystem;
use ArrayObject;
use GeoJson\Exception\UnserializationException;
use function is_array;
use function is_object;
/**
* Named coordinate reference system object.
*
* @deprecated 1.1 Specification of coordinate reference systems has been removed, i.e.,
* the 'crs' member of [GJ2008] is no longer used.
*
* @see http://www.geojson.org/geojson-spec.html#named-crs
* @since 1.0
*/
class Named extends CoordinateReferenceSystem
{
protected string $type = 'name';
public function __construct(string $name)
{
$this->properties = ['name' => $name];
}
/**
* Factory method for creating a Named CRS object from properties.
*
* @param array|object $properties
*
* @throws UnserializationException
*/
protected static function jsonUnserializeFromProperties($properties): self
{
if (! is_array($properties) && ! is_object($properties)) {
throw UnserializationException::invalidProperty('Named CRS', 'properties', $properties, 'array or object');
}
$properties = new ArrayObject($properties);
if (! $properties->offsetExists('name')) {
throw UnserializationException::missingProperty('Named CRS', 'properties.name', 'string');
}
$name = (string) $properties['name'];
return new self($name);
}
}
================================================
FILE: src/Exception/Exception.php
================================================
<?php
declare(strict_types=1);
namespace GeoJson\Exception;
interface Exception
{
}
================================================
FILE: src/Exception/InvalidArgumentException.php
================================================
<?php
declare(strict_types=1);
namespace GeoJson\Exception;
class InvalidArgumentException extends \InvalidArgumentException implements Exception
{
}
================================================
FILE: src/Exception/UnserializationException.php
================================================
<?php
declare(strict_types=1);
namespace GeoJson\Exception;
use RuntimeException;
use function get_class;
use function get_debug_type;
use function gettype;
use function is_object;
use function sprintf;
class UnserializationException extends RuntimeException implements Exception
{
/**
* Creates an UnserializationException for a value with an invalid type.
*
* @param mixed $value
*/
public static function invalidValue(string $context, $value, string $expectedType): self
{
return new self(sprintf(
'%s expected value of type %s, %s given',
$context,
$expectedType,
get_debug_type($value)
));
}
/**
* Creates an UnserializationException for a property with an invalid type.
*
* @param mixed $value
*/
public static function invalidProperty(string $context, string $property, $value, string $expectedType): self
{
return new self(sprintf(
'%s expected "%s" property of type %s, %s given',
$context,
$property,
$expectedType,
is_object($value) ? get_class($value) : gettype($value)
));
}
/**
* Creates an UnserializationException for a missing property.
*/
public static function missingProperty(string $context, string $property, string $expectedType): self
{
return new self(sprintf(
'%s expected "%s" property of type %s, none given',
$context,
$property,
$expectedType
));
}
/**
* Creates an UnserializationException for an unsupported "type" property.
*/
public static function unsupportedType(string $context, string $value): self
{
return new self(sprintf('Invalid %s type "%s"', $context, $value));
}
}
================================================
FILE: src/Feature/Feature.php
================================================
<?php
declare(strict_types=1);
namespace GeoJson\Feature;
use GeoJson\BoundingBox;
use GeoJson\CoordinateReferenceSystem\CoordinateReferenceSystem;
use GeoJson\GeoJson;
use GeoJson\Geometry\Geometry;
use stdClass;
/**
* Feature object.
*
* @see http://www.geojson.org/geojson-spec.html#feature-objects
* @since 1.0
*/
class Feature extends GeoJson
{
protected string $type = self::TYPE_FEATURE;
protected ?Geometry $geometry;
/**
* Properties are a JSON object, which corresponds to an associative array, or null.
*
* @see https://www.rfc-editor.org/rfc/rfc7946#section-3.2
*/
protected ?array $properties;
/**
* The identifier is either a JSON string or a number.
*
* @see https://www.rfc-editor.org/rfc/rfc7946#section-3.2
*
* @var int|string|null
*/
protected $id;
/**
* @param int|string|null $id
* @param CoordinateReferenceSystem|BoundingBox $args
*/
public function __construct(?Geometry $geometry = null, ?array $properties = null, $id = null, ...$args)
{
$this->geometry = $geometry;
$this->properties = $properties;
$this->id = $id;
$this->setOptionalConstructorArgs($args);
}
/**
* Return the Geometry object for this Feature object.
*/
public function getGeometry(): ?Geometry
{
return $this->geometry;
}
/**
* Return the identifier for this Feature object.
*
* @return int|string|null
*/
public function getId()
{
return $this->id;
}
/**
* Return the properties for this Feature object.
*/
public function getProperties(): ?array
{
return $this->properties;
}
public function jsonSerialize(): array
{
$json = parent::jsonSerialize();
$json['geometry'] = isset($this->geometry) ? $this->geometry->jsonSerialize() : null;
$json['properties'] = $this->properties ?? null;
// Ensure empty associative arrays are encoded as JSON objects
if ($json['properties'] === []) {
$json['properties'] = new stdClass();
}
if (isset($this->id)) {
$json['id'] = $this->id;
}
return $json;
}
}
================================================
FILE: src/Feature/FeatureCollection.php
================================================
<?php
declare(strict_types=1);
namespace GeoJson\Feature;
use ArrayIterator;
use Countable;
use GeoJson\BoundingBox;
use GeoJson\CoordinateReferenceSystem\CoordinateReferenceSystem;
use GeoJson\Exception\InvalidArgumentException;
use GeoJson\GeoJson;
use IteratorAggregate;
use Traversable;
use function array_map;
use function array_merge;
use function array_values;
use function count;
/**
* Collection of Feature objects.
*
* @see http://www.geojson.org/geojson-spec.html#feature-collection-objects
* @since 1.0
*/
class FeatureCollection extends GeoJson implements Countable, IteratorAggregate
{
protected string $type = self::TYPE_FEATURE_COLLECTION;
/**
* @var array<Feature>
*/
protected array $features;
/**
* @param array<Feature> $features
* @param CoordinateReferenceSystem|BoundingBox $args
*/
public function __construct(array $features, ...$args)
{
foreach ($features as $feature) {
if (! $feature instanceof Feature) {
throw new InvalidArgumentException('FeatureCollection may only contain Feature objects');
}
}
$this->features = array_values($features);
$this->setOptionalConstructorArgs($args);
}
public function count(): int
{
return count($this->features);
}
/**
* Return the Feature objects in this collection.
*
* @return array<Feature>
*/
public function getFeatures(): array
{
return $this->features;
}
public function getIterator(): Traversable
{
return new ArrayIterator($this->features);
}
public function jsonSerialize(): array
{
return array_merge(
parent::jsonSerialize(),
['features' => array_map(
static fn(Feature $feature) => $feature->jsonSerialize(),
$this->features
)]
);
}
}
================================================
FILE: src/GeoJson.php
================================================
<?php
declare(strict_types=1);
namespace GeoJson;
use ArrayObject;
use GeoJson\CoordinateReferenceSystem\CoordinateReferenceSystem;
use GeoJson\Exception\UnserializationException;
use JsonSerializable;
use function array_map;
use function is_array;
use function is_object;
use function sprintf;
use function strncmp;
/**
* Base GeoJson object.
*
* @see http://www.geojson.org/geojson-spec.html#geojson-objects
* @since 1.0
*/
abstract class GeoJson implements JsonSerializable, JsonUnserializable
{
public const TYPE_LINE_STRING = 'LineString';
public const TYPE_MULTI_LINE_STRING = 'MultiLineString';
public const TYPE_MULTI_POINT = 'MultiPoint';
public const TYPE_MULTI_POLYGON = 'MultiPolygon';
public const TYPE_POINT = 'Point';
public const TYPE_POLYGON = 'Polygon';
public const TYPE_FEATURE = 'Feature';
public const TYPE_FEATURE_COLLECTION = 'FeatureCollection';
public const TYPE_GEOMETRY_COLLECTION = 'GeometryCollection';
protected ?BoundingBox $boundingBox = null;
protected ?CoordinateReferenceSystem $crs = null;
protected string $type;
/**
* Return the BoundingBox for this GeoJson object.
*/
public function getBoundingBox(): ?BoundingBox
{
return $this->boundingBox;
}
/**
* Return the CoordinateReferenceSystem for this GeoJson object.
*/
public function getCrs(): ?CoordinateReferenceSystem
{
return $this->crs;
}
/**
* Return the type for this GeoJson object.
*/
public function getType(): string
{
return $this->type;
}
public function jsonSerialize(): array
{
$json = ['type' => $this->type];
if (isset($this->crs)) {
$json['crs'] = $this->crs->jsonSerialize();
}
if (isset($this->boundingBox)) {
$json['bbox'] = $this->boundingBox->jsonSerialize();
}
return $json;
}
/**
* @param array|object $json
*/
final public static function jsonUnserialize($json): self
{
if (! is_array($json) && ! is_object($json)) {
throw UnserializationException::invalidValue('GeoJson', $json, 'array or object');
}
$json = new ArrayObject($json);
if (! $json->offsetExists('type')) {
throw UnserializationException::missingProperty('GeoJson', 'type', 'string');
}
$type = (string) $json['type'];
$args = [];
switch ($type) {
case self::TYPE_LINE_STRING:
case self::TYPE_MULTI_LINE_STRING:
case self::TYPE_MULTI_POINT:
case self::TYPE_MULTI_POLYGON:
case self::TYPE_POINT:
case self::TYPE_POLYGON:
if (! $json->offsetExists('coordinates')) {
throw UnserializationException::missingProperty($type, 'coordinates', 'array');
}
if (! is_array($json['coordinates'])) {
throw UnserializationException::invalidProperty($type, 'coordinates', $json['coordinates'], 'array');
}
$args[] = $json['coordinates'];
break;
case self::TYPE_FEATURE:
$geometry = $json['geometry'] ?? null;
$properties = $json['properties'] ?? null;
$id = $json['id'] ?? null;
if ($geometry !== null && ! is_array($geometry) && ! is_object($geometry)) {
throw UnserializationException::invalidProperty($type, 'geometry', $geometry, 'array or object');
}
if ($properties !== null && ! is_array($properties) && ! is_object($properties)) {
throw UnserializationException::invalidProperty($type, 'properties', $properties, 'array or object');
}
// TODO: Validate non-null $id as int or string in 2.0
$args[] = $geometry !== null ? self::jsonUnserialize($geometry) : null;
$args[] = $properties !== null ? (array) $properties : null;
$args[] = $id;
break;
case self::TYPE_FEATURE_COLLECTION:
if (! $json->offsetExists('features')) {
throw UnserializationException::missingProperty($type, 'features', 'array');
}
if (! is_array($json['features'])) {
throw UnserializationException::invalidProperty($type, 'features', $json['features'], 'array');
}
$args[] = array_map([self::class, 'jsonUnserialize'], $json['features']);
break;
case self::TYPE_GEOMETRY_COLLECTION:
if (! $json->offsetExists('geometries')) {
throw UnserializationException::missingProperty($type, 'geometries', 'array');
}
if (! is_array($json['geometries'])) {
throw UnserializationException::invalidProperty($type, 'geometries', $json['geometries'], 'array');
}
$args[] = array_map([self::class, 'jsonUnserialize'], $json['geometries']);
break;
default:
throw UnserializationException::unsupportedType('GeoJson', $type);
}
if (isset($json['bbox'])) {
$args[] = BoundingBox::jsonUnserialize($json['bbox']);
}
if (isset($json['crs'])) {
$args[] = CoordinateReferenceSystem::jsonUnserialize($json['crs']);
}
$class = sprintf('GeoJson\%s\%s', (strncmp('Feature', $type, 7) === 0 ? 'Feature' : 'Geometry'), $type);
return new $class(... $args);
}
/**
* Set optional CRS and BoundingBox arguments passed to a constructor.
*
* @todo Decide if multiple CRS or BoundingBox instances should override a
* previous value or be ignored
*/
protected function setOptionalConstructorArgs(array $args): void
{
foreach ($args as $arg) {
if ($arg instanceof CoordinateReferenceSystem) {
$this->crs = $arg;
}
if ($arg instanceof BoundingBox) {
$this->boundingBox = $arg;
}
}
}
}
================================================
FILE: src/Geometry/Geometry.php
================================================
<?php
declare(strict_types=1);
namespace GeoJson\Geometry;
use GeoJson\GeoJson;
/**
* Base geometry object.
*
* @see http://www.geojson.org/geojson-spec.html#geometry-objects
* @since 1.0
*/
abstract class Geometry extends GeoJson
{
protected array $coordinates;
/**
* Return the coordinates for this Geometry object.
*/
public function getCoordinates(): array
{
return $this->coordinates;
}
public function jsonSerialize(): array
{
$json = parent::jsonSerialize();
if (isset($this->coordinates)) {
$json['coordinates'] = $this->coordinates;
}
return $json;
}
}
================================================
FILE: src/Geometry/GeometryCollection.php
================================================
<?php
declare(strict_types=1);
namespace GeoJson\Geometry;
use ArrayIterator;
use Countable;
use GeoJson\BoundingBox;
use GeoJson\CoordinateReferenceSystem\CoordinateReferenceSystem;
use GeoJson\Exception\InvalidArgumentException;
use IteratorAggregate;
use Traversable;
use function array_map;
use function array_merge;
use function array_values;
use function count;
/**
* Collection of Geometry objects.
*
* @see http://www.geojson.org/geojson-spec.html#geometry-collection
* @since 1.0
*/
class GeometryCollection extends Geometry implements Countable, IteratorAggregate
{
protected string $type = self::TYPE_GEOMETRY_COLLECTION;
/**
* @var array<Geometry>
*/
protected array $geometries;
/**
* @param array<Geometry> $geometries
* @param CoordinateReferenceSystem|BoundingBox $args
*/
public function __construct(array $geometries, ...$args)
{
foreach ($geometries as $geometry) {
if (! $geometry instanceof Geometry) {
throw new InvalidArgumentException('GeometryCollection may only contain Geometry objects');
}
}
$this->geometries = array_values($geometries);
$this->setOptionalConstructorArgs($args);
}
public function count(): int
{
return count($this->geometries);
}
/**
* Return the Geometry objects in this collection.
*
* @return array<Geometry>
*/
public function getGeometries(): array
{
return $this->geometries;
}
public function getIterator(): Traversable
{
return new ArrayIterator($this->geometries);
}
public function jsonSerialize(): array
{
return array_merge(
parent::jsonSerialize(),
['geometries' => array_map(
static fn(Geometry $geometry) => $geometry->jsonSerialize(),
$this->geometries
)]
);
}
}
================================================
FILE: src/Geometry/LineString.php
================================================
<?php
declare(strict_types=1);
namespace GeoJson\Geometry;
use GeoJson\BoundingBox;
use GeoJson\CoordinateReferenceSystem\CoordinateReferenceSystem;
use GeoJson\Exception\InvalidArgumentException;
use function count;
/**
* LineString geometry object.
*
* Coordinates consist of an array of at least two positions.
*
* @see http://www.geojson.org/geojson-spec.html#linestring
* @since 1.0
*/
class LineString extends MultiPoint
{
protected string $type = self::TYPE_LINE_STRING;
/**
* @param array<Point|array<float|int>> $positions
* @param CoordinateReferenceSystem|BoundingBox $args
*/
public function __construct(array $positions, ...$args)
{
if (count($positions) < 2) {
throw new InvalidArgumentException('LineString requires at least two positions');
}
parent::__construct($positions, ... $args);
}
}
================================================
FILE: src/Geometry/LinearRing.php
================================================
<?php
declare(strict_types=1);
namespace GeoJson\Geometry;
use GeoJson\BoundingBox;
use GeoJson\CoordinateReferenceSystem\CoordinateReferenceSystem;
use GeoJson\Exception\InvalidArgumentException;
use function count;
use function end;
use function reset;
/**
* LinearRing is a special kind of LineString geometry object.
*
* Coordinates consist of an array of at least four positions, where the first
* and last positions are equivalent.
*
* @see http://www.geojson.org/geojson-spec.html#linestring
* @since 1.0
*/
class LinearRing extends LineString
{
/**
* @param array<Point|array<int|float>> $positions
* @param CoordinateReferenceSystem|BoundingBox $args
*/
public function __construct(array $positions, ...$args)
{
if (count($positions) < 4) {
throw new InvalidArgumentException('LinearRing requires at least four positions');
}
$lastPosition = end($positions);
$firstPosition = reset($positions);
$lastPosition = $lastPosition instanceof Point ? $lastPosition->getCoordinates() : $lastPosition;
$firstPosition = $firstPosition instanceof Point ? $firstPosition->getCoordinates() : $firstPosition;
if ($lastPosition !== $firstPosition) {
throw new InvalidArgumentException('LinearRing requires the first and last positions to be equivalent');
}
parent::__construct($positions, ... $args);
}
}
================================================
FILE: src/Geometry/MultiLineString.php
================================================
<?php
declare(strict_types=1);
namespace GeoJson\Geometry;
use GeoJson\BoundingBox;
use GeoJson\CoordinateReferenceSystem\CoordinateReferenceSystem;
use function array_map;
/**
* MultiLineString geometry object.
*
* Coordinates consist of an array of LineString coordinates.
*
* @see http://www.geojson.org/geojson-spec.html#multilinestring
* @since 1.0
*/
class MultiLineString extends Geometry
{
protected string $type = self::TYPE_MULTI_LINE_STRING;
/**
* @param array<LineString|array<Point|array<int|float>>> $lineStrings
* @param CoordinateReferenceSystem|BoundingBox $args
*/
public function __construct(array $lineStrings, ...$args)
{
$this->coordinates = array_map(
static function ($lineString) {
if (! $lineString instanceof LineString) {
$lineString = new LineString($lineString);
}
return $lineString->getCoordinates();
},
$lineStrings
);
$this->setOptionalConstructorArgs($args);
}
}
================================================
FILE: src/Geometry/MultiPoint.php
================================================
<?php
declare(strict_types=1);
namespace GeoJson\Geometry;
use GeoJson\BoundingBox;
use GeoJson\CoordinateReferenceSystem\CoordinateReferenceSystem;
use function array_map;
/**
* MultiPoint geometry object.
*
* Coordinates consist of an array of positions.
*
* @see http://www.geojson.org/geojson-spec.html#multipoint
* @since 1.0
*/
class MultiPoint extends Geometry
{
protected string $type = self::TYPE_MULTI_POINT;
/**
* @param array<Point|array<float|int>> $positions
* @param CoordinateReferenceSystem|BoundingBox $args
*/
public function __construct(array $positions, ...$args)
{
$this->coordinates = array_map(
static function ($point) {
if (! $point instanceof Point) {
$point = new Point($point);
}
return $point->getCoordinates();
},
$positions
);
$this->setOptionalConstructorArgs($args);
}
}
================================================
FILE: src/Geometry/MultiPolygon.php
================================================
<?php
declare(strict_types=1);
namespace GeoJson\Geometry;
use GeoJson\BoundingBox;
use GeoJson\CoordinateReferenceSystem\CoordinateReferenceSystem;
use function array_map;
/**
* MultiPolygon geometry object.
*
* Coordinates consist of an array of Polygon coordinates.
*
* @see http://www.geojson.org/geojson-spec.html#multipolygon
* @since 1.0
*/
class MultiPolygon extends Geometry
{
protected string $type = self::TYPE_MULTI_POLYGON;
/**
* @param array<Polygon|array<LinearRing|array<Point|array<int|float>>>> $polygons
* @param CoordinateReferenceSystem|BoundingBox $args
*/
public function __construct(array $polygons, ...$args)
{
$this->coordinates = array_map(
static function ($polygon) {
if (! $polygon instanceof Polygon) {
$polygon = new Polygon($polygon);
}
return $polygon->getCoordinates();
},
$polygons
);
$this->setOptionalConstructorArgs($args);
}
}
================================================
FILE: src/Geometry/Point.php
================================================
<?php
declare(strict_types=1);
namespace GeoJson\Geometry;
use GeoJson\BoundingBox;
use GeoJson\CoordinateReferenceSystem\CoordinateReferenceSystem;
use GeoJson\Exception\InvalidArgumentException;
use function count;
use function is_float;
use function is_int;
/**
* Point geometry object.
*
* Coordinates consist of a single position.
*
* @see http://www.geojson.org/geojson-spec.html#point
* @since 1.0
*/
class Point extends Geometry
{
protected string $type = self::TYPE_POINT;
/**
* @param array<float|int> $position
* @param CoordinateReferenceSystem|BoundingBox $args
*/
public function __construct(array $position, ...$args)
{
if (count($position) < 2) {
throw new InvalidArgumentException('Position requires at least two elements');
}
foreach ($position as $value) {
if (! is_int($value) && ! is_float($value)) {
throw new InvalidArgumentException('Position elements must be integers or floats');
}
}
$this->coordinates = $position;
$this->setOptionalConstructorArgs($args);
}
}
================================================
FILE: src/Geometry/Polygon.php
================================================
<?php
declare(strict_types=1);
namespace GeoJson\Geometry;
use GeoJson\BoundingBox;
use GeoJson\CoordinateReferenceSystem\CoordinateReferenceSystem;
/**
* Polygon geometry object.
*
* Coordinates consist of an array of LinearRing coordinates.
*
* @see http://www.geojson.org/geojson-spec.html#polygon
* @since 1.0
*/
class Polygon extends Geometry
{
protected string $type = self::TYPE_POLYGON;
/**
* @param array<LinearRing|array<Point|array<int|float>>> $linearRings
* @param CoordinateReferenceSystem|BoundingBox $args
*/
public function __construct(array $linearRings, ...$args)
{
foreach ($linearRings as $linearRing) {
if (! $linearRing instanceof LinearRing) {
$linearRing = new LinearRing($linearRing);
}
$this->coordinates[] = $linearRing->getCoordinates();
}
$this->setOptionalConstructorArgs($args);
}
}
================================================
FILE: src/JsonUnserializable.php
================================================
<?php
declare(strict_types=1);
namespace GeoJson;
use GeoJson\Exception\UnserializationException;
/**
* JsonUnserializable interface for creating an object from decoded JSON.
*
* This is used as a factory method for GeoJson, BoundingBox, and CRS classes.
*
* @since 1.0
*/
interface JsonUnserializable
{
/**
* Factory method for creating an object from a decoded JSON value.
*
* @param mixed $json
* @return mixed
* @throws UnserializationException
*/
public static function jsonUnserialize($json);
}
================================================
FILE: tests/BaseGeoJsonTest.php
================================================
<?php
declare(strict_types=1);
namespace GeoJson\Tests;
use GeoJson\BoundingBox;
use GeoJson\CoordinateReferenceSystem\CoordinateReferenceSystem;
use GeoJson\Feature\Feature;
use GeoJson\Geometry\Geometry;
use PHPUnit\Framework\TestCase;
abstract class BaseGeoJsonTest extends TestCase
{
/**
* @param ...$extraArgs
*
* @return mixed
*/
abstract public function createSubjectWithExtraArguments(...$extraArgs);
public function testConstructorShouldScanExtraArgumentsForCrsAndBoundingBox(): void
{
$box = $this->getMockBoundingBox();
$crs = $this->getMockCoordinateReferenceSystem();
$sut = $this->createSubjectWithExtraArguments();
$this->assertNull($sut->getBoundingBox());
$this->assertNull($sut->getCrs());
$sut = $this->createSubjectWithExtraArguments($box);
$this->assertSame($box, $sut->getBoundingBox());
$this->assertNull($sut->getCrs());
$sut = $this->createSubjectWithExtraArguments($crs);
$this->assertNull($sut->getBoundingBox());
$this->assertSame($crs, $sut->getCrs());
$sut = $this->createSubjectWithExtraArguments($box, $crs);
$this->assertSame($box, $sut->getBoundingBox());
$this->assertSame($crs, $sut->getCrs());
$sut = $this->createSubjectWithExtraArguments($crs, $box);
$this->assertSame($box, $sut->getBoundingBox());
$this->assertSame($crs, $sut->getCrs());
// Not that you would, but you could…
$sut = $this->createSubjectWithExtraArguments(null, null, $box, $crs);
$this->assertSame($box, $sut->getBoundingBox());
$this->assertSame($crs, $sut->getCrs());
}
public function testSerializationWithCrsAndBoundingBox(): void
{
$box = $this->getMockBoundingBox();
$box->method('jsonSerialize')->willReturn(['boundingBox']);
$crs = $this->getMockCoordinateReferenceSystem();
$crs->method('jsonSerialize')->willReturn(['coordinateReferenceSystem']);
$sut = $this->createSubjectWithExtraArguments($box, $crs);
$json = $sut->jsonSerialize();
$this->assertArrayHasKey('bbox', $json);
$this->assertArrayHasKey('crs', $json);
$this->assertSame(['boundingBox'], $json['bbox']);
$this->assertSame(['coordinateReferenceSystem'], $json['crs']);
}
protected function getMockBoundingBox()
{
return $this->createMock(BoundingBox::class);
}
protected function getMockCoordinateReferenceSystem()
{
return $this->createMock(CoordinateReferenceSystem::class);
}
protected function getMockFeature()
{
return $this->createMock(Feature::class);
}
protected function getMockGeometry()
{
return $this->createMock(Geometry::class);
}
}
================================================
FILE: tests/BoundingBoxTest.php
================================================
<?php
declare(strict_types=1);
namespace GeoJson\Tests;
use GeoJson\BoundingBox;
use GeoJson\Exception\InvalidArgumentException;
use GeoJson\Exception\UnserializationException;
use GeoJson\JsonUnserializable;
use PHPUnit\Framework\TestCase;
use stdClass;
use function func_get_args;
use function json_decode;
class BoundingBoxTest extends TestCase
{
public function testIsJsonSerializable(): void
{
$this->assertInstanceOf('JsonSerializable', new BoundingBox([0, 0, 1, 1]));
}
public function testIsJsonUnserializable(): void
{
$this->assertInstanceOf(JsonUnserializable::class, new BoundingBox([0, 0, 1, 1]));
}
public function testConstructorShouldRequireAtLeastFourValues(): void
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('BoundingBox requires at least four values');
new BoundingBox([0, 0]);
}
public function testConstructorShouldRequireAnEvenNumberOfValues(): void
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('BoundingBox requires an even number of values');
new BoundingBox([0, 0, 1, 1, 2]);
}
/**
* @dataProvider provideBoundsWithInvalidTypes
*/
public function testConstructorShouldRequireIntegerOrFloatValues(): void
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('BoundingBox values must be integers or floats');
new BoundingBox(func_get_args());
}
public function provideBoundsWithInvalidTypes()
{
return [
'strings' => ['0', '0.0', '1', '1.0'],
'objects' => [new stdClass(), new stdClass(), new stdClass(), new stdClass()],
'arrays' => [[], [], [], []],
];
}
public function testConstructorShouldRequireMinBeforeMaxValues(): void
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('BoundingBox min values must precede max values');
new BoundingBox([-90.0, -95.0, -92.5, 90.0]);
}
public function testSerialization(): void
{
$bounds = [-180.0, -90.0, 0.0, 180.0, 90.0, 100.0];
$boundingBox = new BoundingBox($bounds);
$this->assertSame($bounds, $boundingBox->getBounds());
$this->assertSame($bounds, $boundingBox->jsonSerialize());
}
/**
* @dataProvider provideJsonDecodeAssocOptions
* @group functional
*/
public function testUnserialization($assoc): void
{
$json = '[-180.0, -90.0, 180.0, 90.0]';
$json = json_decode($json, $assoc);
$boundingBox = BoundingBox::jsonUnserialize($json);
$this->assertInstanceOf(BoundingBox::class, $boundingBox);
$this->assertSame([-180.0, -90.0, 180.0, 90.0], $boundingBox->getBounds());
}
public function provideJsonDecodeAssocOptions()
{
return [
'assoc=true' => [true],
'assoc=false' => [false],
];
}
/**
* @dataProvider provideInvalidUnserializationValues
*/
public function testUnserializationShouldRequireArray($value): void
{
$this->expectException(UnserializationException::class);
$this->expectExceptionMessage('BoundingBox expected value of type array');
BoundingBox::jsonUnserialize($value);
}
public function provideInvalidUnserializationValues()
{
return [
[null],
[1],
['foo'],
[new stdClass()],
];
}
}
================================================
FILE: tests/CoordinateReferenceSystem/CoordinateReferenceSystemTest.php
================================================
<?php
declare(strict_types=1);
namespace GeoJson\Tests\CoordinateReferenceSystem;
use GeoJson\CoordinateReferenceSystem\CoordinateReferenceSystem;
use GeoJson\Exception\UnserializationException;
use GeoJson\JsonUnserializable;
use JsonSerializable;
use PHPUnit\Framework\TestCase;
class CoordinateReferenceSystemTest extends TestCase
{
public function testIsJsonSerializable(): void
{
$this->assertInstanceOf(
JsonSerializable::class,
$this->createMock(CoordinateReferenceSystem::class)
);
}
public function testIsJsonUnserializable(): void
{
$this->assertInstanceOf(
JsonUnserializable::class,
$this->createMock(CoordinateReferenceSystem::class)
);
}
public function testUnserializationShouldRequireArrayOrObject(): void
{
$this->expectException(UnserializationException::class);
$this->expectExceptionMessage('CRS expected value of type array or object');
CoordinateReferenceSystem::jsonUnserialize(null);
}
public function testUnserializationShouldRequireTypeField(): void
{
$this->expectException(UnserializationException::class);
$this->expectExceptionMessage('CRS expected "type" property of type string, none given');
CoordinateReferenceSystem::jsonUnserialize(['properties' => []]);
}
public function testUnserializationShouldRequirePropertiesField(): void
{
$this->expectException(UnserializationException::class);
$this->expectExceptionMessage('CRS expected "properties" property of type array or object, none given');
CoordinateReferenceSystem::jsonUnserialize(['type' => 'foo']);
}
public function testUnserializationShouldRequireValidType(): void
{
$this->expectException(UnserializationException::class);
$this->expectExceptionMessage('Invalid CRS type "foo"');
CoordinateReferenceSystem::jsonUnserialize(['type' => 'foo', 'properties' => []]);
}
}
================================================
FILE: tests/CoordinateReferenceSystem/LinkedTest.php
================================================
<?php
declare(strict_types=1);
namespace GeoJson\Tests\CoordinateReferenceSystem;
use GeoJson\CoordinateReferenceSystem\CoordinateReferenceSystem;
use GeoJson\CoordinateReferenceSystem\Linked;
use GeoJson\Exception\UnserializationException;
use PHPUnit\Framework\TestCase;
use function is_subclass_of;
use function json_decode;
class LinkedTest extends TestCase
{
public function testIsSubclassOfCoordinateReferenceSystem(): void
{
$this->assertTrue(is_subclass_of(Linked::class, CoordinateReferenceSystem::class));
}
public function testSerialization(): void
{
$crs = new Linked('https://example.com/crs/42', 'proj4');
$expected = [
'type' => 'link',
'properties' => [
'href' => 'https://example.com/crs/42',
'type' => 'proj4',
],
];
$this->assertSame('link', $crs->getType());
$this->assertSame($expected['properties'], $crs->getProperties());
$this->assertSame($expected, $crs->jsonSerialize());
}
public function testSerializationWithoutHrefType(): void
{
$crs = new Linked('https://example.com/crs/42');
$expected = [
'type' => 'link',
'properties' => [
'href' => 'https://example.com/crs/42',
],
];
$this->assertSame($expected, $crs->jsonSerialize());
}
/**
* @dataProvider provideJsonDecodeAssocOptions
* @group functional
*/
public function testUnserialization($assoc): void
{
$json = <<<'JSON'
{
"type": "link",
"properties": {
"href": "https://example.com/crs/42",
"type": "proj4"
}
}
JSON;
$json = json_decode($json, $assoc);
$crs = CoordinateReferenceSystem::jsonUnserialize($json);
$expectedProperties = [
'href' => 'https://example.com/crs/42',
'type' => 'proj4',
];
$this->assertInstanceOf(Linked::class, $crs);
$this->assertSame('link', $crs->getType());
$this->assertSame($expectedProperties, $crs->getProperties());
}
/**
* @dataProvider provideJsonDecodeAssocOptions
* @group functional
*/
public function testUnserializationWithoutHrefType($assoc): void
{
$json = <<<'JSON'
{
"type": "link",
"properties": {
"href": "https://example.com/crs/42"
}
}
JSON;
$json = json_decode($json, $assoc);
$crs = CoordinateReferenceSystem::jsonUnserialize($json);
$expectedProperties = ['href' => 'https://example.com/crs/42'];
$this->assertInstanceOf(Linked::class, $crs);
$this->assertSame('link', $crs->getType());
$this->assertSame($expectedProperties, $crs->getProperties());
}
public function provideJsonDecodeAssocOptions()
{
return [
'assoc=true' => [true],
'assoc=false' => [false],
];
}
public function testUnserializationShouldRequirePropertiesArrayOrObject(): void
{
$this->expectException(UnserializationException::class);
$this->expectExceptionMessage('Linked CRS expected "properties" property of type array or object');
CoordinateReferenceSystem::jsonUnserialize(['type' => 'link', 'properties' => null]);
}
public function testUnserializationShouldRequireHrefProperty(): void
{
$this->expectException(UnserializationException::class);
$this->expectExceptionMessage('Linked CRS expected "properties.href" property of type string');
CoordinateReferenceSystem::jsonUnserialize(['type' => 'link', 'properties' => []]);
}
}
================================================
FILE: tests/CoordinateReferenceSystem/NamedTest.php
================================================
<?php
declare(strict_types=1);
namespace GeoJson\Tests\CoordinateReferenceSystem;
use GeoJson\CoordinateReferenceSystem\CoordinateReferenceSystem;
use GeoJson\CoordinateReferenceSystem\Named;
use GeoJson\Exception\UnserializationException;
use PHPUnit\Framework\TestCase;
use function is_subclass_of;
use function json_decode;
class NamedTest extends TestCase
{
public function testIsSubclassOfCoordinateReferenceSystem(): void
{
$this->assertTrue(is_subclass_of(Named::class, CoordinateReferenceSystem::class));
}
public function testSerialization(): void
{
$crs = new Named('urn:ogc:def:crs:OGC:1.3:CRS84');
$expected = [
'type' => 'name',
'properties' => [
'name' => 'urn:ogc:def:crs:OGC:1.3:CRS84'
],
];
$this->assertSame('name', $crs->getType());
$this->assertSame($expected['properties'], $crs->getProperties());
$this->assertSame($expected, $crs->jsonSerialize());
}
/**
* @dataProvider provideJsonDecodeAssocOptions
* @group functional
*/
public function testUnserialization($assoc): void
{
$json = <<<'JSON'
{
"type": "name",
"properties": {
"name": "urn:ogc:def:crs:OGC:1.3:CRS84"
}
}
JSON;
$json = json_decode($json, $assoc);
$crs = CoordinateReferenceSystem::jsonUnserialize($json);
$expectedProperties = ['name' => 'urn:ogc:def:crs:OGC:1.3:CRS84'];
$this->assertInstanceOf(Named::class, $crs);
$this->assertSame('name', $crs->getType());
$this->assertSame($expectedProperties, $crs->getProperties());
}
public function provideJsonDecodeAssocOptions()
{
return [
'assoc=true' => [true],
'assoc=false' => [false],
];
}
public function testUnserializationShouldRequirePropertiesArrayOrObject(): void
{
$this->expectException(UnserializationException::class);
$this->expectExceptionMessage('Named CRS expected "properties" property of type array or object');
CoordinateReferenceSystem::jsonUnserialize(['type' => 'name', 'properties' => null]);
}
public function testUnserializationShouldRequireNameProperty(): void
{
$this->expectException(UnserializationException::class);
$this->expectExceptionMessage('Named CRS expected "properties.name" property of type string');
CoordinateReferenceSystem::jsonUnserialize(['type' => 'name', 'properties' => []]);
}
}
================================================
FILE: tests/Feature/FeatureCollectionTest.php
================================================
<?php
declare(strict_types=1);
namespace GeoJson\Tests\Feature;
use GeoJson\Exception\InvalidArgumentException;
use GeoJson\Exception\UnserializationException;
use GeoJson\Feature\Feature;
use GeoJson\Feature\FeatureCollection;
use GeoJson\GeoJson;
use GeoJson\Geometry\Point;
use GeoJson\Tests\BaseGeoJsonTest;
use stdClass;
use function is_subclass_of;
use function iterator_to_array;
use function json_decode;
class FeatureCollectionTest extends BaseGeoJsonTest
{
public function createSubjectWithExtraArguments(...$extraArgs)
{
return new FeatureCollection([], ... $extraArgs);
}
public function testIsSubclassOfGeoJson(): void
{
$this->assertTrue(is_subclass_of(FeatureCollection::class, GeoJson::class));
}
public function testConstructorShouldRequireArrayOfFeatureObjects(): void
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('FeatureCollection may only contain Feature objects');
new FeatureCollection([new stdClass()]);
}
public function testConstructorShouldReindexFeaturesArrayNumerically(): void
{
$feature1 = $this->getMockFeature();
$feature2 = $this->getMockFeature();
$features = [
'one' => $feature1,
'two' => $feature2,
];
$collection = new FeatureCollection($features);
$this->assertSame([$feature1, $feature2], iterator_to_array($collection));
}
public function testIsTraversable(): void
{
$features = [
$this->getMockFeature(),
$this->getMockFeature(),
];
$collection = new FeatureCollection($features);
$this->assertInstanceOf('Traversable', $collection);
$this->assertSame($features, iterator_to_array($collection));
}
public function testIsCountable(): void
{
$features = [
$this->getMockFeature(),
$this->getMockFeature(),
];
$collection = new FeatureCollection($features);
$this->assertInstanceOf('Countable', $collection);
$this->assertCount(2, $collection);
}
public function testSerialization(): void
{
$features = [
$this->getMockFeature(),
$this->getMockFeature(),
];
$features[0]->method('jsonSerialize')->willReturn(['feature1']);
$features[1]->method('jsonSerialize')->willReturn(['feature2']);
$collection = new FeatureCollection($features);
$expected = [
'type' => GeoJson::TYPE_FEATURE_COLLECTION,
'features' => [['feature1'], ['feature2']],
];
$this->assertSame(GeoJson::TYPE_FEATURE_COLLECTION, $collection->getType());
$this->assertSame($features, $collection->getFeatures());
$this->assertSame($expected, $collection->jsonSerialize());
}
/**
* @dataProvider provideJsonDecodeAssocOptions
* @group functional
*/
public function testUnserialization($assoc): void
{
$json = <<<'JSON'
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"id": "test.feature.1",
"geometry": {
"type": "Point",
"coordinates": [1, 1]
}
}
]
}
JSON;
$json = json_decode($json, $assoc);
$collection = GeoJson::jsonUnserialize($json);
$this->assertInstanceOf(FeatureCollection::class, $collection);
$this->assertSame(GeoJson::TYPE_FEATURE_COLLECTION, $collection->getType());
$this->assertCount(1, $collection);
$features = iterator_to_array($collection);
$feature = $features[0];
$this->assertInstanceOf(Feature::class, $feature);
$this->assertSame(GeoJson::TYPE_FEATURE, $feature->getType());
$this->assertSame('test.feature.1', $feature->getId());
$this->assertNull($feature->getProperties());
$geometry = $feature->getGeometry();
$this->assertInstanceOf(Point::class, $geometry);
$this->assertSame(GeoJson::TYPE_POINT, $geometry->getType());
$this->assertSame([1, 1], $geometry->getCoordinates());
}
public function provideJsonDecodeAssocOptions()
{
return [
'assoc=true' => [true],
'assoc=false' => [false],
];
}
public function testUnserializationShouldRequireFeaturesProperty(): void
{
$this->expectException(UnserializationException::class);
$this->expectExceptionMessage('FeatureCollection expected "features" property of type array, none given');
GeoJson::jsonUnserialize(['type' => GeoJson::TYPE_FEATURE_COLLECTION]);
}
public function testUnserializationShouldRequireFeaturesArray(): void
{
$this->expectException(UnserializationException::class);
$this->expectExceptionMessage('FeatureCollection expected "features" property of type array');
GeoJson::jsonUnserialize(['type' => GeoJson::TYPE_FEATURE_COLLECTION, 'features' => null]);
}
}
================================================
FILE: tests/Feature/FeatureTest.php
================================================
<?php
declare(strict_types=1);
namespace GeoJson\Tests\Feature;
use GeoJson\Feature\Feature;
use GeoJson\GeoJson;
use GeoJson\Geometry\Point;
use GeoJson\Tests\BaseGeoJsonTest;
use stdClass;
use function is_subclass_of;
use function json_decode;
class FeatureTest extends BaseGeoJsonTest
{
public function createSubjectWithExtraArguments(...$extraArgs)
{
return new Feature(null, null, null, ... $extraArgs);
}
public function testIsSubclassOfGeoJson(): void
{
$this->assertTrue(is_subclass_of(Feature::class, GeoJson::class));
}
public function testSerialization(): void
{
$geometry = $this->getMockGeometry();
$geometry->method('jsonSerialize')->willReturn(['geometry']);
$properties = ['key' => 'value'];
$id = 'identifier';
$feature = new Feature($geometry, $properties, $id);
$expected = [
'type' => GeoJson::TYPE_FEATURE,
'geometry' => ['geometry'],
'properties' => $properties,
'id' => 'identifier',
];
$this->assertSame(GeoJson::TYPE_FEATURE, $feature->getType());
$this->assertSame($geometry, $feature->getGeometry());
$this->assertSame($id, $feature->getId());
$this->assertSame($properties, $feature->getProperties());
$this->assertSame($expected, $feature->jsonSerialize());
}
public function testSerializationWithNullConstructorArguments(): void
{
$feature = new Feature();
$expected = [
'type' => GeoJson::TYPE_FEATURE,
'geometry' => null,
'properties' => null,
];
$this->assertSame($expected, $feature->jsonSerialize());
}
public function testSerializationShouldConvertEmptyPropertiesArrayToObject(): void
{
$feature = new Feature(null, []);
$expected = [
'type' => GeoJson::TYPE_FEATURE,
'geometry' => null,
'properties' => new stdClass(),
];
$this->assertEquals($expected, $feature->jsonSerialize());
}
/**
* @dataProvider provideJsonDecodeAssocOptions
* @group functional
*/
public function testUnserialization($assoc): void
{
$json = <<<'JSON'
{
"type": "Feature",
"id": "test.feature.1",
"properties": {
"key": "value"
},
"geometry": {
"type": "Point",
"coordinates": [1, 1]
}
}
JSON;
$json = json_decode($json, $assoc);
$feature = GeoJson::jsonUnserialize($json);
$this->assertInstanceOf(Feature::class, $feature);
$this->assertSame(GeoJson::TYPE_FEATURE, $feature->getType());
$this->assertSame('test.feature.1', $feature->getId());
$this->assertSame(['key' => 'value'], $feature->getProperties());
$geometry = $feature->getGeometry();
$this->assertInstanceOf(Point::class, $geometry);
$this->assertSame(GeoJson::TYPE_POINT, $geometry->getType());
$this->assertSame([1, 1], $geometry->getCoordinates());
}
public function provideJsonDecodeAssocOptions()
{
return [
'assoc=true' => [true],
'assoc=false' => [false],
];
}
}
================================================
FILE: tests/GeoJsonTest.php
================================================
<?php
declare(strict_types=1);
namespace GeoJson\Tests;
use GeoJson\BoundingBox;
use GeoJson\CoordinateReferenceSystem\Named;
use GeoJson\Exception\UnserializationException;
use GeoJson\GeoJson;
use GeoJson\Geometry\Point;
use GeoJson\JsonUnserializable;
use JsonSerializable;
use PHPUnit\Framework\TestCase;
use function get_class;
use function gettype;
use function is_object;
use function json_decode;
class GeoJsonTest extends TestCase
{
public function testIsJsonSerializable(): void
{
$this->assertInstanceOf(JsonSerializable::class, $this->createMock(GeoJson::class));
}
public function testIsJsonUnserializable(): void
{
$this->assertInstanceOf(JsonUnserializable::class, $this->createMock(GeoJson::class));
}
/**
* @dataProvider provideJsonDecodeAssocOptions
* @group functional
*/
public function testUnserializationWithBoundingBox($assoc): void
{
$json = <<<'JSON'
{
"type": "Point",
"coordinates": [1, 1],
"bbox": [-180.0, -90.0, 180.0, 90.0]
}
JSON;
$json = json_decode($json, $assoc);
$point = GeoJson::jsonUnserialize($json);
$this->assertInstanceOf(Point::class, $point);
$this->assertSame(GeoJson::TYPE_POINT, $point->getType());
$this->assertSame([1, 1], $point->getCoordinates());
$boundingBox = $point->getBoundingBox();
$this->assertInstanceOf(BoundingBox::class, $boundingBox);
$this->assertSame([-180.0, -90.0, 180.0, 90.0], $boundingBox->getBounds());
}
/**
* @dataProvider provideJsonDecodeAssocOptions
* @group functional
*/
public function testUnserializationWithCrs($assoc): void
{
$json = <<<'JSON'
{
"type": "Point",
"coordinates": [1, 1],
"crs": {
"type": "name",
"properties": {
"name": "urn:ogc:def:crs:OGC:1.3:CRS84"
}
}
}
JSON;
$json = json_decode($json, $assoc);
$point = GeoJson::jsonUnserialize($json);
$this->assertInstanceOf(Point::class, $point);
$this->assertSame(GeoJson::TYPE_POINT, $point->getType());
$this->assertSame([1, 1], $point->getCoordinates());
$crs = $point->getCrs();
$expectedProperties = ['name' => 'urn:ogc:def:crs:OGC:1.3:CRS84'];
$this->assertInstanceOf(Named::class, $crs);
$this->assertSame('name', $crs->getType());
$this->assertSame($expectedProperties, $crs->getProperties());
}
public function testUnserializationWithInvalidArgument(): void
{
$this->expectException(UnserializationException::class);
$this->expectExceptionMessage('GeoJson expected value of type array or object, string given');
GeoJson::jsonUnserialize('must be array or object, but this is a string');
}
public function testUnserializationWithUnknownType(): void
{
$this->expectException(UnserializationException::class);
$this->expectExceptionMessage('Invalid GeoJson type "Unknown"');
GeoJson::jsonUnserialize(['type' => 'Unknown']);
}
public function testUnserializationWithMissingType(): void
{
$this->expectException(UnserializationException::class);
$this->expectExceptionMessage('GeoJson expected "type" property of type string, none given');
GeoJson::jsonUnserialize([]);
}
/**
* @dataProvider provideGeoJsonTypesWithCoordinates
*/
public function testUnserializationWithMissingCoordinates(string $type): void
{
$this->expectException(UnserializationException::class);
$this->expectExceptionMessage($type . ' expected "coordinates" property of type array, none given');
GeoJson::jsonUnserialize([
'type' => $type,
]);
}
/**
* @dataProvider provideInvalidCoordinates
*
* @param mixed $value
*/
public function testUnserializationWithInvalidCoordinates($value): void
{
$valueType = is_object($value) ? get_class($value) : gettype($value);
$this->expectException(UnserializationException::class);
$this->expectExceptionMessage('Point expected "coordinates" property of type array, ' . $valueType . ' given');
GeoJson::jsonUnserialize([
'type' => GeoJson::TYPE_POINT,
'coordinates' => $value,
]);
}
public function testFeatureUnserializationWithInvalidGeometry(): void
{
$this->expectException(UnserializationException::class);
$this->expectExceptionMessage('Feature expected "geometry" property of type array or object, string given');
GeoJson::jsonUnserialize([
'type' => GeoJson::TYPE_FEATURE,
'geometry' => 'must be array or object, but this is a string',
]);
}
public function testFeatureUnserializationWithInvalidProperties(): void
{
$this->expectException(UnserializationException::class);
$this->expectExceptionMessage('Feature expected "properties" property of type array or object, string given');
GeoJson::jsonUnserialize([
'type' => GeoJson::TYPE_FEATURE,
'properties' => 'must be array or object, but this is a string',
]);
}
public function provideJsonDecodeAssocOptions()
{
return [
'assoc=true' => [true],
'assoc=false' => [false],
];
}
public function provideGeoJsonTypesWithCoordinates()
{
return [
GeoJson::TYPE_LINE_STRING => [GeoJson::TYPE_LINE_STRING],
GeoJson::TYPE_MULTI_LINE_STRING => [GeoJson::TYPE_MULTI_LINE_STRING],
GeoJson::TYPE_MULTI_POINT => [GeoJson::TYPE_MULTI_POINT],
GeoJson::TYPE_MULTI_POLYGON => [GeoJson::TYPE_MULTI_POLYGON],
GeoJson::TYPE_POINT => [GeoJson::TYPE_POINT],
GeoJson::TYPE_POLYGON => [GeoJson::TYPE_POLYGON],
];
}
public function provideInvalidCoordinates()
{
return [
'string' => ['1,1'],
'int' => [1],
'bool' => [false],
];
}
}
================================================
FILE: tests/Geometry/GeometryCollectionTest.php
================================================
<?php
declare(strict_types=1);
namespace GeoJson\Tests\Geometry;
use GeoJson\Exception\InvalidArgumentException;
use GeoJson\Exception\UnserializationException;
use GeoJson\GeoJson;
use GeoJson\Geometry\Geometry;
use GeoJson\Geometry\GeometryCollection;
use GeoJson\Geometry\Point;
use GeoJson\Tests\BaseGeoJsonTest;
use stdClass;
use function is_subclass_of;
use function iterator_to_array;
use function json_decode;
class GeometryCollectionTest extends BaseGeoJsonTest
{
public function createSubjectWithExtraArguments(...$extraArgs)
{
return new GeometryCollection([], ... $extraArgs);
}
public function testIsSubclassOfGeometry(): void
{
$this->assertTrue(is_subclass_of(GeometryCollection::class, Geometry::class));
}
public function testConstructorShouldRequireArrayOfGeometryObjects(): void
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('GeometryCollection may only contain Geometry objects');
new GeometryCollection([new stdClass()]);
}
public function testConstructorShouldReindexGeometriesArrayNumerically(): void
{
$geometry1 = $this->getMockGeometry();
$geometry2 = $this->getMockGeometry();
$geometries = [
'one' => $geometry1,
'two' => $geometry2,
];
$collection = new GeometryCollection($geometries);
$this->assertSame([$geometry1, $geometry2], iterator_to_array($collection));
}
public function testIsTraversable(): void
{
$geometries = [
$this->getMockGeometry(),
$this->getMockGeometry(),
];
$collection = new GeometryCollection($geometries);
$this->assertInstanceOf('Traversable', $collection);
$this->assertSame($geometries, iterator_to_array($collection));
}
public function testIsCountable(): void
{
$geometries = [
$this->getMockGeometry(),
$this->getMockGeometry(),
];
$collection = new GeometryCollection($geometries);
$this->assertInstanceOf('Countable', $collection);
$this->assertCount(2, $collection);
}
public function testSerialization(): void
{
$geometries = [
$this->getMockGeometry(),
$this->getMockGeometry(),
];
$geometries[0]->method('jsonSerialize')->willReturn(['geometry1']);
$geometries[1]->method('jsonSerialize')->willReturn(['geometry2']);
$collection = new GeometryCollection($geometries);
$expected = [
'type' => GeoJson::TYPE_GEOMETRY_COLLECTION,
'geometries' => [['geometry1'], ['geometry2']],
];
$this->assertSame(GeoJson::TYPE_GEOMETRY_COLLECTION, $collection->getType());
$this->assertSame($geometries, $collection->getGeometries());
$this->assertSame($expected, $collection->jsonSerialize());
}
/**
* @dataProvider provideJsonDecodeAssocOptions
* @group functional
*/
public function testUnserialization($assoc): void
{
$json = <<<'JSON'
{
"type": "GeometryCollection",
"geometries": [
{
"type": "Point",
"coordinates": [1, 1]
}
]
}
JSON;
$json = json_decode($json, $assoc);
$collection = GeoJson::jsonUnserialize($json);
$this->assertInstanceOf(GeometryCollection::class, $collection);
$this->assertSame(GeoJson::TYPE_GEOMETRY_COLLECTION, $collection->getType());
$this->assertCount(1, $collection);
$geometries = iterator_to_array($collection);
$geometry = $geometries[0];
$this->assertInstanceOf(Point::class, $geometry);
$this->assertSame(GeoJson::TYPE_POINT, $geometry->getType());
$this->assertSame([1, 1], $geometry->getCoordinates());
}
public function provideJsonDecodeAssocOptions()
{
return [
'assoc=true' => [true],
'assoc=false' => [false],
];
}
public function testUnserializationShouldRequireGeometriesProperty(): void
{
$this->expectException(UnserializationException::class);
$this->expectExceptionMessage('GeometryCollection expected "geometries" property of type array, none given');
GeoJson::jsonUnserialize(['type' => GeoJson::TYPE_GEOMETRY_COLLECTION]);
}
public function testUnserializationShouldRequireGeometriesArray(): void
{
$this->expectException(UnserializationException::class);
$this->expectExceptionMessage('GeometryCollection expected "geometries" property of type array');
GeoJson::jsonUnserialize(['type' => GeoJson::TYPE_GEOMETRY_COLLECTION, 'geometries' => null]);
}
}
================================================
FILE: tests/Geometry/GeometryTest.php
================================================
<?php
declare(strict_types=1);
namespace GeoJson\Tests\Geometry;
use GeoJson\GeoJson;
use GeoJson\Geometry\Geometry;
use PHPUnit\Framework\TestCase;
use function is_subclass_of;
class GeometryTest extends TestCase
{
public function testIsSubclassOfGeoJson(): void
{
$this->assertTrue(is_subclass_of(Geometry::class, GeoJson::class));
}
}
================================================
FILE: tests/Geometry/LineStringTest.php
================================================
<?php
declare(strict_types=1);
namespace GeoJson\Tests\Geometry;
use GeoJson\Exception\InvalidArgumentException;
use GeoJson\GeoJson;
use GeoJson\Geometry\LineString;
use GeoJson\Geometry\MultiPoint;
use GeoJson\Tests\BaseGeoJsonTest;
use function is_subclass_of;
use function json_decode;
class LineStringTest extends BaseGeoJsonTest
{
public function createSubjectWithExtraArguments(...$extraArgs)
{
return new LineString(
[[1, 1], [2, 2]],
... $extraArgs
);
}
public function testIsSubclassOfMultiPoint(): void
{
$this->assertTrue(is_subclass_of(LineString::class, MultiPoint::class));
}
public function testConstructorShouldRequireAtLeastTwoPositions(): void
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('LineString requires at least two positions');
new LineString([[1, 1]]);
}
public function testSerialization(): void
{
$coordinates = [[1, 1], [2, 2]];
$lineString = new LineString($coordinates);
$expected = [
'type' => GeoJson::TYPE_LINE_STRING,
'coordinates' => $coordinates,
];
$this->assertSame(GeoJson::TYPE_LINE_STRING, $lineString->getType());
$this->assertSame($coordinates, $lineString->getCoordinates());
$this->assertSame($expected, $lineString->jsonSerialize());
}
/**
* @dataProvider provideJsonDecodeAssocOptions
* @group functional
*/
public function testUnserialization($assoc): void
{
$json = <<<'JSON'
{
"type": "LineString",
"coordinates": [
[1, 1],
[2, 2]
]
}
JSON;
$json = json_decode($json, $assoc);
$lineString = GeoJson::jsonUnserialize($json);
$expectedCoordinates = [[1, 1], [2, 2]];
$this->assertInstanceOf(LineString::class, $lineString);
$this->assertSame(GeoJson::TYPE_LINE_STRING, $lineString->getType());
$this->assertSame($expectedCoordinates, $lineString->getCoordinates());
}
public function provideJsonDecodeAssocOptions()
{
return [
'assoc=true' => [true],
'assoc=false' => [false],
];
}
}
================================================
FILE: tests/Geometry/LinearRingTest.php
================================================
<?php
declare(strict_types=1);
namespace GeoJson\Tests\Geometry;
use GeoJson\Exception\InvalidArgumentException;
use GeoJson\GeoJson;
use GeoJson\Geometry\LinearRing;
use GeoJson\Geometry\LineString;
use GeoJson\Geometry\Point;
use GeoJson\Tests\BaseGeoJsonTest;
use function is_subclass_of;
class LinearRingTest extends BaseGeoJsonTest
{
public function createSubjectWithExtraArguments(...$extraArgs)
{
return new LinearRing(
[[1, 1], [2, 2], [3, 3], [1, 1]],
... $extraArgs
);
}
public function testIsSubclassOfLineString(): void
{
$this->assertTrue(is_subclass_of(LinearRing::class, LineString::class));
}
public function testConstructorShouldRequireAtLeastFourPositions(): void
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('LinearRing requires at least four positions');
new LinearRing([
[1, 1],
[2, 2],
[3, 3],
]);
}
public function testConstructorShouldRequireEquivalentFirstAndLastPositions(): void
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('LinearRing requires the first and last positions to be equivalent');
new LinearRing([
[1, 1],
[2, 2],
[3, 3],
[4, 4],
]);
}
/**
* @doesNotPerformAssertions
*/
public function testConstructorShouldAcceptEquivalentPointObjectsAndPositionArrays(): void
{
new LinearRing([
[1, 1],
[2, 2],
[3, 3],
new Point([1, 1]),
]);
}
public function testSerialization(): void
{
$coordinates = [[1, 1], [2, 2], [3, 3], [1, 1]];
$linearRing = new LinearRing($coordinates);
$expected = [
'type' => GeoJson::TYPE_LINE_STRING,
'coordinates' => $coordinates,
];
$this->assertSame(GeoJson::TYPE_LINE_STRING, $linearRing->getType());
$this->assertSame($coordinates, $linearRing->getCoordinates());
$this->assertSame($expected, $linearRing->jsonSerialize());
}
}
================================================
FILE: tests/Geometry/MultiLineStringTest.php
================================================
<?php
declare(strict_types=1);
namespace GeoJson\Tests\Geometry;
use GeoJson\GeoJson;
use GeoJson\Geometry\Geometry;
use GeoJson\Geometry\LineString;
use GeoJson\Geometry\MultiLineString;
use GeoJson\Tests\BaseGeoJsonTest;
use function is_subclass_of;
use function json_decode;
class MultiLineStringTest extends BaseGeoJsonTest
{
public function createSubjectWithExtraArguments(...$extraArgs)
{
return new MultiLineString([], ... $extraArgs);
}
public function testIsSubclassOfGeometry(): void
{
$this->assertTrue(is_subclass_of(MultiLineString::class, Geometry::class));
}
public function testConstructionFromLineStringObjects(): void
{
$multiLineString1 = new MultiLineString([
new LineString([[1, 1], [2, 2]]),
new LineString([[3, 3], [4, 4]]),
]);
$multiLineString2 = new MultiLineString([
[[1, 1], [2, 2]],
[[3, 3], [4, 4]],
]);
$this->assertSame($multiLineString1->getCoordinates(), $multiLineString2->getCoordinates());
}
public function testSerialization(): void
{
$coordinates = [
[[1, 1], [2, 2]],
[[3, 3], [4, 4]],
];
$multiLineString = new MultiLineString($coordinates);
$expected = [
'type' => GeoJson::TYPE_MULTI_LINE_STRING,
'coordinates' => $coordinates,
];
$this->assertSame(GeoJson::TYPE_MULTI_LINE_STRING, $multiLineString->getType());
$this->assertSame($coordinates, $multiLineString->getCoordinates());
$this->assertSame($expected, $multiLineString->jsonSerialize());
}
/**
* @dataProvider provideJsonDecodeAssocOptions
* @group functional
*/
public function testUnserialization($assoc): void
{
$json = <<<'JSON'
{
"type": "MultiLineString",
"coordinates": [
[ [1, 1], [2, 2] ],
[ [3, 3], [4, 4] ]
]
}
JSON;
$json = json_decode($json, $assoc);
$multiLineString = GeoJson::jsonUnserialize($json);
$expectedCoordinates = [
[[1, 1], [2, 2]],
[[3, 3], [4, 4]],
];
$this->assertInstanceOf(MultiLineString::class, $multiLineString);
$this->assertSame(GeoJson::TYPE_MULTI_LINE_STRING, $multiLineString->getType());
$this->assertSame($expectedCoordinates, $multiLineString->getCoordinates());
}
public function provideJsonDecodeAssocOptions()
{
return [
'assoc=true' => [true],
'assoc=false' => [false],
];
}
}
================================================
FILE: tests/Geometry/MultiPointTest.php
================================================
<?php
declare(strict_types=1);
namespace GeoJson\Tests\Geometry;
use GeoJson\GeoJson;
use GeoJson\Geometry\Geometry;
use GeoJson\Geometry\MultiPoint;
use GeoJson\Geometry\Point;
use GeoJson\Tests\BaseGeoJsonTest;
use function is_subclass_of;
use function json_decode;
class MultiPointTest extends BaseGeoJsonTest
{
public function createSubjectWithExtraArguments(...$extraArgs)
{
return new MultiPoint([], ... $extraArgs);
}
public function testIsSubclassOfGeometry(): void
{
$this->assertTrue(is_subclass_of(MultiPoint::class, Geometry::class));
}
public function testConstructionFromPointObjects(): void
{
$multiPoint1 = new MultiPoint([
new Point([1, 1]),
new Point([2, 2]),
]);
$multiPoint2 = new MultiPoint([
[1, 1],
[2, 2],
]);
$this->assertSame($multiPoint1->getCoordinates(), $multiPoint2->getCoordinates());
}
public function testSerialization(): void
{
$coordinates = [[1, 1], [2, 2]];
$multiPoint = new MultiPoint($coordinates);
$expected = [
'type' => GeoJson::TYPE_MULTI_POINT,
'coordinates' => $coordinates,
];
$this->assertSame(GeoJson::TYPE_MULTI_POINT, $multiPoint->getType());
$this->assertSame($coordinates, $multiPoint->getCoordinates());
$this->assertSame($expected, $multiPoint->jsonSerialize());
}
/**
* @dataProvider provideJsonDecodeAssocOptions
* @group functional
*/
public function testUnserialization($assoc): void
{
$json = <<<'JSON'
{
"type": "MultiPoint",
"coordinates": [
[1, 1],
[2, 2]
]
}
JSON;
$json = json_decode($json, $assoc);
$multiPoint = GeoJson::jsonUnserialize($json);
$expectedCoordinates = [[1, 1], [2, 2]];
$this->assertInstanceOf(MultiPoint::class, $multiPoint);
$this->assertSame(GeoJson::TYPE_MULTI_POINT, $multiPoint->getType());
$this->assertSame($expectedCoordinates, $multiPoint->getCoordinates());
}
public function provideJsonDecodeAssocOptions()
{
return [
'assoc=true' => [true],
'assoc=false' => [false],
];
}
}
================================================
FILE: tests/Geometry/MultiPolygonTest.php
================================================
<?php
declare(strict_types=1);
namespace GeoJson\Tests\Geometry;
use GeoJson\GeoJson;
use GeoJson\Geometry\Geometry;
use GeoJson\Geometry\MultiPolygon;
use GeoJson\Geometry\Polygon;
use GeoJson\Tests\BaseGeoJsonTest;
use function is_subclass_of;
use function json_decode;
class MultiPolygonTest extends BaseGeoJsonTest
{
public function createSubjectWithExtraArguments(...$extraArgs)
{
return new MultiPolygon([], ... $extraArgs);
}
public function testIsSubclassOfGeometry(): void
{
$this->assertTrue(is_subclass_of(MultiPolygon::class, Geometry::class));
}
public function testConstructionFromPolygonObjects(): void
{
$multiPolygon1 = new MultiPolygon([
new Polygon([[[0, 0], [0, 4], [4, 4], [4, 0], [0, 0]]]),
new Polygon([[[1, 1], [1, 3], [3, 3], [3, 1], [1, 1]]]),
]);
$multiPolygon2 = new MultiPolygon([
[[[0, 0], [0, 4], [4, 4], [4, 0], [0, 0]]],
[[[1, 1], [1, 3], [3, 3], [3, 1], [1, 1]]],
]);
$this->assertSame($multiPolygon1->getCoordinates(), $multiPolygon2->getCoordinates());
}
public function testSerialization(): void
{
$coordinates = [
[[[0, 0], [0, 4], [4, 4], [4, 0], [0, 0]]],
[[[1, 1], [1, 3], [3, 3], [3, 1], [1, 1]]],
];
$multiPolygon = new MultiPolygon($coordinates);
$expected = [
'type' => GeoJson::TYPE_MULTI_POLYGON,
'coordinates' => $coordinates,
];
$this->assertSame(GeoJson::TYPE_MULTI_POLYGON, $multiPolygon->getType());
$this->assertSame($coordinates, $multiPolygon->getCoordinates());
$this->assertSame($expected, $multiPolygon->jsonSerialize());
}
/**
* @dataProvider provideJsonDecodeAssocOptions
* @group functional
*/
public function testUnserialization($assoc): void
{
$json = <<<'JSON'
{
"type": "MultiPolygon",
"coordinates": [
[ [ [0, 0], [0, 4], [4, 4], [4, 0], [0, 0] ] ],
[ [ [1, 1], [1, 3], [3, 3], [3, 1], [1, 1] ] ]
]
}
JSON;
$json = json_decode($json, $assoc);
$multiPolygon = GeoJson::jsonUnserialize($json);
$expectedCoordinates = [
[[[0, 0], [0, 4], [4, 4], [4, 0], [0, 0]]],
[[[1, 1], [1, 3], [3, 3], [3, 1], [1, 1]]],
];
$this->assertInstanceOf(MultiPolygon::class, $multiPolygon);
$this->assertSame(GeoJson::TYPE_MULTI_POLYGON, $multiPolygon->getType());
$this->assertSame($expectedCoordinates, $multiPolygon->getCoordinates());
}
public function provideJsonDecodeAssocOptions()
{
return [
'assoc=true' => [true],
'assoc=false' => [false],
];
}
}
================================================
FILE: tests/Geometry/PointTest.php
================================================
<?php
declare(strict_types=1);
namespace GeoJson\Tests\Geometry;
use GeoJson\Exception\InvalidArgumentException;
use GeoJson\GeoJson;
use GeoJson\Geometry\Geometry;
use GeoJson\Geometry\Point;
use GeoJson\Tests\BaseGeoJsonTest;
use stdClass;
use function func_get_args;
use function is_subclass_of;
use function json_decode;
class PointTest extends BaseGeoJsonTest
{
public function createSubjectWithExtraArguments(...$extraArgs)
{
return new Point([1, 1], ... $extraArgs);
}
public function testIsSubclassOfGeometry(): void
{
$this->assertTrue(is_subclass_of(Point::class, Geometry::class));
}
public function testConstructorShouldRequireAtLeastTwoElementsInPosition(): void
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Position requires at least two elements');
new Point([1]);
}
/**
* @dataProvider providePositionsWithInvalidTypes
*/
public function testConstructorShouldRequireIntegerOrFloatElementsInPosition(): void
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Position elements must be integers or floats');
new Point(func_get_args());
}
public function providePositionsWithInvalidTypes()
{
return [
'strings' => ['1.0', '2'],
'objects' => [new stdClass(), new stdClass()],
'arrays' => [[], []],
];
}
public function testConstructorShouldAllowMoreThanTwoElementsInAPosition(): void
{
$point = new Point([1, 2, 3, 4]);
$this->assertEquals([1, 2, 3, 4], $point->getCoordinates());
}
public function testSerialization(): void
{
$coordinates = [1, 1];
$point = new Point($coordinates);
$expected = [
'type' => GeoJson::TYPE_POINT,
'coordinates' => $coordinates,
];
$this->assertSame(GeoJson::TYPE_POINT, $point->getType());
$this->assertSame($coordinates, $point->getCoordinates());
$this->assertSame($expected, $point->jsonSerialize());
}
/**
* @dataProvider provideJsonDecodeAssocOptions
* @group functional
*/
public function testUnserialization($assoc): void
{
$json = <<<'JSON'
{
"type": "Point",
"coordinates": [1, 1]
}
JSON;
$json = json_decode($json, $assoc);
$point = GeoJson::jsonUnserialize($json);
$this->assertInstanceOf(Point::class, $point);
$this->assertSame(GeoJson::TYPE_POINT, $point->getType());
$this->assertSame([1, 1], $point->getCoordinates());
}
public function provideJsonDecodeAssocOptions()
{
return [
'assoc=true' => [true],
'assoc=false' => [false],
];
}
}
================================================
FILE: tests/Geometry/PolygonTest.php
================================================
<?php
declare(strict_types=1);
namespace GeoJson\Tests\Geometry;
use GeoJson\GeoJson;
use GeoJson\Geometry\Geometry;
use GeoJson\Geometry\LinearRing;
use GeoJson\Geometry\Polygon;
use GeoJson\Tests\BaseGeoJsonTest;
use function is_subclass_of;
use function json_decode;
class PolygonTest extends BaseGeoJsonTest
{
public function createSubjectWithExtraArguments(...$extraArgs)
{
return new Polygon(
[
[[0, 0], [0, 4], [4, 4], [4, 0], [0, 0]],
[[1, 1], [1, 3], [3, 3], [3, 1], [1, 1]],
],
... $extraArgs
);
}
public function testIsSubclassOfGeometry(): void
{
$this->assertTrue(is_subclass_of(Polygon::class, Geometry::class));
}
public function testConstructionFromLinearRingObjects(): void
{
$polygon1 = new Polygon([
new LinearRing([[0, 0], [0, 4], [4, 4], [4, 0], [0, 0]]),
new LinearRing([[1, 1], [1, 3], [3, 3], [3, 1], [1, 1]]),
]);
$polygon2 = new Polygon([
[[0, 0], [0, 4], [4, 4], [4, 0], [0, 0]],
[[1, 1], [1, 3], [3, 3], [3, 1], [1, 1]],
]);
$this->assertSame($polygon1->getCoordinates(), $polygon2->getCoordinates());
}
public function testSerialization(): void
{
$coordinates = [
[[0, 0], [0, 4], [4, 4], [4, 0], [0, 0]],
[[1, 1], [1, 3], [3, 3], [3, 1], [1, 1]],
];
$polygon = new Polygon($coordinates);
$expected = [
'type' => GeoJson::TYPE_POLYGON,
'coordinates' => $coordinates,
];
$this->assertSame(GeoJson::TYPE_POLYGON, $polygon->getType());
$this->assertSame($coordinates, $polygon->getCoordinates());
$this->assertSame($expected, $polygon->jsonSerialize());
}
/**
* @dataProvider provideJsonDecodeAssocOptions
* @group functional
*/
public function testUnserialization($assoc): void
{
$json = <<<'JSON'
{
"type": "Polygon",
"coordinates": [
[ [0, 0], [0, 4], [4, 4], [4, 0], [0, 0] ],
[ [1, 1], [1, 3], [3, 3], [3, 1], [1, 1] ]
]
}
JSON;
$json = json_decode($json, $assoc);
$polygon = GeoJson::jsonUnserialize($json);
$expectedCoordinates = [
[[0, 0], [0, 4], [4, 4], [4, 0], [0, 0]],
[[1, 1], [1, 3], [3, 3], [3, 1], [1, 1]],
];
$this->assertInstanceOf(Polygon::class, $polygon);
$this->assertSame(GeoJson::TYPE_POLYGON, $polygon->getType());
$this->assertSame($expectedCoordinates, $polygon->getCoordinates());
}
public function provideJsonDecodeAssocOptions()
{
return [
'assoc=true' => [true],
'assoc=false' => [false],
];
}
}
gitextract_kuvb7uxu/
├── .gitattributes
├── .github/
│ └── workflows/
│ ├── coding-standards.yml
│ └── tests.yml
├── .gitignore
├── .scrutinizer.yml
├── LICENSE
├── README.md
├── USAGE.md
├── composer.json
├── phpcs.xml.dist
├── phpunit.xml.dist
├── src/
│ ├── BoundingBox.php
│ ├── CoordinateReferenceSystem/
│ │ ├── CoordinateReferenceSystem.php
│ │ ├── Linked.php
│ │ └── Named.php
│ ├── Exception/
│ │ ├── Exception.php
│ │ ├── InvalidArgumentException.php
│ │ └── UnserializationException.php
│ ├── Feature/
│ │ ├── Feature.php
│ │ └── FeatureCollection.php
│ ├── GeoJson.php
│ ├── Geometry/
│ │ ├── Geometry.php
│ │ ├── GeometryCollection.php
│ │ ├── LineString.php
│ │ ├── LinearRing.php
│ │ ├── MultiLineString.php
│ │ ├── MultiPoint.php
│ │ ├── MultiPolygon.php
│ │ ├── Point.php
│ │ └── Polygon.php
│ └── JsonUnserializable.php
└── tests/
├── BaseGeoJsonTest.php
├── BoundingBoxTest.php
├── CoordinateReferenceSystem/
│ ├── CoordinateReferenceSystemTest.php
│ ├── LinkedTest.php
│ └── NamedTest.php
├── Feature/
│ ├── FeatureCollectionTest.php
│ └── FeatureTest.php
├── GeoJsonTest.php
└── Geometry/
├── GeometryCollectionTest.php
├── GeometryTest.php
├── LineStringTest.php
├── LinearRingTest.php
├── MultiLineStringTest.php
├── MultiPointTest.php
├── MultiPolygonTest.php
├── PointTest.php
└── PolygonTest.php
SYMBOL INDEX (213 symbols across 37 files)
FILE: src/BoundingBox.php
class BoundingBox (line 22) | class BoundingBox implements JsonSerializable, JsonUnserializable
method __construct (line 32) | public function __construct(array $bounds)
method getBounds (line 64) | public function getBounds(): array
method jsonSerialize (line 69) | public function jsonSerialize(): array
method jsonUnserialize (line 77) | final public static function jsonUnserialize($json): self
FILE: src/CoordinateReferenceSystem/CoordinateReferenceSystem.php
class CoordinateReferenceSystem (line 27) | abstract class CoordinateReferenceSystem implements JsonSerializable, Js...
method getProperties (line 36) | public function getProperties(): array
method getType (line 44) | public function getType(): string
method jsonSerialize (line 49) | public function jsonSerialize(): array
method jsonUnserialize (line 60) | final public static function jsonUnserialize($json): self
method jsonUnserializeFromProperties (line 99) | protected static function jsonUnserializeFromProperties($properties): ...
FILE: src/CoordinateReferenceSystem/Linked.php
class Linked (line 23) | class Linked extends CoordinateReferenceSystem
method __construct (line 27) | public function __construct(string $href, ?string $type = null)
method jsonUnserializeFromProperties (line 43) | protected static function jsonUnserializeFromProperties($properties): ...
FILE: src/CoordinateReferenceSystem/Named.php
class Named (line 22) | class Named extends CoordinateReferenceSystem
method __construct (line 26) | public function __construct(string $name)
method jsonUnserializeFromProperties (line 38) | protected static function jsonUnserializeFromProperties($properties): ...
FILE: src/Exception/Exception.php
type Exception (line 7) | interface Exception
FILE: src/Exception/InvalidArgumentException.php
class InvalidArgumentException (line 7) | class InvalidArgumentException extends \InvalidArgumentException impleme...
FILE: src/Exception/UnserializationException.php
class UnserializationException (line 15) | class UnserializationException extends RuntimeException implements Excep...
method invalidValue (line 22) | public static function invalidValue(string $context, $value, string $e...
method invalidProperty (line 37) | public static function invalidProperty(string $context, string $proper...
method missingProperty (line 51) | public static function missingProperty(string $context, string $proper...
method unsupportedType (line 64) | public static function unsupportedType(string $context, string $value)...
FILE: src/Feature/Feature.php
class Feature (line 19) | class Feature extends GeoJson
method __construct (line 45) | public function __construct(?Geometry $geometry = null, ?array $proper...
method getGeometry (line 57) | public function getGeometry(): ?Geometry
method getId (line 67) | public function getId()
method getProperties (line 75) | public function getProperties(): ?array
method jsonSerialize (line 80) | public function jsonSerialize(): array
FILE: src/Feature/FeatureCollection.php
class FeatureCollection (line 27) | class FeatureCollection extends GeoJson implements Countable, IteratorAg...
method __construct (line 40) | public function __construct(array $features, ...$args)
method count (line 53) | public function count(): int
method getFeatures (line 63) | public function getFeatures(): array
method getIterator (line 68) | public function getIterator(): Traversable
method jsonSerialize (line 73) | public function jsonSerialize(): array
FILE: src/GeoJson.php
class GeoJson (line 24) | abstract class GeoJson implements JsonSerializable, JsonUnserializable
method getBoundingBox (line 45) | public function getBoundingBox(): ?BoundingBox
method getCrs (line 53) | public function getCrs(): ?CoordinateReferenceSystem
method getType (line 61) | public function getType(): string
method jsonSerialize (line 66) | public function jsonSerialize(): array
method jsonUnserialize (line 84) | final public static function jsonUnserialize($json): self
method setOptionalConstructorArgs (line 184) | protected function setOptionalConstructorArgs(array $args): void
FILE: src/Geometry/Geometry.php
class Geometry (line 15) | abstract class Geometry extends GeoJson
method getCoordinates (line 22) | public function getCoordinates(): array
method jsonSerialize (line 27) | public function jsonSerialize(): array
FILE: src/Geometry/GeometryCollection.php
class GeometryCollection (line 26) | class GeometryCollection extends Geometry implements Countable, Iterator...
method __construct (line 39) | public function __construct(array $geometries, ...$args)
method count (line 52) | public function count(): int
method getGeometries (line 62) | public function getGeometries(): array
method getIterator (line 67) | public function getIterator(): Traversable
method jsonSerialize (line 72) | public function jsonSerialize(): array
FILE: src/Geometry/LineString.php
class LineString (line 21) | class LineString extends MultiPoint
method __construct (line 29) | public function __construct(array $positions, ...$args)
FILE: src/Geometry/LinearRing.php
class LinearRing (line 24) | class LinearRing extends LineString
method __construct (line 30) | public function __construct(array $positions, ...$args)
FILE: src/Geometry/MultiLineString.php
class MultiLineString (line 20) | class MultiLineString extends Geometry
method __construct (line 28) | public function __construct(array $lineStrings, ...$args)
FILE: src/Geometry/MultiPoint.php
class MultiPoint (line 20) | class MultiPoint extends Geometry
method __construct (line 28) | public function __construct(array $positions, ...$args)
FILE: src/Geometry/MultiPolygon.php
class MultiPolygon (line 20) | class MultiPolygon extends Geometry
method __construct (line 28) | public function __construct(array $polygons, ...$args)
FILE: src/Geometry/Point.php
class Point (line 23) | class Point extends Geometry
method __construct (line 31) | public function __construct(array $position, ...$args)
FILE: src/Geometry/Polygon.php
class Polygon (line 18) | class Polygon extends Geometry
method __construct (line 26) | public function __construct(array $linearRings, ...$args)
FILE: src/JsonUnserializable.php
type JsonUnserializable (line 16) | interface JsonUnserializable
method jsonUnserialize (line 25) | public static function jsonUnserialize($json);
FILE: tests/BaseGeoJsonTest.php
class BaseGeoJsonTest (line 13) | abstract class BaseGeoJsonTest extends TestCase
method createSubjectWithExtraArguments (line 20) | abstract public function createSubjectWithExtraArguments(...$extraArgs);
method testConstructorShouldScanExtraArgumentsForCrsAndBoundingBox (line 22) | public function testConstructorShouldScanExtraArgumentsForCrsAndBoundi...
method testSerializationWithCrsAndBoundingBox (line 53) | public function testSerializationWithCrsAndBoundingBox(): void
method getMockBoundingBox (line 71) | protected function getMockBoundingBox()
method getMockCoordinateReferenceSystem (line 76) | protected function getMockCoordinateReferenceSystem()
method getMockFeature (line 81) | protected function getMockFeature()
method getMockGeometry (line 86) | protected function getMockGeometry()
FILE: tests/BoundingBoxTest.php
class BoundingBoxTest (line 17) | class BoundingBoxTest extends TestCase
method testIsJsonSerializable (line 19) | public function testIsJsonSerializable(): void
method testIsJsonUnserializable (line 24) | public function testIsJsonUnserializable(): void
method testConstructorShouldRequireAtLeastFourValues (line 29) | public function testConstructorShouldRequireAtLeastFourValues(): void
method testConstructorShouldRequireAnEvenNumberOfValues (line 37) | public function testConstructorShouldRequireAnEvenNumberOfValues(): void
method testConstructorShouldRequireIntegerOrFloatValues (line 48) | public function testConstructorShouldRequireIntegerOrFloatValues(): void
method provideBoundsWithInvalidTypes (line 55) | public function provideBoundsWithInvalidTypes()
method testConstructorShouldRequireMinBeforeMaxValues (line 64) | public function testConstructorShouldRequireMinBeforeMaxValues(): void
method testSerialization (line 72) | public function testSerialization(): void
method testUnserialization (line 85) | public function testUnserialization($assoc): void
method provideJsonDecodeAssocOptions (line 96) | public function provideJsonDecodeAssocOptions()
method testUnserializationShouldRequireArray (line 107) | public function testUnserializationShouldRequireArray($value): void
method provideInvalidUnserializationValues (line 115) | public function provideInvalidUnserializationValues()
FILE: tests/CoordinateReferenceSystem/CoordinateReferenceSystemTest.php
class CoordinateReferenceSystemTest (line 13) | class CoordinateReferenceSystemTest extends TestCase
method testIsJsonSerializable (line 15) | public function testIsJsonSerializable(): void
method testIsJsonUnserializable (line 23) | public function testIsJsonUnserializable(): void
method testUnserializationShouldRequireArrayOrObject (line 31) | public function testUnserializationShouldRequireArrayOrObject(): void
method testUnserializationShouldRequireTypeField (line 39) | public function testUnserializationShouldRequireTypeField(): void
method testUnserializationShouldRequirePropertiesField (line 47) | public function testUnserializationShouldRequirePropertiesField(): void
method testUnserializationShouldRequireValidType (line 55) | public function testUnserializationShouldRequireValidType(): void
FILE: tests/CoordinateReferenceSystem/LinkedTest.php
class LinkedTest (line 15) | class LinkedTest extends TestCase
method testIsSubclassOfCoordinateReferenceSystem (line 17) | public function testIsSubclassOfCoordinateReferenceSystem(): void
method testSerialization (line 22) | public function testSerialization(): void
method testSerializationWithoutHrefType (line 39) | public function testSerializationWithoutHrefType(): void
method testUnserialization (line 57) | public function testUnserialization($assoc): void
method testUnserializationWithoutHrefType (line 86) | public function testUnserializationWithoutHrefType($assoc): void
method provideJsonDecodeAssocOptions (line 107) | public function provideJsonDecodeAssocOptions()
method testUnserializationShouldRequirePropertiesArrayOrObject (line 115) | public function testUnserializationShouldRequirePropertiesArrayOrObjec...
method testUnserializationShouldRequireHrefProperty (line 123) | public function testUnserializationShouldRequireHrefProperty(): void
FILE: tests/CoordinateReferenceSystem/NamedTest.php
class NamedTest (line 15) | class NamedTest extends TestCase
method testIsSubclassOfCoordinateReferenceSystem (line 17) | public function testIsSubclassOfCoordinateReferenceSystem(): void
method testSerialization (line 22) | public function testSerialization(): void
method testUnserialization (line 42) | public function testUnserialization($assoc): void
method provideJsonDecodeAssocOptions (line 63) | public function provideJsonDecodeAssocOptions()
method testUnserializationShouldRequirePropertiesArrayOrObject (line 71) | public function testUnserializationShouldRequirePropertiesArrayOrObjec...
method testUnserializationShouldRequireNameProperty (line 79) | public function testUnserializationShouldRequireNameProperty(): void
FILE: tests/Feature/FeatureCollectionTest.php
class FeatureCollectionTest (line 20) | class FeatureCollectionTest extends BaseGeoJsonTest
method createSubjectWithExtraArguments (line 22) | public function createSubjectWithExtraArguments(...$extraArgs)
method testIsSubclassOfGeoJson (line 27) | public function testIsSubclassOfGeoJson(): void
method testConstructorShouldRequireArrayOfFeatureObjects (line 33) | public function testConstructorShouldRequireArrayOfFeatureObjects(): void
method testConstructorShouldReindexFeaturesArrayNumerically (line 41) | public function testConstructorShouldReindexFeaturesArrayNumerically()...
method testIsTraversable (line 56) | public function testIsTraversable(): void
method testIsCountable (line 69) | public function testIsCountable(): void
method testSerialization (line 82) | public function testSerialization(): void
method testUnserialization (line 108) | public function testUnserialization($assoc): void
method provideJsonDecodeAssocOptions (line 148) | public function provideJsonDecodeAssocOptions()
method testUnserializationShouldRequireFeaturesProperty (line 156) | public function testUnserializationShouldRequireFeaturesProperty(): void
method testUnserializationShouldRequireFeaturesArray (line 164) | public function testUnserializationShouldRequireFeaturesArray(): void
FILE: tests/Feature/FeatureTest.php
class FeatureTest (line 16) | class FeatureTest extends BaseGeoJsonTest
method createSubjectWithExtraArguments (line 18) | public function createSubjectWithExtraArguments(...$extraArgs)
method testIsSubclassOfGeoJson (line 23) | public function testIsSubclassOfGeoJson(): void
method testSerialization (line 28) | public function testSerialization(): void
method testSerializationWithNullConstructorArguments (line 53) | public function testSerializationWithNullConstructorArguments(): void
method testSerializationShouldConvertEmptyPropertiesArrayToObject (line 66) | public function testSerializationShouldConvertEmptyPropertiesArrayToOb...
method testUnserialization (line 83) | public function testUnserialization($assoc): void
method provideJsonDecodeAssocOptions (line 114) | public function provideJsonDecodeAssocOptions()
FILE: tests/GeoJsonTest.php
class GeoJsonTest (line 21) | class GeoJsonTest extends TestCase
method testIsJsonSerializable (line 23) | public function testIsJsonSerializable(): void
method testIsJsonUnserializable (line 28) | public function testIsJsonUnserializable(): void
method testUnserializationWithBoundingBox (line 37) | public function testUnserializationWithBoundingBox($assoc): void
method testUnserializationWithCrs (line 64) | public function testUnserializationWithCrs($assoc): void
method testUnserializationWithInvalidArgument (line 95) | public function testUnserializationWithInvalidArgument(): void
method testUnserializationWithUnknownType (line 103) | public function testUnserializationWithUnknownType(): void
method testUnserializationWithMissingType (line 111) | public function testUnserializationWithMissingType(): void
method testUnserializationWithMissingCoordinates (line 122) | public function testUnserializationWithMissingCoordinates(string $type...
method testUnserializationWithInvalidCoordinates (line 137) | public function testUnserializationWithInvalidCoordinates($value): void
method testFeatureUnserializationWithInvalidGeometry (line 150) | public function testFeatureUnserializationWithInvalidGeometry(): void
method testFeatureUnserializationWithInvalidProperties (line 161) | public function testFeatureUnserializationWithInvalidProperties(): void
method provideJsonDecodeAssocOptions (line 172) | public function provideJsonDecodeAssocOptions()
method provideGeoJsonTypesWithCoordinates (line 180) | public function provideGeoJsonTypesWithCoordinates()
method provideInvalidCoordinates (line 192) | public function provideInvalidCoordinates()
FILE: tests/Geometry/GeometryCollectionTest.php
class GeometryCollectionTest (line 20) | class GeometryCollectionTest extends BaseGeoJsonTest
method createSubjectWithExtraArguments (line 22) | public function createSubjectWithExtraArguments(...$extraArgs)
method testIsSubclassOfGeometry (line 27) | public function testIsSubclassOfGeometry(): void
method testConstructorShouldRequireArrayOfGeometryObjects (line 32) | public function testConstructorShouldRequireArrayOfGeometryObjects(): ...
method testConstructorShouldReindexGeometriesArrayNumerically (line 40) | public function testConstructorShouldReindexGeometriesArrayNumerically...
method testIsTraversable (line 54) | public function testIsTraversable(): void
method testIsCountable (line 67) | public function testIsCountable(): void
method testSerialization (line 80) | public function testSerialization(): void
method testUnserialization (line 106) | public function testUnserialization($assoc): void
method provideJsonDecodeAssocOptions (line 135) | public function provideJsonDecodeAssocOptions()
method testUnserializationShouldRequireGeometriesProperty (line 143) | public function testUnserializationShouldRequireGeometriesProperty(): ...
method testUnserializationShouldRequireGeometriesArray (line 151) | public function testUnserializationShouldRequireGeometriesArray(): void
FILE: tests/Geometry/GeometryTest.php
class GeometryTest (line 13) | class GeometryTest extends TestCase
method testIsSubclassOfGeoJson (line 15) | public function testIsSubclassOfGeoJson(): void
FILE: tests/Geometry/LineStringTest.php
class LineStringTest (line 16) | class LineStringTest extends BaseGeoJsonTest
method createSubjectWithExtraArguments (line 18) | public function createSubjectWithExtraArguments(...$extraArgs)
method testIsSubclassOfMultiPoint (line 26) | public function testIsSubclassOfMultiPoint(): void
method testConstructorShouldRequireAtLeastTwoPositions (line 31) | public function testConstructorShouldRequireAtLeastTwoPositions(): void
method testSerialization (line 39) | public function testSerialization(): void
method testUnserialization (line 58) | public function testUnserialization($assoc): void
method provideJsonDecodeAssocOptions (line 80) | public function provideJsonDecodeAssocOptions()
FILE: tests/Geometry/LinearRingTest.php
class LinearRingTest (line 16) | class LinearRingTest extends BaseGeoJsonTest
method createSubjectWithExtraArguments (line 18) | public function createSubjectWithExtraArguments(...$extraArgs)
method testIsSubclassOfLineString (line 26) | public function testIsSubclassOfLineString(): void
method testConstructorShouldRequireAtLeastFourPositions (line 31) | public function testConstructorShouldRequireAtLeastFourPositions(): void
method testConstructorShouldRequireEquivalentFirstAndLastPositions (line 43) | public function testConstructorShouldRequireEquivalentFirstAndLastPosi...
method testConstructorShouldAcceptEquivalentPointObjectsAndPositionArrays (line 59) | public function testConstructorShouldAcceptEquivalentPointObjectsAndPo...
method testSerialization (line 69) | public function testSerialization(): void
FILE: tests/Geometry/MultiLineStringTest.php
class MultiLineStringTest (line 16) | class MultiLineStringTest extends BaseGeoJsonTest
method createSubjectWithExtraArguments (line 18) | public function createSubjectWithExtraArguments(...$extraArgs)
method testIsSubclassOfGeometry (line 23) | public function testIsSubclassOfGeometry(): void
method testConstructionFromLineStringObjects (line 28) | public function testConstructionFromLineStringObjects(): void
method testSerialization (line 43) | public function testSerialization(): void
method testUnserialization (line 66) | public function testUnserialization($assoc): void
method provideJsonDecodeAssocOptions (line 91) | public function provideJsonDecodeAssocOptions()
FILE: tests/Geometry/MultiPointTest.php
class MultiPointTest (line 16) | class MultiPointTest extends BaseGeoJsonTest
method createSubjectWithExtraArguments (line 18) | public function createSubjectWithExtraArguments(...$extraArgs)
method testIsSubclassOfGeometry (line 23) | public function testIsSubclassOfGeometry(): void
method testConstructionFromPointObjects (line 28) | public function testConstructionFromPointObjects(): void
method testSerialization (line 43) | public function testSerialization(): void
method testUnserialization (line 62) | public function testUnserialization($assoc): void
method provideJsonDecodeAssocOptions (line 84) | public function provideJsonDecodeAssocOptions()
FILE: tests/Geometry/MultiPolygonTest.php
class MultiPolygonTest (line 16) | class MultiPolygonTest extends BaseGeoJsonTest
method createSubjectWithExtraArguments (line 18) | public function createSubjectWithExtraArguments(...$extraArgs)
method testIsSubclassOfGeometry (line 23) | public function testIsSubclassOfGeometry(): void
method testConstructionFromPolygonObjects (line 28) | public function testConstructionFromPolygonObjects(): void
method testSerialization (line 43) | public function testSerialization(): void
method testUnserialization (line 66) | public function testUnserialization($assoc): void
method provideJsonDecodeAssocOptions (line 91) | public function provideJsonDecodeAssocOptions()
FILE: tests/Geometry/PointTest.php
class PointTest (line 18) | class PointTest extends BaseGeoJsonTest
method createSubjectWithExtraArguments (line 20) | public function createSubjectWithExtraArguments(...$extraArgs)
method testIsSubclassOfGeometry (line 25) | public function testIsSubclassOfGeometry(): void
method testConstructorShouldRequireAtLeastTwoElementsInPosition (line 30) | public function testConstructorShouldRequireAtLeastTwoElementsInPositi...
method testConstructorShouldRequireIntegerOrFloatElementsInPosition (line 41) | public function testConstructorShouldRequireIntegerOrFloatElementsInPo...
method providePositionsWithInvalidTypes (line 49) | public function providePositionsWithInvalidTypes()
method testConstructorShouldAllowMoreThanTwoElementsInAPosition (line 58) | public function testConstructorShouldAllowMoreThanTwoElementsInAPositi...
method testSerialization (line 65) | public function testSerialization(): void
method testUnserialization (line 84) | public function testUnserialization($assoc): void
method provideJsonDecodeAssocOptions (line 101) | public function provideJsonDecodeAssocOptions()
FILE: tests/Geometry/PolygonTest.php
class PolygonTest (line 16) | class PolygonTest extends BaseGeoJsonTest
method createSubjectWithExtraArguments (line 18) | public function createSubjectWithExtraArguments(...$extraArgs)
method testIsSubclassOfGeometry (line 29) | public function testIsSubclassOfGeometry(): void
method testConstructionFromLinearRingObjects (line 34) | public function testConstructionFromLinearRingObjects(): void
method testSerialization (line 49) | public function testSerialization(): void
method testUnserialization (line 72) | public function testUnserialization($assoc): void
method provideJsonDecodeAssocOptions (line 97) | public function provideJsonDecodeAssocOptions()
Condensed preview — 48 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (109K chars).
[
{
"path": ".gitattributes",
"chars": 211,
"preview": "*.php diff=php\n\n/tests export-ignore\n\n/.gitattributes export-ignore\n/.github export-ignore\n/.gitignore export-ignore\n/.s"
},
{
"path": ".github/workflows/coding-standards.yml",
"chars": 1172,
"preview": "name: \"Coding Standards\"\n\non:\n pull_request:\n branches:\n - \"v*.*\"\n - \"master\"\n push:\n branches:\n "
},
{
"path": ".github/workflows/tests.yml",
"chars": 1083,
"preview": "name: \"Tests\"\n\non:\n pull_request:\n push:\n\njobs:\n phpunit:\n name: PHPUnit Tests\n runs-on: ubuntu-20.04\n\n stra"
},
{
"path": ".gitignore",
"chars": 68,
"preview": ".phpcs-cache\n.phpunit.result.cache\ncomposer.lock\nphpunit.xml\nvendor\n"
},
{
"path": ".scrutinizer.yml",
"chars": 787,
"preview": "filter:\n excluded_paths: [ \"vendor/*\", \"tests/*\" ]\n\ntools:\n # https://scrutinizer-ci.com/docs/tools/external-code-"
},
{
"path": "LICENSE",
"chars": 1065,
"preview": "Copyright (c) 2013-present Jeremy Mikola\n\nPermission is hereby granted, free of charge, to any person obtaining a copy o"
},
{
"path": "README.md",
"chars": 873,
"preview": "# GeoJson PHP Library\n\n[](https"
},
{
"path": "USAGE.md",
"chars": 3374,
"preview": "# GeoJson PHP Library\n\nThis library implements the\n[GeoJSON format specification](https://geojson.org/).\n\nThe `GeoJson` "
},
{
"path": "composer.json",
"chars": 1043,
"preview": "{\n \"name\": \"jmikola/geojson\",\n \"type\": \"library\",\n \"description\": \"GeoJSON implementation for PHP\",\n \"keywor"
},
{
"path": "phpcs.xml.dist",
"chars": 8469,
"preview": "<?xml version=\"1.0\"?>\n<ruleset>\n <arg name=\"basepath\" value=\".\" />\n <arg name=\"extensions\" value=\"php\" />\n <arg"
},
{
"path": "phpunit.xml.dist",
"chars": 542,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<phpunit\n xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n xsi:noNam"
},
{
"path": "src/BoundingBox.php",
"chars": 1978,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace GeoJson;\n\nuse GeoJson\\Exception\\InvalidArgumentException;\nuse GeoJson\\Excepti"
},
{
"path": "src/CoordinateReferenceSystem/CoordinateReferenceSystem.php",
"chars": 2752,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace GeoJson\\CoordinateReferenceSystem;\n\nuse ArrayObject;\nuse BadMethodCallExcepti"
},
{
"path": "src/CoordinateReferenceSystem/Linked.php",
"chars": 1706,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace GeoJson\\CoordinateReferenceSystem;\n\nuse ArrayObject;\nuse GeoJson\\Exception\\Un"
},
{
"path": "src/CoordinateReferenceSystem/Named.php",
"chars": 1441,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace GeoJson\\CoordinateReferenceSystem;\n\nuse ArrayObject;\nuse GeoJson\\Exception\\Un"
},
{
"path": "src/Exception/Exception.php",
"chars": 87,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace GeoJson\\Exception;\n\ninterface Exception\n{\n}\n"
},
{
"path": "src/Exception/InvalidArgumentException.php",
"chars": 153,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace GeoJson\\Exception;\n\nclass InvalidArgumentException extends \\InvalidArgumentEx"
},
{
"path": "src/Exception/UnserializationException.php",
"chars": 1855,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace GeoJson\\Exception;\n\nuse RuntimeException;\n\nuse function get_class;\nuse functi"
},
{
"path": "src/Feature/Feature.php",
"chars": 2267,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace GeoJson\\Feature;\n\nuse GeoJson\\BoundingBox;\nuse GeoJson\\CoordinateReferenceSys"
},
{
"path": "src/Feature/FeatureCollection.php",
"chars": 1936,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace GeoJson\\Feature;\n\nuse ArrayIterator;\nuse Countable;\nuse GeoJson\\BoundingBox;\n"
},
{
"path": "src/GeoJson.php",
"chars": 6279,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace GeoJson;\n\nuse ArrayObject;\nuse GeoJson\\CoordinateReferenceSystem\\CoordinateRe"
},
{
"path": "src/Geometry/Geometry.php",
"chars": 669,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace GeoJson\\Geometry;\n\nuse GeoJson\\GeoJson;\n\n/**\n * Base geometry object.\n *\n * @"
},
{
"path": "src/Geometry/GeometryCollection.php",
"chars": 1949,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace GeoJson\\Geometry;\n\nuse ArrayIterator;\nuse Countable;\nuse GeoJson\\BoundingBox;"
},
{
"path": "src/Geometry/LineString.php",
"chars": 892,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace GeoJson\\Geometry;\n\nuse GeoJson\\BoundingBox;\nuse GeoJson\\CoordinateReferenceSy"
},
{
"path": "src/Geometry/LinearRing.php",
"chars": 1443,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace GeoJson\\Geometry;\n\nuse GeoJson\\BoundingBox;\nuse GeoJson\\CoordinateReferenceSy"
},
{
"path": "src/Geometry/MultiLineString.php",
"chars": 1076,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace GeoJson\\Geometry;\n\nuse GeoJson\\BoundingBox;\nuse GeoJson\\CoordinateReferenceSy"
},
{
"path": "src/Geometry/MultiPoint.php",
"chars": 983,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace GeoJson\\Geometry;\n\nuse GeoJson\\BoundingBox;\nuse GeoJson\\CoordinateReferenceSy"
},
{
"path": "src/Geometry/MultiPolygon.php",
"chars": 1045,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace GeoJson\\Geometry;\n\nuse GeoJson\\BoundingBox;\nuse GeoJson\\CoordinateReferenceSy"
},
{
"path": "src/Geometry/Point.php",
"chars": 1139,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace GeoJson\\Geometry;\n\nuse GeoJson\\BoundingBox;\nuse GeoJson\\CoordinateReferenceSy"
},
{
"path": "src/Geometry/Polygon.php",
"chars": 939,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace GeoJson\\Geometry;\n\nuse GeoJson\\BoundingBox;\nuse GeoJson\\CoordinateReferenceSy"
},
{
"path": "src/JsonUnserializable.php",
"chars": 549,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace GeoJson;\n\nuse GeoJson\\Exception\\UnserializationException;\n\n/**\n * JsonUnseria"
},
{
"path": "tests/BaseGeoJsonTest.php",
"chars": 2830,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace GeoJson\\Tests;\n\nuse GeoJson\\BoundingBox;\nuse GeoJson\\CoordinateReferenceSyste"
},
{
"path": "tests/BoundingBoxTest.php",
"chars": 3613,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace GeoJson\\Tests;\n\nuse GeoJson\\BoundingBox;\nuse GeoJson\\Exception\\InvalidArgumen"
},
{
"path": "tests/CoordinateReferenceSystem/CoordinateReferenceSystemTest.php",
"chars": 2024,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace GeoJson\\Tests\\CoordinateReferenceSystem;\n\nuse GeoJson\\CoordinateReferenceSyst"
},
{
"path": "tests/CoordinateReferenceSystem/LinkedTest.php",
"chars": 3687,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace GeoJson\\Tests\\CoordinateReferenceSystem;\n\nuse GeoJson\\CoordinateReferenceSyst"
},
{
"path": "tests/CoordinateReferenceSystem/NamedTest.php",
"chars": 2547,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace GeoJson\\Tests\\CoordinateReferenceSystem;\n\nuse GeoJson\\CoordinateReferenceSyst"
},
{
"path": "tests/Feature/FeatureCollectionTest.php",
"chars": 5100,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace GeoJson\\Tests\\Feature;\n\nuse GeoJson\\Exception\\InvalidArgumentException;\nuse G"
},
{
"path": "tests/Feature/FeatureTest.php",
"chars": 3243,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace GeoJson\\Tests\\Feature;\n\nuse GeoJson\\Feature\\Feature;\nuse GeoJson\\GeoJson;\nuse"
},
{
"path": "tests/GeoJsonTest.php",
"chars": 6113,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace GeoJson\\Tests;\n\nuse GeoJson\\BoundingBox;\nuse GeoJson\\CoordinateReferenceSyste"
},
{
"path": "tests/Geometry/GeometryCollectionTest.php",
"chars": 4780,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace GeoJson\\Tests\\Geometry;\n\nuse GeoJson\\Exception\\InvalidArgumentException;\nuse "
},
{
"path": "tests/Geometry/GeometryTest.php",
"chars": 363,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace GeoJson\\Tests\\Geometry;\n\nuse GeoJson\\GeoJson;\nuse GeoJson\\Geometry\\Geometry;\n"
},
{
"path": "tests/Geometry/LineStringTest.php",
"chars": 2262,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace GeoJson\\Tests\\Geometry;\n\nuse GeoJson\\Exception\\InvalidArgumentException;\nuse "
},
{
"path": "tests/Geometry/LinearRingTest.php",
"chars": 2218,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace GeoJson\\Tests\\Geometry;\n\nuse GeoJson\\Exception\\InvalidArgumentException;\nuse "
},
{
"path": "tests/Geometry/MultiLineStringTest.php",
"chars": 2605,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace GeoJson\\Tests\\Geometry;\n\nuse GeoJson\\GeoJson;\nuse GeoJson\\Geometry\\Geometry;\n"
},
{
"path": "tests/Geometry/MultiPointTest.php",
"chars": 2287,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace GeoJson\\Tests\\Geometry;\n\nuse GeoJson\\GeoJson;\nuse GeoJson\\Geometry\\Geometry;\n"
},
{
"path": "tests/Geometry/MultiPolygonTest.php",
"chars": 2782,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace GeoJson\\Tests\\Geometry;\n\nuse GeoJson\\GeoJson;\nuse GeoJson\\Geometry\\Geometry;\n"
},
{
"path": "tests/Geometry/PointTest.php",
"chars": 2850,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace GeoJson\\Tests\\Geometry;\n\nuse GeoJson\\Exception\\InvalidArgumentException;\nuse "
},
{
"path": "tests/Geometry/PolygonTest.php",
"chars": 2810,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace GeoJson\\Tests\\Geometry;\n\nuse GeoJson\\GeoJson;\nuse GeoJson\\Geometry\\Geometry;\n"
}
]
About this extraction
This page contains the full source code of the jmikola/geojson GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 48 files (99.5 KB), approximately 25.3k tokens, and a symbol index with 213 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.