Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
e7616e7
Introduction of stricter column definitions
dpanta94 Sep 18, 2025
dfa6c4f
Added indexes
dpanta94 Sep 19, 2025
3465913
Introduced Table_Schema
dpanta94 Sep 19, 2025
0a33fb2
Add dynamic uid column name
dpanta94 Sep 19, 2025
81acd04
Introducing breaking changes
dpanta94 Sep 19, 2025
c69f0e3
Fix and cleanup existing test suite
dpanta94 Sep 20, 2025
827c2ed
Fixing issues after tests
dpanta94 Sep 20, 2025
fe450e1
More fixes after testing
dpanta94 Sep 20, 2025
d50072c
Adding test coverage
dpanta94 Sep 20, 2025
ac7cf73
Added test coverage
dpanta94 Sep 21, 2025
f223e05
Fix static analysis
dpanta94 Sep 21, 2025
e4d576e
Split casting on its own method
dpanta94 Sep 22, 2025
d984aee
type safe casting
dpanta94 Sep 22, 2025
9cbaace
another type safe fix
dpanta94 Sep 22, 2025
5e1d399
JSON encode JSON columns before storage
dpanta94 Sep 22, 2025
22ec5d2
Fixing return type of static upsert
dpanta94 Sep 22, 2025
6ba26ed
Fix test breaking
dpanta94 Sep 22, 2025
bf2e833
Updated to call and cache current schema during runtime
dpanta94 Sep 22, 2025
d483193
Fixed definitions in tests
dpanta94 Sep 22, 2025
100e41e
Fix phpstan
dpanta94 Sep 22, 2025
e04a0a6
removed $name from the ID column
dpanta94 Sep 22, 2025
807ee83
removed pre-filled name vars
dpanta94 Sep 22, 2025
4e6a586
Amend CR comments
dpanta94 Sep 23, 2025
33b5413
added an import
dpanta94 Sep 23, 2025
445daed
Fix a bug during insert statements
dpanta94 Sep 23, 2025
924e9ab
Fix static analysis
dpanta94 Sep 23, 2025
481245a
added JSON type for query preparation
dpanta94 Sep 23, 2025
dbb7f47
Fix default column type to decimal - better representation of php float
dpanta94 Sep 23, 2025
08cc2c8
Added Ref_Id column
dpanta94 Sep 23, 2025
6cab604
Updated class's static methods docs
dpanta94 Sep 24, 2025
c0d4ac2
replaced TBDs
dpanta94 Sep 24, 2025
cf10ae7
Added changelog
dpanta94 Sep 24, 2025
d887ed3
added default implementation of transform method
dpanta94 Sep 24, 2025
629521b
added migration guide
dpanta94 Sep 24, 2025
c8c6635
Fix phpstan
dpanta94 Sep 24, 2025
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
7 changes: 5 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@

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

## [unreleased] Unreleased
## [3.0.0] 2025-09-24

* 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.

[3.0.0]: https://github.com/stellarwp/schema/releases/tag/3.0.0

## [2.0.1] 2025-07-18

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

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


## [1.1.8] 2025-01-10

* 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.
Expand Down
35 changes: 35 additions & 0 deletions docs/migrating-from-v2-to-v3.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Migrating from V2 to V3

## Overview

Version 3 introduces several important changes:

- Stricter column and indexes definitions
- Enhanced query methods available through extending `StellarWP\Schema\Tables\Contracts\Table`

## Migration Steps

### 1. Update Method Visibility

For classes extending `StellarWP\Schema\Tables\Contracts\Table`:

- Convert the `get_definition` method from `protected` to `public`

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.

We strongly recommend extending the provided abstract instead.

### 2. Implement Schema History

In your table class:

- Add the static method `get_schema_history`
- Optionally keep or remove the `get_definition` method

### 3. Define Schema History

The `get_schema_history` method must:

- Return an array of callables
- Each callable should return a `StellarWP\Schema\Tables\Contracts\Table_Schema_Interface` object
- Include at least one entry for your current schema version
1 change: 0 additions & 1 deletion phpstan.neon.dist
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ parameters:
level: 5
inferPrivatePropertyTypeFromConstructor: true
reportUnmatchedIgnoredErrors: false
checkGenericClassInNonGenericObjectType: false

# Paths to be analyzed.
paths:
Expand Down
49 changes: 3 additions & 46 deletions src/Schema/Builder.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@
namespace StellarWP\Schema;

use StellarWP\Schema\Config;
use StellarWP\Schema\Fields;
use StellarWP\Schema\Fields\Contracts\Schema_Interface as Field_Schema_Interface;
use StellarWP\Schema\Tables;
use StellarWP\Schema\Tables\Contracts\Schema_Interface as Table_Schema_Interface;
use StellarWP\Schema\Tables\Contracts\Table_Interface as Table_Schema_Interface;
use StellarWP\Schema\Tables\Filters\Group_FilterIterator;
use WP_CLI;

Expand Down Expand Up @@ -37,7 +35,7 @@ public function __construct( $db = null, $container = null ) {
}

/**
* Whether all the custom tables exist or not. Does not check custom fields.
* Whether all the custom tables exist or not.
*
* Note: the method will return `false` if even one table is missing.
*
Expand All @@ -47,7 +45,7 @@ public function __construct( $db = null, $container = null ) {
*
* @param string|null $group An optional group name to restrict the check to.
*
* @return bool Whether all custom tables exist or not. Does not check custom fields.
* @return bool Whether all custom tables exist or not.
*/
public function all_tables_exist( $group = null ) {
$table_schemas = $this->get_registered_table_schemas();
Expand All @@ -64,7 +62,6 @@ public function all_tables_exist( $group = null ) {
$result = $this->db::get_col( 'SHOW TABLES' );
foreach ( $table_schemas as $table_schema ) {
if ( ! in_array( $table_schema::table_name(), $result, true ) ) {

return false;
}
}
Expand Down Expand Up @@ -108,35 +105,6 @@ public function down() {
* @since 1.0.0
*/
do_action( 'stellarwp_post_drop_tables' );

/**
* Runs before the custom fields are dropped.
*
* @since 1.0.0
*/
do_action( 'stellarwp_pre_drop_fields' );

$field_schemas = $this->get_registered_field_schemas();

/**
* Filters the fields to be dropped.
*
* @since 1.0.0
*
* @param \Iterator $field_classes A list of Field_Schema_Interface objects that will have their fields dropped.
*/
$field_schemas = apply_filters( 'stellarwp_fields_to_drop', $field_schemas );

foreach ( $field_schemas as $field_schema ) {
$field_schema->drop();
}

/**
* Runs after the custom tables have been dropped by The Events Calendar.
*
* @since 1.0.0
*/
do_action( 'stellarwp_post_drop_fields' );
}

/**
Expand All @@ -153,17 +121,6 @@ public function empty_custom_tables() {
}
}

/**
* Get the registered field handlers.
*
* @since 1.0.0
*
* @return Fields\Collection
*/
public function get_registered_field_schemas(): Fields\Collection {
return $this->container->get( Fields\Collection::class );
}

/**
* Get the md5 hash of all the registered schemas classes with their versions.
*
Expand Down
200 changes: 200 additions & 0 deletions src/Schema/Collections/Collection.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
<?php
/**
* Abstract collection.
*
* @since 3.0.0
*
* @package StellarWP\Schema\Collections
*/

declare( strict_types=1 );

namespace StellarWP\Schema\Collections;

use ArrayAccess;
use Countable;
use Iterator;
use JsonSerializable;
use ReturnTypeWillChange;

/**
* Abstract collection.
*
* @since 3.0.0
*
* @package StellarWP\Schema\Collections
*/
abstract class Collection implements ArrayAccess, Iterator, Countable, JsonSerializable {
/**
* Collection of items.
*
* @since 3.0.0
*
* @var array
*/
protected array $resources = [];

/**
* Constructor.
*
* @since 3.0.0
*
* @param array $resources An array of items.
*/
final public function __construct( array $resources = [] ) {
foreach ( $resources as $offset => $value ) {
$this->set( (string) $offset, $value );
}
}

/**
* Sets a value in the collection.
*
* @since 3.0.0
*
* @param string $offset The offset to set.
* @param mixed $value The value to set.
*/
protected function set( string $offset, $value ): void {
$this->resources[ $offset ] = $value;
}

/**
* @inheritDoc
*/
#[ReturnTypeWillChange]
public function current() {
return current( $this->resources );
}

/**
* @inheritDoc
*/
public function key(): ?string {
return (string) key( $this->resources );
}

/**
* @inheritDoc
*/
public function next(): void {
next( $this->resources );
}

/**
* @inheritDoc
*
* @param string $offset The offset to check.
*
* @return bool
*/
public function offsetExists( $offset ): bool {
return array_key_exists( $offset, $this->resources );
}

/**
* @inheritDoc
*
* @param string $offset The offset to get.
*
* @return ?mixed
*/
#[ReturnTypeWillChange]
public function offsetGet( $offset ) {
return $this->resources[ $offset ] ?? null;
}

/**
* @inheritDoc
*
* @param string $offset The offset to set.
* @param mixed $value The value to set.
*/
public function offsetSet( $offset, $value ): void {
if ( ! $offset ) {
$offset = (string) count( $this->resources );
}
$this->set( $offset, $value );
}

/**
* @inheritDoc
*
* @param string $offset The offset to unset.
*/
public function offsetUnset( $offset ): void {
unset( $this->resources[ $offset ] );
}

/**
* @inheritDoc
*/
public function rewind(): void {
reset( $this->resources );
}

/**
* @inheritDoc
*/
public function valid(): bool {
return key( $this->resources ) !== null;
}

/**
* @inheritDoc
*/
public function count(): int {
return count( $this->resources );
}

/**
* Returns the collection as an array.
*
* @since 3.0.0
*
* @return array
*/
public function jsonSerialize(): array {
return $this->resources;
}

/**
* Maps the collection to an array.
*
* @since 3.0.0
*
* @param callable $callback The callback to map the collection to an array.
*
* @return self
*/
public function map( callable $callback ): self {
return new static( array_map( $callback, $this->resources ) );
}

/**
* Filters the collection.
*
* @since 3.0.0
*
* @param callable $callback The callback to filter the collection.
*
* @return self
*/
public function filter( callable $callback ): self {
return new static( array_filter( $this->resources, $callback ) );
}

/**
* Gets a resource from the collection.
*
* @since 3.0.0
*
* @param string $key The key to get.
*
* @return ?mixed
*/
#[ReturnTypeWillChange]
public function get( string $key ) {
return $this->offsetGet( $key );
}
}
Loading