Add validator for directory and file

master 3.3.0
Julien Rosset 2 years ago
parent 73c12fc82f
commit 75a40b9c86

@ -0,0 +1,106 @@
<?php
namespace jrosset\CliProgram\Validation\Validators;
use InvalidArgumentException;
use jrosset\Collections\Collection;
use jrosset\Collections\ICollection;
use Stringable;
/**
* An argument/option value validator for a directory path
*/
class DirectoryValidator implements IValidator {
use TInternalValueValidator;
/**
* @var ICollection<FilesystemValidationOption> The options
*/
private ICollection $options;
/**
* Initialization
*
* @param ICollection<FilesystemValidationOption>|FilesystemValidationOption[]|FilesystemValidationOption|null $options The options
*/
public function __construct (ICollection|array|FilesystemValidationOption|null $options = null) {
$this->setOptions($options);
}
/**
* Get a valid default value from the initial/given default value
*
* @param string|Stringable|null $default The initial/given default value
*
* @return string|bool|int|float|array|null The valid default value
*
* @throws InvalidArgumentException If the default value is not a string or null
* @throws InvalidArgumentException If the default directory doesn't match the options
*/
public function getValidDefault (mixed $default): string|bool|int|float|array|null {
if ($default === null) {
return null;
}
if (!is_string($default) && !$default instanceof Stringable) {
throw new InvalidArgumentException('The default value must be a string or null');
}
if ($this->getOptions()->contains(FilesystemValidationOption::IsReadable) && !is_readable($default)) {
throw new InvalidArgumentException('The default value is not readable');
}
if ($this->getOptions()->contains(FilesystemValidationOption::IsWritable) && !is_writable($default)) {
throw new InvalidArgumentException('The default value is not writable');
}
if ($this->getOptions()->contains(FilesystemValidationOption::MustExists) && !file_exists($default)) {
throw new InvalidArgumentException('The default value doesn\'t exist');
}
return $default;
}
/**
* @inheritDoc
*/
public function validate (mixed $value): bool {
if (!is_string($value) && !$value instanceof Stringable) {
return false;
}
if ($this->getOptions()->contains(FilesystemValidationOption::IsReadable) && !is_readable($value)) {
return false;
}
if ($this->getOptions()->contains(FilesystemValidationOption::IsWritable) && !is_writable($value)) {
return false;
}
if ($this->getOptions()->contains(FilesystemValidationOption::MustExists) && !file_exists($value)) {
return false;
}
$this->setValue($value);
return true;
}
/**
* The options
*
* @return ICollection<FilesystemValidationOption> The options
*/
public function getOptions (): ICollection {
return $this->options;
}
/**
* Replace the options
*
* @param ICollection<FilesystemValidationOption>|FilesystemValidationOption[]|FilesystemValidationOption|null $options The options
*
* @return $this
*/
public function setOptions (ICollection|array|FilesystemValidationOption|null $options = null): static {
$this->options = match (true) {
$options instanceof ICollection => $options,
$options instanceof FilesystemValidationOption => new Collection([$options]),
is_array($options) => new Collection($options),
$options === null => new Collection(),
};
return $this;
}
}

@ -0,0 +1,72 @@
<?php
namespace jrosset\CliProgram\Validation\Validators;
use InvalidArgumentException;
use jrosset\Collections\ICollection;
/**
* An argument/option value validator for a file path
*/
class FileValidator extends DirectoryValidator {
/**
* @var string|null The allowed extensions (regex pattern)
*/
private ?string $extensionsPattern;
/**
* Initialization
*
* @param string|null $extensionsPattern The allowed extensions (regex pattern)
* @param ICollection<FilesystemValidationOption>|FilesystemValidationOption[]|FilesystemValidationOption|null $options The options
*/
public function __construct (?string $extensionsPattern = null, ICollection|FilesystemValidationOption|array|null $options = null) {
parent::__construct($options);
$this->setExtensionsPattern($extensionsPattern);
}
/**
* @inheritDoc
*/
public function getValidDefault (mixed $default): string|bool|int|float|array|null {
if (($default = parent::getValidDefault($default)) === null) {
return null;
}
if ($this->extensionsPattern !== null && preg_match($this->extensionsPattern, $default) !== 1) {
throw new InvalidArgumentException('The default value has not a valid extension');
}
return $default;
}
/**
* @inheritDoc
*/
public function validate (mixed $value): bool {
if (!parent::validate($value)) {
return false;
}
if ($this->extensionsPattern !== null && preg_match($this->extensionsPattern, $value) !== 1) {
return false;
}
return true;
}
/**
* The allowed extensions (regex pattern)
*
* @return string|null The allowed extensions (regex pattern)
*/
public function getExtensionsPattern (): ?string {
return $this->extensionsPattern;
}
/**
* Replace the allowed extensions
*
* @param string|null $extensionsPattern The allowed extensions (regex pattern)
*
* @return $this
*/
public function setExtensionsPattern (?string $extensionsPattern = null): static {
$this->extensionsPattern = $extensionsPattern;
return $this;
}
}

@ -0,0 +1,12 @@
<?php
namespace jrosset\CliProgram\Validation\Validators;
/**
* Options of a filesystem based validator
*/
enum FilesystemValidationOption {
case MustExists;
case IsReadable;
case IsWritable;
}

@ -0,0 +1,47 @@
<?php
namespace jrosset\Tests\Commands;
use jrosset\CliProgram\Validation\CommandWithValidation;
use jrosset\CliProgram\Validation\Validators\FilesystemValidationOption;
use jrosset\CliProgram\Validation\Validators\FileValidator;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class ReadFile extends CommandWithValidation {
/**
* @inheritdoc
*/
protected static $defaultDescription = 'Read a file';
/**
* @inheritDoc
*/
protected function configure (): void {
parent::configure();
$this->addArgument(
'file',
InputArgument::REQUIRED,
'The file to read',
null,
new FileValidator(
/** @lang PhpRegExp */ '#\.txt$#i',
FilesystemValidationOption::IsReadable
)
);
}
/**
* @inheritDoc
*/
protected function execute (InputInterface $input, OutputInterface $output): int {
if (($fileContent = file_get_contents($input->getArgument('file'))) === false) {
return Command::FAILURE;
}
$output->writeln($fileContent);
return Command::SUCCESS;
}
}

@ -0,0 +1 @@
This is a file
Loading…
Cancel
Save