Skip to content

Commit 0c5810b

Browse files
committed
SchemaModel Introduction
1 parent 8fcf39a commit 0c5810b

File tree

7 files changed

+480
-27
lines changed

7 files changed

+480
-27
lines changed

src/Models/Config.php

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace StellarWP\Models;
44

55
use InvalidArgumentException;
6+
use RuntimeException;
67

78
class Config {
89
/**
@@ -21,10 +22,12 @@ class Config {
2122
* @since 1.0.0
2223
*
2324
* @return string
25+
*
26+
* @throws RuntimeException If the hook prefix is not set.
2427
*/
2528
public static function getHookPrefix(): string {
2629
if ( ! static::$hookPrefix ) {
27-
throw new \RuntimeException(
30+
throw new RuntimeException(
2831
sprintf(
2932
'You must provide a hook prefix via %1$s before using the stellarwp/models library.',
3033
__CLASS__ . '::setHookPrefix()'
@@ -66,10 +69,13 @@ public static function reset() {
6669
* @param string $hook_prefix
6770
*
6871
* @return void
72+
*
73+
* @throws RuntimeException If the hook prefix has already been set.
74+
* @throws InvalidArgumentException If the sanitized hook prefix is not the same as the original hook prefix.
6975
*/
7076
public static function setHookPrefix( string $hook_prefix ) {
7177
if ( ! empty( static::$hookPrefix ) ) {
72-
throw new \RuntimeException(
78+
throw new RuntimeException(
7379
sprintf(
7480
'The %1$s has already been called and set to %2$s.',
7581
__CLASS__ . '::setHookPrefix()',
@@ -81,7 +87,7 @@ public static function setHookPrefix( string $hook_prefix ) {
8187
$sanitized_prefix = preg_replace( '/[^a-z0-9_-]/', '', $hook_prefix );
8288

8389
if ( $sanitized_prefix !== $hook_prefix ) {
84-
throw new \InvalidArgumentException( 'Hook prefix must only contain lowercase letters, numbers, "_", or "-".' );
90+
throw new InvalidArgumentException( 'Hook prefix must only contain lowercase letters, numbers, "_", or "-".' );
8591
}
8692

8793
static::$hookPrefix = $hook_prefix;
@@ -95,10 +101,12 @@ public static function setHookPrefix( string $hook_prefix ) {
95101
* @param string $class
96102
*
97103
* @return void
104+
*
105+
* @throws InvalidArgumentException If the provided InvalidArgumentException class is not or does not extend InvalidArgumentException.
98106
*/
99107
public static function setInvalidArgumentException( string $class ) {
100108
if ( ! is_a( $class, InvalidArgumentException::class, true ) ) {
101-
throw new \InvalidArgumentException( 'The provided InvalidArgumentException class must be or must extend ' . InvalidArgumentException::class . '.' );
109+
throw new InvalidArgumentException( 'The provided InvalidArgumentException class must be or must extend ' . InvalidArgumentException::class . '.' );
102110
}
103111

104112
static::$invalidArgumentException = $class;
@@ -112,6 +120,8 @@ public static function setInvalidArgumentException( string $class ) {
112120
* @param string $message
113121
*
114122
* @return void
123+
*
124+
* @throws InvalidArgumentException Always, thats what it does.
115125
*/
116126
public static function throwInvalidArgumentException( string $message ): void {
117127
throw new static::$invalidArgumentException( $message );

src/Models/Contracts/Model.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ public static function hasProperty( string $key ) : bool;
9999
*
100100
* @return bool
101101
*/
102-
public function isClean( string $attribute = null ) : bool;
102+
public function isClean( ?string $attribute = null ) : bool;
103103

104104
/**
105105
* Determines if a given attribute is dirty.
@@ -110,7 +110,7 @@ public function isClean( string $attribute = null ) : bool;
110110
*
111111
* @return bool
112112
*/
113-
public function isDirty( string $attribute = null ) : bool;
113+
public function isDirty( ?string $attribute = null ) : bool;
114114

115115
/**
116116
* Validates an attribute to a PHP type.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
namespace StellarWP\Models\Contracts;
4+
5+
interface SchemaModel extends Model {
6+
public function get_primary_value();
7+
8+
public function set_primary_value( $value ): void;
9+
10+
public function getTableInterface();
11+
12+
public function __call( string $name, array $arguments );
13+
14+
public function getRelationships(): array;
15+
16+
public function deleteRelationshipData( string $key ): void;
17+
18+
public function addToRelationship( string $key, int $id ): void;
19+
20+
public function removeFromRelationship( string $key, int $id ): void;
21+
22+
public function save(): int;
23+
24+
public function delete(): bool;
25+
}

src/Models/Model.php

Lines changed: 47 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,47 @@
11
<?php
2+
/**
3+
* The model.
4+
*
5+
* @since 1.0.0
6+
*
7+
* @package StellarWP\Models;
8+
*/
29

310
namespace StellarWP\Models;
411

512
use JsonSerializable;
6-
use RuntimeException;
713
use StellarWP\Models\Contracts\Arrayable;
814
use StellarWP\Models\Contracts\Model as ModelInterface;
915
use StellarWP\Models\ValueObjects\Relationship;
10-
16+
use InvalidArgumentException;
17+
18+
/**
19+
* The model.
20+
*
21+
* @since 1.0.0
22+
*
23+
* @package StellarWP\Models;
24+
*/
1125
abstract class Model implements ModelInterface, Arrayable, JsonSerializable {
26+
/**
27+
* The build mode for the model.
28+
*
29+
* @var int
30+
*/
1231
public const BUILD_MODE_STRICT = 0;
32+
33+
/**
34+
* The build mode for the model.
35+
*
36+
* @var int
37+
*/
1338
public const BUILD_MODE_IGNORE_MISSING = 1;
39+
40+
/**
41+
* The build mode for the model.
42+
*
43+
* @var int
44+
*/
1445
public const BUILD_MODE_IGNORE_EXTRA = 2;
1546

1647
/**
@@ -25,21 +56,21 @@ abstract class Model implements ModelInterface, Arrayable, JsonSerializable {
2556
*
2657
* @var array<string,string|array>
2758
*/
28-
protected static $properties = [];
59+
protected static array $properties = [];
2960

3061
/**
3162
* The model relationships assigned to their relationship types.
3263
*
3364
* @var array<string,string>
3465
*/
35-
protected static $relationships = [];
66+
protected static array $relationships = [];
3667

3768
/**
3869
* Relationships that have already been loaded and don't need to be loaded again.
3970
*
4071
* @var Model[]
4172
*/
42-
private $cachedRelations = [];
73+
private array $cachedRelations = [];
4374

4475
/**
4576
* Constructor.
@@ -63,6 +94,8 @@ public function __construct( array $attributes = [] ) {
6394
* @param string $property The property being casted.
6495
*
6596
* @return mixed
97+
*
98+
* @throws InvalidArgumentException If the value is not valid for the property.
6699
*/
67100
protected static function castValueForProperty( ModelPropertyDefinition $definition, $value, string $property ) {
68101
if ( $definition->isValidValue( $value ) || $value === null ) {
@@ -75,7 +108,7 @@ protected static function castValueForProperty( ModelPropertyDefinition $definit
75108

76109
$type = $definition->getType();
77110
if ( count( $type ) !== 1 ) {
78-
throw new \InvalidArgumentException( "Property '$property' has multiple types: " . implode( ', ', $type ) . ". To support additional types, implement a custom castValueForProperty() method." );
111+
throw new InvalidArgumentException( "Property '$property' has multiple types: " . implode( ', ', $type ) . ". To support additional types, implement a custom castValueForProperty() method." );
79112
}
80113

81114
switch ( $type[0] ) {
@@ -169,6 +202,8 @@ public function getAttribute( string $key, $default = null ) {
169202
* @since 1.0.0
170203
*
171204
* @return array<string,mixed>
205+
*
206+
* @throws InvalidArgumentException If the property does not exist.
172207
*/
173208
public function getDirty() : array {
174209
return $this->propertyCollection->getDirtyValues();
@@ -178,7 +213,7 @@ public static function getPropertyDefinition( string $key ): ModelPropertyDefini
178213
$definitions = static::getPropertyDefinitions();
179214

180215
if ( ! isset( $definitions[ $key ] ) ) {
181-
throw new \InvalidArgumentException( 'Property ' . $key . ' does not exist.' );
216+
throw new InvalidArgumentException( 'Property ' . $key . ' does not exist.' );
182217
}
183218

184219
return $definitions[ $key ];
@@ -190,6 +225,8 @@ public static function getPropertyDefinition( string $key ): ModelPropertyDefini
190225
* @since 2.0.0
191226
*
192227
* @return array<string,ModelPropertyDefinition>
228+
*
229+
* @throws InvalidArgumentException If the property key is not a string.
193230
*/
194231
public static function getPropertyDefinitions(): array {
195232
static $definition = null;
@@ -199,7 +236,7 @@ public static function getPropertyDefinitions(): array {
199236

200237
foreach ( $definitions as $key => $definition ) {
201238
if ( ! is_string( $key ) ) {
202-
throw new \InvalidArgumentException( 'Property key must be a string.' );
239+
throw new InvalidArgumentException( 'Property key must be a string.' );
203240
}
204241

205242
if ( ! $definition instanceof ModelPropertyDefinition ) {
@@ -224,7 +261,7 @@ public static function getPropertyDefinitions(): array {
224261
*
225262
* @return mixed|array
226263
*/
227-
public function getOriginal( string $key = null ) {
264+
public function getOriginal( ?string $key = null ) {
228265
return $key ? $this->propertyCollection->getOrFail( $key )->getOriginalValue() : $this->propertyCollection->getOriginalValues();
229266
}
230267

@@ -368,7 +405,7 @@ public static function isPropertyTypeValid( string $key, $value ) : bool {
368405
*/
369406
#[\ReturnTypeWillChange]
370407
public function jsonSerialize() {
371-
return get_object_vars( $this );
408+
return $this->toArray();
372409
}
373410

374411
/**

src/Models/ModelPropertyCollection.php

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,19 @@
44

55
namespace StellarWP\Models;
66

7+
use Countable;
8+
use IteratorAggregate;
9+
use InvalidArgumentException;
10+
use ArrayIterator;
11+
use Traversable;
12+
713
/**
814
* A collection of properties for a model.
915
*
1016
* Some philosophical notes:
1117
* * The collection is immutable. Once created, the collection cannot be changed.
1218
*/
13-
class ModelPropertyCollection implements \Countable, \IteratorAggregate {
19+
class ModelPropertyCollection implements Countable, IteratorAggregate {
1420
/**
1521
* The properties.
1622
*
@@ -23,15 +29,18 @@ class ModelPropertyCollection implements \Countable, \IteratorAggregate {
2329
*
2430
* @since 2.0.0
2531
* @param array<string,ModelProperty> $properties
32+
*
33+
* @throws InvalidArgumentException If the property key is not a string.
34+
* @throws InvalidArgumentException If the property is not an instance of ModelProperty.
2635
*/
2736
public function __construct( array $properties = [] ) {
2837
foreach ( $properties as $key => $property ) {
2938
if ( ! is_string( $key ) ) {
30-
throw new \InvalidArgumentException( 'Property key must be a string.' );
39+
throw new InvalidArgumentException( 'Property key must be a string.' );
3140
}
3241

3342
if ( ! $property instanceof ModelProperty ) {
34-
throw new \InvalidArgumentException( 'Property must be an instance of ModelProperty.' );
43+
throw new InvalidArgumentException( 'Property must be an instance of ModelProperty.' );
3544
}
3645

3746
$this->properties[$key] = $property;
@@ -53,7 +62,7 @@ public function commitChangedProperties(): void {
5362
* @since 2.0.0
5463
*/
5564
public function count(): int {
56-
return count($this->properties);
65+
return count( $this->properties );
5766
}
5867

5968
/**
@@ -74,17 +83,20 @@ public function filter( callable $callback, $mode = 0 ): ModelPropertyCollection
7483
*
7584
* @param array<string,ModelPropertyDefinition> $propertyDefinitions
7685
* @return ModelPropertyCollection
86+
*
87+
* @throws InvalidArgumentException If the property key is not a string.
88+
* @throws InvalidArgumentException If the property definition is not an instance of ModelPropertyDefinition.
7789
*/
7890
public static function fromPropertyDefinitions( array $propertyDefinitions, array $initialValues = [] ): ModelPropertyCollection {
7991
$properties = [];
8092

8193
foreach ( $propertyDefinitions as $key => $definition ) {
8294
if ( ! is_string( $key ) ) {
83-
throw new \InvalidArgumentException( 'Property key must be a string.' );
95+
throw new InvalidArgumentException( 'Property key must be a string.' );
8496
}
8597

8698
if ( ! $definition instanceof ModelPropertyDefinition ) {
87-
throw new \InvalidArgumentException( 'Property definition must be an instance of ModelPropertyDefinition.' );
99+
throw new InvalidArgumentException( 'Property definition must be an instance of ModelPropertyDefinition.' );
88100
}
89101

90102
if ( isset( $initialValues[$key] ) ) {
@@ -102,8 +114,8 @@ public static function fromPropertyDefinitions( array $propertyDefinitions, arra
102114
*
103115
* @since 2.0.0
104116
*/
105-
public function getIterator(): \Traversable {
106-
return new \ArrayIterator($this->properties);
117+
public function getIterator(): Traversable {
118+
return new ArrayIterator($this->properties);
107119
}
108120

109121
/**
@@ -137,10 +149,12 @@ public function getDirtyValues(): array {
137149
* Get a property by key. If the property does not exist, throw an exception.
138150
*
139151
* @since 2.0.0
152+
*
153+
* @throws InvalidArgumentException If the property does not exist.
140154
*/
141155
public function getOrFail( string $key ): ModelProperty {
142156
if ( ! $this->has( $key ) ) {
143-
throw new \InvalidArgumentException( 'Property ' . $key . ' does not exist.' );
157+
throw new InvalidArgumentException( 'Property ' . $key . ' does not exist.' );
144158
}
145159

146160
return $this->properties[$key];
@@ -265,17 +279,24 @@ public function revertProperty( string $key ): void {
265279
* Set the values of the properties.
266280
*
267281
* @since 2.0.0
282+
*
283+
* @throws InvalidArgumentException If the property does not exist.
268284
*/
269285
public function setValues( array $values ) {
270286
foreach ( $values as $key => $value ) {
271287
if ( ! $this->has( $key ) ) {
272-
throw new \InvalidArgumentException( 'Property ' . $key . ' does not exist.' );
288+
throw new InvalidArgumentException( 'Property ' . $key . ' does not exist.' );
273289
}
274290

275291
$this->properties[$key]->setValue( $value );
276292
}
277293
}
278294

295+
/**
296+
* Tap the properties.
297+
*
298+
* @since 2.0.0
299+
*/
279300
public function tap( callable $callback ): self {
280301
foreach ( $this->properties as $property ) {
281302
$callback( $property );

src/Models/ModelPropertyDefinition.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ public function requiredOnSave(): self {
263263
* Whether the property supports the given type.
264264
*/
265265
public function supportsType( string $type ): bool {
266-
return in_array( $type, $this->type );
266+
return in_array( $type, $this->type, true );
267267
}
268268

269269
/**

0 commit comments

Comments
 (0)