Skip to content

Releases: fabiocmazzo/rabbit-orm

Definition Functional Release

10 Jun 02:27
Compare
Choose a tag to compare

About Annotations

I work with Java for many years, and perhaps for this reason, has had the idea of using annotation in this project. Annotations or other object metadata are deeply missed in PHP, but thinking well and performing tests is not a good idea to simulate annotations in comments. Open a php file and parse the code to retrieve the annotations takes time and processing power. I decided to use constants to define each attribute and One constant for the definition of the entity. They will have the suffix definition with JSON code.
PS: For this particular use, constants will be implement in camelcase convention, we will not follow the convention and set all characters in uppercase because it will be used for another purpose.
Ex:

 class User extends RabbitORM\Model {

     const userDefinition = '{"name": "Users", "table": "users"}';

     private $idUser; 
     const idUserDefinition = '{"column":"id_user","primaryKey":"true"}';

     private $FirstName; 
     const firstNameDefinition = '{"column":"first_name"}';

     public getIdUser()...

 }

I strongly encourage, although not mandatory, encapsulate the attributes. It will be very useful to work with related entities.

Rabbit ORM

ORM for CodeIgniter based on Laravel's Eloquent. The Rabbit ORM brings the beauty and simplicity of working with Eloquent ORM in Laravel to CodeIgniter framework.

Installation

Download last release https://github.com/fabiocmazzo/rabbit-orm/releases

Extract to your application/libraries directory
In your config/autoload.php file, add elegant-orm/elegant to $autoload['libraries']. So it will look like this:

$autoload['libraries'] = array('rabbit-orm/Rabbitorm');

Usage

Defining Entities

Differently from our predecessor, models in CodeIgniter are preserved. Entities shall be saved in application/entities.

Example: Entity for table user, located in entities/user.php

class User extends RabbitORM\Model {

     const userDefinition = '{"name": "Users", "table": "users"}';

     private $idUser; 
     const idUserDefinition = '{"column":"id_user","primaryKey":"true"}';

     private $FirstName; 
     const firstNameDefinition = '{"column":"first_name"}';

     public getIdUser()...

 }

Fields definition in current source code

In current source code you must define Column for every property, this is required, unmapped fields will not be returned. This choice was made to become clearer definition of the entity in class, not bring unnecessary data from database and reduce the coupling to the database.

Model properties

Here are some properties you can use to customize the model

  • $table : to define the table name. This property is mandatory to set
  • $db_group : to define which database group the model will connect. The groups can be found in config/database.php. By default it uses "default" group
  • $incrementing : to define whether your PK is auto-increment. Default value is true. If you'd like to generate your Primary Key value by custom function, set this to false

Querying

Retrieve all models

$users = User::all();
foreach($users as $user)
{
  echo $user->name;
}

Find a model by primary key

$user = User::find(1);
echo $user->name;

You can also pass multiple IDs or an array to get multiple records.

$users = User::find(1, 2, 3);
// or
$users = User::find( array(1, 2, 3) );

Custom Query

You can still use Code Igniter Active Record to generate a custom query.

$users = User::where('status', 1)->get();

foreach($users as $user) echo $user->name;

Or if you only want to retrieve the first record, you can use first() method

$user = User::where('status', 1)->first();
echo $user->name;

'Pluck'-ing

Plucking is the way to retrieve a single column value of the first record.

// Returns the `name` column of the first row
echo 'Newest user is: ' . User::order_by('id', 'desc')->pluck('name');

Selecting Specific Columns

By default Rabbit will generate a SELECT * query for all examples above. If you think this is a bad practice, you can select only specific columns you need in several ways:

User::all( array('id', 'username') );
User::where('status', 1)->get( array('id', 'username') );
User::select( array('id', 'username') )->get();
User::where('status', 1)->first( array('id', 'username') );

Note: for now find() method doesn't support selecting specific column.

Aggregates Methods

Rabbit also provides aggregates method, such as max, min, avg, sum, and count. You can call these methods right away or chain them with some CI Active Records method.

$total = User::count();

$max = Product::max('price');

// Example of chaining with where()
$min = Product::where('category', 1)->min('price');

$avg = Product::avg('price');

// Another chaining example
$sum = Order::where('status', 1)->sum('price');

Create, Update & Delete

Creating A New Model

$user =  new User;

$user->name = 'John Doe';
$user->email = 'dummy@example.com';

$user->save();

After saving the record, if your model uses auto increment primary key, the generated insert id will be set to the object. So if you use example above, you can show the new user's ID right away

echo "New User ID: " . $user->id;

Note that the property isn't always id. It depends on the primary property you've set before.

Alternatively, you can use create method to create new models.

$user = User::create( array('name' => 'John Doe', 'email' => 'dummy@example.com') );

// create() method will return a newly created model or false if inserting fails
echo $user->id;

Updating Models

Updating Retrieved Model

$user = User::find(1);

$user->name = 'Jack Doe';
$user->save();

Mass Updating

You still can use CodeIgniter Active Record to generate a custom query before updating.

User::where('status', 1)->update( array('name' => 'Jane Doe') );

Or alternatively you can call update method right away.

User::update( array('name' => 'Jane Doe'), array('id' => 1) );
// The first parameter is the new data, and the second is the "where" condition

Deleting Models

There are several ways to delete model

// Delete retrieved model
$user = User::find(1);
$user->delete();

// Delete a single model by its primary key
User::delete(1);

// Delete multiple models by their primary keys
User::delete(1, 2, 3);
//or
User::delete( array(1, 2, 3) );

// Use Active Record
User::where('status', 1)->delete();

Query Scopes

Scopes is a custom function you can create in your models to generate custom queries

Defining A Scope

Some conventions:

  • Scope method name must be in camel case
  • Scope method name must be start with scope
  • At least one parameter is required. This first parameter is a QueryBuilder which you can use to call Active Record methods
class User extends Rabbit\Model {
  protected $table = "user";

  function scopeActive($query)
  {
    return $query->where('status', 1)->order_by('name');
  }
}

Utilizing Scopes

Using example above, you can do this in your controller

$active_users = User::active()->get();

Note that the method name isn't using scope prefix.

Dynamic Scopes

Scopes can also accept parameters to be used in generating queries.

class User extends Rabbit\Model {
  protected $table = "user";

  // Search an active user by name
  function scopeSearch($query, $keyword)
  {
    return $query->like('name', $keyword)->where('status', 1);
  }
}

// In your controller
$search_results = User::search('John')->get();

Relationship

One to One

Defining One to One Relationship

This the example how to define a one-to-one relationship between a User model with Phone. In this case, a User might have one Phone

class User extends Rabbit\Model {
  protected $table = "user";

  function phone()
  {
    return $this->hasOne('Phone');
  }
}

The parameter to hasOne method is the name of the related model. Once the relationship set you can retrieve it in you controller this way:

$user = User::find(1);
$phone = $user->phone;
// You can work with $phone object like the usual way

// Returns its property
echo $phone->brand;

// Or updates it
$phone->brand = "Samsung";
$phone->save();

Note: the name of the method where you call the hasOne isn't have to be the same with the related model name. You can name it anything you want, just make sure it doesn't conflict with exisiting table field name.

In the example above the foreign key in phone table is assumed to be user_id (lowercased related model's name with _id suffix). You can define custom key name as second parameter if your foreign key doesn't match this convention.

$this->hasOne('Phone', 'custom field name');

Defining the Inverse Relationship

You can also define the inverse of the relationship. For the example after you get a Phone object, you want to know who is the name owner. In the Phone model you have to call the belongsTo method.

class Phone extends Rabbit\Model {
  protected $table = "phone";

  function owner()
  {
    return $this->belongsTo('User');
  }
}

// In your controller:
$phone = Phone::find(1);

echo $phone->owner->name;

You can also define a custom foreign key as second parameter to belongsTo method.

One to Many

Defining One to Many Relationship

An example of one to many relationship is an article can has one or many comments. To define such relationship, you can do this:

class Article extends Rabbit\Model {
  protected $table = "article";

  function comments()
  {
    return $this->hasMany('Comment');
  }
}

The difference between hasOne and hasMany is the hasMany will return an array of matched models, while hasOne will ret...

Read more

FunctionalRelease

08 Jun 02:14
Compare
Choose a tag to compare

First Functional Release of RabbitORM Project. Tested on CodeIgniter 3.0.6