Releases: nova-framework/framework
Add method Database\Query\Builder@addSelect
Merge pull request #907 from LuckyCyborg/master Add method Database\Query\Builder@addSelect, being required by ORM for May-to-Many relations
Quick Profiler
This pull request integrate in Nova Framework a small and smart Quick Profiler, very useful for forensics or debugging a application in the development stage.
And YES, I have myself the habit to use this way of debugging, while development.
The Quick Profiler while well integrated on Nova's System, is a standalone system, with no influence over the Classic or New Style APIs, and will be activated on 'development' ENVIRONMENT, while in the Profiler configuration the option useForensics is set to true.
A note of warning: this Quick Profiler is a Live Debugger and show lots of sensitive information, then is recommended to NOT be activated on production sites, even for short time.
The Quick Profiler is for Development Stage only!
What to expect from...
add some site-wide functions, required for the ORM
This pull request add some site-wide functions, required for the ORM to works on every detail, and introduce a small fix on Support\Facades\Session.
Another optimization is moving the execution of the Views associated Hooks from Core\Controller to a Event defined on app/Events.php, making their execution optional.
This ability is very useful when the Nova Framework is used to create a RESTful API, where is no need for execution of those Hooks.
Finally, this pull request introduce improvements and optimizations of Database\Connection, adding also a support for debugging.
Also, a small Google ReCaptcha Helpers is added.
added support for using **PostgresSQL** and **SQLite**
This pull request introduce in the Database API the support for using PostgresSQL and SQLite Databases also, behind of the MySQL ones.
To note that this pull request does NOT introduce any API changes of breaks.
New add_http function and times helper
added addhttp
This function ensures passed $url starts with http or https depending on the scheme.
Usage:
$url = 'novaframework.com';
$url = add_http($url); //http://novaframework.com
Added Times helper
This helper will take an array of times and add them together to get a
total time.
use Helpers\Times;
$times = array('10:23:00', '00:15:46', '1:04:56');
$counter = new Times($times);
echo $counter->getTotalTime();
//outputs: 11:43:42
database helper compatible with database api
This pull request improve the Helpers\Database and integrate it with the Database API, making possible to use it even when Database API is used too, without to duplicate the database connections.
The single visible change in API is that the optional parameter of the method Database::get() is now a string, defaulting to 'default', and indicating the Database API configuration entry used, instead of being a configuration array. Usage is simple:
// Get the default Database instance
$db = Database::get();
// Get a custom configured Database instance
$customDb = Database::get('custom');
To note that the API remains unchanged in the rest.
improved Legacy Rendering System + ORM
An improved Legacy Rendering System
Introduction
The improved Legacy Rendering System will queue the generated View and Template instances, along with the developer's calling of the Legacy View Calls.
They will be processed on the Controller's Middleware, when the current Action returns NULL, together with the given Legacy Header Calls, and there will be generated a Response instance and it will be sent according.
This Design permit a faster page / response generation and an improved compatibility and interchangeability between the Classic and New Style APIs.
Basic Usage
There are no changes on the user-exposed Legacy Rendering API.
Database API - Object Relational Models
- Introduction
- Basic Usage
- Mass Assignment
- Insert, Update, Delete
- Soft Deleting
- Timestamps
- Query Scopes
- Relationships
- Querying Relations
- Eager Loading
- Inserting Related Models
- Touching Parent Timestamps
- Working With Pivot Tables
- Collections
- Accessors & Mutators
- Date Mutators
- Model Events
- Model Observers
- Converting To Arrays / JSON
Introduction
The Database ORM included with Nova Framework provides a beautiful, simple ActiveRecord implementation for working with your database. Each database table has a corresponding "Model" which is used to interact with that table.
Before getting started, be sure to configure a database connection in app/Config/Database.php
.
Basic Usage
To get started, create an ORM model. Models typically live in the app/Models
directory, but you are free to place them anywhere that can be auto-loaded according to your composer.json
file.
Defining An ORM Model
class User extends \Database\ORM\Model {}
Note that we did not tell ORM which table to use for our User
model. The lower-case, plural name of the class will be used as the table name unless another name is explicitly specified. So, in this case, ORM will assume the User
model stores records in the users
table. You may specify a custom table by defining a table
property on your model:
class User extends \Database\ORM\Model {
protected $table = 'my_users';
}
Note: ORM will also assume that each table has a primary key column named
id
. You may define aprimaryKey
property to override this convention. Likewise, you may define aconnection
property to override the name of the database connection that should be used when utilizing the model.
Once a model is defined, you are ready to start retrieving and creating records in your table. Note that you will need to place updated_at
and created_at
columns on your table by default. If you do not wish to have these columns automatically maintained, set the $timestamps
property on your model to false
.
Retrieving All Models
$users = User::all();
Retrieving A Record By Primary Key
$user = User::find(1);
var_dump($user->name);
Note: All methods available on the QueryBuilder are also available when querying ORM models.
Retrieving A Model By Primary Key Or Throw An Exception
Sometimes you may wish to throw an exception if a model is not found, allowing you to catch the exceptions using an App::error
handler and display a 404 page.
$model = User::findOrFail(1);
$model = User::where('votes', '>', 100)->firstOrFail();
To register the error handler, listen for the ModelNotFoundException
use Database\ORM\ModelNotFoundException;
App::error(function(ModelNotFoundException $e)
{
return Response::make('Not Found', 404);
});
Querying Using ORM Models
$users = User::where('votes', '>', 100)->take(10)->get();
foreach ($users as $user)
{
var_dump($user->name);
}
ORM Aggregates
Of course, you may also use the query builder aggregate functions.
$count = User::where('votes', '>', 100)->count();
If you are unable to generate the query you need via the fluent interface, feel free to use whereRaw
:
$users = User::whereRaw('age > ? and votes = 100', array(25))->get();
Chunking Results
If you need to process a lot (thousands) of ORM records, using the chunk
command will allow you to do without eating all of your RAM:
User::chunk(200, function($users)
{
foreach ($users as $user)
{
//
}
});
The first argument passed to the method is the number of records you wish to receive per "chunk". The Closure passed as the second argument will be called for each chunk that is pulled from the database.
Specifying The Query Connection
You may also specify which database connection should be used when running an ORM query. Simply use the on
method:
$user = User::on('connection-name')->find(1);
Mass Assignment
When creating a new model, you pass an array of attributes to the model constructor. These attributes are then assigned to the model via mass-assignment. This is convenient; however, can be a serious security concern when blindly passing user input into a model. If user input is blindly passed into a model, the user is free to modify any and all of the model's attributes. For this reason, all ORM models protect against mass-assignment by default.
To get started, set the fillable
or guarded
properties on your model.
Defining Fillable Attributes On A Model
The fillable
property specifies which attributes should be mass-assignable. This can be set at the class or instance level.
class User extends \Database\ORM\Model {
protected $fillable = array('first_name', 'last_name', 'email');
}
In this example, only the three listed attributes will be mass-assignable.
Defining Guarded Attributes On A Model
The inverse of fillable
is guarded
, and serves as a "black-list" instead of a "white-list":
class User extends \Database\ORM\Model {
protected $guarded = array('id', 'password');
}
Note: When using
guarded
, you should still never passInput::get()
or any raw array of user controlled input into asave
orupdate
method, as any column that is not guarded may be updated.
Blocking All Attributes From Mass Assignment
In the example above, the id
and password
attributes may not be mass assigned. All other attributes will be mass assignable. You may also block all attributes from mass assignment using the guard property:
protected $guarded = array('*');
Insert, Update, Delete
To create a new record in the database from a model, simply create a new model instance and call the save
method.
Saving A New Model
$user = new User;
$user->name = 'John';
$user->save();
Note: Typically, your ORM models will have auto-incrementing keys. However, if you wish to specify your own keys, set the
incrementing
property on your model tofalse
.
You may also use the create
method to save a new model in a single line. The inserted model instance will be returned to you from the method. However, before doing so, you will need to specify either a fillable
or guarded
attribute on the model, as all ORM models protect against mass-assignment.
After saving or creating a new model that uses auto-incrementing IDs, you may retrieve the ID by accessing the object's id
attribute:
$insertedId = $user->id;
Setting The Guarded Attributes On The Model
class User extends \Database\ORM\Model {
protected $guarded = array('id', 'account_id');
}
Using The Model Create Method
// Create a new user in the database...
$user = User::create(array('name' => 'John'));
// Retrieve the user by the attributes, or create it if it doesn't exist...
$user = User::firstOrCreate(array('name' => 'John'));
// Retrieve the user by the attributes, or instantiate a new instance...
$user = User::firstOrNew(array('name' => 'John'));
Updating A Retrieved Model
To update a model, you may retrieve it, change an attribute, and use the save
method:
$user = User::find(1);
$user->email = '[email protected]';
$user->save();
Saving A Model And Relationships
Sometimes you may wish to save not only a model, but also all of its relationships. To do so, you may use the push
method:
$user->push();
You may also run updates as queries against a set of models:
$affectedRows = User::where('votes', '>', 100)->update(array('status' => 2));
Deleting An Existing Model
To delete a model, simply call the delete
method on the instance:
$user = User::find(1);
$user->delete();
Deleting An Existing Model By Key
User::destroy(1);
User::destroy(array(1, 2, 3));
User::destroy(1, 2, 3);
Of course, you may also run a delete query on a set of models:
$affectedRows = User::where('votes', '>', 100)->delete();
Updating Only The Model's Timestamps
If you wish to simply update the timestamps on a model, you may use the touch
method:
$user->touch();
Soft Deleting
When soft deleting a model, it is not actually removed from your database. Instead, a deleted_at
timestamp is set on the record. To enable soft deletes for a model, specify the softDelete
property on the model:
class User extends \Database\ORM\Model {
p...
minor patch for Respose
Merge pull request #889 from geomorillo/master changing use for Respose
improve the **Pagination API**
This pull request improve the Pagination API and its integration with Database API.
Also, it introduce a Facade for Pagination API and ability to configure the current page name, aka the query parameter which specify the Pagination's current Page. Usage:
use Paginator;
use DB;
// Set the custom Page Name
Paginator::setPageName('p');
// Get a Paginator instance from the QueryBuilder.
$paginate = DB::table('posts')->paginate(25);
// Print the Pagination Links.
echo $paginate->links();
// Process the current Page results.
foreach ($paginate->getItems() as $post) {
echo $post->title .'<br>';
}
Also, there is introduced the ability to specify per Model the number of Items returned for a Page on the Pagination\Paginator instance by QueryBuilder, using as following:
namespace App\Models;
use Database\Model;
class Users extends Model
{
/**
* The table associated with the Model.
*
* @var string
*/
protected $table = 'users';
/**
* The primary key for the Model.
*
* @var string
*/
protected $primaryKey = 'id';
/**
* The number of Records to return for pagination.
*
* @var int
*/
protected $perPage = 25;
}
That perPage setting will be honored, of course, on the Model's associated QueryBuilder instances.
Finally, the Database\Query\Builder API is enhanced for a better Pagination integration.
Pagination API
This pull request introduce a new Pagination API, in a Laravel-esque style, integrated with the Database API, permitting a very simple usage while offering a strong API.
Example of the Pagination API usage:
use DB;
// Get a Paginator instance from the QueryBuilder.
$paginate = DB::table('posts')->paginate(20);
// Add additional query parameters.
$paginate->appends(array(
'testing' => 1,
'example' => 'the_example_string',
));
// Get the Pagination Links.
$content = $paginate->links();
// Process the current Page results.
foreach ($paginate->getItems() as $post) {
$content .= '<h3>' .$post->title .'</h3>';
$content .= $post->content;
}
echo $content;
For a full control on QueryBuilder paginate():
// Get a full customized Paginator instance from the QueryBuilder.
$paginate = DB::table('posts')->paginate(25, array('*'));
Like you see, there is no need to instantiate the Pagination\Paginator yourself, the QueryBuilder returning a properly instance, which contains also the expected results for the current Page and accessible with the method getItems(), or even using directly the Paginator isntance. For example:
$content = $paginate->links();
// Process the current Page results.
foreach ($paginate as $post) {
$content .= '<h3>' .$post->title .'</h3>';
$content .= $post->content;
}
echo $content;
For rendering the Pagination Links, the Pagination\Paginator use the concept of Presenter, by default using the native one, Pagination\Presenter, compatible with the Bootstrap 3.x based templates, but it is possible to extend it and to use a custom Presenter instance, as following:
use App\Pagination\CustomPresenter;
use DB;
// Get a Paginator instance from the QueryBuilder.
$paginate = DB::table('posts')->paginate(20);
// Get a custom Presenter instance and setup it.
$presenter = new CustomPresenter($paginate);
echo $presenter->links();
Alternatively, you can setup the custom Presenter instance to be used by the Paginator instance directly by default.
$paginate->setPresenter($presenter);
// Print the custom Pagination Links.
echo $paginate->links();
To note that this Pagination API is a new feature of New Style APIs only, then it doesn't introduce any API break.