Skip to content

Commit af298fc

Browse files
authored
Merge pull request #43 from stellarwp/feat/v3-strict-column-definitions
feat: Introduce v3 strict column definitions and enhanced type safety
2 parents b80c02c + c8c6635 commit af298fc

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+5925
-1161
lines changed

CHANGELOG.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@
22

33
All notable changes to this project will be documented in this file. This project adhere to the [Semantic Versioning](http://semver.org/) standard.
44

5-
## [unreleased] Unreleased
5+
## [3.0.0] 2025-09-24
6+
7+
* Feature - Introduces stricter column and indexes definitions. This is NOT a backwards compatible change. Read the migration guide in docs/migrating-from-v2-to-v3.md.
8+
9+
[3.0.0]: https://github.com/stellarwp/schema/releases/tag/3.0.0
610

711
## [2.0.1] 2025-07-18
812

@@ -16,7 +20,6 @@ Feature - Bump di52 to 4.0.1 and all other deps.
1620

1721
* Tweak - Add @throws tags from the [stellarwp/db](https://github.com/stellarwp/db) library and better generics.
1822

19-
2023
## [1.1.8] 2025-01-10
2124

2225
* Feature - Introduce truncate method which does what the empty_table method was doing. Update empty_table to actually empty the table instead of truncating it.

docs/migrating-from-v2-to-v3.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Migrating from V2 to V3
2+
3+
## Overview
4+
5+
Version 3 introduces several important changes:
6+
7+
- Stricter column and indexes definitions
8+
- Enhanced query methods available through extending `StellarWP\Schema\Tables\Contracts\Table`
9+
10+
## Migration Steps
11+
12+
### 1. Update Method Visibility
13+
14+
For classes extending `StellarWP\Schema\Tables\Contracts\Table`:
15+
16+
- Convert the `get_definition` method from `protected` to `public`
17+
18+
If in your implementation you chose to directly implement the renamed interface `StellarWP\Schema\Tables\Contracts\Schema_Interface`, you will need to implement the new interface `StellarWP\Schema\Tables\Contracts\Table_Interface` instead.
19+
20+
We strongly recommend extending the provided abstract instead.
21+
22+
### 2. Implement Schema History
23+
24+
In your table class:
25+
26+
- Add the static method `get_schema_history`
27+
- Optionally keep or remove the `get_definition` method
28+
29+
### 3. Define Schema History
30+
31+
The `get_schema_history` method must:
32+
33+
- Return an array of callables
34+
- Each callable should return a `StellarWP\Schema\Tables\Contracts\Table_Schema_Interface` object
35+
- Include at least one entry for your current schema version

phpstan.neon.dist

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ parameters:
2020
level: 5
2121
inferPrivatePropertyTypeFromConstructor: true
2222
reportUnmatchedIgnoredErrors: false
23-
checkGenericClassInNonGenericObjectType: false
2423

2524
# Paths to be analyzed.
2625
paths:

src/Schema/Builder.php

Lines changed: 3 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,8 @@
33
namespace StellarWP\Schema;
44

55
use StellarWP\Schema\Config;
6-
use StellarWP\Schema\Fields;
7-
use StellarWP\Schema\Fields\Contracts\Schema_Interface as Field_Schema_Interface;
86
use StellarWP\Schema\Tables;
9-
use StellarWP\Schema\Tables\Contracts\Schema_Interface as Table_Schema_Interface;
7+
use StellarWP\Schema\Tables\Contracts\Table_Interface as Table_Schema_Interface;
108
use StellarWP\Schema\Tables\Filters\Group_FilterIterator;
119
use WP_CLI;
1210

@@ -37,7 +35,7 @@ public function __construct( $db = null, $container = null ) {
3735
}
3836

3937
/**
40-
* Whether all the custom tables exist or not. Does not check custom fields.
38+
* Whether all the custom tables exist or not.
4139
*
4240
* Note: the method will return `false` if even one table is missing.
4341
*
@@ -47,7 +45,7 @@ public function __construct( $db = null, $container = null ) {
4745
*
4846
* @param string|null $group An optional group name to restrict the check to.
4947
*
50-
* @return bool Whether all custom tables exist or not. Does not check custom fields.
48+
* @return bool Whether all custom tables exist or not.
5149
*/
5250
public function all_tables_exist( $group = null ) {
5351
$table_schemas = $this->get_registered_table_schemas();
@@ -64,7 +62,6 @@ public function all_tables_exist( $group = null ) {
6462
$result = $this->db::get_col( 'SHOW TABLES' );
6563
foreach ( $table_schemas as $table_schema ) {
6664
if ( ! in_array( $table_schema::table_name(), $result, true ) ) {
67-
6865
return false;
6966
}
7067
}
@@ -108,35 +105,6 @@ public function down() {
108105
* @since 1.0.0
109106
*/
110107
do_action( 'stellarwp_post_drop_tables' );
111-
112-
/**
113-
* Runs before the custom fields are dropped.
114-
*
115-
* @since 1.0.0
116-
*/
117-
do_action( 'stellarwp_pre_drop_fields' );
118-
119-
$field_schemas = $this->get_registered_field_schemas();
120-
121-
/**
122-
* Filters the fields to be dropped.
123-
*
124-
* @since 1.0.0
125-
*
126-
* @param \Iterator $field_classes A list of Field_Schema_Interface objects that will have their fields dropped.
127-
*/
128-
$field_schemas = apply_filters( 'stellarwp_fields_to_drop', $field_schemas );
129-
130-
foreach ( $field_schemas as $field_schema ) {
131-
$field_schema->drop();
132-
}
133-
134-
/**
135-
* Runs after the custom tables have been dropped by The Events Calendar.
136-
*
137-
* @since 1.0.0
138-
*/
139-
do_action( 'stellarwp_post_drop_fields' );
140108
}
141109

142110
/**
@@ -153,17 +121,6 @@ public function empty_custom_tables() {
153121
}
154122
}
155123

156-
/**
157-
* Get the registered field handlers.
158-
*
159-
* @since 1.0.0
160-
*
161-
* @return Fields\Collection
162-
*/
163-
public function get_registered_field_schemas(): Fields\Collection {
164-
return $this->container->get( Fields\Collection::class );
165-
}
166-
167124
/**
168125
* Get the md5 hash of all the registered schemas classes with their versions.
169126
*
Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
<?php
2+
/**
3+
* Abstract collection.
4+
*
5+
* @since 3.0.0
6+
*
7+
* @package StellarWP\Schema\Collections
8+
*/
9+
10+
declare( strict_types=1 );
11+
12+
namespace StellarWP\Schema\Collections;
13+
14+
use ArrayAccess;
15+
use Countable;
16+
use Iterator;
17+
use JsonSerializable;
18+
use ReturnTypeWillChange;
19+
20+
/**
21+
* Abstract collection.
22+
*
23+
* @since 3.0.0
24+
*
25+
* @package StellarWP\Schema\Collections
26+
*/
27+
abstract class Collection implements ArrayAccess, Iterator, Countable, JsonSerializable {
28+
/**
29+
* Collection of items.
30+
*
31+
* @since 3.0.0
32+
*
33+
* @var array
34+
*/
35+
protected array $resources = [];
36+
37+
/**
38+
* Constructor.
39+
*
40+
* @since 3.0.0
41+
*
42+
* @param array $resources An array of items.
43+
*/
44+
final public function __construct( array $resources = [] ) {
45+
foreach ( $resources as $offset => $value ) {
46+
$this->set( (string) $offset, $value );
47+
}
48+
}
49+
50+
/**
51+
* Sets a value in the collection.
52+
*
53+
* @since 3.0.0
54+
*
55+
* @param string $offset The offset to set.
56+
* @param mixed $value The value to set.
57+
*/
58+
protected function set( string $offset, $value ): void {
59+
$this->resources[ $offset ] = $value;
60+
}
61+
62+
/**
63+
* @inheritDoc
64+
*/
65+
#[ReturnTypeWillChange]
66+
public function current() {
67+
return current( $this->resources );
68+
}
69+
70+
/**
71+
* @inheritDoc
72+
*/
73+
public function key(): ?string {
74+
return (string) key( $this->resources );
75+
}
76+
77+
/**
78+
* @inheritDoc
79+
*/
80+
public function next(): void {
81+
next( $this->resources );
82+
}
83+
84+
/**
85+
* @inheritDoc
86+
*
87+
* @param string $offset The offset to check.
88+
*
89+
* @return bool
90+
*/
91+
public function offsetExists( $offset ): bool {
92+
return array_key_exists( $offset, $this->resources );
93+
}
94+
95+
/**
96+
* @inheritDoc
97+
*
98+
* @param string $offset The offset to get.
99+
*
100+
* @return ?mixed
101+
*/
102+
#[ReturnTypeWillChange]
103+
public function offsetGet( $offset ) {
104+
return $this->resources[ $offset ] ?? null;
105+
}
106+
107+
/**
108+
* @inheritDoc
109+
*
110+
* @param string $offset The offset to set.
111+
* @param mixed $value The value to set.
112+
*/
113+
public function offsetSet( $offset, $value ): void {
114+
if ( ! $offset ) {
115+
$offset = (string) count( $this->resources );
116+
}
117+
$this->set( $offset, $value );
118+
}
119+
120+
/**
121+
* @inheritDoc
122+
*
123+
* @param string $offset The offset to unset.
124+
*/
125+
public function offsetUnset( $offset ): void {
126+
unset( $this->resources[ $offset ] );
127+
}
128+
129+
/**
130+
* @inheritDoc
131+
*/
132+
public function rewind(): void {
133+
reset( $this->resources );
134+
}
135+
136+
/**
137+
* @inheritDoc
138+
*/
139+
public function valid(): bool {
140+
return key( $this->resources ) !== null;
141+
}
142+
143+
/**
144+
* @inheritDoc
145+
*/
146+
public function count(): int {
147+
return count( $this->resources );
148+
}
149+
150+
/**
151+
* Returns the collection as an array.
152+
*
153+
* @since 3.0.0
154+
*
155+
* @return array
156+
*/
157+
public function jsonSerialize(): array {
158+
return $this->resources;
159+
}
160+
161+
/**
162+
* Maps the collection to an array.
163+
*
164+
* @since 3.0.0
165+
*
166+
* @param callable $callback The callback to map the collection to an array.
167+
*
168+
* @return self
169+
*/
170+
public function map( callable $callback ): self {
171+
return new static( array_map( $callback, $this->resources ) );
172+
}
173+
174+
/**
175+
* Filters the collection.
176+
*
177+
* @since 3.0.0
178+
*
179+
* @param callable $callback The callback to filter the collection.
180+
*
181+
* @return self
182+
*/
183+
public function filter( callable $callback ): self {
184+
return new static( array_filter( $this->resources, $callback ) );
185+
}
186+
187+
/**
188+
* Gets a resource from the collection.
189+
*
190+
* @since 3.0.0
191+
*
192+
* @param string $key The key to get.
193+
*
194+
* @return ?mixed
195+
*/
196+
#[ReturnTypeWillChange]
197+
public function get( string $key ) {
198+
return $this->offsetGet( $key );
199+
}
200+
}

0 commit comments

Comments
 (0)