Skip to content

PSR-7 Implementation #3941

New issue

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

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

Already on GitHub? Sign in to your account

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions admin/framework/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"ext-mbstring": "*",
"kint-php/kint": "^3.3",
"laminas/laminas-escaper": "^2.6",
"psr/http-message": "^1.0",
"psr/log": "^1.1"
},
"require-dev": {
Expand Down
3 changes: 3 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"ext-mbstring": "*",
"kint-php/kint": "^3.3",
"laminas/laminas-escaper": "^2.6",
"psr/http-message": "^1.0",
"psr/log": "^1.1"
},
"require-dev": {
Expand All @@ -21,6 +22,8 @@
"phpstan/phpstan": "^0.12",
"phpunit/phpunit": "^8.5",
"predis/predis": "^1.1",
"php-http/psr7-integration-tests": "^1.0",
"psr/http-factory": "^1.0",
"rector/rector": "^0.8",
"squizlabs/php_codesniffer": "^3.3"
},
Expand Down
2 changes: 0 additions & 2 deletions phpstan.neon.dist
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,10 @@ parameters:
- '#Access to an undefined property CodeIgniter\\Database\\Forge::\$dropConstraintStr#'
- '#Access to an undefined property CodeIgniter\\Database\\BaseConnection::\$mysqli|\$schema#'
- '#Access to an undefined property CodeIgniter\\Database\\ConnectionInterface::(\$DBDriver|\$connID|\$likeEscapeStr|\$likeEscapeChar|\$escapeChar|\$protectIdentifiers|\$schema)#'
- '#Access to an undefined property CodeIgniter\\HTTP\\Request::\$uri#'
- '#Access to protected property CodeIgniter\\Database\\BaseConnection::(\$DBDebug|\$DBPrefix|\$swapPre|\$charset|\$DBCollat|\$database)#'
- '#Call to an undefined method CodeIgniter\\Database\\BaseConnection::_(disable|enable)ForeignKeyChecks\(\)#'
- '#Call to an undefined method CodeIgniter\\Database\\BaseConnection::supportsForeignKeys\(\)#'
- '#Call to an undefined method CodeIgniter\\Database\\ConnectionInterface::(tableExists|protectIdentifiers|setAliasedTables|escapeIdentifiers|affectedRows|addTableAlias|getIndexData)\(\)#'
- '#Call to an undefined method CodeIgniter\\HTTP\\Request::(getPath|getSegments|getMethod|setLocale|getPost)\(\)#'
- '#Call to an undefined method CodeIgniter\\Router\\RouteCollectionInterface::(getDefaultNamespace|isFiltered|getFilterForRoute|getRoutesOptions)\(\)#'
- '#Cannot access property [\$a-z_]+ on ((bool\|)?object\|resource)#'
- '#Cannot call method [a-zA-Z_]+\(\) on ((bool\|)?object\|resource)#'
Expand Down
3 changes: 3 additions & 0 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@
<php>
<server name="app.baseURL" value="http://example.com/"/>

<!-- PSR-17 UriFactory for PSR-7 integration tests -->
<const name="URI_FACTORY" value="CodeIgniter\HTTP\UriFactory"/>

<!-- Directory containing phpunit.xml -->
<const name="HOMEPATH" value="./"/>

Expand Down
2 changes: 1 addition & 1 deletion system/CLI/CLI.php
Original file line number Diff line number Diff line change
Expand Up @@ -869,7 +869,7 @@ public static function wrap(string $string = null, int $max = 0, int $padLeft =
*/
protected static function parseCommandLine()
{
$args = $_SERVER['argv'];
$args = $_SERVER['argv'] ?? [];
array_shift($args); // scrap invoking program
$optionValue = false;

Expand Down
28 changes: 11 additions & 17 deletions system/CodeIgniter.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ class CodeIgniter
/**
* Main application configuration
*
* @var \Config\App
* @var App
*/
protected $config;

Expand All @@ -76,7 +76,7 @@ class CodeIgniter
/**
* Current request.
*
* @var HTTP\Request|HTTP\IncomingRequest|CLIRequest
* @var Request|HTTP\IncomingRequest|CLIRequest
*/
protected $request;

Expand Down Expand Up @@ -395,7 +395,7 @@ protected function handleRequest(RouteCollectionInterface $routes = null, Cache
$filters->enableFilter($routeFilter, 'after');
}

$uri = $this->request instanceof CLIRequest ? $this->request->getPath() : $this->request->uri->getPath();
$uri = $this->request instanceof CLIRequest ? $this->request->getPath() : $this->request->getUri()->getPath();

// Never run filters when running through Spark cli
if (! defined('SPARKED'))
Expand Down Expand Up @@ -714,9 +714,7 @@ public function cachePage(Cache $config)
$headers[$header->getName()] = $header->getValueLine();
}

return cache()->save(
$this->generateCacheName($config), serialize(['headers' => $headers, 'output' => $this->output]), static::$cacheTTL
);
return cache()->save($this->generateCacheName($config), serialize(['headers' => $headers, 'output' => $this->output]), static::$cacheTTL);
}

//--------------------------------------------------------------------
Expand Down Expand Up @@ -745,24 +743,20 @@ public function getPerformanceStats(): array
*/
protected function generateCacheName(Cache $config): string
{
if (get_class($this->request) === CLIRequest::class)
if ($this->request instanceof CLIRequest)
{
return md5($this->request->getPath());
}

$uri = $this->request->uri;
$uri = $this->request->getUri();

if ($config->cacheQueryString)
{
$name = URI::createURIString(
$uri->getScheme(), $uri->getAuthority(), $uri->getPath(), $uri->getQuery()
);
$name = URI::createURIString($uri->getScheme(), $uri->getAuthority(), $uri->getPath(), $uri->getQuery());
}
else
{
$name = URI::createURIString(
$uri->getScheme(), $uri->getAuthority(), $uri->getPath()
);
$name = URI::createURIString($uri->getScheme(), $uri->getAuthority(), $uri->getPath());
}

return md5($name);
Expand Down Expand Up @@ -821,7 +815,7 @@ protected function tryToRouteIt(RouteCollectionInterface $routes = null)
// then we need to set the correct locale on our Request.
if ($this->router->hasLocale())
{
$this->request->setLocale($this->router->getLocale());
$this->request->setLocale($this->router->getLocale()); // @phpstan-ignore-line
}

$this->benchmark->stop('routing');
Expand Down Expand Up @@ -926,7 +920,7 @@ protected function createController()
protected function runController($class)
{
// If this is a console request then use the input segments as parameters
$params = defined('SPARKED') ? $this->request->getSegments() : $this->router->params();
$params = defined('SPARKED') ? $this->request->getSegments() : $this->router->params(); // @phpstan-ignore-line

if (method_exists($class, '_remap'))
{
Expand Down Expand Up @@ -1107,7 +1101,7 @@ public function spoofRequestMethod()
return;
}

$method = $this->request->getPost('_method');
$method = $this->request->getPost('_method'); // @phpstan-ignore-line

if (empty($method))
{
Expand Down
25 changes: 16 additions & 9 deletions system/Config/AutoloadConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -81,15 +81,22 @@ class AutoloadConfig
* @var array
*/
protected $coreClassmap = [
'Psr\Log\AbstractLogger' => SYSTEMPATH . 'ThirdParty/PSR/Log/AbstractLogger.php',
'Psr\Log\InvalidArgumentException' => SYSTEMPATH . 'ThirdParty/PSR/Log/InvalidArgumentException.php',
'Psr\Log\LoggerAwareInterface' => SYSTEMPATH . 'ThirdParty/PSR/Log/LoggerAwareInterface.php',
'Psr\Log\LoggerAwareTrait' => SYSTEMPATH . 'ThirdParty/PSR/Log/LoggerAwareTrait.php',
'Psr\Log\LoggerInterface' => SYSTEMPATH . 'ThirdParty/PSR/Log/LoggerInterface.php',
'Psr\Log\LoggerTrait' => SYSTEMPATH . 'ThirdParty/PSR/Log/LoggerTrait.php',
'Psr\Log\LogLevel' => SYSTEMPATH . 'ThirdParty/PSR/Log/LogLevel.php',
'Psr\Log\NullLogger' => SYSTEMPATH . 'ThirdParty/PSR/Log/NullLogger.php',
'Laminas\Escaper\Escaper' => SYSTEMPATH . 'ThirdParty/Escaper/Escaper.php',
'Psr\Http\Message\MessageInterface' => SYSTEMPATH . 'ThirdParty/PSR/Http/Message/MessageInterface.php',
'Psr\Http\Message\RequestInterface' => SYSTEMPATH . 'ThirdParty/PSR/Http/Message/RequestInterface.php',
'Psr\Http\Message\ResponseInterface' => SYSTEMPATH . 'ThirdParty/PSR/Http/Message/ResponseInterface.php',
'Psr\Http\Message\ServerRequestInterface' => SYSTEMPATH . 'ThirdParty/PSR/Http/Message/ServerRequestInterface.php',
'Psr\Http\Message\StreamInterface' => SYSTEMPATH . 'ThirdParty/PSR/Http/Message/StreamInterface.php',
'Psr\Http\Message\UploadedFileInterface' => SYSTEMPATH . 'ThirdParty/PSR/Http/Message/UploadedFileInterface.php',
'Psr\Http\Message\UriInterface' => SYSTEMPATH . 'ThirdParty/PSR/Http/Message/UriInterface.php',
'Psr\Log\AbstractLogger' => SYSTEMPATH . 'ThirdParty/PSR/Log/AbstractLogger.php',
'Psr\Log\InvalidArgumentException' => SYSTEMPATH . 'ThirdParty/PSR/Log/InvalidArgumentException.php',
'Psr\Log\LoggerAwareInterface' => SYSTEMPATH . 'ThirdParty/PSR/Log/LoggerAwareInterface.php',
'Psr\Log\LoggerAwareTrait' => SYSTEMPATH . 'ThirdParty/PSR/Log/LoggerAwareTrait.php',
'Psr\Log\LoggerInterface' => SYSTEMPATH . 'ThirdParty/PSR/Log/LoggerInterface.php',
'Psr\Log\LoggerTrait' => SYSTEMPATH . 'ThirdParty/PSR/Log/LoggerTrait.php',
'Psr\Log\LogLevel' => SYSTEMPATH . 'ThirdParty/PSR/Log/LogLevel.php',
'Psr\Log\NullLogger' => SYSTEMPATH . 'ThirdParty/PSR/Log/NullLogger.php',
'Laminas\Escaper\Escaper' => SYSTEMPATH . 'ThirdParty/Escaper/Escaper.php',
];

//--------------------------------------------------------------------
Expand Down
11 changes: 11 additions & 0 deletions system/HTTP/IncomingRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use CodeIgniter\HTTP\Exceptions\HTTPException;
use CodeIgniter\HTTP\Files\FileCollection;
use CodeIgniter\HTTP\Files\UploadedFile;
use CodeIgniter\HTTP\Request;
use Config\App;
use Config\Services;
use Locale;
Expand Down Expand Up @@ -548,6 +549,16 @@ public function getFile(string $fileID)

//--------------------------------------------------------------------

/**
* Retrieves the URI instance.
*
* @return URI
*/
public function getUri()
{
return $this->uri;
}

/**
* Sets up our URI object based on the information we have. This is
* either provided by the user in the baseURL Config setting, or
Expand Down
121 changes: 105 additions & 16 deletions system/HTTP/Message.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@
namespace CodeIgniter\HTTP;

use CodeIgniter\HTTP\Exceptions\HTTPException;
use CodeIgniter\HTTP\Header;
use Psr\Http\Message\MessageInterface;

/**
* An HTTP message
*/
class Message
class Message implements MessageInterface
{
/**
* List of all HTTP request headers.
Expand Down Expand Up @@ -87,6 +89,20 @@ public function setBody($data): self
return $this;
}

/**
* Returns a new instance with the specified body.
*
* @param mixed $data
*
* @return static
*/
public function withBody($data): self
{
$clone = clone $this;

return $clone->setBody($data);
}

/**
* Appends data to the body of the current message.
*
Expand Down Expand Up @@ -174,28 +190,42 @@ public function header($name)
/**
* Returns an array containing all headers.
*
* @return array<string,Header> An array of the request headers
*
* @deprecated Use Message::headers() to make room for PSR-7
* @return array<string,string[]> An array of the request header valuess
*/
public function getHeaders(): array
{
return $this->headers();
$return = [];

foreach ($this->headers() as $name => $header)
{
$return[$header->getName()] = $header->getValue();
}

return $return;
}

/**
* Returns a single header object. If multiple headers with the same
* name exist, then will return an array of header objects.
* Retrieves a message header value by the given case-insensitive name.
*
* @param string $name
* This method returns an array of all the header values of the given
* case-insensitive header name.
*
* @return array|Header|null
* If the header does not appear in the message, this method MUST return an
* empty array.
*
* @deprecated Use Message::header() to make room for PSR-7
* @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(string $name)
public function getHeader($name)
{
return $this->header($name);
if (! $header = $this->header($name))
{
return [];
}

return is_string($value = $header->getValue()) ? [$value] : $value;
}

/**
Expand All @@ -205,7 +235,7 @@ public function getHeader(string $name)
*
* @return boolean
*/
public function hasHeader(string $name): bool
public function hasHeader($name)
{
$origName = $this->getHeaderName($name);

Expand All @@ -227,7 +257,7 @@ public function hasHeader(string $name): bool
*
* @return string
*/
public function getHeaderLine(string $name): string
public function getHeaderLine($name)
{
$origName = $this->getHeaderName($name);

Expand Down Expand Up @@ -272,6 +302,50 @@ public function setHeader(string $name, $value): self
return $this;
}

/**
* Return a new instance with the specified header.
*
* @param string $name
* @param array|null|string $value
*
* @return static
*/
public function withHeader($name, $value): self
{
$clone = clone $this;

return $clone->setHeader($name, $value);
}

/**
* Return a new instance with the additional specified header.
*
* @param string $name
* @param array|null|string $value
*
* @return static
*/
public function withAddedHeader($name, $value): self
{
$clone = clone $this;

return $clone->appendHeader($name, $value);
}

/**
* Return a new instance without the specified header.
*
* @param string $name
*
* @return static
*/
public function withoutHeader($name): self
{
$clone = clone $this;

return $clone->removeHeader($name);
}

/**
* Removes a header from the list of headers we track.
*
Expand Down Expand Up @@ -377,14 +451,29 @@ public function setProtocolVersion(string $version): self
return $this;
}

/**
* Return a new instance with the specified HTTP protocol version.
*
* @param string $version
*
* @return static
*
* @throws HTTPException For an invalid protocol version
*/
public function withProtocolVersion($version)
{
$clone = clone $this;

return $clone->setProtocolVersion($version);
}

/**
* Determines if this is a json message based on the Content-Type header
*
* @return boolean
*/
public function isJSON()
{
return $this->hasHeader('Content-Type')
&& $this->header('Content-Type')->getValue() === 'application/json';
return $this->hasHeader('Content-Type') && $this->header('Content-Type')->getValue() === 'application/json';
}
}
Loading