From 4c88dbd9acf44009efb948976f2df8db33898530 Mon Sep 17 00:00:00 2001 From: Stephen Abello Date: Fri, 13 May 2022 14:39:19 +0200 Subject: [PATCH] =?UTF-8?q?N=C2=B02504=20N=C2=B03169=20N=C2=B05102=20Add?= =?UTF-8?q?=20libraries?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/bin/generate-deps-for-config-factory | 117 +++++++ lib/bin/generate-factory-for-class | 117 +++++++ .../container-interop/.gitignore | 3 + .../container-interop/LICENSE | 20 ++ .../container-interop/README.md | 148 ++++++++ .../container-interop/composer.json | 15 + .../docs/ContainerInterface-meta.md | 114 +++++++ .../docs/ContainerInterface.md | 158 +++++++++ .../docs/Delegate-lookup-meta.md | 259 ++++++++++++++ .../container-interop/docs/Delegate-lookup.md | 60 ++++ .../docs/images/interoperating_containers.png | Bin 0 -> 25738 bytes .../docs/images/priority.png | Bin 0 -> 16252 bytes .../docs/images/side_by_side_containers.png | Bin 0 -> 16265 bytes .../Interop/Container/ContainerInterface.php | 15 + .../Exception/ContainerException.php | 15 + .../Container/Exception/NotFoundException.php | 15 + lib/psr/http-message/CHANGELOG.md | 36 ++ lib/psr/http-message/LICENSE | 19 ++ lib/psr/http-message/README.md | 13 + lib/psr/http-message/composer.json | 26 ++ lib/psr/http-message/src/MessageInterface.php | 187 ++++++++++ lib/psr/http-message/src/RequestInterface.php | 129 +++++++ .../http-message/src/ResponseInterface.php | 68 ++++ .../src/ServerRequestInterface.php | 261 ++++++++++++++ lib/psr/http-message/src/StreamInterface.php | 158 +++++++++ .../src/UploadedFileInterface.php | 123 +++++++ lib/psr/http-message/src/UriInterface.php | 323 ++++++++++++++++++ 27 files changed, 2399 insertions(+) create mode 100755 lib/bin/generate-deps-for-config-factory create mode 100755 lib/bin/generate-factory-for-class create mode 100644 lib/container-interop/container-interop/.gitignore create mode 100644 lib/container-interop/container-interop/LICENSE create mode 100644 lib/container-interop/container-interop/README.md create mode 100644 lib/container-interop/container-interop/composer.json create mode 100644 lib/container-interop/container-interop/docs/ContainerInterface-meta.md create mode 100644 lib/container-interop/container-interop/docs/ContainerInterface.md create mode 100644 lib/container-interop/container-interop/docs/Delegate-lookup-meta.md create mode 100644 lib/container-interop/container-interop/docs/Delegate-lookup.md create mode 100644 lib/container-interop/container-interop/docs/images/interoperating_containers.png create mode 100644 lib/container-interop/container-interop/docs/images/priority.png create mode 100644 lib/container-interop/container-interop/docs/images/side_by_side_containers.png create mode 100644 lib/container-interop/container-interop/src/Interop/Container/ContainerInterface.php create mode 100644 lib/container-interop/container-interop/src/Interop/Container/Exception/ContainerException.php create mode 100644 lib/container-interop/container-interop/src/Interop/Container/Exception/NotFoundException.php create mode 100644 lib/psr/http-message/CHANGELOG.md create mode 100644 lib/psr/http-message/LICENSE create mode 100644 lib/psr/http-message/README.md create mode 100644 lib/psr/http-message/composer.json create mode 100644 lib/psr/http-message/src/MessageInterface.php create mode 100644 lib/psr/http-message/src/RequestInterface.php create mode 100644 lib/psr/http-message/src/ResponseInterface.php create mode 100644 lib/psr/http-message/src/ServerRequestInterface.php create mode 100644 lib/psr/http-message/src/StreamInterface.php create mode 100644 lib/psr/http-message/src/UploadedFileInterface.php create mode 100644 lib/psr/http-message/src/UriInterface.php diff --git a/lib/bin/generate-deps-for-config-factory b/lib/bin/generate-deps-for-config-factory new file mode 100755 index 000000000..b11a73d34 --- /dev/null +++ b/lib/bin/generate-deps-for-config-factory @@ -0,0 +1,117 @@ +#!/usr/bin/env php +realpath = realpath($opened_path) ?: $opened_path; + $opened_path = $this->realpath; + $this->handle = fopen($this->realpath, $mode); + $this->position = 0; + + return (bool) $this->handle; + } + + public function stream_read($count) + { + $data = fread($this->handle, $count); + + if ($this->position === 0) { + $data = preg_replace('{^#!.*\r?\n}', '', $data); + } + + $this->position += strlen($data); + + return $data; + } + + public function stream_cast($castAs) + { + return $this->handle; + } + + public function stream_close() + { + fclose($this->handle); + } + + public function stream_lock($operation) + { + return $operation ? flock($this->handle, $operation) : true; + } + + public function stream_seek($offset, $whence) + { + if (0 === fseek($this->handle, $offset, $whence)) { + $this->position = ftell($this->handle); + return true; + } + + return false; + } + + public function stream_tell() + { + return $this->position; + } + + public function stream_eof() + { + return feof($this->handle); + } + + public function stream_stat() + { + return array(); + } + + public function stream_set_option($option, $arg1, $arg2) + { + return true; + } + + public function url_stat($path, $flags) + { + $path = substr($path, 17); + if (file_exists($path)) { + return stat($path); + } + + return false; + } + } + } + + if (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper')) { + include("phpvfscomposer://" . __DIR__ . '/..'.'/laminas/laminas-servicemanager/bin/generate-deps-for-config-factory'); + exit(0); + } +} + +include __DIR__ . '/..'.'/laminas/laminas-servicemanager/bin/generate-deps-for-config-factory'; diff --git a/lib/bin/generate-factory-for-class b/lib/bin/generate-factory-for-class new file mode 100755 index 000000000..4896b92fc --- /dev/null +++ b/lib/bin/generate-factory-for-class @@ -0,0 +1,117 @@ +#!/usr/bin/env php +realpath = realpath($opened_path) ?: $opened_path; + $opened_path = $this->realpath; + $this->handle = fopen($this->realpath, $mode); + $this->position = 0; + + return (bool) $this->handle; + } + + public function stream_read($count) + { + $data = fread($this->handle, $count); + + if ($this->position === 0) { + $data = preg_replace('{^#!.*\r?\n}', '', $data); + } + + $this->position += strlen($data); + + return $data; + } + + public function stream_cast($castAs) + { + return $this->handle; + } + + public function stream_close() + { + fclose($this->handle); + } + + public function stream_lock($operation) + { + return $operation ? flock($this->handle, $operation) : true; + } + + public function stream_seek($offset, $whence) + { + if (0 === fseek($this->handle, $offset, $whence)) { + $this->position = ftell($this->handle); + return true; + } + + return false; + } + + public function stream_tell() + { + return $this->position; + } + + public function stream_eof() + { + return feof($this->handle); + } + + public function stream_stat() + { + return array(); + } + + public function stream_set_option($option, $arg1, $arg2) + { + return true; + } + + public function url_stat($path, $flags) + { + $path = substr($path, 17); + if (file_exists($path)) { + return stat($path); + } + + return false; + } + } + } + + if (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper')) { + include("phpvfscomposer://" . __DIR__ . '/..'.'/laminas/laminas-servicemanager/bin/generate-factory-for-class'); + exit(0); + } +} + +include __DIR__ . '/..'.'/laminas/laminas-servicemanager/bin/generate-factory-for-class'; diff --git a/lib/container-interop/container-interop/.gitignore b/lib/container-interop/container-interop/.gitignore new file mode 100644 index 000000000..b2395aa05 --- /dev/null +++ b/lib/container-interop/container-interop/.gitignore @@ -0,0 +1,3 @@ +composer.lock +composer.phar +/vendor/ diff --git a/lib/container-interop/container-interop/LICENSE b/lib/container-interop/container-interop/LICENSE new file mode 100644 index 000000000..7671d9020 --- /dev/null +++ b/lib/container-interop/container-interop/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2013 container-interop + +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. diff --git a/lib/container-interop/container-interop/README.md b/lib/container-interop/container-interop/README.md new file mode 100644 index 000000000..cdd7a44c8 --- /dev/null +++ b/lib/container-interop/container-interop/README.md @@ -0,0 +1,148 @@ +# Container Interoperability + +[![Latest Stable Version](https://poser.pugx.org/container-interop/container-interop/v/stable.png)](https://packagist.org/packages/container-interop/container-interop) +[![Total Downloads](https://poser.pugx.org/container-interop/container-interop/downloads.svg)](https://packagist.org/packages/container-interop/container-interop) + +## Deprecation warning! + +Starting Feb. 13th 2017, container-interop is officially deprecated in favor of [PSR-11](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-11-container.md). +Container-interop has been the test-bed of PSR-11. From v1.2, container-interop directly extends PSR-11 interfaces. +Therefore, all containers implementing container-interop are now *de-facto* compatible with PSR-11. + +- Projects implementing container-interop interfaces are encouraged to directly implement PSR-11 interfaces instead. +- Projects consuming container-interop interfaces are very strongly encouraged to directly type-hint on PSR-11 interfaces, in order to be compatible with PSR-11 containers that are not compatible with container-interop. + +Regarding the delegate lookup feature, that is present in container-interop and not in PSR-11, the feature is actually a design pattern. It is therefore not deprecated. Documentation regarding this design pattern will be migrated from this repository into a separate website in the future. + +## About + +*container-interop* tries to identify and standardize features in *container* objects (service locators, +dependency injection containers, etc.) to achieve interoperability. + +Through discussions and trials, we try to create a standard, made of common interfaces but also recommendations. + +If PHP projects that provide container implementations begin to adopt these common standards, then PHP +applications and projects that use containers can depend on the common interfaces instead of specific +implementations. This facilitates a high-level of interoperability and flexibility that allows users to consume +*any* container implementation that can be adapted to these interfaces. + +The work done in this project is not officially endorsed by the [PHP-FIG](http://www.php-fig.org/), but it is being +worked on by members of PHP-FIG and other good developers. We adhere to the spirit and ideals of PHP-FIG, and hope +this project will pave the way for one or more future PSRs. + + +## Installation + +You can install this package through Composer: + +```json +composer require container-interop/container-interop +``` + +The packages adheres to the [SemVer](http://semver.org/) specification, and there will be full backward compatibility +between minor versions. + +## Standards + +### Available + +- [`ContainerInterface`](src/Interop/Container/ContainerInterface.php). +[Description](docs/ContainerInterface.md) [Meta Document](docs/ContainerInterface-meta.md). +Describes the interface of a container that exposes methods to read its entries. +- [*Delegate lookup feature*](docs/Delegate-lookup.md). +[Meta Document](docs/Delegate-lookup-meta.md). +Describes the ability for a container to delegate the lookup of its dependencies to a third-party container. This +feature lets several containers work together in a single application. + +### Proposed + +View open [request for comments](https://github.com/container-interop/container-interop/labels/RFC) + +## Compatible projects + +### Projects implementing `ContainerInterface` + +- [Acclimate](https://github.com/jeremeamia/acclimate-container): Adapters for + Aura.Di, Laravel, Nette DI, Pimple, Symfony DI, ZF2 Service manager, ZF2 + Dependency injection and any container using `ArrayAccess` +- [Aura.Di](https://github.com/auraphp/Aura.Di) +- [auryn-container-interop](https://github.com/elazar/auryn-container-interop) +- [Burlap](https://github.com/codeeverything/burlap) +- [Chernozem](https://github.com/pyrsmk/Chernozem) +- [Data Manager](https://github.com/chrismichaels84/data-manager) +- [Disco](https://github.com/bitexpert/disco) +- [InDI](https://github.com/idealogica/indi) +- [League/Container](http://container.thephpleague.com/) +- [Mouf](http://mouf-php.com) +- [Njasm Container](https://github.com/njasm/container) +- [PHP-DI](http://php-di.org) +- [Picotainer](https://github.com/thecodingmachine/picotainer) +- [PimpleInterop](https://github.com/moufmouf/pimple-interop) +- [Pimple3-ContainerInterop](https://github.com/Sam-Burns/pimple3-containerinterop) (using Pimple v3) +- [SitePoint Container](https://github.com/sitepoint/Container) +- [Thruster Container](https://github.com/ThrusterIO/container) (PHP7 only) +- [Ultra-Lite Container](https://github.com/ultra-lite/container) +- [Unbox](https://github.com/mindplay-dk/unbox) +- [XStatic](https://github.com/jeremeamia/xstatic) +- [Zend\ServiceManager](https://github.com/zendframework/zend-servicemanager) +- [Zit](https://github.com/inxilpro/Zit) + +### Projects implementing the *delegate lookup* feature + +- [Aura.Di](https://github.com/auraphp/Aura.Di) +- [Burlap](https://github.com/codeeverything/burlap) +- [Chernozem](https://github.com/pyrsmk/Chernozem) +- [InDI](https://github.com/idealogica/indi) +- [League/Container](http://container.thephpleague.com/) +- [Mouf](http://mouf-php.com) +- [Picotainer](https://github.com/thecodingmachine/picotainer) +- [PHP-DI](http://php-di.org) +- [PimpleInterop](https://github.com/moufmouf/pimple-interop) +- [Ultra-Lite Container](https://github.com/ultra-lite/container) + +### Middlewares implementing `ContainerInterface` + +- [Alias-Container](https://github.com/thecodingmachine/alias-container): add + aliases support to any container +- [Prefixer-Container](https://github.com/thecodingmachine/prefixer-container): + dynamically prefix identifiers +- [Lazy-Container](https://github.com/snapshotpl/lazy-container): lazy services + +### Projects using `ContainerInterface` + +The list below contains only a sample of all the projects consuming `ContainerInterface`. For a more complete list have a look [here](http://packanalyst.com/class?q=Interop%5CContainer%5CContainerInterface). + +| | Downloads | +| --- | --- | +| [Adroit](https://github.com/bitexpert/adroit) | ![](https://img.shields.io/packagist/dt/bitexpert/adroit.svg) | +| [Behat](https://github.com/Behat/Behat/pull/974) | ![](https://img.shields.io/packagist/dt/behat/behat.svg) | +| [blast-facades](https://github.com/phpthinktank/blast-facades): Minimize complexity and represent dependencies as facades. | ![](https://img.shields.io/packagist/dt/blast/facades.svg) | +| [interop.silex.di](https://github.com/thecodingmachine/interop.silex.di): an extension to [Silex](http://silex.sensiolabs.org/) that adds support for any *container-interop* compatible container | ![](https://img.shields.io/packagist/dt/mouf/interop.silex.di.svg) | +| [mindplay/walkway](https://github.com/mindplay-dk/walkway): a modular request router | ![](https://img.shields.io/packagist/dt/mindplay/walkway.svg) | +| [mindplay/middleman](https://github.com/mindplay-dk/middleman): minimalist PSR-7 middleware dispatcher | ![](https://img.shields.io/packagist/dt/mindplay/middleman.svg) | +| [PHP-DI/Invoker](https://github.com/PHP-DI/Invoker): extensible and configurable invoker/dispatcher | ![](https://img.shields.io/packagist/dt/php-di/invoker.svg) | +| [Prophiler](https://github.com/fabfuel/prophiler) | ![](https://img.shields.io/packagist/dt/fabfuel/prophiler.svg) | +| [Silly](https://github.com/mnapoli/silly): CLI micro-framework | ![](https://img.shields.io/packagist/dt/mnapoli/silly.svg) | +| [Slim v3](https://github.com/slimphp/Slim) | ![](https://img.shields.io/packagist/dt/slim/slim.svg) | +| [Splash](http://mouf-php.com/packages/mouf/mvc.splash-common/version/8.0-dev/README.md) | ![](https://img.shields.io/packagist/dt/mouf/mvc.splash-common.svg) | +| [Woohoo Labs. Harmony](https://github.com/woohoolabs/harmony): a flexible micro-framework | ![](https://img.shields.io/packagist/dt/woohoolabs/harmony.svg) | +| [zend-expressive](https://github.com/zendframework/zend-expressive) | ![](https://img.shields.io/packagist/dt/zendframework/zend-expressive.svg) | + + +## Workflow + +Everyone is welcome to join and contribute. + +The general workflow looks like this: + +1. Someone opens a discussion (GitHub issue) to suggest an interface +1. Feedback is gathered +1. The interface is added to a development branch +1. We release alpha versions so that the interface can be experimented with +1. Discussions and edits ensue until the interface is deemed stable by a general consensus +1. A new minor version of the package is released + +We try to not break BC by creating new interfaces instead of editing existing ones. + +While we currently work on interfaces, we are open to anything that might help towards interoperability, may that +be code, best practices, etc. diff --git a/lib/container-interop/container-interop/composer.json b/lib/container-interop/container-interop/composer.json new file mode 100644 index 000000000..855f76672 --- /dev/null +++ b/lib/container-interop/container-interop/composer.json @@ -0,0 +1,15 @@ +{ + "name": "container-interop/container-interop", + "type": "library", + "description": "Promoting the interoperability of container objects (DIC, SL, etc.)", + "homepage": "https://github.com/container-interop/container-interop", + "license": "MIT", + "autoload": { + "psr-4": { + "Interop\\Container\\": "src/Interop/Container/" + } + }, + "require": { + "psr/container": "^1.0" + } +} diff --git a/lib/container-interop/container-interop/docs/ContainerInterface-meta.md b/lib/container-interop/container-interop/docs/ContainerInterface-meta.md new file mode 100644 index 000000000..59f3d5599 --- /dev/null +++ b/lib/container-interop/container-interop/docs/ContainerInterface-meta.md @@ -0,0 +1,114 @@ +# ContainerInterface Meta Document + +## Introduction + +This document describes the process and discussions that lead to the `ContainerInterface`. +Its goal is to explain the reasons behind each decision. + +## Goal + +The goal set by `ContainerInterface` is to standardize how frameworks and libraries make use of a +container to obtain objects and parameters. + +By standardizing such a behavior, frameworks and libraries using the `ContainerInterface` +could work with any compatible container. +That would allow end users to choose their own container based on their own preferences. + +It is important to distinguish the two usages of a container: + +- configuring entries +- fetching entries + +Most of the time, those two sides are not used by the same party. +While it is often end users who tend to configure entries, it is generally the framework that fetch +entries to build the application. + +This is why this interface focuses only on how entries can be fetched from a container. + +## Interface name + +The interface name has been thoroughly discussed and was decided by a vote. + +The list of options considered with their respective votes are: + +- `ContainerInterface`: +8 +- `ProviderInterface`: +2 +- `LocatorInterface`: 0 +- `ReadableContainerInterface`: -5 +- `ServiceLocatorInterface`: -6 +- `ObjectFactory`: -6 +- `ObjectStore`: -8 +- `ConsumerInterface`: -9 + +[Full results of the vote](https://github.com/container-interop/container-interop/wiki/%231-interface-name:-Vote) + +The complete discussion can be read in [the issue #1](https://github.com/container-interop/container-interop/issues/1). + +## Interface methods + +The choice of which methods the interface would contain was made after a statistical analysis of existing containers. +The results of this analysis are available [in this document](https://gist.github.com/mnapoli/6159681). + +The summary of the analysis showed that: + +- all containers offer a method to get an entry by its id +- a large majority name such method `get()` +- for all containers, the `get()` method has 1 mandatory parameter of type string +- some containers have an optional additional argument for `get()`, but it doesn't have the same purpose between containers +- a large majority of the containers offer a method to test if it can return an entry by its id +- a majority name such method `has()` +- for all containers offering `has()`, the method has exactly 1 parameter of type string +- a large majority of the containers throw an exception rather than returning null when an entry is not found in `get()` +- a large majority of the containers don't implement `ArrayAccess` + +The question of whether to include methods to define entries has been discussed in +[issue #1](https://github.com/container-interop/container-interop/issues/1). +It has been judged that such methods do not belong in the interface described here because it is out of its scope +(see the "Goal" section). + +As a result, the `ContainerInterface` contains two methods: + +- `get()`, returning anything, with one mandatory string parameter. Should throw an exception if the entry is not found. +- `has()`, returning a boolean, with one mandatory string parameter. + +### Number of parameters in `get()` method + +While `ContainerInterface` only defines one mandatory parameter in `get()`, it is not incompatible with +existing containers that have additional optional parameters. PHP allows an implementation to offer more parameters +as long as they are optional, because the implementation *does* satisfy the interface. + +This issue has been discussed in [issue #6](https://github.com/container-interop/container-interop/issues/6). + +### Type of the `$id` parameter + +The type of the `$id` parameter in `get()` and `has()` has been discussed in +[issue #6](https://github.com/container-interop/container-interop/issues/6). +While `string` is used in all the containers that were analyzed, it was suggested that allowing +anything (such as objects) could allow containers to offer a more advanced query API. + +An example given was to use the container as an object builder. The `$id` parameter would then be an +object that would describe how to create an instance. + +The conclusion of the discussion was that this was beyond the scope of getting entries from a container without +knowing how the container provided them, and it was more fit for a factory. + +## Contributors + +Are listed here all people that contributed in the discussions or votes, by alphabetical order: + +- [Amy Stephen](https://github.com/AmyStephen) +- [David Négrier](https://github.com/moufmouf) +- [Don Gilbert](https://github.com/dongilbert) +- [Jason Judge](https://github.com/judgej) +- [Jeremy Lindblom](https://github.com/jeremeamia) +- [Marco Pivetta](https://github.com/Ocramius) +- [Matthieu Napoli](https://github.com/mnapoli) +- [Paul M. Jones](https://github.com/pmjones) +- [Stephan Hochdörfer](https://github.com/shochdoerfer) +- [Taylor Otwell](https://github.com/taylorotwell) + +## Relevant links + +- [`ContainerInterface.php`](https://github.com/container-interop/container-interop/blob/master/src/Interop/Container/ContainerInterface.php) +- [List of all issues](https://github.com/container-interop/container-interop/issues?labels=ContainerInterface&milestone=&page=1&state=closed) +- [Vote for the interface name](https://github.com/container-interop/container-interop/wiki/%231-interface-name:-Vote) diff --git a/lib/container-interop/container-interop/docs/ContainerInterface.md b/lib/container-interop/container-interop/docs/ContainerInterface.md new file mode 100644 index 000000000..bda973d6f --- /dev/null +++ b/lib/container-interop/container-interop/docs/ContainerInterface.md @@ -0,0 +1,158 @@ +Container interface +=================== + +This document describes a common interface for dependency injection containers. + +The goal set by `ContainerInterface` is to standardize how frameworks and libraries make use of a +container to obtain objects and parameters (called *entries* in the rest of this document). + +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", +"SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be +interpreted as described in [RFC 2119][]. + +The word `implementor` in this document is to be interpreted as someone +implementing the `ContainerInterface` in a dependency injection-related library or framework. +Users of dependency injections containers (DIC) are referred to as `user`. + +[RFC 2119]: http://tools.ietf.org/html/rfc2119 + +1. Specification +----------------- + +### 1.1 Basics + +- The `Interop\Container\ContainerInterface` exposes two methods : `get` and `has`. + +- `get` takes one mandatory parameter: an entry identifier. It MUST be a string. + A call to `get` can return anything (a *mixed* value), or throws an exception if the identifier + is not known to the container. Two successive calls to `get` with the same + identifier SHOULD return the same value. However, depending on the `implementor` + design and/or `user` configuration, different values might be returned, so + `user` SHOULD NOT rely on getting the same value on 2 successive calls. + While `ContainerInterface` only defines one mandatory parameter in `get()`, implementations + MAY accept additional optional parameters. + +- `has` takes one unique parameter: an entry identifier. It MUST return `true` + if an entry identifier is known to the container and `false` if it is not. + `has($id)` returning true does not mean that `get($id)` will not throw an exception. + It does however mean that `get($id)` will not throw a `NotFoundException`. + +### 1.2 Exceptions + +Exceptions directly thrown by the container MUST implement the +[`Interop\Container\Exception\ContainerException`](../src/Interop/Container/Exception/ContainerException.php). + +A call to the `get` method with a non-existing id SHOULD throw a +[`Interop\Container\Exception\NotFoundException`](../src/Interop/Container/Exception/NotFoundException.php). + +### 1.3 Additional features + +This section describes additional features that MAY be added to a container. Containers are not +required to implement these features to respect the ContainerInterface. + +#### 1.3.1 Delegate lookup feature + +The goal of the *delegate lookup* feature is to allow several containers to share entries. +Containers implementing this feature can perform dependency lookups in other containers. + +Containers implementing this feature will offer a greater lever of interoperability +with other containers. Implementation of this feature is therefore RECOMMENDED. + +A container implementing this feature: + +- MUST implement the `ContainerInterface` +- MUST provide a way to register a delegate container (using a constructor parameter, or a setter, + or any possible way). The delegate container MUST implement the `ContainerInterface`. + +When a container is configured to use a delegate container for dependencies: + +- Calls to the `get` method should only return an entry if the entry is part of the container. + If the entry is not part of the container, an exception should be thrown + (as requested by the `ContainerInterface`). +- Calls to the `has` method should only return `true` if the entry is part of the container. + If the entry is not part of the container, `false` should be returned. +- If the fetched entry has dependencies, **instead** of performing + the dependency lookup in the container, the lookup is performed on the *delegate container*. + +Important! By default, the lookup SHOULD be performed on the delegate container **only**, not on the container itself. + +It is however allowed for containers to provide exception cases for special entries, and a way to lookup +into the same container (or another container) instead of the delegate container. + +2. Package +---------- + +The interfaces and classes described as well as relevant exception are provided as part of the +[container-interop/container-interop](https://packagist.org/packages/container-interop/container-interop) package. + +3. `Interop\Container\ContainerInterface` +----------------------------------------- + +```php +setParentContainer($this); + } + } + ... + } +} + +``` + +**Cons:** + +Cons have been extensively discussed [here](https://github.com/container-interop/container-interop/pull/8#issuecomment-51721777). +Basically, forcing a setter into an interface is a bad idea. Setters are similar to constructor arguments, +and it's a bad idea to standardize a constructor: how the delegate container is configured into a container is an implementation detail. This outweights the benefits of the interface. + +### 4.4 Alternative: no exception case for delegate lookups + +Originally, the proposed wording for delegate lookup calls was: + +> Important! The lookup MUST be performed on the delegate container **only**, not on the container itself. + +This was later replaced by: + +> Important! By default, the lookup SHOULD be performed on the delegate container **only**, not on the container itself. +> +> It is however allowed for containers to provide exception cases for special entries, and a way to lookup +> into the same container (or another container) instead of the delegate container. + +Exception cases have been allowed to avoid breaking dependencies with some services that must be provided +by the container (on @njasm proposal). This was proposed here: https://github.com/container-interop/container-interop/pull/20#issuecomment-56597235 + +### 4.5 Alternative: having one of the containers act as the composite container + +In real-life scenarios, we usually have a big framework (Symfony 2, Zend Framework 2, etc...) and we want to +add another DI container to this container. Most of the time, the "big" framework will be responsible for +creating the controller's instances, using it's own DI container. Until *container-interop* is fully adopted, +the "big" framework will not be aware of the existence of a composite container that it should use instead +of its own container. + +For this real-life use cases, @mnapoli and @moufmouf proposed to extend the "big" framework's DI container +to make it act as a composite container. + +This has been discussed [here](https://github.com/container-interop/container-interop/pull/8#issuecomment-40367194) +and [here](http://mouf-php.com/container-interop-whats-next#solution4). + +This was implemented in Symfony 2 using: + +- [interop.symfony.di](https://github.com/thecodingmachine/interop.symfony.di/tree/v0.1.0) +- [framework interop](https://github.com/mnapoli/framework-interop/) + +This was implemented in Silex using: + +- [interop.silex.di](https://github.com/thecodingmachine/interop.silex.di) + +Having a container act as the composite container is not part of the delegate lookup standard because it is +simply a temporary design pattern used to make existing frameworks that do not support yet ContainerInterop +play nice with other DI containers. + + +5. Implementations +------------------ + +The following projects already implement the delegate lookup feature: + +- [Mouf](http://mouf-php.com), through the [`setDelegateLookupContainer` method](https://github.com/thecodingmachine/mouf/blob/2.0/src/Mouf/MoufManager.php#L2120) +- [PHP-DI](http://php-di.org/), through the [`$wrapperContainer` parameter of the constructor](https://github.com/mnapoli/PHP-DI/blob/master/src/DI/Container.php#L72) +- [pimple-interop](https://github.com/moufmouf/pimple-interop), through the [`$container` parameter of the constructor](https://github.com/moufmouf/pimple-interop/blob/master/src/Interop/Container/Pimple/PimpleInterop.php#L62) + +6. People +--------- + +Are listed here all people that contributed in the discussions, by alphabetical order: + +- [Alexandru Pătrănescu](https://github.com/drealecs) +- [Ben Peachey](https://github.com/potherca) +- [David Négrier](https://github.com/moufmouf) +- [Jeremy Lindblom](https://github.com/jeremeamia) +- [Marco Pivetta](https://github.com/Ocramius) +- [Matthieu Napoli](https://github.com/mnapoli) +- [Nelson J Morais](https://github.com/njasm) +- [Phil Sturgeon](https://github.com/philsturgeon) +- [Stephan Hochdörfer](https://github.com/shochdoerfer) + +7. Relevant Links +----------------- + +_**Note:** Order descending chronologically._ + +- [Pull request on the delegate lookup feature](https://github.com/container-interop/container-interop/pull/20) +- [Pull request on the interface idea](https://github.com/container-interop/container-interop/pull/8) +- [Original article exposing the delegate lookup idea along many others](http://mouf-php.com/container-interop-whats-next) + diff --git a/lib/container-interop/container-interop/docs/Delegate-lookup.md b/lib/container-interop/container-interop/docs/Delegate-lookup.md new file mode 100644 index 000000000..f64a8f785 --- /dev/null +++ b/lib/container-interop/container-interop/docs/Delegate-lookup.md @@ -0,0 +1,60 @@ +Delegate lookup feature +======================= + +This document describes a standard for dependency injection containers. + +The goal set by the *delegate lookup* feature is to allow several containers to share entries. +Containers implementing this feature can perform dependency lookups in other containers. + +Containers implementing this feature will offer a greater lever of interoperability +with other containers. Implementation of this feature is therefore RECOMMENDED. + +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", +"SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be +interpreted as described in [RFC 2119][]. + +The word `implementor` in this document is to be interpreted as someone +implementing the delegate lookup feature in a dependency injection-related library or framework. +Users of dependency injections containers (DIC) are referred to as `user`. + +[RFC 2119]: http://tools.ietf.org/html/rfc2119 + +1. Vocabulary +------------- + +In a dependency injection container, the container is used to fetch entries. +Entries can have dependencies on other entries. Usually, these other entries are fetched by the container. + +The *delegate lookup* feature is the ability for a container to fetch dependencies in +another container. In the rest of the document, the word "container" will reference the container +implemented by the implementor. The word "delegate container" will reference the container we are +fetching the dependencies from. + +2. Specification +---------------- + +A container implementing the *delegate lookup* feature: + +- MUST implement the [`ContainerInterface`](ContainerInterface.md) +- MUST provide a way to register a delegate container (using a constructor parameter, or a setter, + or any possible way). The delegate container MUST implement the [`ContainerInterface`](ContainerInterface.md). + +When a container is configured to use a delegate container for dependencies: + +- Calls to the `get` method should only return an entry if the entry is part of the container. + If the entry is not part of the container, an exception should be thrown + (as requested by the [`ContainerInterface`](ContainerInterface.md)). +- Calls to the `has` method should only return `true` if the entry is part of the container. + If the entry is not part of the container, `false` should be returned. +- If the fetched entry has dependencies, **instead** of performing + the dependency lookup in the container, the lookup is performed on the *delegate container*. + +Important: By default, the dependency lookups SHOULD be performed on the delegate container **only**, not on the container itself. + +It is however allowed for containers to provide exception cases for special entries, and a way to lookup +into the same container (or another container) instead of the delegate container. + +3. Package / Interface +---------------------- + +This feature is not tied to any code, interface or package. diff --git a/lib/container-interop/container-interop/docs/images/interoperating_containers.png b/lib/container-interop/container-interop/docs/images/interoperating_containers.png new file mode 100644 index 0000000000000000000000000000000000000000..1d3fdd0ddbea28d77c08cfb65834ec11357be5fb GIT binary patch literal 25738 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 lDg62tY5@ou6EsiaCMAN!E;xV!uGoVl#pK==5.3.0" + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + } +} diff --git a/lib/psr/http-message/src/MessageInterface.php b/lib/psr/http-message/src/MessageInterface.php new file mode 100644 index 000000000..dd46e5ec8 --- /dev/null +++ b/lib/psr/http-message/src/MessageInterface.php @@ -0,0 +1,187 @@ +getHeaders() as $name => $values) { + * echo $name . ": " . implode(", ", $values); + * } + * + * // Emit headers iteratively: + * foreach ($message->getHeaders() as $name => $values) { + * foreach ($values as $value) { + * header(sprintf('%s: %s', $name, $value), false); + * } + * } + * + * While header names are not case-sensitive, getHeaders() will preserve the + * exact case in which headers were originally specified. + * + * @return string[][] Returns an associative array of the message's headers. Each + * key MUST be a header name, and each value MUST be an array of strings + * for that header. + */ + public function getHeaders(); + + /** + * Checks if a header exists by the given case-insensitive name. + * + * @param string $name Case-insensitive header field name. + * @return bool Returns true if any header names match the given header + * name using a case-insensitive string comparison. Returns false if + * no matching header name is found in the message. + */ + public function hasHeader($name); + + /** + * Retrieves a message header value by the given case-insensitive name. + * + * This method returns an array of all the header values of the given + * case-insensitive header name. + * + * If the header does not appear in the message, this method MUST return an + * empty array. + * + * @param string $name Case-insensitive header field name. + * @return string[] An array of string values as provided for the given + * header. If the header does not appear in the message, this method MUST + * return an empty array. + */ + public function getHeader($name); + + /** + * Retrieves a comma-separated string of the values for a single header. + * + * This method returns all of the header values of the given + * case-insensitive header name as a string concatenated together using + * a comma. + * + * NOTE: Not all header values may be appropriately represented using + * comma concatenation. For such headers, use getHeader() instead + * and supply your own delimiter when concatenating. + * + * If the header does not appear in the message, this method MUST return + * an empty string. + * + * @param string $name Case-insensitive header field name. + * @return string A string of values as provided for the given header + * concatenated together using a comma. If the header does not appear in + * the message, this method MUST return an empty string. + */ + public function getHeaderLine($name); + + /** + * Return an instance with the provided value replacing the specified header. + * + * While header names are case-insensitive, the casing of the header will + * be preserved by this function, and returned from getHeaders(). + * + * This method MUST be implemented in such a way as to retain the + * immutability of the message, and MUST return an instance that has the + * new and/or updated header and value. + * + * @param string $name Case-insensitive header field name. + * @param string|string[] $value Header value(s). + * @return static + * @throws \InvalidArgumentException for invalid header names or values. + */ + public function withHeader($name, $value); + + /** + * Return an instance with the specified header appended with the given value. + * + * Existing values for the specified header will be maintained. The new + * value(s) will be appended to the existing list. If the header did not + * exist previously, it will be added. + * + * This method MUST be implemented in such a way as to retain the + * immutability of the message, and MUST return an instance that has the + * new header and/or value. + * + * @param string $name Case-insensitive header field name to add. + * @param string|string[] $value Header value(s). + * @return static + * @throws \InvalidArgumentException for invalid header names or values. + */ + public function withAddedHeader($name, $value); + + /** + * Return an instance without the specified header. + * + * Header resolution MUST be done without case-sensitivity. + * + * This method MUST be implemented in such a way as to retain the + * immutability of the message, and MUST return an instance that removes + * the named header. + * + * @param string $name Case-insensitive header field name to remove. + * @return static + */ + public function withoutHeader($name); + + /** + * Gets the body of the message. + * + * @return StreamInterface Returns the body as a stream. + */ + public function getBody(); + + /** + * Return an instance with the specified message body. + * + * The body MUST be a StreamInterface object. + * + * This method MUST be implemented in such a way as to retain the + * immutability of the message, and MUST return a new instance that has the + * new body stream. + * + * @param StreamInterface $body Body. + * @return static + * @throws \InvalidArgumentException When the body is not valid. + */ + public function withBody(StreamInterface $body); +} diff --git a/lib/psr/http-message/src/RequestInterface.php b/lib/psr/http-message/src/RequestInterface.php new file mode 100644 index 000000000..a96d4fd63 --- /dev/null +++ b/lib/psr/http-message/src/RequestInterface.php @@ -0,0 +1,129 @@ +getQuery()` + * or from the `QUERY_STRING` server param. + * + * @return array + */ + public function getQueryParams(); + + /** + * Return an instance with the specified query string arguments. + * + * These values SHOULD remain immutable over the course of the incoming + * request. They MAY be injected during instantiation, such as from PHP's + * $_GET superglobal, or MAY be derived from some other value such as the + * URI. In cases where the arguments are parsed from the URI, the data + * MUST be compatible with what PHP's parse_str() would return for + * purposes of how duplicate query parameters are handled, and how nested + * sets are handled. + * + * Setting query string arguments MUST NOT change the URI stored by the + * request, nor the values in the server params. + * + * This method MUST be implemented in such a way as to retain the + * immutability of the message, and MUST return an instance that has the + * updated query string arguments. + * + * @param array $query Array of query string arguments, typically from + * $_GET. + * @return static + */ + public function withQueryParams(array $query); + + /** + * Retrieve normalized file upload data. + * + * This method returns upload metadata in a normalized tree, with each leaf + * an instance of Psr\Http\Message\UploadedFileInterface. + * + * These values MAY be prepared from $_FILES or the message body during + * instantiation, or MAY be injected via withUploadedFiles(). + * + * @return array An array tree of UploadedFileInterface instances; an empty + * array MUST be returned if no data is present. + */ + public function getUploadedFiles(); + + /** + * Create a new instance with the specified uploaded files. + * + * This method MUST be implemented in such a way as to retain the + * immutability of the message, and MUST return an instance that has the + * updated body parameters. + * + * @param array $uploadedFiles An array tree of UploadedFileInterface instances. + * @return static + * @throws \InvalidArgumentException if an invalid structure is provided. + */ + public function withUploadedFiles(array $uploadedFiles); + + /** + * Retrieve any parameters provided in the request body. + * + * If the request Content-Type is either application/x-www-form-urlencoded + * or multipart/form-data, and the request method is POST, this method MUST + * return the contents of $_POST. + * + * Otherwise, this method may return any results of deserializing + * the request body content; as parsing returns structured content, the + * potential types MUST be arrays or objects only. A null value indicates + * the absence of body content. + * + * @return null|array|object The deserialized body parameters, if any. + * These will typically be an array or object. + */ + public function getParsedBody(); + + /** + * Return an instance with the specified body parameters. + * + * These MAY be injected during instantiation. + * + * If the request Content-Type is either application/x-www-form-urlencoded + * or multipart/form-data, and the request method is POST, use this method + * ONLY to inject the contents of $_POST. + * + * The data IS NOT REQUIRED to come from $_POST, but MUST be the results of + * deserializing the request body content. Deserialization/parsing returns + * structured data, and, as such, this method ONLY accepts arrays or objects, + * or a null value if nothing was available to parse. + * + * As an example, if content negotiation determines that the request data + * is a JSON payload, this method could be used to create a request + * instance with the deserialized parameters. + * + * This method MUST be implemented in such a way as to retain the + * immutability of the message, and MUST return an instance that has the + * updated body parameters. + * + * @param null|array|object $data The deserialized body data. This will + * typically be in an array or object. + * @return static + * @throws \InvalidArgumentException if an unsupported argument type is + * provided. + */ + public function withParsedBody($data); + + /** + * Retrieve attributes derived from the request. + * + * The request "attributes" may be used to allow injection of any + * parameters derived from the request: e.g., the results of path + * match operations; the results of decrypting cookies; the results of + * deserializing non-form-encoded message bodies; etc. Attributes + * will be application and request specific, and CAN be mutable. + * + * @return array Attributes derived from the request. + */ + public function getAttributes(); + + /** + * Retrieve a single derived request attribute. + * + * Retrieves a single derived request attribute as described in + * getAttributes(). If the attribute has not been previously set, returns + * the default value as provided. + * + * This method obviates the need for a hasAttribute() method, as it allows + * specifying a default value to return if the attribute is not found. + * + * @see getAttributes() + * @param string $name The attribute name. + * @param mixed $default Default value to return if the attribute does not exist. + * @return mixed + */ + public function getAttribute($name, $default = null); + + /** + * Return an instance with the specified derived request attribute. + * + * This method allows setting a single derived request attribute as + * described in getAttributes(). + * + * This method MUST be implemented in such a way as to retain the + * immutability of the message, and MUST return an instance that has the + * updated attribute. + * + * @see getAttributes() + * @param string $name The attribute name. + * @param mixed $value The value of the attribute. + * @return static + */ + public function withAttribute($name, $value); + + /** + * Return an instance that removes the specified derived request attribute. + * + * This method allows removing a single derived request attribute as + * described in getAttributes(). + * + * This method MUST be implemented in such a way as to retain the + * immutability of the message, and MUST return an instance that removes + * the attribute. + * + * @see getAttributes() + * @param string $name The attribute name. + * @return static + */ + public function withoutAttribute($name); +} diff --git a/lib/psr/http-message/src/StreamInterface.php b/lib/psr/http-message/src/StreamInterface.php new file mode 100644 index 000000000..f68f39126 --- /dev/null +++ b/lib/psr/http-message/src/StreamInterface.php @@ -0,0 +1,158 @@ + + * [user-info@]host[:port] + * + * + * If the port component is not set or is the standard port for the current + * scheme, it SHOULD NOT be included. + * + * @see https://tools.ietf.org/html/rfc3986#section-3.2 + * @return string The URI authority, in "[user-info@]host[:port]" format. + */ + public function getAuthority(); + + /** + * Retrieve the user information component of the URI. + * + * If no user information is present, this method MUST return an empty + * string. + * + * If a user is present in the URI, this will return that value; + * additionally, if the password is also present, it will be appended to the + * user value, with a colon (":") separating the values. + * + * The trailing "@" character is not part of the user information and MUST + * NOT be added. + * + * @return string The URI user information, in "username[:password]" format. + */ + public function getUserInfo(); + + /** + * Retrieve the host component of the URI. + * + * If no host is present, this method MUST return an empty string. + * + * The value returned MUST be normalized to lowercase, per RFC 3986 + * Section 3.2.2. + * + * @see http://tools.ietf.org/html/rfc3986#section-3.2.2 + * @return string The URI host. + */ + public function getHost(); + + /** + * Retrieve the port component of the URI. + * + * If a port is present, and it is non-standard for the current scheme, + * this method MUST return it as an integer. If the port is the standard port + * used with the current scheme, this method SHOULD return null. + * + * If no port is present, and no scheme is present, this method MUST return + * a null value. + * + * If no port is present, but a scheme is present, this method MAY return + * the standard port for that scheme, but SHOULD return null. + * + * @return null|int The URI port. + */ + public function getPort(); + + /** + * Retrieve the path component of the URI. + * + * The path can either be empty or absolute (starting with a slash) or + * rootless (not starting with a slash). Implementations MUST support all + * three syntaxes. + * + * Normally, the empty path "" and absolute path "/" are considered equal as + * defined in RFC 7230 Section 2.7.3. But this method MUST NOT automatically + * do this normalization because in contexts with a trimmed base path, e.g. + * the front controller, this difference becomes significant. It's the task + * of the user to handle both "" and "/". + * + * The value returned MUST be percent-encoded, but MUST NOT double-encode + * any characters. To determine what characters to encode, please refer to + * RFC 3986, Sections 2 and 3.3. + * + * As an example, if the value should include a slash ("/") not intended as + * delimiter between path segments, that value MUST be passed in encoded + * form (e.g., "%2F") to the instance. + * + * @see https://tools.ietf.org/html/rfc3986#section-2 + * @see https://tools.ietf.org/html/rfc3986#section-3.3 + * @return string The URI path. + */ + public function getPath(); + + /** + * Retrieve the query string of the URI. + * + * If no query string is present, this method MUST return an empty string. + * + * The leading "?" character is not part of the query and MUST NOT be + * added. + * + * The value returned MUST be percent-encoded, but MUST NOT double-encode + * any characters. To determine what characters to encode, please refer to + * RFC 3986, Sections 2 and 3.4. + * + * As an example, if a value in a key/value pair of the query string should + * include an ampersand ("&") not intended as a delimiter between values, + * that value MUST be passed in encoded form (e.g., "%26") to the instance. + * + * @see https://tools.ietf.org/html/rfc3986#section-2 + * @see https://tools.ietf.org/html/rfc3986#section-3.4 + * @return string The URI query string. + */ + public function getQuery(); + + /** + * Retrieve the fragment component of the URI. + * + * If no fragment is present, this method MUST return an empty string. + * + * The leading "#" character is not part of the fragment and MUST NOT be + * added. + * + * The value returned MUST be percent-encoded, but MUST NOT double-encode + * any characters. To determine what characters to encode, please refer to + * RFC 3986, Sections 2 and 3.5. + * + * @see https://tools.ietf.org/html/rfc3986#section-2 + * @see https://tools.ietf.org/html/rfc3986#section-3.5 + * @return string The URI fragment. + */ + public function getFragment(); + + /** + * Return an instance with the specified scheme. + * + * This method MUST retain the state of the current instance, and return + * an instance that contains the specified scheme. + * + * Implementations MUST support the schemes "http" and "https" case + * insensitively, and MAY accommodate other schemes if required. + * + * An empty scheme is equivalent to removing the scheme. + * + * @param string $scheme The scheme to use with the new instance. + * @return static A new instance with the specified scheme. + * @throws \InvalidArgumentException for invalid or unsupported schemes. + */ + public function withScheme($scheme); + + /** + * Return an instance with the specified user information. + * + * This method MUST retain the state of the current instance, and return + * an instance that contains the specified user information. + * + * Password is optional, but the user information MUST include the + * user; an empty string for the user is equivalent to removing user + * information. + * + * @param string $user The user name to use for authority. + * @param null|string $password The password associated with $user. + * @return static A new instance with the specified user information. + */ + public function withUserInfo($user, $password = null); + + /** + * Return an instance with the specified host. + * + * This method MUST retain the state of the current instance, and return + * an instance that contains the specified host. + * + * An empty host value is equivalent to removing the host. + * + * @param string $host The hostname to use with the new instance. + * @return static A new instance with the specified host. + * @throws \InvalidArgumentException for invalid hostnames. + */ + public function withHost($host); + + /** + * Return an instance with the specified port. + * + * This method MUST retain the state of the current instance, and return + * an instance that contains the specified port. + * + * Implementations MUST raise an exception for ports outside the + * established TCP and UDP port ranges. + * + * A null value provided for the port is equivalent to removing the port + * information. + * + * @param null|int $port The port to use with the new instance; a null value + * removes the port information. + * @return static A new instance with the specified port. + * @throws \InvalidArgumentException for invalid ports. + */ + public function withPort($port); + + /** + * Return an instance with the specified path. + * + * This method MUST retain the state of the current instance, and return + * an instance that contains the specified path. + * + * The path can either be empty or absolute (starting with a slash) or + * rootless (not starting with a slash). Implementations MUST support all + * three syntaxes. + * + * If the path is intended to be domain-relative rather than path relative then + * it must begin with a slash ("/"). Paths not starting with a slash ("/") + * are assumed to be relative to some base path known to the application or + * consumer. + * + * Users can provide both encoded and decoded path characters. + * Implementations ensure the correct encoding as outlined in getPath(). + * + * @param string $path The path to use with the new instance. + * @return static A new instance with the specified path. + * @throws \InvalidArgumentException for invalid paths. + */ + public function withPath($path); + + /** + * Return an instance with the specified query string. + * + * This method MUST retain the state of the current instance, and return + * an instance that contains the specified query string. + * + * Users can provide both encoded and decoded query characters. + * Implementations ensure the correct encoding as outlined in getQuery(). + * + * An empty query string value is equivalent to removing the query string. + * + * @param string $query The query string to use with the new instance. + * @return static A new instance with the specified query string. + * @throws \InvalidArgumentException for invalid query strings. + */ + public function withQuery($query); + + /** + * Return an instance with the specified URI fragment. + * + * This method MUST retain the state of the current instance, and return + * an instance that contains the specified URI fragment. + * + * Users can provide both encoded and decoded fragment characters. + * Implementations ensure the correct encoding as outlined in getFragment(). + * + * An empty fragment value is equivalent to removing the fragment. + * + * @param string $fragment The fragment to use with the new instance. + * @return static A new instance with the specified fragment. + */ + public function withFragment($fragment); + + /** + * Return the string representation as a URI reference. + * + * Depending on which components of the URI are present, the resulting + * string is either a full URI or relative reference according to RFC 3986, + * Section 4.1. The method concatenates the various components of the URI, + * using the appropriate delimiters: + * + * - If a scheme is present, it MUST be suffixed by ":". + * - If an authority is present, it MUST be prefixed by "//". + * - The path can be concatenated without delimiters. But there are two + * cases where the path has to be adjusted to make the URI reference + * valid as PHP does not allow to throw an exception in __toString(): + * - If the path is rootless and an authority is present, the path MUST + * be prefixed by "/". + * - If the path is starting with more than one "/" and no authority is + * present, the starting slashes MUST be reduced to one. + * - If a query is present, it MUST be prefixed by "?". + * - If a fragment is present, it MUST be prefixed by "#". + * + * @see http://tools.ietf.org/html/rfc3986#section-4.1 + * @return string + */ + public function __toString(); +}