PHPackages                             byjoby/destructr - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Database &amp; ORM](/categories/database)
4. /
5. byjoby/destructr

ActiveLibrary[Database &amp; ORM](/categories/database)

byjoby/destructr
================

A library for storing a mix of structured and unstructured data in relational databases

v1.7.0(3y ago)01.9kMITPHPPHP &gt;=7.1CI failing

Since Sep 14Pushed 2y ago1 watchersCompare

[ Source](https://github.com/joby-lol/destructr)[ Packagist](https://packagist.org/packages/byjoby/destructr)[ RSS](/packages/byjoby-destructr/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (10)Dependencies (3)Versions (25)Used By (0)

Destructr
=========

[](#destructr)

[![PHPUnit Tests](https://github.com/jobyone/destructr/actions/workflows/test.yml/badge.svg)](https://github.com/jobyone/destructr/actions/workflows/test.yml)

Destructr is a specialized ORM that allows a seamless mix of structured, relational data with unstructured JSON data.

Getting started
---------------

[](#getting-started)

The purpose of Destructr is to allow many "types" of objects to be stored in a single table. Every Destructr Data Object (DSO) simply contains an array of data that will be saved into the database as JSON. Array access is also flattened, using dots as delimiters, so rather than reading `$dso["foo"]["bar"]` you access that data via `$dso["foo.bar"]`. This is for two reasons. It sidesteps the issue of updating nested array values by reference, and it creates an unambiguous way of locating a node of the unstructured data with a string, which mirrors how we can write SQL queries to reference them.

If this sounds like an insanely slow idea, that's because it is. Luckily MySQL and MariaDB have mechanisms we can take advantage of to make generated columns from any part of the unstructured data, so that pieces of it can be pulled out into their own virtual columns for indexing and faster searching/sorting.

### Database driver and factory

[](#database-driver-and-factory)

In order to read/write objects from a database table, you'll need to configure a Driver and Factory class.

```
// DriverFactory::factory() has the same arguments as PDO::__construct
// You can also construct a driver directly, from a class in Drivers,
// but for common databases DriverFactory::factory should pick the right class
$driver = \Destructr\DriverFactory::factory(
  'mysql:host=127.0.0.1',
  'username',
  'password'
);
// Driver is then used to construct a Factory
$factory = new \Destructr\Factory(
  $driver,      //driver is used to manage connection and generate queries
  'dso_objects' //all of a Factory's data is stored in a single table
);
```

### Creating a new record

[](#creating-a-new-record)

Next, you can use the factory to create a new record object.

```
// by default all objects are the DSO class, but factories can be made to use
// other classes depending on what data objects are instantiated with
$obj = $factory->create();

// returns boolean indicating whether insertion succeeded
// insert() must be called before update() will work
$obj->insert();

// set a new value and call update() to save changes into database. update()
// will return true without doing anything if no changes have been made.
$obj['foo.bar'] = 'some value';
$obj->update();

// deleting an object will by default just set dso.deleted to the current time
// objects with a non-null dso.deleted are excluded from queries by default
// delete() calls update() inside it, so its effect is immediate
$obj->delete();

// objects that were deleted via default delete() are recoverable via undelete()
// undelete() also calls update() for you
$obj->undelete();

// objects can be actually removed from the table by calling delete(true)
$obj->delete(true);
```

### Searching

[](#searching)

Factories provide an interface for creating `Search` objects, which allow you to enter in various SQL clauses in a structured and abstract fashion.

```
// get a new search object from the factory
$search = $factory->search();

// Search::where() takes SQL for the WHERE clause of a query
// ${path} syntax is used to reference data within objects, and
// works everywhere in searches
$search->where('${dso.date.modified} > :time');

// Search::order() takes SQL to go inside an ORDER BY clause
// in the final query.
$search->order('${dso.date.modified} desc');

// Search limit/offset methods can be used for pagination
// there is also a paginate() method for more conveniently
// paginating results
$search->paginate(20,1);

// Search::execute() returns an array of the resulting objects
$results = $search->execute();
```

Requirements
------------

[](#requirements)

This system relies **heavily** on the JSON features of the underlying database. This means it cannot possibly run without a database that supports JSON features. Basically if a database doesn't have JSON functions it's probably impossible for Destructr to ever work with it.

At the moment there is pretty decent support for:

- MySQL &gt;=5.7.8
- MariaDB &gt;=10.2.7
- SQLite 3 (with some caveats)

In practice this means Destructr will **never** be able to run on less than the following versions of the following popular databases:

- MySQL &gt;=5.7.8
- MariaDB &gt;=10.2.7
- PostgreSQL &gt;=9.3
- SQL Server &gt;=2016

Theoretically Destructr is also an excellent fit for NoSQL databases. If I ever find myself needing it there's a good chance it's possible to write drivers for running it on something like MongoDB as well. It might even be kind of easy.

### SQLite caveats

[](#sqlite-caveats)

MySQL and MariaDB drivers set virtual columns to be generated automatically using their native JSON functions. SQLite doesn't have native JSON (in most environments, at least), so Destructr itself manually updates virtual columns whenever objects are inserted or updated. In practice this won't matter *if* you are doing all your insertion and updating via Destructr. If you're doing updates to your database via any other method, however, you need to be aware of this, and manually update the virtual column values.

###  Health Score

30

—

LowBetter than 64% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity15

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity66

Established project with proven stability

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~62 days

Recently: every ~1 days

Total

23

Last Release

1430d ago

Major Versions

v1.7.0 → v2.x-dev2022-06-08

### Community

Maintainers

![](https://www.gravatar.com/avatar/f4e606aa41ebfd7d82c365c6dc4ec158fb1b0bfff5f8dcbfad4ab53e3092e6a6?d=identicon)[jobyone](/maintainers/jobyone)

---

Top Contributors

[![joby-lol](https://avatars.githubusercontent.com/u/856610?v=4)](https://github.com/joby-lol "joby-lol (66 commits)")

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/byjoby-destructr/health.svg)

```
[![Health](https://phpackages.com/badges/byjoby-destructr/health.svg)](https://phpackages.com/packages/byjoby-destructr)
```

###  Alternatives

[doctrine/orm

Object-Relational-Mapper for PHP

10.2k285.3M6.2k](/packages/doctrine-orm)[jdorn/sql-formatter

a PHP SQL highlighting library

3.9k115.1M102](/packages/jdorn-sql-formatter)[illuminate/database

The Illuminate Database package.

2.8k52.4M9.3k](/packages/illuminate-database)[mongodb/mongodb

MongoDB driver library

1.6k64.0M542](/packages/mongodb-mongodb)[ramsey/uuid-doctrine

Use ramsey/uuid as a Doctrine field type.

90340.3M209](/packages/ramsey-uuid-doctrine)[reliese/laravel

Reliese Components for Laravel Framework code generation.

1.7k3.4M16](/packages/reliese-laravel)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
