PHPackages                             kijin/beaver - 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. kijin/beaver

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

kijin/beaver
============

Super lightweight ORM for PHP 5.3+

0.4.0(12y ago)6371LGPL-3.0+PHPPHP &gt;=5.3.0

Since Jul 31Pushed 11y ago2 watchersCompare

[ Source](https://github.com/kijin/beaver)[ Packagist](https://packagist.org/packages/kijin/beaver)[ Docs](https://github.com/kijin/beaver)[ RSS](/packages/kijin-beaver/feed)WikiDiscussions master Synced 4w ago

READMEChangelogDependenciesVersions (12)Used By (0)

Introduction
============

[](#introduction)

Beaver is a very simple object-to-database mapper for **PHP 5.3** and above. It allows you to do CRUD stuff through an object-oriented interface, and also provides basic search and caching functions.

Beaver is designed to be used with [PDO](http://www.php.net/manual/en/book.pdo.php). However, since Beaver uses dependency injection for database interactions, any object that behaves like PDO (such as a custom wrapper for PDO) can be used in its place. Beaver currently supports MySQL, PostgreSQL, and SQLite. Other relational databases have not been tested.

Caching also uses dependency injection. Any class which exposes the following methods is compatible with Beaver:

- get($key, $value)
- set($key, $value, $ttl)

[Memcached](http://www.php.net/manual/en/book.memcached.php) and [PHPRedis](http://github.com/nicolasff/phpredis) work with Beaver out of the box. APC can be made compatible with Beaver by using the author's [OOAPC](http://github.com/kijin/ooapc) class. The older [Memcache](http://www.php.net/manual/en/book.memcache.php) extension is incompatible because it requires an additional argument in `set()`.

Beaver released under the [GNU Lesser General Public License, version 3](http://www.gnu.org/copyleft/lesser.html).

User Guide
==========

[](#user-guide)

Configuration
-------------

[](#configuration)

Beaver doesn't manage database connections for you. So you connect to the database first, and then inject the PDO object into Beaver.

```
$pdo = new \PDO('mysql:host=localhost;dbname=test', 'username', 'password');
$pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);  // Recommended
Beaver\Base::set_database($pdo);

```

Now, do the same for the cache connection. This is optional. Beaver also works perfectly fine without caching.

```
$cache = new \Memcached;
$cache->addServer('127.0.0.1', 11211);
Beaver\Base::set_cache($cache);

```

Data Definition
---------------

[](#data-definition)

Beaver doesn't create tables for you, so you need to create them yourself. This guide assumes that you have a database table as defined below:

```
CREATE TABLE users
(
    id           INTEGER      PRIMARY KEY AUTO_INCREMENT,
    name         VARCHAR(128) NOT NULL,
    email        VARCHAR(128) NOT NULL,
    password     VARCHAR(128) NOT NULL,
    age          INTEGER      NOT NULL,
    karma_points INTEGER      NOT NULL DEFAULT 0,
    group_id     INTEGER
);

```

Now you need to define the corresponding class in PHP. It's your job to update this class if you change your database schema, because Beaver is too lightweight to handle that for you.

```
class User extends Beaver\Base
{
    protected static $_table = 'users';  // Required
    protected static $_pk = 'id';        // Optional
    public $id;
    public $name;
    public $email;
    public $password;
    public $age;
    public $karma_points = 0;
    public $group_id;
}

```

`protected static $_table` is required, because Beaver doesn't do inflections automatically. You can point your classes at any table or view you want.

`protected static $_pk` is optional. It defaults to `id`, so you only need to override it if you want to use a column other than `id` as your primary key.

All other properties should mirror database columns. You may specify default values.

Beaver will treat all properties, both public and protected, as names of database columns. This will cause errors if you define properties that don't exist in the database. If you need to define additional properties, make them begin with an underscore (`_`). Properties that begin with an underscore will be ignored by Beaver.

It is also a good idea to create a collection class that goes with your regular class. In Beaver 0.2.9 and earlier, methods that return multiple objects, such as `get_array()`, `get_if_*()` and `select()`, returned them in an array. In Beaver 0.3.0 and later, they will return an instance of a collection class that implements the `ArrayAccess`, `Iterator`, and `Countable` interfaces. This class behaves just like an array in most common use cases, such as a `foreach()` loop. However, you can also write methods to perform various batch operations on collections of objects. This is preferable to performing the same operation on each object individually.

To use a collection class, just create a class with the same name as your regular class, but with `Collection` appended to it. This class should extend `Beaver\Collection`. For example:

```
class UserCollection extends Beaver\Collection
{
    public function get_average_age()
    {
        $sum = 0;
        foreach ($this->objects as $user)
        {
            $sum += $user->age;
        }
        return $sum / $this->count;
    }
}

```

As you can see, `Beaver\Collection` comes with a few properties for your programming convenience. Documentation of these properties is currently underway. In the meantime, please refer to the source code for reference.

If a custom collection class is not defined, methods that return multiple objects will simply return an instance of `Beaver\Collection`.

Everyday Usage
--------------

[](#everyday-usage)

### Creating New Objects (INSERT)

[](#creating-new-objects-insert)

Well, how else did you think it would work?

```
$obj = new User;
$obj->name = 'John Doe';
$obj->email = 'john_doe@example.com';
$obj->password = hash($password.$salt);
$obj->age = 30;
$obj->save();

```

Usually you would skip the primary key (`id` property) when assigning values to a new object. Primary key are usually set to `AUTO_INCREMENT` or equivalent, in which case they are assigned by the database server. But this means that the primary key (`id` property) will remain `null` until you save the object for the first time. So, be careful not to refer to an object's primary key before it is saved.

If your table has a primary key that does not auto-increment, you may have to set it manually. In that case, it's OK to assign whatever you want to the `id` property manually. Beaver will try to honor your choices, while any mistakes will be caught by the database server.

### Modifying Objects (UPDATE)

[](#modifying-objects-update)

There are two ways to modify an existing object. Here's the first way:

```
$obj->name = 'John Williams';
$obj->email = 'new_email@example.com';
$obj->save();

```

And here's the second way, which may give you better performance in some cases:

```
$obj->save(array('name' => 'John Williams', 'email' => 'new_email@example.com'));

```

When using the first method, Beaver saves every property again, because it can't detect which properties have changed. When using the second method, only those properties that you specify in the array are updated.

### Deleting Objects (DELETE)

[](#deleting-objects-delete)

Here's how you delete an object:

```
$obj->delete();

```

Note that deleted objects can be re-inserted by calling `save()` again.

Beaver currently can't delete more than one object at the same time. If you need to delete many objects at the same time, write your own SQL query -- or better yet, see if you can use foreign keys to achieve the same effect without writing any additional queries.

### Finding Objects (SELECT)

[](#finding-objects-select)

Beaver provides several different ways to retrieve objects that have been previously saved.

If you know the primary key of the object you're looking for, this is by far the simplest method:

```
$obj = User::get($id);
echo $obj->name;
echo $obj->email;

```

Note that `get()` will return `null` if the primary key cannot be found. If you try to grab properties when it's `null`, PHP will slap you with a "fatal error". So you'll need to add some checks before you take your app anywhere near production.

If you want to fetch multiple objects at once, all by primary key:

```
$objects = User::get_array($id1, $id2, $id3, $id4 /* ... */ );
foreach ($objects as $obj)
{
    echo $obj->name;
    echo $obj->email;
}

```

Objects will be returned in the same order as the primary keys used in the argument. Objects that are not found will be returned as `null`, which means that the returned array may contain `null` in some places.

If you have a lot of primary keys to look up, you can also pass an array:

```
$primary_keys = array($id1, $id2, $id3, $id4 /* ... */ );
$objects = User::get_array($primary_keys);

```

#### Built-In Searching

[](#built-in-searching)

Now, this is where it gets fun.

If you want to fetch all users whose `group_id` is 42, this is what you do:

```
$objects = User::get_if_group_id(42);

```

Just call `get_if_()` and Beaver will hand you an array of all objects that match your query. This works with all properties, except those that begin with an underscore (`_`). (Properties that begin with an underscore are not mapped to database columns, as noted above.)

You can also sort the results by the same column, another column, or a combination of columns:

```
$objects = User::get_if_group_id(42, 'name+');
$objects = User::get_if_group_id(42, 'karma_points-');
$objects = User::get_if_group_id(42, 'name+', 20);
$objects = User::get_if_group_id(42, 'karma_points-,name+', 20, 40);

```

The first example above returns all users in group #42, sorted by name in ascending order. The second example returns all users in the same group, sorted by karma points in descending order. The third example is the same as the first example, but only returns the first 20 results. The fourth example sorts results by karma points in descending order followed by name in ascending order, skips the first 40 results, and returns the next 20. This is the kind of thing that you want in pagination.

If the `+` or `-` sign is omitted, ascending order is assumed.

Beaver also supports basic comparison operators when searching. For example, the following example returns all users whose age is 30 or greater.

```
$objects = User::get_if_age_gte(30, 'name+');

```

The next example returns the first 50 users whose age is between 30 and 40.

```
$objects = User::get_if_age_between(array(30, 40), 'id+', 50);

```

The next example returns the second page of the list of users whose name starts with "John" (20 per page, ordered by age).

```
$objects = User::get_if_name_startswith('John', 'age+', 20, 20);

```

In total, Beaver supports 12 operators for searching.

- `_gte` matches values that are greater than or equal to the argument.
- `_lte` matches values that are less than or equal to the argument.
- `_gt` matches values that are greater than, but not equal to, the argument.
- `_lt` matches values that are less than, but not equal to, the argument.
- `_between` matches values that are between two values, including the endpoints. *The argument must be an array.*
- `_xbetween` matches values that are between two values, excluding the endpoints. *The argument must be an array.*
- `_not` matches all values *except* the argument.
- `_in` matches any value that is listed in the argument. *The argument must be an array.*
- `_notin` matches any value that is not listed in the argument. *The argument must be an array.*
- `_startswith` matches all strings that start with the argument.
- `_endswith` matches all strings that end with the argument.
- `_contains` matches all strings that contains the argument.

Note that operators are evaluated only if the full method name does not match a property name. So if you have two properties named `age` and `age_lt`, all calls to `get_if_age_lt()` will be interpreted as an exact match on `age_lt`, rather than as a less-than match on `age`. If you find yourself in this rare situation and you need to do less-than matches on `age`, call `get_if_age__lt()` instead. (Notice the extra underscore that helps disambiguate your query.)

Searching may be slow if the columns you're using for searching and sorting are not indexed. Also, `_endswith` and `_contains` are always slow, so avoid these if you care about performance.

Case sensitivity of string comparisons depends on the type of database and other settings.

#### Custom Searching

[](#custom-searching)

Beaver can't do joins, subqueries, or anything else that isn't covered in the examples above. But even if Beaver can't write those queries for you, it can make it easier for you to make various `SELECT` queries in a convenient and secure way.

```
$objects = User::select('WHERE group_id IN (SELECT id FROM groups WHERE name = ?)', $param);

```

The second argument should be an array of parameters, corresponding to placeholders in the query string. Passing parameters separately is a very good way to prevent SQL injection vulnerabilities. If you don't have any parameters to pass, you can skip the second argument.

Queries such as the above can be encapsulated in a method of the `User` class. Beaver does not care if you add your own methods to classes, as long as you don't interfere with Beaver's core functions. You can, for example, implement your own `save()` method that performs some checks before calling `parent::save()`.

#### Limitations

[](#limitations)

The above syntax only works if the query returns individual rows, including the primary key. For queries that don't return individual rows (such as anything with a `GROUP BY` clause), and for all non-`SELECT` queries, you'll have to talk to the database connection (PDO object) directly.

The only exception is when you merely want to check if a row exists that matches your conditions. This is a common type of query, so Beaver 0.4.0 and above support an `exists()` method. The type and order of arguments are exactly the same as in the `select()` method:

```
$exists = User::exists('WHERE age > 40');

```

The above will return `true` if there exists any user whose age is greater than 40, and `false` otherwise. No other information is fetched from the database, and `exists()` will automatically add `LIMIT 1` to your query if it does not already include a limit clause. It is therefore much faster than using `get()` or `select()` to fetch records and counting them.

Caching
-------

[](#caching)

If you want Beaver to cache the result of a query for a while, just add another argument to `get()`, `get_array()`, `get_if_`, and `select()`.

```
$obj = User::get($id, 300);  // Cache for 300 seconds = 5 minutes.

```

Note that you need to use arrays when calling `get_array()` with a caching argument, because otherwise Beaver can't distinguish the caching argument from all the other arguments.

```
$primary_keys = array($id1, $id2, $id3, $id4 /* ... */ );
$objects = User::get_array($primary_keys, 300);

```

Likewise, when calling `get_if_()`, `select()` or `exists()` with a caching argument, make sure you don't skip optional arguments, such as sorting, limit/offset, or parameters. You can use `null` to skip the limit/offset arguments, and `array()` to indicate an empty parameter list.

```
$objects = User::get_if_age_lte(30, 'name+', null, null, 300);  // OK
$objects = User::get_if_age_lte(30, 300);                       // WRONG

$objects = User::select('WHERE group_id IS NULL', array(), 300);  // OK
$objects = User::select('WHERE group_id IS NULL', 300);           // WRONG

```

###  Health Score

27

—

LowBetter than 47% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity13

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity55

Maturing project, gaining track record

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

Recently: every ~13 days

Total

11

Last Release

4446d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/164058?v=4)[Kijin Sung](/maintainers/kijin)[@kijin](https://github.com/kijin)

---

Top Contributors

[![kijin](https://avatars.githubusercontent.com/u/164058?v=4)](https://github.com/kijin "kijin (47 commits)")

---

Tags

ormmysqlsqlitepgsqlmemcached

### Embed Badge

![Health badge](/badges/kijin-beaver/health.svg)

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

###  Alternatives

[doctrine/dbal

Powerful PHP database abstraction layer (DBAL) with many features for database schema introspection and management.

9.7k595.8M6.5k](/packages/doctrine-dbal)[scienta/doctrine-json-functions

A set of extensions to Doctrine that add support for json query functions.

58825.2M48](/packages/scienta-doctrine-json-functions)[cycle/orm

PHP DataMapper ORM and Data Modelling Engine

1.3k888.3k73](/packages/cycle-orm)[aura/sql

A PDO extension that provides lazy connections, array quoting, query profiling, value binding, and convenience methods for common fetch styles. Because it extends PDO, existing code that uses PDO can use this without any changes to the existing code.

5642.6M53](/packages/aura-sql)[aura/sqlquery

Object-oriented query builders for MySQL, Postgres, SQLite, and SQLServer; can be used with any database connection library.

4563.1M37](/packages/aura-sqlquery)[apix/cache

A thin PSR-6 cache wrapper with a generic interface to various caching backends emphasising cache taggging and indexing to Redis, Memcached, PDO/SQL, APC and other adapters.

114546.3k6](/packages/apix-cache)

PHPackages © 2026

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