Repository files navigation

ronanchilvers/orm

Actions StatusScrutinizer Code Quality

orm is a small and simple database layer implementing the active record pattern. Its aim is to be simple, fast and useful. It relies on the [clancats hydrahon] query builder for database query access.

Overview

Things it does

  • PDO underneath so should work with any PDO compatible database
  • Provides a full query builder interface using clancats/hydrahon
  • Supports full save, destroy, update, insert functionality through the active record implementation
  • Supports model finder objects to help avoid 'fat model' syndrome
  • Supports fine grained model hooks for precise control of model lifecycle data
  • Supports model validation using respect/validation
  • Simple relationship handling - belongsTo, hasMany, hasOne
  • Configurable data type conversion for model properties

Things it does NOT do

  • Migrations - you can use whatever you like to manage your schema. We recommend phinx
  • Multiple database connections - currently orm only supports a single PDO connection.

Installation

You'll need at least PHP7.0 to use the library. The recommended way to install is using composer:

composer install ronanchilvers/orm

Configuring the database

Since orm uses PDO, it's up to you how you create and instantiate your PDO object. This will probably be in your bootstrap somewhere. Once your PDO object is available you will need to give it to orm. Here's an example:

$pdo = newPDO('sqlite::memory:');
Ronanchilvers\Orm\Orm::setConnection($pdo);

Clearly you will almost certainly not be using a :memory: DSN in practice. However you create your PDO object, the crucial point here is that you call Orm::setConnection to provide orm with your connection object.

Basic usage

orm doesn't make any pre-judgments about your database schema. When building models from a database it assumes it maps columns to properties and when saving it assumes that any property has a corresponding database table column. Its up to you to make sure the data makes sense.

Here we assume that we have a database table that looks like the following. We're using MySQL / MariaDB syntax here but whatever PDO supports should be fine.

CREATETABLE `books` (
`book_id`int(11) unsigned NOT NULL AUTO_INCREMENT,
`book_author`int(11) NOT NULL,
`book_name`varchar(1024) NOT NULL DEFAULT '',
`book_created` datetime DEFAULT CURRENT_TIMESTAMP,
`book_updated` datetime DEFAULT NULL,
PRIMARY KEY (`book_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

Defining a model

First create your model class. It should extend the Ronanchilvers\Orm\Model class. As with many active record implementations we assume here that the table has a plural name (books) and its corresponding model class will have a singular name (book).

class Book extends Model
{}

If your columns have no column prefix, that's all you need to do. The table name will be inferred from the class name. If however, like the example above, you have column prefixes then you can tweak your model to suit.

class Book extends Model
{
staticprotected$columnPrefix = 'book';
}

Similarly if your table doesn't map to the model name you can specufy that too.

class Book extends Model
{
staticprotected$table = 'my_books_table';
staticprotected$columnPrefix = 'book';
}

Now you're ready to use the model.

Finding models

orm supports a query builder interface provided by clancats/hydrahon. In order to retrieve models from the database, first obtain a finder object.

$finder = Orm::finder(Book::class);

Then you can use the finder object to retrieve models.

$books = $finder->all();

There are several standard finder methods you can use:

// Get all the records in one go$books = $finder->all();
// Get the third page of models when there are 30 records per page// (10 per page is the default)$books = $finder->all(3, 30);
// Get a specific model by its primary key, here assumed to be numeric$book = $finder->one(23);

You can use the full query builder to gain more control over the query:

// Get all the books for author id 20$books = $finder->select()->where('book_author', 20);
// Get all books added since last week - here we're using the excellent Carbon wrapper// for DateTime$recentBooks = $finder->select()->where('book_created', '>', Carbon::now()->subWeek());

You can read more about the capabilities of the query builder over at the clancats/hydrahon site.

If you want complete control over the SQL that is executed you can do:

$sql = "SELECT *FROM books LEFT JOIN authors ON author_id = book_authorWHERE author_name LIKE :name AND author_created < :created";
$params = [
'name' => 'Fred%',
'created' => Carbon::now()->subYear()->format('Y-m-d H:i:s'),
];
$books = $finder->query($sql, $params);

Custom Finder Classes

By default Orm::finder will give you back a vanilla Ronanchilvers\Orm\Finder object tied to given model class. However you can also override the finder class for a given model by setting the $finder static property on your model. This can be very useful if you want to add custom find methods (for example).

Let's imagine you've created a BookFinder class:

class BookFinder extends Finder
{
publicfunctionforAuthorId(int$id): array
{
return$this
->select()
->where(Book::prefix('author'), $id)
->execute();
}
}

You can see that we've created a subclass of the default finder and we've added a forAuthorId method which returns an array of books for a given author id.

Then we tell the model about our new finder class:

class Book extends Model
{
staticprotected$finder = BookFinder::class;
}

and then finally you're readdy to use it:

// $finder will be an instance of BookFinder here$finder = Orm::finder(Book::class);
$authors = $finder->forAuthorId(2);

Persistence

Saving a model back to the database is simply a matter of calling the save method.

$finder = Orm::finder(Book::class);
$book = $finder->one(23);
$book->save();

Similarly destroying a model is also simple:

$book->delete();

Accessing model data

As in any active record implementation, database table columns are expressed as properties on the model instance. Consequently data can be accessed by accessing those properties.

$finder = Orm::finder(Book::class);
$book = $finder->one(72);
echo$book->name;

About

Simple database ORM implementation

Topics

Resources

Stars

0 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

ronanchilvers/orm

Actions StatusScrutinizer Code Quality

orm is a small and simple database layer implementing the active record pattern. Its aim is to be simple, fast and useful. It relies on the [clancats hydrahon] query builder for database query access.

Overview

Things it does

  • PDO underneath so should work with any PDO compatible database
  • Provides a full query builder interface using clancats/hydrahon
  • Supports full save, destroy, update, insert functionality through the active record implementation
  • Supports model finder objects to help avoid 'fat model' syndrome
  • Supports fine grained model hooks for precise control of model lifecycle data
  • Supports model validation using respect/validation
  • Simple relationship handling - belongsTo, hasMany, hasOne
  • Configurable data type conversion for model properties

Things it does NOT do

  • Migrations - you can use whatever you like to manage your schema. We recommend phinx
  • Multiple database connections - currently orm only supports a single PDO connection.

Installation

You'll need at least PHP7.0 to use the library. The recommended way to install is using composer:

composer install ronanchilvers/orm

Configuring the database

Since orm uses PDO, it's up to you how you create and instantiate your PDO object. This will probably be in your bootstrap somewhere. Once your PDO object is available you will need to give it to orm. Here's an example:

$pdo = newPDO('sqlite::memory:');
Ronanchilvers\Orm\Orm::setConnection($pdo);

Clearly you will almost certainly not be using a :memory: DSN in practice. However you create your PDO object, the crucial point here is that you call Orm::setConnection to provide orm with your connection object.

Basic usage

orm doesn't make any pre-judgments about your database schema. When building models from a database it assumes it maps columns to properties and when saving it assumes that any property has a corresponding database table column. Its up to you to make sure the data makes sense.

Here we assume that we have a database table that looks like the following. We're using MySQL / MariaDB syntax here but whatever PDO supports should be fine.

CREATETABLE `books` (
`book_id`int(11) unsigned NOT NULL AUTO_INCREMENT,
`book_author`int(11) NOT NULL,
`book_name`varchar(1024) NOT NULL DEFAULT '',
`book_created` datetime DEFAULT CURRENT_TIMESTAMP,
`book_updated` datetime DEFAULT NULL,
PRIMARY KEY (`book_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

Defining a model

First create your model class. It should extend the Ronanchilvers\Orm\Model class. As with many active record implementations we assume here that the table has a plural name (books) and its corresponding model class will have a singular name (book).

class Book extends Model
{}

If your columns have no column prefix, that's all you need to do. The table name will be inferred from the class name. If however, like the example above, you have column prefixes then you can tweak your model to suit.

class Book extends Model
{
staticprotected$columnPrefix = 'book';
}

Similarly if your table doesn't map to the model name you can specufy that too.

class Book extends Model
{
staticprotected$table = 'my_books_table';
staticprotected$columnPrefix = 'book';
}

Now you're ready to use the model.

Finding models

orm supports a query builder interface provided by clancats/hydrahon. In order to retrieve models from the database, first obtain a finder object.

$finder = Orm::finder(Book::class);

Then you can use the finder object to retrieve models.

$books = $finder->all();

There are several standard finder methods you can use:

// Get all the records in one go$books = $finder->all();
// Get the third page of models when there are 30 records per page// (10 per page is the default)$books = $finder->all(3, 30);
// Get a specific model by its primary key, here assumed to be numeric$book = $finder->one(23);

You can use the full query builder to gain more control over the query:

// Get all the books for author id 20$books = $finder->select()->where('book_author', 20);
// Get all books added since last week - here we're using the excellent Carbon wrapper// for DateTime$recentBooks = $finder->select()->where('book_created', '>', Carbon::now()->subWeek());

You can read more about the capabilities of the query builder over at the clancats/hydrahon site.

If you want complete control over the SQL that is executed you can do:

$sql = "SELECT *FROM books LEFT JOIN authors ON author_id = book_authorWHERE author_name LIKE :name AND author_created < :created";
$params = [
'name' => 'Fred%',
'created' => Carbon::now()->subYear()->format('Y-m-d H:i:s'),
];
$books = $finder->query($sql, $params);

Custom Finder Classes

By default Orm::finder will give you back a vanilla Ronanchilvers\Orm\Finder object tied to given model class. However you can also override the finder class for a given model by setting the $finder static property on your model. This can be very useful if you want to add custom find methods (for example).

Let's imagine you've created a BookFinder class:

class BookFinder extends Finder
{
publicfunctionforAuthorId(int$id): array
{
return$this
->select()
->where(Book::prefix('author'), $id)
->execute();
}
}

You can see that we've created a subclass of the default finder and we've added a forAuthorId method which returns an array of books for a given author id.

Then we tell the model about our new finder class:

class Book extends Model
{
staticprotected$finder = BookFinder::class;
}

and then finally you're readdy to use it:

// $finder will be an instance of BookFinder here$finder = Orm::finder(Book::class);
$authors = $finder->forAuthorId(2);

Persistence

Saving a model back to the database is simply a matter of calling the save method.

$finder = Orm::finder(Book::class);
$book = $finder->one(23);
$book->save();

Similarly destroying a model is also simple:

$book->delete();

Accessing model data

As in any active record implementation, database table columns are expressed as properties on the model instance. Consequently data can be accessed by accessing those properties.

$finder = Orm::finder(Book::class);
$book = $finder->one(72);
echo$book->name;

About

Simple database ORM implementation

Topics

Resources

Stars

0 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

ronanchilvers/orm

Actions StatusScrutinizer Code Quality

orm is a small and simple database layer implementing the active record pattern. Its aim is to be simple, fast and useful. It relies on the [clancats hydrahon] query builder for database query access.

Overview

Things it does

  • PDO underneath so should work with any PDO compatible database
  • Provides a full query builder interface using clancats/hydrahon
  • Supports full save, destroy, update, insert functionality through the active record implementation
  • Supports model finder objects to help avoid 'fat model' syndrome
  • Supports fine grained model hooks for precise control of model lifecycle data
  • Supports model validation using respect/validation
  • Simple relationship handling - belongsTo, hasMany, hasOne
  • Configurable data type conversion for model properties

Things it does NOT do

  • Migrations - you can use whatever you like to manage your schema. We recommend phinx
  • Multiple database connections - currently orm only supports a single PDO connection.

Installation

You'll need at least PHP7.0 to use the library. The recommended way to install is using composer:

composer install ronanchilvers/orm

Configuring the database

Since orm uses PDO, it's up to you how you create and instantiate your PDO object. This will probably be in your bootstrap somewhere. Once your PDO object is available you will need to give it to orm. Here's an example:

$pdo = newPDO('sqlite::memory:');
Ronanchilvers\Orm\Orm::setConnection($pdo);

Clearly you will almost certainly not be using a :memory: DSN in practice. However you create your PDO object, the crucial point here is that you call Orm::setConnection to provide orm with your connection object.

Basic usage

orm doesn't make any pre-judgments about your database schema. When building models from a database it assumes it maps columns to properties and when saving it assumes that any property has a corresponding database table column. Its up to you to make sure the data makes sense.

Here we assume that we have a database table that looks like the following. We're using MySQL / MariaDB syntax here but whatever PDO supports should be fine.

CREATETABLE `books` (
`book_id`int(11) unsigned NOT NULL AUTO_INCREMENT,
`book_author`int(11) NOT NULL,
`book_name`varchar(1024) NOT NULL DEFAULT '',
`book_created` datetime DEFAULT CURRENT_TIMESTAMP,
`book_updated` datetime DEFAULT NULL,
PRIMARY KEY (`book_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

Defining a model

First create your model class. It should extend the Ronanchilvers\Orm\Model class. As with many active record implementations we assume here that the table has a plural name (books) and its corresponding model class will have a singular name (book).

class Book extends Model
{}

If your columns have no column prefix, that's all you need to do. The table name will be inferred from the class name. If however, like the example above, you have column prefixes then you can tweak your model to suit.

class Book extends Model
{
staticprotected$columnPrefix = 'book';
}

Similarly if your table doesn't map to the model name you can specufy that too.

class Book extends Model
{
staticprotected$table = 'my_books_table';
staticprotected$columnPrefix = 'book';
}

Now you're ready to use the model.

Finding models

orm supports a query builder interface provided by clancats/hydrahon. In order to retrieve models from the database, first obtain a finder object.

$finder = Orm::finder(Book::class);

Then you can use the finder object to retrieve models.

$books = $finder->all();

There are several standard finder methods you can use:

// Get all the records in one go$books = $finder->all();
// Get the third page of models when there are 30 records per page// (10 per page is the default)$books = $finder->all(3, 30);
// Get a specific model by its primary key, here assumed to be numeric$book = $finder->one(23);

You can use the full query builder to gain more control over the query:

// Get all the books for author id 20$books = $finder->select()->where('book_author', 20);
// Get all books added since last week - here we're using the excellent Carbon wrapper// for DateTime$recentBooks = $finder->select()->where('book_created', '>', Carbon::now()->subWeek());

You can read more about the capabilities of the query builder over at the clancats/hydrahon site.

If you want complete control over the SQL that is executed you can do:

$sql = "SELECT *FROM books LEFT JOIN authors ON author_id = book_authorWHERE author_name LIKE :name AND author_created < :created";
$params = [
'name' => 'Fred%',
'created' => Carbon::now()->subYear()->format('Y-m-d H:i:s'),
];
$books = $finder->query($sql, $params);

Custom Finder Classes

By default Orm::finder will give you back a vanilla Ronanchilvers\Orm\Finder object tied to given model class. However you can also override the finder class for a given model by setting the $finder static property on your model. This can be very useful if you want to add custom find methods (for example).

Let's imagine you've created a BookFinder class:

class BookFinder extends Finder
{
publicfunctionforAuthorId(int$id): array
{
return$this
->select()
->where(Book::prefix('author'), $id)
->execute();
}
}

You can see that we've created a subclass of the default finder and we've added a forAuthorId method which returns an array of books for a given author id.

Then we tell the model about our new finder class:

class Book extends Model
{
staticprotected$finder = BookFinder::class;
}

and then finally you're readdy to use it:

// $finder will be an instance of BookFinder here$finder = Orm::finder(Book::class);
$authors = $finder->forAuthorId(2);

Persistence

Saving a model back to the database is simply a matter of calling the save method.

$finder = Orm::finder(Book::class);
$book = $finder->one(23);
$book->save();

Similarly destroying a model is also simple:

$book->delete();

Accessing model data

As in any active record implementation, database table columns are expressed as properties on the model instance. Consequently data can be accessed by accessing those properties.

$finder = Orm::finder(Book::class);
$book = $finder->one(72);
echo$book->name;

About

Simple database ORM implementation

Topics

Resources

Stars

0 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

ronanchilvers/orm

Actions StatusScrutinizer Code Quality

orm is a small and simple database layer implementing the active record pattern. Its aim is to be simple, fast and useful. It relies on the [clancats hydrahon] query builder for database query access.

Overview

Things it does

  • PDO underneath so should work with any PDO compatible database
  • Provides a full query builder interface using clancats/hydrahon
  • Supports full save, destroy, update, insert functionality through the active record implementation
  • Supports model finder objects to help avoid 'fat model' syndrome
  • Supports fine grained model hooks for precise control of model lifecycle data
  • Supports model validation using respect/validation
  • Simple relationship handling - belongsTo, hasMany, hasOne
  • Configurable data type conversion for model properties

Things it does NOT do

  • Migrations - you can use whatever you like to manage your schema. We recommend phinx
  • Multiple database connections - currently orm only supports a single PDO connection.

Installation

You'll need at least PHP7.0 to use the library. The recommended way to install is using composer:

composer install ronanchilvers/orm

Configuring the database

Since orm uses PDO, it's up to you how you create and instantiate your PDO object. This will probably be in your bootstrap somewhere. Once your PDO object is available you will need to give it to orm. Here's an example:

$pdo = newPDO('sqlite::memory:');
Ronanchilvers\Orm\Orm::setConnection($pdo);

Clearly you will almost certainly not be using a :memory: DSN in practice. However you create your PDO object, the crucial point here is that you call Orm::setConnection to provide orm with your connection object.

Basic usage

orm doesn't make any pre-judgments about your database schema. When building models from a database it assumes it maps columns to properties and when saving it assumes that any property has a corresponding database table column. Its up to you to make sure the data makes sense.

Here we assume that we have a database table that looks like the following. We're using MySQL / MariaDB syntax here but whatever PDO supports should be fine.

CREATETABLE `books` (
`book_id`int(11) unsigned NOT NULL AUTO_INCREMENT,
`book_author`int(11) NOT NULL,
`book_name`varchar(1024) NOT NULL DEFAULT '',
`book_created` datetime DEFAULT CURRENT_TIMESTAMP,
`book_updated` datetime DEFAULT NULL,
PRIMARY KEY (`book_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

Defining a model

First create your model class. It should extend the Ronanchilvers\Orm\Model class. As with many active record implementations we assume here that the table has a plural name (books) and its corresponding model class will have a singular name (book).

class Book extends Model
{}

If your columns have no column prefix, that's all you need to do. The table name will be inferred from the class name. If however, like the example above, you have column prefixes then you can tweak your model to suit.

class Book extends Model
{
staticprotected$columnPrefix = 'book';
}

Similarly if your table doesn't map to the model name you can specufy that too.

class Book extends Model
{
staticprotected$table = 'my_books_table';
staticprotected$columnPrefix = 'book';
}

Now you're ready to use the model.

Finding models

orm supports a query builder interface provided by clancats/hydrahon. In order to retrieve models from the database, first obtain a finder object.

$finder = Orm::finder(Book::class);

Then you can use the finder object to retrieve models.

$books = $finder->all();

There are several standard finder methods you can use:

// Get all the records in one go$books = $finder->all();
// Get the third page of models when there are 30 records per page// (10 per page is the default)$books = $finder->all(3, 30);
// Get a specific model by its primary key, here assumed to be numeric$book = $finder->one(23);

You can use the full query builder to gain more control over the query:

// Get all the books for author id 20$books = $finder->select()->where('book_author', 20);
// Get all books added since last week - here we're using the excellent Carbon wrapper// for DateTime$recentBooks = $finder->select()->where('book_created', '>', Carbon::now()->subWeek());

You can read more about the capabilities of the query builder over at the clancats/hydrahon site.

If you want complete control over the SQL that is executed you can do:

$sql = "SELECT *FROM books LEFT JOIN authors ON author_id = book_authorWHERE author_name LIKE :name AND author_created < :created";
$params = [
'name' => 'Fred%',
'created' => Carbon::now()->subYear()->format('Y-m-d H:i:s'),
];
$books = $finder->query($sql, $params);

Custom Finder Classes

By default Orm::finder will give you back a vanilla Ronanchilvers\Orm\Finder object tied to given model class. However you can also override the finder class for a given model by setting the $finder static property on your model. This can be very useful if you want to add custom find methods (for example).

Let's imagine you've created a BookFinder class:

class BookFinder extends Finder
{
publicfunctionforAuthorId(int$id): array
{
return$this
->select()
->where(Book::prefix('author'), $id)
->execute();
}
}

You can see that we've created a subclass of the default finder and we've added a forAuthorId method which returns an array of books for a given author id.

Then we tell the model about our new finder class:

class Book extends Model
{
staticprotected$finder = BookFinder::class;
}

and then finally you're readdy to use it:

// $finder will be an instance of BookFinder here$finder = Orm::finder(Book::class);
$authors = $finder->forAuthorId(2);

Persistence

Saving a model back to the database is simply a matter of calling the save method.

$finder = Orm::finder(Book::class);
$book = $finder->one(23);
$book->save();

Similarly destroying a model is also simple:

$book->delete();

Accessing model data

As in any active record implementation, database table columns are expressed as properties on the model instance. Consequently data can be accessed by accessing those properties.

$finder = Orm::finder(Book::class);
$book = $finder->one(72);
echo$book->name;

About

Simple database ORM implementation

Topics

Resources

Stars

0 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

ronanchilvers/orm

Actions StatusScrutinizer Code Quality

orm is a small and simple database layer implementing the active record pattern. Its aim is to be simple, fast and useful. It relies on the [clancats hydrahon] query builder for database query access.

Overview

Things it does

  • PDO underneath so should work with any PDO compatible database
  • Provides a full query builder interface using clancats/hydrahon
  • Supports full save, destroy, update, insert functionality through the active record implementation
  • Supports model finder objects to help avoid 'fat model' syndrome
  • Supports fine grained model hooks for precise control of model lifecycle data
  • Supports model validation using respect/validation
  • Simple relationship handling - belongsTo, hasMany, hasOne
  • Configurable data type conversion for model properties

Things it does NOT do

  • Migrations - you can use whatever you like to manage your schema. We recommend phinx
  • Multiple database connections - currently orm only supports a single PDO connection.

Installation

You'll need at least PHP7.0 to use the library. The recommended way to install is using composer:

composer install ronanchilvers/orm

Configuring the database

Since orm uses PDO, it's up to you how you create and instantiate your PDO object. This will probably be in your bootstrap somewhere. Once your PDO object is available you will need to give it to orm. Here's an example:

$pdo = newPDO('sqlite::memory:');
Ronanchilvers\Orm\Orm::setConnection($pdo);

Clearly you will almost certainly not be using a :memory: DSN in practice. However you create your PDO object, the crucial point here is that you call Orm::setConnection to provide orm with your connection object.

Basic usage

orm doesn't make any pre-judgments about your database schema. When building models from a database it assumes it maps columns to properties and when saving it assumes that any property has a corresponding database table column. Its up to you to make sure the data makes sense.

Here we assume that we have a database table that looks like the following. We're using MySQL / MariaDB syntax here but whatever PDO supports should be fine.

CREATETABLE `books` (
`book_id`int(11) unsigned NOT NULL AUTO_INCREMENT,
`book_author`int(11) NOT NULL,
`book_name`varchar(1024) NOT NULL DEFAULT '',
`book_created` datetime DEFAULT CURRENT_TIMESTAMP,
`book_updated` datetime DEFAULT NULL,
PRIMARY KEY (`book_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

Defining a model

First create your model class. It should extend the Ronanchilvers\Orm\Model class. As with many active record implementations we assume here that the table has a plural name (books) and its corresponding model class will have a singular name (book).

class Book extends Model
{}

If your columns have no column prefix, that's all you need to do. The table name will be inferred from the class name. If however, like the example above, you have column prefixes then you can tweak your model to suit.

class Book extends Model
{
staticprotected$columnPrefix = 'book';
}

Similarly if your table doesn't map to the model name you can specufy that too.

class Book extends Model
{
staticprotected$table = 'my_books_table';
staticprotected$columnPrefix = 'book';
}

Now you're ready to use the model.

Finding models

orm supports a query builder interface provided by clancats/hydrahon. In order to retrieve models from the database, first obtain a finder object.

$finder = Orm::finder(Book::class);

Then you can use the finder object to retrieve models.

$books = $finder->all();

There are several standard finder methods you can use:

// Get all the records in one go$books = $finder->all();
// Get the third page of models when there are 30 records per page// (10 per page is the default)$books = $finder->all(3, 30);
// Get a specific model by its primary key, here assumed to be numeric$book = $finder->one(23);

You can use the full query builder to gain more control over the query:

// Get all the books for author id 20$books = $finder->select()->where('book_author', 20);
// Get all books added since last week - here we're using the excellent Carbon wrapper// for DateTime$recentBooks = $finder->select()->where('book_created', '>', Carbon::now()->subWeek());

You can read more about the capabilities of the query builder over at the clancats/hydrahon site.

If you want complete control over the SQL that is executed you can do:

$sql = "SELECT *FROM books LEFT JOIN authors ON author_id = book_authorWHERE author_name LIKE :name AND author_created < :created";
$params = [
'name' => 'Fred%',
'created' => Carbon::now()->subYear()->format('Y-m-d H:i:s'),
];
$books = $finder->query($sql, $params);

Custom Finder Classes

By default Orm::finder will give you back a vanilla Ronanchilvers\Orm\Finder object tied to given model class. However you can also override the finder class for a given model by setting the $finder static property on your model. This can be very useful if you want to add custom find methods (for example).

Let's imagine you've created a BookFinder class:

class BookFinder extends Finder
{
publicfunctionforAuthorId(int$id): array
{
return$this
->select()
->where(Book::prefix('author'), $id)
->execute();
}
}

You can see that we've created a subclass of the default finder and we've added a forAuthorId method which returns an array of books for a given author id.

Then we tell the model about our new finder class:

class Book extends Model
{
staticprotected$finder = BookFinder::class;
}

and then finally you're readdy to use it:

// $finder will be an instance of BookFinder here$finder = Orm::finder(Book::class);
$authors = $finder->forAuthorId(2);

Persistence

Saving a model back to the database is simply a matter of calling the save method.

$finder = Orm::finder(Book::class);
$book = $finder->one(23);
$book->save();

Similarly destroying a model is also simple:

$book->delete();

Accessing model data

As in any active record implementation, database table columns are expressed as properties on the model instance. Consequently data can be accessed by accessing those properties.

$finder = Orm::finder(Book::class);
$book = $finder->one(72);
echo$book->name;

About

Simple database ORM implementation

Topics

Resources

Stars

0 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

ronanchilvers/orm

Actions StatusScrutinizer Code Quality

orm is a small and simple database layer implementing the active record pattern. Its aim is to be simple, fast and useful. It relies on the [clancats hydrahon] query builder for database query access.

Overview

Things it does

  • PDO underneath so should work with any PDO compatible database
  • Provides a full query builder interface using clancats/hydrahon
  • Supports full save, destroy, update, insert functionality through the active record implementation
  • Supports model finder objects to help avoid 'fat model' syndrome
  • Supports fine grained model hooks for precise control of model lifecycle data
  • Supports model validation using respect/validation
  • Simple relationship handling - belongsTo, hasMany, hasOne
  • Configurable data type conversion for model properties

Things it does NOT do

  • Migrations - you can use whatever you like to manage your schema. We recommend phinx
  • Multiple database connections - currently orm only supports a single PDO connection.

Installation

You'll need at least PHP7.0 to use the library. The recommended way to install is using composer:

composer install ronanchilvers/orm

Configuring the database

Since orm uses PDO, it's up to you how you create and instantiate your PDO object. This will probably be in your bootstrap somewhere. Once your PDO object is available you will need to give it to orm. Here's an example:

$pdo = newPDO('sqlite::memory:');
Ronanchilvers\Orm\Orm::setConnection($pdo);

Clearly you will almost certainly not be using a :memory: DSN in practice. However you create your PDO object, the crucial point here is that you call Orm::setConnection to provide orm with your connection object.

Basic usage

orm doesn't make any pre-judgments about your database schema. When building models from a database it assumes it maps columns to properties and when saving it assumes that any property has a corresponding database table column. Its up to you to make sure the data makes sense.

Here we assume that we have a database table that looks like the following. We're using MySQL / MariaDB syntax here but whatever PDO supports should be fine.

CREATETABLE `books` (
`book_id`int(11) unsigned NOT NULL AUTO_INCREMENT,
`book_author`int(11) NOT NULL,
`book_name`varchar(1024) NOT NULL DEFAULT '',
`book_created` datetime DEFAULT CURRENT_TIMESTAMP,
`book_updated` datetime DEFAULT NULL,
PRIMARY KEY (`book_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

Defining a model

First create your model class. It should extend the Ronanchilvers\Orm\Model class. As with many active record implementations we assume here that the table has a plural name (books) and its corresponding model class will have a singular name (book).

class Book extends Model
{}

If your columns have no column prefix, that's all you need to do. The table name will be inferred from the class name. If however, like the example above, you have column prefixes then you can tweak your model to suit.

class Book extends Model
{
staticprotected$columnPrefix = 'book';
}

Similarly if your table doesn't map to the model name you can specufy that too.

class Book extends Model
{
staticprotected$table = 'my_books_table';
staticprotected$columnPrefix = 'book';
}

Now you're ready to use the model.

Finding models

orm supports a query builder interface provided by clancats/hydrahon. In order to retrieve models from the database, first obtain a finder object.

$finder = Orm::finder(Book::class);

Then you can use the finder object to retrieve models.

$books = $finder->all();

There are several standard finder methods you can use:

// Get all the records in one go$books = $finder->all();
// Get the third page of models when there are 30 records per page// (10 per page is the default)$books = $finder->all(3, 30);
// Get a specific model by its primary key, here assumed to be numeric$book = $finder->one(23);

You can use the full query builder to gain more control over the query:

// Get all the books for author id 20$books = $finder->select()->where('book_author', 20);
// Get all books added since last week - here we're using the excellent Carbon wrapper// for DateTime$recentBooks = $finder->select()->where('book_created', '>', Carbon::now()->subWeek());

You can read more about the capabilities of the query builder over at the clancats/hydrahon site.

If you want complete control over the SQL that is executed you can do:

$sql = "SELECT *FROM books LEFT JOIN authors ON author_id = book_authorWHERE author_name LIKE :name AND author_created < :created";
$params = [
'name' => 'Fred%',
'created' => Carbon::now()->subYear()->format('Y-m-d H:i:s'),
];
$books = $finder->query($sql, $params);

Custom Finder Classes

By default Orm::finder will give you back a vanilla Ronanchilvers\Orm\Finder object tied to given model class. However you can also override the finder class for a given model by setting the $finder static property on your model. This can be very useful if you want to add custom find methods (for example).

Let's imagine you've created a BookFinder class:

class BookFinder extends Finder
{
publicfunctionforAuthorId(int$id): array
{
return$this
->select()
->where(Book::prefix('author'), $id)
->execute();
}
}

You can see that we've created a subclass of the default finder and we've added a forAuthorId method which returns an array of books for a given author id.

Then we tell the model about our new finder class:

class Book extends Model
{
staticprotected$finder = BookFinder::class;
}

and then finally you're readdy to use it:

// $finder will be an instance of BookFinder here$finder = Orm::finder(Book::class);
$authors = $finder->forAuthorId(2);

Persistence

Saving a model back to the database is simply a matter of calling the save method.

$finder = Orm::finder(Book::class);
$book = $finder->one(23);
$book->save();

Similarly destroying a model is also simple:

$book->delete();

Accessing model data

As in any active record implementation, database table columns are expressed as properties on the model instance. Consequently data can be accessed by accessing those properties.

$finder = Orm::finder(Book::class);
$book = $finder->one(72);
echo$book->name;

About

Simple database ORM implementation

Topics

Resources

Stars

0 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

ronanchilvers/orm

Actions StatusScrutinizer Code Quality

orm is a small and simple database layer implementing the active record pattern. Its aim is to be simple, fast and useful. It relies on the [clancats hydrahon] query builder for database query access.

Overview

Things it does

  • PDO underneath so should work with any PDO compatible database
  • Provides a full query builder interface using clancats/hydrahon
  • Supports full save, destroy, update, insert functionality through the active record implementation
  • Supports model finder objects to help avoid 'fat model' syndrome
  • Supports fine grained model hooks for precise control of model lifecycle data
  • Supports model validation using respect/validation
  • Simple relationship handling - belongsTo, hasMany, hasOne
  • Configurable data type conversion for model properties

Things it does NOT do

  • Migrations - you can use whatever you like to manage your schema. We recommend phinx
  • Multiple database connections - currently orm only supports a single PDO connection.

Installation

You'll need at least PHP7.0 to use the library. The recommended way to install is using composer:

composer install ronanchilvers/orm

Configuring the database

Since orm uses PDO, it's up to you how you create and instantiate your PDO object. This will probably be in your bootstrap somewhere. Once your PDO object is available you will need to give it to orm. Here's an example:

$pdo = newPDO('sqlite::memory:');
Ronanchilvers\Orm\Orm::setConnection($pdo);

Clearly you will almost certainly not be using a :memory: DSN in practice. However you create your PDO object, the crucial point here is that you call Orm::setConnection to provide orm with your connection object.

Basic usage

orm doesn't make any pre-judgments about your database schema. When building models from a database it assumes it maps columns to properties and when saving it assumes that any property has a corresponding database table column. Its up to you to make sure the data makes sense.

Here we assume that we have a database table that looks like the following. We're using MySQL / MariaDB syntax here but whatever PDO supports should be fine.

CREATETABLE `books` (
`book_id`int(11) unsigned NOT NULL AUTO_INCREMENT,
`book_author`int(11) NOT NULL,
`book_name`varchar(1024) NOT NULL DEFAULT '',
`book_created` datetime DEFAULT CURRENT_TIMESTAMP,
`book_updated` datetime DEFAULT NULL,
PRIMARY KEY (`book_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

Defining a model

First create your model class. It should extend the Ronanchilvers\Orm\Model class. As with many active record implementations we assume here that the table has a plural name (books) and its corresponding model class will have a singular name (book).

class Book extends Model
{}

If your columns have no column prefix, that's all you need to do. The table name will be inferred from the class name. If however, like the example above, you have column prefixes then you can tweak your model to suit.

class Book extends Model
{
staticprotected$columnPrefix = 'book';
}

Similarly if your table doesn't map to the model name you can specufy that too.

class Book extends Model
{
staticprotected$table = 'my_books_table';
staticprotected$columnPrefix = 'book';
}

Now you're ready to use the model.

Finding models

orm supports a query builder interface provided by clancats/hydrahon. In order to retrieve models from the database, first obtain a finder object.

$finder = Orm::finder(Book::class);

Then you can use the finder object to retrieve models.

$books = $finder->all();

There are several standard finder methods you can use:

// Get all the records in one go$books = $finder->all();
// Get the third page of models when there are 30 records per page// (10 per page is the default)$books = $finder->all(3, 30);
// Get a specific model by its primary key, here assumed to be numeric$book = $finder->one(23);

You can use the full query builder to gain more control over the query:

// Get all the books for author id 20$books = $finder->select()->where('book_author', 20);
// Get all books added since last week - here we're using the excellent Carbon wrapper// for DateTime$recentBooks = $finder->select()->where('book_created', '>', Carbon::now()->subWeek());

You can read more about the capabilities of the query builder over at the clancats/hydrahon site.

If you want complete control over the SQL that is executed you can do:

$sql = "SELECT *FROM books LEFT JOIN authors ON author_id = book_authorWHERE author_name LIKE :name AND author_created < :created";
$params = [
'name' => 'Fred%',
'created' => Carbon::now()->subYear()->format('Y-m-d H:i:s'),
];
$books = $finder->query($sql, $params);

Custom Finder Classes

By default Orm::finder will give you back a vanilla Ronanchilvers\Orm\Finder object tied to given model class. However you can also override the finder class for a given model by setting the $finder static property on your model. This can be very useful if you want to add custom find methods (for example).

Let's imagine you've created a BookFinder class:

class BookFinder extends Finder
{
publicfunctionforAuthorId(int$id): array
{
return$this
->select()
->where(Book::prefix('author'), $id)
->execute();
}
}

You can see that we've created a subclass of the default finder and we've added a forAuthorId method which returns an array of books for a given author id.

Then we tell the model about our new finder class:

class Book extends Model
{
staticprotected$finder = BookFinder::class;
}

and then finally you're readdy to use it:

// $finder will be an instance of BookFinder here$finder = Orm::finder(Book::class);
$authors = $finder->forAuthorId(2);

Persistence

Saving a model back to the database is simply a matter of calling the save method.

$finder = Orm::finder(Book::class);
$book = $finder->one(23);
$book->save();

Similarly destroying a model is also simple:

$book->delete();

Accessing model data

As in any active record implementation, database table columns are expressed as properties on the model instance. Consequently data can be accessed by accessing those properties.

$finder = Orm::finder(Book::class);
$book = $finder->one(72);
echo$book->name;

About

Simple database ORM implementation

Topics

Resources

Stars

0 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

ronanchilvers/orm

Actions StatusScrutinizer Code Quality

orm is a small and simple database layer implementing the active record pattern. Its aim is to be simple, fast and useful. It relies on the [clancats hydrahon] query builder for database query access.

Overview

Things it does

  • PDO underneath so should work with any PDO compatible database
  • Provides a full query builder interface using clancats/hydrahon
  • Supports full save, destroy, update, insert functionality through the active record implementation
  • Supports model finder objects to help avoid 'fat model' syndrome
  • Supports fine grained model hooks for precise control of model lifecycle data
  • Supports model validation using respect/validation
  • Simple relationship handling - belongsTo, hasMany, hasOne
  • Configurable data type conversion for model properties

Things it does NOT do

  • Migrations - you can use whatever you like to manage your schema. We recommend phinx
  • Multiple database connections - currently orm only supports a single PDO connection.

Installation

You'll need at least PHP7.0 to use the library. The recommended way to install is using composer:

composer install ronanchilvers/orm

Configuring the database

Since orm uses PDO, it's up to you how you create and instantiate your PDO object. This will probably be in your bootstrap somewhere. Once your PDO object is available you will need to give it to orm. Here's an example:

$pdo = newPDO('sqlite::memory:');
Ronanchilvers\Orm\Orm::setConnection($pdo);

Clearly you will almost certainly not be using a :memory: DSN in practice. However you create your PDO object, the crucial point here is that you call Orm::setConnection to provide orm with your connection object.

Basic usage

orm doesn't make any pre-judgments about your database schema. When building models from a database it assumes it maps columns to properties and when saving it assumes that any property has a corresponding database table column. Its up to you to make sure the data makes sense.

Here we assume that we have a database table that looks like the following. We're using MySQL / MariaDB syntax here but whatever PDO supports should be fine.

CREATETABLE `books` (
`book_id`int(11) unsigned NOT NULL AUTO_INCREMENT,
`book_author`int(11) NOT NULL,
`book_name`varchar(1024) NOT NULL DEFAULT '',
`book_created` datetime DEFAULT CURRENT_TIMESTAMP,
`book_updated` datetime DEFAULT NULL,
PRIMARY KEY (`book_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

Defining a model

First create your model class. It should extend the Ronanchilvers\Orm\Model class. As with many active record implementations we assume here that the table has a plural name (books) and its corresponding model class will have a singular name (book).

class Book extends Model
{}

If your columns have no column prefix, that's all you need to do. The table name will be inferred from the class name. If however, like the example above, you have column prefixes then you can tweak your model to suit.

class Book extends Model
{
staticprotected$columnPrefix = 'book';
}

Similarly if your table doesn't map to the model name you can specufy that too.

class Book extends Model
{
staticprotected$table = 'my_books_table';
staticprotected$columnPrefix = 'book';
}

Now you're ready to use the model.

Finding models

orm supports a query builder interface provided by clancats/hydrahon. In order to retrieve models from the database, first obtain a finder object.

$finder = Orm::finder(Book::class);

Then you can use the finder object to retrieve models.

$books = $finder->all();

There are several standard finder methods you can use:

// Get all the records in one go$books = $finder->all();
// Get the third page of models when there are 30 records per page// (10 per page is the default)$books = $finder->all(3, 30);
// Get a specific model by its primary key, here assumed to be numeric$book = $finder->one(23);

You can use the full query builder to gain more control over the query:

// Get all the books for author id 20$books = $finder->select()->where('book_author', 20);
// Get all books added since last week - here we're using the excellent Carbon wrapper// for DateTime$recentBooks = $finder->select()->where('book_created', '>', Carbon::now()->subWeek());

You can read more about the capabilities of the query builder over at the clancats/hydrahon site.

If you want complete control over the SQL that is executed you can do:

$sql = "SELECT *FROM books LEFT JOIN authors ON author_id = book_authorWHERE author_name LIKE :name AND author_created < :created";
$params = [
'name' => 'Fred%',
'created' => Carbon::now()->subYear()->format('Y-m-d H:i:s'),
];
$books = $finder->query($sql, $params);

Custom Finder Classes

By default Orm::finder will give you back a vanilla Ronanchilvers\Orm\Finder object tied to given model class. However you can also override the finder class for a given model by setting the $finder static property on your model. This can be very useful if you want to add custom find methods (for example).

Let's imagine you've created a BookFinder class:

class BookFinder extends Finder
{
publicfunctionforAuthorId(int$id): array
{
return$this
->select()
->where(Book::prefix('author'), $id)
->execute();
}
}

You can see that we've created a subclass of the default finder and we've added a forAuthorId method which returns an array of books for a given author id.

Then we tell the model about our new finder class:

class Book extends Model
{
staticprotected$finder = BookFinder::class;
}

and then finally you're readdy to use it:

// $finder will be an instance of BookFinder here$finder = Orm::finder(Book::class);
$authors = $finder->forAuthorId(2);

Persistence

Saving a model back to the database is simply a matter of calling the save method.

$finder = Orm::finder(Book::class);
$book = $finder->one(23);
$book->save();

Similarly destroying a model is also simple:

$book->delete();

Accessing model data

As in any active record implementation, database table columns are expressed as properties on the model instance. Consequently data can be accessed by accessing those properties.

$finder = Orm::finder(Book::class);
$book = $finder->one(72);
echo$book->name;

About

Simple database ORM implementation

Topics

Resources

Stars

0 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages