Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Core: Continue component review #362

Merged
merged 5 commits into from
Feb 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 26 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,30 +31,33 @@ composer require --dev salient/phpstan
## Components

The Salient toolkit includes the following components, each of which can be
installed separately:
installed separately to minimise the dependency footprint of your project. The
only third-party dependencies are [PSR][] interface packages and [lkrms/dice][],
a standalone dependency injection container that will be removed when
[salient/container][] is finalised.

![Salient toolkit component diagram](images/components.svg)

| Component | Composer package | Provides |
| ------------- | ----------------------- | ----------------------------------------------------------------------------------- |
| Cache | [salient/cache][] | A key-value store backed by a SQLite database |
| **CLI** | [salient/cli][] | A service container and command framework for CLI applications |
| Collections | [salient/collections][] | Access to collections of values via array-like objects with chainable methods |
| **Console** | [salient/console][] | Terminal output and message logging via an API similar to `console` in web browsers |
| **Container** | [salient/container][] | A service container with contextual bindings |
| **Contracts** | [salient/contracts][] | Interfaces and abstractions |
| **Core** | [salient/core][] | Reusable classes, traits and services |
| Curler | [salient/curler][] | An HTTP client optimised for RESTful API endpoints |
| Db | [salient/db][] | Access to databases |
| HTTP | [salient/http][] | HTTP message and utility classes |
| Iterators | [salient/iterators][] | Iterator classes and traits |
| PHPDoc | [salient/phpdoc][] | A PHPDoc extractor and parser |
| PHPStan | [salient/phpstan][][^1] | PHPStan extensions |
| Polyfills | [salient/polyfills][] | Polyfills |
| Sli | [salient/sli][][^1] | `sli`, the toolkit's CLI utility |
| **Sync** | [salient/sync][] | A framework and SQLite-backed store for synchronising data with backends |
| Testing | [salient/testing][][^1] | Classes that are useful in test suites |
| **Utils** | [salient/utils][] | Utility methods via stateless classes |
| Component | Package | Provides |
| ----------- | ----------------------- | ----------------------------------------------------------------------------------- |
| Cache | [salient/cache][] | A key-value store backed by a SQLite database |
| CLI | [salient/cli][] | A service container and command framework for CLI applications |
| Collections | [salient/collections][] | Access to collections of values via array-like objects with chainable methods |
| Console | [salient/console][] | Terminal output and message logging via an API similar to `console` in web browsers |
| Container | [salient/container][] | A service container with contextual bindings |
| Contracts | [salient/contracts][] | Interfaces, abstractions and enumerations |
| Core | [salient/core][] | Reusable classes, traits and services |
| Curler | [salient/curler][] | An HTTP client optimised for RESTful API endpoints |
| Db | [salient/db][] | Access to databases |
| HTTP | [salient/http][] | HTTP message and utility classes |
| Iterators | [salient/iterators][] | Iterator classes and traits |
| PHPDoc | [salient/phpdoc][] | A PHPDoc extractor and parser |
| PHPStan | [salient/phpstan][][^1] | PHPStan extensions |
| Polyfills | [salient/polyfills][] | Polyfills |
| Sli | [salient/sli][][^1] | `sli`, the toolkit's CLI utility |
| Sync | [salient/sync][] | A framework and SQLite-backed store for synchronising data with backends |
| Testing | [salient/testing][][^1] | Classes that are useful in test suites |
| Utils | [salient/utils][] | Utility methods via stateless classes |

[^1]: This component should only be installed as a development dependency.

Expand Down Expand Up @@ -82,7 +85,9 @@ This project is licensed under the [MIT License][].
[ApiGen]: https://github.com/ApiGen/ApiGen
[Composer]: https://getcomposer.org/
[docs]: docs/
[lkrms/dice]: https://packagist.org/packages/lkrms/dice
[MIT License]: LICENSE
[PSR]: https://www.php-fig.org/psr/
[repo]: https://github.com/salient-labs/toolkit
[salient/cache]: https://packagist.org/packages/salient/cache
[salient/cli]: https://packagist.org/packages/salient/cli
Expand Down
5 changes: 3 additions & 2 deletions docs/Builders.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,16 @@
<?php

use Salient\Contract\Core\Buildable;
use Salient\Core\Concern\HasBuilder;
use Salient\Core\Concern\BuildableTrait;
use Salient\Core\AbstractBuilder;

/**
* @implements Buildable<OptionBuilder>
*/
class Option implements Buildable
{
use HasBuilder;
/** @use BuildableTrait<OptionBuilder> */
use BuildableTrait;

protected $Long;
protected $Short;
Expand Down
30 changes: 30 additions & 0 deletions docs/Entities.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,35 @@
# Entity interfaces

## `Readable`

If a class implements `Readable`:

- `protected` properties covered by `Readable::getReadableProperties()` can be
read via magic methods
- if `_get<Property>()` is defined, it is called instead of returning the value
of `<Property>`
- similarly, if `_isset<Property>()` is defined, it is called instead of
returning `isset(<Property>)`
- if `_get<Property>()` is defined and `_isset<Property>()` is not,
`isset(<Property>)` is equivalent to `_get<Property>() === null`
- the existence of `_get<Property>()` makes `<Property>` readable, regardless of
the return value of `Readable::getReadableProperties()`

## `Writable`

If a class implements `Writable`:

- `protected` properties covered by `Writable::getWritableProperties()` can be
written via magic methods
- if `_set<Property>()` is defined, it is called instead of assigning `$value`
to `<Property>`
- similarly, if `_unset<Property>()` is defined, it is called instead of using
`unset(<Property>)`
- if `_set<Property>()` is defined and `_unset<Property>()` is not,
`unset(<Property>)` is equivalent to `_set<Property>(null)`
- the existence of `_set<Property>()` makes `<Property>` writable, regardless of
the return value of `Writable::getWritableProperties()`

## `Relatable`

Example:
Expand Down
4 changes: 2 additions & 2 deletions scripts/generate.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
use Salient\Testing\Console\MockTarget;
use Salient\Tests\Core\AbstractFacade\MyBrokenFacade;
use Salient\Tests\Core\AbstractFacade\MyClassFacade;
use Salient\Tests\Core\AbstractFacade\MyHasFacadeClass;
use Salient\Tests\Core\AbstractFacade\MyFacadeAwareInstanceClass;
use Salient\Tests\Core\AbstractFacade\MyInterfaceFacade;
use Salient\Tests\Core\AbstractFacade\MyServiceClass;
use Salient\Tests\Core\AbstractFacade\MyServiceInterface;
Expand Down Expand Up @@ -84,7 +84,7 @@
Profile::class => [MetricCollector::class, '--api'],
// Test fixtures
MyBrokenFacade::class => [MyServiceInterface::class, ['Salient\Tests\Core\AbstractFacade\MyNonExistentClass']],
MyInterfaceFacade::class => [MyServiceInterface::class, ['Salient\Tests\Core\AbstractFacade\MyNonExistentClass', MyHasFacadeClass::class]],
MyInterfaceFacade::class => [MyServiceInterface::class, ['Salient\Tests\Core\AbstractFacade\MyNonExistentClass', MyFacadeAwareInstanceClass::class]],
MyClassFacade::class => [MyServiceClass::class, '--skip', 'withArgs'],
];

Expand Down
2 changes: 2 additions & 0 deletions src/Toolkit/Cli/CliCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -695,6 +695,8 @@ final protected function getNameWithProgram(): string
}

/**
* Get a JSON Schema for the command's options
*
* @return array{'$schema':string,type:string,required?:string[],properties?:array<string,mixed>,...}
*/
final public function getJsonSchema(): array
Expand Down
4 changes: 2 additions & 2 deletions src/Toolkit/Cli/CliHelpStyle.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
use Salient\Contract\Cli\CliHelpTarget;
use Salient\Contract\Cli\CliOptionVisibility;
use Salient\Contract\Console\ConsoleFormatterInterface as FormatterInterface;
use Salient\Core\Concern\HasMutator;
use Salient\Core\Concern\ImmutableTrait;
use Salient\Core\Facade\Console;
use Salient\Utility\Regex;
use LogicException;
Expand All @@ -23,7 +23,7 @@
*/
final class CliHelpStyle implements CliHelpStyleInterface
{
use HasMutator;
use ImmutableTrait;

private ?int $Width;
private FormatterInterface $Formatter;
Expand Down
12 changes: 6 additions & 6 deletions src/Toolkit/Cli/CliOption.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
use Salient\Contract\Core\Buildable;
use Salient\Contract\Core\HasJsonSchema;
use Salient\Contract\Core\Immutable;
use Salient\Core\Concern\HasBuilder;
use Salient\Core\Concern\ReadsProtectedProperties;
use Salient\Core\Concern\BuildableTrait;
use Salient\Core\Concern\ReadableProtectedPropertiesTrait;
use Salient\Core\Facade\Console;
use Salient\Utility\Arr;
use Salient\Utility\Env;
Expand Down Expand Up @@ -68,9 +68,9 @@
*/
final class CliOption implements Buildable, HasJsonSchema, Immutable, Readable
{
/** @use HasBuilder<CliOptionBuilder> */
use HasBuilder;
use ReadsProtectedProperties;
/** @use BuildableTrait<CliOptionBuilder> */
use BuildableTrait;
use ReadableProtectedPropertiesTrait;

private const LONG_REGEX = '/^[a-z0-9_][-a-z0-9_]++$/iD';
private const SHORT_REGEX = '/^[a-z0-9_]$/iD';
Expand Down Expand Up @@ -619,7 +619,7 @@ private function throwEnvVariableException(string $value): void
}

/**
* Get the option's JSON Schema
* Get a JSON Schema for the option
*
* @return array{description?:string,type?:string[]|string,enum?:array<string|int|bool|float|null>,items?:array{type?:string[]|string,enum?:array<string|int|bool|float|null>},uniqueItems?:bool,default?:array<string|int|bool|float>|string|int|bool|float}
*/
Expand Down
4 changes: 2 additions & 2 deletions src/Toolkit/Console/ConsoleFormatter.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
use Salient\Contract\Console\ConsoleFormatterInterface as FormatterInterface;
use Salient\Contract\Console\ConsoleMessageType as MessageType;
use Salient\Contract\Console\ConsoleTag as Tag;
use Salient\Core\Concern\HasMutator;
use Salient\Core\Concern\ImmutableTrait;
use Salient\Utility\Regex;
use Salient\Utility\Str;
use LogicException;
Expand All @@ -24,7 +24,7 @@
*/
final class ConsoleFormatter implements FormatterInterface
{
use HasMutator;
use ImmutableTrait;

public const DEFAULT_LEVEL_PREFIX_MAP = [
Level::EMERGENCY => '! ', // U+0021
Expand Down
6 changes: 3 additions & 3 deletions src/Toolkit/Console/ConsoleWriter.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
use Salient\Contract\Core\Exception\MultipleErrorException;
use Salient\Contract\Core\Facade\FacadeAwareInterface;
use Salient\Contract\Core\Unloadable;
use Salient\Core\Concern\HasFacade;
use Salient\Core\Concern\FacadeAwareInstanceTrait;
use Salient\Core\Facade\Console;
use Salient\Utility\Exception\InvalidEnvironmentException;
use Salient\Utility\Arr;
Expand All @@ -45,8 +45,8 @@
*/
final class ConsoleWriter implements ConsoleWriterInterface, FacadeAwareInterface, Unloadable
{
/** @use HasFacade<ConsoleWriterInterface> */
use HasFacade;
/** @use FacadeAwareInstanceTrait<ConsoleWriterInterface> */
use FacadeAwareInstanceTrait;

private ConsoleWriterState $State;

Expand Down
4 changes: 2 additions & 2 deletions src/Toolkit/Console/Support/ConsoleMessageAttributes.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@
use Salient\Contract\Catalog\MessageLevel as Level;
use Salient\Contract\Console\ConsoleMessageAttributesInterface;
use Salient\Contract\Console\ConsoleMessageType as MessageType;
use Salient\Core\Concern\HasMutator;
use Salient\Core\Concern\ImmutableTrait;

/**
* Message attributes
*/
final class ConsoleMessageAttributes implements ConsoleMessageAttributesInterface
{
use HasMutator;
use ImmutableTrait;

/**
* Message level
Expand Down
4 changes: 2 additions & 2 deletions src/Toolkit/Console/Support/ConsoleTagFormats.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@
use Salient\Contract\Console\ConsoleFormatInterface as Format;
use Salient\Contract\Console\ConsoleTag as Tag;
use Salient\Contract\Core\Immutable;
use Salient\Core\Concern\HasMutator;
use Salient\Core\Concern\ImmutableTrait;
use Salient\Utility\Arr;

/**
* Maps inline formatting tags to formats
*/
final class ConsoleTagFormats implements Immutable
{
use HasMutator;
use ImmutableTrait;

/** @var array<Tag::*,Format> */
private array $Formats = [];
Expand Down
10 changes: 5 additions & 5 deletions src/Toolkit/Container/Container.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@
use Salient\Contract\Container\SingletonInterface;
use Salient\Contract\Core\Facade\FacadeAwareInterface;
use Salient\Contract\Sync\SyncStoreInterface;
use Salient\Core\Concern\HasChainableMethods;
use Salient\Core\Concern\UnloadsFacades;
use Salient\Core\Concern\ChainableTrait;
use Salient\Core\Concern\FacadeAwareTrait;
use Salient\Core\Facade\Event;
use Salient\Sync\SyncStore;
use Closure;
Expand All @@ -43,9 +43,9 @@
*/
class Container implements ContainerInterface, FacadeAwareInterface
{
/** @use UnloadsFacades<ContainerInterface> */
use UnloadsFacades;
use HasChainableMethods;
/** @use FacadeAwareTrait<ContainerInterface> */
use FacadeAwareTrait;
use ChainableTrait;

private const SERVICE_PROVIDER_INTERFACES = [
ContainerAwareInterface::class,
Expand Down
2 changes: 1 addition & 1 deletion src/Toolkit/Contract/Core/BuilderInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public static function create();
public static function resolve($object);

/**
* Terminate the builder by returning an instance
* Terminate the builder by creating an instance
*
* @return TClass
*/
Expand Down
9 changes: 2 additions & 7 deletions src/Toolkit/Contract/Core/Comparable.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,17 @@
namespace Salient\Contract\Core;

/**
* Able to compare instances of itself, e.g. for sorting purposes
* @api
*/
interface Comparable
{
/**
* Get an integer less than, equal to, or greater than zero when $a is less
* than, equal to, or greater than $b, respectively
*
* This method returns the equivalent of:
*
* ```php
* $a <=> $b
* ```
*
* @param static $a
* @param static $b
* @return int A value that can be used instead of `$a <=> $b`.
*/
public static function compare($a, $b): int;
}
10 changes: 2 additions & 8 deletions src/Toolkit/Contract/Core/DateFormatterInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,15 @@

namespace Salient\Contract\Core;

use DateTimeImmutable;
use DateTimeInterface;

/**
* @api
*/
interface DateFormatterInterface
interface DateFormatterInterface extends DateParserInterface
{
/**
* Format a date and time
* Format a date and time as a string
*/
public function format(DateTimeInterface $date): string;

/**
* Convert a value to a date and time, or return null if it can't be parsed
*/
public function parse(string $value): ?DateTimeImmutable;
}
20 changes: 7 additions & 13 deletions src/Toolkit/Contract/Core/DateParserInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,15 @@
interface DateParserInterface
{
/**
* Convert a value to a date and time, or return null if it can't be parsed
* Convert a string to a date and time, returning null if it can't be parsed
*
* If the value does not specify a timezone, one of the following is used
* during parsing:
* The timezone used during parsing is the first that applies of:
*
* - `$timezone` (if given)
* - the parser's default timezone (if applicable)
* - the script's default timezone (if set)
* - the timezone specified by `$value`
* - `$timezone`
* - the parser's default timezone (if implemented)
* - the default timezone used by date and time functions (if set)
* - `UTC`
*
* If `$timezone` is given, it is applied to the date and time before it is
* returned.
*/
public function parse(
string $value,
?DateTimeZone $timezone = null
): ?DateTimeImmutable;
public function parse(string $value, ?DateTimeZone $timezone = null): ?DateTimeImmutable;
}
2 changes: 1 addition & 1 deletion src/Toolkit/Contract/Core/Entity/Treeable.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public static function getParentProperty(): string;
/**
* Get the property that links a parent to children of the same type
*
* The property returned must accept `iterable<static>`.
* The property returned must accept `static[]`.
*/
public static function getChildrenProperty(): string;
}
2 changes: 1 addition & 1 deletion src/Toolkit/Contract/Core/HasId.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
interface HasId
{
/**
* Get the object's unique identifier
* Get the unique identifier of the object
*
* @return int|string|null
*/
Expand Down
Loading