Skip to content

Commit 959b295

Browse files
committed
chore: Add partial base implementation
1 parent f1db702 commit 959b295

15 files changed

+776
-1
lines changed

src/Concise.php

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace Articulate\Concise;
5+
6+
use Articulate\Concise\Contracts\EntityMapper;
7+
use Articulate\Concise\Contracts\Mapper;
8+
use Articulate\Concise\Contracts\Repository;
9+
use Illuminate\Foundation\Application;
10+
11+
final class Concise
12+
{
13+
/**
14+
* @var \Illuminate\Foundation\Application
15+
*/
16+
private Application $app;
17+
18+
/**
19+
* @var array<class-string, \Articulate\Concise\Contracts\EntityMapper<*>>
20+
*/
21+
private array $entityMappers = [];
22+
23+
/**
24+
* @var array<class-string, \Articulate\Concise\Contracts\Mapper<*>>
25+
*/
26+
private array $componentMappers = [];
27+
28+
public function __construct(Application $app)
29+
{
30+
$this->app = $app;
31+
}
32+
33+
/**
34+
* Register a class mapper.
35+
*
36+
* @template MapperObject of object
37+
*
38+
* @param \Articulate\Concise\Contracts\Mapper<MapperObject> $mapper
39+
* @param bool $overwrite
40+
*
41+
* @return bool
42+
*/
43+
public function register(Mapper $mapper, bool $overwrite = false): bool
44+
{
45+
if ($mapper instanceof EntityMapper) {
46+
if ($overwrite === false && isset($this->entityMappers[$mapper->class()])) {
47+
return false;
48+
}
49+
50+
$this->entityMappers[$mapper->class()] = $mapper;
51+
52+
return true;
53+
}
54+
55+
if ($overwrite === false && isset($this->componentMappers[$mapper->class()])) {
56+
return false;
57+
}
58+
59+
$this->componentMappers[$mapper->class()] = $mapper;
60+
61+
return true;
62+
}
63+
64+
/**
65+
* Get a registered entity mapper for the provided class.
66+
*
67+
* @template EntityObject of object
68+
*
69+
* @param class-string<EntityObject> $class
70+
*
71+
* @return \Articulate\Concise\Contracts\EntityMapper<EntityObject>|null
72+
*/
73+
public function entity(string $class): ?EntityMapper
74+
{
75+
/** @var \Articulate\Concise\Contracts\EntityMapper<EntityObject>|null $mapper */
76+
$mapper = $this->entityMappers[$class] ?? null;
77+
78+
return $mapper;
79+
}
80+
81+
/**
82+
* Get an entity repository for the provided class.
83+
*
84+
* @template EntityObject of object
85+
*
86+
* @param class-string<EntityObject> $class
87+
*
88+
* @return \Articulate\Concise\Contracts\Repository<EntityObject>|null
89+
*
90+
* @throws \Illuminate\Contracts\Container\BindingResolutionException
91+
*/
92+
public function repository(string $class): ?Repository
93+
{
94+
/** @var \Articulate\Concise\Contracts\EntityMapper<EntityObject>|null $mapper */
95+
$mapper = $this->entity($class);
96+
97+
if ($mapper === null) {
98+
return null;
99+
}
100+
101+
$repository = $mapper->repository();
102+
103+
if ($repository === null) {
104+
return new EntityRepository(
105+
$mapper,
106+
$this->app->make('db')->connection($mapper->connection()),
107+
);
108+
}
109+
110+
return $this->app->make($repository, [
111+
'mapper' => $mapper,
112+
'connection' => $this->app->make('db')->connection($mapper->connection()),
113+
]);
114+
}
115+
}

src/ConciseServiceProvider.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,20 @@
33

44
namespace Articulate\Concise;
55

6+
use Articulate\Concise\Support\ImplicitBindingSubstitution;
7+
use Illuminate\Routing\Router;
68
use Illuminate\Support\ServiceProvider;
79

810
class ConciseServiceProvider extends ServiceProvider
911
{
1012
public function register(): void
1113
{
14+
// Bind the main concise class
15+
$this->app->singleton(Concise::class);
1216

17+
// Add our custom implicit binding substitution
18+
$this->app->afterResolving(Router::class, function (Router $router) {
19+
$router->substituteImplicitBindingsUsing($this->app->make(ImplicitBindingSubstitution::class));
20+
});
1321
}
1422
}

src/Contracts/Criteria.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
namespace Articulate\Concise\Contracts;
4+
5+
use Articulate\Concise\Query\Builder;
6+
7+
/**
8+
*
9+
*/
10+
interface Criteria
11+
{
12+
/**
13+
* @template EntityObject of object
14+
*
15+
* @param \Articulate\Concise\Query\Builder<EntityObject> $query
16+
* @param \Articulate\Concise\Contracts\EntityMapper<EntityObject> $mapper
17+
*
18+
* @return void
19+
*/
20+
public function apply(Builder $query, EntityMapper $mapper): void;
21+
}

src/Contracts/EntityMapper.php

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
3+
namespace Articulate\Concise\Contracts;
4+
5+
/**
6+
* Entity Mapper
7+
*
8+
* Entity mappers are more specific implementations of
9+
* {@see \Articulate\Concise\Contracts\Mapper} that deal with entities stored in
10+
* the database.
11+
*
12+
* @template EntityObject of object
13+
*
14+
* @extends \Articulate\Concise\Contracts\Mapper<EntityObject>
15+
*/
16+
interface EntityMapper extends Mapper
17+
{
18+
/**
19+
* Get the custom repository class for the entity
20+
*
21+
* @return class-string<\Articulate\Concise\Contracts\Repository<EntityObject>>|null
22+
*/
23+
public function repository(): ?string;
24+
25+
/**
26+
* Get the connection the entity should use
27+
*
28+
* @return string|null
29+
*/
30+
public function connection(): ?string;
31+
32+
/**
33+
* Get the entities' database table
34+
*
35+
* @return string
36+
*/
37+
public function table(): string;
38+
39+
/**
40+
* Get the name of the identity field
41+
*
42+
* @return string
43+
*/
44+
public function identity(): string;
45+
}

src/Contracts/Mapper.php

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
3+
namespace Articulate\Concise\Contracts;
4+
5+
/**
6+
* Mapper
7+
*
8+
* Mappers are responsible for mapping between raw data and object representations.
9+
*
10+
* @template MapObject of object
11+
*/
12+
interface Mapper
13+
{
14+
/**
15+
* Get the class name this mapper represents.
16+
*
17+
* Returns the fully qualified class name of the object that this mapper is
18+
* mapping.
19+
*
20+
* @return class-string<MapObject>
21+
*/
22+
public function class(): string;
23+
24+
/**
25+
* Convert a raw array to an object representation.
26+
*
27+
* @param array<string, mixed> $data
28+
*
29+
* @return object
30+
*
31+
* @phpstan-return MapObject
32+
*/
33+
public function toObject(array $data): object;
34+
35+
/**
36+
* Convert an object representation to raw data.
37+
*
38+
* @param object $object
39+
*
40+
* @phpstan-param MapObject $object
41+
*
42+
* @return array<string, mixed>
43+
*/
44+
public function toData(object $object): array;
45+
}

src/Contracts/Repository.php

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
3+
namespace Articulate\Concise\Contracts;
4+
5+
use Illuminate\Contracts\Pagination\Paginator;
6+
use Illuminate\Support\Collection;
7+
8+
/**
9+
* @template EntityObject of object
10+
*/
11+
interface Repository
12+
{
13+
/**
14+
* Get one record for the provided criteria.
15+
*
16+
* @param \Articulate\Concise\Contracts\Criteria ...$criteria
17+
*
18+
* @return object|null
19+
*
20+
* @phpstan-return EntityObject|null
21+
*/
22+
public function getOne(Criteria ...$criteria): ?object;
23+
24+
/**
25+
* Get many records for the provided criteria.
26+
*
27+
* @param \Articulate\Concise\Contracts\Criteria ...$criteria
28+
*
29+
* @return \Illuminate\Support\Collection<array-key, EntityObject>
30+
*/
31+
public function getMany(Criteria ...$criteria): Collection;
32+
33+
/**
34+
* Get a paginated collection of records for the provided criteria.
35+
*
36+
* @param \Articulate\Concise\Contracts\Criteria ...$criteria
37+
*
38+
* @return \Illuminate\Contracts\Pagination\Paginator<EntityObject>
39+
*/
40+
public function getPaginated(Criteria ...$criteria): Paginator;
41+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
namespace Articulate\Concise\Contracts;
4+
5+
/**
6+
* @template EntityObject of object
7+
*
8+
* @requires \Articulate\Concise\Contracts\Repository<EntityObject>
9+
*/
10+
interface RoutableRepository
11+
{
12+
/**
13+
* @param string $value
14+
* @param string|null $binding
15+
*
16+
* @return object|null
17+
*
18+
* @phpstan-return EntityObject|null
19+
*/
20+
public function getOneForRouting(string $value, ?string $binding = null): ?object;
21+
}

src/Criteria/ForIdentifier.php

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace Articulate\Concise\Criteria;
5+
6+
use Articulate\Concise\Contracts\Criteria;
7+
use Articulate\Concise\Contracts\EntityMapper;
8+
use Articulate\Concise\Query\Builder;
9+
10+
final readonly class ForIdentifier implements Criteria
11+
{
12+
private string|int $identifier;
13+
14+
public function __construct(string|int $identifier)
15+
{
16+
$this->identifier = $identifier;
17+
}
18+
19+
/**
20+
* @template EntityObject of object
21+
*
22+
* @param \Articulate\Concise\Query\Builder<EntityObject> $query
23+
* @param \Articulate\Concise\Contracts\EntityMapper<EntityObject> $mapper
24+
*
25+
* @return void
26+
*/
27+
public function apply(Builder $query, EntityMapper $mapper): void
28+
{
29+
$query->where(
30+
$query->qualifyColumn($mapper->identity()),
31+
'=',
32+
$this->identifier
33+
);
34+
}
35+
}

src/Criteria/WhereColumn.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace Articulate\Concise\Criteria;
5+
6+
use Articulate\Concise\Contracts\Criteria;
7+
use Articulate\Concise\Contracts\EntityMapper;
8+
use Articulate\Concise\Query\Builder;
9+
10+
final class WhereColumn implements Criteria
11+
{
12+
private string $column;
13+
14+
private string $operator;
15+
16+
private mixed $value;
17+
18+
public function __construct(string $column, string $operator, mixed $value)
19+
{
20+
$this->column = $column;
21+
$this->operator = $operator;
22+
$this->value = $value;
23+
}
24+
25+
/**
26+
* @template EntityObject of object
27+
*
28+
* @param \Articulate\Concise\Query\Builder<EntityObject> $query
29+
* @param \Articulate\Concise\Contracts\EntityMapper<EntityObject> $mapper
30+
*
31+
* @return void
32+
*/
33+
public function apply(Builder $query, EntityMapper $mapper): void
34+
{
35+
$query->where($this->column, $this->operator, $this->value);
36+
}
37+
}

0 commit comments

Comments
 (0)