Skip to content

Commit 0e642b3

Browse files
Release 12.0.2
2 parents 5736fd6 + 0e5b525 commit 0e642b3

26 files changed

+459
-146
lines changed

.github/workflows/coverage.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ jobs:
2828
matrix:
2929
# quotes are needed it is treated as a number and zero at decimal part is gone
3030
# at runtime i.e. 8.10 -> 8.1, while "8.10" => "8.10".
31-
laravel: ["11.0"]
31+
laravel: ["12.0"]
3232
php: ["8.2"]
3333

3434
runs-on: ubuntu-latest

.github/workflows/phpstan.yml

Lines changed: 54 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -14,26 +14,73 @@ name: "Static Analysis"
1414
on:
1515
push:
1616
branches:
17-
- "master"
17+
- "master"
1818
pull_request:
1919
branches:
20-
- "master"
21-
- "dev"
20+
- "master"
21+
- "dev"
2222

2323
jobs:
24+
analyze_sources:
25+
name: "Is there any source code to work on?"
26+
runs-on: ubuntu-latest
27+
28+
outputs:
29+
# Export 'filter' step check result so next step can use it.
30+
run_action: ${{ steps.filter.outputs.src }}
31+
# These are source files matching our filter that are affected by the PR.
32+
changed_files: ${{ steps.filter.outputs.src_files }}
33+
34+
steps:
35+
# https://github.com/marketplace/actions/checkout
36+
- name: "Checkout sources"
37+
uses: actions/checkout@v4
38+
39+
# https://github.com/marketplace/actions/paths-changes-filter
40+
- name: "Look for changes that matters for us..."
41+
uses: dorny/paths-filter@v3
42+
id: filter
43+
with:
44+
# Token is optional for public repos, but required for private repos
45+
token: ${{ secrets.GITHUB_TOKEN }}
46+
list-files: 'escape'
47+
filters: |
48+
src:
49+
- 'src/**/*.php'
50+
- 'tests/**/*.php'
51+
52+
- name: "Will action step be run?"
53+
run: |
54+
found="NO"
55+
[[ ${{ steps.filter.outputs.src }} == 'true' ]] && found="YES"
56+
echo "run_action=${found}" >> $GITHUB_OUTPUT
57+
echo -e "\n****************************************\n"
58+
echo "${found}"
59+
echo -e "****************************************"
60+
2461
check:
62+
# Will run only if analyze_sources determined it is needed.
63+
needs: analyze_sources
64+
if: needs.analyze_sources.outputs.run_action == 'true'
65+
2566
strategy:
2667
# do not stop the workflow if single run failed
2768
fail-fast: false
2869
matrix:
29-
# quotes are needed it is treated as a number and zero at decimal part is gone
70+
# Quotes are needed it is treated as a number and zero at decimal part is gone
3071
# at runtime i.e. 8.10 -> 8.1, while "8.10" => "8.10".
31-
laravel: ["11.0"]
32-
php: ["8.2"]
72+
php: [ "8.2" ]
3373

3474
runs-on: ubuntu-latest
3575

3676
steps:
77+
# https://github.com/marketplace/actions/setup-php-action
78+
- name: "Setup PHP ${{ matrix.php }}"
79+
uses: shivammathur/setup-php@v2
80+
with:
81+
php-version: "${{ matrix.php }}"
82+
83+
# https://github.com/marketplace/actions/checkout
3784
- name: "Checkout repository..."
3885
uses: actions/checkout@v4
3986

@@ -45,18 +92,6 @@ jobs:
4592
php_version: "${{ matrix.php }}"
4693
dev: yes
4794

48-
# # https://github.com/marketplace/actions/phpstan-php-actions
49-
# - name: "Running PHPStan..."
50-
# uses: php-actions/phpstan@v3
51-
# with:
52-
# configuration: "phpstan.neon"
53-
# php_version: "${{ matrix.php }}"
54-
# # memory_limit: "16M"
55-
56-
# - name: "Making cache folder writable"
57-
# shell: bash
58-
# run: chmod 777 vendor/orchestra/testbench-core/laravel/bootstrap/cache
59-
6095
- name: "Running PHPStan..."
6196
shell: bash
62-
run: vendor/bin/phpstan
97+
run: composer lint

.pre-commit-config.yaml

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
##################################################################################
2+
#
3+
# Laravel API Response Builder PHPStan config file
4+
#
5+
# @author Marcin Orlowski <mail (#) marcinOrlowski (.) com>
6+
# @copyright 2016-2025 Marcin Orlowski
7+
# @license http://www.opensource.org/licenses/mit-license.php MIT
8+
# @link https://github.com/MarcinOrlowski/laravel-api-response-builder
9+
#
10+
##################################################################################
11+
#
12+
# Using pre-commit hooks #
13+
#
14+
# To improve quality of your commit, it's recommended to use "pre-commit"
15+
# (http://pre-commit.com) hooks, that will block your commits unless all tests
16+
# pass. This project comes with template configuration file
17+
# `.pre-commit-config.yaml.dist`.
18+
#
19+
# Brief installation instruction:
20+
#
21+
# * Ensure you got Python installed
22+
# * Install pre-commit: `pip install pre-commit`
23+
# * Go to your Logisim-evolution source code root directory
24+
# * Copy provided config file template: `cp .pre-commit-config.yaml.dist .pre-commit-config.yaml`
25+
# * Plug hooks into Git pipeline: `pre-commit install`
26+
#
27+
# See `pre-commit` official installation docs too: https://pre-commit.com/#install
28+
#
29+
# To see how pre-commit identifies given file (i.e. for 'exclude_type' config) use `identify-cli <FILE>`
30+
#
31+
32+
repos:
33+
- repo: https://github.com/pre-commit/pre-commit-hooks
34+
rev: v5.0.0
35+
hooks:
36+
# Prevent giant files from being committed
37+
- id: check-added-large-files
38+
args: [ '--maxkb=1555550' ]
39+
# This hook checks yaml files for parseable syntax
40+
- id: check-yaml
41+
# Check for files that would conflict in case-insensitive filesystems
42+
- id: check-case-conflict
43+
# Ensures that (non-binary) executables have a shebang.
44+
- id: check-executables-have-shebangs
45+
# Check for files that contain merge conflict strings
46+
- id: check-merge-conflict
47+
# Prevent addition of new git submodules
48+
- id: forbid-new-submodules
49+
# Replaces or checks mixed line ending
50+
- id: mixed-line-ending
51+
args: [ '--fix=no' ]
52+
53+
- repo: https://github.com/jumanjihouse/pre-commit-hooks
54+
rev: 3.0.0
55+
hooks:
56+
# Non-executable shell script filename ends in .sh
57+
- id: script-must-have-extension
58+
59+
- repo: https://github.com/Lucas-C/pre-commit-hooks
60+
rev: v1.5.5
61+
hooks:
62+
# Forbid files containing CRLF end-lines to be committed
63+
- id: forbid-crlf
64+
exclude: \.svg$
65+
66+
- repo: https://github.com/MarcinOrlowski/pre-commit-hooks
67+
rev: 1.3.1
68+
hooks:
69+
# This hook trims trailing whitespace.
70+
- id: trailing-whitespaces
71+
exclude_types: [ 'binary', 'xml', 'png', 'jpeg', 'pdf', 'svg' ]
72+
args: [ '--markdown-linebreak-ext=md', '--fix=yes' ]
73+
# Ensures that a file is either empty, or ends with one newline
74+
- id: end-of-file
75+
exclude_types: [ 'binary', 'xml', 'png', 'jpeg', 'pdf', 'svg' ]
76+
args: [ '--fix=yes' ]
77+
78+
- repo: https://github.com/digitalpulp/pre-commit-php.git
79+
rev: 1.4.0
80+
hooks:
81+
# Runs PHPStan analyser
82+
- id: php-stan
83+
files: \.(php)$

composer.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "marcin-orlowski/laravel-api-response-builder",
33
"description": "Helps building nice, normalized and easy to consume Laravel REST API.",
44
"homepage": "https://github.com/MarcinOrlowski/laravel-api-response-builder",
5-
"version": "12.0.1",
5+
"version": "12.0.2",
66
"keywords": [
77
"laravel",
88
"laravel10",
@@ -63,7 +63,7 @@
6363
],
6464
"lint": [
6565
"Composer\\Config::disableProcessTimeout",
66-
"vendor/bin/phpstan analyse --no-progress --no-interaction -c phpstan.neon"
66+
"vendor/bin/phpstan analyse --no-progress --no-interaction src/"
6767
],
6868
"mdlint": [
6969
"Composer\\Config::disableProcessTimeout",

docs/CHANGES.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@ should be able to easily backport future new features to older versions rather e
1818

1919
## CHANGE LOG ##
2020

21+
* v12.0.2 (2025-07-10)
22+
* [GH-263] Fixed `Validator::assertIsType()` not validating provided exception class against `InvalidTypeExceptionContract`.
23+
* [GH-263] Added unit tests for `Validator::assertIsType()`.
24+
* [GH-265] Fixed PHP 8.4 deprecation `Implicitly nullable parameters...` (reporeted by @technetius)
25+
* Fixed typehints to make PHPStan green on `max` sensitivity level.
26+
2127
* v12.0.1 (2025-04-16)
2228
* [RB-255] Fixed `ToArrayConverter` using a new Request instance instead of the actual request.
2329
* [BR-256] Fixed `ToArrayConverter` potentially causing fatal error if object lacks `toArray` method.

phpstan.neon

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,8 @@
1212
includes:
1313
- vendor/larastan/larastan/extension.neon
1414
parameters:
15-
checkGenericClassInNonGenericObjectType: false
1615
level: max
17-
checkMissingIterableValueType: false
16+
treatPhpDocTypesAsCertain: false
1817
paths:
1918
- src/
2019
- tests/

src/ApiCodesHelpers.php

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ public static function getMaxCode(): int
5959

6060
/**
6161
* Returns array of error code constants defined in this class. Used mainly for debugging/tests
62+
*
63+
* @return array<string, mixed>
6264
*/
6365
public static function getApiCodeConstants(): array
6466
{
@@ -69,6 +71,7 @@ public static function getApiCodeConstants(): array
6971
/**
7072
* Returns complete error code to locale string mapping array
7173
*
74+
* @return array<int, string>
7275
* @throws Ex\IncompatibleTypeException
7376
* @throws Ex\InvalidTypeException
7477
* @throws Ex\MissingConfigurationKeyException Thrown when builder map is not configured.
@@ -83,8 +86,10 @@ public static function getMap(): array
8386
}
8487
Validator::assertIsArray(RB::CONF_KEY_MAP, $user_map);
8588

86-
/** @var array $user_map */
87-
return Util::mergeConfig(BaseApiCodes::getBaseMap(), $user_map);
89+
/** @var array<int, string> $user_map */
90+
$result = Util::mergeConfig(BaseApiCodes::getBaseMap(), $user_map); // @phpstan-ignore-line
91+
/** @var array<int, string> $result */
92+
return $result;
8893
}
8994

9095
/**
@@ -108,7 +113,7 @@ public static function getCodeMessageKey(int $api_code): ?string
108113

109114
$map = static::getMap();
110115

111-
return $map[ $api_code ] ?? null;
116+
return $map[$api_code] ?? null;
112117
}
113118

114119
/**

src/ApiResponse.php

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,11 @@ protected function __construct()
2222

2323
public static function fromJson(string $jsonString): self
2424
{
25-
/** @var array $decoded_json */
25+
/** @var array<string, mixed> $decoded_json */
2626
$decoded_json = \json_decode($jsonString, true, 32, JSON_THROW_ON_ERROR);
2727

2828
// Ensure all response elements are present.
29+
/** @var array<string, array<string>> $keys */
2930
$keys = [
3031
ResponseBuilder::KEY_SUCCESS => [Type::BOOLEAN],
3132
ResponseBuilder::KEY_CODE => [Type::INTEGER],
@@ -37,11 +38,7 @@ public static function fromJson(string $jsonString): self
3738
if (!\array_key_exists($key, $decoded_json)) {
3839
throw new \InvalidArgumentException("Missing key '$key' in JSON response.");
3940
}
40-
/** @var mixed|null $allowed_types */
41-
if (!empty($allowed_types)) {
42-
/** @var array $allowed_types */
43-
Validator::assertIsType($key, $decoded_json[ $key ], $allowed_types);
44-
}
41+
Validator::assertIsType($key, $decoded_json[$key], $allowed_types);
4542
}
4643

4744
// Ensure certain elements are not empty.
@@ -57,16 +54,29 @@ public static function fromJson(string $jsonString): self
5754
"The '{$key}' in JSON response cannot be NULL.");
5855
}
5956

57+
/** @var bool $success */
58+
$success = $decoded_json[ResponseBuilder::KEY_SUCCESS];
59+
/** @var int $code */
60+
$code = $decoded_json[ResponseBuilder::KEY_CODE];
61+
/** @var string $message */
62+
$message = $decoded_json[ResponseBuilder::KEY_MESSAGE];
63+
/** @var string $locale */
64+
$locale = $decoded_json[ResponseBuilder::KEY_LOCALE];
65+
/** @var array<string, mixed>|null $data */
66+
$data = $decoded_json[ResponseBuilder::KEY_DATA];
67+
6068
$api = (new self())
61-
->setSuccess($decoded_json[ ResponseBuilder::KEY_SUCCESS ])
62-
->setCode($decoded_json[ ResponseBuilder::KEY_CODE ])
63-
->setMessage($decoded_json[ ResponseBuilder::KEY_MESSAGE ])
64-
->setLocale($decoded_json[ ResponseBuilder::KEY_LOCALE ])
65-
->setData($decoded_json[ ResponseBuilder::KEY_DATA ]);
69+
->setSuccess($success)
70+
->setCode($code)
71+
->setMessage($message)
72+
->setLocale($locale)
73+
->setData($data);
6674

6775
// Optional debug data
6876
if (\array_key_exists(ResponseBuilder::KEY_DEBUG, $decoded_json)) {
69-
$api->setDebug($decoded_json[ ResponseBuilder::KEY_DEBUG ]);
77+
/** @var array<string, mixed>|null $debug */
78+
$debug = $decoded_json[ResponseBuilder::KEY_DEBUG];
79+
$api->setDebug($debug);
7080
}
7181

7282
return $api;
@@ -134,13 +144,20 @@ protected function setLocale(string $locale): self
134144

135145
// ---------------------------------------------------------------------------------------------
136146

147+
/** @var array<string, mixed>|null */
137148
protected ?array $data;
138149

150+
/**
151+
* @return array<string, mixed>|null
152+
*/
139153
public function getData(): ?array
140154
{
141155
return $this->data;
142156
}
143157

158+
/**
159+
* @param array<string, mixed>|null $data
160+
*/
144161
protected function setData(?array $data): self
145162
{
146163
$this->data = $data;
@@ -149,13 +166,20 @@ protected function setData(?array $data): self
149166

150167
// ---------------------------------------------------------------------------------------------
151168

169+
/** @var array<string, mixed>|null */
152170
protected ?array $debug = null;
153171

172+
/**
173+
* @return array<string, mixed>|null
174+
*/
154175
public function getDebug(): ?array
155176
{
156177
return $this->debug;
157178
}
158179

180+
/**
181+
* @param array<string, mixed>|null $debug
182+
*/
159183
public function setDebug(?array $debug): self
160184
{
161185
$this->debug = $debug;

src/BaseApiCodes.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ class BaseApiCodes
9090
/**
9191
* Returns base code mapping array
9292
*
93+
* @return array<int, string>
9394
* @throws Ex\InvalidTypeException
9495
* @throws Ex\MissingConfigurationKeyException
9596
* @throws Ex\NotIntegerException

src/Contracts/ConverterContract.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@ interface ConverterContract
1717
* Returns array representation of the object.
1818
*
1919
* @param object $obj Object to be converted
20-
* @param array $config Converter config array to be used for this object (based on exact class
20+
* @param array<string, mixed> $config Converter config array to be used for this object (based on exact class
2121
* name match or inheritance).
22+
* @return array<string, mixed>
2223
*/
2324
public function convert(object $obj, array $config): array;
2425

0 commit comments

Comments
 (0)