Skip to content

Commit 03beb30

Browse files
authored
Merge pull request #3563 from paulbalandan/format-new
Refactor Format class
2 parents 8c90aa0 + 2fb987f commit 03beb30

File tree

15 files changed

+417
-166
lines changed

15 files changed

+417
-166
lines changed

app/Config/Format.php

Lines changed: 45 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,59 @@
1-
<?php namespace Config;
1+
<?php
2+
3+
namespace Config;
24

35
use CodeIgniter\Config\BaseConfig;
46

57
class Format extends BaseConfig
68
{
7-
/*
8-
|--------------------------------------------------------------------------
9-
| Available Response Formats
10-
|--------------------------------------------------------------------------
11-
|
12-
| When you perform content negotiation with the request, these are the
13-
| available formats that your application supports. This is currently
14-
| only used with the API\ResponseTrait. A valid Formatter must exist
15-
| for the specified format.
16-
|
17-
| These formats are only checked when the data passed to the respond()
18-
| method is an array.
19-
|
20-
*/
9+
/**
10+
* --------------------------------------------------------------------------
11+
* Available Response Formats
12+
* --------------------------------------------------------------------------
13+
*
14+
* When you perform content negotiation with the request, these are the
15+
* available formats that your application supports. This is currently
16+
* only used with the API\ResponseTrait. A valid Formatter must exist
17+
* for the specified format.
18+
*
19+
* These formats are only checked when the data passed to the respond()
20+
* method is an array.
21+
*
22+
* @var string[]
23+
*/
2124
public $supportedResponseFormats = [
2225
'application/json',
2326
'application/xml', // machine-readable XML
2427
'text/xml', // human-readable XML
2528
];
2629

27-
/*
28-
|--------------------------------------------------------------------------
29-
| Formatters
30-
|--------------------------------------------------------------------------
31-
|
32-
| Lists the class to use to format responses with of a particular type.
33-
| For each mime type, list the class that should be used. Formatters
34-
| can be retrieved through the getFormatter() method.
35-
|
36-
*/
30+
/**
31+
* --------------------------------------------------------------------------
32+
* Formatters
33+
* --------------------------------------------------------------------------
34+
*
35+
* Lists the class to use to format responses with of a particular type.
36+
* For each mime type, list the class that should be used. Formatters
37+
* can be retrieved through the getFormatter() method.
38+
*
39+
* @var array<string, string>
40+
*/
3741
public $formatters = [
38-
'application/json' => \CodeIgniter\Format\JSONFormatter::class,
39-
'application/xml' => \CodeIgniter\Format\XMLFormatter::class,
40-
'text/xml' => \CodeIgniter\Format\XMLFormatter::class,
42+
'application/json' => 'CodeIgniter\Format\JSONFormatter',
43+
'application/xml' => 'CodeIgniter\Format\XMLFormatter',
44+
'text/xml' => 'CodeIgniter\Format\XMLFormatter',
4145
];
4246

43-
/*
44-
|--------------------------------------------------------------------------
45-
| Formatters Options
46-
|--------------------------------------------------------------------------
47-
|
48-
| Additional Options to adjust default formatters behaviour.
49-
| For each mime type, list the additional options that should be used.
50-
|
51-
*/
47+
/**
48+
* --------------------------------------------------------------------------
49+
* Formatters Options
50+
* --------------------------------------------------------------------------
51+
*
52+
* Additional Options to adjust default formatters behaviour.
53+
* For each mime type, list the additional options that should be used.
54+
*
55+
* @var array<string, int>
56+
*/
5257
public $formatterOptions = [
5358
'application/json' => JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES,
5459
'application/xml' => 0,
@@ -63,24 +68,11 @@ class Format extends BaseConfig
6368
* @param string $mime
6469
*
6570
* @return \CodeIgniter\Format\FormatterInterface
71+
*
72+
* @deprecated This is an alias of `\CodeIgniter\Format\Format::getFormatter`. Use that instead.
6673
*/
6774
public function getFormatter(string $mime)
6875
{
69-
if (! array_key_exists($mime, $this->formatters))
70-
{
71-
throw new \InvalidArgumentException('No Formatter defined for mime type: ' . $mime);
72-
}
73-
74-
$class = $this->formatters[$mime];
75-
76-
if (! class_exists($class))
77-
{
78-
throw new \BadMethodCallException($class . ' is not a valid Formatter.');
79-
}
80-
81-
return new $class();
76+
return Services::format()->getFormatter($mime);
8277
}
83-
84-
//--------------------------------------------------------------------
85-
8678
}

system/API/ResponseTrait.php

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
namespace CodeIgniter\API;
4141

4242
use CodeIgniter\HTTP\Response;
43-
use Config\Format;
43+
use Config\Services;
4444

4545
/**
4646
* Response trait.
@@ -102,6 +102,13 @@ trait ResponseTrait
102102
*/
103103
protected $format = 'json';
104104

105+
/**
106+
* Current Formatter instance. This is usually set by ResponseTrait::format
107+
*
108+
* @var \CodeIgniter\Format\FormatterInterface
109+
*/
110+
protected $formatter;
111+
105112
//--------------------------------------------------------------------
106113

107114
/**
@@ -123,7 +130,8 @@ public function respond($data = null, int $status = null, string $message = '')
123130

124131
// Create the output var here in case of $this->response([]);
125132
$output = null;
126-
} // If data is null but status provided, keep the output empty.
133+
}
134+
// If data is null but status provided, keep the output empty.
127135
elseif ($data === null && is_numeric($status))
128136
{
129137
$output = null;
@@ -134,8 +142,7 @@ public function respond($data = null, int $status = null, string $message = '')
134142
$output = $this->format($data);
135143
}
136144

137-
return $this->response->setBody($output)
138-
->setStatusCode($status, $message);
145+
return $this->response->setBody($output)->setStatusCode($status, $message);
139146
}
140147

141148
//--------------------------------------------------------------------
@@ -159,7 +166,7 @@ public function fail($messages, int $status = 400, string $code = null, string $
159166

160167
$response = [
161168
'status' => $status,
162-
'error' => $code === null ? $status : $code,
169+
'error' => $code ?? $status,
163170
'messages' => $messages,
164171
];
165172

@@ -386,25 +393,25 @@ protected function format($data = null)
386393
return $data;
387394
}
388395

389-
$config = new Format();
390-
$format = "application/$this->format";
396+
$format = Services::format();
397+
$mime = "application/{$this->format}";
391398

392399
// Determine correct response type through content negotiation if not explicitly declared
393400
if (empty($this->format) || ! in_array($this->format, ['json', 'xml'], true))
394401
{
395-
$format = $this->request->negotiate('media', $config->supportedResponseFormats, false);
402+
$mime = $this->request->negotiate('media', $format->getConfig()->supportedResponseFormats, false);
396403
}
397404

398-
$this->response->setContentType($format);
405+
$this->response->setContentType($mime);
399406

400407
// if we don't have a formatter, make one
401408
if (! isset($this->formatter))
402409
{
403410
// if no formatter, use the default
404-
$this->formatter = $config->getFormatter($format); // @phpstan-ignore-line
411+
$this->formatter = $format->getFormatter($mime);
405412
}
406413

407-
if ($format !== 'application/json')
414+
if ($mime !== 'application/json')
408415
{
409416
// Recursively convert objects into associative arrays
410417
// Conversion not required for JSONFormatter

system/Config/Services.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
use CodeIgniter\Encryption\EncrypterInterface;
5252
use CodeIgniter\Encryption\Encryption;
5353
use CodeIgniter\Filters\Filters;
54+
use CodeIgniter\Format\Format;
5455
use CodeIgniter\Honeypot\Honeypot;
5556
use CodeIgniter\HTTP\CLIRequest;
5657
use CodeIgniter\HTTP\CURLRequest;
@@ -83,6 +84,7 @@
8384
use Config\Email as EmailConfig;
8485
use Config\Encryption as EncryptionConfig;
8586
use Config\Exceptions as ExceptionsConfig;
87+
use Config\Format as FormatConfig;
8688
use Config\Filters as FiltersConfig;
8789
use Config\Honeypot as HoneypotConfig;
8890
use Config\Images;
@@ -311,6 +313,28 @@ public static function filters(FiltersConfig $config = null, bool $getShared = t
311313

312314
//--------------------------------------------------------------------
313315

316+
/**
317+
* The Format class is a convenient place to create Formatters.
318+
*
319+
* @param \Config\Format|null $config
320+
* @param boolean $getShared
321+
*
322+
* @return \CodeIgniter\Format\Format
323+
*/
324+
public static function format(FormatConfig $config = null, bool $getShared = true)
325+
{
326+
if ($getShared)
327+
{
328+
return static::getSharedInstance('format', $config);
329+
}
330+
331+
$config = $config ?? config('Format');
332+
333+
return new Format($config);
334+
}
335+
336+
//--------------------------------------------------------------------
337+
314338
/**
315339
* The Honeypot provides a secret input on forms that bots should NOT
316340
* fill in, providing an additional safeguard when accepting user input.
Lines changed: 82 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,100 @@
1-
<?php namespace CodeIgniter\Format\Exceptions;
1+
<?php
2+
3+
/**
4+
* CodeIgniter
5+
*
6+
* An open source application development framework for PHP
7+
*
8+
* This content is released under the MIT License (MIT)
9+
*
10+
* Copyright (c) 2014-2019 British Columbia Institute of Technology
11+
* Copyright (c) 2019-2020 CodeIgniter Foundation
12+
*
13+
* Permission is hereby granted, free of charge, to any person obtaining a copy
14+
* of this software and associated documentation files (the "Software"), to deal
15+
* in the Software without restriction, including without limitation the rights
16+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17+
* copies of the Software, and to permit persons to whom the Software is
18+
* furnished to do so, subject to the following conditions:
19+
*
20+
* The above copyright notice and this permission notice shall be included in
21+
* all copies or substantial portions of the Software.
22+
*
23+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29+
* THE SOFTWARE.
30+
*
31+
* @package CodeIgniter
32+
* @author CodeIgniter Dev Team
33+
* @copyright 2019-2020 CodeIgniter Foundation
34+
* @license https://opensource.org/licenses/MIT MIT License
35+
* @link https://codeigniter.com
36+
* @since Version 4.0.0
37+
* @filesource
38+
*/
39+
40+
namespace CodeIgniter\Format\Exceptions;
241

342
use CodeIgniter\Exceptions\ExceptionInterface;
43+
use RuntimeException;
444

5-
class FormatException extends \RuntimeException implements ExceptionInterface
45+
/**
46+
* FormatException
47+
*/
48+
class FormatException extends RuntimeException implements ExceptionInterface
649
{
50+
/**
51+
* Thrown when the instantiated class does not exist.
52+
*
53+
* @param string $class
54+
*
55+
* @return FormatException
56+
*/
57+
public static function forInvalidFormatter(string $class)
58+
{
59+
return new static(lang('Format.invalidFormatter', [$class]));
60+
}
61+
62+
/**
63+
* Thrown in JSONFormatter when the json_encode produces
64+
* an error code other than JSON_ERROR_NONE and JSON_ERROR_RECURSION.
65+
*
66+
* @param string $error
67+
*
68+
* @return FormatException
69+
*/
770
public static function forInvalidJSON(string $error = null)
871
{
972
return new static(lang('Format.invalidJSON', [$error]));
1073
}
1174

1275
/**
13-
* This will never be thrown in travis-ci
76+
* Thrown when the supplied MIME type has no
77+
* defined Formatter class.
78+
*
79+
* @param string $mime
80+
*
81+
* @return FormatException
82+
*/
83+
public static function forInvalidMime(string $mime)
84+
{
85+
return new static(lang('Format.invalidMime', [$mime]));
86+
}
87+
88+
/**
89+
* Thrown on XMLFormatter when the `simplexml` extension
90+
* is not installed.
91+
*
92+
* @return FormatException
1493
*
1594
* @codeCoverageIgnore
1695
*/
1796
public static function forMissingExtension()
1897
{
1998
return new static(lang('Format.missingExtension'));
2099
}
21-
22100
}

0 commit comments

Comments
 (0)