Skip to content

Commit

Permalink
refactor: Refactor plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
tienvx committed Apr 6, 2024
1 parent c8ce108 commit b15b9dd
Show file tree
Hide file tree
Showing 50 changed files with 1,300 additions and 30 deletions.
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
}
],
"require": {
"composer-plugin-api": "^2.0",
"composer-plugin-api": "^2.1",
"php": "^8.1",
"leongrdic/smplang": "^1.0.2",
"symfony/filesystem": "^5.4 || ^6.4 || ^7.0",
Expand All @@ -42,6 +42,6 @@
}
},
"extra": {
"class": "LastCall\\DownloadsPlugin\\Plugin"
"class": "LastCall\\DownloadsPlugin\\Composer\\Plugin\\ExtraDownloadsPlugin"
}
}
39 changes: 39 additions & 0 deletions src/Attribute/AttributeManager.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

namespace LastCall\DownloadsPlugin\Attribute;

use LastCall\DownloadsPlugin\Attribute\Validator\ValidatorInterface;
use LastCall\DownloadsPlugin\Enum\Attribute;
use LastCall\DownloadsPlugin\Exception\OutOfRangeException;

class AttributeManager implements AttributeManagerInterface
{
/**
* @var ValidatorInterface[]
*/
private array $validators = [];

private array $values = [];

public function __construct(private array $attributes)
{
}

public function addValidator(ValidatorInterface $validator): void
{
$this->validators[$validator->getAttribute()] = $validator;
}

public function get(Attribute $attribute): mixed
{
if (isset($this->values[$attribute->value])) {
return $this->values[$attribute->value];
}

if (!isset($this->validators[$attribute->value])) {
throw new OutOfRangeException(sprintf('Validator "%s" not found.', $attribute->value));
}

return $this->values[$attribute->value] = $this->validators[$attribute->value]->validate($this->attributes[$attribute->value] ?? null);
}
}
13 changes: 13 additions & 0 deletions src/Attribute/AttributeManagerInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace LastCall\DownloadsPlugin\Attribute;

use LastCall\DownloadsPlugin\Attribute\Validator\ValidatorInterface;
use LastCall\DownloadsPlugin\Enum\Attribute;

interface AttributeManagerInterface
{
public function addValidator(ValidatorInterface $validator): void;

public function get(Attribute $attribute): mixed;
}
53 changes: 53 additions & 0 deletions src/Attribute/Validator/ExecutableValidator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php

namespace LastCall\DownloadsPlugin\Attribute\Validator;

use LastCall\DownloadsPlugin\Attribute\AttributeManagerInterface;
use LastCall\DownloadsPlugin\Enum\Attribute;
use LastCall\DownloadsPlugin\Enum\Type;
use LastCall\DownloadsPlugin\Exception\InvalidAttributeException;

class ExecutableValidator implements ValidatorInterface
{
private array $executable;

public function __construct(
private string $parentPath,
private AttributeManagerInterface $attributeManager,
private PathValidator $pathValidator
) {
}

public function validate(mixed $values): array
{
$type = $this->attributeManager->get(Attribute::TYPE);
if (!$type->isArchive()) {
if (null !== $values && !\is_bool($values)) {
throw new InvalidAttributeException(sprintf('Attribute "%s" must be boolean, "%s" given', $this->getAttribute(), get_debug_type($values)));
}

if (Type::PHAR === $type) {
if (null !== $values && true !== $values) {
throw new InvalidAttributeException(sprintf('Attribute "%s" must be true, "%s" given', $this->getAttribute(), get_debug_type($values)));
} else {
$values = true;
}
}

return $values ? [$this->attributeManager->get(Attribute::PATH)] : [];
}

$values ??= [];
if (!\is_array($values)) {
throw new InvalidAttributeException(sprintf('Attribute "%s" must be array, "%s" given', $this->getAttribute(), get_debug_type($values)));
}
array_walk($values, fn (mixed $value) => $this->pathValidator->validate($value));

return $values;
}

public function getAttribute(): string
{
return Attribute::EXECUTABLE->value;
}
}
42 changes: 42 additions & 0 deletions src/Attribute/Validator/HashValidator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

namespace LastCall\DownloadsPlugin\Attribute\Validator;

use LastCall\DownloadsPlugin\Enum\Attribute;
use LastCall\DownloadsPlugin\Exception\InvalidAttributeException;
use LastCall\DownloadsPlugin\Model\Hash;

class HashValidator implements ValidatorInterface
{
public function validate(mixed $values): ?Hash
{
if (null === $values) {
return null;
}

if (!\is_array($values)) {
throw new InvalidAttributeException(sprintf('Attribute "%s" must be array, "%s" given', $this->getAttribute(), get_debug_type($values)));
}

$algo = $values['algo'] ?? null;
if (!\is_string($algo)) {
throw new InvalidAttributeException(sprintf('Attribute "%s > algo" must be string, "%s" given', $this->getAttribute(), get_debug_type($algo)));
}

if (!\in_array($algo, hash_algos(), true)) {
throw new InvalidAttributeException(sprintf('Attribute "%s > algo" is not supported', $this->getAttribute()));
}

$value = $values['value'] ?? null;
if (!\is_string($value)) {
throw new InvalidAttributeException(sprintf('Attribute "%s > value" must be string, "%s" given', $this->getAttribute(), get_debug_type($value)));
}

return new Hash($algo, $value);
}

public function getAttribute(): string
{
return Attribute::HASH->value;
}
}
40 changes: 40 additions & 0 deletions src/Attribute/Validator/IgnoreValidator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

namespace LastCall\DownloadsPlugin\Attribute\Validator;

use LastCall\DownloadsPlugin\Attribute\AttributeManagerInterface;
use LastCall\DownloadsPlugin\Enum\Attribute;
use LastCall\DownloadsPlugin\Exception\InvalidAttributeException;

class IgnoreValidator implements ValidatorInterface
{
public function __construct(private AttributeManagerInterface $attributeManager)
{
}

public function validate(mixed $values): array
{
if (!$this->attributeManager->get(Attribute::TYPE)->isArchive() || null === $values) {
return [];
}

if (!\is_array($values)) {
throw new InvalidAttributeException(sprintf('Attribute "%s" must be array, "%s" given', $this->getAttribute(), get_debug_type($values)));
}

$ignores = [];
foreach ($values as $value) {
if (!\is_string($value)) {
throw new InvalidAttributeException(sprintf('Attribute "%s" must be array of string', $this->getAttribute()));
}
$ignores[] = strtr($value, $this->attributeManager->get(Attribute::VARIABLES));
}

return $ignores;
}

public function getAttribute(): string
{
return Attribute::IGNORE->value;
}
}
42 changes: 42 additions & 0 deletions src/Attribute/Validator/PathValidator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

namespace LastCall\DownloadsPlugin\Attribute\Validator;

use LastCall\DownloadsPlugin\Attribute\AttributeManagerInterface;
use LastCall\DownloadsPlugin\Enum\Attribute;
use LastCall\DownloadsPlugin\Exception\InvalidAttributeException;
use Symfony\Component\Filesystem\Path;

class PathValidator implements ValidatorInterface
{
public function __construct(private string $parentPath, private AttributeManagerInterface $attributeManager, private string $attribute = 'path')
{
}

public function validate(mixed $value): string
{
if (null === $value) {
throw new InvalidAttributeException(sprintf('Attribute "%s" is required', $this->getAttribute()));
}

if (!\is_string($value)) {
throw new InvalidAttributeException(sprintf('Attribute "%s" must be string, "%s" given', $this->getAttribute(), get_debug_type($value)));
}

$path = strtr($value, $this->attributeManager->get(Attribute::VARIABLES));
if (Path::isAbsolute($path)) {
throw new InvalidAttributeException(sprintf('Attribute "%s" must be relative path', $this->getAttribute()));
}

if (!Path::isBasePath($this->parentPath, $this->parentPath.\DIRECTORY_SEPARATOR.$path)) {
throw new InvalidAttributeException(sprintf("Attribute \"%s\" must be inside relative to parent package's path", $this->getAttribute()));
}

return $path;
}

public function getAttribute(): string
{
return $this->attribute;
}
}
53 changes: 53 additions & 0 deletions src/Attribute/Validator/TypeValidator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php

namespace LastCall\DownloadsPlugin\Attribute\Validator;

use LastCall\DownloadsPlugin\Attribute\AttributeManagerInterface;
use LastCall\DownloadsPlugin\Enum\Attribute;
use LastCall\DownloadsPlugin\Enum\Type;
use LastCall\DownloadsPlugin\Exception\InvalidAttributeException;

class TypeValidator implements ValidatorInterface
{
public function __construct(private AttributeManagerInterface $attributeManager)
{
}

public function validate(mixed $value): Type
{
if (null === $value) {
return $this->parseUrl();
}

if (!\is_string($value)) {
throw new InvalidAttributeException(sprintf('Attribute "%s" must be string, "%s" given', $this->getAttribute(), get_debug_type($value)));
}

$type = Type::tryFrom($value);
if (null === $type) {
throw new InvalidAttributeException(sprintf('Attribute "%s" is not supported', $this->getAttribute()));
}

return $type;
}

public function getAttribute(): string
{
return Attribute::TYPE->value;
}

private function parseUrl(): Type
{
$parts = parse_url($this->attributeManager->get(Attribute::URL));
$filename = pathinfo($parts['path'], \PATHINFO_BASENAME);
if (preg_match('/\.(tar\.gz|tar\.bz2)$/', $filename)) {
return Type::from('tar');
}
if (preg_match('/\.tar\.xz$/', $filename)) {
return Type::from('xz');
}
$extension = pathinfo($parts['path'], \PATHINFO_EXTENSION);

return Type::fromExtension($extension);
}
}
41 changes: 41 additions & 0 deletions src/Attribute/Validator/UrlValidator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

namespace LastCall\DownloadsPlugin\Attribute\Validator;

use LastCall\DownloadsPlugin\Attribute\AttributeManagerInterface;
use LastCall\DownloadsPlugin\Enum\Attribute;
use LastCall\DownloadsPlugin\Exception\InvalidAttributeException;

class UrlValidator implements ValidatorInterface
{
public function __construct(private AttributeManagerInterface $attributeManager)
{
}

public function validate(mixed $value): string
{
if (null === $value) {
throw new InvalidAttributeException(sprintf('Attribute "%s" is required', $this->getAttribute()));
}

if (!\is_string($value)) {
throw new InvalidAttributeException(sprintf('Attribute "%s" must be string, "%s" given', $this->getAttribute(), get_debug_type($value)));
}

$url = strtr($value, $this->attributeManager->get(Attribute::VARIABLES));
if (false === filter_var($url, \FILTER_VALIDATE_URL)) {
throw new InvalidAttributeException(sprintf('Attribute "%s" is invalid url', $this->getAttribute()));
}

if (!\in_array(parse_url($url, \PHP_URL_SCHEME), ['http', 'https'])) {
throw new InvalidAttributeException(sprintf('Attribute "%s" has invalid scheme. Only http and https are allowed', $this->getAttribute()));
}

return $url;
}

public function getAttribute(): string
{
return Attribute::URL->value;
}
}
10 changes: 10 additions & 0 deletions src/Attribute/Validator/ValidatorInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace LastCall\DownloadsPlugin\Attribute\Validator;

interface ValidatorInterface
{
public function validate(mixed $value): mixed;

public function getAttribute(): string;
}
Loading

0 comments on commit b15b9dd

Please sign in to comment.