Skip to content

Releases: std-out/simple-data-objects

v1.11.0

Choose a tag to compare

@yuriizee yuriizee released this 15 Jul 18:16

CommaSeparatedCast — splits a delimited string into an array on
hydration and joins it back on serialization (separator and trim
are configurable; default , and true).

v1.10.0

Choose a tag to compare

@yuriizee yuriizee released this 15 Jul 16:22

UuidCast — validates RFC 4122 UUID strings on hydration and normalizes to lowercase on both hydration and serialization. Invalid input throws InvalidArgumentException.

v1.9.0

Choose a tag to compare

@yuriizee yuriizee released this 15 Jul 11:36

Added

  • LowercaseValuePipe / UppercaseValuePipe — case normalization pipes for #[Pipe]-attributed properties, e.g. emails or country/currency codes.
    Non-string values pass through untouched (same contract as TrimValuePipe).

Changed

  • Documentation site: custom VitePress theme with breadcrumb navigation.

Full Changelog: v1.8.0...v1.9.0

v1.8.0

Choose a tag to compare

@yuriizee yuriizee released this 03 Jul 12:06

Slimmer installs

📦 Changed

  • Dev-only files (tests, docs, CI config, Docker setup) are now excluded from Composer dist archives via .gitattributes export-ignore — composer require std-out/simple-data-objects downloads only what runs in production.

Full Changelog: v1.7.2...v1.8.0

v1.7.2

Choose a tag to compare

@yuriizee yuriizee released this 03 Jul 11:20

Universal from() + lazy hydration

✨ Added

  • Universal from() — one factory now accepts arrays (unchanged fast path), Eloquent models and any Arrayable, stdClass, JsonSerializable, any Traversable, JSON strings, plain objects with public properties, and same-class instances (returned as-is). All detection lives on the cold path — the hot array path executes the same opcodes as before.
  • BaseData::fromLazy() — lazy hydration built on native PHP 8.4 lazy ghosts; hydration runs on first property access. With ~10% of objects actually read: ~3× faster on cast-heavy DTOs, ~6× with nested collections.
  • Integrations docs — Plain PHP, Laravel, Symfony, Slim/PSR-7, plus an opcache.preload recipe.

⚡ Changed

  • Compiled hydrator hoisted out of collection loops (TypedDataCollection::of(), lazyCollection()): +19% on collection hydration (220k → 267k ops/s).
  • fromJson() is now an explicit alias of from().

🐛 Fixed

  • HydratorCompiler::compile() fails fast when given a non-BaseData class.

Full Changelog: v1.4.3...v1.7.2

v1.4.3

Choose a tag to compare

@yuriizee yuriizee released this 02 Jul 20:26

Full Changelog: v1.1.15...v1.4.3
feat: compile per-class hydrators/serializers, warmable cache, lazy collections

Performance refactor: from() and toArray() now execute a specialized
closure generated per data class (plain properties become inline array
reads; casts, enums, nested DTOs, collections, and pipes delegate to the
existing runtime via captured metadata — behavior is unchanged).
Steady-state throughput: hydration ~2.6x, serialization ~2.2x over the
interpreted path.

  • Add HydratorCompiler and SerializerCompiler (eval once per class per
    process, in-memory registries, flush hooks); remove the interpreted
    Hydrator; extract ValueNormalizer for compiled serializers
  • Precompute ParameterMeta::$isPlain so hot paths skip ValueCaster;
    inline the is_array() input check; use it in with() overrides too
  • Cache format v2: .meta.php files now carry the compiled hydrator and
    serializer alongside the metadata — a warmed FPM worker pays neither
    reflection nor eval (opcache serves the whole file); legacy v1 files
    still load
  • Add vendor/bin/sdo-warm + Support\CacheWarmer: scans sources (PSR-4
    dirs from composer.json by default) for concrete BaseData subclasses
    and pre-builds the cache on deploy; fails fast on invalid DTO
    definitions, reports non-exportable classes as skipped
  • Add BaseData::lazyCollection() for streaming large iterables with a
    flat memory profile (~0.26 MB peak for 50k rows vs ~13 MB materialized)
  • Docs: compiled hot path, pre-warming guide, streaming collections,
    README performance section

245 tests, 100% coverage.

v1.1.15

Choose a tag to compare

@yuriizee yuriizee released this 02 Jul 12:46

Hardened enums & encryption coverage

✨ Added

  • Test coverage for EncryptedCast (XSalsa20-Poly1305) and expanded enum-handling scenarios.

⚡ Changed

  • Improved enum handling and metadata caching.
  • CI: dynamic coverage badge, GitHub Actions bumped to latest versions.

Full Changelog: v1.0.0...v1.1.15

v1.0.0

Choose a tag to compare

@yuriizee yuriizee released this 01 Jul 09:20

What's New

🔄 Pipes

Transform incoming values before hydration using the new #[Pipe] attribute. Apply pipes per-property or globally via class-level #[Pipe]:

#[Pipe(TrimStringsPipe::class, NullifyEmptyStringsPipe::class)]
class ContactData extends BaseData
{
public function __construct(
#[Pipe(UpperCasePipe::class)]
public readonly string $name,
public readonly ?string $comment,
) {}
}

  • Built-in pipes: TrimStringsPipe, NullifyEmptyStringsPipe, TrimValuePipe, NullifyEmptyStringValuePipe.
  • Implement ValuePipe to create custom pipes.

🔀 Key Transformation

Automatically remap camelCase input keys to snake_case, kebab-case or STUDLY_CASE using #[TransformKeys]:

#[TransformKeys(TransformKeys::SNAKE_CASE)]
class UserData extends BaseData { ... }


💾 File-based Metadata Cache

Cache resolved class metadata to disk for near-zero overhead in production:

MetadataRegistry::setStoragePath(storage_path('framework/sdo'));

  • Supports atomic writes and __set_state-based serialization.
  • Skips non-exportable classes gracefully.

🛠️ New BaseData & Collection Methods

Method Description
tryFrom(mixed $data) Returns null instead of throwing on failure
with(...$overrides) Returns a new instance with overridden fields
equals(self $other) Compares two instances by value
diff(self $other) Returns array of changed fields
only(string ...$keys) Returns a subset of fields
except(string ...$keys) Returns all fields except specified
fromValidated(mixed $data) Hydrates after Laravel validation
validate(mixed $data) Runs validation without hydration

TypedDataCollection

$collection->last(); // returns last item or null


🧪 100% Test Coverage

All classes, methods, and lines are covered. Enforced in CI via pcov.

v0.6.7

Choose a tag to compare

@yuriizee yuriizee released this 27 Jun 06:50

Full Changelog: v0.6.3...v0.6.7

v0.6.3

Choose a tag to compare

@yuriizee yuriizee released this 27 Jun 05:24

Full Changelog: v0.3.0...v0.6.3