diff --git a/.github/workflows/PhpUnit-MacOs.yaml b/.github/workflows/PhpUnit-MacOs.yaml index aed82a1..d15e217 100644 --- a/.github/workflows/PhpUnit-MacOs.yaml +++ b/.github/workflows/PhpUnit-MacOs.yaml @@ -10,10 +10,10 @@ jobs: - uses: actions/checkout@v2 - uses: shivammathur/setup-php@v2 with: - php-version: '8.0' + php-version: '8.2' extensions: bcmath coverage: xdebug - tools: phpunit:9 + tools: phpunit - name: Run PHPUnit run: phpunit -c FeastTests/githubphpunit.xml --coverage-clover coverage.xml \ No newline at end of file diff --git a/.github/workflows/PhpUnit-Win.yaml b/.github/workflows/PhpUnit-Win.yaml index 1fd4101..9adf0db 100644 --- a/.github/workflows/PhpUnit-Win.yaml +++ b/.github/workflows/PhpUnit-Win.yaml @@ -10,10 +10,10 @@ jobs: - uses: actions/checkout@v2 - uses: shivammathur/setup-php@v2 with: - php-version: '8.0' + php-version: '8.2' extensions: bcmath coverage: xdebug - tools: phpunit:9 + tools: phpunit - name: Run PHPUnit run: phpunit -c FeastTests/githubphpunit.xml --coverage-clover coverage.xml \ No newline at end of file diff --git a/.github/workflows/PhpUnit.yaml b/.github/workflows/PhpUnit.yaml index 4d1135a..10e714d 100644 --- a/.github/workflows/PhpUnit.yaml +++ b/.github/workflows/PhpUnit.yaml @@ -10,10 +10,10 @@ jobs: - uses: actions/checkout@v2 - uses: shivammathur/setup-php@v2 with: - php-version: '8.0' + php-version: '8.2' extensions: bcmath coverage: xdebug - tools: phpunit:9 + tools: phpunit - name: Run PHPUnit run: phpunit -c FeastTests/githubphpunit.xml --coverage-clover coverage.xml - uses: codecov/codecov-action@v1 diff --git a/.github/workflows/Psalm.yaml b/.github/workflows/Psalm.yaml index 2971b9f..b45f209 100644 --- a/.github/workflows/Psalm.yaml +++ b/.github/workflows/Psalm.yaml @@ -10,7 +10,7 @@ jobs: - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: '8.0' + php-version: '8.2' - name: Checkout project uses: actions/checkout@v2 diff --git a/Attributes/AccessControl.php b/Attributes/AccessControl.php index 7dbf094..8460c44 100644 --- a/Attributes/AccessControl.php +++ b/Attributes/AccessControl.php @@ -23,7 +23,7 @@ use Attribute; #[Attribute(Attribute::TARGET_METHOD)] -class AccessControl +readonly class AccessControl { /** * AccessControl constructor. diff --git a/Attributes/Action.php b/Attributes/Action.php index 36f2ad0..7964d45 100644 --- a/Attributes/Action.php +++ b/Attributes/Action.php @@ -23,10 +23,8 @@ use Attribute; #[Attribute(Attribute::TARGET_METHOD)] -class Action +readonly class Action { - protected array $params = []; - public function __construct(public string $usage = '', public string $description = '') { } diff --git a/Attributes/JsonItem.php b/Attributes/JsonItem.php index 0e5b5bb..6300c99 100644 --- a/Attributes/JsonItem.php +++ b/Attributes/JsonItem.php @@ -24,7 +24,7 @@ use Feast\Date; #[Attribute(Attribute::TARGET_PROPERTY)] -class JsonItem +readonly class JsonItem { /** * JsonItem constructor. diff --git a/Attributes/JsonParam.php b/Attributes/JsonParam.php index 3675f99..bb12c8b 100644 --- a/Attributes/JsonParam.php +++ b/Attributes/JsonParam.php @@ -23,7 +23,7 @@ use Attribute; #[Attribute(Attribute::TARGET_PARAMETER)] -class JsonParam +readonly class JsonParam { public function __construct(public string $key = '') { diff --git a/Attributes/Param.php b/Attributes/Param.php index 68c7f73..141fb1f 100644 --- a/Attributes/Param.php +++ b/Attributes/Param.php @@ -25,13 +25,13 @@ use Feast\Terminal; #[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] -class Param +readonly class Param { public function __construct( public string $type = '', public string $name = '', public string $description = '', - public string $paramType = ParamType::PARAM + public ParamType $paramType = ParamType::PARAM ) { } diff --git a/Attributes/Path.php b/Attributes/Path.php index 65a3250..5e8f624 100644 --- a/Attributes/Path.php +++ b/Attributes/Path.php @@ -24,14 +24,14 @@ use Feast\Enums\RequestMethod; #[Attribute(Attribute::TARGET_METHOD)] -class Path +readonly class Path { - public const METHOD_GET = 1; - public const METHOD_POST = 2; - public const METHOD_PUT = 4; - public const METHOD_DELETE = 8; - public const METHOD_PATCH = 16; - public const METHOD_ALL = self::METHOD_GET | self::METHOD_POST | self::METHOD_PUT | self::METHOD_DELETE | self::METHOD_PATCH; + final public const METHOD_GET = 1; + final public const METHOD_POST = 2; + final public const METHOD_PUT = 4; + final public const METHOD_DELETE = 8; + final public const METHOD_PATCH = 16; + final public const METHOD_ALL = self::METHOD_GET | self::METHOD_POST | self::METHOD_PUT | self::METHOD_DELETE | self::METHOD_PATCH; /** * Path constructor. @@ -50,7 +50,7 @@ public function __construct( } /** - * @return array + * @return array */ public function getMethods(): array { diff --git a/BaseMapper.php b/BaseMapper.php index bacb131..176a951 100644 --- a/BaseMapper.php +++ b/BaseMapper.php @@ -42,7 +42,7 @@ abstract class BaseMapper /** @var string|null SEQUENCE_NAME */ protected const SEQUENCE_NAME = null; public const CONNECTION = 'default'; - public const NOT_NULL = 'not_null'; + final public const NOT_NULL = 'not_null'; protected DatabaseInterface $connection; /** diff --git a/BaseModel.php b/BaseModel.php index ad78fdf..92e2176 100755 --- a/BaseModel.php +++ b/BaseModel.php @@ -20,6 +20,7 @@ namespace Feast; +use Feast\Enums\ResponseCode; use Feast\Attributes\JsonItem; use Feast\Exception\InvalidOptionException; use Feast\Exception\NotFoundException; @@ -39,7 +40,7 @@ abstract class BaseModel */ public function __set(string $name, mixed $value): void { - throw new InvalidOptionException('Invalid option for model', 500); + throw new InvalidOptionException('Invalid option for model', ResponseCode::HTTP_CODE_500); } /** @@ -47,7 +48,7 @@ public function __set(string $name, mixed $value): void */ public function __get(string $name): void { - throw new InvalidOptionException('Invalid option for model', 500); + throw new InvalidOptionException('Invalid option for model', ResponseCode::HTTP_CODE_500); } /** diff --git a/Binary.php b/Binary.php index 231caac..22b5616 100644 --- a/Binary.php +++ b/Binary.php @@ -244,7 +244,7 @@ private function processCliMethods(ReflectionMethod $method): void /** * Process custom actions built into Feast. Defaults to all classes. * - * @param array $classes + * @param array $classes * @throws ReflectionException */ private function analyzeFeast( diff --git a/CliArguments.php b/CliArguments.php index 7a9295b..5241283 100644 --- a/CliArguments.php +++ b/CliArguments.php @@ -25,7 +25,7 @@ class CliArguments implements ServiceContainerItemInterface { - public function __construct(protected array $arguments) + public function __construct(protected array $arguments = []) { } diff --git a/CliController.php b/CliController.php index caf76aa..5332eb8 100755 --- a/CliController.php +++ b/CliController.php @@ -28,7 +28,6 @@ abstract class CliController implements ControllerInterface { protected Terminal $terminal; - protected CliArguments $cliArguments; /** * @throws NotFoundException @@ -36,12 +35,11 @@ abstract class CliController implements ControllerInterface public function __construct( ServiceContainer $di, ?ConfigInterface $config = null, - ?CliArguments $cliArguments = null + protected CliArguments $cliArguments = new CliArguments() ) { $config ??= $di->get(ConfigInterface::INTERFACE_NAME); - $this->cliArguments = $cliArguments ?? new CliArguments([]); /** @var bool|null $setting */ - $setting = $config->getSetting('ttycolor', null); + $setting = $config->getSetting('ttycolor'); $this->terminal = new Terminal($setting); } diff --git a/Config/Config.php b/Config/Config.php index ba446a5..6f3845c 100755 --- a/Config/Config.php +++ b/Config/Config.php @@ -20,11 +20,13 @@ namespace Feast\Config; +use BackedEnum; use Feast\Collection\CollectionList; use Feast\Exception\ConfigException; use Feast\Exception\ServerFailureException; use Feast\Interfaces\ConfigInterface; use Feast\ServiceContainer\ContainerException; +use Feast\ServiceContainer\NotFoundException; use Feast\ServiceContainer\ServiceContainerItemInterface; use Feast\Traits\DependencyInjected; use stdClass; @@ -45,7 +47,7 @@ class Config implements ServiceContainerItemInterface, ConfigInterface * * @param bool $pullFromContainer - True to check if already in service container * @param string|null $overriddenEnvironment - if set, the environment will be the one passed in - * @throws ServerFailureException|ContainerException + * @throws ServerFailureException|ContainerException|NotFoundException */ public function __construct(bool $pullFromContainer = true, string $overriddenEnvironment = null) { @@ -371,7 +373,7 @@ private function cloneObjectOrArrayAsObject(stdClass|array $settings): stdClass /** * @psalm-suppress PossibleRawObjectIteration * @var string $key - * @var scalar|array|stdClass $val + * @var scalar|array|stdClass|BackedEnum $val */ foreach ($settings as $key => $val) { if (is_array($val) || $val instanceof stdClass) { @@ -390,7 +392,7 @@ private function objectToArray(stdClass|array $settings): array /** * @psalm-suppress PossibleRawObjectIteration * @var string $key - * @var scalar|array|stdClass $val + * @var scalar|array|stdClass|BackedEnum $val */ foreach ($settings as $key => $val) { if (is_array($val) || $val instanceof stdClass) { diff --git a/Controllers/JobController.php b/Controllers/JobController.php index 5dba06d..11824b7 100644 --- a/Controllers/JobController.php +++ b/Controllers/JobController.php @@ -50,7 +50,8 @@ class JobController extends CliController * @param positive-int $wait * @param bool $exitLoop * @return void - * @throws Exception + * @throws \Feast\Exception\ServerFailureException + * @throws \Feast\ServiceContainer\NotFoundException */ #[Action(usage: '--keepalive={true|false} {queues}', description: 'Listen for and run all jobs on one or more queues.')] #[Param(type: 'string', name: 'queues', description: 'Name of queues to monitor, pipe delimited')] @@ -75,7 +76,7 @@ public function listenGet( do { $job = $jobMapper->findOnePendingByQueues($queueList); if ($job instanceof Job && !file_exists(APPLICATION_ROOT . DIRECTORY_SEPARATOR . 'maintenance.txt')) { - $this->runJob($job, $errorLogger,$logger, $jobMapper); + $this->runJob($job, $errorLogger, $logger, $jobMapper); } else { $this->terminal->command('No jobs found. ', false); if ($keepalive) { @@ -182,10 +183,13 @@ public function runCronItemGet( /** * @throws Exception */ - protected function runJob(Job $job, ErrorLoggerInterface $errorLogger, LoggerInterface $logger, JobMapper $jobMapper): bool - { - /** @psalm-suppress DeprecatedMethod @todo: switch to markJobRunningIfAble */ - $canRun = $jobMapper->markJobPendingIfAble($job); + protected function runJob( + Job $job, + ErrorLoggerInterface $errorLogger, + LoggerInterface $logger, + JobMapper $jobMapper + ): bool { + $canRun = $jobMapper->markJobRunningIfAble($job); if ($canRun === false) { $logger->error('Could not lock job ' . $job->job_id . '.'); $this->terminal->error('Could not lock job ' . $job->job_id . '.'); diff --git a/Controllers/MigrationController.php b/Controllers/MigrationController.php index 7e0003e..5158da1 100644 --- a/Controllers/MigrationController.php +++ b/Controllers/MigrationController.php @@ -33,7 +33,7 @@ class MigrationController extends WriteTemplateController { - protected const MIGRATION_TABLE_MIGRATION = '1_migrations'; + final protected const MIGRATION_TABLE_MIGRATION = '1_migrations'; /** @var array $migrationsByName */ protected array $migrationsByName = []; /** @var array $migrationsByNumber */ diff --git a/Csv/CsvReader.php b/Csv/CsvReader.php index 4d5ca8f..fdd6c5e 100644 --- a/Csv/CsvReader.php +++ b/Csv/CsvReader.php @@ -91,8 +91,9 @@ public function getNextLine(): array|false $this->buildHeader(); } $return = []; + /** @var array|false $row */ $row = $this->file->fgetcsv(); - if ($row === null || $row === false) { + if ($row === false) { return false; } diff --git a/Database/Database.php b/Database/Database.php index b404388..56c0f15 100644 --- a/Database/Database.php +++ b/Database/Database.php @@ -42,30 +42,40 @@ class Database implements DatabaseInterface use DebugQuery; private PDO $connection; - private string $databaseType; + private DatabaseType $databaseType; private string $queryClass; - private LoggerInterface $logger; private string $escapeCharacter; /** * @param stdClass $connectionDetails * @param string $pdoClass - * @param LoggerInterface|null $logger - * @throws DatabaseException + * @param LoggerInterface $logger * @throws InvalidOptionException * @throws ServerFailureException - * @throws \Feast\ServiceContainer\NotFoundException */ - public function __construct(stdClass $connectionDetails, string $pdoClass, ?LoggerInterface $logger) - { - $logger ??= di(LoggerInterface::INTERFACE_NAME); - $this->logger = $logger; - + public function __construct( + #[\SensitiveParameter] + stdClass $connectionDetails, + string $pdoClass, + private readonly LoggerInterface $logger + ) { $username = (string)$connectionDetails->user; $password = (string)$connectionDetails->pass; - $this->databaseType = (string)$connectionDetails->connectionType; - /** @psalm-suppress DeprecatedMethod (will be removed in 2.0) */ - $this->queryClass = (string)($connectionDetails->queryClass ?? $this->getQueryClass()); + /** @var DatabaseType */ + $this->databaseType = $connectionDetails->connectionType; + $queryClass = (string)($connectionDetails->queryClass ?? ''); + if ($queryClass === '') { + throw new InvalidOptionException( + 'queryClass not passed in. Expected a class that inherits \Feast\Database\Query ' + ); + } + if (!class_exists($queryClass)) { + throw new InvalidOptionException('queryClass ' . $queryClass . ' not found.'); + } + if (!is_subclass_of($queryClass, Query::class)) { + throw new InvalidOptionException('queryClass ' . $queryClass . ' does not extend \Feast\Database\Query.'); + } + $this->queryClass = $queryClass; $options = $this->getConfigOptions($connectionDetails); // Get connection string @@ -191,26 +201,6 @@ private function startQuery(): Query return new ($this->queryClass)($this->connection, $this->logger); } - /** - * Get Query class from DatabaseType (Deprecated) - * - * @return string - * @throws DatabaseException - * @deprecated - */ - public function getQueryClass(): string - { - trigger_error( - 'The method ' . self::class . '::getQueryClass is deprecated. Set the queryClass option in your database config.', - E_USER_DEPRECATED - ); - return match ($this->databaseType) { - DatabaseType::MYSQL => MySQLQuery::class, - DatabaseType::SQLITE => SQLiteQuery::class, - default => throw new DatabaseException('Invalid Database Type') - }; - } - /** * Return true if transaction running, otherwise false. * @@ -381,7 +371,6 @@ public function rawQuery(string $query, array $bindings = [], bool $forceEmulate * @param string $hostname * @param int $port * @return string - * @throws ServerFailureException */ private function getConnectionString(string $database, string $hostname = 'localhost', int $port = 3306): string { @@ -391,18 +380,16 @@ private function getConnectionString(string $database, string $hostname = 'local DatabaseType::SQLITE => sprintf('sqlite:%s', $database), DatabaseType::POSTGRES => - sprintf('pgsql:host=%s;port=%s;dbname=%s', $hostname, $port, $database), - default => - throw new DatabaseException('Invalid Database type') + sprintf('pgsql:host=%s;port=%s;dbname=%s', $hostname, $port, $database) }; } /** * Get Database type. * - * @return string + * @return DatabaseType */ - public function getDatabaseType(): string + public function getDatabaseType(): DatabaseType { return $this->databaseType; } diff --git a/Database/DatabaseFactory.php b/Database/DatabaseFactory.php index e199de9..043e837 100644 --- a/Database/DatabaseFactory.php +++ b/Database/DatabaseFactory.php @@ -20,6 +20,7 @@ namespace Feast\Database; +use Feast\Enums\ResponseCode; use Feast\Exception\DatabaseException; use Feast\Exception\ServerFailureException; use Feast\Interfaces\ConfigInterface; @@ -75,7 +76,7 @@ public function getConnection(string $connection = self::DEFAULT_CONNECTION, ?Lo return $connectionObject; } - throw new DatabaseException('Invalid Database Specified', 500, 500); + throw new DatabaseException('Invalid Database Specified', ResponseCode::HTTP_CODE_500, 500); } /** diff --git a/Database/MySQLQuery.php b/Database/MySQLQuery.php index 87ea2ed..b0f85c3 100644 --- a/Database/MySQLQuery.php +++ b/Database/MySQLQuery.php @@ -217,8 +217,6 @@ protected function whereToString(string $sql): string $sql .= '(' . $where['statement'] . ') and '; if (is_array($where['bindings'])) { $this->bindings = array_merge($this->bindings, array_values($where['bindings'])); - } elseif ($where['bindings'] !== null) { - $this->bindings[] = $where['bindings']; } } $sql = substr($sql, 0, -5); @@ -249,8 +247,6 @@ protected function havingToString(string $sql): string $havingBinding = $having['bindings']; if (is_array($havingBinding)) { $this->bindings = array_merge($this->bindings, array_values($havingBinding)); - } else { - $this->bindings[] = $havingBinding; } } $sql = substr($sql, 0, -5); diff --git a/Database/Query.php b/Database/Query.php index 8554564..af0bece 100755 --- a/Database/Query.php +++ b/Database/Query.php @@ -33,7 +33,7 @@ abstract class Query { use DebugQuery; - + public const DIRECTION_ASC = 'ASC'; public const DIRECTION_DESC = 'DESC'; public const JOIN_INNER = 'INNER JOIN'; @@ -71,25 +71,21 @@ public function __construct(protected PDO $database, ?LoggerInterface $logger = /** * Add where clause. * - * Bindings can be a scalar or Feast\Date or an array for multiple bindings. + * Bindings can be a scalar or Feast\Date and are variadic for multiple bindings. * * @param string $statement - * @param Date|string|int|bool|float|array|null $bindings + * @param Date|string|int|bool|float|null ...$bindings * @return static */ - public function where(string $statement, Date|string|int|bool|float|array|null $bindings = null): static + public function where(string $statement, Date|string|int|bool|float|null ...$bindings): static { - if ( is_bool($bindings) ) { - $bindings = $bindings ? 'true' : 'false'; - } elseif (is_array($bindings) ) { - $newBinding = []; - /** @var Date|string|int|bool|float|null $binding */ - foreach ($bindings as $binding) { - $newBinding[] = $this->filterBinding($binding); - } - $bindings = $newBinding; + $newBinding = []; + /** @var Date|string|int|bool|float|null $binding */ + foreach ($bindings as $binding) { + $newBinding[] = $this->filterBinding($binding); } - $this->where[] = ['statement' => $statement, 'bindings' => $bindings]; + + $this->where[] = ['statement' => $statement, 'bindings' => $newBinding]; return $this; } @@ -97,25 +93,21 @@ public function where(string $statement, Date|string|int|bool|float|array|null $ /** * Add having clause. * - * Bindings can be a scalar or an array for multiple bindings. + * Bindings can be a scalar or Feast\Date and are variadic for multiple bindings. * * @param string $statement - * @param Date|string|int|bool|float|array|null $bindings + * @param Date|string|int|bool|float|null ...$bindings * @return static */ - public function having(string $statement, Date|string|int|bool|float|array|null $bindings = null): static + public function having(string $statement, Date|string|int|bool|float|null ...$bindings): static { - if ( is_bool($bindings) ) { - $bindings = $bindings ? 'true' : 'false'; - } elseif (is_array($bindings) ) { - $newBinding = []; - /** @var Date|string|int|bool|float|null $binding */ - foreach ($bindings as $binding) { - $newBinding[] = $this->filterBinding($binding); - } - $bindings = $newBinding; + $newBinding = []; + /** @var Date|string|int|bool|float|null $binding */ + foreach ($bindings as $binding) { + $newBinding[] = $this->filterBinding($binding); } - $this->having[] = ['statement' => $statement, 'bindings' => $bindings]; + + $this->having[] = ['statement' => $statement, 'bindings' => $newBinding]; return $this; } @@ -468,7 +460,7 @@ public function getSequenceForPrimary(string $tableName, ?string $primarykey, bo { return null; } - + protected function filterBinding(string|int|bool|Date|float|null $binding): string|int|bool|Date|float|null { return $binding; diff --git a/Date.php b/Date.php index 452cd65..3008d9a 100755 --- a/Date.php +++ b/Date.php @@ -32,35 +32,35 @@ class Date { - public const FORMAT_YMD_WITH_SLASHES = 'Y/m/d'; - public const FORMAT_YMD_HMS_WITH_SLASHES = 'Y/m/d H:i:s'; - public const FORMAT_YMD_HM_WITH_SLASHES = 'Y/m/d H:i'; - public const FORMAT_YMD_WITH_DASHES = 'Y-m-d'; - public const FORMAT_YMD_HMS_WITH_DASHES = 'Y-m-d H:i:s'; - public const FORMAT_YMD_HM_WITH_DASHES = 'Y-m-d H:i'; - public const FORMAT_MDY_WITH_SLASHES = 'm/d/Y'; - public const FORMAT_MDY_HMS_WITH_SLASHES = 'm/d/Y H:i:s'; - public const FORMAT_MDY_HM_WITH_SLASHES = 'm/d/Y H:i'; - public const FORMAT_MDY_WITH_DASHES = 'm-d-Y'; - public const FORMAT_MDY_HMS_WITH_DASHES = 'm-d-Y H:i:s'; - public const FORMAT_MDY_HM_WITH_DASHES = 'm-d-y H:i'; - public const FORMAT_MDY_TEXT_FORMAT_WITHOUT_SUFFIX = 'F j, Y'; - public const FORMAT_MDY_TEXT_FORMAT_WITH_SUFFIX = 'F jS, Y'; - public const FORMAT_HMS = 'H:i:s'; - public const FORMAT_HM = 'H:i'; - public const FORMAT_UNIXTIMESTAMP = 'U'; - public const ATOM = "Y-m-d\TH:i:sP"; - public const COOKIE = "l, d-M-Y H:i:s T"; - public const ISO8601 = "Y-m-d\TH:i:sO"; - public const RFC822 = "D, d M y H:i:s O"; - public const RFC850 = "l, d-M-y H:i:s T"; - public const RFC1036 = "D, d M y H:i:s O"; - public const RFC1123 = "D, d M Y H:i:s O"; - public const RFC2822 = "D, d M Y H:i:s O"; - public const RFC3339 = "Y-m-d\TH:i:sP"; - public const RFC3339_EXTENDED = "Y-m-d\TH:i:s.vP"; - public const RSS = "D, d M Y H:i:s O"; - public const W3C = "Y-m-d\TH:i:sP"; + final public const FORMAT_YMD_WITH_SLASHES = 'Y/m/d'; + final public const FORMAT_YMD_HMS_WITH_SLASHES = 'Y/m/d H:i:s'; + final public const FORMAT_YMD_HM_WITH_SLASHES = 'Y/m/d H:i'; + final public const FORMAT_YMD_WITH_DASHES = 'Y-m-d'; + final public const FORMAT_YMD_HMS_WITH_DASHES = 'Y-m-d H:i:s'; + final public const FORMAT_YMD_HM_WITH_DASHES = 'Y-m-d H:i'; + final public const FORMAT_MDY_WITH_SLASHES = 'm/d/Y'; + final public const FORMAT_MDY_HMS_WITH_SLASHES = 'm/d/Y H:i:s'; + final public const FORMAT_MDY_HM_WITH_SLASHES = 'm/d/Y H:i'; + final public const FORMAT_MDY_WITH_DASHES = 'm-d-Y'; + final public const FORMAT_MDY_HMS_WITH_DASHES = 'm-d-Y H:i:s'; + final public const FORMAT_MDY_HM_WITH_DASHES = 'm-d-y H:i'; + final public const FORMAT_MDY_TEXT_FORMAT_WITHOUT_SUFFIX = 'F j, Y'; + final public const FORMAT_MDY_TEXT_FORMAT_WITH_SUFFIX = 'F jS, Y'; + final public const FORMAT_HMS = 'H:i:s'; + final public const FORMAT_HM = 'H:i'; + final public const FORMAT_UNIXTIMESTAMP = 'U'; + final public const ATOM = "Y-m-d\TH:i:sP"; + final public const COOKIE = "l, d-M-Y H:i:s T"; + final public const ISO8601 = "Y-m-d\TH:i:sO"; + final public const RFC822 = "D, d M y H:i:s O"; + final public const RFC850 = "l, d-M-y H:i:s T"; + final public const RFC1036 = "D, d M y H:i:s O"; + final public const RFC1123 = "D, d M Y H:i:s O"; + final public const RFC2822 = "D, d M Y H:i:s O"; + final public const RFC3339 = "Y-m-d\TH:i:sP"; + final public const RFC3339_EXTENDED = "Y-m-d\TH:i:s.vP"; + final public const RSS = "D, d M Y H:i:s O"; + final public const W3C = "Y-m-d\TH:i:sP"; private int $timestamp; protected ?string $timezone = null; diff --git a/Email/Attachment.php b/Email/Attachment.php index 350f349..c973f67 100644 --- a/Email/Attachment.php +++ b/Email/Attachment.php @@ -20,6 +20,7 @@ namespace Feast\Email; +use Feast\Enums\ResponseCode; use Feast\Exception\NotFoundException; class Attachment @@ -41,7 +42,7 @@ class Attachment public function setContentFromFile(string $fileName): static { if (is_file($fileName) === false || is_readable($fileName) === false) { - throw new NotFoundException('Invalid file', 500); + throw new NotFoundException('Invalid file', ResponseCode::HTTP_CODE_500); } $file = file_get_contents($fileName); $this->setContent($file); diff --git a/Enums/CollectionSort.php b/Enums/CollectionSort.php index 6aeaca8..a3d4e10 100644 --- a/Enums/CollectionSort.php +++ b/Enums/CollectionSort.php @@ -20,11 +20,11 @@ namespace Feast\Enums; -class CollectionSort +enum CollectionSort: int { - public const KEY = 1; - public const KEY_REVERSE = 2; - public const VALUE = 3; - public const VALUE_REVERSE = 4; + case KEY = 1; + case KEY_REVERSE = 2; + case VALUE = 3; + case VALUE_REVERSE = 4; } diff --git a/Enums/DatabaseType.php b/Enums/DatabaseType.php index a17afca..dbd5b3b 100644 --- a/Enums/DatabaseType.php +++ b/Enums/DatabaseType.php @@ -20,10 +20,9 @@ namespace Feast\Enums; -class DatabaseType +enum DatabaseType: string { - public const MYSQL = 'mysql'; - public const SQLITE = 'sqlite'; - public const POSTGRES = 'postgres'; - + case MYSQL = 'mysql'; + case SQLITE = 'sqlite'; + case POSTGRES = 'postgres'; } diff --git a/Exception/ResponseException.php b/Enums/DocType.php similarity index 62% rename from Exception/ResponseException.php rename to Enums/DocType.php index 0b53857..7df6acc 100644 --- a/Exception/ResponseException.php +++ b/Enums/DocType.php @@ -18,9 +18,16 @@ declare(strict_types=1); -namespace Feast\Exception; +namespace Feast\Enums; -class ResponseException extends ServerFailureException +enum DocType: string { - + case HTML_4_01_FRAMESET = 'html401frame'; + case HTML_4_01_STRICT = 'html401strict'; + case HTML_4_01_TRANSITIONAL = 'html401transitional'; + case HTML_5 = 'html5'; + case XHTML_1_0_FRAMESET = 'xhtml1frame'; + case XHTML_1_0_STRICT = 'xhtml1strict'; + case XHTML_1_0_TRANSITIONAL = 'xhtml1transitional'; + case XHTML_1_1 = 'xhtml11'; } diff --git a/Enums/DocTypes.php b/Enums/DocTypes.php deleted file mode 100644 index 39bff99..0000000 --- a/Enums/DocTypes.php +++ /dev/null @@ -1,34 +0,0 @@ - - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -declare(strict_types=1); - -namespace Feast\Enums; - -class DocTypes -{ - public const HTML_4_01_FRAMESET = 'html401frame'; - - public const HTML_4_01_STRICT = 'html401strict'; - public const HTML_4_01_TRANSITIONAL = 'html401transitional'; - public const HTML_5 = 'html5'; - public const XHTML_1_0_FRAMESET = 'xhtml1frame'; - public const XHTML_1_0_STRICT = 'xhtml1strict'; - public const XHTML_1_0_TRANSITIONAL = 'xhtml1transitional'; - public const XHTML_1_1 = 'xhtml11'; -} diff --git a/Enums/LogLevelCode.php b/Enums/LogLevelCode.php index 5ab7dd7..7dec998 100644 --- a/Enums/LogLevelCode.php +++ b/Enums/LogLevelCode.php @@ -20,14 +20,15 @@ namespace Feast\Enums; -class LogLevelCode +enum LogLevelCode: int { - public const DEBUG = 7; - public const INFO = 6; - public const NOTICE = 5; - public const WARNING = 4; - public const ERROR = 3; - public const CRITICAL = 2; - public const ALERT = 1; - public const EMERGENCY = 0; + case DEBUG = 7; //LOG_DEBUG; + case INFO = 6; // LOG_INFO; + case NOTICE = 5; //LOG_NOTICE; + case WARNING = 4; //LOG_WARNING; + case ERROR = 3; //LOG_ERR; + case CRITICAL = 2; //LOG_CRIT; + case ALERT = 1; //LOG_ALERT; + case EMERGENCY = 0; //LOG_EMERG; + } diff --git a/Enums/ParamType.php b/Enums/ParamType.php index f1a72f3..14a0649 100644 --- a/Enums/ParamType.php +++ b/Enums/ParamType.php @@ -20,8 +20,8 @@ namespace Feast\Enums; -class ParamType +enum ParamType { - public const FLAG = 'flag'; - public const PARAM = 'param'; + case FLAG; + case PARAM; } diff --git a/Enums/RequestMethod.php b/Enums/RequestMethod.php index 0ed5461..26e2b09 100644 --- a/Enums/RequestMethod.php +++ b/Enums/RequestMethod.php @@ -20,11 +20,11 @@ namespace Feast\Enums; -class RequestMethod +enum RequestMethod: string { - public const GET = 'GET'; - public const POST = 'POST'; - public const PUT = 'PUT'; - public const PATCH = 'PATCH'; - public const DELETE = 'DELETE'; + case GET = 'GET'; + case POST = 'POST'; + case PUT = 'PUT'; + case PATCH = 'PATCH'; + case DELETE = 'DELETE'; } diff --git a/Enums/ResponseCode.php b/Enums/ResponseCode.php index 3d80ed5..b9edcdf 100644 --- a/Enums/ResponseCode.php +++ b/Enums/ResponseCode.php @@ -20,87 +20,89 @@ namespace Feast\Enums; -class ResponseCode { - public const HTTP_CODE_100 = 100; - public const HTTP_CODE_101 = 101; - public const HTTP_CODE_102 = 102; - public const HTTP_CODE_200 = 200; - public const HTTP_CODE_201 = 201; - public const HTTP_CODE_202 = 202; - public const HTTP_CODE_203 = 203; - public const HTTP_CODE_204 = 204; - public const HTTP_CODE_205 = 205; - public const HTTP_CODE_206 = 206; - public const HTTP_CODE_207 = 207; - public const HTTP_CODE_300 = 300; - public const HTTP_CODE_301 = 301; - public const HTTP_CODE_302 = 302; - public const HTTP_CODE_303 = 303; - public const HTTP_CODE_304 = 304; - public const HTTP_CODE_305 = 305; - public const HTTP_CODE_306 = 306; - public const HTTP_CODE_307 = 307; - public const HTTP_CODE_308 = 308; - public const HTTP_CODE_400 = 400; - public const HTTP_CODE_401 = 401; - public const HTTP_CODE_402 = 402; - public const HTTP_CODE_403 = 403; - public const HTTP_CODE_404 = 404; - public const HTTP_CODE_405 = 405; - public const HTTP_CODE_406 = 406; - public const HTTP_CODE_407 = 407; - public const HTTP_CODE_408 = 408; - public const HTTP_CODE_409 = 409; - public const HTTP_CODE_410 = 410; - public const HTTP_CODE_411 = 411; - public const HTTP_CODE_412 = 412; - public const HTTP_CODE_413 = 413; - public const HTTP_CODE_414 = 414; - public const HTTP_CODE_415 = 415; - public const HTTP_CODE_416 = 416; - public const HTTP_CODE_417 = 417; - public const HTTP_CODE_418 = 418; - public const HTTP_CODE_419 = 419; - public const HTTP_CODE_420 = 420; - public const HTTP_CODE_422 = 422; - public const HTTP_CODE_423 = 423; - public const HTTP_CODE_424 = 424; - public const HTTP_CODE_425 = 425; - public const HTTP_CODE_426 = 426; - public const HTTP_CODE_428 = 428; - public const HTTP_CODE_429 = 429; - public const HTTP_CODE_431 = 431; - public const HTTP_CODE_444 = 444; - public const HTTP_CODE_449 = 449; - public const HTTP_CODE_450 = 450; - public const HTTP_CODE_451 = 451; - public const HTTP_CODE_494 = 494; - public const HTTP_CODE_495 = 495; - public const HTTP_CODE_496 = 496; - public const HTTP_CODE_497 = 497; - public const HTTP_CODE_499 = 499; - public const HTTP_CODE_500 = 500; - public const HTTP_CODE_501 = 501; - public const HTTP_CODE_502 = 502; - public const HTTP_CODE_503 = 503; - public const HTTP_CODE_504 = 504; - public const HTTP_CODE_505 = 505; - public const HTTP_CODE_506 = 506; - public const HTTP_CODE_507 = 507; - public const HTTP_CODE_508 = 508; - public const HTTP_CODE_509 = 509; - public const HTTP_CODE_510 = 510; - public const HTTP_CODE_511 = 511; - public const HTTP_CODE_598 = 598; - public const HTTP_CODE_599 = 599; +enum ResponseCode: int +{ + case HTTP_CODE_100 = 100; + case HTTP_CODE_101 = 101; + case HTTP_CODE_102 = 102; + case HTTP_CODE_200 = 200; + case HTTP_CODE_201 = 201; + case HTTP_CODE_202 = 202; + case HTTP_CODE_203 = 203; + case HTTP_CODE_204 = 204; + case HTTP_CODE_205 = 205; + case HTTP_CODE_206 = 206; + case HTTP_CODE_207 = 207; + case HTTP_CODE_300 = 300; + case HTTP_CODE_301 = 301; + case HTTP_CODE_302 = 302; + case HTTP_CODE_303 = 303; + case HTTP_CODE_304 = 304; + case HTTP_CODE_305 = 305; + case HTTP_CODE_306 = 306; + case HTTP_CODE_307 = 307; + case HTTP_CODE_308 = 308; + case HTTP_CODE_400 = 400; + case HTTP_CODE_401 = 401; + case HTTP_CODE_402 = 402; + case HTTP_CODE_403 = 403; + case HTTP_CODE_404 = 404; + case HTTP_CODE_405 = 405; + case HTTP_CODE_406 = 406; + case HTTP_CODE_407 = 407; + case HTTP_CODE_408 = 408; + case HTTP_CODE_409 = 409; + case HTTP_CODE_410 = 410; + case HTTP_CODE_411 = 411; + case HTTP_CODE_412 = 412; + case HTTP_CODE_413 = 413; + case HTTP_CODE_414 = 414; + case HTTP_CODE_415 = 415; + case HTTP_CODE_416 = 416; + case HTTP_CODE_417 = 417; + case HTTP_CODE_418 = 418; + case HTTP_CODE_419 = 419; + case HTTP_CODE_420 = 420; + case HTTP_CODE_422 = 422; + case HTTP_CODE_423 = 423; + case HTTP_CODE_424 = 424; + case HTTP_CODE_425 = 425; + case HTTP_CODE_426 = 426; + case HTTP_CODE_428 = 428; + case HTTP_CODE_429 = 429; + case HTTP_CODE_431 = 431; + case HTTP_CODE_444 = 444; + case HTTP_CODE_449 = 449; + case HTTP_CODE_450 = 450; + case HTTP_CODE_451 = 451; + case HTTP_CODE_494 = 494; + case HTTP_CODE_495 = 495; + case HTTP_CODE_496 = 496; + case HTTP_CODE_497 = 497; + case HTTP_CODE_499 = 499; + case HTTP_CODE_500 = 500; + case HTTP_CODE_501 = 501; + case HTTP_CODE_502 = 502; + case HTTP_CODE_503 = 503; + case HTTP_CODE_504 = 504; + case HTTP_CODE_505 = 505; + case HTTP_CODE_506 = 506; + case HTTP_CODE_507 = 507; + case HTTP_CODE_508 = 508; + case HTTP_CODE_509 = 509; + case HTTP_CODE_510 = 510; + case HTTP_CODE_511 = 511; + case HTTP_CODE_598 = 598; + case HTTP_CODE_599 = 599; /** * Returns if response code is valid. - * + * * @param int $responseCode * @return bool */ - public static function isValidResponseCode(int $responseCode): bool { + public static function isValidResponseCode(int $responseCode): bool + { return defined('self::HTTP_CODE_' . (string)$responseCode); } } diff --git a/Enums/ServiceContainer.php b/Enums/ServiceContainer.php index e21535a..afb7519 100644 --- a/Enums/ServiceContainer.php +++ b/Enums/ServiceContainer.php @@ -20,8 +20,9 @@ namespace Feast\Enums; -class ServiceContainer { +enum ServiceContainer: string +{ // This flag should only be used when running unit tests and needing to add mock items. // Use at your own risk. Better yet, don't use it at all. Ever. Not even for fun. Nope. - public const CLEAR_CONTAINER = 'clear'; + case CLEAR_CONTAINER = 'clear'; } diff --git a/Exception/Error404Exception.php b/Exception/Error404Exception.php index 01cbc37..baa3974 100644 --- a/Exception/Error404Exception.php +++ b/Exception/Error404Exception.php @@ -20,6 +20,7 @@ namespace Feast\Exception; +use Feast\Enums\ResponseCode; use Throwable; class Error404Exception extends ServerFailureException @@ -27,7 +28,7 @@ class Error404Exception extends ServerFailureException public function __construct(string $message, int $errorCode = 0, Throwable $previousException = null) { - parent::__construct($message, 404, $errorCode, $previousException); + parent::__construct($message, ResponseCode::HTTP_CODE_404, $errorCode, $previousException); } } diff --git a/Exception/InvalidDateException.php b/Exception/InvalidDateException.php index ffc73f7..118dc8e 100644 --- a/Exception/InvalidDateException.php +++ b/Exception/InvalidDateException.php @@ -20,6 +20,7 @@ namespace Feast\Exception; +use Feast\Enums\ResponseCode; use Throwable; class InvalidDateException extends ServerFailureException @@ -27,7 +28,7 @@ class InvalidDateException extends ServerFailureException public function __construct( string $message, - ?int $responseCode = null, + ?ResponseCode $responseCode = null, int $errorCode = 0, Throwable $previousException = null ) { diff --git a/Exception/ServerFailureException.php b/Exception/ServerFailureException.php index b7b5ca2..a89176f 100644 --- a/Exception/ServerFailureException.php +++ b/Exception/ServerFailureException.php @@ -22,6 +22,7 @@ use Exception; +use Feast\Enums\ResponseCode; use Feast\Interfaces\ConfigInterface; use Feast\Interfaces\RequestInterface; use Feast\Interfaces\ResponseInterface; @@ -45,14 +46,14 @@ class ServerFailureException extends Exception * Construct a new Exception, and include the response code. * * @param string $message - * @param int|null $responseCode + * @param ResponseCode|null $responseCode * @param int $errorCode * @param Throwable|null $previousException * @param string|null $overrideRunAs */ public function __construct( string $message, - private ?int $responseCode = null, + private ?ResponseCode $responseCode = null, int $errorCode = 0, Throwable $previousException = null, ?string $overrideRunAs = null @@ -67,9 +68,9 @@ public function __construct( /** * Get the response code * - * @return int|null + * @return ResponseCode|null */ - public function getResponseCode(): ?int + public function getResponseCode(): ?ResponseCode { return $this->responseCode; } diff --git a/FeastTests/Attributes/PathTest.php b/FeastTests/Attributes/PathTest.php index 3264e8a..e35b88c 100644 --- a/FeastTests/Attributes/PathTest.php +++ b/FeastTests/Attributes/PathTest.php @@ -21,6 +21,7 @@ namespace Attributes; use Feast\Attributes\Path; +use Feast\Enums\RequestMethod; use PHPUnit\Framework\TestCase; class PathTest extends TestCase @@ -28,42 +29,42 @@ class PathTest extends TestCase public function testGetMethodGetOnly(): void { $path = new Path('/index', 'index', Path::METHOD_GET); - $this->assertEquals(['GET'], $path->getMethods()); + $this->assertEquals([RequestMethod::GET], $path->getMethods()); } public function testGetMethodPostOnly(): void { $path = new Path('/index', 'index', Path::METHOD_POST); - $this->assertEquals(['POST'], $path->getMethods()); + $this->assertEquals([RequestMethod::POST], $path->getMethods()); } public function testGetMethodPutOnly(): void { $path = new Path('/index', 'index', Path::METHOD_PUT); - $this->assertEquals(['PUT'], $path->getMethods()); + $this->assertEquals([RequestMethod::PUT], $path->getMethods()); } public function testGetMethodDeleteOnly(): void { $path = new Path('/index', 'index', Path::METHOD_DELETE); - $this->assertEquals(['DELETE'], $path->getMethods()); + $this->assertEquals([RequestMethod::DELETE], $path->getMethods()); } public function testGetMethodPatchOnly(): void { $path = new Path('/index', 'index', Path::METHOD_PATCH); - $this->assertEquals(['PATCH'], $path->getMethods()); + $this->assertEquals([RequestMethod::PATCH], $path->getMethods()); } public function testGetMethodGetAndPost(): void { $path = new Path('/index', 'index', Path::METHOD_GET | Path::METHOD_POST); - $this->assertEquals(['GET', 'POST'], $path->getMethods()); + $this->assertEquals([RequestMethod::GET, RequestMethod::POST], $path->getMethods()); } public function testGetMethodAll(): void { $path = new Path('/index', 'index', Path::METHOD_ALL); - $this->assertEquals(['GET', 'POST', 'PUT', 'DELETE', 'PATCH'], $path->getMethods()); + $this->assertEquals([RequestMethod::GET, RequestMethod::POST, RequestMethod::PUT, RequestMethod::DELETE, RequestMethod::PATCH], $path->getMethods()); } -} \ No newline at end of file +} diff --git a/FeastTests/Collection/CollectionListTest.php b/FeastTests/Collection/CollectionListTest.php index 73e297a..6bf07a0 100644 --- a/FeastTests/Collection/CollectionListTest.php +++ b/FeastTests/Collection/CollectionListTest.php @@ -142,7 +142,7 @@ public function testReverseSortValueAndPop(): void public function testSortInvalid(): void { $collection = new CollectionList('string', ['b' => 'early', 'a' => 'testing']); - $this->expectException(InvalidOptionException::class); + $this->expectException(\TypeError::class); $collection->sort(7, true); } @@ -237,7 +237,7 @@ public function testObjectSortInvalid(): void public function testObjectSortTypeInvalid(): void { $collection = new CollectionList(stdClass::class); - $this->expectException(InvalidOptionException::class); + $this->expectException(\TypeError::class); $collection->objectSort('test', 7); } diff --git a/FeastTests/Controllers/JobControllerTest.php b/FeastTests/Controllers/JobControllerTest.php index 58d2e66..40274df 100644 --- a/FeastTests/Controllers/JobControllerTest.php +++ b/FeastTests/Controllers/JobControllerTest.php @@ -130,7 +130,7 @@ public function testRunWithJobs(): void $jobMapper = $this->createStub(JobMapper::class); $jobMapper->method('findOnePendingByQueues')->willReturn($job); $jobMapper->method('findByPrimaryKey')->willReturn($job); - $jobMapper->method('markJobPendingIfAble')->willReturn(true); + $jobMapper->method('markJobRunningIfAble')->willReturn(true); $controller->listenGet( $this->createStub(LoggerInterface::class), @@ -253,7 +253,7 @@ public function testRunOneCannotLock(): void $jobMapper = $this->createStub(JobMapper::class); $jobMapper->method('findByPrimaryKey')->willReturn($job); - $jobMapper->method('markJobPendingIfAble')->willReturn(false); + $jobMapper->method('markJobRunningIfAble')->willReturn(false); $controller->runOneGet( $this->createStub(LoggerInterface::class), $jobMapper, @@ -287,7 +287,7 @@ public function testRunOneSuccess(): void $jobMapper = $this->createStub(JobMapper::class); $jobMapper->method('findByPrimaryKey')->willReturn($job); - $jobMapper->method('markJobPendingIfAble')->willReturn(true); + $jobMapper->method('markJobRunningIfAble')->willReturn(true); $controller->runOneGet( $this->createStub(LoggerInterface::class), $jobMapper, @@ -321,7 +321,7 @@ public function testRunOneWillThrow(): void $jobMapper = $this->createStub(JobMapper::class); $jobMapper->method('findByPrimaryKey')->willReturn($job); - $jobMapper->method('markJobPendingIfAble')->willReturn(true); + $jobMapper->method('markJobRunningIfAble')->willReturn(true); $controller->runOneGet( $this->createStub(LoggerInterface::class), $jobMapper, @@ -355,7 +355,7 @@ public function testRunOneTriesExceeded(): void $jobMapper = $this->createStub(JobMapper::class); $jobMapper->method('findByPrimaryKey')->willReturn($job); - $jobMapper->method('markJobPendingIfAble')->willReturn(true); + $jobMapper->method('markJobRunningIfAble')->willReturn(true); $controller->runOneGet( $this->createStub(LoggerInterface::class), $jobMapper, @@ -388,7 +388,7 @@ public function testRunOneInvalidContext(): void $jobMapper = $this->createStub(JobMapper::class); $jobMapper->method('findByPrimaryKey')->willReturn($job); - $jobMapper->method('markJobPendingIfAble')->willReturn(true); + $jobMapper->method('markJobRunningIfAble')->willReturn(true); $controller->runOneGet( $this->createStub(LoggerInterface::class), $jobMapper, diff --git a/FeastTests/Controllers/MaintenanceControllerTest.php b/FeastTests/Controllers/MaintenanceControllerTest.php index 6530e1c..e630823 100644 --- a/FeastTests/Controllers/MaintenanceControllerTest.php +++ b/FeastTests/Controllers/MaintenanceControllerTest.php @@ -22,7 +22,7 @@ use Feast\CliArguments; use Feast\Config\Config; use Feast\Controllers\MaintenanceController; -use Feast\Enums\DocTypes; +use Feast\Enums\DocType; use Feast\Interfaces\RouterInterface; use Feast\ServiceContainer\ServiceContainer; use Feast\View; diff --git a/FeastTests/Database/DatabaseFactoryTest.php b/FeastTests/Database/DatabaseFactoryTest.php index d1bc7d0..6c001b6 100644 --- a/FeastTests/Database/DatabaseFactoryTest.php +++ b/FeastTests/Database/DatabaseFactoryTest.php @@ -23,6 +23,7 @@ use Feast\Config\Config; use Feast\Database\Database; use Feast\Database\DatabaseFactory; +use Feast\Database\MySQLQuery; use Feast\Enums\DatabaseType; use Feast\Exception\DatabaseException; use Feast\Interfaces\LoggerInterface; @@ -41,6 +42,7 @@ public function testGetConnection(): void $details->pass = 'test'; $details->name = 'Test'; $details->connectionType = DatabaseType::MYSQL; + $details->queryClass = MySQLQuery::class; $config = $this->createStub(Config::class); $config->method('getSetting')->willReturnMap( [ diff --git a/FeastTests/Database/DatabaseTest.php b/FeastTests/Database/DatabaseTest.php index d275c16..479257a 100644 --- a/FeastTests/Database/DatabaseTest.php +++ b/FeastTests/Database/DatabaseTest.php @@ -37,7 +37,7 @@ class DatabaseTest extends TestCase { protected function getValidConnection( - ?string $connectionType = DatabaseType::MYSQL, + ?DatabaseType $connectionType = DatabaseType::MYSQL, ?string $queryClass = MySQLQuery::class, bool $options = false ): Database { @@ -121,8 +121,8 @@ public function testInstantiationUnknownType(): void $details->pass = 'test'; $details->name = 'Test'; $details->connectionType = 'This Database Doesn\'t Exist'; - $this->expectException(DatabaseException::class); $logger = $this->createMock(LoggerInterface::INTERFACE_NAME); + $this->expectException(\TypeError::class); new Database($details, PDOMock::class, $logger); } @@ -135,6 +135,7 @@ public function testInstantiationWithUrl(): void $details->name = 'Test'; $details->url = 'mysql:host=localhost;port=3306;'; $details->connectionType = DatabaseType::MYSQL; + $details->queryClass = MySQLQuery::class; $logger = $this->createMock(LoggerInterface::INTERFACE_NAME); $database = new Database($details, PDOMock::class, $logger); $this->assertInstanceOf(Database::class, $database); @@ -148,12 +149,13 @@ public function testInstantiationUnknownDbClass(): void $details->pass = 'test'; $details->name = 'Test'; $details->connectionType = DatabaseType::MYSQL; + $details->queryClass = MySQLQuery::class; $this->expectException(InvalidOptionException::class); $logger = $this->createMock(LoggerInterface::INTERFACE_NAME); new Database($details, \stdClass::class, $logger); } - public function testInstantiationWithDeprecatedMethodMySQL(): void + public function testInstantiationInvalidDbClass(): void { $details = new \stdClass(); $details->host = 'localhost'; @@ -161,12 +163,40 @@ public function testInstantiationWithDeprecatedMethodMySQL(): void $details->pass = 'test'; $details->name = 'Test'; $details->connectionType = DatabaseType::MYSQL; + $details->queryClass = 'completegibberishdefinitelynotaclass'; + $logger = $this->createMock(LoggerInterface::INTERFACE_NAME); + $this->expectException(InvalidOptionException::class); + new Database($details, \stdClass::class, $logger); + } + + public function testInstantiationNonExtendedDbClass(): void + { + $details = new \stdClass(); + $details->host = 'localhost'; + $details->user = 'root'; + $details->pass = 'test'; + $details->name = 'Test'; + $details->connectionType = DatabaseType::MYSQL; + $details->queryClass = \stdClass::class; + $logger = $this->createMock(LoggerInterface::INTERFACE_NAME); + $this->expectException(InvalidOptionException::class); + new Database($details, \stdClass::class, $logger); + } + + public function testInstantiationWithRemovedFormerlyDeprecatedMethodMySQL(): void + { + $details = new \stdClass(); + $details->host = 'localhost'; + $details->user = 'root'; + $details->pass = 'test'; + $details->name = 'Test'; + $details->connectionType = DatabaseType::MYSQL; + $this->expectException(InvalidOptionException::class); $logger = $this->createMock(LoggerInterface::INTERFACE_NAME); $database = new Database($details, PDOMock::class, $logger); - $this->assertInstanceOf(Database::class, $database); } - public function testInstantiationWithDeprecatedMethodSqLite(): void + public function testInstantiationWithRemovedFormerlyDeprecatedMethodSqLite(): void { $details = new \stdClass(); $details->host = 'localhost'; @@ -174,9 +204,9 @@ public function testInstantiationWithDeprecatedMethodSqLite(): void $details->pass = 'test'; $details->name = 'Test'; $details->connectionType = DatabaseType::SQLITE; + $this->expectException(InvalidOptionException::class); $logger = $this->createMock(LoggerInterface::INTERFACE_NAME); $database = new Database($details, PDOMock::class, $logger); - $this->assertInstanceOf(Database::class, $database); } public function testInsert(): void @@ -248,24 +278,12 @@ public function testGetDatabaseTypeMySQL(): void $this->assertEquals(DatabaseType::MYSQL, $database->getDatabaseType()); } - public function testGetQueryClassMySQL(): void - { - $database = $this->getValidConnection(); - $this->assertEquals(MySQLQuery::class, $database->getQueryClass()); - } - public function testGetDatabaseTypeSqlite(): void { $database = $this->getValidConnection(DatabaseType::SQLITE, SQLiteQuery::class); $this->assertEquals(DatabaseType::SQLITE, $database->getDatabaseType()); } - public function testGetQueryClassSqlite(): void - { - $database = $this->getValidConnection(DatabaseType::SQLITE, SQLiteQuery::class); - $this->assertEquals(SQLiteQuery::class, $database->getQueryClass()); - } - public function testDelete(): void { $database = $this->getValidConnection(); diff --git a/FeastTests/Database/MySQLQueryTest.php b/FeastTests/Database/MySQLQueryTest.php index 7e38c1f..d12e602 100644 --- a/FeastTests/Database/MySQLQueryTest.php +++ b/FeastTests/Database/MySQLQueryTest.php @@ -46,51 +46,55 @@ public function testFrom(): void { $query = $this->getValidQuery(); $query->from('test', ['test']); - $this->assertEquals('SELECT test FROM test', $query->__toString()); + $this->assertEquals('SELECT test FROM test', (string)$query); } public function testSelect(): void { $query = $this->getValidQuery(); $query->select('test'); - $this->assertEquals('SELECT test.* FROM test', $query->__toString()); + $this->assertEquals('SELECT test.* FROM test', (string)$query); } public function testFromNoColumn(): void { $query = $this->getValidQuery(); $query->from('test'); - $this->assertEquals('SELECT test.* FROM test', $query->__toString()); + $this->assertEquals('SELECT test.* FROM test', (string)$query); } public function testLimit(): void { $query = $this->getValidQuery(); $query->from('test', ['test'])->limit(1, 1); - $this->assertEquals('SELECT test FROM test LIMIT 1,1', $query->__toString()); + $this->assertEquals('SELECT test FROM test LIMIT 1,1', (string)$query); } public function testGroupBy(): void { $query = $this->getValidQuery(); $query->from('test', ['test'])->groupBy('test'); - $this->assertEquals('SELECT test FROM test GROUP BY test', $query->__toString()); + $this->assertEquals('SELECT test FROM test GROUP BY test', (string)$query); } public function testReplace(): void { $query = $this->getValidQuery(); $query->replace('test', ['test' => 'test']); - $this->assertEquals('REPLACE INTO test (test) VALUES (?)', $query->__toString()); + $this->assertEquals('REPLACE INTO test (test) VALUES (?)', (string)$query); } - public function testWhere(): void + public function testWhereMulti(): void { $query = $this->getValidQuery(); - $query->from('test', ['test'])->where('test = ? and active = ?', ['test', true]); - $this->assertEquals('SELECT test FROM test WHERE (test = ? and active = ?)', $query->__toString()); + $query->from('test', ['test'])->where('test = ? and feast = ? and active = ?', 'test', 'framework', true); + $this->assertEquals('SELECT test FROM test WHERE (test = ? and feast = ? and active = ?)', (string)$query); + $this->assertEquals( + 'SELECT test FROM test WHERE (test = \'test\' and feast = \'framework\' and active = \'1\')', + $query->getRawQueryWithParams() + ); } - + public function testWhereBool(): void { $query = $this->getValidQuery(); @@ -98,11 +102,11 @@ public function testWhereBool(): void $this->assertEquals('SELECT test FROM test WHERE (active = ?)', $query->__toString()); } - public function testWhereNonArray(): void + public function testWhereSingle(): void { $query = $this->getValidQuery(); $query->from('test', ['test'])->where('test = ?', 'test'); - $this->assertEquals('SELECT test FROM test WHERE (test = ?)', $query->__toString()); + $this->assertEquals('SELECT test FROM test WHERE (test = ?)', (string)$query); } public function testExecute(): void @@ -125,21 +129,21 @@ public function testDescribe(): void { $query = $this->getValidQuery(); $query->describe('test'); - $this->assertEquals('DESCRIBE test', $query->__toString()); + $this->assertEquals('DESCRIBE test', (string)$query); } public function testDelete(): void { $query = $this->getValidQuery(); $query->delete('test'); - $this->assertEquals('DELETE FROM test', $query->__toString()); + $this->assertEquals('DELETE FROM test', (string)$query); } public function testInnerJoin(): void { $query = $this->getValidQuery(); $query->from('test', ['test'])->innerJoin('test2', 'test.ing', 'test2.ing'); - $this->assertEquals('SELECT test FROM test INNER JOIN test2 ON test.ing = test2.ing', $query->__toString()); + $this->assertEquals('SELECT test FROM test INNER JOIN test2 ON test.ing = test2.ing', (string)$query); } public function testInnerJoinArray(): void @@ -148,7 +152,7 @@ public function testInnerJoinArray(): void $query->from('test', ['test'])->innerJoin('test2', ['test.ing', 'test.feast'], ['test2.ing', 'test2.feast']); $this->assertEquals( 'SELECT test FROM test INNER JOIN test2 ON test.ing = test2.ing AND test.feast = test2.feast', - $query->__toString() + (string)$query ); } @@ -170,28 +174,28 @@ public function testLeftJoinUsing(): void { $query = $this->getValidQuery(); $query->from('test', ['test'])->leftJoinUsing('test2', 'ing'); - $this->assertEquals('SELECT test FROM test LEFT JOIN test2 USING (ing)', $query->__toString()); + $this->assertEquals('SELECT test FROM test LEFT JOIN test2 USING (ing)', (string)$query); } public function testLeftJoinUsingArray(): void { $query = $this->getValidQuery(); $query->from('test', ['test'])->leftJoinUsing('test2', ['ing', 'feast']); - $this->assertEquals('SELECT test FROM test LEFT JOIN test2 USING (ing,feast)', $query->__toString()); + $this->assertEquals('SELECT test FROM test LEFT JOIN test2 USING (ing,feast)', (string)$query); } public function testInsert(): void { $query = $this->getValidQuery(); $query->insert('test', ['testing' => 'test2']); - $this->assertEquals('INSERT INTO test (testing) VALUES (?)', $query->__toString()); + $this->assertEquals('INSERT INTO test (testing) VALUES (?)', (string)$query); } public function testInnerJoinUsing(): void { $query = $this->getValidQuery(); $query->from('test', ['test'])->innerJoinUsing('test2', 'ing'); - $this->assertEquals('SELECT test FROM test INNER JOIN test2 USING (ing)', $query->__toString()); + $this->assertEquals('SELECT test FROM test INNER JOIN test2 USING (ing)', (string)$query); } public function testGetRawQueryWithParams(): void @@ -201,10 +205,17 @@ public function testGetRawQueryWithParams(): void $this->assertEquals('SELECT test FROM test WHERE (test = \'test\')', $query->getRawQueryWithParams()); } + public function testGetRawQueryWithMultiParams(): void + { + $query = $this->getValidQuery(); + $query->from('test', ['test'])->where('test = ? and feast = ?', 'test', 'framework'); + $this->assertEquals('SELECT test FROM test WHERE (test = \'test\' and feast = \'framework\')', $query->getRawQueryWithParams()); + } + public function testGetRawQueryNoParams(): void { $query = $this->getValidQuery(); - $query->from('test', ['test'])->where('1=1', ['test']); + $query->from('test', ['test'])->where('1=1', 'test'); $this->assertEquals('SELECT test FROM test WHERE (1=1)', $query->getRawQueryWithParams()); } @@ -219,42 +230,42 @@ public function testLeftJoin(): void { $query = $this->getValidQuery(); $query->from('test', ['test'])->leftJoin('test2', 'test.ing', 'test2.ing'); - $this->assertEquals('SELECT test FROM test LEFT JOIN test2 ON test.ing = test2.ing', $query->__toString()); + $this->assertEquals('SELECT test FROM test LEFT JOIN test2 ON test.ing = test2.ing', (string)$query); } public function testRightJoinUsing(): void { $query = $this->getValidQuery(); $query->from('test', ['test'])->rightJoinUsing('test2', 'ing'); - $this->assertEquals('SELECT test FROM test RIGHT JOIN test2 USING (ing)', $query->__toString()); + $this->assertEquals('SELECT test FROM test RIGHT JOIN test2 USING (ing)', (string)$query); } public function testRightJoin(): void { $query = $this->getValidQuery(); $query->from('test', ['test'])->rightJoin('test2', 'test.ing', 'test2.ing'); - $this->assertEquals('SELECT test FROM test RIGHT JOIN test2 ON test.ing = test2.ing', $query->__toString()); + $this->assertEquals('SELECT test FROM test RIGHT JOIN test2 ON test.ing = test2.ing', (string)$query); } public function testOrderBy(): void { $query = $this->getValidQuery(); $query->from('test', ['test'])->orderBy('test'); - $this->assertEquals('SELECT test FROM test ORDER BY test', $query->__toString()); + $this->assertEquals('SELECT test FROM test ORDER BY test', (string)$query); } public function testUpdate(): void { $query = $this->getValidQuery(); $query->update('test', ['field' => 'test']); - $this->assertEquals('UPDATE test SET field = ?', $query->__toString()); + $this->assertEquals('UPDATE test SET field = ?', (string)$query); } public function testHaving(): void { $query = $this->getValidQuery(); $query->from('test', ['test'])->having('test > ?', '1'); - $this->assertEquals('SELECT test FROM test HAVING (test > ?)', $query->__toString()); + $this->assertEquals('SELECT test FROM test HAVING (test > ?)', (string)$query); } public function testHavingBool(): void @@ -267,8 +278,8 @@ public function testHavingBool(): void public function testHavingMulti(): void { $query = $this->getValidQuery(); - $query->from('test', ['test'])->having('test > ? and active = ?', ['1', true]); - $this->assertEquals('SELECT test FROM test HAVING (test > ? and active = ?)', $query->__toString()); + $query->from('test', ['test'])->having('test > ? and test2 > ? and active = ?', '1','2', true); + $this->assertEquals('SELECT test FROM test HAVING (test > ? and test2 > ? and active = ?)', (string)$query); } public function testSQLiteQuery(): void diff --git a/FeastTests/Database/PostgresQueryTest.php b/FeastTests/Database/PostgresQueryTest.php index 8b8a415..8889d9c 100644 --- a/FeastTests/Database/PostgresQueryTest.php +++ b/FeastTests/Database/PostgresQueryTest.php @@ -83,11 +83,19 @@ public function testReplace(): void $query->replace('test', ['test' => 'test']); } - public function testWhere(): void + public function testWhereMulti(): void { $query = $this->getValidQuery(); - $query->from('test', ['test'])->where('test = ?', ['test']); - $this->assertEquals('SELECT test FROM test WHERE (test = ?)', $query->__toString()); + $query->from('test', ['test'])->where('test = ? and feast = ?', 'test', 'framework'); + $this->assertEquals('SELECT test FROM test WHERE (test = ? and feast = ?)', (string)$query); + $this->assertEquals('SELECT test FROM test WHERE (test = \'test\' and feast = \'framework\')', $query->getRawQueryWithParams()); + } + + public function testWhereSingle(): void + { + $query = $this->getValidQuery(); + $query->from('test', ['test'])->where('test = ?', 'test'); + $this->assertEquals('SELECT test FROM test WHERE (test = ?)', (string)$query); } public function testWhereNonArray(): void @@ -189,7 +197,7 @@ public function testGetRawQueryWithParams(): void public function testGetRawQueryNoParams(): void { $query = $this->getValidQuery(); - $query->from('test', ['test'])->where('1=1', ['test']); + $query->from('test', ['test'])->where('1=1', 'test'); $this->assertEquals('SELECT test FROM test WHERE (1=1)', $query->getRawQueryWithParams()); } @@ -266,8 +274,8 @@ public function testHaving(): void public function testHavingMulti(): void { $query = $this->getValidQuery(); - $query->from('test', ['test'])->having('test > ?', ['1']); - $this->assertEquals('SELECT test FROM test HAVING (test > ?)', $query->__toString()); + $query->from('test', ['test'])->having('test > ? and test2 > ?', '1','2'); + $this->assertEquals('SELECT test FROM test HAVING (test > ? and test2 > ?)', (string)$query); } diff --git a/FeastTests/Database/SQLiteQueryTest.php b/FeastTests/Database/SQLiteQueryTest.php index 954f24d..91bec11 100644 --- a/FeastTests/Database/SQLiteQueryTest.php +++ b/FeastTests/Database/SQLiteQueryTest.php @@ -43,56 +43,56 @@ public function testFrom(): void { $query = $this->getValidQuery(); $query->from('test', ['test']); - $this->assertEquals('SELECT test FROM test', $query->__toString()); + $this->assertEquals('SELECT test FROM test', (string)$query); } public function testSelect(): void { $query = $this->getValidQuery(); $query->select('test'); - $this->assertEquals('SELECT test.* FROM test', $query->__toString()); + $this->assertEquals('SELECT test.* FROM test', (string)$query); } public function testFromNoColumn(): void { $query = $this->getValidQuery(); $query->from('test'); - $this->assertEquals('SELECT test.* FROM test', $query->__toString()); + $this->assertEquals('SELECT test.* FROM test', (string)$query); } public function testLimit(): void { $query = $this->getValidQuery(); $query->from('test', ['test'])->limit(1, 1); - $this->assertEquals('SELECT test FROM test LIMIT 1,1', $query->__toString()); + $this->assertEquals('SELECT test FROM test LIMIT 1,1', (string)$query); } public function testGroupBy(): void { $query = $this->getValidQuery(); $query->from('test', ['test'])->groupBy('test'); - $this->assertEquals('SELECT test FROM test GROUP BY test', $query->__toString()); + $this->assertEquals('SELECT test FROM test GROUP BY test', (string)$query); } public function testReplace(): void { $query = $this->getValidQuery(); $query->replace('test', ['test' => 'test']); - $this->assertEquals('REPLACE INTO test (test) VALUES (?)', $query->__toString()); + $this->assertEquals('REPLACE INTO test (test) VALUES (?)', (string)$query); } public function testWhere(): void { $query = $this->getValidQuery(); - $query->from('test', ['test'])->where('test = ?', ['test']); - $this->assertEquals('SELECT test FROM test WHERE (test = ?)', $query->__toString()); + $query->from('test', ['test'])->where('test = ?', 'test'); + $this->assertEquals('SELECT test FROM test WHERE (test = ?)', (string)$query); } public function testWhereNonArray(): void { $query = $this->getValidQuery(); $query->from('test', ['test'])->where('test = ?', 'test'); - $this->assertEquals('SELECT test FROM test WHERE (test = ?)', $query->__toString()); + $this->assertEquals('SELECT test FROM test WHERE (test = ?)', (string)$query); } public function testExecute(): void @@ -115,42 +115,42 @@ public function testDescribe(): void { $query = $this->getValidQuery(); $query->describe('test'); - $this->assertEquals('DESCRIBE test', $query->__toString()); + $this->assertEquals('DESCRIBE test', (string)$query); } public function testDelete(): void { $query = $this->getValidQuery(); $query->delete('test'); - $this->assertEquals('DELETE FROM test', $query->__toString()); + $this->assertEquals('DELETE FROM test', (string)$query); } public function testInnerJoin(): void { $query = $this->getValidQuery(); $query->from('test', ['test'])->innerJoin('test2', 'test.ing', 'test2.ing'); - $this->assertEquals('SELECT test FROM test INNER JOIN test2 ON test.ing = test2.ing', $query->__toString()); + $this->assertEquals('SELECT test FROM test INNER JOIN test2 ON test.ing = test2.ing', (string)$query); } public function testLeftJoinUsing(): void { $query = $this->getValidQuery(); $query->from('test', ['test'])->leftJoinUsing('test2', 'ing'); - $this->assertEquals('SELECT test FROM test LEFT JOIN test2 USING (ing)', $query->__toString()); + $this->assertEquals('SELECT test FROM test LEFT JOIN test2 USING (ing)', (string)$query); } public function testInsert(): void { $query = $this->getValidQuery(); $query->insert('test', ['testing' => 'test2']); - $this->assertEquals('INSERT INTO test (testing) VALUES (?)', $query->__toString()); + $this->assertEquals('INSERT INTO test (testing) VALUES (?)', (string)$query); } public function testInnerJoinUsing(): void { $query = $this->getValidQuery(); $query->from('test', ['test'])->innerJoinUsing('test2', 'ing'); - $this->assertEquals('SELECT test FROM test INNER JOIN test2 USING (ing)', $query->__toString()); + $this->assertEquals('SELECT test FROM test INNER JOIN test2 USING (ing)', (string)$query); } public function testGetRawQueryWithParams(): void @@ -163,7 +163,7 @@ public function testGetRawQueryWithParams(): void public function testGetRawQueryNoParams(): void { $query = $this->getValidQuery(); - $query->from('test', ['test'])->where('1=1', ['test']); + $query->from('test', ['test'])->where('1=1', 'test'); $this->assertEquals('SELECT test FROM test WHERE (1=1)', $query->getRawQueryWithParams()); } @@ -171,49 +171,50 @@ public function testLeftJoin(): void { $query = $this->getValidQuery(); $query->from('test', ['test'])->leftJoin('test2', 'test.ing', 'test2.ing'); - $this->assertEquals('SELECT test FROM test LEFT JOIN test2 ON test.ing = test2.ing', $query->__toString()); + $this->assertEquals('SELECT test FROM test LEFT JOIN test2 ON test.ing = test2.ing', (string)$query); } public function testRightJoinUsing(): void { $query = $this->getValidQuery(); $query->from('test', ['test'])->rightJoinUsing('test2', 'ing'); - $this->assertEquals('SELECT test FROM test RIGHT JOIN test2 USING (ing)', $query->__toString()); + $this->assertEquals('SELECT test FROM test RIGHT JOIN test2 USING (ing)', (string)$query); } public function testRightJoin(): void { $query = $this->getValidQuery(); $query->from('test', ['test'])->rightJoin('test2', 'test.ing', 'test2.ing'); - $this->assertEquals('SELECT test FROM test RIGHT JOIN test2 ON test.ing = test2.ing', $query->__toString()); + $this->assertEquals('SELECT test FROM test RIGHT JOIN test2 ON test.ing = test2.ing', (string)$query); } public function testOrderBy(): void { $query = $this->getValidQuery(); $query->from('test', ['test'])->orderBy('test'); - $this->assertEquals('SELECT test FROM test ORDER BY test', $query->__toString()); + $this->assertEquals('SELECT test FROM test ORDER BY test', (string)$query); } public function testUpdate(): void { $query = $this->getValidQuery(); $query->update('test', ['field' => 'test']); - $this->assertEquals('UPDATE test SET field = ?', $query->__toString()); + $this->assertEquals('UPDATE test SET field = ?', (string)$query); } public function testHaving(): void { $query = $this->getValidQuery(); $query->from('test', ['test'])->having('test > ?', '1'); - $this->assertEquals('SELECT test FROM test HAVING (test > ?)', $query->__toString()); + $this->assertEquals('SELECT test FROM test HAVING (test > ?)', (string)$query); } public function testHavingMulti(): void { $query = $this->getValidQuery(); - $query->from('test', ['test'])->having('test > ?', ['1']); - $this->assertEquals('SELECT test FROM test HAVING (test > ?)', $query->__toString()); + $query->from('test', ['test'])->having('test > ? and test < ?', '1','3'); + $this->assertEquals('SELECT test FROM test HAVING (test > ? and test < ?)', (string)$query); + $this->assertEquals('SELECT test FROM test HAVING (test > \'1\' and test < \'3\')', $query->getRawQueryWithParams()); } } diff --git a/FeastTests/Database/Table/TableFactoryTest.php b/FeastTests/Database/Table/TableFactoryTest.php index 41b1668..c38df61 100644 --- a/FeastTests/Database/Table/TableFactoryTest.php +++ b/FeastTests/Database/Table/TableFactoryTest.php @@ -66,11 +66,11 @@ public function testGetTableUnrecognized(): void { $dbfInterface = $this->createStub(DatabaseFactory::class); $dbInterface = $this->createStub(DatabaseInterface::class); - $dbInterface->method('getDatabaseType')->willReturn('TableTypeDoesn\'tExist'); + $dbInterface->method('getDatabaseType')->willThrowException(new \TypeError()); $dbfInterface->method('getConnection')->willReturn($dbInterface); $serviceContainer = di(null, \Feast\Enums\ServiceContainer::CLEAR_CONTAINER); $serviceContainer->add(DatabaseFactoryInterface::class, $dbfInterface); - $this->expectException(DatabaseException::class); + $this->expectException(\TypeError::class); TableFactory::getTable('test'); } } diff --git a/FeastTests/DateTest.php b/FeastTests/DateTest.php index 0e275dc..69d7b71 100755 --- a/FeastTests/DateTest.php +++ b/FeastTests/DateTest.php @@ -22,9 +22,6 @@ use Feast\Exception\InvalidDateException; use PHPUnit\Framework\TestCase; -/** - * @psalm-suppress PropertyNotSetInConstructor - */ class DateTest extends TestCase { diff --git a/FeastTests/Exception/ServerFailureExceptionTest.php b/FeastTests/Exception/ServerFailureExceptionTest.php index 01f9072..356f2fd 100644 --- a/FeastTests/Exception/ServerFailureExceptionTest.php +++ b/FeastTests/Exception/ServerFailureExceptionTest.php @@ -20,6 +20,7 @@ namespace Exception; +use Feast\Enums\ResponseCode; use Feast\Exception\ServerFailureException; use Feast\Interfaces\ConfigInterface; use Feast\Interfaces\RequestInterface; @@ -34,7 +35,7 @@ public function testPrintErrorJson(): void { $this->buildContainer('json', true); - $exception = new ServerFailureException('Test', 302, 5, null, Main::RUN_AS_CLI); + $exception = new ServerFailureException('Test', ResponseCode::HTTP_CODE_302, 5, null, Main::RUN_AS_CLI); $this->expectOutputString('{"error":{"message":"Test","code":5}}'); $exception->printError(); @@ -43,7 +44,7 @@ public function testPrintErrorJson(): void public function testPrintError(): void { $this->buildContainer(setting: true); - $exception = new ServerFailureException('Test', 302, 0, null, Main::RUN_AS_WEBAPP); + $exception = new ServerFailureException('Test', ResponseCode::HTTP_CODE_302, 0, null, Main::RUN_AS_WEBAPP); $this->expectOutputRegex('/Test
.*/'); $exception->printError(); @@ -52,7 +53,7 @@ public function testPrintError(): void public function testPrintParentExceptionCliNoParent(): void { $this->buildContainer('json', true); - $exception = new ServerFailureException('Test', 302, 5, null, Main::RUN_AS_CLI); + $exception = new ServerFailureException('Test', ResponseCode::HTTP_CODE_302, 5, null, Main::RUN_AS_CLI); $this->expectOutputString(''); $exception->printParentException(); } @@ -60,7 +61,7 @@ public function testPrintParentExceptionCliNoParent(): void public function testPrintParentExceptionCliWithParent(): void { $this->buildContainer('json', true); - $exception = new ServerFailureException('Test', 302, 5, new \Exception('Test'), Main::RUN_AS_CLI); + $exception = new ServerFailureException('Test', ResponseCode::HTTP_CODE_302, 5, new \Exception('Test'), Main::RUN_AS_CLI); $exception->printParentException(); $output = $this->getActualOutputForAssertion(); $this->assertStringContainsStringIgnoreLineEndingDiff( @@ -73,7 +74,7 @@ public function testPrintParentExceptionCliWithParent(): void public function testPrintExceptionCli(): void { $this->buildContainer(setting: true); - $exception = new ServerFailureException('Test', 302, 5, null, Main::RUN_AS_CLI); + $exception = new ServerFailureException('Test', ResponseCode::HTTP_CODE_302, 5, null, Main::RUN_AS_CLI); $exception->printError(); $output = $this->getActualOutputForAssertion(); $this->assertStringContainsStringIgnoreLineEndingDiff( @@ -86,7 +87,7 @@ public function testPrintExceptionCli(): void public function testPrintParentExceptionWebNoParent(): void { $this->buildContainer('json', true); - $exception = new ServerFailureException('Test', 302, 5, null, Main::RUN_AS_WEBAPP); + $exception = new ServerFailureException('Test', ResponseCode::HTTP_CODE_302, 5, null, Main::RUN_AS_WEBAPP); $this->expectOutputString(''); $exception->printParentException(); } @@ -94,7 +95,7 @@ public function testPrintParentExceptionWebNoParent(): void public function testPrintParentExceptionWebWithParent(): void { $this->buildContainer('json', true); - $exception = new ServerFailureException('Test', 302, 5, new \Exception('Test'), Main::RUN_AS_WEBAPP); + $exception = new ServerFailureException('Test', ResponseCode::HTTP_CODE_302, 5, new \Exception('Test'), Main::RUN_AS_WEBAPP); $this->expectOutputRegex('/Test
Thrown on.*printParentException(); } @@ -102,8 +103,8 @@ public function testPrintParentExceptionWebWithParent(): void public function testGetResponseCode(): void { $this->buildContainer('json', true); - $exception = new ServerFailureException('Test', 302, 5, null, Main::RUN_AS_CLI); - $this->assertEquals(302, $exception->getResponseCode()); + $exception = new ServerFailureException('Test', ResponseCode::HTTP_CODE_302, 5, null, Main::RUN_AS_CLI); + $this->assertEquals(ResponseCode::HTTP_CODE_302, $exception->getResponseCode()); } protected function buildContainer(?string $format = null, ?bool $setting = null): void diff --git a/FeastTests/HttpRequest/CurlTest.php b/FeastTests/HttpRequest/CurlTest.php index df73b9e..ff4a48c 100644 --- a/FeastTests/HttpRequest/CurlTest.php +++ b/FeastTests/HttpRequest/CurlTest.php @@ -19,6 +19,8 @@ namespace HttpRequest; +use Feast\Enums\RequestMethod; +use Feast\Enums\ResponseCode; use Feast\Exception\BadRequestException; use Feast\Exception\CurlException; use Feast\HttpRequest\Curl; @@ -31,7 +33,7 @@ public function testGet(): void { $request = new Curl(); $request->get('http://www.google.com/'); - $this->assertEquals('GET', $request->getMethod()); + $this->assertEquals(RequestMethod::GET, $request->getMethod()); $this->assertTrue($request->getUrl() === 'http://www.google.com/'); /** THIS METHOD IS EXPECTED TO FAIL WITH AN EXCEPTION BECAUSE WE ARE MOCKING THE CURL ITEM WITH stdClass */ $this->expectException(\TypeError::class); @@ -42,7 +44,7 @@ public function testPatch(): void { $request = new Curl(); $request->patch('http://www.google.com/'); - $this->assertEquals('PATCH', $request->getMethod()); + $this->assertEquals(RequestMethod::PATCH, $request->getMethod()); $this->assertTrue($request->getUrl() === 'http://www.google.com/'); } @@ -71,7 +73,7 @@ public function testPost(): void { $request = new Curl(); $request->post('http://www.google.com/'); - $this->assertEquals('POST', $request->getMethod()); + $this->assertEquals(RequestMethod::POST, $request->getMethod()); $this->assertTrue($request->getUrl() === 'http://www.google.com/'); } @@ -79,7 +81,7 @@ public function testPostJson(): void { $request = new Curl(); $request->postJson('http://www.google.com/'); - $this->assertEquals('POST', $request->getMethod()); + $this->assertEquals(RequestMethod::POST, $request->getMethod()); $this->assertEquals(HttpRequest::CONTENT_TYPE_JSON, $request->getContentType()); } @@ -87,7 +89,7 @@ public function testPut(): void { $request = new Curl(); $request->put('http://www.google.com/'); - $this->assertEquals('PUT', $request->getMethod()); + $this->assertEquals(RequestMethod::PUT, $request->getMethod()); $this->assertTrue($request->getUrl() === 'http://www.google.com/'); } @@ -95,7 +97,7 @@ public function testDelete(): void { $request = new Curl(); $request->delete('http://www.google.com/'); - $this->assertEquals('DELETE', $request->getMethod()); + $this->assertEquals(RequestMethod::DELETE, $request->getMethod()); $this->assertTrue($request->getUrl() === 'http://www.google.com/'); } @@ -146,7 +148,7 @@ public function testMakeRequestAndGetResponseCode(): void $request = new Curl(); $request->get('https://www.google.com/html'); $request->makeRequest(); - $this->assertEquals(200, $request->getResponseCode()); + $this->assertEquals(ResponseCode::HTTP_CODE_200, $request->getResponseCode()); $this->assertEqualsIgnoreLineEndingDiff( ' @@ -168,7 +170,7 @@ public function testGetResultAsXml(): void $request = new Curl(); $request->get('https://www.google.com/xml'); $request->makeRequest(); - $this->assertEquals(200, $request->getResponseCode()); + $this->assertEquals(ResponseCode::HTTP_CODE_200, $request->getResponseCode()); $this->assertEqualsIgnoreLineEndingDiff( ' @@ -190,7 +192,7 @@ public function testGetInvalidAsXml(): void $request = new Curl(); $request->get('https://www.google.com/json'); $request->makeRequest(); - $this->assertEquals(200, $request->getResponseCode()); + $this->assertEquals(ResponseCode::HTTP_CODE_200, $request->getResponseCode()); $this->assertNull( $request->getResponseAsXml() ); @@ -202,7 +204,7 @@ public function testGetResponseCode(): void $request->get('https://www.google.com/json'); $request->makeRequest(); $response = $request->getResponse(); - $this->assertEquals(200, $response->getResponseCode()); + $this->assertEquals(ResponseCode::HTTP_CODE_200, $response->getResponseCode()); $this->assertNull( $request->getResponseAsXml() ); @@ -280,7 +282,7 @@ public function testGetResultAsJson(): void $request = new Curl(); $request->get('https://www.google.com/json'); $request->makeRequest(); - $this->assertEquals(200, $request->getResponseCode()); + $this->assertEquals(ResponseCode::HTTP_CODE_200, $request->getResponseCode()); $response = $request->getResponseAsJson(); $this->assertEquals('feast', $response->test); } @@ -290,7 +292,7 @@ public function testGetResultAsJsonInvalid(): void $request = new Curl(); $request->get('https://www.google.com/html'); $request->makeRequest(); - $this->assertEquals(200, $request->getResponseCode()); + $this->assertEquals(ResponseCode::HTTP_CODE_200, $request->getResponseCode()); $response = $request->getResponseAsJson(); $this->assertNull($response); } @@ -300,7 +302,7 @@ public function testGetResultCurlFailed(): void $request = new Curl(); $request->get('https://www.google.com/fail'); $request->makeRequest(); - $this->assertEquals(500, $request->getResponseCode()); + $this->assertEquals(ResponseCode::HTTP_CODE_500, $request->getResponseCode()); $response = $request->getResponseAsString(); $this->assertEquals('', $response); } @@ -439,7 +441,7 @@ public function testAddArgumentsPostJson(): void $this->assertIsArray($arguments['type']); $this->assertEquals('text', $arguments['type'][0]); $this->assertEquals('pass', $arguments['type'][1]); - $this->assertEquals('POST', $request->getMethod()); + $this->assertEquals(RequestMethod::POST, $request->getMethod()); $request->makeRequest(); } @@ -459,7 +461,7 @@ public function testAddArgumentsPutJson(): void $this->assertIsArray($arguments['type']); $this->assertEquals('text', $arguments['type'][0]); $this->assertEquals('pass', $arguments['type'][1]); - $this->assertEquals('PUT', $request->getMethod()); + $this->assertEquals(RequestMethod::PUT, $request->getMethod()); $request->makeRequest(); } @@ -479,7 +481,7 @@ public function testAddArgumentsPatchJson(): void $this->assertIsArray($arguments['type']); $this->assertEquals('text', $arguments['type'][0]); $this->assertEquals('pass', $arguments['type'][1]); - $this->assertEquals('PATCH', $request->getMethod()); + $this->assertEquals(RequestMethod::PATCH, $request->getMethod()); $request->makeRequest(); } diff --git a/FeastTests/HttpRequest/SimpleTest.php b/FeastTests/HttpRequest/SimpleTest.php index 2541e7e..82e7ad6 100644 --- a/FeastTests/HttpRequest/SimpleTest.php +++ b/FeastTests/HttpRequest/SimpleTest.php @@ -160,7 +160,7 @@ public function testAddArgumentsPostJson(): void $this->assertEquals('text', $arguments['type'][0]); $this->assertEquals('pass', $arguments['type'][1]); $request->makeRequest(); - $this->assertEquals('POST', $request->getMethod()); + $this->assertEquals('POST', $request->getMethod()->value); } public function testPut(): void @@ -175,7 +175,7 @@ public function testPut(): void ); $this->assertTrue($request->getUrl() === 'https://www.google.com/'); - $this->assertEquals('PUT', $request->getMethod()); + $this->assertEquals('PUT', $request->getMethod()->value); $request->makeRequest(); } @@ -191,7 +191,7 @@ public function testPatch(): void ); $this->assertTrue($request->getUrl() === 'https://www.google.com/'); - $this->assertEquals('PATCH', $request->getMethod()); + $this->assertEquals('PATCH', $request->getMethod()->value); $request->makeRequest(); } diff --git a/FeastTests/IdentityTest.php b/FeastTests/IdentityTest.php index df49e2a..21b900d 100644 --- a/FeastTests/IdentityTest.php +++ b/FeastTests/IdentityTest.php @@ -18,7 +18,6 @@ declare(strict_types=1); use Feast\Interfaces\ConfigInterface; -use Feast\ServiceContainer\ServiceContainer; use Feast\Session\Identity; use Feast\Session\Session; use Mocks\MockUser; @@ -41,7 +40,7 @@ public function testGetUser(): void $config = $this->createStub(ConfigInterface::class); $config->method('getSetting')->willReturn('test'); - $identity = new Identity($config, $session); + $identity = new Identity($config,$session); $user = $identity->getUser(); $this->assertEquals('testUser', $user->user); } @@ -69,7 +68,7 @@ public function testSaveUser(): void $testUser = new MockUser(); $testUser->user = 'testUser'; - $identity = new Identity($config, $session); + $identity = new Identity($config,$session); $user = $identity->getUser(); $this->assertEquals(null, $user); @@ -89,7 +88,7 @@ public function testDestroyUser(): void $testUser = new MockUser(); $testUser->user = 'testUser'; - $identity = new Identity($config, $session); + $identity = new Identity($config,$session); $identity->saveUser($testUser); $user = $identity->getUser(); diff --git a/FeastTests/Logger/LoggerTest.php b/FeastTests/Logger/LoggerTest.php index efa1749..966f32d 100644 --- a/FeastTests/Logger/LoggerTest.php +++ b/FeastTests/Logger/LoggerTest.php @@ -243,7 +243,7 @@ public function testRawLogHigherLevel(): void $config = $this->createStub(Config::class); $this->updateConfigStub($config, LogLevel::EMERGENCY, false); $logger = new Logger($config, Main::RUN_AS_CLI); - $logger->rawLog(LogLevelCode::ALERT, 'you noticing me'); + $logger->rawLog(LogLevelCode::ALERT->value, 'you noticing me'); $output = $this->getActualOutputForAssertion(); $this->assertStringNotContainsString('you noticing me', $output); } @@ -253,7 +253,7 @@ public function testRawLogSysLogNoGo(): void $config = $this->createStub(Config::class); $this->updateConfigStub($config, LogLevel::ALERT, true); $logger = new Logger($config, Main::RUN_AS_CLI); - $logger->rawLog(LogLevelCode::DEBUG, 'you noticing me'); + $logger->rawLog(LogLevelCode::DEBUG->value, 'you noticing me'); $output = $this->getActualOutputForAssertion(); $this->assertStringNotContainsString('you noticing me', $output); } @@ -263,7 +263,7 @@ public function testRawLogSysLogDebug(): void $config = $this->createStub(Config::class); $this->updateConfigStub($config, LogLevel::DEBUG, true); $logger = new Logger($config, Main::RUN_AS_CLI); - $logger->rawLog(LogLevelCode::DEBUG, 'you noticing me'); + $logger->rawLog(LogLevelCode::DEBUG->value, 'you noticing me'); $output = $this->getActualOutputForAssertion(); $this->assertStringContainsString('you noticing me', $output); } @@ -273,7 +273,7 @@ public function testRawLogSysLogNotice(): void $config = $this->createStub(Config::class); $this->updateConfigStub($config, LogLevel::DEBUG, true); $logger = new Logger($config, Main::RUN_AS_CLI); - $logger->rawLog(LogLevelCode::NOTICE, 'you noticing me'); + $logger->rawLog(LogLevelCode::NOTICE->value, 'you noticing me'); $output = $this->getActualOutputForAssertion(); $this->assertStringContainsString('you noticing me', $output); } @@ -283,7 +283,7 @@ public function testRawLogSysLogWarning(): void $config = $this->createStub(Config::class); $this->updateConfigStub($config, LogLevel::DEBUG, true); $logger = new Logger($config, Main::RUN_AS_CLI); - $logger->rawLog(LogLevelCode::WARNING, 'you noticing me'); + $logger->rawLog(LogLevelCode::WARNING->value, 'you noticing me'); $output = $this->getActualOutputForAssertion(); $this->assertStringContainsString('you noticing me', $output); } @@ -293,7 +293,7 @@ public function testRawLogSysLogError(): void $config = $this->createStub(Config::class); $this->updateConfigStub($config, LogLevel::DEBUG, true); $logger = new Logger($config, Main::RUN_AS_CLI); - $logger->rawLog(LogLevelCode::ERROR, 'you noticing me'); + $logger->rawLog(LogLevelCode::ERROR->value, 'you noticing me'); $output = $this->getActualOutputForAssertion(); $this->assertStringContainsString('you noticing me', $output); } @@ -303,7 +303,7 @@ public function testRawLogSysLogCritical(): void $config = $this->createStub(Config::class); $this->updateConfigStub($config, LogLevel::DEBUG, true); $logger = new Logger($config, Main::RUN_AS_CLI); - $logger->rawLog(LogLevelCode::CRITICAL, 'you noticing me'); + $logger->rawLog(LogLevelCode::CRITICAL->value, 'you noticing me'); $output = $this->getActualOutputForAssertion(); $this->assertStringContainsString('you noticing me', $output); } @@ -313,7 +313,7 @@ public function testRawLogSysLogEmergency(): void $config = $this->createStub(Config::class); $this->updateConfigStub($config, LogLevel::DEBUG, true); $logger = new Logger($config, Main::RUN_AS_CLI); - $logger->rawLog(LogLevelCode::EMERGENCY, 'you noticing me'); + $logger->rawLog(LogLevelCode::EMERGENCY->value, 'you noticing me'); $output = $this->getActualOutputForAssertion(); $this->assertStringContainsString('you noticing me', $output); } @@ -323,7 +323,7 @@ public function testRawLogSysLogAlert(): void $config = $this->createStub(Config::class); $this->updateConfigStub($config, LogLevel::DEBUG, true); $logger = new Logger($config, Main::RUN_AS_CLI); - $logger->rawLog(LogLevelCode::ALERT, 'you noticing me'); + $logger->rawLog(LogLevelCode::ALERT->value, 'you noticing me'); $output = $this->getActualOutputForAssertion(); $this->assertStringContainsString('you noticing me', $output); } @@ -333,7 +333,7 @@ public function testRawLogSysLogInfo(): void $config = $this->createStub(Config::class); $this->updateConfigStub($config, LogLevel::DEBUG, true); $logger = new Logger($config, Main::RUN_AS_CLI); - $logger->rawLog(LogLevelCode::INFO, 'you noticing me'); + $logger->rawLog(LogLevelCode::INFO->value, 'you noticing me'); $output = $this->getActualOutputForAssertion(); $this->assertStringContainsString('you noticing me', $output); } diff --git a/FeastTests/Mapper/JobMapper.php b/FeastTests/Mapper/JobMapper.php index 3cd56c9..33a2e41 100644 --- a/FeastTests/Mapper/JobMapper.php +++ b/FeastTests/Mapper/JobMapper.php @@ -30,33 +30,43 @@ public function findByPrimaryKey(int|string $value, bool $validate = false): ?Jo return null; } + /** + * Find a single pending job if available. + * + * @param array $queues + * @return \Model\Job|null + * @throws \Feast\Exception\ServerFailureException + * @throws \Feast\ServiceContainer\NotFoundException + */ public function findOnePendingByQueues(array $queues): ?Job { - $query = $this->getQueryBase()->where('status = ?','pending')->where('tries < max_tries and queue_name IN (' . str_repeat('?,',count($queues)-1) . '?)',$queues); + $query = $this->getQueryBase()->where('status = ?', 'pending')->where( + 'tries < max_tries and queue_name IN (' . str_repeat('?,', count($queues) - 1) . '?)', + ...$queues + ); $return = $this->fetchOne($query); - if ( $return === null || $return instanceof Job ) { + if ($return === null || $return instanceof Job) { return $return; } return null; } /** - * Mark job as running. Method name is incorrect and will be removed in 2.0 + * Mark job as running. * * @param \Model\Job $job * @return bool * @throws \Exception - * @deprecated */ - public function markJobPendingIfAble(Job $job): bool + public function markJobRunningIfAble(Job $job): bool { - trigger_error('This method is deprecated. Use JobMapper::markJobRunningIfAble',E_USER_DEPRECATED); - return $this->markJobRunningIfAble($job); - } - - public function markJobRunningIfAble(Job $job): bool { - $query = $this->connection->update(self::TABLE_NAME,['status' => \Feast\Jobs\QueueableJob::JOB_STATUS_RUNNING]) - ->where('job_id = ? and status IN (?,?)',[$job->job_id,\Feast\Jobs\QueueableJob::JOB_STATUS_PENDING,\Feast\Jobs\QueueableJob::JOB_STATUS_FAILED]); + $query = $this->connection->update(self::TABLE_NAME, ['status' => \Feast\Jobs\QueueableJob::JOB_STATUS_RUNNING]) + ->where( + 'job_id = ? and status IN (?,?)', + $job->job_id, + \Feast\Jobs\QueueableJob::JOB_STATUS_PENDING, + \Feast\Jobs\QueueableJob::JOB_STATUS_FAILED + ); $result = $query->execute(); return $result->rowCount() !== 0; } diff --git a/FeastTests/Mocks/LoggerMock.php b/FeastTests/Mocks/LoggerMock.php index 6c2b47e..f8c1370 100644 --- a/FeastTests/Mocks/LoggerMock.php +++ b/FeastTests/Mocks/LoggerMock.php @@ -20,6 +20,7 @@ namespace Mocks; +use Feast\Enums\LogLevelCode; use Feast\Interfaces\LoggerInterface; class LoggerMock implements LoggerInterface diff --git a/FeastTests/ResponseTest.php b/FeastTests/ResponseTest.php index 09adbb8..d4a511b 100644 --- a/FeastTests/ResponseTest.php +++ b/FeastTests/ResponseTest.php @@ -18,7 +18,6 @@ declare(strict_types=1); use Feast\Enums\ResponseCode; -use Feast\Exception\ResponseException; use Feast\Response; use PHPUnit\Framework\TestCase; @@ -48,7 +47,7 @@ public function testUpdateResponse(): void public function testInvalidResponse(): void { $response = new Response(); - $this->expectException(ResponseException::class); + $this->expectException(TypeError::class); $response->setResponseCode(99999); } @@ -142,6 +141,16 @@ public function testRedirect(): void $this->assertEquals('/redirecting', $response->getRedirectPath()); } + public function testIsValidResponseCodeTrue(): void + { + $this->assertTrue(ResponseCode::isValidResponseCode(200)); + } + + public function testIsValidResponseCodeFalse(): void + { + $this->assertFalse(ResponseCode::isValidResponseCode(2000)); + } + public function testSetHeader(): void { $response = new Response(); diff --git a/FeastTests/ViewTest.php b/FeastTests/ViewTest.php index fa1c10f..0bfacf8 100644 --- a/FeastTests/ViewTest.php +++ b/FeastTests/ViewTest.php @@ -18,13 +18,10 @@ declare(strict_types=1); -use Feast\Enums\DocTypes; +use Feast\Enums\DocType; use Feast\Interfaces\ConfigInterface; use Feast\View; -/** - * @psalm-suppress PropertyNotSetInConstructor - */ class ViewTest extends OsSafeTestCase { protected View $view; @@ -41,7 +38,7 @@ public function setUp(): void $this->returnValueMap( [ ['siteurl', null, 'test'], - ['html.doctype', DocTypes::HTML_5, DocTypes::HTML_4_01_STRICT] + ['html.doctype', DocType::HTML_5->value, DocType::HTML_4_01_STRICT->value] ] ) ); @@ -66,24 +63,24 @@ public function testGetDoctypeHtml401Strict(): void '', trim($this->view->getDtd()) ); - $this->assertEquals(DocTypes::HTML_4_01_STRICT, $this->view->getDocType()); + $this->assertEquals(DocType::HTML_4_01_STRICT, $this->view->getDocType()); } public function testGetDoctypeHtml5(): void { - $this->view->setDoctype(DocTypes::HTML_5); + $this->view->setDoctype(DocType::HTML_5); $this->assertEqualsIgnoreLineEndingDiff( ' ', trim($this->view->getDtd()) ); - $this->assertEquals(DocTypes::HTML_5, $this->view->getDocType()); + $this->assertEquals(DocType::HTML_5, $this->view->getDocType()); } public function testGetDoctypeXhtml10Strict(): void { - $this->view->setDoctype(DocTypes::XHTML_1_0_STRICT); + $this->view->setDoctype(DocType::XHTML_1_0_STRICT); $this->assertEqualsIgnoreLineEndingDiff( '', trim($this->view->getDtd()) ); - $this->assertEquals(DocTypes::XHTML_1_0_STRICT, $this->view->getDocType()); + $this->assertEquals(DocType::XHTML_1_0_STRICT, $this->view->getDocType()); } public function testGetDoctypeXhtml11(): void { - $this->view->setDoctype(DocTypes::XHTML_1_1); + $this->view->setDoctype(DocType::XHTML_1_1); $this->assertEquals( '', trim($this->view->getDtd()) ); - $this->assertEquals(DocTypes::XHTML_1_1, $this->view->getDocType()); + $this->assertEquals(DocType::XHTML_1_1, $this->view->getDocType()); } public function testGetDoctypeXhtml10Transitional(): void { - $this->view->setDoctype(DocTypes::XHTML_1_0_TRANSITIONAL); + $this->view->setDoctype(DocType::XHTML_1_0_TRANSITIONAL); $this->assertEquals( '', trim($this->view->getDtd()) ); - $this->assertEquals(DocTypes::XHTML_1_0_TRANSITIONAL, $this->view->getDocType()); + $this->assertEquals(DocType::XHTML_1_0_TRANSITIONAL, $this->view->getDocType()); } public function testGetDoctypeHtml401Frameset(): void { - $this->view->setDoctype(DocTypes::HTML_4_01_FRAMESET); + $this->view->setDoctype(DocType::HTML_4_01_FRAMESET); $this->assertEquals( '', trim($this->view->getDtd()) ); - $this->assertEquals(DocTypes::HTML_4_01_FRAMESET, $this->view->getDocType()); + $this->assertEquals(DocType::HTML_4_01_FRAMESET, $this->view->getDocType()); } public function testGetDoctypeXhtml10Frameset(): void { - $this->view->setDoctype(DocTypes::XHTML_1_0_FRAMESET); + $this->view->setDoctype(DocType::XHTML_1_0_FRAMESET); $this->assertEquals( '', trim($this->view->getDtd()) ); - $this->assertEquals(DocTypes::XHTML_1_0_FRAMESET, $this->view->getDocType()); + $this->assertEquals(DocType::XHTML_1_0_FRAMESET, $this->view->getDocType()); } public function testGetDoctypeHtml401Transitional(): void { - $this->view->setDoctype(DocTypes::HTML_4_01_TRANSITIONAL); + $this->view->setDoctype(DocType::HTML_4_01_TRANSITIONAL); $this->assertEquals( '', trim($this->view->getDtd()) ); - $this->assertEquals(DocTypes::HTML_4_01_TRANSITIONAL, $this->view->getDocType()); + $this->assertEquals(DocType::HTML_4_01_TRANSITIONAL, $this->view->getDocType()); } public function testSetInvalidDoctype(): void { - $this->expectException(\Exception::class); + $this->expectException(\TypeError::class); $this->view->setDoctype('This is bad data.'); } @@ -220,7 +217,7 @@ public function testGetEncodingHtml(): void public function testGetEncodingXhtmlHtml(): void { - $this->view->setDoctype(DocTypes::XHTML_1_0_STRICT); + $this->view->setDoctype(DocType::XHTML_1_0_STRICT); $this->view->setEncoding('EN'); $this->assertEquals( '', @@ -231,7 +228,7 @@ public function testGetEncodingXhtmlHtml(): void public function testGetEncodingHtml5Html(): void { - $this->view->setDoctype(DocTypes::HTML_5); + $this->view->setDoctype(DocType::HTML_5); $this->view->setEncoding('EN'); $this->assertEquals( '', @@ -242,7 +239,7 @@ public function testGetEncodingHtml5Html(): void public function testSetDocTypeGibberish(): void { - $this->expectException(Exception::class); + $this->expectException(TypeError::class); $this->view->setDoctype('FeastHtml'); } diff --git a/FeastTests/githubphpunit.xml b/FeastTests/githubphpunit.xml index 0bd5f39..f65e021 100644 --- a/FeastTests/githubphpunit.xml +++ b/FeastTests/githubphpunit.xml @@ -1,26 +1,21 @@ - - - - . - - - - - ../ - - - ../FeastTests - ../Install - ../PsalmLoader.php - - - - - - \ No newline at end of file + + + + + . + + + + + ../ + + + ../FeastTests + ../Install + ../PsalmLoader.php + + + + + + diff --git a/Form/Field.php b/Form/Field.php index 36d08ea..cb5b89a 100644 --- a/Form/Field.php +++ b/Form/Field.php @@ -34,8 +34,8 @@ abstract class Field { - public const LABEL_POSITION_FIRST = 'first'; - public const LABEL_POSITION_LAST = 'last'; + final public const LABEL_POSITION_FIRST = 'first'; + final public const LABEL_POSITION_LAST = 'last'; public string $class = ''; public ?string $default = null; diff --git a/Form/Label.php b/Form/Label.php index 689e3ab..91df1e0 100755 --- a/Form/Label.php +++ b/Form/Label.php @@ -23,8 +23,8 @@ class Label { - public const LABEL_POSITION_FIRST = 'first'; - public const LABEL_POSITION_LAST = 'last'; + final public const LABEL_POSITION_FIRST = 'first'; + final public const LABEL_POSITION_LAST = 'last'; public function __construct( public string $text = '', diff --git a/Form/Validator/Url.php b/Form/Validator/Url.php index d73fbcd..cea6eb9 100644 --- a/Form/Validator/Url.php +++ b/Form/Validator/Url.php @@ -52,7 +52,7 @@ public static function validate( $errors[] = [$key, 'URL']; $valid = false; } - + return $valid; } diff --git a/HttpController.php b/HttpController.php index a8c5615..c8c39a7 100755 --- a/HttpController.php +++ b/HttpController.php @@ -126,7 +126,7 @@ public function alwaysJson(string $actionName): bool * @param array $queryString * @param string|null $module * @param string $route - * @param int $code (30x) + * @param ResponseCode $code (30x) * @throws NotFoundException * @throws Exception */ @@ -137,7 +137,7 @@ public function redirect( array $queryString = [], ?string $module = null, string $route = '', - int $code = ResponseCode::HTTP_CODE_302 + ResponseCode $code = ResponseCode::HTTP_CODE_302 ): void { $router = $this->di->get(RouterInterface::class); $response = $this->di->get(ResponseInterface::class); @@ -152,10 +152,10 @@ public function redirect( * Redirect to an external link after all post dispatch plugins finish. * * @param string $url The URL to redirect to - * @param int $code Redirect code to use (default 302) + * @param ResponseCode $code Redirect code to use (default 302) * @throws NotFoundException */ - public function externalRedirect(string $url, int $code = ResponseCode::HTTP_CODE_302): void + public function externalRedirect(string $url, ResponseCode $code = ResponseCode::HTTP_CODE_302): void { $response = $this->di->get(ResponseInterface::class); $response->redirect($url, $code); diff --git a/HttpRequest/Curl.php b/HttpRequest/Curl.php index 8dfa095..3491d86 100644 --- a/HttpRequest/Curl.php +++ b/HttpRequest/Curl.php @@ -73,7 +73,7 @@ public function makeRequest(): HttpRequestInterface { $url = $this->url ?? ''; curl_setopt($this->curl, CURLOPT_URL, $url); - curl_setopt($this->curl, CURLOPT_CUSTOMREQUEST, $this->method); + curl_setopt($this->curl, CURLOPT_CUSTOMREQUEST, $this->method->value); curl_setopt($this->curl, CURLOPT_USERAGENT, $this->userAgent); $header = []; $header[] = 'Accept-language: ' . $this->language; diff --git a/HttpRequest/HttpRequest.php b/HttpRequest/HttpRequest.php index ba34a1e..8193040 100644 --- a/HttpRequest/HttpRequest.php +++ b/HttpRequest/HttpRequest.php @@ -40,7 +40,7 @@ abstract class HttpRequest implements HttpRequestInterface public const CONTENT_TYPE_JSON = 'application/json'; public const DEFAULT_USER_AGENT = 'Mozilla/5.0 (X11; Linux x86_64) FeastFramework/1.0'; - protected string $method; + protected RequestMethod $method; /** @var array $cookies */ protected array $cookies; protected array $arguments; @@ -49,7 +49,7 @@ abstract class HttpRequest implements HttpRequestInterface protected ?string $username = null; protected ?string $password = null; protected ?Response $response = null; - protected ?int $responseCode = null; + protected ?ResponseCode $responseCode = null; protected string $userAgent; protected ?string $referer = null; protected ?string $contentType = null; @@ -145,9 +145,9 @@ public function delete(string $url): HttpRequestInterface /** * Set request method. * - * @param string $method + * @param RequestMethod $method */ - private function setMethod(string $method): void + private function setMethod(RequestMethod $method): void { $this->contentType = null; $this->arguments = []; @@ -259,10 +259,9 @@ public function getArguments(): array * Set the url for the request. * * @param string $url - * @return HttpRequest - * @throws ServerFailureException + * @throws BadRequestException */ - private function setUrl(string $url): HttpRequestInterface + private function setUrl(string $url): void { $this->url = $url; if (!str_contains($url, 'http://') && !str_contains($url, 'https://')) { @@ -278,8 +277,6 @@ private function setUrl(string $url): HttpRequestInterface } else { $this->baseUrl = $url; } - - return $this; } /** @@ -295,9 +292,9 @@ public function getUrl(): string /** * Get request method. * - * @return string + * @return RequestMethod */ - public function getMethod(): string + public function getMethod(): RequestMethod { return $this->method; } @@ -332,8 +329,11 @@ public function getUserAgent(): string * @param string $password * @return HttpRequest */ - public function authenticate(string $username, string $password): HttpRequestInterface - { + public function authenticate( + string $username, + #[\SensitiveParameter] + string $password + ): HttpRequestInterface { $this->username = $username; $this->password = $password; @@ -426,7 +426,9 @@ protected function parseResponseCode(array $responseHeaders): void return; } $status = explode(' ', $responseHeaders[0]); - $this->responseCode = !empty($status[1]) ? (int)$status[1] : ResponseCode::HTTP_CODE_500; + $responseCode = !empty($status[1]) ? (int)$status[1] : ResponseCode::HTTP_CODE_500->value; + $this->responseCode = ResponseCode::tryFrom($responseCode) ?? ResponseCode::HTTP_CODE_500; + } /** @@ -495,9 +497,9 @@ public function getResponseAsString(): string /** * Get the request result as a json object. * - * @return stdClass|null + * @return array|stdClass|null */ - public function getResponseAsJson(): ?stdClass + public function getResponseAsJson(): null|array|stdClass { if ($this->response === null) { return null; @@ -520,7 +522,7 @@ public function getResponseAsXml(): ?SimpleXMLElement /** * Get the \Feast\Response object for a finished request. - * + * * @return Response|null */ public function getResponse(): ?Response @@ -592,9 +594,9 @@ public function getReferer(): ?string /** * Get the http response code for the request. * - * @return int|null + * @return ResponseCode|null */ - public function getResponseCode(): ?int + public function getResponseCode(): ?ResponseCode { return $this->responseCode; } diff --git a/HttpRequest/Response.php b/HttpRequest/Response.php index 21986ad..dd9c002 100644 --- a/HttpRequest/Response.php +++ b/HttpRequest/Response.php @@ -33,7 +33,7 @@ class Response protected CollectionList $headers; protected ?string $contentType = null; protected ?string $contentTypeHeader = null; - public function __construct(protected string $rawResponse, protected int $responseCode) + public function __construct(protected string $rawResponse, protected ResponseCode $responseCode) { $this->headers = new CollectionList('string'); } @@ -79,7 +79,7 @@ public function getResponseAsText(): string return $this->rawResponse; } - public function getResultAsJson(): ?stdClass + public function getResultAsJson(): stdClass|array|null { try { /** @var stdClass */ @@ -101,7 +101,7 @@ public function getResultAsXml(): ?SimpleXMLElement } } - public function getResponseCode(): int + public function getResponseCode(): ResponseCode { return $this->responseCode; } diff --git a/HttpRequest/Simple.php b/HttpRequest/Simple.php index 8e3e80b..5e617e3 100644 --- a/HttpRequest/Simple.php +++ b/HttpRequest/Simple.php @@ -42,7 +42,7 @@ public function makeRequest(): Simple } $url = $this->url; $context = []; - $context['method'] = $this->method; + $context['method'] = $this->method->value; $context['user_agent'] = $this->userAgent; $context['request_fulluri'] = true; $header = 'Accept-language: ' . $this->language . "\r\n"; diff --git a/Install/Mapper/JobMapper.php.txt b/Install/Mapper/JobMapper.php.txt index 1bda2f6..3facf8a 100644 --- a/Install/Mapper/JobMapper.php.txt +++ b/Install/Mapper/JobMapper.php.txt @@ -28,33 +28,43 @@ class JobMapper extends BaseMapper return null; } + /** + * Find a single pending job if available. + * + * @param array $queues + * @return \Model\Job|null + * @throws \Feast\Exception\ServerFailureException + * @throws \Feast\ServiceContainer\NotFoundException + */ public function findOnePendingByQueues(array $queues): ?Job { - $query = $this->getQueryBase()->where('status = ?','pending')->where('tries < max_tries and queue_name IN (' . str_repeat('?,',count($queues)-1) . '?)',$queues); + $query = $this->getQueryBase()->where('status = ?', 'pending')->where( + 'tries < max_tries and queue_name IN (' . str_repeat('?,', count($queues) - 1) . '?)', + ...$queues + ); $return = $this->fetchOne($query); - if ( $return === null || $return instanceof Job ) { + if ($return === null || $return instanceof Job) { return $return; } return null; } - + /** - * Mark job as running. Method name is incorrect and will be removed in 2.0 + * Mark job as running. * * @param \Model\Job $job * @return bool * @throws \Exception - * @deprecated */ - public function markJobPendingIfAble(Job $job): bool + public function markJobRunningIfAble(Job $job): bool { - trigger_error('This method is deprecated. Use JobMapper::markJobRunningIfAble',E_USER_DEPRECATED); - return $this->markJobRunningIfAble($job); - } - - public function markJobRunningIfAble(Job $job): bool { - $query = $this->connection->update(self::TABLE_NAME,['status' => \Feast\Jobs\QueueableJob::JOB_STATUS_RUNNING]) - ->where('job_id = ? and status IN (?,?)',[$job->job_id,\Feast\Jobs\QueueableJob::JOB_STATUS_PENDING,\Feast\Jobs\QueueableJob::JOB_STATUS_FAILED]); + $query = $this->connection->update(self::TABLE_NAME, ['status' => \Feast\Jobs\QueueableJob::JOB_STATUS_RUNNING]) + ->where( + 'job_id = ? and status IN (?,?)', + $job->job_id, + \Feast\Jobs\QueueableJob::JOB_STATUS_PENDING, + \Feast\Jobs\QueueableJob::JOB_STATUS_FAILED + ); $result = $query->execute(); return $result->rowCount() !== 0; } diff --git a/Install/Model/Job.php.txt b/Install/Model/Job.php.txt index 53f9924..accb2a3 100644 --- a/Install/Model/Job.php.txt +++ b/Install/Model/Job.php.txt @@ -20,4 +20,4 @@ class Job extends BaseModel public int $tries; public int $max_tries; public string $queue_name; -} \ No newline at end of file +} diff --git a/Install/Model/Migration.php.txt b/Install/Model/Migration.php.txt index 0b6c109..bc497f2 100644 --- a/Install/Model/Migration.php.txt +++ b/Install/Model/Migration.php.txt @@ -48,4 +48,4 @@ class Migration extends BaseModel $this->status = 'down'; $this->save(); } -} \ No newline at end of file +} diff --git a/Install/famine b/Install/famine index 95409c9..9571e21 100755 --- a/Install/famine +++ b/Install/famine @@ -25,11 +25,11 @@ use Feast\ServiceContainer\ServiceContainer; chdir(__DIR__); if (file_exists('vendor/autoload.php')) { require_once('vendor/autoload.php'); -}; +} // Set up framework -define('APPLICATION_ROOT', __DIR__ . DIRECTORY_SEPARATOR); -define('CONTROLLERS_FOLDER', 'Controllers'); -define('PLUGINS_FOLDER', 'Plugins'); +const APPLICATION_ROOT = __DIR__ . DIRECTORY_SEPARATOR; +const CONTROLLERS_FOLDER = 'Controllers'; +const PLUGINS_FOLDER = 'Plugins'; // Initialize autoloader if (file_exists(APPLICATION_ROOT . 'Feast/Autoloader.php')) { diff --git a/Install/public/index.php b/Install/public/index.php index 59fee5a..6962357 100644 --- a/Install/public/index.php +++ b/Install/public/index.php @@ -30,10 +30,10 @@ // Application start time $startTime = microtime(true); -define('APPLICATION_ROOT', __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR); -define('CONTROLLERS_FOLDER', 'Controllers'); -define('HANDLERS_FOLDER', 'Handlers'); -define('PLUGINS_FOLDER', 'Plugins'); +const APPLICATION_ROOT = __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR; +const CONTROLLERS_FOLDER = 'Controllers'; +const HANDLERS_FOLDER = 'Handlers'; +const PLUGINS_FOLDER = 'Plugins'; if (file_exists(APPLICATION_ROOT . 'maintenance.txt')) { http_response_code(503); @@ -43,7 +43,7 @@ } if (file_exists(APPLICATION_ROOT . 'vendor/autoload.php')) { require_once(APPLICATION_ROOT . 'vendor/autoload.php'); -}; +} // Initialize autoloader if (file_exists(APPLICATION_ROOT . '/Feast/Autoloader.php')) { require_once(APPLICATION_ROOT . '/Feast/Autoloader.php'); @@ -53,7 +53,7 @@ $autoLoader->addPathMapping('Psr', ['/Feast/Psr']); -define('RUN_AS', Main::RUN_AS_WEBAPP); +const RUN_AS = Main::RUN_AS_WEBAPP; require_once(APPLICATION_ROOT . 'container.php'); /** @var ServiceContainer $container */ $container->add(Autoloader::class, $autoLoader); diff --git a/Interfaces/ConfigInterface.php b/Interfaces/ConfigInterface.php index e8abe04..1b98d7e 100644 --- a/Interfaces/ConfigInterface.php +++ b/Interfaces/ConfigInterface.php @@ -31,7 +31,7 @@ */ interface ConfigInterface extends ServiceContainerItemInterface { - public const INTERFACE_NAME = self::class; + final public const INTERFACE_NAME = self::class; /** * Cache the config and store on disk diff --git a/Interfaces/DatabaseDetailsInterface.php b/Interfaces/DatabaseDetailsInterface.php index 5b5e5d5..a4a3ce8 100644 --- a/Interfaces/DatabaseDetailsInterface.php +++ b/Interfaces/DatabaseDetailsInterface.php @@ -22,7 +22,7 @@ interface DatabaseDetailsInterface extends ServiceContainerItemInterface { - public const INTERFACE_NAME = self::class; + final public const INTERFACE_NAME = self::class; public function cache(): void; diff --git a/Interfaces/DatabaseFactoryInterface.php b/Interfaces/DatabaseFactoryInterface.php index ed52b81..8a62003 100644 --- a/Interfaces/DatabaseFactoryInterface.php +++ b/Interfaces/DatabaseFactoryInterface.php @@ -30,9 +30,9 @@ */ interface DatabaseFactoryInterface extends ServiceContainerItemInterface { - public const INTERFACE_NAME = self::class; + final public const INTERFACE_NAME = self::class; - public const DEFAULT_CONNECTION = 'default'; + final public const DEFAULT_CONNECTION = 'default'; /** * Get the specified connection diff --git a/Interfaces/DatabaseInterface.php b/Interfaces/DatabaseInterface.php index 759a381..276ea78 100644 --- a/Interfaces/DatabaseInterface.php +++ b/Interfaces/DatabaseInterface.php @@ -23,6 +23,7 @@ use Exception; use Feast\Database\Query; use Feast\Database\TableDetails; +use Feast\Enums\DatabaseType; use Feast\Date; use PDO; @@ -177,9 +178,9 @@ public function rawQuery(string $query, array $bindings = [], bool $forceEmulate /** * Get Database type. * - * @return string + * @return DatabaseType */ - public function getDatabaseType(): string; + public function getDatabaseType(): DatabaseType; /** * Get the escape character for identifiers. diff --git a/Interfaces/HttpRequestInterface.php b/Interfaces/HttpRequestInterface.php index 672e3c4..6350aec 100644 --- a/Interfaces/HttpRequestInterface.php +++ b/Interfaces/HttpRequestInterface.php @@ -21,6 +21,7 @@ namespace Feast\Interfaces; use CurlHandle; +use Feast\Enums\ResponseCode; use Feast\Exception\ServerFailureException; use Feast\HttpRequest\HttpRequest; use Feast\HttpRequest\Response; @@ -42,9 +43,9 @@ public function addHeader(string $header, string $value): HttpRequestInterface; /** * Get the http response code for the request. * - * @return int|null + * @return ResponseCode|null */ - public function getResponseCode(): ?int; + public function getResponseCode(): ?ResponseCode; /** * Get cookies from the request. @@ -63,9 +64,9 @@ public function getResponseAsXml(): ?SimpleXMLElement; /** * Get the request result as a json object. * - * @return stdClass|null + * @return null|array|stdClass */ - public function getResponseAsJson(): ?stdClass; + public function getResponseAsJson(): null|array|stdClass; /** * Get the request result as a string. diff --git a/Interfaces/LoggerInterface.php b/Interfaces/LoggerInterface.php index 870ad2b..58bd3b0 100644 --- a/Interfaces/LoggerInterface.php +++ b/Interfaces/LoggerInterface.php @@ -24,7 +24,7 @@ interface LoggerInterface extends ServiceContainerItemInterface { - public const INTERFACE_NAME = self::class; + final public const INTERFACE_NAME = self::class; /** * System is unusable. diff --git a/Interfaces/ProfilerInterface.php b/Interfaces/ProfilerInterface.php index 09f093e..4e2f18c 100644 --- a/Interfaces/ProfilerInterface.php +++ b/Interfaces/ProfilerInterface.php @@ -29,7 +29,7 @@ */ interface ProfilerInterface extends ServiceContainerItemInterface { - public const INTERFACE_NAME = self::class; + final public const INTERFACE_NAME = self::class; /** * Return the total time of execution up to this point. diff --git a/Interfaces/RequestInterface.php b/Interfaces/RequestInterface.php index 7e4187e..2a0db42 100644 --- a/Interfaces/RequestInterface.php +++ b/Interfaces/RequestInterface.php @@ -26,7 +26,7 @@ interface RequestInterface extends ServiceContainerItemInterface { - public const INTERFACE_NAME = self::class; + final public const INTERFACE_NAME = self::class; /** * Clear all request arguments. diff --git a/Interfaces/ResponseInterface.php b/Interfaces/ResponseInterface.php index 3fcca32..bcb023f 100644 --- a/Interfaces/ResponseInterface.php +++ b/Interfaces/ResponseInterface.php @@ -21,7 +21,7 @@ namespace Feast\Interfaces; use Exception; -use Feast\Exception\ResponseException; +use Feast\Enums\ResponseCode; use Feast\ServiceContainer\ServiceContainerItemInterface; use Feast\View; @@ -30,15 +30,15 @@ */ interface ResponseInterface extends ServiceContainerItemInterface { - public const INTERFACE_NAME = self::class; + final public const INTERFACE_NAME = self::class; /** * Set the response code. * - * @param int $responseCode - * @throws ResponseException + * @param ResponseCode $responseCode + * @throws Exception */ - public function setResponseCode(int $responseCode): void; + public function setResponseCode(ResponseCode $responseCode): void; /** * Send http response header. @@ -73,10 +73,9 @@ public function setJson(bool $isJson = true): void; * Set redirect path. * * @param string $path - * @param int $code - * @throws ResponseException + * @param ResponseCode $code */ - public function redirect(string $path, int $code = 302): void; + public function redirect(string $path, ResponseCode $code = ResponseCode::HTTP_CODE_302): void; /** * Get the redirect path for a redirect. diff --git a/Interfaces/RouterInterface.php b/Interfaces/RouterInterface.php index 5f1f2ab..16501d9 100644 --- a/Interfaces/RouterInterface.php +++ b/Interfaces/RouterInterface.php @@ -27,7 +27,7 @@ interface RouterInterface extends ServiceContainerItemInterface { - public const INTERFACE_NAME = self::class; + final public const INTERFACE_NAME = self::class; /** * Update the "runAs". Needed to properly route in case of cached router. diff --git a/Jobs/CronJob.php b/Jobs/CronJob.php index 6f2a7b8..3e47db8 100644 --- a/Jobs/CronJob.php +++ b/Jobs/CronJob.php @@ -164,7 +164,7 @@ public function cron(string $cronString): static */ public function everyMinute(): static { - [$minute, $hour, $dayOfMonth, $month, $dayOfWeek] = explode(' ', $this->cronString); + [, $hour, $dayOfMonth, $month, $dayOfWeek] = explode(' ', $this->cronString); $this->cronString = implode(' ', ['*', $hour, $dayOfMonth, $month, $dayOfWeek]); return $this; } @@ -176,7 +176,7 @@ public function everyMinute(): static */ public function everyOddMinute(): static { - [$minute, $hour, $dayOfMonth, $month, $dayOfWeek] = explode(' ', $this->cronString); + [, $hour, $dayOfMonth, $month, $dayOfWeek] = explode(' ', $this->cronString); $this->cronString = implode(' ', ['1-59/2', $hour, $dayOfMonth, $month, $dayOfWeek]); return $this; } @@ -269,7 +269,7 @@ public function everyThirtyMinutes(): static */ protected function everyXDivisibleMinutes(int $x): static { - [$minute, $hour, $dayOfMonth, $month, $dayOfWeek] = explode(' ', $this->cronString); + [, $hour, $dayOfMonth, $month, $dayOfWeek] = explode(' ', $this->cronString); $this->cronString = implode(' ', ['*/' . (string)$x, $hour, $dayOfMonth, $month, $dayOfWeek]); return $this; } @@ -281,7 +281,7 @@ protected function everyXDivisibleMinutes(int $x): static */ public function hourly(): static { - [$minute, $hour, $dayOfMonth, $month, $dayOfWeek] = explode(' ', $this->cronString); + [$minute, , $dayOfMonth, $month, $dayOfWeek] = explode(' ', $this->cronString); $minute = $minute === '*' ? '0' : $minute; $this->cronString = implode(' ', [$minute, '*', $dayOfMonth, $month, $dayOfWeek]); return $this; @@ -295,7 +295,7 @@ public function hourly(): static */ public function hourlyAt(int $minuteNew): static { - [$minute, $hour, $dayOfMonth, $month, $dayOfWeek] = explode(' ', $this->cronString); + [, , $dayOfMonth, $month, $dayOfWeek] = explode(' ', $this->cronString); $this->cronString = implode(' ', [$minuteNew, '*', $dayOfMonth, $month, $dayOfWeek]); return $this; } @@ -307,7 +307,7 @@ public function hourlyAt(int $minuteNew): static */ public function hourlyOnOddHours(): static { - [$minute, $hour, $dayOfMonth, $month, $dayOfWeek] = explode(' ', $this->cronString); + [$minute, , $dayOfMonth, $month, $dayOfWeek] = explode(' ', $this->cronString); $minute = $minute === '*' ? '0' : $minute; $this->cronString = implode(' ', [$minute, '1-23/2', $dayOfMonth, $month, $dayOfWeek]); return $this; @@ -381,7 +381,7 @@ public function everyTwelveHours(): static */ protected function everyXDivisibleHours(int $x): static { - [$minute, $hour, $dayOfMonth, $month, $dayOfWeek] = explode(' ', $this->cronString); + [$minute, , $dayOfMonth, $month, $dayOfWeek] = explode(' ', $this->cronString); $minute = $minute === '*' ? '0' : $minute; $this->cronString = implode(' ', [$minute, '*/' . $x, $dayOfMonth, $month, $dayOfWeek]); return $this; @@ -409,7 +409,7 @@ public function daily(): static */ public function dailyAt(string $time): static { - [$minute, $hour, $dayOfMonth, $month, $dayOfWeek] = explode(' ', $this->cronString); + [, , $dayOfMonth, $month, $dayOfWeek] = explode(' ', $this->cronString); [$hour, $minute] = explode(':', $time); $this->cronString = implode(' ', [(string)(int)$minute, (string)(int)$hour, $dayOfMonth, $month, $dayOfWeek]); @@ -425,7 +425,7 @@ public function dailyAt(string $time): static */ public function twiceDaily(int $hour1, int $hour2): static { - [$minute, $hour, $dayOfMonth, $month, $dayOfWeek] = explode(' ', $this->cronString); + [$minute, , $dayOfMonth, $month, $dayOfWeek] = explode(' ', $this->cronString); $minute = $minute === '*' ? '0' : $minute; $hour = implode(',', [$hour1, $hour2]); $this->cronString = implode(' ', [$minute, $hour, $dayOfMonth, $month, $dayOfWeek]); @@ -439,7 +439,7 @@ public function twiceDaily(int $hour1, int $hour2): static */ public function weekly(): static { - [$minute, $hour, $dayOfMonth, $month, $dayOfWeek] = explode(' ', $this->cronString); + [$minute, $hour, $dayOfMonth, $month,] = explode(' ', $this->cronString); $minute = $minute === '*' ? '0' : $minute; $hour = $hour === '*' ? '0' : $hour; $this->cronString = implode(' ', [$minute, $hour, $dayOfMonth, $month, '0']); @@ -455,7 +455,7 @@ public function weekly(): static */ public function weeklyOn(int $dayOfWeekNew, ?string $time = null): static { - [$minute, $hour, $dayOfMonth, $month, $dayOfWeek] = explode(' ', $this->cronString); + [$minute, $hour, $dayOfMonth, $month,] = explode(' ', $this->cronString); $minute = $minute === '*' ? '0' : $minute; $hour = $hour === '*' ? '0' : $hour; $this->cronString = implode(' ', [$minute, $hour, $dayOfMonth, $month, $dayOfWeekNew]); @@ -472,7 +472,7 @@ public function weeklyOn(int $dayOfWeekNew, ?string $time = null): static */ public function monthly(): static { - [$minute, $hour, $dayOfMonth, $month, $dayOfWeek] = explode(' ', $this->cronString); + [$minute, $hour, , $month, $dayOfWeek] = explode(' ', $this->cronString); $minute = $minute === '*' ? '0' : $minute; $hour = $hour === '*' ? '0' : $hour; $this->cronString = implode(' ', [$minute, $hour, '1', $month, $dayOfWeek]); @@ -488,7 +488,7 @@ public function monthly(): static */ public function monthlyOn(int $dayOfMonthNew, ?string $time = null): static { - [$minute, $hour, $dayOfMonth, $month, $dayOfWeek] = explode(' ', $this->cronString); + [$minute, $hour, , $month, $dayOfWeek] = explode(' ', $this->cronString); $minute = $minute === '*' ? '0' : $minute; $hour = $hour === '*' ? '0' : $hour; $this->cronString = implode(' ', [$minute, $hour, $dayOfMonthNew, $month, $dayOfWeek]); @@ -508,7 +508,7 @@ public function monthlyOn(int $dayOfMonthNew, ?string $time = null): static */ public function twiceMonthly(int $dayOfMonthOne, int $dayOfMonthTwo, ?string $time = null): static { - [$minute, $hour, $dayOfMonth, $month, $dayOfWeek] = explode(' ', $this->cronString); + [$minute, $hour, , $month, $dayOfWeek] = explode(' ', $this->cronString); $minute = $minute === '*' ? '0' : $minute; $hour = $hour === '*' ? '0' : $hour; $this->cronString = implode(' ', [$minute, $hour, $dayOfMonthOne . ',' . $dayOfMonthTwo, $month, $dayOfWeek]); @@ -527,7 +527,7 @@ public function twiceMonthly(int $dayOfMonthOne, int $dayOfMonthTwo, ?string $ti */ public function quarterly(): static { - [$minute, $hour, $dayOfMonth, $month, $dayOfWeek] = explode(' ', $this->cronString); + [$minute, $hour, $dayOfMonth, , $dayOfWeek] = explode(' ', $this->cronString); $minute = $minute === '*' ? '0' : $minute; $hour = $hour === '*' ? '0' : $hour; $dayOfMonth = $dayOfMonth === '*' ? '1' : $dayOfMonth; @@ -542,7 +542,7 @@ public function quarterly(): static */ public function yearly(): static { - [$minute, $hour, $dayOfMonth, $month, $dayOfWeek] = explode(' ', $this->cronString); + [$minute, $hour, $dayOfMonth, , $dayOfWeek] = explode(' ', $this->cronString); $minute = $minute === '*' ? '0' : $minute; $hour = $hour === '*' ? '0' : $hour; $dayOfMonth = $dayOfMonth === '*' ? '1' : $dayOfMonth; @@ -560,7 +560,7 @@ public function yearly(): static */ public function yearlyOn(int $dayOfMonthNew, int $monthNew, ?string $time = null): static { - [$minute, $hour, $dayOfMonth, $month, $dayOfWeek] = explode(' ', $this->cronString); + [$minute, $hour, , , $dayOfWeek] = explode(' ', $this->cronString); $minute = $minute === '*' ? '0' : $minute; $hour = $hour === '*' ? '0' : $hour; $this->cronString = implode(' ', [$minute, $hour, $dayOfMonthNew, $monthNew, $dayOfWeek]); @@ -577,7 +577,7 @@ public function yearlyOn(int $dayOfMonthNew, int $monthNew, ?string $time = null */ public function weekdays(): static { - [$minute, $hour, $dayOfMonth, $month, $dayOfWeek] = explode(' ', $this->cronString); + [$minute, $hour, $dayOfMonth, $month,] = explode(' ', $this->cronString); $this->cronString = implode(' ', [$minute, $hour, $dayOfMonth, $month, '1,2,3,4,5']); return $this; } @@ -589,7 +589,7 @@ public function weekdays(): static */ public function weekends(): static { - [$minute, $hour, $dayOfMonth, $month, $dayOfWeek] = explode(' ', $this->cronString); + [$minute, $hour, $dayOfMonth, $month,] = explode(' ', $this->cronString); $this->cronString = implode(' ', [$minute, $hour, $dayOfMonth, $month, '0,6']); return $this; } @@ -601,7 +601,7 @@ public function weekends(): static */ public function sundays(): static { - [$minute, $hour, $dayOfMonth, $month, $dayOfWeek] = explode(' ', $this->cronString); + [$minute, $hour, $dayOfMonth, $month,] = explode(' ', $this->cronString); $this->cronString = implode(' ', [$minute, $hour, $dayOfMonth, $month, '0']); return $this; } @@ -613,7 +613,7 @@ public function sundays(): static */ public function mondays(): static { - [$minute, $hour, $dayOfMonth, $month, $dayOfWeek] = explode(' ', $this->cronString); + [$minute, $hour, $dayOfMonth, $month,] = explode(' ', $this->cronString); $this->cronString = implode(' ', [$minute, $hour, $dayOfMonth, $month, '1']); return $this; } @@ -625,7 +625,7 @@ public function mondays(): static */ public function tuesdays(): static { - [$minute, $hour, $dayOfMonth, $month, $dayOfWeek] = explode(' ', $this->cronString); + [$minute, $hour, $dayOfMonth, $month,] = explode(' ', $this->cronString); $this->cronString = implode(' ', [$minute, $hour, $dayOfMonth, $month, '2']); return $this; } @@ -637,7 +637,7 @@ public function tuesdays(): static */ public function wednesdays(): static { - [$minute, $hour, $dayOfMonth, $month, $dayOfWeek] = explode(' ', $this->cronString); + [$minute, $hour, $dayOfMonth, $month,] = explode(' ', $this->cronString); $this->cronString = implode(' ', [$minute, $hour, $dayOfMonth, $month, '3']); return $this; } @@ -649,7 +649,7 @@ public function wednesdays(): static */ public function thursdays(): static { - [$minute, $hour, $dayOfMonth, $month, $dayOfWeek] = explode(' ', $this->cronString); + [$minute, $hour, $dayOfMonth, $month,] = explode(' ', $this->cronString); $this->cronString = implode(' ', [$minute, $hour, $dayOfMonth, $month, '4']); return $this; } @@ -661,7 +661,7 @@ public function thursdays(): static */ public function fridays(): static { - [$minute, $hour, $dayOfMonth, $month, $dayOfWeek] = explode(' ', $this->cronString); + [$minute, $hour, $dayOfMonth, $month,] = explode(' ', $this->cronString); $this->cronString = implode(' ', [$minute, $hour, $dayOfMonth, $month, '5']); return $this; } @@ -673,7 +673,7 @@ public function fridays(): static */ public function saturdays(): static { - [$minute, $hour, $dayOfMonth, $month, $dayOfWeek] = explode(' ', $this->cronString); + [$minute, $hour, $dayOfMonth, $month,] = explode(' ', $this->cronString); $this->cronString = implode(' ', [$minute, $hour, $dayOfMonth, $month, '6']); return $this; } @@ -688,7 +688,7 @@ public function saturdays(): static */ public function days(array $days): static { - [$minute, $hour, $dayOfMonth, $month, $dayOfWeek] = explode(' ', $this->cronString); + [$minute, $hour, $dayOfMonth, $month,] = explode(' ', $this->cronString); $this->cronString = implode(' ', [$minute, $hour, $dayOfMonth, $month, implode(',', $days)]); return $this; } @@ -901,7 +901,6 @@ protected function checkSubPiece(string $field, int $value): bool $divisor = null; $rulesPassed = true; $start = null; - $end = null; if (str_contains($field, '/')) { [$field, $divisor] = explode('/', $field, 2); } diff --git a/Jobs/QueueableJob.php b/Jobs/QueueableJob.php index 3658265..34ba267 100644 --- a/Jobs/QueueableJob.php +++ b/Jobs/QueueableJob.php @@ -29,10 +29,10 @@ abstract class QueueableJob implements JobInterface { - public const JOB_STATUS_PENDING = 'pending'; - public const JOB_STATUS_RUNNING = 'running'; - public const JOB_STATUS_COMPLETE = 'complete'; - public const JOB_STATUS_FAILED = 'failed'; + final public const JOB_STATUS_PENDING = 'pending'; + final public const JOB_STATUS_RUNNING = 'running'; + final public const JOB_STATUS_COMPLETE = 'complete'; + final public const JOB_STATUS_FAILED = 'failed'; protected int $maxTries = 3; protected string $queueName = 'default'; @@ -41,14 +41,13 @@ abstract class QueueableJob implements JobInterface /** * Store job in the database for the queue to pick up. * - * @param ?JobMapper $jobMapper + * @param JobMapper $jobMapper * @return Job * @throws InvalidDateException * @throws Exception */ - public function store(JobMapper $jobMapper = null): Job + public function store(JobMapper $jobMapper = new JobMapper()): Job { - $jobMapper ??= new JobMapper(); $model = new Job(); $model->job_id = $this->generateUuid(); $model->job_name = $this->jobName; diff --git a/Logger/ErrorLogger.php b/Logger/ErrorLogger.php index f2700cf..637021c 100644 --- a/Logger/ErrorLogger.php +++ b/Logger/ErrorLogger.php @@ -113,7 +113,7 @@ public function exceptionHandler(Throwable $exception, bool $caught = false): bo ) . ' on line ' . (string)$exception->getLine(); $this->logger->error($errorMessage); - $this->logger->rawLog(LogLevelCode::ERROR, $exception->getTraceAsString()); + $this->logger->rawLog(LogLevelCode::ERROR->value, $exception->getTraceAsString()); $newException = new ServerFailureException( $exception->getMessage(), null, diff --git a/Logger/Logger.php b/Logger/Logger.php index 85d3e16..28ae599 100644 --- a/Logger/Logger.php +++ b/Logger/Logger.php @@ -39,7 +39,7 @@ class Logger implements LoggerInterface, ServiceContainerItemInterface, \Feast\I use DependencyInjected; private string $logPath; - private ?int $logLevel; + protected LogLevelCode $logLevel; private bool $useSysLog = false; private int $sysLogFacility = LOG_USER; @@ -171,11 +171,11 @@ public function log($level, $message, array $context = []): void $message = strtoupper($level) . ': ' . $message; $level = $this->getLevelFromString($level); } - if ($level > $this->logLevel) { + if ($level instanceof LogLevelCode === false || $level->value > $this->logLevel->value) { return; } $message = $this->interpolateContext($message, $context); - $this->rawLog((int)$level, (date('[Y-m-d H:i:s] ')) . trim($message)); + $this->rawLog($level->value, (date('[Y-m-d H:i:s] ')) . trim($message)); if (isset($context['exception']) && $context['exception'] instanceof Throwable) { $exception = $context['exception']; @@ -213,7 +213,7 @@ protected function interpolateContext(Stringable|string $message, array $context */ public function rawLog(int $level, string $message): void { - if ($level > $this->logLevel) { + if ($level > $this->logLevel->value) { return; } if ($this->useSysLog) { @@ -262,7 +262,7 @@ protected function openSysLog(): void openlog($prefix, $sysLogFlags, $sysLogFacility); } - private function getLevelFromString(string $level): int + private function getLevelFromString(string $level): LogLevelCode { return match (strtolower($level)) { LogLevel::DEBUG => LogLevelCode::DEBUG, diff --git a/Main.php b/Main.php index d34890c..c2664e2 100644 --- a/Main.php +++ b/Main.php @@ -53,9 +53,9 @@ class Main implements MainInterface { - public const RUN_AS_WEBAPP = 'webapp'; - public const RUN_AS_CLI = 'cli'; - public const FRAMEWORK_ROOT = __DIR__; + final public const RUN_AS_WEBAPP = 'webapp'; + final public const RUN_AS_CLI = 'cli'; + final public const FRAMEWORK_ROOT = __DIR__; private array $plugins = []; private ErrorLoggerInterface $logger; @@ -501,7 +501,7 @@ protected function handle404Exception( /** @var string|null $errorUrl */ $errorUrl = $config->getSetting('error.http404.url', 'error/fourohfour'); if (is_string($errorUrl)) { - header('Location:/' . $errorUrl, true, ResponseCode::HTTP_CODE_302); + header('Location:/' . $errorUrl, true, ResponseCode::HTTP_CODE_302->value); return; } throw $exception; diff --git a/PsalmLoader.php b/PsalmLoader.php index d377e76..8352a4e 100644 --- a/PsalmLoader.php +++ b/PsalmLoader.php @@ -38,9 +38,9 @@ use Feast\Router\Router; use Feast\View; -define('APPLICATION_ROOT', __DIR__ . '/'); -define('CONTROLLERS_FOLDER', 'Controllers'); -define('PLUGINS_FOLDER', 'Plugins'); +const APPLICATION_ROOT = __DIR__ . '/'; +const CONTROLLERS_FOLDER = 'Controllers'; +const PLUGINS_FOLDER = 'Plugins'; // Initialize autoloader require_once(APPLICATION_ROOT . 'Autoloader.php'); diff --git a/Psr/Log/LogLevel.php b/Psr/Log/LogLevel.php index 3dd5173..212afde 100644 --- a/Psr/Log/LogLevel.php +++ b/Psr/Log/LogLevel.php @@ -8,11 +8,11 @@ class LogLevel { public const EMERGENCY = 'emergency'; - public const ALERT = 'alert'; - public const CRITICAL = 'critical'; - public const ERROR = 'error'; - public const WARNING = 'warning'; - public const NOTICE = 'notice'; - public const INFO = 'info'; - public const DEBUG = 'debug'; -} \ No newline at end of file + public const ALERT = 'alert'; + public const CRITICAL = 'critical'; + public const ERROR = 'error'; + public const WARNING = 'warning'; + public const NOTICE = 'notice'; + public const INFO = 'info'; + public const DEBUG = 'debug'; +} diff --git a/README.md b/README.md index 1163517..9385280 100644 --- a/README.md +++ b/README.md @@ -2,11 +2,11 @@ # FEAST Framework -![PHPUnit](https://github.com/FeastFramework/framework/workflows/PHPUnit/badge.svg?branch=v1.x) -![Psalm Static analysis](https://github.com/FeastFramework/framework/workflows/Psalm%20Static%20analysis/badge.svg?branch=v1.x) -[![codecov](https://codecov.io/gh/FeastFramework/framework/branch/v1.x/graph/badge.svg?token=FBP2AKLJB3)](https://codecov.io/gh/FeastFramework/framework) +![PHPUnit](https://github.com/FeastFramework/framework/workflows/PHPUnit/badge.svg?branch=v3.x) +![Psalm Static analysis](https://github.com/FeastFramework/framework/workflows/Psalm%20Static%20analysis/badge.svg?branch=v3.x) +[![codecov](https://codecov.io/gh/FeastFramework/framework/branch/v3.x/graph/badge.svg?token=FBP2AKLJB3)](https://codecov.io/gh/FeastFramework/framework) -![PHP Version](https://img.shields.io/packagist/php-v/feast/framework/v1.x-dev) +![PHP Version](https://img.shields.io/packagist/php-v/feast/framework/v3.x-dev) [![Packagist](https://img.shields.io/packagist/v/feast/framework)](https://packagist.org/packages/feast/framework) ![License](https://img.shields.io/packagist/l/feast/framework.svg) [![Docs](https://img.shields.io/badge/docs-quickstart-green.svg)](https://docs.feast-framework.com) diff --git a/Request.php b/Request.php index 012e202..c863738 100755 --- a/Request.php +++ b/Request.php @@ -222,7 +222,7 @@ public function getAllArguments(): stdClass */ public function isPost(): bool { - return !empty($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === RequestMethod::POST; + return !empty($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === RequestMethod::POST->value; } /** @@ -232,7 +232,7 @@ public function isPost(): bool */ public function isGet(): bool { - return !empty($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === RequestMethod::GET; + return !empty($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === RequestMethod::GET->value; } /** @@ -242,7 +242,7 @@ public function isGet(): bool */ public function isDelete(): bool { - return !empty($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === RequestMethod::DELETE; + return !empty($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === RequestMethod::DELETE->value; } /** @@ -252,7 +252,7 @@ public function isDelete(): bool */ public function isPut(): bool { - return !empty($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === RequestMethod::PUT; + return !empty($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === RequestMethod::PUT->value; } /** @@ -262,7 +262,7 @@ public function isPut(): bool */ public function isPatch(): bool { - return !empty($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === RequestMethod::PATCH; + return !empty($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === RequestMethod::PATCH->value; } /** diff --git a/Response.php b/Response.php index ac527e2..905a2c9 100644 --- a/Response.php +++ b/Response.php @@ -21,7 +21,6 @@ namespace Feast; use Feast\Enums\ResponseCode; -use Feast\Exception\ResponseException; use Feast\Interfaces\ResponseInterface; use Feast\Interfaces\RouterInterface; use Feast\ServiceContainer\ContainerException; @@ -38,7 +37,7 @@ class Response implements ServiceContainerItemInterface, ResponseInterface { use DependencyInjected; - private int $responseCode = ResponseCode::HTTP_CODE_200; + private ResponseCode $responseCode = ResponseCode::HTTP_CODE_200; private bool $isJson = false; private object|array|null $jsonResponse = null; private ?int $jsonResponsePropertyTypes = null; @@ -57,16 +56,11 @@ public function __construct() /** * Set the response code. * - * @param int $responseCode - * @throws ResponseException + * @param ResponseCode $responseCode */ - public function setResponseCode(int $responseCode): void + public function setResponseCode(ResponseCode $responseCode): void { - if (ResponseCode::isValidResponseCode($responseCode)) { - $this->responseCode = $responseCode; - } else { - throw new ResponseException('Invalid response code!'); - } + $this->responseCode = $responseCode; } /** @@ -74,7 +68,7 @@ public function setResponseCode(int $responseCode): void */ public function sendResponseCode(): void { - http_response_code($this->responseCode); + http_response_code($this->responseCode->value); } /** @@ -83,7 +77,8 @@ public function sendResponseCode(): void * @param View $view * @param RouterInterface $router * @param string $routePath - * @throws JsonException|ReflectionException + * @throws JsonException + * @throws ReflectionException */ public function sendResponse(View $view, RouterInterface $router, string $routePath): void { @@ -146,10 +141,9 @@ public function getRedirectPath(): ?string * Set redirect path. * * @param string $path - * @param int $code - * @throws ResponseException + * @param ResponseCode $code */ - public function redirect(string $path, int $code = 302): void + public function redirect(string $path, ResponseCode $code = ResponseCode::HTTP_CODE_302): void { $this->redirectPath = $path; $this->setResponseCode($code); diff --git a/Router/Router.php b/Router/Router.php index 905ff80..46b9982 100644 --- a/Router/Router.php +++ b/Router/Router.php @@ -330,8 +330,7 @@ protected function getNamedRouteForUrlPath(string $requestMethod, string $checkS $routeGroup = $this->routes->$requestMethod; /** @var RouteData $routeData */ foreach ((array)$routeGroup as $routeData) { - $arguments = []; - if (preg_match_all($routeData->pattern, $checkString, $arguments)) { + if (preg_match_all($routeData->pattern, $checkString)) { return $routeData; } } @@ -354,7 +353,7 @@ protected function setCliArgumentsOnRequest( $instance = $parameter->newInstance(); if ($instance->paramType === ParamType::PARAM) { $parameterList[] = $instance->name; - } elseif ($instance->paramType === ParamType::FLAG) { + } else { $flagList[$instance->name] = $instance->name; } } @@ -884,7 +883,7 @@ private function analyzeMethodForRoute(ReflectionMethod $method, string $classNa $methodName, $pathAttribute->name, $pathAttribute->defaults, - $methodType, + $methodType->value, $module ); } @@ -913,7 +912,7 @@ private function getFilteredMethodName(string $methodName): string */ protected function getCurrentRequestMethod(): string { - return !empty($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : RequestMethod::GET; + return !empty($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : RequestMethod::GET->value; } } diff --git a/Session/Session.php b/Session/Session.php index a75faed..d88257b 100755 --- a/Session/Session.php +++ b/Session/Session.php @@ -48,7 +48,6 @@ class Session implements ServiceContainerItemInterface * @param ConfigInterface $config * @throws ContainerException * @throws NotFoundException - * @throws ResponseException */ public function __construct(ConfigInterface $config) { diff --git a/Terminal.php b/Terminal.php index 1d1d7b2..9390b47 100644 --- a/Terminal.php +++ b/Terminal.php @@ -32,7 +32,7 @@ class Terminal public function __construct(?bool $useColor = null) { if ($useColor === null) { - $this->isTty = (function_exists('posix_isatty') ? posix_isatty(STDOUT) : false); + $this->isTty = (function_exists('posix_isatty') && posix_isatty(STDOUT)); } else { $this->isTty = $useColor; } diff --git a/Traits/Collection.php b/Traits/Collection.php index f5a341f..edde414 100644 --- a/Traits/Collection.php +++ b/Traits/Collection.php @@ -90,15 +90,13 @@ protected function objectImplode(string $separator, string $key): string /** * Sort the collection by different sort options. * - * @param $sortType + * @param CollectionSort $sortType * @param bool $modifyOriginal * @param int $sortOptions * @return array - * @throws InvalidOptionException * @see CollectionSort - * */ - public function sort(int $sortType, bool $modifyOriginal = false, int $sortOptions = SORT_REGULAR): array + public function sort(CollectionSort $sortType, bool $modifyOriginal = false, int $sortOptions = SORT_REGULAR): array { $array = $this->array; switch ($sortType) { @@ -114,8 +112,6 @@ public function sort(int $sortType, bool $modifyOriginal = false, int $sortOptio case CollectionSort::VALUE_REVERSE: arsort($array, $sortOptions); break; - default: - throw new InvalidOptionException('Invalid sort type'); } if ($modifyOriginal) { $this->array = $array; @@ -128,7 +124,7 @@ public function sort(int $sortType, bool $modifyOriginal = false, int $sortOptio * Sort named-class based collection by the value of a key or multiple keys. * * @param string|array $key - * @param int $sortType + * @param CollectionSort $sortType * @param bool $modifyOriginal * @return array * @throws InvalidOptionException @@ -136,7 +132,7 @@ public function sort(int $sortType, bool $modifyOriginal = false, int $sortOptio */ public function objectSort( string|array $key, - int $sortType = CollectionSort::VALUE, + CollectionSort $sortType = CollectionSort::VALUE, bool $modifyOriginal = false ): array { switch ($this->type) { @@ -151,13 +147,7 @@ public function objectSort( 'Collection must contain objects of a named class in order to use objectSort' ); } - switch ($sortType) { - case CollectionSort::VALUE: - case CollectionSort::VALUE_REVERSE: - break; - default: - throw new InvalidOptionException('Invalid sort option'); - } + /** @var array $array */ $array = $this->array; usort( @@ -272,7 +262,7 @@ public function clear(): void /** * Check if item exists in collection. * - * @param $value + * @param mixed $value * @param bool $strictMatch * @return bool */ @@ -307,7 +297,7 @@ public function containsAll( /** * Find the first index of an item in the collection. * - * @param $value + * @param mixed $value * @param bool $strictMatch * @return null|int|string */ @@ -326,7 +316,7 @@ public function indexOf( /** * Find the last index of an item in the collection. * - * @param $value + * @param mixed $value * @param bool $strictMatch * @return array-key|null */ @@ -355,7 +345,7 @@ public function size(): int /** * Remove an item from the collection. * - * @param $valueMatch + * @param mixed $valueMatch * @param bool $strictMatch */ public function remove( diff --git a/View.php b/View.php index 4b3ab32..0a832d1 100644 --- a/View.php +++ b/View.php @@ -22,7 +22,7 @@ use Exception; use Feast\Collection\Collection; -use Feast\Enums\DocTypes; +use Feast\Enums\DocType; use Feast\Interfaces\ConfigInterface; use Feast\Interfaces\RouterInterface; use Feast\ServiceContainer\ServiceContainerItemInterface; @@ -42,7 +42,7 @@ class View extends stdClass implements ServiceContainerItemInterface private array $css = []; private bool $outputDisabled = false; private string $content = ''; - private string $docType = DocTypes::HTML_5; + private DocType $docType = DocType::HTML_5; private string $dtd = '' . "\n" . ''; private string $encoding = 'UTF-8'; private array $postScripts = []; @@ -63,7 +63,7 @@ public function __construct(protected ConfigInterface $config, protected RouterI { $this->checkInjected(); $this->baseUrl = (string)$config->getSetting('siteurl'); - $docType = (string)$config->getSetting('html.doctype', DocTypes::HTML_5); + $docType = DocType::tryFrom((string)$config->getSetting('html.doctype', DocType::HTML_5->value)) ?? DocType::HTML_5; $this->setDoctype($docType); } @@ -306,7 +306,7 @@ public function getCss(): string /** * Adds a css file to the page, - * + * * Feast uses the /css/ folder for the base directory for all stylesheets. * * @param string $fileName @@ -359,41 +359,39 @@ public function getTitle(bool $html = true): string /** * Sets the doc type of the page. - * + * * Also sets the doctype declaration * - * @param string $doctype + * @param DocType $doctype * @throws Exception */ - public function setDoctype(string $doctype = DocTypes::HTML_5): void + public function setDoctype(DocType $doctype = DocType::HTML_5): void { - if ($doctype == DocTypes::HTML_4_01_TRANSITIONAL) { + if ($doctype == DocType::HTML_4_01_TRANSITIONAL) { $this->dtd = ''; - } elseif ($doctype == DocTypes::HTML_4_01_STRICT) { + } elseif ($doctype == DocType::HTML_4_01_STRICT) { $this->dtd = ''; - } elseif ($doctype == DocTypes::HTML_4_01_FRAMESET) { + } elseif ($doctype == DocType::HTML_4_01_FRAMESET) { $this->dtd = ''; - } elseif ($doctype == DocTypes::HTML_5) { + } elseif ($doctype == DocType::HTML_5) { $this->dtd = '' . "\n" . ''; - } elseif ($doctype == DocTypes::XHTML_1_0_TRANSITIONAL) { + } elseif ($doctype == DocType::XHTML_1_0_TRANSITIONAL) { $this->dtd = ''; - } elseif ($doctype == DocTypes::XHTML_1_0_STRICT) { + } elseif ($doctype == DocType::XHTML_1_0_STRICT) { $this->dtd = ' '; - } elseif ($doctype == DocTypes::XHTML_1_0_FRAMESET) { + } elseif ($doctype == DocType::XHTML_1_0_FRAMESET) { $this->dtd = ''; - } elseif ($doctype == DocTypes::XHTML_1_1) { + } else { // DocType::XHTML_1_1 $this->dtd = ''; - } else { - throw new Exception('Invalid doctype'); } $this->docType = $doctype; } /** * Get the Doctype Declaration. - * + * * @return string */ public function getDtd(): string @@ -403,17 +401,17 @@ public function getDtd(): string /** * Get the Doctype. - * - * @return string + * + * @return DocType */ - public function getDocType(): string + public function getDocType(): DocType { return $this->docType; } /** * Set the encoding for the page. - * + * * Default is UTF-8. * * @param string $encoding @@ -432,15 +430,15 @@ public function setEncoding(string $encoding = 'UTF-8'): void public function getEncodingHtml(): string { return match ($this->docType) { - DocTypes::XHTML_1_0_STRICT, DocTypes::XHTML_1_0_TRANSITIONAL, DocTypes::XHTML_1_0_FRAMESET => '' . PHP_EOL, - DocTypes::HTML_4_01_TRANSITIONAL, DocTypes::HTML_4_01_FRAMESET, DocTypes::HTML_4_01_STRICT => '' . PHP_EOL, - DocTypes::HTML_5 => '' . PHP_EOL + DocType::XHTML_1_0_STRICT, DocType::XHTML_1_0_TRANSITIONAL, DocType::XHTML_1_0_FRAMESET, DocType::XHTML_1_1 => '' . PHP_EOL, + DocType::HTML_4_01_TRANSITIONAL, DocType::HTML_4_01_FRAMESET, DocType::HTML_4_01_STRICT => '' . PHP_EOL, + DocType::HTML_5 => '' . PHP_EOL }; } /** * Get the raw encoding. - * + * * @return string */ public function getEncoding(): string @@ -450,8 +448,8 @@ public function getEncoding(): string /** * Render a partial view. - * - * Any duplicate arguments will override ones in the view during the partial. + * + * Any duplicate arguments will override ones in the view during the partial. * The view itself does not change. * * @param string $file - filename to use for the view (in Views folder). @@ -464,7 +462,7 @@ public function partial(string $file, array $arguments = [], bool $includeView = } /** - * Render partial views by looping through the arguments loop. + * Render partial views by looping through the arguments loop. * * Any duplicate arguments will override ones in the view during the partial. * The view itself does not change. @@ -537,7 +535,7 @@ public function emptyView(): void /** * Get layout filename. - * + * * @return string */ public function getLayoutFile(): string @@ -546,7 +544,8 @@ public function getLayoutFile(): string } /** - * Set layout filename. + * Set layout filename. + * * @param string $file */ public function setLayoutFile(string $file = 'layout'): void @@ -556,7 +555,7 @@ public function setLayoutFile(string $file = 'layout'): void /** * Set a dynamic value on the view. - * + * * @param string $key * @param string|int|bool|float|object|array|null $value */ @@ -567,7 +566,7 @@ public function __set(string $key, string|int|bool|float|object|null|array $valu /** * Get a dynamic value from the view. - * + * * @param string $value * @return mixed */ diff --git a/bootstrap.php b/bootstrap.php index 70facb0..82c48f6 100644 --- a/bootstrap.php +++ b/bootstrap.php @@ -23,6 +23,7 @@ # DO NOT MODIFY THIS FILE AT ALL # ########################################################## # + use Feast\Autoloader; use Feast\Interfaces\RouterInterface; diff --git a/composer.json b/composer.json index e5dc46c..ee1686a 100644 --- a/composer.json +++ b/composer.json @@ -11,14 +11,19 @@ } ], "require": { - "php": "^8.0.0", + "php": "^8.2.0", "ext-pdo": "*", "ext-xml": "*", - "ext-readline": "*" + "ext-readline": "*", + "ext-ctype": "*", + "ext-simplexml": "*", + "ext-libxml": "*", + "ext-fileinfo": "*" }, "suggest": { "ext-mysql": "*", - "ext-pdo_mysql": "*" + "ext-pdo_mysql": "*", + "ext-curl": "*" }, "require-dev": { "psalm/phar": "^4.7" diff --git a/composer.lock b/composer.lock index 5d586dd..1c8d4ab 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "da5daea481c1324c0861881b62d11060", + "content-hash": "3f37ec1ab718163295e8b43c2e02c774", "packages": [], "packages-dev": [ { @@ -49,10 +49,14 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": "^8.0.0", + "php": "^8.2.0", "ext-pdo": "*", "ext-xml": "*", - "ext-readline": "*" + "ext-readline": "*", + "ext-ctype": "*", + "ext-simplexml": "*", + "ext-libxml": "*", + "ext-fileinfo": "*" }, "platform-dev": [], "plugin-api-version": "2.1.0" diff --git a/docs/CNAME b/docs/CNAME deleted file mode 100644 index ae42c55..0000000 --- a/docs/CNAME +++ /dev/null @@ -1 +0,0 @@ -docs.feast-framework.com \ No newline at end of file diff --git a/docs/index.md b/docs/index.md index 770d70e..ba89e67 100644 --- a/docs/index.md +++ b/docs/index.md @@ -67,8 +67,10 @@ up with the following principles always in mind. ## Requirements -The current release of FEAST requires PHP 8.0 and (if you wish to use the Curl service classes) PHP 8.0-curl. In -addition, PHP 8.0-bcmath is recommended. +The current release of FEAST requires >=PHP 8.2 and (if you wish to use the Curl service classes) PHP 8.2-curl. In +addition, PHP 8.2-bcmath is recommended. + +The v1.x line of FEAST requires >=PHP 8.0 and v2.x line requires >=PHP 8.1. The same recommendations above apply FEAST currently works with the MySQL and PostgreSQL database management systems as well as with SQLite for simple queries. diff --git a/docs/models.md b/docs/models.md index 495c7b7..9353a7d 100644 --- a/docs/models.md +++ b/docs/models.md @@ -305,6 +305,7 @@ see [feast:migration](cli.md#feastmigration) in the CLI docs. If you have cached your database info (see [feast:cache:dbinfo-generate](cli.md#feastcachedbinfo-generate)), then the cache will automatically re-generate after migrations are ran. + ### List Migrations You can quickly get a list of all migrations as well as their status by running `php famine feast:migration:list` @@ -343,14 +344,15 @@ All bindings in the below methods are passed in as a prepared statement executio ##### Where The `where` method creates a where clause on the query. It takes in a statement (or the where clause) -and bindings as either a `\Feast\Date` argument, a scalar, or an array of bindings for multiple. Each call to -the `where` method will create a parenthesis wrapped group, allowing you to focus only on what you need for that piece -of the statement. +and bindings as either a `\Feast\Date` argument, or a scalar. Multiple bindings may be passed in as needed. In versions +of FEAST Framework prior to 2.0, multiple bindings are passed in as an array. Each call to the `where` method will create +a parenthesis wrapped group, allowing you to focus only on what you need for that piece of the statement. Example ```php -$query->where('test = ? or test_name = ?', ['feast','feast])->where('active' => 1); +$query->where('test = ? or test_name = ?', ['feast','feast'])->where('active' => 1); // In version 1.x +$query->where('test = ? or test_name = ?', 'feast','feast')->where('active' => 1); // In version 2.0.0 and above // This will result in the following where clause on the query. // where (test = ? or test_name = ?) and (active = ?) ``` diff --git a/phpunit.xml b/phpunit.xml index eaa617d..6198ce2 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -1,36 +1,30 @@ - - - - FeastTests - - - - - . - Form.php - Email.php - Main.php - Attributes - Collection - Traits/Collection.php - Controllers - - - FeastTests - Install - PsalmLoader.php - ../Autoloader.php - - - - - - - - \ No newline at end of file + + + + + FeastTests + + + + + . + Form.php + Email.php + Main.php + Attributes + Collection + Traits/Collection.php + Controllers + + + FeastTests + Install + PsalmLoader.php + ../Autoloader.php + + + + + + + diff --git a/psalm.xml b/psalm.xml index 9e813e3..bfa369e 100644 --- a/psalm.xml +++ b/psalm.xml @@ -6,6 +6,7 @@ strictBinaryOperands="true" allowStringToStandInForClass="true" findUnusedPsalmSuppress="true" + sealAllMethods="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="https://getpsalm.org/schema/config" xsi:schemaLocation="https://getpsalm.org/schema/config%20vendor/vimeo/psalm/config.xsd"