Generate
Code Generation can be used to speed up development times by building much of the repetitive code for you. This is entirely optionally - like all of oil - and all code can be edited however you like afterwards. You can generate the following items:
- Controllers
- Models
- Presenters
- Migrations
- Scaffolding
- Admin scaffolding
- Tasks
- Configs
- Packages
- Modules
Controllers
To generate a skeleton Controller with actions and views predefined, use the following command:
$ php oil g controller posts action1 action2 action3
Created view: APPPATH/views/posts/action1.php
Created view: APPPATH/views/posts/action2.php
Created view: APPPATH/views/posts/action3.php
Created controller: APPPATH/classes/controller/posts.php
This will produce a controller that looks like this:
class Controller_Posts extends Controller_Template
{
public function action_action1()
{
$this->template->title = 'Posts » Action1';
$this->template->content = View::forge('posts/action1');
}
public function action_action2()
{
$this->template->title = 'Posts » Action2';
$this->template->content = View::forge('posts/action2');
}
public function action_action3()
{
$this->template->title = 'Posts » Action3';
$this->template->content = View::forge('posts/action3');
}
}
/* End of file posts.php */
Models
Generate a simple Model by listing fields and have the Migration automatically created for you to match:
$ php oil g model post title:varchar[50] body:text user_id:int
Created model: APPPATH/classes/model/post.php
Created migration: APPPATH/migrations/001_create_posts.php
That will create a simple Model that uses Orm, so make sure the package is enabled in your config file. It will look like this:
class Model_Post extends Orm\Model {
protected static $_properties = array(
'id',
'title',
'body',
'created_at',
'updated_at'
);
protected static $_observers = array(
'Orm\Observer_CreatedAt' => array(
'events' => array('before_insert'),
'mysql_timestamp' => false,
),
'Orm\Observer_UpdatedAt' => array(
'events' => array('before_save'),
'mysql_timestamp' => false,
),
);
}
/* End of file post.php */
Not very exciting, but the migration is the useful part here:
namespace Fuel\Migrations;
class Create_posts
{
public function up()
{
\DBUtil::create_table('posts', array(
'id' => array('constraint' => 11, 'type' => 'int', 'auto_increment' => true),
'title' => array('constraint' => 50, 'type' => 'varchar'),
'body' => array('type' => 'text'),
'user_id' => array('constraint' => 11, 'type' => 'int'),
'created_at' => array('type' => 'datetime'),
), array('id'));
}
public function down()
{
\DBUtil::drop_table('posts');
}
}
If you do not wish to generate a migration, simply supply the --no-migration
:
$ php oil g model post title:varchar[50] body:text user_id:int --no-migration
Created model: APPPATH/classes/model/post.php
By default, the class name is generated singular (it represents one post), but the corresponding table is generated
in plural (in contains multiple posts). You can make the table use the same name as the model by using --singular
.
Generating Model using Model_Crud
FuelPHP v1.1 added a simple Model_Crud base model which offers similar functionality of using ORM without overhead of relational data. You can have the model generated using this by adding --crud
$ php oil g model post title:varchar[50] body:text user_id:int created_at:datetime --crud
Created model: APPPATH/classes/model/post.php
Created migration: APPPATH/migrations/001_create_posts.php
That will create a simple Model that uses Fuel\Core\Model_Crud. It will look like this:
class Model_Post extends \Model_Crud
{
protected static $_properties = array(
'id',
'title',
'body',
'user_id',
'created_at',
'updated_at'
);
protected static $_table_name = 'posts';
}
Generating Model Without Timestamp Option
Add --no-timestamp
to exclude the created/updated fields and observers.
$ php oil g model post title:varchar[50] body:text user_id:int --no-timestamp
class Model_Post extends \Orm\Model
{
protected static $_properties = array(
'id',
'title',
'body',
'user_id'
);
}
namespace Fuel\Migrations;
class Create_posts
{
public function up()
{
\DBUtil::create_table('posts', array(
'id' => array('constraint' => 11, 'type' => 'int', 'auto_increment' => true),
'title' => array('constraint' => 50, 'type' => 'varchar'),
'body' => array('type' => 'text'),
'user_id' => array('constraint' => 11, 'type' => 'int'),
), array('id'));
}
public function down()
{
\DBUtil::drop_table('posts');
}
}
Changing the Timestamp and Timestamp Fields
When you're using the timestamp fields in either ORM models or CRUD models (\Model_Crud) you can
chose your own field names. Use the --created-at
and --updated-at
options to set your own field names.
By default, when you enable timestamps, the timestamps are stored in unixtime, as an integer. If you
prefer the MySQL DATETIME format, you can use the --mysql-timestamp
option.
$ php oil g model post title:varchar[50] body:text user_id:int --mysql-timestamp --created-at=my_created
Which will give you:
<?php
class Model_Post extends \Orm\Model
{
protected static $_properties = array(
'id',
'title',
'body',
'user_id',
'my_created',
'updated_at'
);
protected static $_observers = array(
'Orm\Observer_CreatedAt' => array(
'events' => array('before_insert'),
'mysql_timestamp' => true,
'property' => 'my_created',
),
'Orm\Observer_UpdatedAt' => array(
'events' => array('before_save'),
'mysql_timestamp' => true,
),
);
}
<?php
namespace Fuel\Migrations;
class Create_posts
{
public function up()
{
\DBUtil::create_table('posts', array(
'id' => array('constraint' => 11, 'type' => 'int', 'auto_increment' => true),
'title' => array('constraint' => 50, 'type' => 'varchar'),
'body' => array('type' => 'text'),
'user_id' => array('constraint' => 11, 'type' => 'int'),
'my_created' => array('constraint' => 11, 'type' => 'int'),
'updated_at' => array('constraint' => 11, 'type' => 'int'),
), array('id'));
}
public function down()
{
\DBUtil::drop_table('posts');
}
}
Generating Model using Model_Soft
FuelPHP v1.5 added a Model_Soft based ORM model. Add --soft-delete
to use Model_Soft.
$ php oil g model post title:varchar[50] body:text user_id:int --soft-delete
Which will give you:
<?php
class Model_Post extends \Orm\Model_Soft
{
protected static $_properties = array(
'id',
'title',
'body',
'user_id',
'created_at',
'updated_at',
'deleted_at',
);
protected static $_observers = array(
'Orm\Observer_CreatedAt' => array(
'events' => array('before_insert'),
'mysql_timestamp' => false,
),
'Orm\Observer_UpdatedAt' => array(
'events' => array('before_update'),
'mysql_timestamp' => false,
),
);
protected static $_soft_delete = array(
'mysql_timestamp' => false,
);
}
<?php
namespace Fuel\Migrations;
class Create_posts
{
public function up()
{
\DBUtil::create_table('posts', array(
'id' => array('constraint' => 11, 'type' => 'int', 'auto_increment' => true, 'unsigned' => true),
'title' => array('constraint' => 50, 'type' => 'varchar'),
'body' => array('type' => 'text'),
'user_id' => array('constraint' => 11, 'type' => 'int'),
'created_at' => array('constraint' => 11, 'type' => 'int', 'null' => true),
'updated_at' => array('constraint' => 11, 'type' => 'int', 'null' => true),
'deleted_at' => array('constraint' => 11, 'type' => 'int', 'null' => true),
), array('id'));
}
public function down()
{
\DBUtil::drop_table('posts');
}
}
If you wish changing deleted_at field name. Use the --deleted-at
option to set your own field name.
$ php oil g model post title:varchar[50] body:text user_id:int --soft-delete --deleted-at=mydeleted
Generating Model using Model_Temporal
Add --temporal
to use Model_Temporal.
$ php oil g model post title:varchar[50] body:text user_id:int --temporal
Which will give you:
<?php
class Model_Post extends \Orm\Model_Temporal
{
protected static $_properties = array(
'id',
'temporal_start',
'temporal_end',
'title',
'body',
'user_id',
);
protected static $_temporal = array(
'mysql_timestamp' => false,
);
protected static $_primary_key = array('id', 'temporal_start', 'temporal_end');
protected static $_table_name = 'posts';
}
<?php
namespace Fuel\Migrations;
class Create_posts
{
public function up()
{
\DBUtil::create_table('posts', array(
'id' => array('constraint' => 11, 'type' => 'int', 'auto_increment' => true, 'unsigned' => true),
'temporal_start' => array('constraint' => 11, 'type' => 'int'),
'temporal_end' => array('constraint' => 11, 'type' => 'int'),
'title' => array('constraint' => 50, 'type' => 'varchar'),
'body' => array('type' => 'text'),
'user_id' => array('constraint' => 11, 'type' => 'int'),
), array('id'));
}
public function down()
{
\DBUtil::drop_table('posts');
}
}
Please note that temporal_start and temporal_end are not added to the migration's primary_key array. You have to add them manually.
--no-timestamp
is set to true by default which means both created_at and updated_at fields and the related observers are ommited. You can bypass this default with --no-timestamp=0
to get them back.
If you wish changing temporal_start or temporal_end field name. Use --temporal-start
or --temporal-end
option to set your own field name.
$ php oil g model post title:varchar[50] body:text user_id:int --temporal --temporal-start=mystart --temporal-end=myend
Generating Model using Model_Nestedset
Add --nestedset
to use Model_Nestedset.
$ php oil g model post title:varchar[50] body:text user_id:int --nestedset
Which will give you:
<?php
class Model_Post extends \Orm\Model_Nestedset
{
protected static $_properties = array(
'id',
'left_id',
'right_id',
'title',
'body',
'user_id',
);
protected static $_table_name = 'posts';
}
<?php
namespace Fuel\Migrations;
class Create_posts
{
public function up()
{
\DBUtil::create_table('posts', array(
'id' => array('constraint' => 11, 'type' => 'int', 'auto_increment' => true, 'unsigned' => true),
'left_id' => array('constraint' => 11, 'type' => 'int', 'unsigned' => true),
'right_id' => array('constraint' => 11, 'type' => 'int', 'unsigned' => true),
'title' => array('constraint' => 50, 'type' => 'varchar'),
'body' => array('type' => 'text'),
'user_id' => array('constraint' => 11, 'type' => 'int'),
), array('id'));
}
public function down()
{
\DBUtil::drop_table('posts');
}
}
--no-timestamp
is set to true by default which means both created_at and updated_at fields and the related observers are ommited.You can bypass this default with --no-timestamp=0
to get them back.
If you wish changing title, tree_id, left_id, right_id field name. Use one of --title
, --tre-id
, --left-id
, --right-id
options to set your own field name.
$ php oil g model post title:varchar[50] body:text user_id:int --nestedset --title=mytitle --tree-id=mytreeid --left-id=myleftid --right-id=myrightid
Presenters
Optionally you have have oil to generate a Presenter class to accompany the view.
$ php oil g controller posts action1 action2 action3 --with-presenter
Running Migrations
The following commands illustrate how to use the refine command to run useful migration tasks, assuming that the system is currently at migration 5. The migrate task can be given parameters to move directly to a given version, or just up/down by a single version.
$ php oil refine migrate
Currently on migration: 5.
$ php oil refine migrate --version=4
Migrated to version: 4.
$ php oil refine migrate --version=5
Migrated to version: 5.
$ php oil refine migrate:down
Migrated to version: 4.
$ php oil refine migrate:up
Migrated to version: 5.
The following field types are supported: string[n], varchar[n], int[n], enum[value1, value2], decimal[n, n], float[n, n], text, blob, datetime, date, timestamp and time.
If you are using Windows Powershell to execute oil commands, you need to enclose parameters with a comma in quotes (decimal['n, n']) so Powershell doesn't see them as arrays. Alternatively, you can use Git Bash, especially if you are a git user too.
Generating Migrations
You can generate migrations without creating a model. This could be used to rename a table, or add fields to a table in a way that is easy to deploy in other environments.
$ php oil generate migration rename_table_users_to_accounts
Building magic migration: rename_table
Created migration: APPPATH/migrations/002_rename_table_users_to_accounts.php
Magic Migrations
There are a number of "magic" migrations which automatically build you a migration based on a prefix to your migration name.
$ php oil generate migration create_users name:text email:string[50] password:string[125]
$ php oil generate migration rename_table_users_to_accounts
$ php oil generate migration add_bio_to_accounts bio:text
$ php oil generate migration delete_bio_from_accounts bio:text
$ php oil generate migration rename_field_name_to_username_in_accounts
$ php oil generate migration drop_accounts
Note: Be careful when naming your migrations that you don't begin with any keywords by accident.
Scaffolding
Scaffolding is the really exciting part of Oil's code generation. This approach is heavily borrowed from Rails who have done a great job with it. The idea is that you create not only the MVC skeletons and migrations, but populate them with default CRUD code so the code will actually work after writing the command.
$ php oil g scaffold monkey name:string description:text
Created model: APPPATH/classes/model/monkey.php
Created migration: APPPATH/migrations/003_create_monkeys.php
Created controller: APPPATH/classes/controller/monkeys.php
Created view: APPPATH/views/monkeys/index.php
Created view: APPPATH/views/monkeys/view.php
Created view: APPPATH/views/monkeys/create.php
Created view: APPPATH/views/monkeys/edit.php
Created view: APPPATH/views/monkeys/_form.php
$ php oil refine migrate
Migrated to latest version: 3.
As you can see lots of code is generated by this command including a command that is executed in the second command. The controller looks like this:
class Controller_Monkey extends Controller_Template
{
public function action_index()
{
$data['monkeys'] = Model_Monkey::find('all');
$this->template->title = "Monkeys";
$this->template->content = View::forge('monkey/index', $data);
}
public function action_view($id = null)
{
$data['monkey'] = Model_Monkey::find($id);
$this->template->title = "Monkey";
$this->template->content = View::forge('monkey/view', $data);
}
public function action_create($id = null)
{
if (Input::method() == 'POST')
{
$monkey = Model_Monkey::forge(array(
'name' => Input::post('name'),
'description' => Input::post('description'),
));
if ($monkey and $monkey->save())
{
Session::set_flash('success', 'Added monkey #'.$monkey->id.'.');
Response::redirect('monkey');
}
else
{
Session::set_flash('error', 'Could not save monkey.');
}
}
$this->template->title = "Monkeys";
$this->template->content = View::forge('monkey/create');
}
public function action_edit($id = null)
{
$monkey = Model_Monkey::find($id);
if (Input::method() == 'POST')
{
$monkey->name = Input::post('name');
$monkey->description = Input::post('description');
if ($monkey->save())
{
Session::set_flash('success', 'Updated monkey #' . $id);
Response::redirect('monkey');
}
else
{
Session::set_flash('error', 'Could not update monkey #' . $id);
}
}
else
{
$this->template->set_global('monkey', $monkey, false);
}
$this->template->title = "Monkeys";
$this->template->content = View::forge('monkey/edit');
}
public function action_delete($id = null)
{
if ($monkey = Model_Monkey::find($id))
{
$monkey->delete();
Session::set_flash('success', 'Deleted monkey #'.$id);
}
else
{
Session::set_flash('error', 'Could not delete monkey #'.$id);
}
Response::redirect('monkey');
}
}
Admin scaffolding
You can swap scaffold with admin and generate a controller which extends Controller_Admin instead of Controller_Template. On the first use of this command an admin skeleton will be generated, to expand this skeleton use the skip force argument. To generate in subdirectories name the prefix the model's name accordingly.
$ php oil g admin project_entry title:string abstract:text full_text:text project_id:int is_draft:int order:int -s
Creating migration: APPPATH/migrations/012_create_project_entries.php
Creating model: APPPATH/classes/model/project/entry.php
Creating controller: APPPATH/classes/controller/admin/project/entry.php
Creating view: APPPATH/views/admin/project/entry/index.php
Creating view: APPPATH/views/admin/project/entry/view.php
Creating view: APPPATH/views/admin/project/entry/create.php
Creating view: APPPATH/views/admin/project/entry/edit.php
Creating view: APPPATH/views/admin/project/entry/_form.php
Tasks
You can also have oil generate the skeleton of a new task.
$ php oil g task newtask cmd1 cmd2
Which will generate
<?php
namespace Fuel\Tasks;
class Newtask
{
public static function run($args = NULL)
{
echo "\n===========================================";
echo "\nRunning DEFAULT task [Newtask:Run]";
echo "\n-------------------------------------------\n\n";
/***************************
Put in TASK DETAILS HERE
**************************/
}
public static function cmd1($args = NULL)
{
echo "\n===========================================";
echo "\nRunning task [Newtask:Cmd1]";
echo "\n-------------------------------------------\n\n";
/***************************
Put in TASK DETAILS HERE
**************************/
}
public static function cmd2($args = NULL)
{
echo "\n===========================================";
echo "\nRunning task [Newtask:Cmd2]";
echo "\n-------------------------------------------\n\n";
/***************************
Put in TASK DETAILS HERE
**************************/
}
}
/* End of file tasks/newtask.php */
Configs
To generate a Config, use the following command:
$ php oil g config sample hello:world
Created config: APPPATH/config/sample.php
This will produce a config that looks like this:
return array (
'hello' => 'world',
);
/* End of file sample.php */
Generate Config from COREPATH
To combine config from COREPATH/config if APPPATH/config doesn't have one
$ php oil g config package
Created config: APPPATH/config/package.php
This will produce a config that looks like this:
return array (
'sources' =>
array (
0 => 'github.com/fuel-packages',
),
);
Force Update Config from COREPATH & APPPATH
To combine config from COREPATH/config and combine APPPATH/config to APPPATH/config
$ php oil g config form --overwrite
Created config: APPPATH/config/form.php
This will produce a config that looks like this:
return array (
'prep_value' => true,
'auto_id' => true,
'auto_id_prefix' => '',
'form_method' => 'post',
);
/* End of file form.php */
Packages
To generate a Package, use the following command:
$ php oil g package sample
Creating file: PKGPATH/sample/classes/sample.php
Creating file: PKGPATH/sample/config/sample.php
Creating file: PKGPATH/sample/bootstrap.php
The path where the package is generated is PKGPATH by default, but this value can be changed to any path defined in the package_paths
config by passing the --path=package_path
or -p=package_path
option to the command.
Generate Driver-based Package
If you wish to generate a driver-based package, simply supply the --drivers
or -d
option:
$ php oil g package sample -d
Creating file: PKGPATH/sample/classes/sample.php
Creating file: PKGPATH/sample/classes/sample/driver.php
Creating file: PKGPATH/sample/config/sample.php
Creating file: PKGPATH/sample/bootstrap.php
You can also generate your own drivers. Simply pass the driver names separated by commas to the --drivers
or -d
option:
$ php oil g package sample -d=driver1,driver2
Creating file: PKGPATH/sample/classes/sample.php
Creating file: PKGPATH/sample/classes/sample/driver.php
Creating file: PKGPATH/sample/classes/sample/driver1.php
Creating file: PKGPATH/sample/classes/sample/driver2.php
Creating file: PKGPATH/sample/config/sample.php
Creating file: PKGPATH/sample/bootstrap.php
Generate Package with VCS files
If you wish to generate composer.json and README.md files for your package, simply supply the --vcs
or -v
option:
$ php oil g package sample -v
Creating file: PKGPATH/sample/composer.json
Creating file: PKGPATH/sample/README.md
Creating file: PKGPATH/sample/classes/sample.php
Creating file: PKGPATH/sample/config/sample.php
Creating file: PKGPATH/sample/bootstrap.php
Modules
To generate a Module, use the following command:
$ php oil g module blog
This command will create a folder called blog
in you app's module path defined in config.module_paths
. If you have multiple module paths defined, you will get a list of paths that you can choose from, e.g.:
$ php oil g module blog
Your app has multiple module paths defined. Please choose the appropriate path from the list below
[1] /var/www/fuel/shared/modules/
[2] /var/www/fuel/app/modules/
To provide for even easier module generation, you can supply the --folders
option with a list of comma-separated folders to be created. These can be nested almost indefinitely and you don't need to provide every parent folder. A short yet useful example can be:
$ php oil g module blog --folders=classes/model,classes/controller,config,lang