diff --git a/.editorconfig b/.editorconfig
index 30202d3f..26c64fbc 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -6,13 +6,12 @@ root = true
[*]
indent_style = space
indent_size = 4
-charset = "utf-8"
+charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*.yml]
-indent_style = space
indent_size = 2
[*.neon]
diff --git a/.gitattributes b/.gitattributes
index 797f418b..a399e5d7 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -4,8 +4,10 @@ CONTRIBUTING.md export-ignore
.gitattributes export-ignore
.gitignore export-ignore
phpunit.xml.dist export-ignore
-.scrutinizer.yml export-ignore
-.stickler.yml export-ignore
tests export-ignore
docs export-ignore
.github export-ignore
+.phive export-ignore
+phpcs.xml export-ignore
+psalm.xml export-ignore
+phpstan.neon export-ignore
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 2c0fe41e..214ac91f 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -1,90 +1,22 @@
name: CI
-on: [push, pull_request]
+on:
+ push:
+ branches:
+ - master
+ - cake-5
+ pull_request:
+ branches:
+ - '*'
+
+permissions:
+ contents: read
jobs:
testsuite:
- runs-on: ubuntu-18.04
- strategy:
- fail-fast: false
- matrix:
- php-version: ['7.4', '8.0', '8.1']
- db-type: [mysql, pgsql]
- prefer-lowest: ['']
- include:
- - php-version: '7.2'
- db-type: 'sqlite'
- prefer-lowest: 'prefer-lowest'
-
- services:
- postgres:
- image: postgres
- ports:
- - 5432:5432
- env:
- POSTGRES_PASSWORD: postgres
-
- steps:
- - uses: actions/checkout@v2
-
- - name: Setup Service
- if: matrix.db-type == 'mysql'
- run: |
- sudo service mysql start
- mysql -h 127.0.0.1 -u root -proot -e 'CREATE DATABASE cakephp;'
-
- - name: Setup PHP
- uses: shivammathur/setup-php@v2
- with:
- php-version: ${{ matrix.php-version }}
- extensions: mbstring, intl, pdo_${{ matrix.db-type }}
- coverage: pcov
-
- - name: Composer install
- run: |
- if ${{ matrix.prefer-lowest == 'prefer-lowest' }}; then
- composer update --prefer-lowest --prefer-stable
- else
- composer install
- fi
-
- - name: Run PHPUnit
- run: |
- if [[ ${{ matrix.db-type }} == 'sqlite' ]]; then export DB_URL='sqlite:///:memory:'; fi
- if [[ ${{ matrix.db-type }} == 'mysql' ]]; then export DB_URL='mysql://root:root@127.0.0.1/cakephp'; fi
- if [[ ${{ matrix.db-type }} == 'pgsql' ]]; then export DB_URL='postgres://postgres:postgres@127.0.0.1/postgres'; fi
-
- if [[ ${{ matrix.php-version }} == '7.4' && ${{ matrix.db-type }} == 'mysql' ]]; then
- vendor/bin/phpunit --coverage-clover=coverage.xml
- else
- vendor/bin/phpunit
- fi
-
- - name: Code Coverage Report
- if: success() && matrix.php-version == '7.4' && matrix.db-type == 'mysql'
- uses: codecov/codecov-action@v2
+ uses: cakephp/.github/.github/workflows/testsuite-with-db.yml@5.x
+ secrets: inherit
cs-stan:
- name: Coding Standard & Static Analysis
- runs-on: ubuntu-18.04
-
- steps:
- - uses: actions/checkout@v2
-
- - name: Setup PHP
- uses: shivammathur/setup-php@v2
- with:
- php-version: '7.4'
- extensions: mbstring, intl
- coverage: none
- tools: cs2pr, phpstan:1.2
-
- - name: Composer Install
- run: composer install
-
- - name: Run phpcs
- run: vendor/bin/phpcs --report=checkstyle --standard=vendor/cakephp/cakephp-codesniffer/CakePHP src/ tests/ | cs2pr
-
- - name: Run phpstan
- if: success() || failure()
- run: phpstan analyse
+ uses: cakephp/.github/.github/workflows/cs-stan.yml@5.x
+ secrets: inherit
diff --git a/.phive/phars.xml b/.phive/phars.xml
new file mode 100644
index 00000000..17093fd6
--- /dev/null
+++ b/.phive/phars.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/.scrutinizer.yml b/.scrutinizer.yml
deleted file mode 100644
index 27146f70..00000000
--- a/.scrutinizer.yml
+++ /dev/null
@@ -1,21 +0,0 @@
-imports:
- - php
-
-filter:
- excluded_paths:
- - docs/
- - tests/
-tools:
- php_mess_detector: true
- php_cpd:
- excluded_dirs:
- - docs/
- - tests/
- php_loc:
- excluded_dirs:
- - docs/
- - tests/
- php_pdepend:
- excluded_dirs:
- 1: docs/
- 2: tests/
diff --git a/README.md b/README.md
index 49e612e4..6522153a 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-[![Build Status](https://img.shields.io/github/workflow/status/FriendsOfCake/cakephp-upload/CI/master?style=flat-square)](https://github.com/FriendsOfCake/cakephp-upload/actions?query=workflow%3ACI+branch%3Amaster)
+[![Build Status](https://img.shields.io/github/actions/workflow/status/FriendsOfCake/cakephp-upload/ci.yml?style=flat-square)](https://github.com/FriendsOfCake/cakephp-upload/actions?query=workflow%3ACI+branch%3Amaster)
[![Coverage Status](https://img.shields.io/codecov/c/github/FriendsOfCake/cakephp-upload/master?style=flat-square)](https://codecov.io/gh/FriendsOfCake/cakephp-upload)
[![Total Downloads](https://img.shields.io/packagist/dt/josegonzalez/cakephp-upload.svg?style=flat-square)](https://packagist.org/packages/josegonzalez/cakephp-upload)
[![Latest Stable Version](https://img.shields.io/packagist/v/josegonzalez/cakephp-upload.svg?style=flat-square)](https://packagist.org/packages/josegonzalez/cakephp-upload)
@@ -8,6 +8,8 @@
The Upload Plugin is an attempt to easily handle file uploads with CakePHP.
+See [7.x branch](https://github.com/FriendsOfCake/cakephp-upload/tree/7.x) for CakePHP 4.x documentation.
+
See [4.x branch](https://github.com/FriendsOfCake/cakephp-upload/tree/4.x) for CakePHP 3.x documentation.
See [2.x branch](https://github.com/FriendsOfCake/cakephp-upload/tree/2.x) for CakePHP 2.x documentation.
diff --git a/composer.json b/composer.json
index 926dcab8..4912c0f2 100644
--- a/composer.json
+++ b/composer.json
@@ -12,15 +12,30 @@
}
],
"require": {
- "cakephp/orm": "^4.0.2",
- "league/flysystem": "^2.2|^3.0"
+ "cakephp/orm": "^5.0",
+ "league/flysystem": "^3.15.1.0"
},
"require-dev": {
- "cakephp/cakephp": "^4.0.2",
- "phpunit/phpunit": "^8.5 || ^9.3",
- "cakephp/cakephp-codesniffer": "^4.0",
- "league/flysystem-memory": "^2.0|^3.0",
- "mikey179/vfsstream": "^1.6.10"
+ "cakephp/cakephp": "^5.0",
+ "phpunit/phpunit": "^10.1.0",
+ "cakephp/cakephp-codesniffer": "^5.0",
+ "league/flysystem-memory": "^3.15",
+ "mikey179/vfsstream": "^1.6.10",
+ "cakephp/migrations": "^4.1"
+ },
+ "scripts": {
+ "cs-check": "phpcs --colors --parallel=16 -p src/ tests/",
+ "cs-fix": "phpcbf --colors --parallel=16 -p src/ tests/",
+ "phpstan": "tools/phpstan analyse",
+ "psalm": "tools/psalm --show-info=false",
+ "stan": [
+ "@phpstan",
+ "@psalm"
+ ],
+ "stan-baseline": "tools/phpstan --generate-baseline",
+ "psalm-baseline": "tools/psalm --set-baseline=psalm-baseline.xml",
+ "stan-setup": "phive install",
+ "test": "phpunit"
},
"autoload": {
"psr-4": {
diff --git a/phpcs.xml b/phpcs.xml
new file mode 100644
index 00000000..584f45c3
--- /dev/null
+++ b/phpcs.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/phpstan.neon b/phpstan.neon
index 63128791..5ef12379 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -1,5 +1,5 @@
parameters:
- level: 7
+ level: 8
checkMissingIterableValueType: false
checkGenericClassInNonGenericObjectType: false
paths:
@@ -21,11 +21,11 @@ parameters:
path: src/Model/Behavior/UploadBehavior.php
-
- message: "#^Cannot use array destructuring on array\\|false\\.$#"
+ message: "#^Cannot use array destructuring on array\\\\|false\\.$#"
count: 4
path: src/Validation/DefaultValidation.php
-
- message: "#^Cannot use array destructuring on array\\|false\\.$#"
+ message: "#^Cannot use array destructuring on array\\\\|false\\.$#"
count: 4
path: src/Validation/ImageValidation.php
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index 024a3378..5afdae57 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -1,40 +1,23 @@
-
+
+
+
-
-
-
+
-
-
- ./tests/TestCase
+
+ tests/TestCase/
-
-
-
- ./src
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
diff --git a/psalm.xml b/psalm.xml
new file mode 100644
index 00000000..0eeb98b1
--- /dev/null
+++ b/psalm.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/Database/Type/FileType.php b/src/Database/Type/FileType.php
index f59faa75..684e5287 100644
--- a/src/Database/Type/FileType.php
+++ b/src/Database/Type/FileType.php
@@ -3,7 +3,7 @@
namespace Josegonzalez\Upload\Database\Type;
-use Cake\Database\DriverInterface;
+use Cake\Database\Driver;
use Cake\Database\Type\BaseType;
class FileType extends BaseType
@@ -17,7 +17,7 @@ class FileType extends BaseType
* @param mixed $value The value to convert.
* @return mixed Converted value.
*/
- public function marshal($value)
+ public function marshal(mixed $value): mixed
{
return $value;
}
@@ -25,7 +25,7 @@ public function marshal($value)
/**
* @inheritDoc
*/
- public function toDatabase($value, DriverInterface $driver)
+ public function toDatabase(mixed $value, Driver $driver): mixed
{
return $value;
}
@@ -33,7 +33,7 @@ public function toDatabase($value, DriverInterface $driver)
/**
* @inheritDoc
*/
- public function toPHP($value, DriverInterface $driver)
+ public function toPHP(mixed $value, Driver $driver): mixed
{
return $value;
}
diff --git a/src/File/Path/Basepath/DefaultTrait.php b/src/File/Path/Basepath/DefaultTrait.php
index e6925278..99e82ddc 100644
--- a/src/File/Path/Basepath/DefaultTrait.php
+++ b/src/File/Path/Basepath/DefaultTrait.php
@@ -23,7 +23,7 @@ public function basepath(): string
{
$defaultPath = 'webroot{DS}files{DS}{model}{DS}{field}{DS}';
$path = Hash::get($this->settings, 'path', $defaultPath);
- if (strpos($path, '{primaryKey}') !== false) {
+ if (str_contains($path, '{primaryKey}')) {
if ($this->entity->isNew()) {
throw new LogicException('{primaryKey} substitution not allowed for new entities');
}
@@ -43,7 +43,7 @@ public function basepath(): string
'{microtime}' => microtime(true),
'{DS}' => DIRECTORY_SEPARATOR,
];
- if (strpos($path, '{primaryKey}') !== false) {
+ if (str_contains($path, '{primaryKey}')) {
$replacements['{primaryKey}'] = $this->entity->get($this->table->getPrimaryKey());
}
diff --git a/src/File/Path/DefaultProcessor.php b/src/File/Path/DefaultProcessor.php
index d3b1df92..76944382 100644
--- a/src/File/Path/DefaultProcessor.php
+++ b/src/File/Path/DefaultProcessor.php
@@ -7,6 +7,7 @@
use Cake\ORM\Table;
use Josegonzalez\Upload\File\Path\Basepath\DefaultTrait as BasepathTrait;
use Josegonzalez\Upload\File\Path\Filename\DefaultTrait as FilenameTrait;
+use Psr\Http\Message\UploadedFileInterface;
class DefaultProcessor implements ProcessorInterface
{
@@ -18,47 +19,52 @@ class DefaultProcessor implements ProcessorInterface
*
* @var \Cake\ORM\Table
*/
- protected $table;
+ protected Table $table;
/**
* Entity instance.
*
* @var \Cake\Datasource\EntityInterface
*/
- protected $entity;
+ protected EntityInterface $entity;
/**
* Instance of \Psr\Http\Message\UploadedFileInterface conaining the meta info from the file.
*
* @var \Psr\Http\Message\UploadedFileInterface|string
*/
- protected $data;
+ protected UploadedFileInterface|string $data;
/**
* Name of field
*
* @var string
*/
- protected $field;
+ protected string $field;
/**
* Settings for processing a path
*
* @var array
*/
- protected $settings;
+ protected array $settings;
/**
* Constructor
*
- * @param \Cake\ORM\Table $table the instance managing the entity
+ * @param \Cake\ORM\Table $table the instance managing the entity
* @param \Cake\Datasource\EntityInterface $entity the entity to construct a path for.
- * @param \Psr\Http\Message\UploadedFileInterface|string $data the data being submitted for a save or filename stored in db
- * @param string $field the field for which data will be saved
- * @param array $settings the settings for the current field
+ * @param \Psr\Http\Message\UploadedFileInterface|string $data the data being submitted for a save or filename stored in db
+ * @param string $field the field for which data will be saved
+ * @param array $settings the settings for the current field
*/
- public function __construct(Table $table, EntityInterface $entity, $data, string $field, array $settings)
- {
+ public function __construct(
+ Table $table,
+ EntityInterface $entity,
+ UploadedFileInterface|string $data,
+ string $field,
+ array $settings
+ ) {
$this->table = $table;
$this->entity = $entity;
$this->data = $data;
diff --git a/src/File/Path/Filename/DefaultTrait.php b/src/File/Path/Filename/DefaultTrait.php
index 379212ba..e7dd9c41 100644
--- a/src/File/Path/Filename/DefaultTrait.php
+++ b/src/File/Path/Filename/DefaultTrait.php
@@ -16,15 +16,21 @@ trait DefaultTrait
*/
public function filename(): string
{
- $processor = Hash::get($this->settings, 'nameCallback', null);
+ $processor = Hash::get($this->settings, 'nameCallback');
if (is_callable($processor)) {
- return $processor($this->table, $this->entity, $this->data, $this->field, $this->settings);
+ return $processor(
+ $this->table,
+ $this->entity,
+ $this->data,
+ $this->field,
+ $this->settings
+ );
}
if (is_string($this->data)) {
return $this->data;
}
- return $this->data->getClientFilename();
+ return (string)$this->data->getClientFilename();
}
}
diff --git a/src/File/Path/ProcessorInterface.php b/src/File/Path/ProcessorInterface.php
index 96735eef..4eb3e70f 100644
--- a/src/File/Path/ProcessorInterface.php
+++ b/src/File/Path/ProcessorInterface.php
@@ -5,6 +5,7 @@
use Cake\Datasource\EntityInterface;
use Cake\ORM\Table;
+use Psr\Http\Message\UploadedFileInterface;
interface ProcessorInterface
{
@@ -13,11 +14,17 @@ interface ProcessorInterface
*
* @param \Cake\ORM\Table $table the instance managing the entity
* @param \Cake\Datasource\EntityInterface $entity the entity to construct a path for.
- * @param \Psr\Http\Message\UploadedFileInterface|string $data the data being submitted for a save or filename stored in db
+ * @param \Psr\Http\Message\UploadedFileInterface|string $data the data being submitted for a save or filename stored in db
* @param string $field the field for which data will be saved
* @param array $settings the settings for the current field
*/
- public function __construct(Table $table, EntityInterface $entity, $data, string $field, array $settings);
+ public function __construct(
+ Table $table,
+ EntityInterface $entity,
+ string|UploadedFileInterface $data,
+ string $field,
+ array $settings
+ );
/**
* Returns the basepath for the current field/data combination
diff --git a/src/File/Transformer/DefaultTransformer.php b/src/File/Transformer/DefaultTransformer.php
index 7d7c32f2..09c48fd1 100644
--- a/src/File/Transformer/DefaultTransformer.php
+++ b/src/File/Transformer/DefaultTransformer.php
@@ -9,62 +9,22 @@
class DefaultTransformer implements TransformerInterface
{
- /**
- * Table instance.
- *
- * @var \Cake\ORM\Table
- */
- protected $table;
-
- /**
- * Entity instance.
- *
- * @var \Cake\Datasource\EntityInterface
- */
- protected $entity;
-
- /**
- * Array of uploaded data for this field
- *
- * @var \Psr\Http\Message\UploadedFileInterface
- */
- protected $data;
-
- /**
- * Name of field
- *
- * @var string
- */
- protected $field;
-
- /**
- * Settings for processing a path
- *
- * @var array
- */
- protected $settings;
-
/**
* Constructor
*
- * @param \Cake\ORM\Table $table the instance managing the entity
+ * @param \Cake\ORM\Table $table the instance managing the entity
* @param \Cake\Datasource\EntityInterface $entity the entity to construct a path for.
* @param \Psr\Http\Message\UploadedFileInterface $data the data being submitted for a save
- * @param string $field the field for which data will be saved
- * @param array $settings the settings for the current field
+ * @param string $field the field for which data will be saved
+ * @param array $settings the settings for the current field
*/
public function __construct(
- Table $table,
- EntityInterface $entity,
- UploadedFileInterface $data,
- string $field,
- array $settings
+ protected Table $table,
+ protected EntityInterface $entity,
+ protected UploadedFileInterface $data,
+ protected string $field,
+ protected array $settings
) {
- $this->table = $table;
- $this->entity = $entity;
- $this->data = $data;
- $this->field = $field;
- $this->settings = $settings;
}
/**
diff --git a/src/File/Writer/DefaultWriter.php b/src/File/Writer/DefaultWriter.php
index 548ee354..06218f13 100644
--- a/src/File/Writer/DefaultWriter.php
+++ b/src/File/Writer/DefaultWriter.php
@@ -17,41 +17,6 @@
class DefaultWriter implements WriterInterface
{
- /**
- * Table instance.
- *
- * @var \Cake\ORM\Table
- */
- protected $table;
-
- /**
- * Entity instance.
- *
- * @var \Cake\Datasource\EntityInterface
- */
- protected $entity;
-
- /**
- * Array of uploaded data for this field
- *
- * @var \Psr\Http\Message\UploadedFileInterface|null
- */
- protected $data;
-
- /**
- * Name of field
- *
- * @var string
- */
- protected $field;
-
- /**
- * Settings for processing a path
- *
- * @var array
- */
- protected $settings;
-
/**
* Constructs a writer
*
@@ -62,17 +27,12 @@ class DefaultWriter implements WriterInterface
* @param array $settings the settings for the current field
*/
public function __construct(
- Table $table,
- EntityInterface $entity,
- ?UploadedFileInterface $data,
- string $field,
- array $settings
+ protected Table $table,
+ protected EntityInterface $entity,
+ protected ?UploadedFileInterface $data,
+ protected string $field,
+ protected array $settings
) {
- $this->table = $table;
- $this->entity = $entity;
- $this->data = $data;
- $this->field = $field;
- $this->settings = $settings;
}
/**
@@ -117,7 +77,7 @@ public function delete(array $files): array
* @param string $path that path to which the file should be written
* @return bool
*/
- public function writeFile(FilesystemOperator $filesystem, $file, $path): bool
+ public function writeFile(FilesystemOperator $filesystem, string $file, string $path): bool
{
// phpcs:ignore
$stream = @fopen($file, 'r');
@@ -134,10 +94,10 @@ public function writeFile(FilesystemOperator $filesystem, $file, $path): bool
try {
$filesystem->move($tempPath, $path);
$success = true;
- } catch (FilesystemException $e) {
+ } catch (FilesystemException) {
// noop
}
- } catch (FilesystemException $e) {
+ } catch (FilesystemException) {
// noop
}
@@ -159,7 +119,7 @@ public function deletePath(FilesystemOperator $filesystem, string $path): bool
$success = true;
try {
$filesystem->delete($path);
- } catch (FilesystemException $e) {
+ } catch (FilesystemException) {
$success = false;
// TODO: log this?
}
diff --git a/src/Model/Behavior/UploadBehavior.php b/src/Model/Behavior/UploadBehavior.php
index 702c23bf..abde3949 100644
--- a/src/Model/Behavior/UploadBehavior.php
+++ b/src/Model/Behavior/UploadBehavior.php
@@ -18,6 +18,9 @@
use Psr\Http\Message\UploadedFileInterface;
use UnexpectedValueException;
+/**
+ * UploadBehavior
+ */
class UploadBehavior extends Behavior
{
/**
@@ -25,7 +28,7 @@ class UploadBehavior extends Behavior
*
* @var array
*/
- private $protectedFieldNames = [
+ private array $protectedFieldNames = [
'priority',
];
@@ -47,7 +50,7 @@ public function initialize(array $config): void
}
$this->setConfig($configs);
- $this->setConfig('className', null);
+ $this->setConfig('className');
$schema = $this->_table->getSchema();
/** @var string $field */
@@ -65,7 +68,7 @@ public function initialize(array $config): void
* @param \ArrayObject $options options for the current event
* @return void
*/
- public function beforeMarshal(EventInterface $event, ArrayObject $data, ArrayObject $options)
+ public function beforeMarshal(EventInterface $event, ArrayObject $data, ArrayObject $options): void
{
$validator = $this->_table->getValidator();
$dataArray = $data->getArrayCopy();
@@ -96,9 +99,9 @@ public function beforeMarshal(EventInterface $event, ArrayObject $data, ArrayObj
* @param \Cake\Event\EventInterface $event The beforeSave event that was fired
* @param \Cake\Datasource\EntityInterface $entity The entity that is going to be saved
* @param \ArrayObject $options the options passed to the save method
- * @return void|false
+ * @return void
*/
- public function beforeSave(EventInterface $event, EntityInterface $entity, ArrayObject $options)
+ public function beforeSave(EventInterface $event, EntityInterface $entity, ArrayObject $options): void
{
foreach ($this->getConfig(null, []) as $field => $settings) {
if (
@@ -134,7 +137,7 @@ public function beforeSave(EventInterface $event, EntityInterface $entity, Array
$writer = $this->getWriter($entity, $data, $field, $settings);
$success = $writer->write($files);
if ((new Collection($success))->contains(false)) {
- return false;
+ return;
}
$entity->set($field, $filename);
@@ -153,7 +156,7 @@ public function beforeSave(EventInterface $event, EntityInterface $entity, Array
* @param \ArrayObject $options the options passed to the delete method
* @return bool
*/
- public function afterDelete(EventInterface $event, EntityInterface $entity, ArrayObject $options)
+ public function afterDelete(EventInterface $event, EntityInterface $entity, ArrayObject $options): bool
{
$result = true;
@@ -169,11 +172,14 @@ public function afterDelete(EventInterface $event, EntityInterface $entity, Arra
$path = $this->getPathProcessor($entity, $entity->get($field), $field, $settings)->basepath();
}
- $callback = Hash::get($settings, 'deleteCallback', null);
+ $callback = Hash::get($settings, 'deleteCallback');
if ($callback && is_callable($callback)) {
$files = $callback($path, $entity, $field, $settings);
} else {
- $files = [$path . $entity->get($field)];
+ /** @var \Psr\Http\Message\UploadedFileInterface $uploaded */
+ $uploaded = $entity->get($field);
+
+ $files = [$path . $uploaded->getClientFilename()];
}
$writer = $this->getWriter($entity, null, $field, $settings);
@@ -197,8 +203,12 @@ public function afterDelete(EventInterface $event, EntityInterface $entity, Arra
* @param array $settings the settings for the current field
* @return \Josegonzalez\Upload\File\Path\ProcessorInterface
*/
- public function getPathProcessor(EntityInterface $entity, $data, string $field, array $settings): ProcessorInterface
- {
+ public function getPathProcessor(
+ EntityInterface $entity,
+ string|UploadedFileInterface $data,
+ string $field,
+ array $settings
+ ): ProcessorInterface {
/** @var class-string<\Josegonzalez\Upload\File\Path\ProcessorInterface> $processorClass */
$processorClass = Hash::get($settings, 'pathProcessor', DefaultProcessor::class);
diff --git a/src/Plugin.php b/src/UploadPlugin.php
similarity index 58%
rename from src/Plugin.php
rename to src/UploadPlugin.php
index 141eef7d..f420e81f 100644
--- a/src/Plugin.php
+++ b/src/UploadPlugin.php
@@ -11,8 +11,29 @@
/**
* Plugin class.
*/
-class Plugin extends BasePlugin
+class UploadPlugin extends BasePlugin
{
+ /**
+ * The name of this plugin
+ *
+ * @var string|null
+ */
+ protected ?string $name = 'Upload';
+
+ /**
+ * Console middleware
+ *
+ * @var bool
+ */
+ protected bool $consoleEnabled = false;
+
+ /**
+ * Load routes or not
+ *
+ * @var bool
+ */
+ protected bool $routesEnabled = false;
+
/**
* Plugin bootstrap.
*
diff --git a/src/Validation/Traits/ImageValidationTrait.php b/src/Validation/Traits/ImageValidationTrait.php
index b69d0bb4..7ef8a747 100644
--- a/src/Validation/Traits/ImageValidationTrait.php
+++ b/src/Validation/Traits/ImageValidationTrait.php
@@ -14,7 +14,7 @@ trait ImageValidationTrait
* @param int $width Width of Image
* @return bool Success
*/
- public static function isAboveMinWidth($check, int $width): bool
+ public static function isAboveMinWidth(mixed $check, int $width): bool
{
if ($check instanceof UploadedFileInterface) {
$file = $check->getStream()->getMetadata('uri');
@@ -37,7 +37,7 @@ public static function isAboveMinWidth($check, int $width): bool
* @param int $width Width of Image
* @return bool Success
*/
- public static function isBelowMaxWidth($check, int $width): bool
+ public static function isBelowMaxWidth(mixed $check, int $width): bool
{
if ($check instanceof UploadedFileInterface) {
$file = $check->getStream()->getMetadata('uri');
@@ -61,7 +61,7 @@ public static function isBelowMaxWidth($check, int $width): bool
* @param int $height Height of Image
* @return bool Success
*/
- public static function isAboveMinHeight($check, int $height): bool
+ public static function isAboveMinHeight(mixed $check, int $height): bool
{
if ($check instanceof UploadedFileInterface) {
$file = $check->getStream()->getMetadata('uri');
@@ -84,7 +84,7 @@ public static function isAboveMinHeight($check, int $height): bool
* @param int $height Height of Image
* @return bool Success
*/
- public static function isBelowMaxHeight($check, int $height): bool
+ public static function isBelowMaxHeight(mixed $check, int $height): bool
{
if ($check instanceof UploadedFileInterface) {
$file = $check->getStream()->getMetadata('uri');
diff --git a/src/Validation/Traits/UploadValidationTrait.php b/src/Validation/Traits/UploadValidationTrait.php
index 21ab3338..cd4ace87 100644
--- a/src/Validation/Traits/UploadValidationTrait.php
+++ b/src/Validation/Traits/UploadValidationTrait.php
@@ -15,7 +15,7 @@ trait UploadValidationTrait
* @param mixed $check Value to check
* @return bool Success
*/
- public static function isUnderPhpSizeLimit($check): bool
+ public static function isUnderPhpSizeLimit(mixed $check): bool
{
if ($check instanceof UploadedFileInterface) {
return $check->getError() !== UPLOAD_ERR_INI_SIZE;
@@ -31,7 +31,7 @@ public static function isUnderPhpSizeLimit($check): bool
* @param mixed $check Value to check
* @return bool Success
*/
- public static function isUnderFormSizeLimit($check): bool
+ public static function isUnderFormSizeLimit(mixed $check): bool
{
if ($check instanceof UploadedFileInterface) {
return $check->getError() !== UPLOAD_ERR_FORM_SIZE;
@@ -46,7 +46,7 @@ public static function isUnderFormSizeLimit($check): bool
* @param mixed $check Value to check
* @return bool Success
*/
- public static function isCompletedUpload($check): bool
+ public static function isCompletedUpload(mixed $check): bool
{
if ($check instanceof UploadedFileInterface) {
return $check->getError() !== UPLOAD_ERR_PARTIAL;
@@ -61,7 +61,7 @@ public static function isCompletedUpload($check): bool
* @param mixed $check Value to check
* @return bool Success
*/
- public static function isFileUpload($check): bool
+ public static function isFileUpload(mixed $check): bool
{
if ($check instanceof UploadedFileInterface) {
return $check->getError() !== UPLOAD_ERR_NO_FILE;
@@ -76,7 +76,7 @@ public static function isFileUpload($check): bool
* @param mixed $check Value to check
* @return bool Success
*/
- public static function isSuccessfulWrite($check): bool
+ public static function isSuccessfulWrite(mixed $check): bool
{
if ($check instanceof UploadedFileInterface) {
return $check->getError() !== UPLOAD_ERR_CANT_WRITE;
@@ -92,7 +92,7 @@ public static function isSuccessfulWrite($check): bool
* @param int $size Minimum file size
* @return bool Success
*/
- public static function isAboveMinSize($check, $size): bool
+ public static function isAboveMinSize(mixed $check, int $size): bool
{
if ($check instanceof UploadedFileInterface) {
return $check->getSize() >= $size;
@@ -108,7 +108,7 @@ public static function isAboveMinSize($check, $size): bool
* @param int $size Maximum file size
* @return bool Success
*/
- public static function isBelowMaxSize($check, $size): bool
+ public static function isBelowMaxSize(mixed $check, int $size): bool
{
if ($check instanceof UploadedFileInterface) {
return $check->getSize() <= $size;
diff --git a/tests/Fixture/FilesFixture.php b/tests/Fixture/FilesFixture.php
index f890514f..57a5ad89 100644
--- a/tests/Fixture/FilesFixture.php
+++ b/tests/Fixture/FilesFixture.php
@@ -5,26 +5,12 @@
class FilesFixture extends TestFixture
{
- public $table = 'files';
-
- /**
- * fields property
- *
- * @var array
- */
- public $fields = [
- 'id' => ['type' => 'integer'],
- 'filename' => ['type' => 'string'],
- 'created' => ['type' => 'datetime', 'null' => true],
- '_constraints' => ['primary' => ['type' => 'primary', 'columns' => ['id']]],
- ];
-
/**
* records property
*
* @var array
*/
- public $records = [
+ public array $records = [
['filename' => 'FileOne'],
['filename' => 'FileTwo'],
['filename' => 'FileThree'],
diff --git a/tests/Stub/ChildBehavior.php b/tests/Stub/ChildBehavior.php
index b8afddb5..03ba4b3e 100644
--- a/tests/Stub/ChildBehavior.php
+++ b/tests/Stub/ChildBehavior.php
@@ -9,7 +9,7 @@
class ChildBehavior extends UploadBehavior
{
- protected $_defaultConfig = ['key' => 'value'];
+ protected array $_defaultConfig = ['key' => 'value'];
public function constructFiles(
EntityInterface $entity,
diff --git a/tests/TestCase/File/Writer/DefaultWriterTest.php b/tests/TestCase/File/Writer/DefaultWriterTest.php
index 602d481d..8ce52fb4 100644
--- a/tests/TestCase/File/Writer/DefaultWriterTest.php
+++ b/tests/TestCase/File/Writer/DefaultWriterTest.php
@@ -64,11 +64,10 @@ public function testInvoke()
], 'field', []));
}
- public function testDelete()
+ public function testDeleteSucess()
{
$filesystem = $this->getMockBuilder('League\Flysystem\FilesystemOperator')->getMock();
- $filesystem->expects($this->at(0))->method('delete');
- $filesystem->expects($this->at(1))->method('delete')->will($this->throwException(new UnableToDeleteFile()));
+ $filesystem->expects($this->once())->method('delete');
$writer = $this->getMockBuilder('Josegonzalez\Upload\File\Writer\DefaultWriter')
->onlyMethods(['getFilesystem'])
->setConstructorArgs([$this->table, $this->entity, $this->data, $this->field, $this->settings])
@@ -79,6 +78,19 @@ public function testDelete()
$this->assertEquals([true], $writer->delete([
$this->vfs->url() . '/tempfile',
]));
+ }
+
+ public function testDeleteFailure()
+ {
+ $filesystem = $this->getMockBuilder('League\Flysystem\FilesystemOperator')->getMock();
+ $filesystem->expects($this->once())->method('delete')->will($this->throwException(new UnableToDeleteFile()));
+ $writer = $this->getMockBuilder('Josegonzalez\Upload\File\Writer\DefaultWriter')
+ ->onlyMethods(['getFilesystem'])
+ ->setConstructorArgs([$this->table, $this->entity, $this->data, $this->field, $this->settings])
+ ->getMock();
+ $writer->expects($this->any())->method('getFilesystem')->will($this->returnValue($filesystem));
+
+ $this->assertEquals([], $writer->delete([]));
$this->assertEquals([false], $writer->delete([
$this->vfs->url() . '/invalid.txt',
diff --git a/tests/TestCase/Model/Behavior/UploadBehaviorTest.php b/tests/TestCase/Model/Behavior/UploadBehaviorTest.php
index bda3545f..45e7b9b3 100644
--- a/tests/TestCase/Model/Behavior/UploadBehaviorTest.php
+++ b/tests/TestCase/Model/Behavior/UploadBehaviorTest.php
@@ -16,7 +16,7 @@
class UploadBehaviorTest extends TestCase
{
- protected $fixtures = [
+ protected array $fixtures = [
'plugin.Josegonzalez/Upload.Files',
];
@@ -74,12 +74,9 @@ public function testInitialize()
$schema->expects($this->once())
->method('setColumnType')
->with('field', 'upload.file');
- $table->expects($this->at(0))
+ $table->expects($this->any())
->method('getSchema')
->will($this->returnValue($schema));
- $table->expects($this->at(1))
- ->method('setSchema')
- ->will($this->returnValue($schema));
$methods = array_diff($this->behaviorMethods, ['initialize']);
$behavior = $this->getMockBuilder('Josegonzalez\Upload\Model\Behavior\UploadBehavior')
@@ -119,12 +116,9 @@ public function testInitializeIndexedConfig()
$schema->expects($this->once())
->method('setColumnType')
->with('field', 'upload.file');
- $table->expects($this->at(0))
+ $table->expects($this->any())
->method('getSchema')
->will($this->returnValue($schema));
- $table->expects($this->at(1))
- ->method('setSchema')
- ->will($this->returnValue($schema));
$methods = array_diff($this->behaviorMethods, ['initialize', 'setConfig', 'getConfig']);
$behavior = $this->getMockBuilder('Josegonzalez\Upload\Model\Behavior\UploadBehavior')
@@ -154,12 +148,9 @@ public function testInitializeAddBehaviorOptionsInterfaceConfig()
$schema->expects($this->once())
->method('setColumnType')
->with('field', 'upload.file');
- $table->expects($this->at(0))
+ $table->expects($this->any())
->method('getSchema')
->will($this->returnValue($schema));
- $table->expects($this->at(1))
- ->method('setSchema')
- ->will($this->returnValue($schema));
$methods = array_diff($this->behaviorMethods, ['initialize', 'setConfig', 'getConfig']);
//$behavior = $this->getMock('Josegonzalez\Upload\Model\Behavior\UploadBehavior', $methods, [$table, $settings], '', false);
@@ -444,7 +435,10 @@ public function testAfterDeleteOk()
->setConstructorArgs([$this->table, $this->dataOk])
->getMock();
$behavior->setConfig($this->configOk);
-
+ $this->entity->expects($this->any())
+ ->method('get')
+ ->with('field')
+ ->will($this->returnValue($this->dataOk['field']));
$behavior->expects($this->any())
->method('getPathProcessor')
->willReturn($this->processor);
@@ -466,7 +460,10 @@ public function testAfterDeleteFail()
->setConstructorArgs([$this->table, $this->dataOk])
->getMock();
$behavior->setConfig($this->configOk);
-
+ $this->entity->expects($this->any())
+ ->method('get')
+ ->with('field')
+ ->will($this->returnValue($this->dataOk['field']));
$behavior->expects($this->any())
->method('getPathProcessor')
->willReturn($this->processor);
@@ -476,7 +473,6 @@ public function testAfterDeleteFail()
$this->writer->expects($this->any())
->method('delete')
->will($this->returnValue([false]));
-
$this->assertFalse($behavior->afterDelete(new Event('fake.event'), $this->entity, new ArrayObject()));
}
@@ -502,7 +498,13 @@ public function testAfterDeleteSkip()
public function testAfterDeleteUsesPathProcessorToDetectPathToTheFile()
{
$dir = '/some/path/';
- $field = 'file.txt';
+ $field = new UploadedFile(
+ fopen('php://temp', 'wb+'),
+ 1,
+ UPLOAD_ERR_OK,
+ 'file.txt',
+ 'text/plain'
+ );
$methods = array_diff($this->behaviorMethods, ['afterDelete', 'config', 'setConfig', 'getConfig']);
$behavior = $this->getMockBuilder('Josegonzalez\Upload\Model\Behavior\UploadBehavior')
@@ -511,15 +513,12 @@ public function testAfterDeleteUsesPathProcessorToDetectPathToTheFile()
->getMock();
$behavior->setConfig($this->configOk);
- $this->entity->expects($this->at(0))
+ $this->entity->expects($this->once())
->method('has')
->with('dir')
->will($this->returnValue(false));
- $this->entity->expects($this->at(1))
- ->method('get')
- ->with('field')
- ->will($this->returnValue($field));
- $this->entity->expects($this->at(2))
+
+ $this->entity->expects($this->exactly(2))
->method('get')
->with('field')
->will($this->returnValue($field));
@@ -541,7 +540,7 @@ public function testAfterDeleteUsesPathProcessorToDetectPathToTheFile()
// and here we check that file with right path will be deleted
$this->writer->expects($this->once())
->method('delete')
- ->with([$dir . $field])
+ ->with([$dir . $field->getClientFilename()])
->willReturn([true]);
$behavior->afterDelete(new Event('fake.event'), $this->entity, new ArrayObject());
@@ -550,7 +549,13 @@ public function testAfterDeleteUsesPathProcessorToDetectPathToTheFile()
public function testAfterDeletePrefersStoredPathOverPathProcessor()
{
$dir = '/some/path/';
- $field = 'file.txt';
+ $field = new UploadedFile(
+ fopen('php://temp', 'wb+'),
+ 1,
+ UPLOAD_ERR_OK,
+ 'file.txt',
+ 'text/plain'
+ );
$methods = array_diff($this->behaviorMethods, ['afterDelete', 'config', 'setConfig', 'getConfig']);
$behavior = $this->getMockBuilder('Josegonzalez\Upload\Model\Behavior\UploadBehavior')
@@ -559,19 +564,16 @@ public function testAfterDeletePrefersStoredPathOverPathProcessor()
->getMock();
$behavior->setConfig($this->configOk);
- $this->entity->expects($this->at(0))
+ $this->entity->expects($this->once())
->method('has')
->with('dir')
->will($this->returnValue(true));
- $this->entity->expects($this->at(1))
- ->method('get')
- ->with('dir')
- ->will($this->returnValue($dir));
- $this->entity->expects($this->at(2))
- ->method('get')
- ->with('field')
- ->will($this->returnValue($field));
+ $this->entity->method('get')
+ ->will($this->returnValueMap([
+ ['dir', $dir],
+ ['field', $field],
+ ]));
$behavior->expects($this->never())
->method('getPathProcessor');
$behavior->expects($this->once())
@@ -580,7 +582,7 @@ public function testAfterDeletePrefersStoredPathOverPathProcessor()
$this->writer->expects($this->once())
->method('delete')
- ->with([$dir . $field])
+ ->with([$dir . $field->getClientFilename()])
->will($this->returnValue([true]));
$this->assertTrue($behavior->afterDelete(new Event('fake.event'), $this->entity, new ArrayObject()));
@@ -599,8 +601,12 @@ public function testAfterDeleteNoDeleteCallback()
$this->configOk['field']['deleteCallback'] = null;
$behavior->setConfig($this->configOk);
+ $this->entity->expects($this->any())
+ ->method('get')
+ ->with('field')
+ ->will($this->returnValue($this->dataOk['field']));
$behavior->expects($this->once())->method('getPathProcessor')
- ->with($this->entity, $this->entity->field, 'field', $this->configOk['field'])
+ ->with($this->entity, $this->dataOk['field'], 'field', $this->configOk['field'])
->willReturn($this->processor);
$this->processor->expects($this->once())->method('basepath')
->willReturn($path);
@@ -610,7 +616,7 @@ public function testAfterDeleteNoDeleteCallback()
$this->writer->expects($this->once())
->method('delete')
->with([
- $path . $this->entity->field,
+ $path . $this->entity->field . $this->dataOk['field']->getClientFilename(),
])
->willReturn([true, true, true]);
@@ -636,8 +642,12 @@ public function testAfterDeleteUsesDeleteCallback()
};
$behavior->setConfig($this->configOk);
+ $this->entity->expects($this->any())
+ ->method('get')
+ ->with('field')
+ ->will($this->returnValue($this->dataOk['field']));
$behavior->expects($this->once())->method('getPathProcessor')
- ->with($this->entity, $this->entity->field, 'field', $this->configOk['field'])
+ ->with($this->entity, $this->dataOk['field'], 'field', $this->configOk['field'])
->willReturn($this->processor);
$this->processor->expects($this->once())->method('basepath')
->willReturn($path);
diff --git a/tests/bootstrap.php b/tests/bootstrap.php
index 5ba11a54..3e295d12 100644
--- a/tests/bootstrap.php
+++ b/tests/bootstrap.php
@@ -2,9 +2,12 @@
declare(strict_types=1);
use Cake\Core\Configure;
+use Cake\Datasource\ConnectionManager;
+use Cake\TestSuite\Fixture\SchemaLoader;
+use function Cake\Core\env;
-/*
- * Test suite bootstrap
+/**
+ * Test suite bootstrap.
*
* This function is used to find the location of CakePHP whether CakePHP
* has been installed as a dependency of the plugin, or the plugin is itself
@@ -20,11 +23,26 @@
} while ($root !== $lastRoot);
throw new Exception('Cannot find the root of the application, unable to run tests');
};
-
$root = $findRoot(__FILE__);
unset($findRoot);
chdir($root);
-require $root . '/vendor/cakephp/cakephp/tests/bootstrap.php';
+require_once 'vendor/autoload.php';
+
+define('ROOT', $root . DS . 'tests' . DS . 'test_app' . DS);
+define('APP', ROOT . 'App' . DS);
+define('TMP', sys_get_temp_dir() . DS);
+define('CONFIG', ROOT . DS . 'config' . DS);
+
+if (!getenv('DB_URL')) {
+ putenv('DB_URL=sqlite:///:memory:');
+}
+ConnectionManager::setConfig('test', ['url' => getenv('DB_URL')]);
+
+Configure::write('App.namespace', 'Josegonzalez\Upload\Test\TestApp');
-Configure::write('Error.ignoredDeprecationPaths', ['src/TestSuite/Fixture/FixtureInjector.php']);
+// Create test database schema
+if (env('FIXTURE_SCHEMA_METADATA')) {
+ $loader = new SchemaLoader();
+ $loader->loadInternalFile(env('FIXTURE_SCHEMA_METADATA'));
+}
diff --git a/tests/schema.php b/tests/schema.php
new file mode 100644
index 00000000..37da7c83
--- /dev/null
+++ b/tests/schema.php
@@ -0,0 +1,19 @@
+ 'files',
+ 'columns' => [
+ 'id' => ['type' => 'integer'],
+ 'filename' => ['type' => 'string'],
+ 'created' => ['type' => 'datetime', 'null' => true],
+ ],
+ 'constraints' => [
+ 'primary' => [
+ 'type' => 'primary',
+ 'columns' => ['id'],
+ ],
+ ],
+ ],
+];