├── .DS_Store
├── .gitignore
├── Plugin.php
├── Readme.md
├── composer.json
├── controllers
├── ApiGeneratorController.php
├── api
│ └── readme.txt
└── apigeneratorcontroller
│ ├── _list_toolbar.htm
│ ├── _reorder_toolbar.htm
│ ├── config_form.yaml
│ ├── config_list.yaml
│ ├── config_reorder.yaml
│ ├── create.htm
│ ├── index.htm
│ ├── preview.htm
│ ├── reorder.htm
│ └── update.htm
├── helpers
└── Helpers.php
├── lang
└── en
│ └── lang.php
├── models
├── ApiGenerator.php
└── apigenerator
│ ├── columns.yaml
│ └── fields.yaml
├── plugin.yaml
├── routes.php
├── template
├── controller.dot
├── controller.php
├── customcontroller.dot
├── route.dot
└── routes.dot
└── updates
├── builder_table_create_ahmadfatoni_apigenerator_data.php
└── version.yaml
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dev-lav/api-generator/57d193cf55270c63f7e81b8b77ece5c43746c384/.DS_Store
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /controllers/*
2 | !/controllers/apigeneratorcontroller/*
3 | !/controllers/apigeneratorcontroller
4 | !/controllers/ApiGeneratorController.php
5 | !routes.php
6 | /controllers/API/*
--------------------------------------------------------------------------------
/Plugin.php:
--------------------------------------------------------------------------------
1 | October CMS plugin to build RESTful APIs.
5 |
6 | ## Features
7 |
8 | - Auto generate routes
9 | - Auto Generate Controller (CRUD)
10 | - Support relationship restful API
11 |
12 | ## Install
13 | ```
14 | composer require AhmadFatoni.ApiGenerator
15 | ```
16 |
17 | ## Usage
18 |
19 | ### Form
20 | - API Name : Name of your API module
21 | - Base Endpoint : Base endpoint of your API, ex : api/v1/modulename
22 | - Short Description : Describe your API
23 | - Model : select model that will be created API
24 | - Custom Condition : Build customer response using JSON modeling
25 |
26 | ### Custom Condition Example
27 | ```
28 | {
29 | 'fillable': 'id,title,content',
30 | 'relation': [{
31 | 'name': 'user',
32 | 'fillable': 'id,first_name'
33 | }, {
34 | 'name': 'categories',
35 | 'fillable': 'id,name
36 | }]
37 | }
38 | ```
39 | * please replace single quote with quote
40 |
41 | ## Contribute
42 |
43 | Pull Requests accepted.
44 |
45 | ## Contact
46 |
47 | You can communicate with me using [linkedin](https://www.linkedin.com/in/ahmad-fatoni)
48 |
49 | ## License
50 | The OctoberCMS platform is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT).
51 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ahmadfatoni/apigenerator-plugin",
3 | "type": "october-plugin",
4 | "description": "October CMS plugin to build RESTful APIs",
5 | "require": {
6 | "composer/installers": "~1.0",
7 | "rainlab/builder-plugin": "^2.0"
8 | }
9 | }
--------------------------------------------------------------------------------
/controllers/ApiGeneratorController.php:
--------------------------------------------------------------------------------
1 | files = $files;
30 | }
31 |
32 | /**
33 | * delete selected data (multiple delete)
34 | * @return [type] [description]
35 | */
36 | public function index_onDelete()
37 | {
38 | if (($checkedIds = post('checked')) && is_array($checkedIds) && count($checkedIds)) {
39 |
40 | foreach ($checkedIds as $id) {
41 | if ((!$item = ApiGenerator::find($id)))
42 | continue;
43 | $name = $item->name;
44 | if($item->delete()){
45 | $this->deleteApi($name);
46 | }
47 | }
48 |
49 | Flash::success('Successfully deleted those data.');
50 | }
51 |
52 | return $this->listRefresh();
53 | }
54 |
55 | /**
56 | * generate API
57 | * @param Request $request [description]
58 | * @return [type] [description]
59 | */
60 | public function generateApi(Request $request){
61 |
62 | $data['model'] = $request->model;
63 | $modelname = explode("\\", $request->model);
64 | $modelname = $modelname[count($modelname)-1];
65 | $data['modelname'] = $modelname;
66 | $data['controllername'] = str_replace(" ", "", $request->name);
67 | $data['endpoint'] = $request->endpoint;
68 | $data['custom_format'] = $request->custom_format;
69 |
70 | if( strpos($data['controllername'], ".") OR strpos($data['controllername'], "/") ){
71 |
72 | Flash::success('Failed to create data, invalid API name.');
73 | return Redirect::to( Backend::url($this->homePage));
74 |
75 | }
76 |
77 | if( isset($request->id) ){
78 | $this->deleteApi($request->oldname, 'false');
79 | }
80 |
81 | $this->files->put(__DIR__ . $this->path . $data['controllername'].'Controller.php', $this->compile($data));
82 |
83 | $this->files->put(__DIR__ . '/'.'../routes.php', $this->compileRoute($data));
84 |
85 | return Redirect::to( Backend::url($this->homePage));
86 |
87 | }
88 |
89 | /**
90 | * delete available API
91 | * @param [type] $name [description]
92 | * @param [type] $redirect [description]
93 | * @return [type] [description]
94 | */
95 | public function deleteApi($name, $redirect = null){
96 |
97 | $fileLocation = __DIR__ . $this->path.$name;
98 | $fileLocation = str_replace(".", "", $fileLocation);
99 |
100 | if( ! file_exists($fileLocation.'Controller.php') ){
101 |
102 | Flash::success('Failed to delete data, invalid file location.');
103 | return Redirect::to( Backend::url($this->homePage));
104 |
105 | }
106 |
107 | if( strpos( strtolower($name), 'apigenerator' ) === false){
108 | $data = [];
109 |
110 | //generate new route
111 | $this->files->put(__DIR__ . '/'.'../routes.php', $this->compileRoute($data));
112 |
113 | //remove controller
114 | if (file_exists( __DIR__ . $this->path.$name.'Controller.php' )) {
115 |
116 | unlink(__DIR__ . $this->path.$name.'Controller.php');
117 |
118 | }
119 |
120 | if( $redirect != null ){
121 | return 'success without redirect';
122 | }
123 | }
124 |
125 | return Redirect::to( Backend::url($this->homePage));
126 |
127 | }
128 |
129 | public function updateApi($name){
130 |
131 | }
132 |
133 | /**
134 | * compile controller from template
135 | * @param [type] $data [description]
136 | * @return [type] [description]
137 | */
138 | public function compile($data){
139 | if( $data['custom_format'] != ''){
140 |
141 | $template = $this->files->get(__DIR__ .'/../template/customcontroller.dot');
142 | $template = $this->replaceAttribute($template, $data);
143 | $template = $this->replaceCustomAttribute($template, $data);
144 | }else{
145 | $template = $this->files->get(__DIR__ .'/../template/controller.dot');
146 | $template = $this->replaceAttribute($template, $data);
147 | }
148 | return $template;
149 | }
150 |
151 | /**
152 | * replace attribute
153 | * @param [type] $template [description]
154 | * @param [type] $data [description]
155 | * @return [type] [description]
156 | */
157 | public function replaceAttribute($template, $data){
158 | if( isset( $data['model'] ) ){
159 | $template = str_replace('{{model}}', $data['model'], $template);
160 | }
161 | $template = str_replace('{{modelname}}', $data['modelname'], $template);
162 | $template = str_replace('{{controllername}}', $data['controllername'], $template);
163 | return $template;
164 | }
165 |
166 | /**
167 | * replace custom attribute
168 | * @param [type] $template [description]
169 | * @param [type] $data [description]
170 | * @return [type] [description]
171 | */
172 | public function replaceCustomAttribute($template, $data){
173 |
174 | $arr = str_replace('\t', '', $data['custom_format']);
175 | $arr = json_decode($arr);
176 | $select = str_replace('
', '', $this->compileOpenIndexFunction($data['modelname'], 'index'));
177 | $show = str_replace('
', '', $this->compileOpenIndexFunction($data['modelname'], 'show'));
178 | $fillableParent = '';
179 |
180 | if( isset($arr->fillable) AND $arr->fillable != null ) {
181 | $fillableParent = $this->compileFillableParent($arr->fillable);
182 | }
183 |
184 | if( isset($arr->relation) AND $arr->relation != null AND is_array($arr->relation) AND count($arr->relation) > 0) {
185 | $select .= str_replace('
', '', $this->compileFillableChild($arr->relation));
186 | $show .= str_replace('
', '', $this->compileFillableChild($arr->relation));
187 | }
188 |
189 | $select .= "->select(".$fillableParent.")";
190 | $show .= "->select(".$fillableParent.")->where('id', '=', \$id)->first();";
191 |
192 | ( $fillableParent != '') ? $select .= "->get()->toArray();" : $select .= "->toArray();" ;
193 |
194 | $closeFunction = str_replace('
', '', nl2br(
195 | "
196 | return \$this->helpers->apiArrayResponseBuilder(200, 'success', \$data);
197 | }"));
198 | $select .= $closeFunction;
199 | $show .= $closeFunction;
200 |
201 | $template = str_replace('{{select}}', $select, $template);
202 | $template = str_replace('{{show}}', $show, $template);
203 |
204 | return $template;
205 | }
206 |
207 | public function compileOpenIndexFunction($modelname, $type){
208 | if( $type == 'index'){
209 | return nl2br("
210 | public function index(){
211 | \$data = \$this->".$modelname);
212 | }else{
213 | return nl2br("
214 | public function show(\$id){
215 | \$data = \$this->".$modelname);
216 | }
217 |
218 | }
219 |
220 | public function compileFillableParent($fillable){
221 |
222 | $fillableParentArr = explode(",", $fillable);
223 | $fillableParent = '';
224 |
225 | foreach ($fillableParentArr as $key) {
226 |
227 | $fillableParent .= ",'".$key."'";
228 |
229 | }
230 |
231 | $fillableParent = substr_replace($fillableParent, '', 0 , 1);
232 |
233 | return $fillableParent;
234 | }
235 |
236 | public function compileFillableChild($fillable){
237 |
238 | $select = "->with(array(";
239 |
240 | foreach ($fillable as $key) {
241 |
242 | $fillableChild = "";
243 |
244 | if( isset($key->fillable) AND $key->fillable != null ){
245 | $fillableChildArr = explode(",", $key->fillable);
246 |
247 |
248 | foreach ($fillableChildArr as $key2) {
249 |
250 | $fillableChild .= ",'".$key2."'";
251 |
252 | }
253 |
254 | $fillableChild = substr_replace($fillableChild, '', 0 , 1);
255 | }
256 |
257 | $select .= nl2br(
258 | "
259 | '".$key->name."'=>function(\$query){
260 | \$query->select(".$fillableChild.");
261 | },");
262 |
263 | }
264 |
265 | $select .= " ))";
266 |
267 | return $select;
268 | }
269 |
270 | public function compileRoute($data){
271 |
272 | $oldData = ApiGenerator::all();
273 | $routeList = "";
274 |
275 | if( count($oldData) > 0 ){
276 |
277 | $routeList .= $this->parseRouteOldData($oldData, $data);
278 |
279 | }
280 |
281 | if( count($data) > 0 ){
282 | $data['modelname'] = $data['endpoint'];
283 | if( $data['modelname'][0] == "/" ){
284 | $data['modelname'] = substr_replace($data['modelname'], '', 0 , 1);
285 | }
286 | $routeList .= $this->parseRoute($data);
287 | }
288 |
289 | $route = $this->files->get(__DIR__ .'/../template/routes.dot');
290 | $route = str_replace('{{route}}', $routeList, $route);
291 |
292 | return $route;
293 |
294 | }
295 |
296 | public function parseRouteOldData($oldData, $data = null){
297 |
298 | $routeList = "";
299 |
300 | if( count($data) == 0 ) $data['modelname']='';
301 |
302 | foreach ( $oldData as $key ) {
303 |
304 | $modelname = explode("\\", $key->model);
305 | $modelname = $modelname[count($modelname)-1];
306 | $old['modelname'] = $key->endpoint;
307 | $old['controllername'] = $key->name;
308 |
309 | if( $data['modelname'] != $modelname ){
310 |
311 | if( $old['modelname'][0] == "/" ){
312 | $old['modelname'] = substr_replace($old['modelname'], '', 0 , 1);
313 | }
314 |
315 | $routeList .= $this->parseRoute($old);
316 | }
317 | }
318 |
319 | return $routeList;
320 |
321 | }
322 |
323 | public function parseRoute($data){
324 |
325 | $template = $this->files->get(__DIR__ .'/../template/route.dot');
326 | $template = $this->replaceAttribute($template, $data);
327 | return $template;
328 | }
329 |
330 |
331 | public static function getAfterFilters() {return [];}
332 | public static function getBeforeFilters() {return [];}
333 | public function callAction($method, $parameters=false) {
334 | return call_user_func_array(array($this, $method), $parameters);
335 | }
336 | }
337 |
--------------------------------------------------------------------------------
/controllers/api/readme.txt:
--------------------------------------------------------------------------------
1 | api controller here
--------------------------------------------------------------------------------
/controllers/apigeneratorcontroller/_list_toolbar.htm:
--------------------------------------------------------------------------------
1 |
= e(trans('backend::lang.form.return_to_list')) ?>
86 | 87 | 88 | -------------------------------------------------------------------------------- /controllers/apigeneratorcontroller/index.htm: -------------------------------------------------------------------------------- 1 | = $this->listRender() ?> 2 | -------------------------------------------------------------------------------- /controllers/apigeneratorcontroller/preview.htm: -------------------------------------------------------------------------------- 1 | 2 |19 | 20 | = e(trans('backend::lang.form.return_to_list')) ?> 21 | 22 |
-------------------------------------------------------------------------------- /controllers/apigeneratorcontroller/reorder.htm: -------------------------------------------------------------------------------- 1 | 2 |