Skip to content

Commit 8fd553d

Browse files
author
Sebastian Fix
committed
Updated to Laravel 13
1 parent 8cde593 commit 8fd553d

10 files changed

Lines changed: 420 additions & 79 deletions

File tree

.github/workflows/run-tests.yml

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,15 @@ jobs:
1414
max-parallel: 1
1515
matrix:
1616
os: [ ubuntu-latest ]
17-
php: [ 8.4 ]
18-
laravel: [ 12.* ]
17+
php: [ 8.3, 8.5 ]
18+
laravel: [ 13.* ]
1919
stability: [ prefer-lowest, prefer-stable ]
2020

2121
name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }} - ${{ matrix.os }}
2222

2323
steps:
2424
- name: Checkout code
25-
uses: actions/checkout@v5
25+
uses: actions/checkout@v6
2626

2727
- name: Setup PHP
2828
uses: shivammathur/setup-php@v2
@@ -45,7 +45,7 @@ jobs:
4545
run: cp phpunit.xml.dist phpunit.xml
4646

4747
- name: Execute tests
48-
run: vendor/bin/pest
48+
run: vendor/bin/pest --no-coverage
4949
env:
5050
M_FILES_URL: ${{ secrets.M_FILES_URL }}
5151
M_FILES_USERNAME: ${{ secrets.M_FILES_USERNAME }}
@@ -55,7 +55,45 @@ jobs:
5555

5656
- name: Store Log Artifacts
5757
if: failure()
58-
uses: actions/upload-artifact@v5
58+
uses: actions/upload-artifact@v6
5959
with:
6060
name: Store report artifacts
6161
path: ./vendor/orchestra/testbench-core/laravel/storage/logs
62+
63+
coverage:
64+
runs-on: ubuntu-latest
65+
name: coverage (PHP 8.5)
66+
67+
steps:
68+
- name: Checkout code
69+
uses: actions/checkout@v6
70+
71+
- name: Setup PHP
72+
uses: shivammathur/setup-php@v2
73+
with:
74+
php-version: 8.5
75+
extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick, fileinfo, pcov
76+
coverage: pcov
77+
78+
- name: Install dependencies
79+
run: |
80+
composer require "laravel/framework:13.*" --no-interaction --no-update
81+
composer update --prefer-stable --prefer-dist --no-interaction
82+
83+
- name: Run tests with coverage
84+
run: |
85+
mkdir -p build/logs
86+
cp phpunit.xml.dist phpunit.xml
87+
vendor/bin/pest --coverage --coverage-clover build/logs/clover.xml
88+
env:
89+
M_FILES_URL: ${{ secrets.M_FILES_URL }}
90+
M_FILES_USERNAME: ${{ secrets.M_FILES_USERNAME }}
91+
M_FILES_PASSWORD: ${{ secrets.M_FILES_PASSWORD }}
92+
M_FILES_VAULT_GUID: ${{ secrets.M_FILES_VAULT_GUID }}
93+
M_FILES_CACHE_DRIVER: ${{ secrets.M_FILES_CACHE_DRIVER }}
94+
95+
- name: Upload coverage artifact
96+
uses: actions/upload-artifact@v6
97+
with:
98+
name: coverage-clover
99+
path: build/logs/clover.xml

README.md

Lines changed: 53 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ You can install the package via composer:
1818
composer require codebar-ag/laravel-m-files
1919
```
2020

21+
### Requirements
22+
23+
- PHP **8.3+**
24+
- Laravel **13.x** (the package targets `illuminate/contracts` and `illuminate/support` **^13**)
25+
2126
## Configuration
2227

2328
Publish the configuration file:
@@ -34,6 +39,8 @@ M_FILES_USERNAME=your-username
3439
M_FILES_PASSWORD=your-password
3540
M_FILES_VAULT_GUID=ABC0DE2G-3HW-QWCQ-SDF3-WERWETWETW
3641
M_FILES_CACHE_DRIVER=file
42+
M_FILES_EXPIRATION_SECONDS=3600
43+
# M_FILES_SESSION_ID= # optional; exposed as config('m-files.auth.session_id') for custom use
3744
```
3845

3946
### Configuration Options
@@ -44,7 +51,9 @@ The package supports the following configuration options:
4451
- `M_FILES_USERNAME` - Your M-Files username
4552
- `M_FILES_PASSWORD` - Your M-Files password
4653
- `M_FILES_VAULT_GUID` - The vault GUID to connect to
47-
- `M_FILES_CACHE_DRIVER` - Cache driver for storing authentication tokens (default: file)
54+
- `M_FILES_CACHE_DRIVER` - Cache driver for storing authentication tokens (defaults to `CACHE_DRIVER`, then `file`)
55+
- `M_FILES_EXPIRATION_SECONDS` - How long to cache the vault authentication token, in seconds (default: `3600`)
56+
- `M_FILES_SESSION_ID` - Optional; sets `config('m-files.auth.session_id')` (not used by the package’s built-in connector/requests; available for your own integrations)
4857

4958
## Authentication
5059

@@ -61,19 +70,27 @@ $config = new ConfigWithCredentials(
6170
vaultGuid: '{ABC0DE2G-3HW-QWCQ-SDF3-WERWETWETW}',
6271
username: 'your-username',
6372
password: 'your-password',
64-
cacheDriver: 'file'
73+
cacheDriver: 'file',
74+
tokenTtlSeconds: 3600,
6575
);
6676

67-
$connector = new MFilesConnector(config: $config);
77+
$connector = new MFilesConnector(configuration: $config);
6878
```
6979

70-
### Authentication
80+
### How the connector authenticates
7181

7282
Authentication is handled automatically by the `MFilesConnector`. When you create a connector instance with your credentials, it will automatically:
7383

74-
1. **Cache authentication tokens** - Tokens are cached for 1 hour to avoid repeated login requests
84+
1. **Cache authentication tokens** - Tokens are cached for `M_FILES_EXPIRATION_SECONDS` / `config('m-files.auth.expiration')` (default 3600 seconds), or the `tokenTtlSeconds` argument on `ConfigWithCredentials`
7585
2. **Include authentication headers** - The `X-Authentication` header is automatically added to all requests
76-
3. **Handle token refresh** - When tokens expire, new ones are automatically obtained
86+
3. **Handle token refresh** - When the cache entry expires, a new token is obtained on the next request
87+
88+
You can optionally inject a `CacheKeyManager` for tests or custom cache wiring: `new MFilesConnector(configuration: $config, cacheKeyManager: $manager)`.
89+
90+
### Cache and production security
91+
92+
- Auth tokens are stored in your configured **Laravel cache store**. Use a **private** backend in production (not a shared public cache).
93+
- Cache keys incorporate a hash of connection parameters (including credentials). For **multi-tenant** apps, avoid sharing one cache namespace across tenants; prefer per-tenant key prefixes or separate Redis databases where applicable.
7794

7895
```php
7996
use CodebarAg\MFiles\Requests\LogInToVaultRequest;
@@ -301,31 +318,34 @@ Represents M-Files configuration with authentication credentials.
301318
- `vaultGuid` (string) - Vault GUID
302319
- `username` (string) - M-Files username
303320
- `password` (string) - M-Files password
304-
- `cacheDriver` (string|null) - Cache driver for tokens
321+
- `cacheDriver` (string|null) - Cache store name for tokens (see `M_FILES_CACHE_DRIVER` / `config('m-files.cache_driver')`)
322+
- `tokenTtlSeconds` (int) - Cache TTL for the vault token in seconds (default **3600**; must be **≥ 1**)
305323

306324
**Methods:**
307-
- `fromArray(array $data): self` - Static factory method
308-
- `toArray(): array` - Converts to array format
325+
- `fromArray(array $data): self` - Builds from an array; **requires a Laravel app context** so `config('m-files.*')` defaults apply for omitted `cacheDriver` / `tokenTtlSeconds`. Required keys: `url`, `vaultGuid`, `username`, `password` (each a non-empty string). Throws `InvalidArgumentException` if validation fails.
326+
- `toArray(): array` - Converts to array format (includes `tokenTtlSeconds`)
309327

310328
**Usage:**
311329
```php
312330
use CodebarAg\MFiles\DTO\ConfigWithCredentials;
313331

314332
$config = new ConfigWithCredentials(
315333
url: 'https://your-mfiles-server.com',
334+
vaultGuid: '{ABC0DE2G-3HW-QWCQ-SDF3-WERWETWETW}',
316335
username: 'your-username',
317336
password: 'your-password',
318-
vaultGuid: '{ABC0DE2G-3HW-QWCQ-SDF3-WERWETWETW}',
319-
cacheDriver: 'file'
337+
cacheDriver: 'file',
338+
tokenTtlSeconds: 3600,
320339
);
321340

322-
// Using static factory method
341+
// Using static factory method (inside a Laravel application)
323342
$config = ConfigWithCredentials::fromArray([
324343
'url' => 'https://your-mfiles-server.com',
344+
'vaultGuid' => '{ABC0DE2G-3HW-QWCQ-SDF3-WERWETWETW}',
325345
'username' => 'your-username',
326346
'password' => 'your-password',
327-
'vaultGuid' => '{ABC0DE2G-3HW-QWCQ-SDF3-WERWETWETW}',
328-
'cacheDriver' => 'file'
347+
'cacheDriver' => 'file',
348+
'tokenTtlSeconds' => 3600,
329349
]);
330350
```
331351

@@ -541,16 +561,34 @@ $dataTypeValue = $dataType->value; // 1
541561
composer test
542562
```
543563

564+
`composer test` runs Pest with `--no-coverage` so the suite passes without PCOV or Xdebug (PHPUnit is configured with `failOnWarning="true"`, and missing a coverage driver would otherwise fail the run).
565+
566+
Static analysis:
567+
568+
```bash
569+
composer analyse
570+
```
571+
572+
To generate a coverage report locally, install and enable [PCOV](https://github.com/krakjoe/pcov) or Xdebug, then run:
573+
574+
```bash
575+
composer test-coverage
576+
```
577+
578+
On GitHub Actions, the `run-tests` workflow runs the matrix with `--no-coverage` and includes a **coverage** job (PHP 8.5 + PCOV) that writes Clover output and uploads it as a workflow artifact.
579+
544580
## Changelog
545581

546582
Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.
547583

548584
## Contributing
549585

550-
Please see [CONTRIBUTING](CONTRIBUTING.md) for details.
586+
Open a pull request or issue on [GitHub](https://github.com/codebar-ag/laravel-m-files). Please run `composer test` and `composer analyse` before submitting.
551587

552588
## Security
553589

590+
Operational notes on caching and credentials are described under [Cache and production security](#cache-and-production-security).
591+
554592
If you discover any security related issues, please email security@codebar.ch instead of using the issue tracker.
555593

556594
## Credits

composer.json

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -20,24 +20,26 @@
2020
}
2121
],
2222
"require": {
23-
"php": "8.4.*",
24-
"guzzlehttp/guzzle": "^7.8",
25-
"illuminate/contracts": "^12.0",
26-
"nesbot/carbon": "^3.8",
23+
"php": "^8.3",
24+
"guzzlehttp/guzzle": "^7.9.2",
25+
"illuminate/contracts": "^13.0",
26+
"illuminate/support": "^13.0",
2727
"saloonphp/cache-plugin": "^3.1",
28-
"saloonphp/laravel-plugin": "^3.0|^4.0",
29-
"saloonphp/saloon": "^3.0|^4.0",
30-
"spatie/laravel-package-tools": "^1.19",
31-
"spatie/laravel-ray": "^1.40"
28+
"saloonphp/laravel-plugin": "^4.0",
29+
"saloonphp/saloon": "^4.0",
30+
"spatie/laravel-package-tools": "^1.19.0"
3231
},
3332
"require-dev": {
34-
"larastan/larastan": "^v3.1",
35-
"laravel/pint": "^1.21",
36-
"orchestra/testbench": "^10.0",
33+
"laravel/pint": "^1.21.1",
34+
"larastan/larastan": "^3.9.3",
35+
"nunomaduro/collision": "^8.6.1",
36+
"orchestra/testbench": "^11.0",
3737
"pestphp/pest": "^4.4",
38-
"phpstan/extension-installer": "^1.4",
39-
"phpstan/phpstan-deprecation-rules": "^2.0",
40-
"phpstan/phpstan-phpunit": "^2.0"
38+
"phpdocumentor/reflection-docblock": "^5.6.1",
39+
"phpstan/extension-installer": "^1.4.3",
40+
"phpstan/phpstan-deprecation-rules": "^2.0.1",
41+
"phpstan/phpstan-phpunit": "^2.0.4",
42+
"spatie/laravel-ray": "^1.40.0"
4143
},
4244
"autoload": {
4345
"psr-4": {
@@ -53,16 +55,16 @@
5355
"post-autoload-dump": "@php ./vendor/bin/testbench package:discover --ansi",
5456
"analyse": "vendor/bin/phpstan analyse",
5557
"larastan": "vendor/bin/phpstan analyse",
56-
"test": "vendor/bin/pest",
58+
"test": "vendor/bin/pest --no-coverage",
5759
"test-coverage": "vendor/bin/pest --coverage",
5860
"format": "vendor/bin/pint"
5961
},
6062
"config": {
6163
"sort-packages": true,
6264
"allow-plugins": {
63-
"composer/package-versions-deprecated": true,
64-
"phpstan/extension-installer": true,
65-
"pestphp/pest-plugin": true
65+
"composer/package-versions-deprecated": false,
66+
"pestphp/pest-plugin": true,
67+
"phpstan/extension-installer": true
6668
}
6769
},
6870
"extra": {
@@ -72,6 +74,5 @@
7274
]
7375
}
7476
},
75-
"minimum-stability": "dev",
7677
"prefer-stable": true
7778
}

config/m-files.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
'url' => env('M_FILES_URL'),
66
'username' => env('M_FILES_USERNAME'),
77
'password' => env('M_FILES_PASSWORD'),
8-
'expiration' => env('M_FILES_EXPIRATION_SECONDS', 1),
8+
'expiration' => (int) env('M_FILES_EXPIRATION_SECONDS', 3600),
99
'session_id' => env('M_FILES_SESSION_ID'),
1010
],
1111

phpstan-baseline.neon

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
parameters:
2+
ignoreErrors:
3+
-
4+
message: '#^Call to an undefined method Pest\\PendingCalls\\TestCall\|Pest\\Support\\HigherOrderTapProxy\:\:expect\(\)\.$#'
5+
identifier: method.notFound
6+
count: 1
7+
path: tests/Core/ArchTest.php
8+
9+
-
10+
message: '#^Access to an undefined property PHPUnit\\Framework\\TestCase\:\:\$config\.$#'
11+
identifier: property.notFound
12+
count: 1
13+
path: tests/Feature/Requests/DownloadFileRequestTest.php
14+
15+
-
16+
message: '#^Access to an undefined property PHPUnit\\Framework\\TestCase\:\:\$connector\.$#'
17+
identifier: property.notFound
18+
count: 1
19+
path: tests/Feature/Requests/DownloadFileRequestTest.php
20+
21+
-
22+
message: '#^Assign to protected\(set\) property CodebarAg\\MFiles\\DTO\\DownloadedFile\:\:\$content\.$#'
23+
identifier: assign.propertyProtectedSet
24+
count: 1
25+
path: tests/Unit/DTO/DownloadedFileTest.php
26+
27+
-
28+
message: '#^Assign to protected\(set\) property CodebarAg\\MFiles\\DTO\\File\:\:\$id\.$#'
29+
identifier: assign.propertyProtectedSet
30+
count: 1
31+
path: tests/Unit/DTO/FileTest.php
32+
33+
-
34+
message: '#^Assign to protected\(set\) property CodebarAg\\MFiles\\DTO\\ObjectProperties\:\:\$classId\.$#'
35+
identifier: assign.propertyProtectedSet
36+
count: 1
37+
path: tests/Unit/DTO/ObjectPropertiesTest.php
38+
39+
-
40+
message: '#^Call to method PHPUnit\\Framework\\Assert\:\:assertInstanceOf\(\) with ''Carbon\\\\CarbonImmutable'' and Carbon\\CarbonImmutable will always evaluate to true\.$#'
41+
identifier: method.alreadyNarrowedType
42+
count: 3
43+
path: tests/Unit/DTO/ObjectPropertiesTest.php
44+
45+
-
46+
message: '#^Call to method PHPUnit\\Framework\\Assert\:\:assertInstanceOf\(\) with ''Illuminate\\\\Support\\\\Collection'' and Illuminate\\Support\\Collection will always evaluate to true\.$#'
47+
identifier: method.alreadyNarrowedType
48+
count: 6
49+
path: tests/Unit/DTO/ObjectPropertiesTest.php
50+
51+
-
52+
message: '#^Access to an undefined property PHPUnit\\Framework\\TestCase\:\:\$cacheManager\.$#'
53+
identifier: property.notFound
54+
count: 9
55+
path: tests/Unit/Helpers/CacheKeyManagerTest.php
56+
57+
-
58+
message: '#^Access to an undefined property PHPUnit\\Framework\\TestCase\:\:\$config\.$#'
59+
identifier: property.notFound
60+
count: 1
61+
path: tests/Unit/Helpers/CacheKeyManagerTest.php

phpstan.neon.dist

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
1+
includes:
2+
- phpstan-baseline.neon
3+
14
parameters:
25
level: 5
36
paths:
4-
- src
57
- config
8+
- src
9+
- tests
610
tmpDir: build/phpstan
711
checkOctaneCompatibility: true
812
checkModelProperties: true

0 commit comments

Comments
 (0)