PHPackages                             andyfleming/handy - 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. andyfleming/handy

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

andyfleming/handy
=================

Handy Model class for amazing data magic.

v1.2.4(12y ago)44853[1 PRs](https://github.com/andyfleming/handy/pulls)Apache 2.0PHPPHP &gt;=5.3.0

Since Jan 27Pushed 9y ago1 watchersCompare

[ Source](https://github.com/andyfleming/handy)[ Packagist](https://packagist.org/packages/andyfleming/handy)[ Docs](http://github.com/andyfleming/handy)[ RSS](/packages/andyfleming-handy/feed)WikiDiscussions master Synced 1w ago

READMEChangelogDependenciesVersions (13)Used By (0)

\#Handy

Handy is a utility for managing MySQL models, etc.

Quick Start
-----------

[](#quick-start)

**person.class.php**

```
class Person extends HandyModel {
	const TABLE_NAME = 'people';
}
```

**example.php**

```
# ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
#	Setup
# ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––

	// Setup database handle
	$dbh = new mysqli( $host, $user, $pass, $database );

	// Pass Handy the database handle
	Handy::setDefaultDB($dbh);

	// Require class
	require "person.class.php";

# ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
#	Usage
# ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––

	// Get each person over 30
	$people = Person::lookupEach("age > 30");

	// Handy returns an array of Person objects by ID (or empty array)
	if (count($people) > 0) {
	    foreach ($people as $person) {
	    	echo $person->get('first_name').": ".$person->get('age');
	        echo "";
	    }
	}

```

Comparison to traditional syntax
--------------------------------

[](#comparison-to-traditional-syntax)

### Add new person and fetch them back as a Person (class) object

[](#add-new-person-and-fetch-them-back-as-a-person-class-object)

**Traditional:**

```
$db->query("INSERT INTO `people` SET `x`='y', `a`='b'");

$newPersonID = $db->insert_id;
$newPerson = $db->query("SELECT * FROM `people` WHERE `id` = '{$newPersonID}'");

$newPerson = $newPerson->fetch_object('Person');
```

**With Handy:**

```
$newPerson = Person::create(array(
	'x' => 'y',
	'a' => 'b'
));
```

Documentation
-------------

[](#documentation)

- [Basic Usage](#basic-usage)
    - [Basic Item Class](#basic-item-class)
    - [Item Creation](#item-creation)
    - [Item Lookup by ID](#item-lookup-by-id)
    - [Item Lookup WHERE](#item-lookup-where)
    - [Multiple Item Lookup by WHERE](#multiple-item-lookup-by-where)

Basic Usage
-----------

[](#basic-usage)

### Basic Item Class

[](#basic-item-class)

```
class Person extends HandyModel {

	const TABLE_NAME = 'people';

}
```

### Item Creation

[](#item-creation)

```
Person::create(array(
	'first_name' => 'John',
	'last_name' => 'Smith'
);
```

### Item Lookup by ID

[](#item-lookup-by-id)

ModelName::lookupByID( *ID* )

```
$person = Person::lookupByID(12);

// Returns single Person object or false
if (!$person) {
	echo "Person 12 was not found!";
} else {
	echo "Person 12's first name is ".$person->get('first_name');
}
```

### Item Lookup by WHERE

[](#item-lookup-by-where)

ModelName::lookup( *WHERE clause* (optional) )

```
$person = Person::lookup("`first_name`='Bob'");

// Returns single Person object or false
```

### Multiple Item Lookup by WHERE

[](#multiple-item-lookup-by-where)

ModelName::lookupEach( *WHERE clause* (optional) )

```
$people = Person::lookupEach("age > 30");

// Returns array of Person objects by ID or empty array

if (count($people) == 0) {
	echo 'No one found!';
} else {
	foreach ($people as $person) {
		echo $person->get('first_name').": ".$person->get('age');
		echo "";
	}
}

/*

Array people
	17 => Object Person
	27 => Object Person
	28 => Object Person

*/
```

### Item Lookup Random by WHERE

[](#item-lookup-random-by-where)

ModelName::lookupRandom( *WHERE clause (optional)* )

```
$person = Person::lookupRandom("`age` > 30");

// Returns single (random) Person object or false
```

Advanded Usage
--------------

[](#advanded-usage)

### \_\_extensionConstruct()

[](#__extensionconstruct)

### \_\_postCreate()

[](#__postcreate)

Goals and the Future
--------------------

[](#goals-and-the-future)

- Possibly migrate from MySQLI to PDO
- Consider expanding functionality to include other database types other than MySQL
- Add option to select only certain fields or JOIN
- Show recommended syntax for adding custom lookup methods or overriding

Changelog
---------

[](#changelog)

**1.2.4** – Fixes for custom UID name.

**1.2.3** – Changed $uidName to static property and implemented more fully.

**1.2.2** – Added `setEscaped` method

**1.2.1** – Added support for using alternate unique id name. Should be set in HandyModel class extension with `protected $uidName = 'alt_uid'`, (defaults to `id`).

**1.2.0** – Added support for multiple data sources. Limit 1 per model class. `Handy::setDefaultDB($dbh)` or `Handy::setModelDB('ModelName',$dbh)`

**1.1.4** — Fixes for new static methods access

**1.1.3** — Changed database handle setup to `Handy::setDB($databaseHandlerVariable);`

**1.1.2** — README udpates

**1.1.1** — Fixes and updated README

**1.1.0** — Simplification of calls. Static methods moved to main model class `Handy::getByID('Person',12)` is now `Person::getByID(12)`

**1.0.1** — Fixes, etc

**1.0.0** — Initial Release

###  Health Score

32

—

LowBetter than 70% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity19

Limited adoption so far

Community11

Small or concentrated contributor base

Maturity65

Established project with proven stability

 Bus Factor1

Top contributor holds 93.8% 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 ~19 days

Recently: every ~44 days

Total

12

Last Release

4667d ago

### Community

Maintainers

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

---

Top Contributors

[![andyfleming](https://avatars.githubusercontent.com/u/721038?v=4)](https://github.com/andyfleming "andyfleming (30 commits)")[![chrishiestand](https://avatars.githubusercontent.com/u/100825?v=4)](https://github.com/chrishiestand "chrishiestand (2 commits)")

---

Tags

phpmysqlmodel

### Embed Badge

![Health badge](/badges/andyfleming-handy/health.svg)

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

###  Alternatives

[watheqalshowaiter/model-fields

Get model fields fast — required, nullable, or default

401.4k](/packages/watheqalshowaiter-model-fields)[eftec/pdoone

Minimaist procedural PDO wrapper library

1116.1k9](/packages/eftec-pdoone)

PHPackages © 2026

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