PHPackages                             granadaorm/granada - 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. granadaorm/granada

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

granadaorm/granada
==================

Active Record / ORM with eager loading, lazy loading and more

4.0.9(3mo ago)178.9k↓33.3%41BSD-2-ClausePHPPHP &gt;=8.1CI passing

Since Oct 2Pushed 3mo ago4 watchersCompare

[ Source](https://github.com/GranadaORM/Granada)[ Packagist](https://packagist.org/packages/granadaorm/granada)[ Docs](https://github.com/GranadaORM/Granada)[ RSS](/packages/granadaorm-granada/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (10)Dependencies (3)Versions (54)Used By (1)

Granada
=======

[](#granada)

[![Latest Stable Version](https://camo.githubusercontent.com/98fdebd9ea73bf366b45014ef88aa527db9aad08a3402698b7323f2b56194dcb/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f6772616e6164616f726d2f6772616e6164613f736f72743d73656d766572267374796c653d666c61742d737175617265)](https://packagist.org/packages/granadaorm/granada)[![Total Downloads](https://camo.githubusercontent.com/176084b974580c6fc285e42c37506fc7979ea442bdf53c331e818231698ca89d/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6772616e6164616f726d2f6772616e6164613f7374796c653d666c61742d737175617265)](https://packagist.org/packages/granadaorm/granada/stats)[![Build Status](https://github.com/GranadaORM/Granada/actions/workflows/ci.yml/badge.svg)](https://github.com/GranadaORM/Granada/actions/workflows/ci.yml/badge.svg)

Granada is a easy to use Active Record implementation, and ORM based on Idiorm/Paris.

A quick view
------------

[](#a-quick-view)

```
use Granada\Model;

class User extends Model
{
    public function posts() {
        return $this->has_many('Post');
    }
}

class Post extends Model {}

// select
$user = User::where('name', 'John')->find_one();

// modify
$user->first_name = 'Doe';
$user->save();

// select relationship
$posts = $user->posts()->find_many();
foreach ($posts as $post) {
    echo $post->content;
}
```

You can read the Paris Docs on [paris.readthedocs.org](http://paris.rtfd.org) but be sure to read the additions below.

Install
-------

[](#install)

Using composer:

```
composer require granadaorm/granada
```

Configure it:

```
require 'vendor/autoload.php';

use Granada\ORM;

ORM::configure('mysql:host=localhost;dbname=my_database');
ORM::configure('username', 'database_user');
ORM::configure('password', 'top_secret');
```

As always, you can check it in detail on [Paris documentation](http://idiorm.readthedocs.org/en/latest/configuration.html#setup)

Additions
---------

[](#additions)

### Eager loading

[](#eager-loading)

You can use the "with" method to add relationships eager loading to the query.

```
$results = User::with('avatar', 'posts')->find_many();
```

will use 3 querys to fetch the users and the relationships:

```
SELECT * FROM user
SELECT * FROM avatar WHERE user_id IN (....)
SELECT * FROM posts WHERE user_id IN (....)
```

It is possible to get the relationships results for each result, this way

```
foreach($results as $result){
    echo $result->avatar->img;
    foreach($result->posts as $post){
        echo $post->title;
    }
}
```

### Lazy loading

[](#lazy-loading)

Triying to access to a not fetched relationship will call and return it

```
$results = User::find_many();
foreach($results as $result){
    echo $result->avatar->img;
}
```

Notice that if there is no result for `avatar` on the above example it will throw a `Notice: Trying to get property of non-object...`Note: Maybe worth the effort to create a NULL object for this use case and others.

### Chained relationships with arguments for eager loading

[](#chained-relationships-with-arguments-for-eager-loading)

It is possible to chain relationships and add arguments to the relationships calls

```
// chained relationships with dot notation
$results = User::with('posts.comments')->find_many();

// OR

// chained relationships use the "with" reserved word. (usefull if you want to pass arguments to the relationships)
$results = User::with(array('posts'=>array('with'=>array('comments'))))->find_many();

// SELECT * FROM user
// SELECT * FROM post WHERE user_id IN (....)
// SELECT * FROM comments WHERE post_id IN (....)

foreach($results as $result){
    foreach($posts as $post){
        echo $post->title;
        foreach($post->comments as $comment){
        echo $comment->subject;
        }
    }
}

// you can use arguments (one or more) to call the models relationships
$results = User::with(array('posts'=>array('arg1')))->find_many();
// will call the relationship defined in the user model with the argument "arg1"
```

### Custom query filters

[](#custom-query-filters)

It's possible to create static functions on the model to work as filter in queries. Prepended it with "filter\_":

```
use Granada\Model;

class ModelName extends Model {
    ....
    public static function filter_aname($query, $argument1, $argument2...){
        return $query->where('property', 'value')->limit('X')......;
    }
    ....
}
```

and call it on a static call

```
ModelName::aname($argument1, $argument2)->....
```

### Multiple additions names for Granada

[](#multiple-additions-names-for-granada)

- select\_raw
- group\_by\_raw
- order\_by\_raw
- raw\_join
- insert : To create and save multiple elements from an array
- pluck : returns a single column from the result.
- find\_pairs : Return array of key=&gt;value as result
- save : accepts a boolean to use "ON DUPLICATE KEY UPDATE" (just for Mysql)
- delete\_many (accept join clauses)

### Overload SET

[](#overload-set)

```
// In the Model
protected function set_title($value)
{
    $this->alias = Str::slug($value);
    return $value;
}
```

```
// outside of the model
$content_instance->set('title', 'A title');

// works with multiple set too
$properties = array(
    'title'   => 'A title',
    'content' => 'Some content'
);
$content_instance->set($properties);

// try it with a direct assignement
$content_instance->title = 'A title';
```

### Overload GET and MISSING property

[](#overload-get-and-missing-property)

```
// In the Model

// Work on defined
protected function get_path($value)
{
    return strtolower($value);
}

// and non-defined attributes.
protected function mising_testing()
{
    return 'whatever';
}
...

// outside of the model
echo $content_instance->path; // returns the lowercase path value of $content_instance
echo $content_instance->testing; // returns 'whatever' since we defined a missing_{attribute_name}
```

Of course, you still can define functions with the property name if you want to overload it completely.

### Define resultSet (collection type) class on Model

[](#define-resultset-collection-type-class-on-model)

Now is possible to define the resultSet class returned for a model instances result. (if `return_result_sets` config variable is set to true) Notice that the resultSet class defined must `extends Granada\ResultSet` and must be loaded

```
// In the Model
public static $resultSetClass = 'TreeResultSet';
```

```
// outside of the model
var_dump(Content::find_many());

// echoes
object(TreeResultSet)[10]
    protected '_results' => array(...)
....
```

ResultSets are defined by the model in the result, as you can see above. On eager load, the results are consistent. For example, if we have a `Content` model, with `$resultSetClass = 'TreeResultSet'` and a `has_many` relationship defined as `media`:

```
Content::with('media')->find_many();
```

will return a `TreeResultSet` with instances of `Content` each with a `property $media` containing `Granada\ResultSet` (the default resultSet if none if defined on the Model)

Basic Documentation comes from Paris
------------------------------------

[](#basic-documentation-comes-from-paris)

### Paris

[](#paris)

### Feature complete

[](#feature-complete)

Paris is now considered to be feature complete as of version 1.4.0. Whilst it will continue to be maintained with bug fixes there will be no further new features added.

A lightweight Active Record implementation for PHP5.

Built on top of [Idiorm](http://github.com/j4mie/idiorm/).

Tested on PHP 5.2.0+ - may work on earlier versions with PDO and the correct database drivers.

Released under a [BSD license](http://en.wikipedia.org/wiki/BSD_licenses).

### Features

[](#features)

- Extremely simple configuration.
- Exposes the full power of [Idiorm](http://github.com/j4mie/idiorm/)'s fluent query API.
- Supports associations.
- Simple mechanism to encapsulate common queries in filter methods.
- Built on top of [PDO](http://php.net/pdo).
- Uses [prepared statements](http://uk.php.net/manual/en/pdo.prepared-statements.php) throughout to protect against [SQL injection](http://en.wikipedia.org/wiki/SQL_injection) attacks.
- Database agnostic. Currently supports SQLite, MySQL, Firebird and PostgreSQL. May support others, please give it a try!
- Supports collections of models with method chaining to filter or apply actions to multiple results at once.
- Multiple connections are supported

### History

[](#history)

Granada was originally developed by [Erik Wiesenthal](https://github.com/surt), up to version 1.5. Further development started by [Josh Marshall](https://github.com/joshbmarshall) to release version 2.0

###  Health Score

59

—

FairBetter than 99% of packages

Maintenance82

Actively maintained with recent releases

Popularity33

Limited adoption so far

Community22

Small or concentrated contributor base

Maturity84

Battle-tested with a long release history

 Bus Factor2

2 contributors hold 50%+ of commits

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 ~52 days

Recently: every ~63 days

Total

52

Last Release

90d ago

Major Versions

2.10.12 → 3.0.02023-04-20

3.1.6 → 4.0.02024-09-09

PHP version history (2 changes)2.0.0PHP &gt;=5.6.0

4.0.0PHP &gt;=8.1

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/4043827?v=4)[Josh Marshall](/maintainers/joshbmarshall)[@joshbmarshall](https://github.com/joshbmarshall)

---

Top Contributors

[![Surt](https://avatars.githubusercontent.com/u/48085?v=4)](https://github.com/Surt "Surt (167 commits)")[![joshbmarshall](https://avatars.githubusercontent.com/u/4043827?v=4)](https://github.com/joshbmarshall "joshbmarshall (153 commits)")[![j4mie](https://avatars.githubusercontent.com/u/6988?v=4)](https://github.com/j4mie "j4mie (56 commits)")[![treffynnon](https://avatars.githubusercontent.com/u/65215?v=4)](https://github.com/treffynnon "treffynnon (44 commits)")[![tomvo](https://avatars.githubusercontent.com/u/1503385?v=4)](https://github.com/tomvo "tomvo (11 commits)")[![kw-pr](https://avatars.githubusercontent.com/u/9133572?v=4)](https://github.com/kw-pr "kw-pr (4 commits)")[![PeterSchumacher](https://avatars.githubusercontent.com/u/200637?v=4)](https://github.com/PeterSchumacher "PeterSchumacher (4 commits)")[![Wuffz](https://avatars.githubusercontent.com/u/996222?v=4)](https://github.com/Wuffz "Wuffz (3 commits)")[![pine3ree](https://avatars.githubusercontent.com/u/3229979?v=4)](https://github.com/pine3ree "pine3ree (1 commits)")[![jahvi](https://avatars.githubusercontent.com/u/661330?v=4)](https://github.com/jahvi "jahvi (1 commits)")[![bitdeli-chef](https://avatars.githubusercontent.com/u/3092978?v=4)](https://github.com/bitdeli-chef "bitdeli-chef (1 commits)")[![scrutinizer-auto-fixer](https://avatars.githubusercontent.com/u/6253494?v=4)](https://github.com/scrutinizer-auto-fixer "scrutinizer-auto-fixer (1 commits)")

---

Tags

ormphpdatabaseormactive-recordeager-loadingidiormparis

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/granadaorm-granada/health.svg)

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

###  Alternatives

[propel/propel1

Propel is an open-source Object-Relational Mapping (ORM) for PHP5.

8481.6M87](/packages/propel-propel1)[perplorm/perpl

Perpl is an improved and still maintained fork of Propel2, an open-source Object-Relational Mapping (ORM) for PHP.

203.7k](/packages/perplorm-perpl)[flightphp/active-record

Micro Active Record library in PHP, support chain calls, events, and relations.

163.0k](/packages/flightphp-active-record)

PHPackages © 2026

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