diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 0000000..550e711
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,45 @@
+on:
+ push:
+ branches: [ 'master' ]
+ pull_request:
+ branches: [ 'master' ]
+
+permissions:
+ contents: read
+
+jobs:
+ run:
+ runs-on: ubuntu-latest
+
+ strategy:
+ fail-fast: false
+ matrix:
+ php-versions: [ '5.4', '5.5', '5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3' ]
+
+ name: Run Unit Test on PHP ${{ matrix.php-versions }}
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+
+ - name: Install PHP
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: ${{ matrix.php-versions }}
+
+ - name: Check the PHP version
+ run: php -v
+
+ - name: Validate composer.json and composer.lock
+ run: composer validate --strict
+
+ - name: Install dependencies
+ run: composer install --prefer-dist --no-progress
+
+ - name: Run test suite
+ run: vendor/bin/phpunit --coverage-clover=coverage.clover
+
+ - name: Upload coverage to Codecov
+ uses: codecov/codecov-action@v4-beta
+ env:
+ CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 52f6cfc..6e17c22 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,11 @@
+.php-cs-fixer.cache
.phpintel
+.phpunit.result.cache
build
+combustor.bak
+combustor.yml
composer.lock
-docs
+tests/Fixture/Sample/controllers
+tests/Fixture/Sample/models
+tests/Fixture/Sample/views
vendor
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 99f5cb9..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,34 +0,0 @@
-dist: xenial
-language: php
-os: linux
-
-php:
- - 5.6
- - 7.0
- - 7.1
- - 7.2
- - 7.3
- - 7.4
-
-jobs:
- include:
- # - php: 5.3
- # dist: precise
- - php: 5.4
- dist: trusty
- - php: 5.5
- dist: trusty
-
-before_install:
- - echo "memory_limit=-1" >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini
-
-before_script:
- - npm install -g bower
- - travis_retry composer self-update
- - travis_retry composer update ${COMPOSER_FLAGS} --no-interaction --prefer-source
-
-script:
- - vendor/bin/phpunit --coverage-text --coverage-clover=coverage.clover
-
-after_script:
- - if [[ $TRAVIS_PHP_VERSION != 'hhvm' && $TRAVIS_PHP_VERSION != '7.0' ]]; then php vendor/bin/ocular code-coverage:upload --format=php-clover coverage.clover; fi
diff --git a/CHANGELOG.md b/CHANGELOG.md
index dbed6e7..63780e5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,28 @@
All notable changes to `Combustor` will be documented in this file.
+## [1.3.0](https://github.com/rougin/transcribe/compare/v1.2.4...v1.3.0) - Unreleased
+
+### Added
+- Command for creating `combustor.yml` configuration file
+- Fields that can be excluded through `excluded_files`
+- Specify customized `application` path using `app_path`
+
+### Changed
+- Code coverage provider to `Codecov`
+- Code documentation by `php-cs-fixer`
+- Improved code quality by `phpstan`
+- Main argument `name` to `table` in `Commands`
+- Simplified code structure
+- Workflow provider to `Github Actions`
+
+### Removed
+- Options to strictly conform in coding style of `Codeigniter`:
+ - `--camel`
+ - `--keep`
+ - `--lowercase`
+- `CONTRIBUTING.md`
+
## [1.2.4](https://github.com/rougin/combustor/compare/v1.2.3...v1.2.4) - 2018-04-18
### Fixed
diff --git a/CONDUCT.md b/CONDUCT.md
deleted file mode 100644
index 6ff94ca..0000000
--- a/CONDUCT.md
+++ /dev/null
@@ -1,22 +0,0 @@
-# Contributor Code of Conduct
-
-As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
-
-We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or nationality.
-
-Examples of unacceptable behavior by participants include:
-
-* The use of sexualized language or imagery
-* Personal attacks
-* Trolling or insulting/derogatory comments
-* Public or private harassment
-* Publishing other's private information, such as physical or electronic addresses, without explicit permission
-* Other unethical or unprofessional conduct.
-
-Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team.
-
-This code of conduct applies both within project spaces and in public spaces when an individual is representing the project or its community in a direct capacity. Personal views, beliefs and values of individuals do not necessarily reflect those of the organisation or affiliated individuals and organisations.
-
-Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
-
-This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.2.0, available at [http://contributor-covenant.org/version/1/2/0/](http://contributor-covenant.org/version/1/2/0/)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
deleted file mode 100644
index e0d35f4..0000000
--- a/CONTRIBUTING.md
+++ /dev/null
@@ -1,29 +0,0 @@
-# Contributing
-
-Contributions are **welcome** and will be fully **credited**.
-
-We accept contributions via Pull Requests on [Github](https://github.com/rougin/combustor).
-
-## Pull Requests
-
-- **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** - The easiest way to apply the conventions is to install [PHP Code Sniffer](http://pear.php.net/package/PHP_CodeSniffer).
-
-- **Add tests!** - Your patch won't be accepted if it doesn't have tests.
-
-- **Document any change in behaviour** - Make sure the `README.md` and any other relevant documentation are kept up-to-date.
-
-- **Consider our release cycle** - We try to follow [SemVer v2.0.0](http://semver.org/). Randomly breaking public APIs is not an option.
-
-- **Create feature branches** - Don't ask us to pull from your master branch.
-
-- **One pull request per feature** - If you want to do more than one thing, send multiple pull requests.
-
-- **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please [squash them](http://www.git-scm.com/book/en/v2/Git-Tools-Rewriting-History#Changing-Multiple-Commit-Messages) before submitting.
-
-## Running Tests
-
-``` bash
-$ composer test
-```
-
-**Happy coding**!
diff --git a/LICENSE.md b/LICENSE.md
index b867830..10b5cd7 100644
--- a/LICENSE.md
+++ b/LICENSE.md
@@ -1,6 +1,6 @@
MIT License
-Copyright (c) 2020 Rougin Gutib
+Copyright (c) Rougin Gutib
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/README.md b/README.md
index 3c6af5a..428468f 100644
--- a/README.md
+++ b/README.md
@@ -2,45 +2,103 @@
[![Latest Version on Packagist][ico-version]][link-packagist]
[![Software License][ico-license]][link-license]
-[![Build Status][ico-travis]][link-travis]
-[![Coverage Status][ico-scrutinizer]][link-scrutinizer]
-[![Quality Score][ico-code-quality]][link-code-quality]
+[![Build Status][ico-build]][link-build]
+[![Coverage Status][ico-coverage]][link-coverage]
[![Total Downloads][ico-downloads]][link-downloads]
-Combustor is a [Codeigniter](https://codeigniter.com/) library that generates controllers, models, and views based from database tables. It uses the [Describe](/describe/) library for retrieving the database tables and as the basis for code generation.
+Combustor is a utility package for [Codeigniter 3](https://codeigniter.com/userguide3/) that generates controllers, models, and views based on the provided database tables. It uses the [Describe](https://roug.in/describe/) library for getting columns from a database table and as the basis for code generation.
## Features
-* Generates code based from the structure of the Codeigniter framework
-* Speeds up the code development for prototyping web applications
-* View templates are based on Bootstrap which can also be modified later
-* Needs to worry only on the database schema, and Combustor will do the rest
+* Generates code based on the structure of the `Codeigniter 3` framework;
+* Speeds up the code development for prototyping web applications;
+* View templates can be based on Bootstrap and are upgradable; and
+* Only worry on the database schema, and `Combustor` will do the rest.
## Installation
-1. Download the Codeigniter framework [here](https://github.com/bcit-ci/CodeIgniter/archive/3.1.8.zip) and extract it to the web server.
-2. Configure the application's database connectivity settings in `application/config/database.php`.
-3. Install Combustor through the [Composer](https://getcomposer.org/) package manager:
+Extract the contents of the [latest Codeigniter 3 project](https://github.com/bcit-ci/CodeIgniter/archive/3.1.13.zip) first:
+
+``` bash
+$ wget https://github.com/bcit-ci/CodeIgniter/archive/3.1.13.zip
+$ unzip 3.1.13.zip -d acme
+```
+
+Then configure the project's database connectivity settings:
+
+```
+$ cd acme
+$ nano application/config/database.php
+```
+
+``` php
+// acme/application/config/database.php
+
+// ...
+
+$db['default'] = array(
+ 'dsn' => '',
+ 'hostname' => 'localhost',
+ 'username' => '',
+ 'password' => '',
+ 'database' => '',
+ 'dbdriver' => 'mysqli',
+
+ // ...
+);
+```
+
+Next is to proceed in installing `Combustor` via [Composer](https://getcomposer.org/):
+
``` bash
$ composer require rougin/combustor --dev
```
-4. Install the ORM wrappers `Wildfire` and `Doctrine ORM` or both:
+
+``` json
+// acme/composer.json
+
+{
+ // ...
+
+ "require-dev":
+ {
+ "mikey179/vfsstream": "1.6.*",
+ "phpunit/phpunit": "4.* || 5.* || 9.*",
+ "rougin/combustor": "~1.0"
+ }
+}
+```
+
+Lastly, install the ORM wrappers like `Wildfire` or `Doctrine`:
+
``` bash
$ vendor/bin/combustor install:wildfire
$ vendor/bin/combustor install:doctrine
```
+> [!NOTE]
+> Using the `install:wildfire` command installs [Wildfire](https://roug.in/wildfire/) package while the `install:doctrine` installs [Credo](https://roug.in/credo/) package.
+
+## Reminders
+
+Prior in executing any commands, kindly ensure that the **database tables are defined properly** (foreign keys, indexes, relationships, normalizations) in order to minimize the modifications after the code structure has been generated.
+
+Also, please proceed first in generating models, views, or controllers to database tables that are having _**no relationship with other tables**_ in the database.
+
+> [!TIP]
+> `Combustor` will generate controllers, models, or views based on the specified database schema. If there's something wrong in the specified database schema, `Combustor` will generate a bad codebase.
+
## Commands
### `create:layout`
-Creates a new header and footer file.
+Create a new header and footer file.
-#### Options
+**Options**
-* `--bootstrap` - includes the Bootstrap tags
+* `--bootstrap` - adds styling based on Bootstrap
-#### Example
+**Example**
``` bash
$ vendor/bin/combustor create-layout --bootstrap
@@ -48,66 +106,60 @@ $ vendor/bin/combustor create-layout --bootstrap
### `create:controller`
-Creates a new HTTP controller.
+Create a new HTTP controller.
+
+**Arguments**
-#### Arguments
+* `table` - name of the database table
-* `name` - name of the database table
+**Options**
-#### Options
+* `--doctrine` - generates a Doctrine-based controller
+* `--wildfire` - generates a Wildfire-based controller
-* `--camel` - uses camel case naming convention for the accessor and mutators
-* `--doctrine` - generates a controller based on Doctrine
-* `--keep` - keeps the name to be used
-* `--lowercase` - keeps the first character of the name to lowercase
-* `--wildfire` - generates a controller based from Wildfire
+> [!NOTE]
+> If either `Wildfire` or `Doctrine` is installed, no need to specify it as option for executing a specified command (e.g. `--wildfire`). However if both are installed, a command must have a `--wildfire` or `--doctrine` option added.
-#### Example
+**Example**
``` bash
-$ vendor/bin/combustor create:controller users --camel --wildfire
+$ vendor/bin/combustor create:controller users --wildfire
```
### `create:model`
-Creates a new model.
+Create a new model.
-#### Arguments
+**Arguments**
-* `name` - name of the database table
+* `table` - name of the database table
-#### Options
+**Options**
-* `--camel` - uses camel case naming convention for the accessor and mutators
-* `--doctrine` - generates a controller based on Doctrine
-* `--keep` - keeps the name to be used
-* `--lowercase` - keeps the first character of the name to lowercase
-* `--wildfire` - generates a controller based from Wildfire
+* `--doctrine` - generates a Doctrine-based model
+* `--wildfire` - generates a Wildfire-based model
-#### Example
+**Example**
``` bash
-$ vendor/bin/combustor create:model users --camel --wildfire
+$ vendor/bin/combustor create:model users --wildfire
```
### `create:view`
-Creates a new view template.
+Create view templates.
-#### Arguments
+**Arguments**
-* `name` - name of the database table
+* `table` - name of the database table
-#### Options
+**Options**
-* `--bootstrap` - includes the Bootstrap tags
-* `--camel` - uses camel case naming convention for the accessor and mutators
-* `--doctrine` - generates a controller based on Doctrine
-* `--keep` - keeps the name to be used
-* `--lowercase` - keeps the first character of the name to lowercase
-* `--wildfire` - generates a controller based from Wildfire
+* `--bootstrap` - adds styling based on Bootstrap
+* `--doctrine` - generates Doctrine-based views
+* `--wildfire` - generates Wildfire-based views
-#### Example
+**Example**
``` bash
$ vendor/bin/combustor create:view users --bootstrap
@@ -115,102 +167,135 @@ $ vendor/bin/combustor create:view users --bootstrap
### `create:scaffold`
-Creates a new HTTP controller, model, and view template.
+Create a new HTTP controller, model, and view templates.
-#### Arguments
+**Arguments**
-* `name` - name of the database table
+* `table` - name of the database table
-#### Options
+**Options**
-* `--bootstrap` - includes the Bootstrap tags
-* `--camel` - uses camel case naming convention for the accessor and mutators
-* `--doctrine` - generates a controller based on Doctrine
-* `--keep` - keeps the name to be used
-* `--lowercase` - keeps the first character of the name to lowercase
-* `--wildfire` - generates a controller based from Wildfire
+* `--bootstrap` - adds styling based on Bootstrap
+* `--doctrine` - generates a Doctrine-based controller, model, and views
+* `--wildfire` - generates a Wildfire-based controller, model, and views
-#### Example
+**Example**
``` bash
$ vendor/bin/combustor create:scaffold users --bootstrap --wildfire
```
-## Wilfire's Methods
+### `install:doctrine`
-The following methods below are available if `--wildfire` is installed:
+Install the [Doctrine](https://roug.in/credo/) package.
-### `delete($table, $delimiters = [])`
+**Example**
-Deletes the specified data from storage.
+``` bash
+$ vendor/bin/combustor install:doctrine
+```
-#### Arguments
+> [!NOTE]
+> * This command will be available if `Doctrine` is not installed in the project.
+> * It also adds a `Loader.php` in the `core` directory. The said file is used for loading custom repositories extended to `EntityRepository`.
-* `$table` - name of the database table
-* `$delimiters` - delimits the list of rows to be returned
+### `install:wildfire`
-#### Example
+Install the [Wildfire](https://roug.in/wildfire/) package.
-``` php
-$this->wildfire->delete('users', ['id' => 3]);
+**Example**
+
+``` bash
+$ vendor/bin/combustor install:wildfire
```
-### `find($table, $delimiters = [])`
+> [!NOTE]
+> This command will be available if `Wildfire` is not installed in the project.
-Finds the row from the specified ID or with the list of delimiters from the specified table.
+### `remove:doctrine`
-#### Arguments
+Remove the [Doctrine](https://roug.in/credo/) package.
-* `$table` - name of the database table
-* `$delimiters` - delimits the list of rows to be returned
+**Example**
-#### Example
+``` bash
+$ vendor/bin/combustor remove:doctrine
+```
-``` php
-$this->wildfire->delete('users', ['id' => 3]);
+> [!NOTE]
+> This command will be available if `Doctrine` is installed in the project.
+
+### `remove:wildfire`
+
+Remove the [Wildfire](https://roug.in/wildfire/) package.
+
+**Example**
+
+``` bash
+$ vendor/bin/combustor remove:wildfire
```
-### `get_all($table, $delimiters = [])`
+> [!NOTE]
+> This command will be available if `Wildfire` is installed in the project.
-Returns all rows from the specified table
+## Using `combustor.yml`
-#### Arguments
+`Combustor` currently works out of the box after the configuration based on `Installation`. However, using a `combustor.yml` can be used for complex setups like specifying the new application path and excluding columns:
-* `$table` - name of the database table
-* `$delimiters` - delimits the list of rows to be returned
- * `keyword` - used for searching the data from the storage
- * `per_page` - defines the number of rows per page
+``` yaml
+# combustor.yml
-#### Returned methods
+app_path: %%CURRENT_DIRECTORY%%/Sample
-* `as_dropdown($description)` - returns the list of rows that can be used in `form_dropdown()`
- * `description` - the field to be displayed in the result (the default value is `description`)
-* `result()` - returns the list of rows from the storage in a model
-* `total_rows()` - returns the total number of rows based from the result
+excluded_fields:
+ - created_at
+ - updated_at
+ - deleted_at
+```
-#### Example
+To create a `combustor.yml`, simply run the `initialize` command:
-``` php
-$delimiters = ['keyword' => 'test', 'per_page' = 3];
+``` bash
+$ vendor/bin/combustor initialize
+[PASS] "combustor.yml" added successfully!
+```
-$result = $this->wildfire->all('users', $delimiters);
+### `app_path`
-var_dump((array) $result->result());
+This property specifies the `application` directory. It may updated to any directory (e.g., `acme/application`, `acme/config`, etc.) as long it can detect the `config/config.php` file from the defined directory:
+
+``` yaml
+# combustor.yml
+
+app_path: %%CURRENT_DIRECTORY%%/Sample
+
+# ...
```
-**NOTE**: This method is also available if `--doctrine` is installed.
+> [!NOTE]
+> `Combustor` will try to check the path specified in `app_path` if it is a valid `Codeigniter 3` project. Then it will perform another check if the `application` directory exists or if the `config` directory can be accessed directly from the directory defined in `app_path`.
-## Reminders
+### `excluded_fields`
+
+Specified fields in this property are excluded from generation to the following templates:
-* If either Wildfire or Doctrine is installed, no need to specify it as option for executing a specified command (e.g. `vendor/bin/combustor create:controller --wildfire`). However if both are installed, the command to be executed must have a `--wildfire` or `--doctrine` option added.
+* `controllers`
+* `models`
+* `views` (only for `create` and `edit` templates)
-* To learn more about Doctrine's functionalities and its concepts, the documentation page can be found [here](http://doctrine-orm.readthedocs.org/en/latest).
+``` yaml
+# combustor.yml
-* Before generating the models, views, and controllers, please make sure that the **database is defined properly** (foreign keys, indexes, relationships, normalizations) in order to minimize the modifications after the codes has been generated. Also, generate the models, views, and controllers first to tables that are having **no relationship with other tables** in the database.
+# ...
- * The reason for this is that Combustor will generate controllers, models, and views based on the specified database schema. If there's something wrong in the said database, Combustor will definitely generate a bad codebase.
+excluded_fields:
+ - created_at
+ - updated_at
+ - deleted_at
+```
-* For found bugs or suggestions, feel free to [open an issue](https://github.com/rougin/combustor/issues) or [create a pull request](https://github.com/rougin/combustor/compare).
+> [!NOTE]
+> By default, the timestamps are added when creating a `combustor.yml` for the first time as they are usually populated automatically by installed ORMs such as `Wildfire` or `Doctrine`.
## Changelog
@@ -230,18 +315,16 @@ $ composer test
The MIT License (MIT). Please see [LICENSE][link-license] for more information.
-[ico-code-quality]: https://img.shields.io/scrutinizer/g/rougin/combustor.svg?style=flat-square
+[ico-build]: https://img.shields.io/github/actions/workflow/status/rougin/combustor/build.yml?style=flat-square
+[ico-coverage]: https://img.shields.io/codecov/c/github/rougin/combustor?style=flat-square
[ico-downloads]: https://img.shields.io/packagist/dt/rougin/combustor.svg?style=flat-square
[ico-license]: https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square
-[ico-scrutinizer]: https://img.shields.io/scrutinizer/coverage/g/rougin/combustor.svg?style=flat-square
-[ico-travis]: https://img.shields.io/travis/rougin/combustor/master.svg?style=flat-square
[ico-version]: https://img.shields.io/packagist/v/rougin/combustor.svg?style=flat-square
+[link-build]: https://github.com/rougin/combustor/actions
[link-changelog]: https://github.com/rougin/combustor/blob/master/CHANGELOG.md
-[link-code-quality]: https://scrutinizer-ci.com/g/rougin/combustor
[link-contributors]: https://github.com/rougin/combustor/contributors
+[link-coverage]: https://app.codecov.io/gh/rougin/combustor
[link-downloads]: https://packagist.org/packages/rougin/combustor
[link-license]: https://github.com/rougin/combustor/blob/master/LICENSE.md
-[link-packagist]: https://packagist.org/packages/rougin/combustor
-[link-scrutinizer]: https://scrutinizer-ci.com/g/rougin/combustor/code-structure
-[link-travis]: https://travis-ci.org/rougin/combustor
\ No newline at end of file
+[link-packagist]: https://packagist.org/packages/rougin/combustor
\ No newline at end of file
diff --git a/TODO.txt b/TODO.txt
new file mode 100644
index 0000000..96b23c8
--- /dev/null
+++ b/TODO.txt
@@ -0,0 +1,7 @@
+[x] bootstrap
+- [ ] index pagination
+[ ] --empty
+[ ] --force
+[x] custom fields
+- [ ] email
+[ ] multi relations
\ No newline at end of file
diff --git a/bin/combustor b/bin/combustor
index 575bce6..69dd143 100644
--- a/bin/combustor
+++ b/bin/combustor
@@ -1,5 +1,22 @@
#!/usr/bin/env php
run();
+// -------------------------------
diff --git a/bin/combustor.php b/bin/combustor.php
deleted file mode 100644
index 9848897..0000000
--- a/bin/combustor.php
+++ /dev/null
@@ -1,50 +0,0 @@
-console->setName('Combustor');
-$app->console->setVersion('1.2.2');
-
-$app
- ->setTemplatePath(__DIR__ . '/../src/Templates')
- ->setCommandPath(__DIR__ . '/../src/Commands')
- ->setCommandNamespace('Rougin\Combustor\Commands');
-
-$app->injector->delegate('CI_Controller', function () {
- return Rougin\SparkPlug\Instance::create();
-});
-
-$ci = $app->injector->make('CI_Controller');
-
-$app->injector->delegate('Rougin\Describe\Describe', function () use ($ci) {
- $ci->load->database();
- $ci->load->helper('inflector');
-
- $config = [];
-
- $config['default'] = [
- 'dbdriver' => $ci->db->dbdriver,
- 'hostname' => $ci->db->hostname,
- 'username' => $ci->db->username,
- 'password' => $ci->db->password,
- 'database' => $ci->db->database
- ];
-
- if (empty($config['default']['hostname'])) {
- $config['default']['hostname'] = $ci->db->dsn;
- }
-
- $driver = new Rougin\Describe\Driver\CodeIgniterDriver($config);
-
- return new Rougin\Describe\Describe($driver);
-});
-
-// Run the Combustor console application
-$app->run();
diff --git a/composer.json b/composer.json
index 4756482..7d34a9d 100644
--- a/composer.json
+++ b/composer.json
@@ -1,67 +1,68 @@
{
- "name": "rougin/combustor",
- "description": "CRUD generator for the Codeigniter framework.",
- "keywords": ["codeigniter", "combustor", "crud", "generator"],
- "homepage": "https://roug.in/combustor/",
- "license": "MIT",
- "authors":
- [
- {
- "email": "rougingutib@gmail.com",
- "homepage": "https://roug.in/",
- "name": "Rougin Gutib",
- "role": "Software Engineer"
- }
- ],
- "require":
+ "name": "rougin/combustor",
+ "description": "MVC code generator for Codeigniter 3.",
+ "keywords": [ "code-generator", "crud-generator" ],
+ "homepage": "https://roug.in/combustor/",
+ "license": "MIT",
+ "authors":
+ [
{
- "php": ">=5.4.0",
- "rougin/blueprint": "~0.1",
- "rougin/describe": "~1.4",
- "rougin/spark-plug": "~0.4"
- },
- "require-dev":
- {
- "phpunit/phpunit": "~4.2|~5.7",
- "rougin/codeigniter": "~3.0",
- "scrutinizer/ocular": "~1.1"
- },
- "bin": [
- "bin/combustor",
- "bin/combustor.php"
- ],
- "autoload":
- {
- "psr-4":
- {
- "Rougin\\Combustor\\": "src"
- }
- },
- "autoload-dev":
- {
- "psr-4":
- {
- "Rougin\\Combustor\\": "tests"
- }
- },
- "scripts":
+ "email": "rougingutib@gmail.com",
+ "homepage": "https://roug.in/",
+ "name": "Rougin Gutib",
+ "role": "Software Engineer"
+ }
+ ],
+ "require":
+ {
+ "php": ">=5.4.0",
+ "rougin/blueprint": "dev-master",
+ "rougin/classidy": "dev-master",
+ "rougin/describe": "dev-master",
+ "rougin/spark-plug": "~0.6"
+ },
+ "require-dev":
+ {
+ "rougin/codeigniter": "~3.0",
+ "phpunit/phpunit": "~4.2|~5.7|~6.0|~7.0|~8.0|~9.0",
+ "sanmai/phpunit-legacy-adapter": "~6.1|~8.0"
+ },
+ "bin":
+ [
+ "bin/combustor"
+ ],
+ "autoload":
+ {
+ "psr-4":
{
- "test": "phpunit"
- },
- "extra":
+ "Rougin\\Combustor\\": "src"
+ }
+ },
+ "autoload-dev":
+ {
+ "psr-4":
{
- "branch-alias":
- {
- "dev-master": "2.0-dev"
- }
- },
- "suggest":
+ "Rougin\\Combustor\\": "tests"
+ }
+ },
+ "scripts":
+ {
+ "test": "phpunit"
+ },
+ "extra":
+ {
+ "branch-alias":
{
- "rougin/codeigniter": "Packaged \"system\" folder of the Codeigniter framework.",
- "rougin/credo": "Doctrine ORM integration for the Codeigniter framework.",
- "rougin/ignite": "Composer-based project for the Codeigniter framework.",
- "rougin/refinery": "\"Ready-to-eat\" migrations for Codeigniter framework",
- "rougin/spark-plug": "Codeigniter applications as single variables.",
- "rougin/wildfire": "Query Builder wrapper for the Codeigniter framework."
+ "dev-master": "2.0-dev"
}
+ },
+ "suggest":
+ {
+ "rougin/codeigniter": "Packaged \"system\" of Codeigniter 3.",
+ "rougin/credo": "Doctrine ORM wrapper for Codeigniter 3.",
+ "rougin/ignite": "Yet another Codeigniter 3 project template.",
+ "rougin/refinery": "\"Ready-to-eat\" Codeigniter 3 migrations.",
+ "rougin/spark-plug": "Codeigniter 3 projects as variables.",
+ "rougin/wildfire": "Query Builder wrapper for Codeigniter 3."
+ }
}
\ No newline at end of file
diff --git a/phpstan.neon b/phpstan.neon
new file mode 100644
index 0000000..bd86b33
--- /dev/null
+++ b/phpstan.neon
@@ -0,0 +1,22 @@
+parameters:
+ level: 9
+ paths:
+ - src
+ - tests
+ excludePaths:
+ analyse:
+ - tests/Fixture/Plates
+ - tests/Fixture/Sample/controllers
+ - tests/Fixture/Sample/models
+ - tests/Fixture/Sample/views
+ scanDirectories:
+ - vendor/rougin/codeigniter/src
+ ignoreErrors:
+ - '#^Access to property \$database on an unknown class CI_DB\.$#'
+ - '#^Access to property \$dbdriver on an unknown class CI_DB\.$#'
+ - '#^Access to property \$dsn on an unknown class CI_DB\.$#'
+ - '#^Access to property \$hostname on an unknown class CI_DB\.$#'
+ - '#^Access to property \$password on an unknown class CI_DB\.$#'
+ - '#^Access to property \$username on an unknown class CI_DB\.$#'
+ - '#^Constant APPPATH not found\.$#'
+ - '#^Constant ENVIRONMENT not found\.$#'
\ No newline at end of file
diff --git a/phpstyle.php b/phpstyle.php
new file mode 100644
index 0000000..a327e31
--- /dev/null
+++ b/phpstyle.php
@@ -0,0 +1,76 @@
+ true);
+
+$cscp = 'control_structure_continuation_position';
+$rules[$cscp] = ['position' => 'next_line'];
+
+$braces = array();
+$braces['control_structures_opening_brace'] = 'next_line_unless_newline_at_signature_end';
+$braces['functions_opening_brace'] = 'next_line_unless_newline_at_signature_end';
+$braces['anonymous_functions_opening_brace'] = 'next_line_unless_newline_at_signature_end';
+$braces['anonymous_classes_opening_brace'] = 'next_line_unless_newline_at_signature_end';
+$braces['allow_single_line_empty_anonymous_classes'] = false;
+$braces['allow_single_line_anonymous_functions'] = false;
+$rules['braces_position'] = $braces;
+
+$visibility = array('elements' => array());
+$visibility['elements'] = array('method', 'property');
+$rules['visibility_required'] = $visibility;
+
+$rules['phpdoc_var_annotation_correct_order'] = true;
+
+$rules['single_quote'] = ['strings_containing_single_quote_chars' => true];
+
+$rules['no_unused_imports'] = true;
+
+$rules['align_multiline_comment'] = true;
+
+$rules['trim_array_spaces'] = true;
+
+$order = ['case_sensitive' => true];
+$order['null_adjustment'] = 'always_last';
+$rules['phpdoc_types_order'] = $order;
+
+$rules['new_with_parentheses'] = ['named_class' => false];
+
+$rules['concat_space'] = ['spacing' => 'one'];
+
+$rules['no_empty_phpdoc'] = true;
+
+$groups = [];
+$groups[] = ['template', 'extends'];
+$groups[] = ['deprecated', 'link', 'see', 'since', 'codeCoverageIgnore'];
+$groups[] = ['property', 'property-read', 'property-write'];
+$groups[] = ['method'];
+$groups[] = ['author', 'copyright', 'license'];
+$groups[] = ['category', 'package', 'subpackage'];
+$groups[] = ['param'];
+$groups[] = ['return', 'throws'];
+$rules['phpdoc_separation'] = ['groups' => $groups];
+
+$align = ['align' => 'vertical'];
+$align['tags'] = ['method', 'param', 'property', 'throws', 'type', 'var'];
+$rules['phpdoc_align'] = $align;
+
+$rules['statement_indentation'] = false;
+
+$rules['align_multiline_comment'] = true;
+// -----------------------------------------------
+
+$finder = new \PhpCsFixer\Finder;
+
+$finder->in((array) $paths);
+
+$config = new \PhpCsFixer\Config;
+
+$config->setRules($rules);
+
+return $config->setFinder($finder);
diff --git a/src/Combustor.php b/src/Combustor.php
new file mode 100644
index 0000000..beef4c2
--- /dev/null
+++ b/src/Combustor.php
@@ -0,0 +1,114 @@
+
+ */
+class Combustor
+{
+ /**
+ * @var \Rougin\SparkPlug\Controller|null
+ */
+ protected $app = null;
+
+ /**
+ * @var \Rougin\Describe\Driver\DriverInterface|null
+ */
+ protected $driver = null;
+
+ /**
+ * @var string[]
+ */
+ protected $excluded = array();
+
+ /**
+ * @var string
+ */
+ protected $root;
+
+ /**
+ * @param string $root
+ */
+ public function __construct($root)
+ {
+ $this->root = $root;
+ }
+
+ /**
+ * @return string
+ */
+ public function getAppPath()
+ {
+ $app = $this->root . '/application';
+
+ $root = $this->getRootPath();
+
+ return is_dir($app) ? $app : $root;
+ }
+
+ /**
+ * @return \Rougin\Describe\Driver\DriverInterface|null
+ */
+ public function getDriver()
+ {
+ return $this->driver;
+ }
+
+ /**
+ * @return string[]
+ */
+ public function getExcluded()
+ {
+ return $this->excluded;
+ }
+
+ /**
+ * @return string
+ */
+ public function getRootPath()
+ {
+ return $this->root;
+ }
+
+ /**
+ * @param \Rougin\SparkPlug\Controller $app
+ *
+ * @return self
+ */
+ public function setApp(Controller $app)
+ {
+ $this->app = $app;
+
+ return $this;
+ }
+
+ /**
+ * @param \Rougin\Describe\Driver\DriverInterface $driver
+ *
+ * @return self
+ */
+ public function setDriver(DriverInterface $driver)
+ {
+ $this->driver = $driver;
+
+ return $this;
+ }
+
+ /**
+ * @param string[] $excluded
+ *
+ * @return self
+ */
+ public function setExcluded($excluded)
+ {
+ $this->excluded = $excluded;
+
+ return $this;
+ }
+}
diff --git a/src/Command.php b/src/Command.php
new file mode 100644
index 0000000..154a2af
--- /dev/null
+++ b/src/Command.php
@@ -0,0 +1,151 @@
+
+ */
+class Command extends Blueprint
+{
+ const TYPE_WILDFIRE = 0;
+
+ const TYPE_DOCTRINE = 1;
+
+ /**
+ * @var \Rougin\Describe\Driver\DriverInterface|null
+ */
+ protected $driver = null;
+
+ /**
+ * @var string[]
+ */
+ protected $excluded = array();
+
+ /**
+ * @var \Rougin\Classidy\Generator
+ */
+ protected $maker;
+
+ /**
+ * @var string
+ */
+ protected $path;
+
+ /**
+ * @param \Rougin\Combustor\Combustor $combustor
+ * @param \Rougin\Classidy\Generator $maker
+ */
+ public function __construct(Combustor $combustor, Generator $maker)
+ {
+ $this->driver = $combustor->getDriver();
+
+ $this->excluded = $combustor->getExcluded();
+
+ $this->maker = $maker;
+
+ $this->path = $combustor->getAppPath();
+ }
+
+ /**
+ * @return void
+ */
+ public function init()
+ {
+ $this->addArgument('table', 'Name of the database table');
+ }
+
+ /**
+ * @return boolean
+ */
+ public function isEnabled()
+ {
+ return $this->driver !== null;
+ }
+
+ /**
+ * @param boolean $doctrine
+ * @param boolean $wildfire
+ *
+ * @return integer
+ * @throws \Exception
+ */
+ protected function getInstalled($doctrine, $wildfire)
+ {
+ $class = 'Rougin\Credo\Credo';
+ $doctrineExists = class_exists($class);
+
+ $class = 'Rougin\Wildfire\Wildfire';
+ $wildfireExists = class_exists($class);
+
+ /**
+ * If --doctrine or --wildfire not specified
+ */
+ if (! $doctrine && ! $wildfire)
+ {
+ /**
+ * If not specified as option and packages are not yet installed
+ */
+ if (! $doctrineExists && ! $wildfireExists)
+ {
+ $text = 'Both "rougin/credo" and "rougin/wildfire" are not installed.';
+
+ throw new \Exception($text . ' Kindly "rougin/credo" or "rougin/wildfire" first.');
+ }
+
+ /**
+ * If both installed and not specified as option
+ */
+ if ($doctrineExists && $wildfireExists)
+ {
+ $text = 'Both "rougin/credo" and "rougin/wildfire" are installed.';
+
+ throw new \Exception($text . ' Kindly select --doctrine or --wildfire first.');
+ }
+ }
+
+ if (! $wildfire && ($doctrine || $doctrineExists))
+ {
+ return self::TYPE_DOCTRINE;
+ }
+
+ return self::TYPE_WILDFIRE;
+ }
+
+ /**
+ * @param integer $type
+ *
+ * @return \Rougin\Classidy\Classidy
+ */
+ protected function getTemplate($type)
+ {
+ /** @var string */
+ $table = $this->getArgument('table');
+
+ $isModel = $this->name === 'create:model';
+
+ /** @var \Rougin\Describe\Driver\DriverInterface */
+ $driver = $this->driver;
+
+ $cols = $driver->columns($table);
+
+ if ($isModel && $type === self::TYPE_DOCTRINE)
+ {
+ return new DoctrineModel($table, $cols, $this->excluded);
+ }
+
+ if ($isModel && $type === self::TYPE_WILDFIRE)
+ {
+ return new WildfireModel($table, $cols, $this->excluded);
+ }
+
+ return new Controller($table, $type);
+ }
+}
diff --git a/src/Commands/AbstractCommand.php b/src/Commands/AbstractCommand.php
deleted file mode 100644
index 311f7ce..0000000
--- a/src/Commands/AbstractCommand.php
+++ /dev/null
@@ -1,99 +0,0 @@
-
- */
-abstract class AbstractCommand extends Command
-{
- /**
- * @var string
- */
- protected $command = '';
-
- /**
- * @var \Rougin\Describe\Describe
- */
- protected $describe;
-
- /**
- * @var \Twig_Environment
- */
- protected $renderer;
-
- /**
- * @param \Twig_Environment $renderer
- * @param \Rougin\Describe\Describe $describe
- */
- public function __construct(Describe $describe, Twig_Environment $renderer)
- {
- parent::__construct();
-
- $this->describe = $describe;
- $this->renderer = $renderer;
- }
-
- /**
- * Set the configurations of the specified command
- *
- * @return void
- */
- protected function configure()
- {
- $this->setName('create:' . $this->command)
- ->setDescription('Create a new ' . $this->command)
- ->addArgument(
- 'name',
- InputArgument::REQUIRED,
- 'Name of the table'
- )->addOption(
- 'bootstrap',
- null,
- InputOption::VALUE_NONE,
- 'Includes the Bootstrap CSS/JS Framework tags'
- )->addOption(
- 'camel',
- null,
- InputOption::VALUE_NONE,
- 'Uses the camel case naming convention'
- )->addOption(
- 'keep',
- null,
- InputOption::VALUE_NONE,
- 'Keeps the name to be used'
- );
-
- if ($this->command == 'controller') {
- $this->addOption(
- 'lowercase',
- null,
- InputOption::VALUE_NONE,
- 'Keeps the first character of the name to lowercase'
- );
- }
- }
-
- /**
- * Checks whether the command is enabled or not in the current environment.
- *
- * @return bool
- */
- public function isEnabled()
- {
- return Tools::isCommandEnabled();
- }
-}
diff --git a/src/Commands/CreateControllerCommand.php b/src/Commands/CreateControllerCommand.php
deleted file mode 100644
index 0ec21f2..0000000
--- a/src/Commands/CreateControllerCommand.php
+++ /dev/null
@@ -1,80 +0,0 @@
-
- */
-class CreateControllerCommand extends AbstractCommand
-{
- /**
- * @var string
- */
- protected $command = 'controller';
-
- /**
- * Executes the command.
- *
- * @param \Symfony\Component\Console\Input\InputInterface $input
- * @param \Symfony\Component\Console\Output\OutputInterface $output
- * @return object|\Symfony\Component\Console\Output\OutputInterface
- */
- protected function execute(InputInterface $input, OutputInterface $output)
- {
- $fileName = ucfirst(plural($input->getArgument('name')));
-
- if ($input->getOption('keep')) {
- $fileName = ucfirst($input->getArgument('name'));
- }
-
- $path = APPPATH . 'controllers' . DIRECTORY_SEPARATOR . $fileName . '.php';
-
- $info = [
- 'name' => $fileName,
- 'type' => 'controller',
- 'path' => $path
- ];
-
- $validator = new ControllerValidator($input->getOption('camel'), $info);
-
- if ($validator->fails()) {
- $message = $validator->getMessage();
-
- return $output->writeln('' . $message . '');
- }
-
- $data = [
- 'file' => $info,
- 'isCamel' => $input->getOption('camel'),
- 'name' => $input->getArgument('name'),
- 'title' => strtolower($fileName),
- 'type' => $validator->getLibrary()
- ];
-
- $generator = new ControllerGenerator($this->describe, $data);
-
- $result = $generator->generate();
- $controller = $this->renderer->render('Controller.tpl', $result);
- $message = 'The controller "' . $fileName . '" has been created successfully!';
-
- $file = new File($path);
-
- $file->putContents($controller);
- $file->close();
-
- return $output->writeln('' . $message . '');
- }
-}
diff --git a/src/Commands/CreateLayout.php b/src/Commands/CreateLayout.php
new file mode 100644
index 0000000..fac2599
--- /dev/null
+++ b/src/Commands/CreateLayout.php
@@ -0,0 +1,71 @@
+
+ */
+class CreateLayout extends Command
+{
+ /**
+ * @var string
+ */
+ protected $name = 'create:layout';
+
+ /**
+ * @var string
+ */
+ protected $description = 'Create a new header and footer file';
+
+ /**
+ * Configures the current command.
+ *
+ * @return void
+ */
+ public function init()
+ {
+ $this->addOption('bootstrap', 'adds styling based on Bootstrap');
+ }
+
+ /**
+ * Executes the command.
+ *
+ * @return integer
+ */
+ public function run()
+ {
+ /** @var boolean */
+ $bootstrap = $this->getOption('bootstrap');
+
+ $path = $this->path . '/views/';
+
+ if (! is_dir($path . 'layout'))
+ {
+ mkdir($path . 'layout');
+ }
+
+ // Create the "header.php" file ----------
+ $header = new HeaderPlate($bootstrap);
+
+ $file = $path . 'layout/header.php';
+
+ file_put_contents($file, $header->make());
+ // ---------------------------------------
+
+ // Create the "footer.php" file ----------
+ $footer = new FooterPlate($bootstrap);
+
+ $file = $path . 'layout/footer.php';
+
+ file_put_contents($file, $footer->make());
+ // ---------------------------------------
+
+ return self::RETURN_SUCCESS;
+ }
+}
diff --git a/src/Commands/CreateLayoutCommand.php b/src/Commands/CreateLayoutCommand.php
deleted file mode 100644
index c8aa26b..0000000
--- a/src/Commands/CreateLayoutCommand.php
+++ /dev/null
@@ -1,115 +0,0 @@
-
- */
-class CreateLayoutCommand extends AbstractCommand
-{
- /**
- * Checks whether the command is enabled or not in the current environment.
- *
- * @return bool
- */
- public function isEnabled()
- {
- return ! Tools::hasLayout();
- }
-
- /**
- * Sets the configurations of the specified command.
- *
- * @return void
- */
- protected function configure()
- {
- $this->setName('create:layout')
- ->setDescription('Creates a new header and footer file')
- ->addOption(
- 'bootstrap',
- null,
- InputOption::VALUE_NONE,
- 'Includes the Bootstrap CSS/JS Framework tags'
- );
- }
-
- /**
- * Executes the command.
- *
- * @param \Symfony\Component\Console\Input\InputInterface $input
- * @param \Symfony\Component\Console\Output\OutputInterface $output
- * @return object|\Symfony\Component\Console\Output\OutputInterface
- */
- protected function execute(InputInterface $input, OutputInterface $output)
- {
- $layoutPath = APPPATH . 'views/layout';
-
- $data = [];
-
- $data['bootstrapContainer'] = '';
- $data['scripts'] = [];
- $data['styleSheets'] = [];
-
- $css = '//maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css';
-
- if (! is_dir('bower_components/font-awesome') && system('bower install font-awesome --save')) {
- $css = '';
- }
-
- $data['styleSheets'][0] = $css;
-
- if ($input->getOption('bootstrap')) {
- $data['bootstrapContainer'] = 'container';
-
- $css = 'https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css';
- $js = 'https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.js';
- $jquery = 'https://code.jquery.com/jquery-2.1.1.min.js';
-
- if (! is_dir('bower_components/bootstrap') && system('bower install bootstrap#3.3.7 --save')) {
- $css = '';
- $js = '';
- $jquery = '';
- }
-
- array_push($data['styleSheets'], $css);
- array_push($data['scripts'], $jquery);
- array_push($data['scripts'], $js);
- }
-
- if (! @mkdir($layoutPath, 0777, true)) {
- $message = 'The layout directory already exists!';
-
- return $output->writeln('' . $message . '');
- }
-
- $header = $this->renderer->render('Views/Layout/header.tpl', $data);
- $footer = $this->renderer->render('Views/Layout/footer.tpl', $data);
-
- $headerFile = new File($layoutPath . '/header.php');
- $footerFile = new File($layoutPath . '/footer.php');
-
- $headerFile->putContents($header);
- $footerFile->putContents($footer);
-
- $headerFile->close();
- $footerFile->close();
-
- $message = 'The layout folder has been created successfully!';
-
- return $output->writeln('' . $message . '');
- }
-}
diff --git a/src/Commands/CreateModel.php b/src/Commands/CreateModel.php
new file mode 100644
index 0000000..ca58f8a
--- /dev/null
+++ b/src/Commands/CreateModel.php
@@ -0,0 +1,86 @@
+
+ */
+class CreateModel extends Command
+{
+ /**
+ * @var string
+ */
+ protected $name = 'create:model';
+
+ /**
+ * @var string
+ */
+ protected $description = 'Create a new model';
+
+ /**
+ * Configures the current command.
+ *
+ * @return void
+ */
+ public function init()
+ {
+ parent::init();
+
+ $this->addOption('doctrine', 'generates a Doctrine-based model');
+
+ $this->addOption('wildfire', 'generates a Wildfire-based model');
+ }
+
+ /**
+ * Executes the command.
+ *
+ * @return integer
+ */
+ public function run()
+ {
+ /** @var string */
+ $table = $this->getArgument('table');
+
+ /** @var boolean */
+ $doctrine = $this->getOption('doctrine');
+
+ /** @var boolean */
+ $wildfire = $this->getOption('wildfire');
+
+ try
+ {
+ $type = $this->getInstalled($doctrine, $wildfire);
+ }
+ catch (\Exception $e)
+ {
+ $this->showFail($e->getMessage());
+
+ return self::RETURN_FAILURE;
+ }
+
+ // Create the model file --------------------
+ $name = Inflector::singular($table);
+
+ $name = ucfirst(Inflector::singular($table));
+
+ $path = $this->path . '/models/';
+
+ $file = $path . $name . '.php';
+
+ $plate = $this->getTemplate($type);
+
+ $plate = $this->maker->make($plate);
+
+ file_put_contents($file, $plate);
+ // ------------------------------------------
+
+ $this->showPass('Model successfully created!');
+
+ return self::RETURN_SUCCESS;
+ }
+}
diff --git a/src/Commands/CreateModelCommand.php b/src/Commands/CreateModelCommand.php
deleted file mode 100644
index 6c73e9e..0000000
--- a/src/Commands/CreateModelCommand.php
+++ /dev/null
@@ -1,104 +0,0 @@
-
- */
-class CreateModelCommand extends AbstractCommand
-{
- /**
- * @var string
- */
- protected $command = 'model';
-
- /**
- * Sets the configurations of the specified command.
- *
- * @return void
- */
- protected function configure()
- {
- $this
- ->setName('create:model')
- ->setDescription('Creates a new model')
- ->addArgument(
- 'name',
- InputArgument::REQUIRED,
- 'Name of the table'
- )->addOption(
- 'camel',
- null,
- InputOption::VALUE_NONE,
- 'Uses the camel case naming convention'
- )->addOption(
- 'lowercase',
- null,
- InputOption::VALUE_NONE,
- 'Keeps the first character of the name to lowercase'
- );
- }
-
- /**
- * Executes the command.
- *
- * @param \Symfony\Component\Console\Input\InputInterface $input
- * @param \Symfony\Component\Console\Output\OutputInterface $output
- * @return object|\Symfony\Component\Console\Output\OutputInterface
- */
- protected function execute(InputInterface $input, OutputInterface $output)
- {
- $fileName = ucfirst(singular($input->getArgument('name')));
-
- $path = APPPATH . 'models' . DIRECTORY_SEPARATOR . $fileName . '.php';
-
- $info = [
- 'name' => $fileName,
- 'type' => 'model',
- 'path' => $path
- ];
-
- $validator = new ModelValidator($input->getOption('camel'), $info);
-
- if ($validator->fails()) {
- $message = $validator->getMessage();
-
- return $output->writeln('' . $message . '');
- }
-
- $data = [
- 'file' => $info,
- 'isCamel' => $input->getOption('camel'),
- 'name' => $input->getArgument('name'),
- 'type' => $validator->getLibrary()
- ];
-
- $generator = new ModelGenerator($this->describe, $data);
-
- $result = $generator->generate();
- $model = $this->renderer->render('Model.tpl', $result);
- $message = 'The model "' . $fileName . '" has been created successfully!';
-
- $file = new File($path);
-
- $file->putContents($model);
- $file->close();
-
- return $output->writeln('' . $message . '');
- }
-}
diff --git a/src/Commands/CreateRoute.php b/src/Commands/CreateRoute.php
new file mode 100644
index 0000000..e7f959c
--- /dev/null
+++ b/src/Commands/CreateRoute.php
@@ -0,0 +1,86 @@
+
+ */
+class CreateRoute extends Command
+{
+ /**
+ * @var string
+ */
+ protected $name = 'create:controller';
+
+ /**
+ * @var string
+ */
+ protected $description = 'Create a new HTTP controller';
+
+ /**
+ * Configures the current command.
+ *
+ * @return void
+ */
+ public function init()
+ {
+ parent::init();
+
+ $this->addOption('doctrine', 'generates a Doctrine-based controller');
+
+ $this->addOption('wildfire', 'generates a Wildfire-based controller');
+ }
+
+ /**
+ * Executes the command.
+ *
+ * @return integer
+ */
+ public function run()
+ {
+ /** @var string */
+ $table = $this->getArgument('table');
+
+ /** @var boolean */
+ $doctrine = $this->getOption('doctrine');
+
+ /** @var boolean */
+ $wildfire = $this->getOption('wildfire');
+
+ try
+ {
+ $type = $this->getInstalled($doctrine, $wildfire);
+ }
+ catch (\Exception $e)
+ {
+ $this->showFail($e->getMessage());
+
+ return self::RETURN_FAILURE;
+ }
+
+ // Create the controller file -------------
+ $path = $this->path . '/controllers/';
+
+ $name = Inflector::plural($table);
+
+ $name = ucfirst(Inflector::plural($table));
+
+ $file = $path . $name . '.php';
+
+ $plate = $this->getTemplate($type);
+
+ $plate = $this->maker->make($plate);
+
+ file_put_contents($file, $plate);
+ // ----------------------------------------
+
+ $this->showPass('Controller successfully created!');
+
+ return self::RETURN_SUCCESS;
+ }
+}
diff --git a/src/Commands/CreateScaffold.php b/src/Commands/CreateScaffold.php
new file mode 100644
index 0000000..cb92f13
--- /dev/null
+++ b/src/Commands/CreateScaffold.php
@@ -0,0 +1,99 @@
+
+ */
+class CreateScaffold extends Command
+{
+ const TYPE_WILDFIRE = 0;
+
+ const TYPE_DOCTRINE = 1;
+
+ /**
+ * @var \Rougin\Describe\Driver\DriverInterface|null
+ */
+ protected $driver = null;
+
+ /**
+ * @var string
+ */
+ protected $name = 'create:scaffold';
+
+ /**
+ * @var string
+ */
+ protected $description = 'Create a new HTTP controller, model, and view templates';
+
+ /**
+ * Configures the current command.
+ *
+ * @return void
+ */
+ public function init()
+ {
+ parent::init();
+
+ $this->addOption('bootstrap', 'adds styling based on Bootstrap');
+
+ $this->addOption('doctrine', 'generates a Doctrine-based controller, models, and views');
+
+ $this->addOption('wildfire', 'generates a Wildfire-based controller, models, and views');
+ }
+
+ /**
+ * Executes the command.
+ *
+ * @return integer
+ */
+ public function run()
+ {
+ /** @var boolean */
+ $doctrine = $this->getOption('doctrine');
+
+ /** @var boolean */
+ $wildfire = $this->getOption('wildfire');
+
+ try
+ {
+ $this->getInstalled($doctrine, $wildfire);
+ }
+ catch (\Exception $e)
+ {
+ $this->showFail($e->getMessage());
+
+ return Command::RETURN_FAILURE;
+ }
+
+ /** @var string */
+ $table = $this->getArgument('table');
+
+ $input = array('table' => $table);
+ $input['--doctrine'] = $doctrine;
+ $input['--wildfire'] = $wildfire;
+
+ // Execute the "create:controller" command ----
+ $this->runCommand('create:controller', $input);
+ // --------------------------------------------
+
+ // Execute the "create:model" command ----
+ $this->runCommand('create:model', $input);
+ // ---------------------------------------
+
+ // Execute the "create:views" command -----
+ /** @var boolean */
+ $bootstrap = $this->getOption('bootstrap');
+
+ $input['--bootstrap'] = $bootstrap;
+
+ $this->runCommand('create:views', $input);
+ // ----------------------------------------
+
+ return Command::RETURN_SUCCESS;
+ }
+}
diff --git a/src/Commands/CreateScaffoldCommand.php b/src/Commands/CreateScaffoldCommand.php
deleted file mode 100644
index 5313fa8..0000000
--- a/src/Commands/CreateScaffoldCommand.php
+++ /dev/null
@@ -1,120 +0,0 @@
-
- */
-class CreateScaffoldCommand extends AbstractCommand
-{
- /**
- * Checks whether the command is enabled or not in the current environment.
- *
- * @return bool
- */
- public function isEnabled()
- {
- return Tools::isCommandEnabled();
- }
-
- /**
- * Sets the configurations of the specified command.
- *
- * @return void
- */
- protected function configure()
- {
- $this->setName('create:scaffold')
- ->setDescription('Creates a new controller, model and view')
- ->addArgument(
- 'name',
- InputArgument::REQUIRED,
- 'Name of the table'
- )->addOption(
- 'bootstrap',
- null,
- InputOption::VALUE_NONE,
- 'Includes the Bootstrap CSS/JS Framework tags'
- )->addOption(
- 'camel',
- null,
- InputOption::VALUE_NONE,
- 'Uses the camel case naming convention'
- )->addOption(
- 'keep',
- null,
- InputOption::VALUE_NONE,
- 'Keeps the name to be used'
- )->addOption(
- 'lowercase',
- null,
- InputOption::VALUE_NONE,
- 'Keeps the first character of the name to lowercase'
- );
- }
-
- /**
- * Executes the command.
- *
- * @param \Symfony\Component\Console\Input\InputInterface $input
- * @param \Symfony\Component\Console\Output\OutputInterface $output
- * @return object|\Symfony\Component\Console\Output\OutputInterface
- */
- protected function execute(InputInterface $input, OutputInterface $output)
- {
- $commands = [
- 'create:controller',
- 'create:model',
- 'create:view'
- ];
-
- $bootstrap = $input->getOption('bootstrap');
- $camel = $input->getOption('camel');
- $keep = $input->getOption('keep');
- $lowercase = $input->getOption('lowercase');
-
- foreach ($commands as $command) {
- $arguments = [
- 'command' => $command,
- 'name' => $input->getArgument('name')
- ];
-
- switch ($command) {
- case 'create:controller':
- case 'create:model':
- $arguments['--camel'] = $camel;
- $arguments['--lowercase'] = $lowercase;
-
- break;
- case 'create:view':
- $arguments['--bootstrap'] = $bootstrap;
- $arguments['--camel'] = $camel;
- $arguments['--keep'] = $keep;
-
- break;
- }
-
- if ($command == 'create:controller') {
- $arguments['--keep'] = $keep;
- }
-
- $input = new ArrayInput($arguments);
-
- $application = $this->getApplication()->find($command);
- $application->run($input, $output);
- }
- }
-}
diff --git a/src/Commands/CreateView.php b/src/Commands/CreateView.php
new file mode 100644
index 0000000..c16dbe4
--- /dev/null
+++ b/src/Commands/CreateView.php
@@ -0,0 +1,126 @@
+
+ */
+class CreateView extends Command
+{
+ /**
+ * @var string
+ */
+ protected $name = 'create:views';
+
+ /**
+ * @var string
+ */
+ protected $description = 'Create view templates';
+
+ /**
+ * Configures the current command.
+ *
+ * @return void
+ */
+ public function init()
+ {
+ parent::init();
+
+ $this->addOption('bootstrap', 'adds styling based on Bootstrap');
+
+ $this->addOption('doctrine', 'generates Doctrine-based views');
+
+ $this->addOption('wildfire', 'generates Wildfire-based views');
+ }
+
+ /**
+ * Executes the command.
+ *
+ * @return integer
+ */
+ public function run()
+ {
+ /** @var string */
+ $table = $this->getArgument('table');
+
+ /** @var boolean */
+ $doctrine = $this->getOption('doctrine');
+
+ /** @var boolean */
+ $wildfire = $this->getOption('wildfire');
+
+ try
+ {
+ $type = $this->getInstalled($doctrine, $wildfire);
+ }
+ catch (\Exception $e)
+ {
+ $this->showFail($e->getMessage());
+
+ return self::RETURN_FAILURE;
+ }
+
+ /** @var \Rougin\Describe\Driver\DriverInterface */
+ $describe = $this->driver;
+
+ $cols = $describe->columns($table);
+
+ $name = Inflector::plural($table);
+
+ $path = $this->path . '/views/';
+
+ if (! is_dir($path . $name))
+ {
+ mkdir($path . $name);
+ }
+
+ /** @var boolean */
+ $bootstrap = $this->getOption('bootstrap');
+
+ // Create the "create.php" file ---------------------------------
+ $create = new CreatePlate($table, $type, $cols);
+
+ $create->withBootstrap($bootstrap);
+
+ $create->withExcluded($this->excluded);
+
+ $file = $path . $name . '/create.php';
+
+ file_put_contents($file, $create->make(' '));
+ // --------------------------------------------------------------
+
+ // Create the "edit.php" file -------------------------------
+ $edit = new EditPlate($table, $type, $cols);
+
+ $edit->withBootstrap($bootstrap);
+
+ $edit->withExcluded($this->excluded);
+
+ $file = $path . $name . '/edit.php';
+
+ file_put_contents($file, $edit->make(' '));
+ // ----------------------------------------------------------
+
+ // Create the "index.php" file ---------------
+ $index = new IndexPlate($table, $type, $cols);
+
+ $index->withBootstrap($bootstrap);
+
+ $file = $path . $name . '/index.php';
+
+ file_put_contents($file, $index->make(' '));
+ // -------------------------------------------
+
+ $this->showPass('Views successfully created!');
+
+ return self::RETURN_SUCCESS;
+ }
+}
diff --git a/src/Commands/CreateViewCommand.php b/src/Commands/CreateViewCommand.php
deleted file mode 100644
index 72cfc56..0000000
--- a/src/Commands/CreateViewCommand.php
+++ /dev/null
@@ -1,89 +0,0 @@
-
- */
-class CreateViewCommand extends AbstractCommand
-{
- /**
- * @var string
- */
- protected $command = 'view';
-
- /**
- * Executes the command.
- *
- * @param \Symfony\Component\Console\Input\InputInterface $input
- * @param \Symfony\Component\Console\Output\OutputInterface $output
- * @return object|\Symfony\Component\Console\Output\OutputInterface
- */
- protected function execute(InputInterface $input, OutputInterface $output)
- {
- $name = Tools::stripTableSchema(plural($input->getArgument('name')));
-
- if ($input->getOption('keep')) {
- $name = Tools::stripTableSchema($input->getArgument('name'));
- }
-
- $validator = new ViewValidator($name);
-
- if ($validator->fails()) {
- $message = $validator->getMessage();
-
- return $output->writeln('' . $message . '');
- }
-
- $data = [
- 'isBootstrap' => $input->getOption('bootstrap'),
- 'isCamel' => $input->getOption('camel'),
- 'name' => $input->getArgument('name')
- ];
-
- $generator = new ViewGenerator($this->describe, $data);
-
- $result = $generator->generate();
-
- $results = [
- 'create' => $this->renderer->render('Views/create.tpl', $result),
- 'edit' => $this->renderer->render('Views/edit.tpl', $result),
- 'index' => $this->renderer->render('Views/index.tpl', $result),
- 'show' => $this->renderer->render('Views/show.tpl', $result)
- ];
-
- $filePath = APPPATH . 'views/' . $name;
-
- $create = new File($filePath . '/create.php');
- $edit = new File($filePath . '/edit.php');
- $index = new File($filePath . '/index.php');
- $show = new File($filePath . '/show.php');
-
- $create->putContents($results['create']);
- $edit->putContents($results['edit']);
- $index->putContents($results['index']);
- $show->putContents($results['show']);
-
- $create->close();
- $edit->close();
- $index->close();
- $show->close();
-
- $message = 'The views folder "' . $name . '" has been created successfully!';
-
- return $output->writeln('' . $message . '');
- }
-}
diff --git a/src/Commands/CreateYaml.php b/src/Commands/CreateYaml.php
new file mode 100644
index 0000000..e2c92a1
--- /dev/null
+++ b/src/Commands/CreateYaml.php
@@ -0,0 +1,43 @@
+
+ */
+class CreateYaml extends InitializeCommand
+{
+ /**
+ * @var string
+ */
+ protected $file = 'combustor.yml';
+
+ /**
+ * Returns the source directory for the specified file.
+ *
+ * @return string
+ */
+ protected function getPlatePath()
+ {
+ /** @var string */
+ return realpath(__DIR__ . '/../Template');
+ }
+
+ /**
+ * Returns the root directory from the package.
+ *
+ * @return string
+ */
+ protected function getRootPath()
+ {
+ $root = (string) __DIR__ . '/../../../../../';
+
+ $exists = file_exists($root . '/vendor/autoload.php');
+
+ return $exists ? $root : __DIR__ . '/../../';
+ }
+}
diff --git a/src/Commands/InstallDoctrine.php b/src/Commands/InstallDoctrine.php
new file mode 100644
index 0000000..ab7d6ba
--- /dev/null
+++ b/src/Commands/InstallDoctrine.php
@@ -0,0 +1,79 @@
+
+ */
+class InstallDoctrine extends Command
+{
+ /**
+ * @var string
+ */
+ protected $name = 'install:doctrine';
+
+ /**
+ * @var string
+ */
+ protected $description = 'Install the Doctrine package';
+
+ /**
+ * @var string
+ */
+ protected $path = '';
+
+ /**
+ * @param \Rougin\Combustor\Combustor $combustor
+ */
+ public function __construct(Combustor $combustor)
+ {
+ $this->path = $combustor->getAppPath();
+ }
+
+ /**
+ * Checks whether the command is enabled or not in the current environment.
+ *
+ * @return boolean
+ */
+ public function isEnabled()
+ {
+ return ! class_exists('Rougin\Credo\Credo');
+ }
+
+ /**
+ * Executes the command.
+ *
+ * @return integer
+ */
+ public function run()
+ {
+ system('composer require rougin/credo');
+
+ $class = new Classidy;
+
+ $class->setName('MY_Loader');
+ $class->extendsTo('Rougin\Credo\Loader');
+
+ $maker = new Generator;
+
+ $result = $maker->make($class);
+
+ $file = $this->path . '/core/Loader.php';
+
+ if (! file_exists($file))
+ {
+ file_put_contents($file, $result);
+ }
+
+ $this->showPass('Doctrine installed successfully!');
+
+ return self::RETURN_SUCCESS;
+ }
+}
diff --git a/src/Commands/InstallDoctrineCommand.php b/src/Commands/InstallDoctrineCommand.php
deleted file mode 100644
index 8840330..0000000
--- a/src/Commands/InstallDoctrineCommand.php
+++ /dev/null
@@ -1,85 +0,0 @@
-
- */
-class InstallDoctrineCommand extends InstallCommand
-{
- /**
- * @var string
- */
- protected $library = 'doctrine';
-
- /**
- * Executes the command.
- *
- * @param \Symfony\Component\Console\Input\InputInterface $input
- * @param \Symfony\Component\Console\Output\OutputInterface $output
- * @return object|\Symfony\Component\Console\Output\OutputInterface
- */
- protected function execute(InputInterface $input, OutputInterface $output)
- {
- system('composer require doctrine/orm');
-
- $cli = $this->renderer->render('DoctrineCLI.tpl');
- $doctrine = new File(APPPATH . 'libraries/Doctrine.php');
- $template = $this->renderer->render('Libraries/Doctrine.tpl');
- $vendor = realpath('vendor');
-
- // Modifies the contents of vendor/bin/doctrine.php, creates the
- // Doctrine library and creates a "proxies" directory for lazy loading.
- file_put_contents($vendor . '/bin/doctrine.php', $cli);
- file_put_contents($vendor . '/doctrine/orm/bin/doctrine.php', $cli);
-
- $doctrine->putContents($template);
- $doctrine->close();
-
- $this->addLibrary('doctrine');
-
- if (! is_dir(APPPATH . 'models/proxies')) {
- mkdir(APPPATH . 'models/proxies');
- chmod(APPPATH . 'models/proxies', 0777);
- }
-
- $abstractCommandPath = $vendor . '/doctrine/orm/lib/Doctrine/ORM/' .
- 'Tools/Console/Command/SchemaTool/AbstractCommand.php';
-
- // Includes the Base Model class in Doctrine CLI
- $abstractCommand = file_get_contents($abstractCommandPath);
-
- $search = 'use Doctrine\ORM\Tools\SchemaTool;';
- $replace = $search . "\n" . 'include BASEPATH . \'core/Model.php\';';
-
- $contents = $abstractCommand;
- $schemaTool = 'use Doctrine\ORM\Tools\SchemaTool;';
- $coreModel = 'include BASEPATH . \'core/Model.php\';';
-
- if (strpos($abstractCommand, $schemaTool) !== false) {
- if (strpos($abstractCommand, $coreModel) === false) {
- $contents = str_replace($search, $replace, $abstractCommand);
- }
- }
-
- file_put_contents($abstractCommandPath, $contents);
-
- Tools::ignite();
-
- $message = 'Doctrine ORM is now installed successfully!';
-
- return $output->writeln('' . $message . '');
- }
-}
diff --git a/src/Commands/InstallWildfire.php b/src/Commands/InstallWildfire.php
new file mode 100644
index 0000000..043f25d
--- /dev/null
+++ b/src/Commands/InstallWildfire.php
@@ -0,0 +1,47 @@
+
+ */
+class InstallWildfire extends Command
+{
+ /**
+ * @var string
+ */
+ protected $name = 'install:wildfire';
+
+ /**
+ * @var string
+ */
+ protected $description = 'Install the Wildfire package';
+
+ /**
+ * Checks whether the command is enabled or not in the current environment.
+ *
+ * @return boolean
+ */
+ public function isEnabled()
+ {
+ return ! class_exists('Rougin\Wildfire\Wildfire');
+ }
+
+ /**
+ * Executes the command.
+ *
+ * @return integer
+ */
+ public function run()
+ {
+ system('composer require rougin/wildfire');
+
+ $this->showPass('Wildfire installed successfully!');
+
+ return self::RETURN_SUCCESS;
+ }
+}
diff --git a/src/Commands/InstallWildfireCommand.php b/src/Commands/InstallWildfireCommand.php
deleted file mode 100644
index 2a1999b..0000000
--- a/src/Commands/InstallWildfireCommand.php
+++ /dev/null
@@ -1,50 +0,0 @@
-
- */
-class InstallWildfireCommand extends InstallCommand
-{
- /**
- * @var string
- */
- protected $library = 'wildfire';
-
- /**
- * Executes the command.
- *
- * @param \Symfony\Component\Console\Input\InputInterface $input
- * @param \Symfony\Component\Console\Output\OutputInterface $output
- * @return object|\Symfony\Component\Console\Output\OutputInterface
- */
- protected function execute(InputInterface $input, OutputInterface $output)
- {
- $this->addLibrary('wildfire');
-
- $template = $this->renderer->render('Libraries/Wildfire.tpl');
- $wildfire = new File(APPPATH . 'libraries/Wildfire.php');
-
- $wildfire->putContents($template);
- $wildfire->close();
-
- Tools::ignite();
-
- $message = 'Wildfire is now installed successfully!';
-
- return $output->writeln('' . $message . '');
- }
-}
diff --git a/src/Commands/RemoveDoctrine.php b/src/Commands/RemoveDoctrine.php
new file mode 100644
index 0000000..9849a04
--- /dev/null
+++ b/src/Commands/RemoveDoctrine.php
@@ -0,0 +1,68 @@
+
+ */
+class RemoveDoctrine extends Command
+{
+ /**
+ * @var string
+ */
+ protected $name = 'remove:doctrine';
+
+ /**
+ * @var string
+ */
+ protected $description = 'Remove the Doctrine package';
+
+ /**
+ * @var string
+ */
+ protected $path = '';
+
+ /**
+ * @param \Rougin\Combustor\Combustor $combustor
+ */
+ public function __construct(Combustor $combustor)
+ {
+ $this->path = $combustor->getAppPath();
+ }
+
+ /**
+ * Checks whether the command is enabled or not in the current environment.
+ *
+ * @return boolean
+ */
+ public function isEnabled()
+ {
+ return class_exists('Rougin\Credo\Credo');
+ }
+
+ /**
+ * Executes the command.
+ *
+ * @return integer
+ */
+ public function run()
+ {
+ system('composer remove rougin/credo');
+
+ $file = $this->path . '/core/Loader.php';
+
+ if (file_exists($file))
+ {
+ unlink($file);
+ }
+
+ $this->showPass('Doctrine removed successfully!');
+
+ return self::RETURN_SUCCESS;
+ }
+}
diff --git a/src/Commands/RemoveDoctrineCommand.php b/src/Commands/RemoveDoctrineCommand.php
deleted file mode 100644
index f9dfd7f..0000000
--- a/src/Commands/RemoveDoctrineCommand.php
+++ /dev/null
@@ -1,21 +0,0 @@
-
- */
-class RemoveDoctrineCommand extends RemoveCommand
-{
- /**
- * @var string
- */
- protected $library = 'doctrine';
-}
diff --git a/src/Commands/RemoveWildfire.php b/src/Commands/RemoveWildfire.php
new file mode 100644
index 0000000..f4c3493
--- /dev/null
+++ b/src/Commands/RemoveWildfire.php
@@ -0,0 +1,47 @@
+
+ */
+class RemoveWildfire extends Command
+{
+ /**
+ * @var string
+ */
+ protected $name = 'remove:wildfire';
+
+ /**
+ * @var string
+ */
+ protected $description = 'Remove the Wildfire package';
+
+ /**
+ * Checks whether the command is enabled or not in the current environment.
+ *
+ * @return boolean
+ */
+ public function isEnabled()
+ {
+ return class_exists('Rougin\Wildfire\Wildfire');
+ }
+
+ /**
+ * Executes the command.
+ *
+ * @return integer
+ */
+ public function run()
+ {
+ system('composer remove rougin/wildfire');
+
+ $this->showPass('Wildfire removed successfully!');
+
+ return self::RETURN_SUCCESS;
+ }
+}
diff --git a/src/Commands/RemoveWildfireCommand.php b/src/Commands/RemoveWildfireCommand.php
deleted file mode 100644
index b04e035..0000000
--- a/src/Commands/RemoveWildfireCommand.php
+++ /dev/null
@@ -1,21 +0,0 @@
-
- */
-class RemoveWildfireCommand extends RemoveCommand
-{
- /**
- * @var string
- */
- protected $library = 'wildfire';
-}
diff --git a/src/Common/Commands/InstallCommand.php b/src/Common/Commands/InstallCommand.php
deleted file mode 100644
index 68a6ea7..0000000
--- a/src/Common/Commands/InstallCommand.php
+++ /dev/null
@@ -1,70 +0,0 @@
-
- */
-class InstallCommand extends AbstractCommand
-{
- /**
- * @var string
- */
- protected $library = '';
-
- /**
- * Checks whether the command is enabled or not in the current environment.
- *
- * @return boolean
- */
- public function isEnabled()
- {
- $library = ($this->library == 'doctrine') ? 'Wildfire' : 'Doctrine';
-
- return ! file_exists(APPPATH . 'libraries/' . $library . '.php');
- }
-
- /**
- * Sets the configurations of the specified command.
- *
- * @return void
- */
- protected function configure()
- {
- $this
- ->setName('install:' . $this->library)
- ->setDescription('Installs ' . ucfirst($this->library));
- }
-
- /**
- * Adds the specified library in the autoload.php.
- *
- * @param string $library
- * @return void
- */
- protected function addLibrary($library)
- {
- $autoload = new Config('autoload', APPPATH . 'config');
-
- $libraries = $autoload->get('libraries', 60, 'array');
-
- if (! in_array($library, $libraries)) {
- array_push($libraries, $library);
-
- $autoload->set('libraries', 60, $libraries, 'array');
- $autoload->save();
- }
- }
-}
diff --git a/src/Common/Commands/RemoveCommand.php b/src/Common/Commands/RemoveCommand.php
deleted file mode 100644
index f30b5d0..0000000
--- a/src/Common/Commands/RemoveCommand.php
+++ /dev/null
@@ -1,86 +0,0 @@
-
- */
-class RemoveCommand extends AbstractCommand
-{
- /**
- * @var string
- */
- protected $library = '';
-
- /**
- * Checks whether the command is enabled or not in the current environment.
- *
- * Override this to check for x or y and return false if the command can not
- * run properly under the current conditions.
- *
- * @return bool
- */
- public function isEnabled()
- {
- $file = APPPATH . 'libraries/' . $this->library . '.php';
-
- return file_exists($file);
- }
-
- /**
- * Sets the configurations of the specified command.
- *
- * @return void
- */
- protected function configure()
- {
- $this
- ->setName('remove:' . $this->library)
- ->setDescription('Removes ' . ucfirst($this->library));
- }
-
- /**
- * Executes the command.
- *
- * @param \Symfony\Component\Console\Input\InputInterface $input
- * @param \Symfony\Component\Console\Output\OutputInterface $output
- * @return OutputInterface
- */
- protected function execute(InputInterface $input, OutputInterface $output)
- {
- $autoload = new Config('autoload', APPPATH . 'config');
-
- $libraries = $autoload->get('libraries', 60, 'array');
-
- if (in_array($this->library, $libraries)) {
- $position = array_search($this->library, $libraries);
-
- unset($libraries[$position]);
-
- $autoload->set('libraries', 60, $libraries, 'array');
- $autoload->save();
- }
-
- if ($this->library == 'doctrine') {
- system('composer remove doctrine/orm');
- }
-
- unlink(APPPATH . 'libraries/' . ucfirst($this->library) . '.php');
-
- $message = ucfirst($this->library) . ' is now successfully removed!';
-
- return $output->writeln('' . $message . '');
- }
-}
diff --git a/src/Common/Config.php b/src/Common/Config.php
deleted file mode 100644
index 7300021..0000000
--- a/src/Common/Config.php
+++ /dev/null
@@ -1,183 +0,0 @@
-
- */
-class Config
-{
- /**
- * @var string
- */
- protected $config;
-
- /**
- * @var string
- */
- public $fileName;
-
- /**
- * @var array
- */
- protected $lines;
-
- /**
- * @param string $config
- * @param string $configPath
- */
- public function __construct($config, $configPath)
- {
- $this->config = $config;
- $this->fileName = $configPath . '/' . $config . '.php';
-
- $content = file_get_contents($this->fileName);
-
- $this->lines = preg_split("/\\r\\n|\\r|\\n/", $content);
- }
-
- /**
- * Returns the specified value from the config item.
- *
- * @param string $item
- * @param integer $line
- * @param string $dataType
- * @return mixed
- */
- public function get($item, $line, $dataType)
- {
- $result = null;
- $value = null;
-
- switch ($dataType) {
- case 'array':
- $value = 'array\((.*?)\)';
-
- break;
- case 'boolean':
- $value = '(true|TRUE|false|FALSE)';
-
- break;
- case 'string':
- $value = '(.*?)';
-
- break;
- }
-
- $pattern = '/\$' . $this->config . '\[\'' . $item . '\'\] = ' . $value . ';/';
-
- preg_match_all($pattern, $this->lines[$line], $match);
-
- switch ($dataType) {
- case 'array':
- $result = array_filter($match[1]);
- $data = '';
-
- if (! empty($result[0])) {
- $data = $result[0];
- }
-
- $result = array_filter(explode(',', $data));
- $length = count($result);
-
- for ($i = 0; $i < $length; $i++) {
- $result[$i] = str_replace(['\'', '"'], '', trim($result[$i]));
- }
-
- break;
- case 'boolean':
- $result = $match[1][0] == 'TRUE';
-
- break;
- case 'string':
- $result = $match[1][0];
-
- if ($result == '\'\'') {
- $result = null;
- }
-
- if ($result[0] == '\'' && $result[strlen($result) - 1] == '\'') {
- $result = substr($result, 1, strlen($result) - 2);
- }
-
- break;
- }
-
- return $result;
- }
-
- /**
- * Sets an value to an item in the config.
- *
- * @param string $item
- * @param integer $line
- * @param mixed $value
- * @param string $dataType
- * @param boolean $exact
- */
- public function set($item, $line, $value, $dataType, $exact = false)
- {
- $data = null;
- $format = null;
-
- switch ($dataType) {
- case 'array':
- $length = count($value);
-
- for ($i = 0; $i < $length; $i++) {
- $value[$i] = '\'' . $value[$i] . '\'';
- }
-
- $data = 'array(' . implode(', ', $value) . ')';
- $format = 'array\([^)]*\)';
-
- break;
- case 'boolean':
- $data = ($value) ? 'TRUE' : 'FALSE';
- $format = '[^)]*';
-
- break;
- case 'string':
- $data = '\'' . $value . '\'';
- $format = '(.*?)';
-
- break;
- }
-
- if ($exact) {
- $data = $value;
- }
-
- $pattern = '/\$' . $this->config . '\[\'' . $item . '\'\] = ' . $format . ';/';
- $replacement = '$' . $this->config . '[\'' . $item . '\'] = ' . $data . ';';
-
- $result = preg_replace($pattern, $replacement, $this->lines[$line]);
-
- $this->lines[$line] = $result;
- }
-
- /**
- * Saves the current config.
- *
- * @return void
- */
- public function save()
- {
- file_put_contents($this->fileName, (string) $this);
- }
-
- /**
- * Returns the whole class into a string.
- *
- * @return string
- */
- public function __toString()
- {
- return implode(PHP_EOL, $this->lines);
- }
-}
diff --git a/src/Common/File.php b/src/Common/File.php
deleted file mode 100644
index c27a580..0000000
--- a/src/Common/File.php
+++ /dev/null
@@ -1,76 +0,0 @@
-
- */
-class File
-{
- /**
- * @var resource
- */
- protected $file;
-
- /**
- * @var string
- */
- protected $path;
-
- /**
- * @param string $path
- * @param string $mode
- */
- public function __construct($path, $mode = 'wb')
- {
- $this->path = $path;
- $this->file = fopen($path, $mode);
- }
-
- /**
- * Closes an open file pointer.
- *
- * @return boolean
- */
- public function close()
- {
- return fclose($this->file);
- }
-
- /**
- * Reads entire file into a string.
- *
- * @return string
- */
- public function getContents()
- {
- return file_get_contents($this->path);
- }
-
- /**
- * Writes a string to a file.
- *
- * @param string $content
- * @return integer|boolean
- */
- public function putContents($content)
- {
- return file_put_contents($this->path, $content);
- }
-
- /**
- * Changes the file mode of the file.
- *
- * @param integer $mode
- * @return boolean
- */
- public function chmod($mode)
- {
- return chmod($this->path, $mode);
- }
-}
diff --git a/src/Common/Tools.php b/src/Common/Tools.php
deleted file mode 100644
index a92b2d4..0000000
--- a/src/Common/Tools.php
+++ /dev/null
@@ -1,134 +0,0 @@
-
- */
-class Tools
-{
- /**
- * Checks whether the header and footer file exists.
- *
- * @return bool
- */
- public static function hasLayout()
- {
- $header = APPPATH . 'views/layout/header.php';
- $footer = APPPATH . 'views/layout/footer.php';
-
- return file_exists($header) && file_exists($footer);
- }
-
- /**
- * "Ignites" the post installation process.
- *
- * @return void
- */
- public static function ignite()
- {
- $autoloadPath = 'realpath(\'vendor\') . \'/autoload.php\'';
- $configPath = APPPATH . 'config';
- $templatePath = __DIR__ . '/../Templates';
-
- // Gets data from application/config/config.php
- $config = new Config('config', $configPath);
-
- $config->set('composer_autoload', 138, $autoloadPath, 'string', true);
- $config->set('index_page', 37, '', 'string');
- $config->set('encryption_key', 316, md5('rougin'), 'string');
-
- $config->save();
-
- // Gets data from application/config/autoload.php
- $autoload = new Config('autoload', $configPath);
-
- // Gets the currently included drivers.
- $drivers = $autoload->get('drivers', 81, 'array');
-
- // Includes "session" driver.
- if (! in_array('session', $drivers)) {
- array_push($drivers, 'session');
- }
-
- // Gets the currently included helpers
- $defaultHelpers = [ 'form', 'url' ];
- $helpers = $autoload->get('helper', 91, 'array');
-
- foreach ($defaultHelpers as $helper) {
- if (! in_array($helper, $helpers)) {
- array_push($helpers, $helper);
- }
- }
-
- $autoload->set('drivers', 81, $drivers, 'array');
- $autoload->set('helper', 91, $helpers, 'array');
-
- $autoload->save();
-
- $templates = [
- [
- 'file' => '.htaccess',
- 'name' => 'Htaccess'
- ],
- [
- 'file' => APPPATH . 'config/pagination.php',
- 'name' => 'Pagination'
- ]
- ];
-
- foreach ($templates as $template) {
- $file = new File($template['file']);
- $path = $templatePath . '/' . $template['name'] . '.tpl';
-
- if ($template['file'] == '.htaccess') {
- $file->chmod(0777);
- }
-
- $file->putContents(file_get_contents($path));
- $file->close();
- }
- }
-
- /**
- * Checks whether the command is enabled or not in the current environment.
- *
- * @return bool
- */
- public static function isCommandEnabled()
- {
- $doctrine = APPPATH . 'libraries/Doctrine.php';
- $wildfire = APPPATH . 'libraries/Wildfire.php';
-
- return file_exists($doctrine) || file_exists($wildfire);
- }
-
- /**
- * Strips the table schema from the table name.
- *
- * @param string $table
- * @return string
- */
- public static function stripTableSchema($table)
- {
- return (strpos($table, '.') !== false)
- ? substr($table, strpos($table, '.') + 1)
- : $table;
- }
-
- /**
- * Strips the table schema from the table name.
- *
- * @param string $table
- * @return string
- */
- public static function strip_table_schema($table)
- {
- return self::stripTableSchema($table);
- }
-}
diff --git a/src/Console.php b/src/Console.php
new file mode 100644
index 0000000..65bc202
--- /dev/null
+++ b/src/Console.php
@@ -0,0 +1,149 @@
+
+ */
+class Console extends Blueprint
+{
+ /**
+ * @var string
+ */
+ protected $name = 'Combustor';
+
+ /**
+ * @var string
+ */
+ protected $file = 'combustor.yml';
+
+ /**
+ * @var string
+ */
+ protected $root;
+
+ /**
+ * @var string
+ */
+ protected $version = '1.3.0';
+
+ /**
+ * @param string $root
+ */
+ public function __construct($root)
+ {
+ $namespace = __NAMESPACE__ . '\Commands';
+
+ $this->setCommandNamespace($namespace);
+
+ $this->setCommandPath(__DIR__ . '/Commands');
+
+ $this->root = $root;
+
+ $this->setPackages();
+ }
+
+ /**
+ * @return string
+ */
+ public function getAppPath()
+ {
+ /** @var string */
+ $path = realpath($this->root);
+
+ if (! file_exists($path . '/combustor.yml'))
+ {
+ return $path;
+ }
+
+ $parsed = $this->getParsed();
+
+ if (array_key_exists('app_path', $parsed))
+ {
+ /** @var string */
+ $path = $parsed['app_path'];
+ }
+
+ /** @var string */
+ return realpath($path);
+ }
+
+ /**
+ * @return string[]
+ */
+ public function getExcluded()
+ {
+ $parsed = $this->getParsed();
+
+ $field = 'excluded_fields';
+
+ if (! array_key_exists($field, $parsed))
+ {
+ return array();
+ }
+
+ /** @var string[] */
+ return $parsed[$field];
+ }
+
+ /**
+ * @return array
+ */
+ protected function getParsed()
+ {
+ /** @var string */
+ $path = realpath($this->root);
+
+ if (! file_exists($path . '/' . $this->file))
+ {
+ return array();
+ }
+
+ $file = $path . '/' . $this->file;
+
+ /** @var string */
+ $file = file_get_contents($file);
+
+ // Replace the constant with root path ----
+ $search = '%%CURRENT_DIRECTORY%%';
+
+ $file = str_replace($search, $path, $file);
+ // ----------------------------------------
+
+ /** @var array */
+ return Yaml::parse($file);
+ }
+
+ /**
+ * @return void
+ */
+ protected function setPackages()
+ {
+ $container = new Container;
+
+ $path = $this->getAppPath();
+
+ $sparkPlug = new SparkplugPackage($path);
+ $container->addPackage($sparkPlug);
+
+ $describe = new DescribePackage;
+ $container->addPackage($describe);
+
+ $combustor = new CombustorPackage($path);
+ $excluded = $this->getExcluded();
+
+ $combustor->setExcluded($excluded);
+ $container->addPackage($combustor);
+
+ $this->setContainer($container);
+ }
+}
diff --git a/src/Generator/BaseGenerator.php b/src/Generator/BaseGenerator.php
deleted file mode 100644
index d7c508c..0000000
--- a/src/Generator/BaseGenerator.php
+++ /dev/null
@@ -1,81 +0,0 @@
-
- */
-class BaseGenerator
-{
- /**
- * @var \Rougin\Describe\Describe
- */
- protected $describe;
-
- /**
- * @var array
- */
- protected $data = [];
-
- /**
- * @param \Rougin\Describe\Describe $describe
- * @param array $data
- */
- public function __construct(Describe $describe, array $data)
- {
- $this->describe = $describe;
- $this->data = $data;
- }
-
- /**
- * Gets the primary keys based on specified field.
- *
- * @param array $data
- * @param string $field
- * @param string $referencedTable
- * @return array
- */
- protected function getPrimaryKey(array $data, $field, $referencedTable)
- {
- $accessor = 'get_' . $this->describe->getPrimaryKey($referencedTable);
-
- $data['primaryKeys'][$field] = $accessor;
-
- if ($data['isCamel']) {
- $camelized = camelize($data['primaryKeys'][$field]);
-
- $data['primaryKeys'][$field] = $camelized;
- }
-
- return $data;
- }
-
- /**
- * Transforms the field into the template.
- *
- * @param string $field
- * @param string $type
- * @return array
- */
- protected function transformField($field, $type)
- {
- if ($type == 'camelize') {
- return [
- 'field' => lcfirst(camelize($field)),
- 'accessor' => lcfirst(camelize('get_' . $field)),
- 'mutator' => lcfirst(camelize('set_' . $field))
- ];
- }
-
- return [
- 'field' => lcfirst(underscore($field)),
- 'accessor' => lcfirst(underscore('get_' . $field)),
- 'mutator' => lcfirst(underscore('set_' . $field))
- ];
- }
-}
diff --git a/src/Generator/ControllerGenerator.php b/src/Generator/ControllerGenerator.php
deleted file mode 100644
index 36f842b..0000000
--- a/src/Generator/ControllerGenerator.php
+++ /dev/null
@@ -1,88 +0,0 @@
-
- */
-class ControllerGenerator extends BaseGenerator implements GeneratorInterface
-{
- /**
- * Prepares the data before generation.
- *
- * @param array &$data
- * @return void
- */
- public function prepareData(array &$data)
- {
- $data['camel'] = [];
- $data['columns'] = [];
- $data['dropdowns'] = [];
- $data['foreignKeys'] = [];
- $data['models'] = [$data['name']];
- $data['plural'] = plural($data['name']);
- $data['singular'] = singular($data['name']);
- $data['underscore'] = [];
- }
-
- /**
- * Generates set of code based on data.
- *
- * @return array
- */
- public function generate()
- {
- $this->prepareData($this->data);
-
- $columnFields = ['name', 'description', 'label'];
-
- $table = $this->describe->getTable($this->data['name']);
-
- foreach ($table as $column) {
- if ($column->isAutoIncrement()) {
- continue;
- }
-
- $field = strtolower($column->getField());
- $method = 'set_' . $field;
-
- $this->data['camel'][$field] = lcfirst(camelize($method));
- $this->data['underscore'][$field] = underscore($method);
-
- array_push($this->data['columns'], $field);
-
- if ($column->isForeignKey()) {
- $referencedTable = Tools::stripTableSchema(
- $column->getReferencedTable()
- );
-
- $this->data['foreignKeys'][$field] = $referencedTable;
-
- array_push($this->data['models'], $referencedTable);
-
- $dropdown = [
- 'list' => plural($referencedTable),
- 'table' => $referencedTable,
- 'field' => $field
- ];
-
- if (! in_array($field, $columnFields)) {
- $field = $this->describe->getPrimaryKey($referencedTable);
-
- $dropdown['field'] = $field;
- }
-
- array_push($this->data['dropdowns'], $dropdown);
- }
- }
-
- return $this->data;
- }
-}
diff --git a/src/Generator/GeneratorInterface.php b/src/Generator/GeneratorInterface.php
deleted file mode 100644
index 48f7030..0000000
--- a/src/Generator/GeneratorInterface.php
+++ /dev/null
@@ -1,21 +0,0 @@
-
- */
-interface GeneratorInterface
-{
- /**
- * Generates set of code based on data.
- *
- * @return array
- */
- public function generate();
-}
diff --git a/src/Generator/ModelGenerator.php b/src/Generator/ModelGenerator.php
deleted file mode 100644
index 4f5997f..0000000
--- a/src/Generator/ModelGenerator.php
+++ /dev/null
@@ -1,76 +0,0 @@
-
- */
-class ModelGenerator extends BaseGenerator implements GeneratorInterface
-{
- /**
- * Prepares the data before generation.
- *
- * @param array &$data
- * @return void
- */
- public function prepareData(array &$data)
- {
- $data['camel'] = [];
- $data['columns'] = [];
- $data['indexes'] = [];
- $data['primaryKeys'] = [];
- $data['underscore'] = [];
- $data['columns'] = $this->describe->getTable($data['name']);
- $data['primaryKey'] = $this->describe->getPrimaryKey($data['name']);
- }
-
- /**
- * Generates set of code based on data.
- *
- * @return array
- */
- public function generate()
- {
- $this->prepareData($this->data);
-
- foreach ($this->data['columns'] as $column) {
- $field = strtolower($column->getField());
-
- $this->data['camel'][$field] = $this->transformField(
- $field,
- 'camelize'
- );
-
- $this->data['underscore'][$field] = $this->transformField(
- $field,
- 'underscore'
- );
-
- if ($column->isForeignKey()) {
- $field = $column->getField();
- $referencedTable = $column->getReferencedTable();
-
- array_push($this->data['indexes'], $field);
-
- $this->data = $this->getPrimaryKey(
- $this->data,
- $field,
- $referencedTable
- );
- }
-
- $column->setReferencedTable(
- Tools::stripTableSchema($column->getReferencedTable())
- );
- }
-
- return $this->data;
- }
-}
diff --git a/src/Generator/ViewGenerator.php b/src/Generator/ViewGenerator.php
deleted file mode 100644
index 822abcd..0000000
--- a/src/Generator/ViewGenerator.php
+++ /dev/null
@@ -1,104 +0,0 @@
-
- */
-class ViewGenerator extends BaseGenerator implements GeneratorInterface
-{
- /**
- * Prepares the data before generation.
- *
- * @param array $data
- * @return void
- */
- public function prepareData(array &$data)
- {
- $bootstrap = [
- 'button' => 'btn btn-default',
- 'buttonPrimary' => 'btn btn-primary',
- 'formControl' => 'form-control',
- 'formGroup' => 'form-group col-lg-12 col-md-12 col-sm-12 col-xs-12',
- 'label' => 'control-label',
- 'table' => 'table table table-striped table-hover',
- 'textRight' => 'text-right'
- ];
-
- if ($data['isBootstrap']) {
- $data['bootstrap'] = $bootstrap;
- }
-
- $data['camel'] = [];
- $data['underscore'] = [];
- $data['foreignKeys'] = [];
- $data['primaryKeys'] = [];
-
- $data['plural'] = plural($data['name']);
- $data['singular'] = singular($data['name']);
-
- $primaryKey = 'get_' . $this->describe->getPrimaryKey($data['name']);
- $data['primaryKey'] = $primaryKey;
-
- if ($this->data['isCamel']) {
- $data['primaryKey'] = camelize($data['primaryKey']);
- }
-
- $data['columns'] = $this->describe->getTable(
- $data['name']
- );
- }
-
- /**
- * Generates set of code based on data.
- *
- * @return array
- */
- public function generate()
- {
- $this->prepareData($this->data);
-
- foreach ($this->data['columns'] as $column) {
- $field = strtolower($column->getField());
-
- $this->data['camel'][$field] = $this->transformField(
- $field,
- 'camelize'
- );
-
- $this->data['underscore'][$field] = $this->transformField(
- $field,
- 'underscore'
- );
-
- if ($column->isForeignKey()) {
- $referencedTable = Tools::stripTableSchema(
- $column->getReferencedTable()
- );
-
- $this->data['foreignKeys'][$field] = plural($referencedTable);
-
- $singular = $field . '_singular';
-
- $this->data['foreignKeys'][$singular] = singular(
- $referencedTable
- );
-
- $this->data = $this->getPrimaryKey(
- $this->data,
- $field,
- $referencedTable
- );
- }
- }
-
- return $this->data;
- }
-}
diff --git a/src/Inflector.php b/src/Inflector.php
new file mode 100644
index 0000000..68f70b4
--- /dev/null
+++ b/src/Inflector.php
@@ -0,0 +1,150 @@
+
+ */
+class Inflector
+{
+ /**
+ * Takes multiple words separated by the separator and changes them to spaces
+ *
+ * @param string $word
+ * @param string $separator
+ *
+ * @return string
+ */
+ public static function humanize($word, $separator = '_')
+ {
+ $regex = '/[' . preg_quote($separator) . ']+/';
+
+ $word = trim(mb_strtolower($word));
+
+ /** @var string */
+ $result = preg_replace($regex, ' ', $word);
+
+ return ucwords($result);
+ }
+
+ /**
+ * Takes a singular word and makes it plural.
+ *
+ * @param string $word
+ *
+ * @return string
+ */
+ public static function plural($word)
+ {
+ $result = strval($word);
+
+ $rules = array(
+ '/(quiz)$/' => '\1zes', // quizzes
+ '/^(ox)$/' => '\1\2en', // ox
+ '/([m|l])ouse$/' => '\1ice', // mouse, louse
+ '/(matr|vert|ind)ix|ex$/' => '\1ices', // matrix, vertex, index
+ '/(x|ch|ss|sh)$/' => '\1es', // search, switch, fix, box, process, address
+ '/([^aeiouy]|qu)y$/' => '\1ies', // query, ability, agency
+ '/(hive)$/' => '\1s', // archive, hive
+ '/(?:([^f])fe|([lr])f)$/' => '\1\2ves', // half, safe, wife
+ '/sis$/' => 'ses', // basis, diagnosis
+ '/([ti])um$/' => '\1a', // datum, medium
+ '/(p)erson$/' => '\1eople', // person, salesperson
+ '/(m)an$/' => '\1en', // man, woman, spokesman
+ '/(c)hild$/' => '\1hildren', // child
+ '/(buffal|tomat)o$/' => '\1\2oes', // buffalo, tomato
+ '/(bu|campu)s$/' => '\1\2ses', // bus, campus
+ '/(alias|status|virus)$/' => '\1es', // alias
+ '/(octop)us$/' => '\1i', // octopus
+ '/(ax|cris|test)is$/' => '\1es', // axis, crisis
+ '/s$/' => 's', // no change (compatibility)
+ '/$/' => 's',
+ );
+
+ foreach ($rules as $rule => $replace)
+ {
+ if (preg_match($rule, $result))
+ {
+ /** @var string */
+ $result = preg_replace($rule, $replace, $result);
+
+ break;
+ }
+ }
+
+ return $result;
+ }
+
+ /**
+ * Takes a singular word and makes it singular.
+ *
+ * @param string $word
+ *
+ * @return string
+ */
+ public static function singular($word)
+ {
+ $result = strval($word);
+
+ $rules = array(
+ '/(matr)ices$/' => '\1ix',
+ '/(vert|ind)ices$/' => '\1ex',
+ '/^(ox)en/' => '\1',
+ '/(alias)es$/' => '\1',
+ '/([octop|vir])i$/' => '\1us',
+ '/(cris|ax|test)es$/' => '\1is',
+ '/(shoe)s$/' => '\1',
+ '/(o)es$/' => '\1',
+ '/(bus|campus)es$/' => '\1',
+ '/([m|l])ice$/' => '\1ouse',
+ '/(x|ch|ss|sh)es$/' => '\1',
+ '/(m)ovies$/' => '\1\2ovie',
+ '/(s)eries$/' => '\1\2eries',
+ '/([^aeiouy]|qu)ies$/' => '\1y',
+ '/([lr])ves$/' => '\1f',
+ '/(tive)s$/' => '\1',
+ '/(hive)s$/' => '\1',
+ '/([^f])ves$/' => '\1fe',
+ '/(^analy)ses$/' => '\1sis',
+ '/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/' => '\1\2sis',
+ '/([ti])a$/' => '\1um',
+ '/(p)eople$/' => '\1\2erson',
+ '/(m)en$/' => '\1an',
+ '/(s)tatuses$/' => '\1\2tatus',
+ '/(c)hildren$/' => '\1\2hild',
+ '/(n)ews$/' => '\1\2ews',
+ '/(quiz)zes$/' => '\1',
+ '/([^us])s$/' => '\1'
+ );
+
+ foreach ($rules as $rule => $replacement)
+ {
+ if (preg_match($rule, $result))
+ {
+ /** @var string */
+ $result = preg_replace($rule, $replacement, $result);
+
+ break;
+ }
+ }
+
+ return $result;
+ }
+
+ /**
+ * Takes multiple words separated by spaces and underscores them.
+ *
+ * @param string $word
+ *
+ * @return string
+ */
+ public static function snakeCase($word)
+ {
+ /** @var string */
+ return preg_replace('/[\s]+/', '_', mb_strtolower($word));
+ }
+}
diff --git a/src/Packages/CombustorPackage.php b/src/Packages/CombustorPackage.php
new file mode 100644
index 0000000..0e4ff5a
--- /dev/null
+++ b/src/Packages/CombustorPackage.php
@@ -0,0 +1,84 @@
+
+ */
+class CombustorPackage implements IntegrationInterface
+{
+ /**
+ * @var string[]
+ */
+ protected $excluded = array();
+
+ /**
+ * @var string
+ */
+ protected $root;
+
+ /**
+ * @param string $root
+ */
+ public function __construct($root)
+ {
+ $this->root = $root;
+ }
+
+ /**
+ * @param \Rougin\Slytherin\Container\ContainerInterface $container
+ * @param \Rougin\Slytherin\Integration\Configuration $config
+ *
+ * @return \Rougin\Slytherin\Container\ContainerInterface
+ */
+ public function define(ContainerInterface $container, Configuration $config)
+ {
+ $app = new Combustor($this->root);
+
+ if ($this->excluded)
+ {
+ $app->setExcluded($this->excluded);
+ }
+
+ $name = 'Rougin\SparkPlug\Controller';
+
+ if ($container->has($name))
+ {
+ /** @var \Rougin\SparkPlug\Controller */
+ $class = $container->get($name);
+
+ $app->setApp($class);
+ }
+
+ $name = 'Rougin\Describe\Driver\DriverInterface';
+
+ if ($container->has($name))
+ {
+ /** @var \Rougin\Describe\Driver\DriverInterface */
+ $class = $container->get($name);
+
+ $app->setDriver($class);
+ }
+
+ return $container->set(get_class($app), $app);
+ }
+
+ /**
+ * @param string[] $excluded
+ *
+ * @return self
+ */
+ public function setExcluded($excluded)
+ {
+ $this->excluded = $excluded;
+
+ return $this;
+ }
+}
diff --git a/src/Packages/DescribePackage.php b/src/Packages/DescribePackage.php
new file mode 100644
index 0000000..6ffea5e
--- /dev/null
+++ b/src/Packages/DescribePackage.php
@@ -0,0 +1,82 @@
+
+ */
+class DescribePackage implements IntegrationInterface
+{
+ /**
+ * @param \Rougin\Slytherin\Container\ContainerInterface $container
+ * @param \Rougin\Slytherin\Integration\Configuration $config
+ *
+ * @return \Rougin\Slytherin\Container\ContainerInterface
+ */
+ public function define(ContainerInterface $container, Configuration $config)
+ {
+ // Ignore if Spark Plug is not defined ---
+ $ci3Ctrl = 'Rougin\SparkPlug\Controller';
+
+ if (! $container->has($ci3Ctrl))
+ {
+ return $container;
+ }
+ // ---------------------------------------
+
+ /** @var \Rougin\SparkPlug\Controller */
+ $ci3App = $container->get($ci3Ctrl);
+
+ $config = $this->getConfig($ci3App);
+
+ $interface = 'Rougin\Describe\Driver\DriverInterface';
+
+ $driver = $this->getDriver($config);
+
+ return $container->set($interface, $driver);
+ }
+
+ /**
+ * @param \Rougin\SparkPlug\Controller $ci
+ *
+ * @return array
+ */
+ protected function getConfig(Controller $ci)
+ {
+ $ci->load->database();
+ $ci->load->helper('inflector');
+
+ $config = array();
+
+ $config['dbdriver'] = $ci->db->dbdriver;
+ $config['hostname'] = $ci->db->hostname;
+ $config['username'] = $ci->db->username;
+ $config['password'] = $ci->db->password;
+ $config['database'] = $ci->db->database;
+
+ if (empty($config['hostname']))
+ {
+ $config['hostname'] = $ci->db->dsn;
+ };
+
+ return $config;
+ }
+
+ /**
+ * @param array $config
+ *
+ * @return \Rougin\Describe\Driver\DriverInterface
+ */
+ protected function getDriver($config)
+ {
+ return new DatabaseDriver($config['dbdriver'], $config);
+ }
+}
diff --git a/src/Packages/SparkplugPackage.php b/src/Packages/SparkplugPackage.php
new file mode 100644
index 0000000..20755cc
--- /dev/null
+++ b/src/Packages/SparkplugPackage.php
@@ -0,0 +1,55 @@
+
+ */
+class SparkplugPackage implements IntegrationInterface
+{
+ /**
+ * @var string
+ */
+ protected $root;
+
+ /**
+ * @param string $root
+ */
+ public function __construct($root)
+ {
+ $this->root = $root;
+ }
+
+ /**
+ * @param \Rougin\Slytherin\Container\ContainerInterface $container
+ * @param \Rougin\Slytherin\Integration\Configuration $config
+ *
+ * @return \Rougin\Slytherin\Container\ContainerInterface
+ */
+ public function define(ContainerInterface $container, Configuration $config)
+ {
+ $class = 'Rougin\SparkPlug\Controller';
+
+ // If cannot determine APPPATH, ignore ---
+ $appPath = $this->root . '/application';
+
+ $root = $this->root . '/config';
+
+ if (! is_dir($appPath) && ! is_dir($root))
+ {
+ return $container;
+ }
+ // ---------------------------------------
+
+ $app = Instance::create($this->root);
+
+ return $container->set($class, $app);
+ }
+}
diff --git a/src/Template/Controller.php b/src/Template/Controller.php
new file mode 100644
index 0000000..cabc50f
--- /dev/null
+++ b/src/Template/Controller.php
@@ -0,0 +1,538 @@
+
+ */
+class Controller extends Classidy
+{
+ const TYPE_WILDFIRE = 0;
+
+ const TYPE_DOCTRINE = 1;
+
+ /**
+ * @var integer
+ */
+ protected $type;
+
+ /**
+ * @param string $table
+ * @param integer $type
+ */
+ public function __construct($table, $type)
+ {
+ $this->type = $type;
+
+ $this->init($table);
+ }
+
+ /**
+ * Configures the current class.
+ *
+ * @param string $table
+ *
+ * @return void
+ */
+ public function init($table)
+ {
+ $name = Inflector::plural($table);
+
+ $model = Inflector::singular($table);
+
+ /** @var class-string */
+ $class = ucfirst($model);
+
+ $type = $this->type;
+
+ $this->addClassProperty('db', 'CI_DB_query_builder')->asTag();
+
+ $this->addClassProperty('input', 'CI_Input')->asTag();
+
+ if ($type === self::TYPE_DOCTRINE)
+ {
+ $this->imports[] = 'Rougin\Credo\Credo';
+
+ $this->addClassProperty('load', 'MY_Loader')->asTag();
+ }
+
+ $this->addClassProperty('session', 'CI_Session')->asTag();
+
+ $this->addClassProperty($model, $class)->asTag();
+
+ if ($type === self::TYPE_DOCTRINE)
+ {
+ $repo = $model . '_repository';
+
+ $class = ucfirst($repo);
+
+ $this->addClassProperty($repo, $class)->asTag();
+
+ $this->addClassProperty('repo', $class)->asPrivate();
+ }
+
+ $this->setName(ucfirst($name));
+
+ $this->extendsTo('Rougin\SparkPlug\Controller');
+
+ $this->setConstructor($model, $type);
+
+ $this->setCreateMethod($name, $model, $type);
+
+ $this->setDeleteMethod($name, $model, $type);
+
+ $this->setEditMethod($name, $model, $type);
+
+ $this->setIndexMethod($name, $model, $type);
+ }
+
+ /**
+ * @param string $model
+ * @param integer $type
+ *
+ * @return void
+ */
+ protected function setConstructor($model, $type)
+ {
+ $method = new Method('__construct');
+
+ $method->setComment('Loads the required helpers, libraries, and models.');
+
+ $method->setCodeLine(function ($lines) use ($model, $type)
+ {
+ $lines[] = 'parent::__construct();';
+ $lines[] = '';
+
+ $lines[] = '// Initialize the Database loader ---';
+
+ if ($type === self::TYPE_WILDFIRE)
+ {
+ $lines[] = '$this->load->helper(\'inflector\');';
+ }
+
+ $lines[] = '$this->load->database();';
+ $lines[] = '// ----------------------------------';
+ $lines[] = '';
+
+ // TODO: Show if --with-view enabled -------------
+ $lines[] = '// Load view-related helpers ------';
+ $lines[] = '$this->load->helper(\'form\');';
+ $lines[] = '$this->load->helper(\'url\');';
+ $lines[] = '$this->load->library(\'pagination\');';
+ $lines[] = '$this->load->library(\'session\');';
+ $lines[] = '// --------------------------------';
+ $lines[] = '';
+ // -----------------------------------------------
+
+ $lines[] = '// Load multiple models if required ---';
+ $lines[] = '$this->load->model(\'' . $model . '\');';
+
+ if ($type === self::TYPE_DOCTRINE)
+ {
+ $lines[] = '';
+ $lines[] = '$this->load->repository(\'' . $model . '\');';
+ }
+
+ $lines[] = '// ------------------------------------';
+
+ $model = ucfirst($model);
+
+ if ($type === self::TYPE_DOCTRINE)
+ {
+ $lines[] = '';
+ $lines[] = '// Load the main repository of the model ---';
+ $lines[] = '$credo = new Credo($this->db);';
+ $lines[] = '';
+ $lines[] = '/** @var \\' . $model . '_repository */';
+ $lines[] = '$repo = $credo->get_repository(\'' . $model . '\');';
+ $lines[] = '';
+ $lines[] = '$this->repo = $repo;';
+ $lines[] = '// -----------------------------------------';
+ }
+
+ return $lines;
+ });
+
+ $this->addMethod($method);
+ }
+
+ /**
+ * @param string $name
+ * @param string $model
+ * @param integer $type
+ *
+ * @return void
+ */
+ protected function setCreateMethod($name, $model, $type)
+ {
+ $method = new Method('create');
+
+ $texts = array('Returns the form page for creating a ' . $model . '.');
+ $texts[] = 'Creates a new ' . $model . ' if receiving payload.';
+ $method->setComment($texts);
+
+ $method->setReturn('void');
+
+ $method->setCodeLine(function ($lines) use ($name, $model, $type)
+ {
+ $lines[] = '// Skip if provided empty input ---';
+ $lines[] = '/** @var array */';
+ $lines[] = '$input = $this->input->post(null, true);';
+ $lines[] = '';
+ $lines[] = 'if (! $input)';
+ $lines[] = '{';
+
+ // TODO: Show if --with-view enabled -------------------------
+ $lines[] = ' $this->load->view(\'' . $name . '/create\');';
+ $lines[] = '';
+ // -----------------------------------------------------------
+
+ $lines[] = ' return;';
+ $lines[] = '}';
+ $lines[] = '// --------------------------------';
+ $lines[] = '';
+
+ $lines[] = '// Specify logic here if applicable ---';
+
+ if ($type === self::TYPE_WILDFIRE)
+ {
+ $lines[] = '$exists = $this->' . $model . '->exists($input);';
+ }
+ else
+ {
+ $lines[] = '$exists = $this->repo->exists($input);';
+ }
+
+ $lines[] = '';
+ $lines[] = '$data = array();';
+ $lines[] = '';
+ $lines[] = 'if ($exists)';
+ $lines[] = '{';
+ $lines[] = ' $data[\'error\'] = \'\';';
+ $lines[] = '}';
+ $lines[] = '// ------------------------------------';
+ $lines[] = '';
+
+ $lines[] = '// Check if provided input is valid ---';
+ $lines[] = '$valid = $this->' . $model . '->validate($input);';
+ $lines[] = '';
+ $lines[] = 'if (! $valid || $exists)';
+ $lines[] = '{';
+
+ // TODO: Show if --with-view enabled ----------------------------
+ $lines[] = ' $this->load->view(\'' . $name . '/create\', $data);';
+ $lines[] = '';
+ // --------------------------------------------------------------
+
+ $lines[] = ' return;';
+ $lines[] = '}';
+ $lines[] = '// ------------------------------------';
+ $lines[] = '';
+
+ $lines[] = '// Create the item then go back to "index" page ---';
+
+ if ($type === self::TYPE_WILDFIRE)
+ {
+ $lines[] = '$this->' . $model . '->create($input);';
+ }
+ else
+ {
+ $class = ucfirst($model);
+
+ $lines[] = '$this->repo->create($input, new ' . $class . ');';
+ }
+
+ $lines[] = '';
+ $lines[] = '$text = (string) \'' . ucfirst($model) . ' successfully created!\';';
+ $lines[] = '';
+ $lines[] = '$this->session->set_flashdata(\'alert\', $text);';
+ $lines[] = '';
+ $lines[] = 'redirect(\'' . $name . '\');';
+ $lines[] = '// ------------------------------------------------';
+
+ return $lines;
+ });
+
+ $this->addMethod($method);
+ }
+
+ /**
+ * @param string $name
+ * @param string $model
+ * @param integer $type
+ *
+ * @return void
+ */
+ protected function setDeleteMethod($name, $model, $type)
+ {
+ $method = new Method('delete');
+
+ $method->setComment('Deletes the specified ' . $model . '.');
+
+ $method->addIntegerArgument('id');
+
+ $method->setReturn('void');
+
+ $method->setCodeLine(function ($lines) use ($name, $model, $type)
+ {
+ $lines[] = '// Show 404 page if not using "DELETE" method ---';
+ $lines[] = '$method = $this->input->post(\'_method\', true);';
+ $lines[] = '';
+
+ if ($type === self::TYPE_WILDFIRE)
+ {
+ $lines[] = '$item = $this->' . $model . '->find($id);';
+ }
+ else
+ {
+ $lines[] = '$item = $this->repo->find($id);';
+ }
+
+ $lines[] = '';
+ $lines[] = 'if ($method !== \'DELETE\' || ! $item)';
+ $lines[] = '{';
+ $lines[] = ' show_404();';
+ $lines[] = '}';
+ $lines[] = '// ----------------------------------------------';
+ $lines[] = '';
+
+ $lines[] = '// Delete the item then go back to "index" page ---';
+
+ if ($type === self::TYPE_WILDFIRE)
+ {
+ $lines[] = '$this->' . $model . '->delete($id);';
+ }
+ else
+ {
+ $class = ucfirst($model);
+
+ $lines[] = '/** @var \\' . $class . ' $item */';
+ $lines[] = '$this->repo->delete($item);';
+ }
+
+ $lines[] = '';
+ $lines[] = '$text = (string) \'' . ucfirst($model) . ' successfully deleted!\';';
+ $lines[] = '';
+ $lines[] = '$this->session->set_flashdata(\'alert\', $text);';
+ $lines[] = '';
+ $lines[] = 'redirect(\'' . $name . '\');';
+ $lines[] = '// ------------------------------------------------';
+
+ return $lines;
+ });
+
+ $this->addMethod($method);
+ }
+
+ /**
+ * @param string $name
+ * @param string $model
+ * @param integer $type
+ *
+ * @return void
+ */
+ protected function setEditMethod($name, $model, $type)
+ {
+ $method = new Method('edit');
+
+ $texts = array('Returns the form page for updating a ' . $model . '.');
+ $texts[] = 'Updates the specified ' . $model . ' if receiving payload.';
+ $method->setComment($texts);
+
+ $method->addIntegerArgument('id');
+
+ $method->setReturn('void');
+
+ $method->setCodeLine(function ($lines) use ($name, $model, $type)
+ {
+ $lines[] = '// Show 404 page if item not found ---';
+
+ if ($type === self::TYPE_WILDFIRE)
+ {
+ $lines[] = 'if (! $item = $this->' . $model . '->find($id))';
+ }
+ else
+ {
+ $lines[] = 'if (! $item = $this->repo->find($id))';
+ }
+
+ $lines[] = '{';
+ $lines[] = ' show_404();';
+ $lines[] = '}';
+ $lines[] = '';
+ $lines[] = '/** @var \\' . ucfirst($model) . ' $item */';
+ $lines[] = '$data = array(\'item\' => $item);';
+ $lines[] = '// -----------------------------------';
+ $lines[] = '';
+
+ $lines[] = '// Skip if provided empty input ---';
+ $lines[] = '/** @var array */';
+ $lines[] = '$input = $this->input->post(null, true);';
+ $lines[] = '';
+ $lines[] = 'if (! $input)';
+ $lines[] = '{';
+
+ // TODO: Show if --with-view enabled ----------------------------
+ $lines[] = ' $this->load->view(\'' . $name . '/edit\', $data);';
+ $lines[] = '';
+ // --------------------------------------------------------------
+
+ $lines[] = ' return;';
+ $lines[] = '}';
+ $lines[] = '// --------------------------------';
+ $lines[] = '';
+
+ $lines[] = '// Show 404 page if not using "PUT" method ---';
+ $lines[] = '$method = $this->input->post(\'_method\', true);';
+ $lines[] = '';
+ $lines[] = 'if ($method !== \'PUT\')';
+ $lines[] = '{';
+ $lines[] = ' show_404();';
+ $lines[] = '}';
+ $lines[] = '// -------------------------------------------';
+ $lines[] = '';
+
+ $lines[] = '// Specify logic here if applicable ---';
+
+ if ($type === self::TYPE_WILDFIRE)
+ {
+ $lines[] = '$exists = $this->' . $model . '->exists($input, $id);';
+ }
+ else
+ {
+ $lines[] = '$exists = $this->repo->exists($input, $id);';
+ }
+
+ $lines[] = '';
+ $lines[] = 'if ($exists)';
+ $lines[] = '{';
+ $lines[] = ' $data[\'error\'] = \'\';';
+ $lines[] = '}';
+ $lines[] = '// ------------------------------------';
+ $lines[] = '';
+
+ $lines[] = '// Check if provided input is valid ---';
+ $lines[] = '$valid = $this->' . $model . '->validate($input);';
+ $lines[] = '';
+ $lines[] = 'if (! $valid || $exists)';
+ $lines[] = '{';
+
+ // TODO: Show if --with-view enabled ----------------------------
+ $lines[] = ' $this->load->view(\'' . $name . '/edit\', $data);';
+ $lines[] = '';
+ // --------------------------------------------------------------
+
+ $lines[] = ' return;';
+ $lines[] = '}';
+ $lines[] = '// ------------------------------------';
+ $lines[] = '';
+
+ $lines[] = '// Update the item then go back to "index" page ---';
+
+ if ($type === self::TYPE_WILDFIRE)
+ {
+ $lines[] = '$this->' . $model . '->update($id, $input);';
+ }
+ else
+ {
+ $class = ucfirst($model);
+
+ $lines[] = '/** @var \\' . $class . ' $item */';
+ $lines[] = '$this->repo->update($item, $input);';
+ }
+
+ $lines[] = '';
+ $lines[] = '$text = (string) \'User successfully updated!\';';
+ $lines[] = '';
+ $lines[] = '$this->session->set_flashdata(\'alert\', $text);';
+ $lines[] = '';
+ $lines[] = 'redirect(\'' . $name . '\');';
+ $lines[] = '// ------------------------------------------------';
+
+ return $lines;
+ });
+
+ $this->addMethod($method);
+ }
+
+ /**
+ * @param string $name
+ * @param string $model
+ * @param integer $type
+ *
+ * @return void
+ */
+ protected function setIndexMethod($name, $model, $type)
+ {
+ $method = new Method('index');
+
+ $method->setComment('Returns the list of paginated ' . $name . '.');
+
+ $method->setReturn('void');
+
+ $method->setCodeLine(function ($lines) use ($name, $model, $type)
+ {
+ $lines[] = '// Create pagination links and get the offset ---';
+
+ if ($type === self::TYPE_WILDFIRE)
+ {
+ $lines[] = '$total = (int) $this->' . $model . '->total();';
+ }
+ else
+ {
+ $lines[] = '$total = (int) $this->repo->total();';
+ }
+
+ $lines[] = '';
+ $lines[] = '$result = $this->' . $model . '->paginate(10, $total);';
+ $lines[] = '';
+ $lines[] = '$data = array(\'links\' => $result[1]);';
+ $lines[] = '';
+ $lines[] = '/** @var integer */';
+ $lines[] = '$offset = $result[0];';
+ $lines[] = '// ----------------------------------------------';
+ $lines[] = '';
+
+ if ($type === self::TYPE_WILDFIRE)
+ {
+ $lines[] = '$items = $this->' . $model . '->get(10, $offset);';
+ }
+ else
+ {
+ $lines[] = '$items = $this->repo->get(10, $offset);';
+ }
+
+ $lines[] = '';
+
+ if ($type === self::TYPE_WILDFIRE)
+ {
+ $lines[] = '$data[\'items\'] = $items->result();';
+ }
+ else
+ {
+ $lines[] = '$data[\'items\'] = $items;';
+ }
+
+ $lines[] = '';
+ $lines[] = 'if ($alert = $this->session->flashdata(\'alert\'))';
+ $lines[] = '{';
+ $lines[] = ' $data[\'alert\'] = $alert;';
+ $lines[] = '}';
+
+ // TODO: Show if --with-view enabled ---------------------------
+ $lines[] = '';
+ $lines[] = '$this->load->view(\'' . $name . '/index\', $data);';
+ // -------------------------------------------------------------
+
+ return $lines;
+ });
+
+ $this->addMethod($method);
+ }
+}
diff --git a/src/Template/CreatePlate.php b/src/Template/CreatePlate.php
new file mode 100644
index 0000000..95f29d8
--- /dev/null
+++ b/src/Template/CreatePlate.php
@@ -0,0 +1,16 @@
+
+ */
+class CreatePlate extends FormPlate
+{
+ /**
+ * @var boolean
+ */
+ protected $edit = false;
+}
diff --git a/src/Template/Doctrine/Model.php b/src/Template/Doctrine/Model.php
new file mode 100644
index 0000000..0c98cfd
--- /dev/null
+++ b/src/Template/Doctrine/Model.php
@@ -0,0 +1,300 @@
+
+ */
+class Model extends Classidy
+{
+ /**
+ * @var \Rougin\Describe\Column[]
+ */
+ protected $cols;
+
+ /**
+ * @var string[]
+ */
+ protected $excluded = array();
+
+ /**
+ * @param string $table
+ * @param \Rougin\Describe\Column[] $cols
+ * @param string[] $excluded
+ */
+ public function __construct($table, $cols, $excluded = array())
+ {
+ $this->cols = $cols;
+
+ $this->excluded = $excluded;
+
+ $this->init($table);
+ }
+
+ /**
+ * @param string $table
+ *
+ * @return void
+ */
+ public function init($table)
+ {
+ $name = Inflector::singular($table);
+
+ $this->setName(ucfirst($name));
+ $this->extendsTo('Rougin\Credo\Model');
+
+ $this->addTrait('Rougin\Credo\Traits\PaginateTrait');
+ $this->addTrait('Rougin\Credo\Traits\ValidateTrait');
+
+ $repo = ucfirst($name) . '_repository';
+
+ $comment = array('@Entity(repositoryClass="' . $repo . '")');
+ $comment[] = '';
+ $comment[] = '@Table(name="' . $table . '")';
+ $this->setComment($comment);
+
+ $link = 'https://codeigniter.com/userguide3/libraries';
+
+ // Sort columns by name ------------
+ $items = array();
+
+ foreach ($this->cols as $col)
+ {
+ $items[$col->getField()] = $col;
+ }
+
+ ksort($items);
+ // ---------------------------------
+
+ $this->setProperties($items);
+
+ $this->setPagee($link);
+
+ $this->setRules($link);
+
+ $this->setMethods($items);
+ }
+
+ /**
+ * @param \Rougin\Describe\Column[] $cols
+ *
+ * @return void
+ */
+ protected function setMethods($cols)
+ {
+ foreach ($cols as $col)
+ {
+ $name = $col->getField();
+
+ $name = Inflector::snakeCase($name);
+
+ $type = $col->getDataType();
+
+ if ($col->isNull())
+ {
+ $type = $type . '|null';
+ }
+
+ $method = 'get_' . $name;
+
+ if ($col->getDataType() === 'boolean')
+ {
+ // Remove "is_" from name to get proper name ---
+ $temp = str_replace('is_', '', $name);
+ // ---------------------------------------------
+
+ $method = 'is_' . $temp;
+ }
+
+ $method = new Method($method);
+
+ $method->setReturn($type);
+
+ $method->setCodeLine(function ($lines) use ($name)
+ {
+ $lines[] = 'return $this->' . $name . ';';
+
+ return $lines;
+ });
+
+ $this->addMethod($method);
+ }
+
+ foreach ($cols as $col)
+ {
+ if ($col->isPrimaryKey())
+ {
+ continue;
+ }
+
+ $name = $col->getField();
+
+ $name = Inflector::snakeCase($name);
+
+ $type = $col->getDataType();
+
+ if ($col->isNull())
+ {
+ $type = $type . '|null';
+ }
+
+ $method = new Method('set_' . $name);
+
+ $method->setReturn('self');
+
+ $type = $col->getDataType();
+
+ $isNull = $col->isNull();
+
+ switch ($type)
+ {
+ case 'boolean':
+ $method->addBooleanArgument($name, $isNull);
+
+ break;
+ case 'integer':
+ $method->addIntegerArgument($name, $isNull);
+
+ break;
+ default:
+ $method->addStringArgument($name, $isNull);
+
+ break;
+ }
+
+ $method->setCodeLine(function ($lines) use ($name)
+ {
+ $lines[] = '$this->' . $name . ' = $' . $name . ';';
+ $lines[] = '';
+ $lines[] = 'return $this;';
+
+ return $lines;
+ });
+
+ $this->addMethod($method);
+ }
+ }
+
+ /**
+ * @param string $link
+ *
+ * @return void
+ */
+ protected function setPagee($link)
+ {
+ $default = array();
+
+ $default['page_query_string'] = true;
+ $default['use_page_numbers'] = true;
+ $default['query_string_segment'] = 'p';
+ $default['reuse_query_string'] = true;
+
+ $this->addArrayProperty('pagee', 'array')
+ ->withComment('Additional configuration to Pagination Class.')
+ ->withLink($link . '/pagination.html#customizing-the-pagination')
+ ->withDefaultValue($default);
+ }
+
+ /**
+ * @param \Rougin\Describe\Column[] $cols
+ *
+ * @return void
+ */
+ protected function setProperties($cols)
+ {
+ foreach ($cols as $col)
+ {
+ $isNull = $col->isNull();
+
+ $isUnique = $col->isUnique();
+
+ $name = $col->getField();
+
+ $name = Inflector::snakeCase($name);
+
+ $type = $col->getDataType();
+
+ switch ($type)
+ {
+ case 'boolean':
+ $this->addBooleanProperty($name, $isNull);
+
+ break;
+ case 'integer':
+ $this->addIntegerProperty($name, $isNull);
+
+ break;
+ default:
+ $this->addStringProperty($name, $isNull);
+
+ break;
+ }
+
+ // Generate Doctrine annotations to columns ---------
+ $lines = array();
+
+ if ($col->isPrimaryKey())
+ {
+ $lines[] = '@Id @GeneratedValue';
+ $lines[] = '';
+ }
+
+ $keys = array('name="' . $name . '"');
+ $keys[] = 'type="' . $type . '"';
+
+ if ($length = $col->getLength())
+ {
+ $keys[] = 'length=' . $length;
+ }
+
+ $keys[] = 'nullable=' . ($isNull ? 'true' : 'false');
+ $keys[] = 'unique=' . ($isUnique ? 'true' : 'false');
+
+ $lines[] = '@Column(' . implode(', ', $keys) . ')';
+ // --------------------------------------------------
+
+ $this->withComment($lines);
+ }
+ }
+
+ /**
+ * @param string $link
+ *
+ * @return void
+ */
+ protected function setRules($link)
+ {
+ $rules = array();
+
+ foreach ($this->cols as $col)
+ {
+ $name = $col->getField();
+
+ $isExcluded = in_array($name, $this->excluded);
+
+ if ($col->isNull() || $col->isPrimaryKey() || $isExcluded)
+ {
+ continue;
+ }
+
+ $rule = array('field' => $name);
+
+ $rule['label'] = ucfirst($name);
+
+ $rule['rules'] = 'required';
+
+ $rules[] = $rule;
+ }
+
+ $this->addArrayProperty('rules', 'array[]')
+ ->withComment('List of validation rules for Form Validation.')
+ ->withLink($link . '/form_validation.html#setting-rules-using-an-array')
+ ->withDefaultValue($rules);
+ }
+}
diff --git a/src/Template/EditPlate.php b/src/Template/EditPlate.php
new file mode 100644
index 0000000..891e533
--- /dev/null
+++ b/src/Template/EditPlate.php
@@ -0,0 +1,16 @@
+
+ */
+class EditPlate extends FormPlate
+{
+ /**
+ * @var boolean
+ */
+ protected $edit = true;
+}
diff --git a/src/Template/FooterPlate.php b/src/Template/FooterPlate.php
new file mode 100644
index 0000000..8b7d3bc
--- /dev/null
+++ b/src/Template/FooterPlate.php
@@ -0,0 +1,45 @@
+
+ */
+class FooterPlate
+{
+ /**
+ * @var boolean
+ */
+ protected $bootstrap;
+
+ /**
+ * @param boolean $bootstrap
+ */
+ public function __construct($bootstrap)
+ {
+ $this->bootstrap = $bootstrap;
+ }
+
+ /**
+ * @param string $tab
+ *
+ * @return string
+ */
+ public function make($tab = ' ')
+ {
+ $lines = array();
+
+ if ($this->bootstrap)
+ {
+ $lines[] = $tab . '';
+ $lines[] = $tab . '';
+ }
+
+ $lines[] = '