├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ └── bug_report.md └── images │ ├── db-conf.png │ ├── devtools-version.png │ └── devtools.png ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── composer.json └── src ├── Ubiquity └── devtools ├── cmd └── commands │ ├── AbstractCmdModel.php │ ├── AbstractThemeCmd.php │ ├── AuthCmd.php │ ├── ConfigCmd.php │ ├── ConfigSetCmd.php │ ├── CreateCommandCmd.php │ ├── CrudCmd.php │ ├── DAOCmd.php │ ├── DisplayAclsCmd.php │ ├── EncryptNewKey.php │ ├── HelpCmd.php │ ├── IndexCrudCmd.php │ ├── InfoMailerCmd.php │ ├── InfoMigrationsCmd.php │ ├── InfoModelCmd.php │ ├── InfoModelsCmd.php │ ├── InfoRoutesCmd.php │ ├── InfoValidationCmd.php │ ├── InitAclsCmd.php │ ├── InitCacheCmd.php │ ├── InstallThemeCmd.php │ ├── LiveReloadCmd.php │ ├── MigrationsCmd.php │ ├── NewActionCmd.php │ ├── NewClassCmd.php │ ├── NewDomainCmd.php │ ├── NewMailCmd.php │ ├── NewModelCmd.php │ ├── NewThemeCmd.php │ ├── RestApiCmd.php │ ├── RestCmd.php │ ├── SendMailQueueCmd.php │ ├── TemplateParserCmd.php │ ├── popo │ └── NewModel.php │ └── traits │ └── DbCheckTrait.php ├── core ├── ConsoleScaffoldController.php ├── themesConfig.php └── toolsConfig.php ├── project-files ├── .htaccess ├── README.md ├── app │ ├── .htaccess │ ├── controllers │ │ ├── Admin.php │ │ ├── ControllerBase.php │ │ └── IndexController.php │ └── views │ │ └── themes │ │ ├── bootstrap │ │ └── main │ │ │ ├── vFooter.html │ │ │ ├── vHeader.html │ │ │ └── vMenu.html │ │ ├── foundation │ │ └── main │ │ │ ├── vFooter.html │ │ │ ├── vHeader.html │ │ │ └── vMenu.html │ │ ├── model │ │ └── main │ │ │ ├── vFooter.html │ │ │ ├── vHeader.html │ │ │ └── vMenu.html │ │ └── semantic │ │ └── main │ │ ├── vFooter.html │ │ ├── vHeader.html │ │ └── vMenu.html ├── index.php ├── public │ └── themes │ │ ├── bootstrap │ │ ├── css │ │ │ ├── style.css │ │ │ └── style.css.map │ │ ├── img │ │ │ └── .gitkeep │ │ └── scss │ │ │ ├── _myVariables.scss │ │ │ └── app.scss │ │ ├── foundation │ │ ├── css │ │ │ ├── style.css │ │ │ └── style.css.map │ │ ├── img │ │ │ └── .gitkeep │ │ └── scss │ │ │ ├── _myVariables.scss │ │ │ └── app.scss │ │ ├── model │ │ ├── css │ │ │ └── style.css │ │ ├── img │ │ │ └── .gitkeep │ │ └── js │ │ │ └── .gitkeep │ │ └── semantic │ │ ├── css │ │ └── style.css │ │ └── img │ │ └── .gitkeep └── templates │ ├── .env.tpl │ ├── bootstrap.tpl │ ├── config.tpl │ ├── controller.tpl │ ├── indexNoTheme.tpl │ ├── indexThemes.tpl │ ├── preloader.config.tpl │ ├── preloader.script.tpl │ ├── services.tpl │ ├── vFooter.tpl │ ├── vHeader.tpl │ └── view.tpl ├── server ├── .htrouter.php ├── _index.php ├── _ngx.php ├── _react.php ├── _swoole.php ├── _swow.php └── _workerman.php └── utils └── FrameworkParts.php /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: "[command] Element should do X" 5 | labels: '' 6 | assignees: jcheron 7 | 8 | --- 9 | 10 | 17 | ### Steps 18 | 19 | ### Expected Result 20 | 21 | ### Actual Result 22 | 23 | ### Versions 24 | - Ubiquity framework x.y.z 25 | - Ubiquity devtools x.y.z 26 | - php x.y.z 27 | - OS 28 | -------------------------------------------------------------------------------- /.github/images/db-conf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phpMv/ubiquity-devtools/8c0e8f5923cee82acb25db9e84897960de380875/.github/images/db-conf.png -------------------------------------------------------------------------------- /.github/images/devtools-version.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phpMv/ubiquity-devtools/8c0e8f5923cee82acb25db9e84897960de380875/.github/images/devtools-version.png -------------------------------------------------------------------------------- /.github/images/devtools.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phpMv/ubiquity-devtools/8c0e8f5923cee82acb25db9e84897960de380875/.github/images/devtools.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .buildpath 2 | .project 3 | .settings 4 | vendor/ 5 | composer.lock 6 | .idea/ 7 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## [unreleased] 8 | - nothing 9 | 10 | ## [1.4.8] - 2023-02-05 11 | ### Added 12 | - **v(view)** option with **create-project(new)** command 13 | 14 | ## [1.4.3] - 2022-12-31 15 | ### Updated 16 | - `aclInit` command (add table and models creation) 17 | - `new project` (add init-cache after creation) 18 | 19 | ## [1.4.2] - 2022-12-19 20 | ### Fixed 21 | - add `vlucas/phpdotenv` in composer.json 22 | 23 | ## [1.4.1] - 2022-12-18 24 | ### Fixed 25 | - config cache first initialization 26 | 27 | ## [1.4.0] - 2022-12-18 28 | ### Updated 29 | - Compatibility with Ubiquity 2.5.0 30 | ### Added 31 | - env vars support 32 | ## [1.3.11] - 2022-05-06 33 | ### Updated 34 | - Change root directory to `public` for async platforms 35 | 36 | ## [1.3.10] - 2022-02-15 37 | ### Fixed 38 | - `InstallThemeCmd` pb with `DDDManager` 39 | 40 | ## [1.3.9] - 2022-02-13 41 | 42 | ### Updated 43 | - Default vHeader and vFooter templates 44 | - Add create and 2FA views for Auth controllers 45 | 46 | 47 | ## [1.3.8] - 2022-01-01 48 | ### Fixed 49 | - cache initialization pb with `new-model` command 50 | 51 | ### Changed 52 | - `str_pad` usage for questions in commands 53 | - relocate livereload starting (after nonce creation) 54 | - add nonce in template files 55 | - add default nonce 56 | 57 | ## [1.3.7] - 2021-12-02 58 | ### Fixed 59 | - Other models loading +cache re-init in `new-model` command 60 | - Re-init cache before migrations commands 61 | - typo in `addRelation`: `$namepsace` 62 | 63 | ## [1.3.6] - 2021-12-01 64 | 65 | ### Added 66 | #### Migrations commands: 67 | 68 | ``` 69 | ■ info-migrations [] => 70 | · Returns the migration infos. 71 | · Aliases : info_migrations,info:migrations,infoMigrations 72 | · Parameters : 73 | -d shortcut of --database 74 | The database offset. 75 | Default : [default] 76 | 77 | -o shortcut of --domain 78 | The domain in which the database models are. 79 | 80 | × Samples : 81 | Display all migrations for the default database 82 | · Ubiquity info:migrations 83 | ``` 84 | 85 | ``` 86 | ■ migrations [] => 87 | · Display and execute the database migrations. 88 | · Aliases : migrations,migrate 89 | · Parameters : 90 | -d shortcut of --database 91 | The database offset. 92 | Default : [default] 93 | 94 | -o shortcut of --domain 95 | The domain in which the database models are. 96 | 97 | × Samples : 98 | Display and execute all migrations for the default database 99 | · Ubiquity migrations 100 | ``` 101 | #### Models creation 102 | 103 | ``` 104 | ■ model [modelName] => 105 | · Generates models from scratch. 106 | · Aliases : create_model,create:model,create-model,createModel,new_model,new:model,new-model,newModel 107 | · Parameters : 108 | -d shortcut of --database 109 | The database connection to use 110 | Default : [default] 111 | 112 | -o shortcut of --domain 113 | The domain in which to create the model. 114 | 115 | -k shortcut of --autoincPk 116 | The default primary key defined as autoinc. 117 | Default : [id] 118 | 119 | × Samples : 120 | · Ubiquity model User 121 | · Ubiquity model Author -d=projects 122 | · Ubiquity model Group,User -o=orga 123 | ``` 124 | 125 | ## [1.3.5] - 2021-11-01 126 | 127 | ### Added 128 | - Adds Domain option (`-o` or `--domain`) for commands: `controller, action, auth, crud-index, model, all-models, dao, rest, rest-api, info-model, info-models, info-validation` 129 | 130 | ### Updated 131 | - Command names parsing: 132 | For all commands with multiple parts in the name, the following syntaxes can be used: 133 | ex: for `Ubiquity all-models` 134 | - `Ubiquity all_models` 135 | - `Ubiquity all:models` 136 | - `Ubiquity allModels` 137 | 138 | ## [1.3.4] - 2021-10-07 139 | ### Fixed 140 | - assets folder location with Ubiquity server 141 | 142 | ## [1.3.3] - 2021-09-06 143 | ### Updated 144 | - Default index page 145 | - ui libraries 146 | 147 | ## [1.3.2] - 2021-07-11 148 | #### Added 149 | - `index-crud` command 150 | 151 | ## [1.3.1] - 2021-07-06 152 | #### Fixed 153 | - Application root pb (public folder) with embedded web server 154 | 155 | ## [1.3.0] - 2021-06-15 156 | #### Models generation 157 | - The regeneration of models preserves the code implemented on the existing models. 158 | 159 | #### Application root (breaking change) 160 | - For apache and nginX, root folder is set to public folder (for new projects since Ubiquity 2.4.5) 161 | 162 | For an old project (created with a version prior to 2.4.5), you have to modify ``index.php`` and move the ``index.php`` and ``.htaccess`` files to the ``public`` folder. 163 | 164 | ```php 165 | no routes displayed 182 | 183 | ## [1.2.26] - 2021-03-10 184 | ### Fixed 185 | - crud & rest commands bug 186 | >Call to a member function asAnnotation on null 187 | >BaseControllerCreator line 58 188 | 189 | ## [1.2.25] - 2021-02-15 190 | ### Fixed 191 | - Bug on new class command with parent class (inheritance) 192 | 193 | ## [1.2.24] - 2021-02-08 194 | ### Added 195 | - `newClass` command for creating a new class 196 | 197 | ## [1.2.23] - 2021-02-06 198 | ### Updated 199 | - replace `livereloadx` with `livereload` 200 | >livereloadx has not been updated for 2 years, and does not manage file operations (add, delete). 201 | 202 | - add livereload with default php server 203 | 204 | Starts php web server and livereload (on 35729 port) 205 | ```bash 206 | Ubiquity serve 207 | ``` 208 | 209 | Starts php web server without livereload 210 | ```bash 211 | Ubiquity serve -n 212 | ``` 213 | 214 | ## [1.2.22] - 2021-02-05 215 | ### Added 216 | - `live-reload` command for dev server 217 | 218 | ## [1.2.21] - 2021-01-17 219 | ### Added 220 | - `newKey` command for generating the encryption key with Ubiquity-security 221 | 222 | ## [1.2.20] - 2020-12-31 223 | ### Fixed 224 | - new action problem 225 | >Call to a member function asAnnotation() on null 226 | 227 | ## [1.2.19] - 2020-12-31 228 | 229 | ### Updated 230 | - Add attributes or annotations fix 231 | 232 | ## [1.2.18] - 2020-12-11 233 | 234 | ### Added 235 | - `display-acls` command 236 | 237 | ### Updated 238 | - composer for php 8 239 | 240 | ## [1.2.17] - 2020-09-30 241 | ### Updated 242 | - add access option (member access) to all-models & create-model cmd 243 | - add db offset param to info:models command 244 | - add OS in version command 245 | 246 | ## [1.2.16] - 2020-07-28 247 | ### Updated 248 | - Update client libraries for new projects (Fomantic 2.8.6) 249 | - Fix session name generation pb (only alphanumeric chars) 250 | 251 | ## [1.2.15] - 2020-06-27 252 | ### Added 253 | - Add `create:command`command 254 | - support for custom commands 255 | ### Updated 256 | - move utility classes to `ubiquity-commands` repo 257 | - Update client libraries for new projects (Fomantic 2.8.5) 258 | 259 | ## [1.2.14] - 2020-05-06 260 | #### Updated 261 | - Update client libraries for new projects (Fomantic 2.8.4, jQuery 3.5.1) 262 | - Add port checking for `Ubiquity serve` command 263 | ## [1.2.13] - 2020-03-23 264 | #### Added 265 | - roadrunner server command (Thanks @Lapinskas) 266 | 267 | `Ubiquity serve -t=roadrunner` 268 | #### Added 269 | 270 | ## [1.2.12] - 2020-01-25 271 | #### Added 272 | - Mailer commands (mailer, newMail, sendMail) 273 | - opcache preloading in project creation 274 | #### Changed 275 | - set `help` as default command 276 | - require php 7.4 277 | 278 | ## [1.2.11] - 2019-11-18 279 | #### Changed 280 | - Update client libraries for new projects (Fomantic 2.8, jQuery 3.4.1, phpMv-ui 2.3) 281 | - require php 7.2 282 | 283 | ## [1.2.10] - 2019-10-28 284 | #### Added 285 | - Composer create-project 286 | ``` 287 | composer create-project phpmv/ubiquity-project {projectName} 288 | ``` 289 | 290 | ## [1.2.9] - 2019-09-25 291 | ### Fixed 292 | - [Cannot set database](https://github.com/phpMv/ubiquity/issues/74) 293 | - https://github.com/phpMv/ubiquity/issues/72 294 | - Fix https://github.com/phpMv/ubiquity-devtools/commit/c06b6704126a4bf56b2a6a52c60aa1d40edcfcdb 295 | ### Added 296 | #### Commands 297 | - `composer` [cmd] 298 | 299 | Samples: 300 | ``` 301 | Ubiquity composer update 302 | Ubiquity composer nodev 303 | Ubiquity composer optimize 304 | ``` 305 | - `bootstrap` [cmd] 306 | 307 | Execute the `cmd` method from the `.ubiquity/_bootstrap.php` file to prepare an environment. 308 | 309 | Sample: 310 | ``` 311 | Ubiquity bootstrap prod 312 | Ubiquity bootstrap dev 313 | ``` 314 | ## [1.2.8] - 2019-08-01 315 | ### Changed 316 | - `model` (`create-model`) command 317 | - added parameter `d`(`database`): the database connection name defined in config file (use default connection if absent) 318 | 319 | Samples: 320 | ``` 321 | Ubiquity model Author -d=projects 322 | Ubiquity model Author --database=projects 323 | ``` 324 | 325 | - `all-models` (`create-all-models`) command 326 | - added parameter `d`(`database`): the database connection name defined in config file (use default connection if absent) 327 | - removed parameter `b`(`dbName`): the database name defined in config file 328 | 329 | Samples: 330 | ``` 331 | Ubiquity all-models -d=projects 332 | Ubiquity create-all-models --database=projects 333 | ``` 334 | ## [1.2.7] - 2019-07-03 335 | ### Changed 336 | - Checks if devtools are globally installed in ``sefUpdate`` op 337 | - Integrates ubiquity-webtools ``2.2.0`` (in a separate repository) 338 | 339 | ### Fixed 340 | - Remove warning for ``\DS`` constant redefinition (thanks @TakeMeNL) 341 | 342 | ## [1.2.6] - 2019-06-13 343 | ### Added 344 | - Ubiquity Swoole server: ``Ubiquity serve -t=swoole`` 345 | - Parameters for `new` command see [#45](https://github.com/phpMv/ubiquity/issues/45) 346 | - `siteUrl (i)` : Sets the site base URL. 347 | - `rewriteBase (e)` : Sets .htaccess file rewriteBase. 348 | 349 | Use 350 | ``` 351 | Ubiquity new fooProject -i=http://foo.local -w=foo 352 | ``` 353 | or 354 | ``` 355 | Ubiquity new fooProject --siteUrl=http://foo.local --rewriteBase=foo 356 | ``` 357 | ## [1.2.5] - 2019-05-10 358 | ### Fixed 359 | - Warning in pages with php Web server Fix: [#5](https://github.com/phpMv/ubiquity-devtools/issues/5) 360 | 361 | ## [1.2.4] - 2019-05-09 362 | ### Added 363 | - **README.md** file for new projects 364 | - ReactPHP server: ```Ubiquity serve t=react``` 365 | 366 | ### Fixed 367 | - Change of theme without control in the ``ct`` action of ``IndexController`` for new projects : see Ubiquity issue [#38](https://github.com/phpMv/ubiquity/issues/38) 368 | 369 | ## [1.2.3] - 2019-04-03 370 | - relooking of the messages for clarity 371 | 372 | ## [1.2.2] - 2019-04-02 373 | - Fix issue [#22](https://github.com/phpMv/ubiquity/issues/22) (install without -a option bug) 374 | 375 | ## [1.2.0] - 2019-04-01 376 | ### Added 377 | - Commands 378 | - `install-theme` for installing Bootstrap, Semantic-UI or Foundation 379 | - `create-theme` for creating a new theme (eventually based on a ref theme) 380 | ### Changed 381 | - `services.tpl file` 382 | ### Fixed 383 | - An exception is thrown In case of problem with the Database connection (in `DataBase::connect` method) see https://github.com/phpMv/ubiquity/issues/12 384 | >The connection to the database must be protected by a `try/catch` in `app/config/services.php` 385 | ``` 386 | try{ 387 | \Ubiquity\orm\DAO::startDatabase($config); 388 | }catch(Exception $e){ 389 | echo $e->getMessage(); 390 | } 391 | ``` 392 | 393 | ## [1.1.6] - 2019-03-14 394 | ### Added 395 | - New commands 396 | - ``Ubiquity restapi`` -> create a REST API controller (based on JsonApi) 397 | - ``Ubiquity rest`` -> create a REST controller associated to a model 398 | - ``Ubiquity dao`` -> query the database 399 | - getOne 400 | - getAll 401 | - uGetOne 402 | - uGetAll 403 | - count 404 | - uCount 405 | 406 | ### Fixed 407 | - [New project template has invalid link to Admin page](https://github.com/phpMv/ubiquity/issues/8) 408 | 409 | ## [1.1.5] - 2019-02-22 410 | ### Added 411 | - New commands 412 | - ``Ubiquity config`` -> display config file variables 413 | - ``Ubiquity config:set --database.dbName=blog`` -> modify/add and save config variables 414 | - ``Ubiquity info:models`` -> display all models metadatas 415 | - ``Ubiquity info:model -m=User`` -> display metadatas for the selected model 416 | - ``Ubiquity info:validation`` -> display validation infos for all models or the selected one 417 | 418 | ### Changed 419 | - Project structure (commands are in separate classes). 420 | - services.tpl template for new project creation 421 | 422 | ## [1.1.4] - 2019-02-18 423 | ### Added 424 | - New commands 425 | - ``Ubiquity info:routes`` -> display the router informations/test the routes resolution (with -s parameter) 426 | 427 | ### Changed 428 | - Project structure (src folder). 429 | 430 | ## [1.1.3] - 2019-02-13 431 | ### Added 432 | - New commands 433 | - ``Ubiquity serve`` -> php internal web server for dev 434 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![img](https://github.com/phpmv/ubiquity-devtools/blob/master/.github/images/devtools.png?raw=true) 2 | 3 | [![Latest Stable Version](https://poser.pugx.org/phpmv/ubiquity-devtools/v/stable)](https://packagist.org/packages/phpmv/ubiquity-devtools) 4 | [![Total Downloads](https://poser.pugx.org/phpmv/ubiquity-devtools/downloads)](https://packagist.org/packages/phpmv/ubiquity-devtools) 5 | [![License](https://poser.pugx.org/phpmv/ubiquity-devtools/license)](https://packagist.org/packages/phpmv/ubiquity-devtools) 6 | [![Documentation Status](https://readthedocs.org/projects/micro-framework/badge/?version=latest)](http://micro-framework.readthedocs.io/en/latest/?badge=latest) 7 | 8 | Command line tools for [Ubiquity framework](https://github.com/phpMv/ubiquity) 9 | ## I - Installation 10 | 11 | ### Installing via Composer 12 | 13 | Install Composer in a common location or in your project: 14 | 15 | ```bash 16 | curl -s http://getcomposer.org/installer | php 17 | ``` 18 | Run the composer installer : 19 | 20 | ```bash 21 | composer global require phpmv/ubiquity-devtools 22 | ``` 23 | Make sure to place the `~/.composer/vendor/bin` directory in your PATH so the **Ubiquity** executable can be located by your system. 24 | 25 | To confirm **Ubiquity** was successfully installed, type ``Ubiquity version``: 26 | 27 | ![img](https://github.com/phpmv/ubiquity-devtools/blob/master/.github/images/devtools-version.png) 28 | 29 |
30 | If you get the message Ubiquity command not found 31 | Add composer's bin directory to the system path 32 | 44 |
45 | 46 | ## II Devtools commands 47 | ### Information 48 | To get a list of available commands just run in console: 49 | ```bash 50 | Ubiquity help 51 | ``` 52 | This command should display something similar to: 53 | 54 | ```bash 55 | Ubiquity devtools (1.3.6) 56 | 57 | ■ init-cache [] => 58 | · Init the cache for models, router, rest. 59 | · Aliases : init_cache,init:cache,initCache 60 | · Parameters : 61 | -t shortcut of --type 62 | Defines the type of cache to create. 63 | Possibles values : 64 | all,controllers,acls,rest,models 65 | Default : [all] 66 | 67 | × Samples : 68 | Init all caches 69 | · Ubiquity init-cache 70 | Init models cache 71 | · Ubiquity init-cache -t=models 72 | 73 | ■ clear-cache [] => 74 | · Clear models cache. 75 | · Aliases : clear_cache,clear:cache,clearCache 76 | · Parameters : 77 | -t shortcut of --type 78 | Defines the type of cache to reset. 79 | Possibles values : 80 | all,annotations,controllers,rest,models,queries,views 81 | Default : [all] 82 | 83 | × Samples : 84 | Clear all caches 85 | · Ubiquity clear-cache -t=all 86 | Clear models cache 87 | · Ubiquity clear-cache -t=models 88 | 89 | ■ controller [controllerName] => 90 | · Creates a new controller. 91 | · Aliases : create_controller,create:controller,create-controller,createController 92 | · Parameters : 93 | -v shortcut of --views 94 | creates an associated view folder and index.html 95 | Possibles values : 96 | true,false 97 | Default : [false] 98 | 99 | -o shortcut of --domain 100 | The domain in which to create the controller. 101 | 102 | × Samples : 103 | Creates a controller 104 | · Ubiquity controller UserController 105 | with its associated view 106 | · Ubiquity controller UserController -v 107 | Creates a controller in the orga domain 108 | · Ubiquity controller OrgaController -o=orga 109 | 110 | ■ action [controller.action] => 111 | · Creates a new action in a controller. 112 | · Aliases : new-action,new_action,new:action,newAction 113 | · Parameters : 114 | -p shortcut of --params 115 | The action parameters (or arguments) 116 | 117 | -r shortcut of --route 118 | The associated route path 119 | 120 | -v shortcut of --create-view 121 | Creates the associated view 122 | Possibles values : 123 | true,false 124 | Default : [false] 125 | 126 | -o shortcut of --domain 127 | The domain in which the controller is. 128 | 129 | × Samples : 130 | Adds the action all in controller Users 131 | · Ubiquity action Users.all 132 | Adds the action display in controller Users with a parameter 133 | · Ubiquity action Users.display -p=idUser 134 | and associates a route to it 135 | · Ubiquity action Users.display -p=idUser -r=/users/display/{idUser} 136 | with multiple parameters 137 | · Ubiquity action Users.search -p=name,address 138 | and create the associated view 139 | · Ubiquity action Users.search -p=name,address -v 140 | 141 | ■ auth [authControllerName] => 142 | · Creates a new controller for authentification. 143 | · Aliases : auth-controller,auth_controller,auth:controller,authController 144 | · Parameters : 145 | -e shortcut of --extends 146 | The base class of the controller (must derived from AuthController) 147 | Default : [Ubiquity\controllers\auth\AuthController] 148 | 149 | -t shortcut of --templates 150 | The templates to modify 151 | Possibles values : 152 | index,info,noAccess,disconnected,message,baseTemplate 153 | Default : [index,info,noAccess,disconnected,message,baseTemplate] 154 | 155 | -p shortcut of --path 156 | The associated route 157 | 158 | -o shortcut of --domain 159 | The domain in which to create the controller. 160 | 161 | × Samples : 162 | Creates a new controller for authentification 163 | · Ubiquity auth AdminAuthController 164 | and associates a route to it 165 | · Ubiquity auth AdminAuthController -p=/admin/auth 166 | allows customization of index and info templates 167 | · Ubiquity auth AdminAuthController -t=index,info 168 | 169 | ■ crud-index [crudControllerName] => 170 | · Creates a new index-CRUD controller. 171 | · Aliases : crud-index-controller,crud_index,crud:index,crudIndex 172 | · Parameters : 173 | -d shortcut of --datas 174 | The associated Datas class 175 | Possibles values : 176 | true,false 177 | Default : [true] 178 | 179 | -v shortcut of --viewer 180 | The associated Viewer class 181 | Possibles values : 182 | true,false 183 | Default : [true] 184 | 185 | -e shortcut of --events 186 | The associated Events class 187 | Possibles values : 188 | true,false 189 | Default : [true] 190 | 191 | -t shortcut of --templates 192 | The templates to modify 193 | Possibles values : 194 | index,form,display,item,itemHome 195 | Default : [index,form,display,home,itemHome] 196 | 197 | -p shortcut of --path 198 | The associated route 199 | Default : [{resource}] 200 | 201 | -o shortcut of --domain 202 | The domain in which to create the controller. 203 | 204 | × Samples : 205 | Creates an index crud controller 206 | · Ubiquity crud-index MainCrud -p=crud/{resource} 207 | allows customization of index and form templates 208 | · Ubiquity index-crud MainCrud -t=index,form 209 | 210 | ■ crud [crudControllerName] => 211 | · Creates a new CRUD controller. 212 | · Aliases : crud_controller,crud:controller,crud-controller,crudController 213 | · Parameters : 214 | -r shortcut of --resource 215 | The model used 216 | 217 | -d shortcut of --datas 218 | The associated Datas class 219 | Possibles values : 220 | true,false 221 | Default : [true] 222 | 223 | -v shortcut of --viewer 224 | The associated Viewer class 225 | Possibles values : 226 | true,false 227 | Default : [true] 228 | 229 | -e shortcut of --events 230 | The associated Events class 231 | Possibles values : 232 | true,false 233 | Default : [true] 234 | 235 | -t shortcut of --templates 236 | The templates to modify 237 | Possibles values : 238 | index,form,display 239 | Default : [index,form,display] 240 | 241 | -p shortcut of --path 242 | The associated route 243 | 244 | -o shortcut of --domain 245 | The domain in which to create the controller. 246 | 247 | × Samples : 248 | Creates a crud controller for the class models\User 249 | · Ubiquity crud CrudUsers -r=User 250 | and associates a route to it 251 | · Ubiquity crud CrudUsers -r=User -p=/users 252 | allows customization of index and form templates 253 | · Ubiquity crud CrudUsers -r=User -t=index,form 254 | Creates a crud controller for the class models\projects\Author 255 | · Ubiquity crud Authors -r=models\projects\Author 256 | 257 | ■ new-class [name] => 258 | · Creates a new class. 259 | · Aliases : new_class,new:class,newClass,class 260 | · Parameters : 261 | -p shortcut of --parent 262 | The class parent. 263 | 264 | × Samples : 265 | Creates a new class 266 | · Ubiquity class services.OrgaRepository 267 | 268 | ■ create-theme [themeName] => 269 | · Creates a new theme or installs an existing one. 270 | · Aliases : create_theme,create:theme,createTheme 271 | · Parameters : 272 | -x shortcut of --extend 273 | If specified, inherits from an existing theme (bootstrap,semantic or foundation). 274 | Possibles values : 275 | bootstrap,semantic,foundation 276 | 277 | -o shortcut of --domain 278 | The domain in which to create the theme. 279 | 280 | × Samples : 281 | Creates a new theme custom 282 | · Ubiquity create-theme custom 283 | Creates a new theme inheriting from Bootstrap 284 | · Ubiquity theme myBootstrap -x=bootstrap 285 | 286 | ■ theme [themeName] => 287 | · Installs an existing theme or creates a new one if the specified theme does not exists. 288 | · Aliases : install_theme,install-theme,install:theme,installTheme 289 | · Parameters : 290 | -o shortcut of --domain 291 | The domain in which to install the theme. 292 | 293 | × Samples : 294 | Creates a new theme custom 295 | · Ubiquity theme custom 296 | Install bootstrap theme 297 | · Ubiquity theme bootstrap 298 | 299 | ■ project [projectName] => 300 | · Creates a new #ubiquity project. 301 | · Aliases : new,create_project 302 | · Parameters : 303 | -b shortcut of --dbName 304 | Sets the database name. 305 | 306 | -s shortcut of --serverName 307 | Defines the db server address. 308 | Default : [127.0.0.1] 309 | 310 | -p shortcut of --port 311 | Defines the db server port. 312 | Default : [3306] 313 | 314 | -u shortcut of --user 315 | Defines the db server user. 316 | Default : [root] 317 | 318 | -w shortcut of --password 319 | Defines the db server password. 320 | 321 | -h shortcut of --themes 322 | Install themes. 323 | Possibles values : 324 | semantic,bootstrap,foundation 325 | 326 | -m shortcut of --all-models 327 | Creates all models from database. 328 | 329 | -a shortcut of --admin 330 | Adds UbiquityMyAdmin tool. 331 | Possibles values : 332 | true,false 333 | Default : [false] 334 | 335 | -i shortcut of --siteUrl 336 | Sets the site base URL. 337 | 338 | -e shortcut of --rewriteBase 339 | Sets .htaccess file rewriteBase. 340 | 341 | × Samples : 342 | Creates a new project 343 | · Ubiquity new blog 344 | With admin interface 345 | · Ubiquity new blog -a 346 | and models generation 347 | · Ubiquity new blog -a -m -b=blogDB 348 | 349 | ■ serve [] => 350 | · Start a web server. 351 | · Parameters : 352 | -h shortcut of --host 353 | Sets the host ip address. 354 | Default : [127.0.0.1] 355 | 356 | -p shortcut of --port 357 | Sets the listen port number. 358 | Default : [8090] 359 | 360 | -n shortcut of --nolr 361 | Starts without live-reload. 362 | 363 | -l shortcut of --lrport 364 | Sets the live-reload listen port number. 365 | Default : [35729] 366 | 367 | -t shortcut of --type 368 | Sets the server type. 369 | Possibles values : 370 | php,react,swoole,roadrunner 371 | Default : [php] 372 | 373 | × Samples : 374 | Starts a php server at 127.0.0.1:8090 375 | · Ubiquity serve 376 | Starts a reactPHP server at 127.0.0.1:8080 377 | · Ubiquity serve -t=react 378 | 379 | ■ livereload [path] => 380 | · Start the live reload server. 381 | · Aliases : live-reload,live 382 | · Parameters : 383 | -p shortcut of --port 384 | Sets the listen port number. 385 | Default : [35729] 386 | 387 | -e shortcut of --exts 388 | Specify extentions to observe . 389 | Default : [php,html] 390 | 391 | -x shortcut of --exclusions 392 | Exclude file matching pattern . 393 | Default : [cache/,logs/] 394 | 395 | × Samples : 396 | Starts the live-reload server at 127.0.0.1:35729 397 | · Ubiquity live-reload 398 | Starts the live-reload server at 127.0.0.1:35800 excluding logs directory 399 | · Ubiquity live-reload -p=35800 -x=logs/ 400 | 401 | ■ bootstrap [command] => 402 | · Executes a command created in app/config/_bootstrap.php file for bootstraping the app. 403 | · Aliases : boot 404 | × Samples : 405 | Bootstrap for dev mode 406 | · Ubiquity bootstrap dev 407 | Bootstrap for prod mode 408 | · Ubiquity bootstrap prod 409 | 410 | ■ help [?] => 411 | · Get some help about a dev-tools command. 412 | × Samples : 413 | Get some help about crud 414 | · Ubiquity help crud 415 | 416 | ■ version [] => 417 | · Return PHP, Framework and dev-tools versions. 418 | 419 | ■ model [modelName] => 420 | · Generates models from scratch. 421 | · Aliases : create_model,create:model,create-model,createModel,new_model,new:model,new-model,newModel 422 | · Parameters : 423 | -d shortcut of --database 424 | The database connection to use 425 | Default : [default] 426 | 427 | -o shortcut of --domain 428 | The domain in which to create the model. 429 | 430 | -k shortcut of --autoincPk 431 | The default primary key defined as autoinc. 432 | Default : [id] 433 | 434 | × Samples : 435 | · Ubiquity model User 436 | · Ubiquity model Author -d=projects 437 | · Ubiquity model Group,User -o=orga 438 | 439 | ■ genModel [tableName] => 440 | · Generates a new model from an existing table. 441 | · Aliases : gen_model,gen:model,gen-model,genModel 442 | · Parameters : 443 | -d shortcut of --database 444 | The database connection to use 445 | Default : [default] 446 | 447 | -a shortcut of --access 448 | The default access to the class members 449 | Default : [private] 450 | 451 | -o shortcut of --domain 452 | The domain in which to create the model. 453 | 454 | × Samples : 455 | · Ubiquity genModel User 456 | · Ubiquity genModel Author -d=projects 457 | · Ubiquity genModel Author -d=projects -a=protected 458 | 459 | ■ all-models [] => 460 | · Generates all models from database. 461 | · Aliases : create-all-models,all_models,all:models,allModels 462 | · Parameters : 463 | -d shortcut of --database 464 | The database connection to use (offset) 465 | Default : [default] 466 | 467 | -a shortcut of --access 468 | The default access to the class members 469 | Default : [private] 470 | 471 | -o shortcut of --domain 472 | The domain in which to create the models. 473 | 474 | × Samples : 475 | · Ubiquity all-models 476 | · Ubiquity all-models -d=projects 477 | · Ubiquity all-models -d=projects -a=protected 478 | 479 | ■ info-migrations [] => 480 | · Returns the migration infos. 481 | · Aliases : info_migrations,info:migrations,infoMigrations 482 | · Parameters : 483 | -d shortcut of --database 484 | The database offset. 485 | Default : [default] 486 | 487 | -o shortcut of --domain 488 | The domain in which the database models are. 489 | 490 | × Samples : 491 | Display all migrations for the default database 492 | · Ubiquity info:migrations 493 | 494 | ■ migrations [] => 495 | · Display and execute the database migrations. 496 | · Aliases : migrations,migrate 497 | · Parameters : 498 | -d shortcut of --database 499 | The database offset. 500 | Default : [default] 501 | 502 | -o shortcut of --domain 503 | The domain in which the database models are. 504 | 505 | × Samples : 506 | Display and execute all migrations for the default database 507 | · Ubiquity migrations 508 | 509 | ■ dao [command] => 510 | · Executes a DAO command (getAll,getOne,count,uGetAll,uGetOne,uCount). 511 | · Aliases : DAO 512 | · Parameters : 513 | -r shortcut of --resource 514 | The model used 515 | 516 | -c shortcut of --condition 517 | The where part of the query 518 | 519 | -i shortcut of --included 520 | The associated members to load (boolean or array: client.*,commands) 521 | 522 | -p shortcut of --parameters 523 | The parameters for a parameterized query 524 | 525 | -f shortcut of --fields 526 | The fields to display in the response 527 | 528 | -o shortcut of --domain 529 | The domain in which the models are. 530 | 531 | × Samples : 532 | Returns all instances of models\User 533 | · Ubiquity dao getAll -r=User 534 | Returns all instances of models\User and includes their commands 535 | · Ubiquity dao getAll -r=User -i=commands 536 | Returns the User with the id 5 537 | · Ubiquity dao getOne -c="id=5"-r=User 538 | Returns the list of users belonging to the "Brittany" or "Normandy" regions 539 | · Ubiquity uGetAll -r=User -c="region.name= ? or region.name= ?" -p=Brittany,Normandy 540 | 541 | ■ self-update [] => 542 | · Updates Ubiquity framework for the current project. 543 | 544 | ■ composer [command] => 545 | · Executes a composer command. 546 | · Aliases : compo 547 | × Samples : 548 | composer update 549 | · Ubiquity composer update 550 | composer update with no-dev 551 | · Ubiquity composer nodev 552 | composer optimization for production 553 | · Ubiquity composer optimize 554 | 555 | ■ admin [] => 556 | · Add UbiquityMyAdmin webtools to the current project. 557 | 558 | ■ rest [restControllerName] => 559 | · Creates a new REST controller. 560 | · Aliases : rest-controller,rest:controller,rest_controller,restController 561 | · Parameters : 562 | -r shortcut of --resource 563 | The model used 564 | 565 | -p shortcut of --path 566 | The associated route 567 | 568 | -o shortcut of --domain 569 | The domain in which to create the controller. 570 | 571 | × Samples : 572 | Creates a REST controller for the class models\User 573 | · Ubiquity rest RestUsers -r=User -p=/rest/users 574 | 575 | ■ restapi [restControllerName] => 576 | · Creates a new REST API controller. 577 | · Aliases : restapi-controller,restapi:controller,restapi_controller,restapiController 578 | · Parameters : 579 | -p shortcut of --path 580 | The associated route 581 | 582 | -o shortcut of --domain 583 | The domain in which to create the controller. 584 | 585 | × Samples : 586 | Creates a REST API controller 587 | · Ubiquity restapi -p=/rest 588 | 589 | ■ info-routes [] => 590 | · Display the cached routes. 591 | · Aliases : info:r,info_routes,info:routes,infoRoutes 592 | · Parameters : 593 | -t shortcut of --type 594 | Defines the type of routes to display. 595 | Possibles values : 596 | all,routes,rest 597 | 598 | -l shortcut of --limit 599 | Specifies the number of routes to return. 600 | 601 | -o shortcut of --offset 602 | Specifies the number of routes to skip before starting to return. 603 | 604 | -s shortcut of --search 605 | Search routes corresponding to a path. 606 | 607 | -m shortcut of --method 608 | Allows to specify a method with search attribute. 609 | Possibles values : 610 | get,post,put,delete,patch 611 | 612 | × Samples : 613 | All routes 614 | · Ubiquity info:routes 615 | Rest routes 616 | · Ubiquity info:routes -type=rest 617 | Only the routes with the method post 618 | · Ubiquity info:routes -type=rest -m=-post 619 | 620 | ■ info-model [?infoType] => 621 | · Returns the model meta datas. 622 | · Aliases : info_model,info:model,infoModel 623 | · Parameters : 624 | -s shortcut of --separate 625 | If true, returns each info in a separate table 626 | Possibles values : 627 | true,false 628 | Default : [false] 629 | 630 | -m shortcut of --model 631 | The model on which the information is sought. 632 | 633 | -f shortcut of --fields 634 | The fields to display in the table. 635 | 636 | -o shortcut of --domain 637 | The domain in which the models is. 638 | 639 | × Samples : 640 | Gets metadatas for User class 641 | · Ubiquity info:model -m=User 642 | 643 | ■ info-models [] => 644 | · Returns the models meta datas. 645 | · Aliases : info_models,info:models,infoModels 646 | · Parameters : 647 | -d shortcut of --database 648 | The database connection to use (offset) 649 | Default : [default] 650 | 651 | -m shortcut of --models 652 | The models on which the information is sought. 653 | 654 | -f shortcut of --fields 655 | The fields to display in the table. 656 | 657 | -o shortcut of --domain 658 | The domain in which the models are. 659 | 660 | × Samples : 661 | Gets metadatas for all models in default db 662 | · Ubiquity info:models 663 | Gets metadatas for all models in messagerie db 664 | · Ubiquity info:models -d=messagerie 665 | Gets metadatas for User and Group models 666 | · Ubiquity info:models -m=User,Group 667 | Gets all primary keys for all models 668 | · Ubiquity info:models -f=#primaryKeys 669 | 670 | ■ info-validation [?memberName] => 671 | · Returns the models validation info. 672 | · Aliases : info_validation,info:validation,infoValidation,info_validators,info-validators,info:validators,infoValidators 673 | · Parameters : 674 | -s shortcut of --separate 675 | If true, returns each info in a separate table 676 | Possibles values : 677 | true,false 678 | Default : [false] 679 | 680 | -m shortcut of --model 681 | The model on which the information is sought. 682 | 683 | -o shortcut of --domain 684 | The domain in which the models is. 685 | 686 | × Samples : 687 | Gets validators for User class 688 | · Ubiquity info:validation -m=User 689 | Gets validators for User class on member firstname 690 | · Ubiquity info:validation firstname -m=User 691 | 692 | ■ config [] => 693 | · Returns the config informations from app/config/config.php. 694 | · Aliases : info_config,info-config,info:config,infoConfig 695 | · Parameters : 696 | -f shortcut of --fields 697 | The fields to display. 698 | 699 | × Samples : 700 | Display all config vars 701 | · Ubiquity config 702 | Display database config vars 703 | · Ubiquity config -f=database 704 | 705 | ■ config-set [] => 706 | · Modify/add variables and save them in app/config/config.php. Supports only long parameters with --. 707 | · Aliases : set_config,set-config,set:config,setConfig 708 | × Samples : 709 | Assigns a new value to siteURL 710 | · Ubiquity config:set --siteURL=http://127.0.0.1/quick-start/ 711 | Change the database name and port 712 | · Ubiquity config:set --database.dbName=blog --database.port=3307 713 | 714 | ■ mailer [part] => 715 | · Displays mailer classes, mailer queue or mailer dequeue. 716 | × Samples : 717 | Display mailer classes 718 | · Ubiquity mailer classes 719 | Display mailer messages in queue(To send) 720 | · Ubiquity mailer queue 721 | Display mailer messages in dequeue(sent) 722 | · Ubiquity mailer dequeue 723 | 724 | ■ new-mail [name] => 725 | · Creates a new mailer class. 726 | · Aliases : new_mail,new:mail,newMail 727 | · Parameters : 728 | -p shortcut of --parent 729 | The class parent. 730 | Default : [\Ubiquity\mailer\AbstractMail] 731 | 732 | -v shortcut of --view 733 | Add the associated view. 734 | 735 | × Samples : 736 | Creates a new mailer class 737 | · Ubiquity newMail InformationMail 738 | 739 | ■ send-mail [] => 740 | · Send message(s) from queue. 741 | · Aliases : send-mails,send_mails,send:mails,sendMails 742 | · Parameters : 743 | -n shortcut of --num 744 | If specified, Send the mail at the position n in queue. 745 | 746 | × Samples : 747 | Send all messages to send from queue 748 | · Ubiquity semdMails 749 | Send the first message in queue 750 | · Ubiquity sendMail 1 751 | 752 | ■ create-command [commandName] => 753 | · Creates a new custom command for the devtools. 754 | · Aliases : create_command,create:command,createCommand 755 | · Parameters : 756 | -v shortcut of --value 757 | The command value (first parameter). 758 | 759 | -p shortcut of --parameters 760 | The command parameters (comma separated). 761 | 762 | -d shortcut of --description 763 | The command description. 764 | 765 | -a shortcut of --aliases 766 | The command aliases (comma separated). 767 | 768 | × Samples : 769 | Creates a new custom command 770 | · Ubiquity create-command custom 771 | 772 | ■ acl-init [] => 773 | · Initialize Acls defined with annotations in controllers. 774 | · Aliases : acl_init,acl:init,aclInit 775 | × Samples : 776 | Initialize Acls 777 | · Ubiquity aclInit 778 | 779 | ■ acl-display [] => 780 | · Display Acls defined with annotations in controllers. 781 | · Aliases : acl_display,acl:display,aclDisplay 782 | · Parameters : 783 | -v shortcut of --value 784 | The ACL part to display. 785 | Possibles values : 786 | all,role,resource,permission,map,acl 787 | Default : [acl] 788 | 789 | × Samples : 790 | Display all defined roles with ACL annotations 791 | · Ubiquity aclDisplay role 792 | 793 | ■ new-key [cypher] => 794 | · Generate a new encryption key using a cipher. 795 | · Aliases : new_key,new:key,newKey 796 | × Samples : 797 | Generate a key for AES-128 798 | · Ubiquity new-key 128 799 | 800 | ■ domain [name] => 801 | · Creates a new domain (for a Domain Driven Design approach). 802 | · Aliases : new-domain,new_domain,new:domain,newDomain 803 | · Parameters : 804 | -b shortcut of --base 805 | The base folder for domains. 806 | Default : [domains] 807 | 808 | × Samples : 809 | Creates a new domain users 810 | · Ubiquity domain users 811 | ``` 812 | 813 | ### Project creation 814 | Once installed, the simple `Ubiquity new` command will create a fresh micro installation in the directory you specify. For instance, `Micro new blog` would create a directory named blog containing an Ubiquity project: 815 | ```bash 816 | Ubiquity new blog 817 | ``` 818 | You can see more options about installation by reading the [Project creation section](http://micro-framework.readthedocs.io/en/latest/install.html). 819 | 820 | ### Running 821 | You can test with the php web server, 822 | from the root folder of your web application, run : 823 | ``` 824 | Ubiquity serve 825 | ``` 826 | 827 | ### Models creation 828 | make sure that the database is configured properly in app/config/config.php file : 829 | ```bash 830 | Ubiquity config -f=database 831 | ``` 832 | 833 | ![img](https://github.com/phpmv/ubiquity-devtools/blob/master/.github/images/db-conf.png) 834 | 835 | Execute the command, make sure you are also in the project folder or one of its subfolders : 836 | ```bash 837 | Ubiquity all-models 838 | ``` 839 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "phpmv/ubiquity-devtools", 3 | "description": "Command line tools for ubiquity-framework", 4 | "type": "installer", 5 | "keywords": [ 6 | "php", 7 | "framework" 8 | ], 9 | "require": { 10 | "php": ">=7.4", 11 | "phpmv/ubiquity-commands":"^0.0", 12 | "symfony/process": "^5.2", 13 | "vlucas/phpdotenv": "^5.5" 14 | }, 15 | "license": "Apache-2.0", 16 | "authors": [ 17 | { 18 | "name": "Jean-Christophe HERON", 19 | "email": "myaddressmail@gmail.com", 20 | "role": "Lead developer" 21 | } 22 | ], 23 | "bin": [ 24 | "src/Ubiquity" 25 | ], 26 | "autoload" : { 27 | "psr-4" : { 28 | "Ubiquity\\" : "src/" 29 | } 30 | }, 31 | "extra": { 32 | "branch-alias": { 33 | "dev-master": "1.3.x-dev" 34 | } 35 | }, 36 | "minimum-stability": "dev", 37 | "prefer-stable": true 38 | } 39 | -------------------------------------------------------------------------------- /src/devtools/cmd/commands/AbstractCmdModel.php: -------------------------------------------------------------------------------- 1 | setIndent(5); 26 | $rArray=new ClassicArray($infos,$what); 27 | if(is_array($aFields) && sizeof($aFields)>0){ 28 | $rArray->setFields($aFields); 29 | } 30 | $tbl->setDatas($rArray->parse()); 31 | if($what!=null){ 32 | echo ConsoleFormatter::showInfo($what); 33 | } 34 | echo $tbl->getTable(); 35 | if($rArray->hasMessages()){ 36 | echo ConsoleFormatter::showMessage(implode("\n", $rArray->getMessages()),'error'); 37 | } 38 | } 39 | } 40 | 41 | } 42 | 43 | -------------------------------------------------------------------------------- /src/devtools/cmd/commands/AbstractThemeCmd.php: -------------------------------------------------------------------------------- 1 | addAuthController($what, $baseClass, $authView, $routePath); 16 | } 17 | } 18 | 19 | -------------------------------------------------------------------------------- /src/devtools/cmd/commands/ConfigCmd.php: -------------------------------------------------------------------------------- 1 | app/config/config.php file'); 12 | $datas=$config; 13 | $fields=self::getOption($options, 'f', 'fields'); 14 | if($fields!=null){ 15 | $fields=explode(",", $fields); 16 | } 17 | if($what!=null && isset($config[$what])){ 18 | $datas=$config[$what]; 19 | } 20 | $tbl=new ConsoleTable(); 21 | $tbl->setIndent(5); 22 | $rArray=new ClassicArray($datas,$what); 23 | if(is_array($fields) && sizeof($fields)>0){ 24 | $rArray->setFields($fields); 25 | } 26 | $tbl->setDatas($rArray->parse()); 27 | if($what!=null){ 28 | echo ConsoleFormatter::showInfo($what); 29 | } 30 | echo $tbl->getTable(); 31 | } 32 | } 33 | 34 | -------------------------------------------------------------------------------- /src/devtools/cmd/commands/ConfigSetCmd.php: -------------------------------------------------------------------------------- 1 | $value){ 15 | if(is_string($option)){ 16 | $optionParts=explode(".", $option); 17 | $oldValue=self::getConfigOption($config, $optionParts); 18 | if(isset($oldValue)){ 19 | if(UString::isValid($oldValue)){ 20 | if($value!==$oldValue){ 21 | self::setConfigOption($config, $optionParts, $value); 22 | echo ConsoleFormatter::showMessage($option." : ".var_export($oldValue,true)." -> ".var_export($value,true)."","info"); 23 | $modified=true; 24 | } 25 | }else{ 26 | echo ConsoleFormatter::showMessage($option." : Unable to change a value of type object","error"); 27 | } 28 | }else{ 29 | self::setConfigOption($config, $optionParts, $value); 30 | echo ConsoleFormatter::showMessage($option." : inserted -> ".var_export($value,true)."","info"); 31 | $modified=true; 32 | } 33 | } 34 | } 35 | if($modified){ 36 | $content="1){ 68 | self::setConfigOption($config[$options[0]], array_slice($options, 1), $value); 69 | } 70 | } 71 | 72 | private static function setConfigOption_(&$config,$option,$value){ 73 | $optionParts=explode(".", $option); 74 | $c=$config; 75 | $nb=sizeof($optionParts); 76 | for ($i=0;$i<$nb-1;$i++){ 77 | $opt=$optionParts[$i]; 78 | if(!isset($c[$opt])){ 79 | $c[$opt]=[]; 80 | } 81 | $c=$c[$opt]; 82 | } 83 | $c[$optionParts[$nb-1]]=$value; 84 | } 85 | } 86 | 87 | -------------------------------------------------------------------------------- /src/devtools/cmd/commands/CreateCommandCmd.php: -------------------------------------------------------------------------------- 1 | create($pattern, $cmdPath)) { 19 | echo ConsoleFormatter::showMessage(sprintf('Command %s created in %s!', $what, $cmdPath), 'success', 'Command creation'); 20 | Command::reloadCustomCommands($devtoolsConfig); 21 | HelpCmd::run($caller, $what); 22 | } else { 23 | echo ConsoleFormatter::showMessage(sprintf('Error during the creation of %s!', $what), 'error', 'Command creation'); 24 | } 25 | } 26 | } 27 | 28 | -------------------------------------------------------------------------------- /src/devtools/cmd/commands/CrudCmd.php: -------------------------------------------------------------------------------- 1 | addCrudController($what, $resource, $crudDatas, $crudViewer, $crudEvents, $crudViews, $routePath); 23 | } else { 24 | echo ConsoleFormatter::showMessage("The models class {$resource} does not exists!", 'error', 'crud-controller'); 25 | } 26 | } 27 | } 28 | 29 | -------------------------------------------------------------------------------- /src/devtools/cmd/commands/DAOCmd.php: -------------------------------------------------------------------------------- 1 | getDatas($objects); 40 | break; 41 | case 'getOne': 42 | $object = DAO::getOne($resource, $condition, $included, $parameters); 43 | $rf = new ResponseFormatter(); 44 | $datas = $rf->cleanRestObject($object); 45 | break; 46 | case 'uGetAll': 47 | $objects = DAO::uGetAll($resource, $condition, $included, $parameters); 48 | $rf = new ResponseFormatter(); 49 | $datas = $rf->getDatas($objects); 50 | break; 51 | case 'uGetOne': 52 | $object = DAO::uGetOne($resource, $condition, $included, $parameters); 53 | $rf = new ResponseFormatter(); 54 | $datas = $rf->cleanRestObject($object); 55 | break; 56 | case 'count': 57 | $nb = DAO::count($resource, $condition, $parameters); 58 | echo ConsoleFormatter::showInfo($nb . " instances of " . $resource); 59 | break; 60 | case 'uCount': 61 | $nb = DAO::uCount($resource, $condition, $parameters); 62 | echo ConsoleFormatter::showInfo($nb . " instances of " . $resource); 63 | break; 64 | default: 65 | echo ConsoleFormatter::showMessage("Unknown command for dao : " . $what, 'error', 'dao'); 66 | break; 67 | } 68 | if (\is_array($datas)) { 69 | $tbl = new ConsoleTable(); 70 | $tbl->setIndent(5); 71 | $rArray = new ClassicArray($datas, $what); 72 | if (\is_array($fields) && \count($fields) > 0) { 73 | if (\is_array($objects)) { 74 | $rArray->setIFields($fields); 75 | } else { 76 | $rArray->setFields($fields); 77 | } 78 | } 79 | $tbl->setDatas($rArray->parse()); 80 | if ($what != null) { 81 | echo ConsoleFormatter::showInfo($what); 82 | } 83 | echo $tbl->getTable(); 84 | if (\is_array($objects)) { 85 | echo ConsoleFormatter::showInfo(\count($datas) . " instances of " . $resource); 86 | } 87 | echo ConsoleFormatter::showInfo(sprintf("Query executed in %.3f seconds", (float) microtime(true) - $start)); 88 | } else { 89 | echo ConsoleFormatter::showInfo('Nothing to display'); 90 | } 91 | } else { 92 | echo ConsoleFormatter::showMessage("The models class {$resource} does not exists!", 'error', 'dao'); 93 | } 94 | } 95 | } 96 | 97 | -------------------------------------------------------------------------------- /src/devtools/cmd/commands/DisplayAclsCmd.php: -------------------------------------------------------------------------------- 1 | getMap(), [ 66 | 'controller.action', 67 | 'resource', 68 | 'permission' 69 | ]); 70 | break; 71 | } 72 | } 73 | } 74 | 75 | private static function displayPart($title, $datas, $fields) { 76 | $count = \count($datas); 77 | $tbl = new ConsoleTable(); 78 | $rArray = new ReflectArray(); 79 | $rArray->setProperties($fields); 80 | $rArray->setObjects($datas); 81 | $tbl->setDatas($rArray->parse()); 82 | echo ConsoleFormatter::showInfo("$count $title(s)\n"); 83 | echo $tbl->getTable(); 84 | if ($rArray->hasMessages()) { 85 | echo ConsoleFormatter::showMessage(\implode("\n", $rArray->getMessages()), 'error'); 86 | } 87 | } 88 | } 89 | 90 | -------------------------------------------------------------------------------- /src/devtools/cmd/commands/EncryptNewKey.php: -------------------------------------------------------------------------------- 1 | longString()); 33 | } 34 | $command = $info['cmd']; 35 | echo "\n"; 36 | } 37 | } 38 | 39 | private static function info($caller) { 40 | echo $caller::getAppVersion() . "\n"; 41 | $commands = Command::getCommands(); 42 | foreach ($commands as $command) { 43 | echo ConsoleFormatter::formatHtml($command->longString()); 44 | echo "\n"; 45 | } 46 | } 47 | } 48 | 49 | -------------------------------------------------------------------------------- /src/devtools/cmd/commands/IndexCrudCmd.php: -------------------------------------------------------------------------------- 1 | 1) { 25 | $dbOffset = Console::question('Please select a valid database offset', $dbs); 26 | } else { 27 | $dbOffset = \current($dbs); 28 | } 29 | $scaffold->setActiveDb($dbOffset); 30 | } 31 | if (\strpos($routePath, '{resource') === false) { 32 | echo ConsoleFormatter::showMessage("The path variable {$routePath} does not contain the {resource} part!", 'error', 'index-crud-controller'); 33 | } else { 34 | $scaffold->addIndexCrudController($what, $crudDatas, $crudViewer, $crudEvents, $crudViews, $routePath); 35 | } 36 | } 37 | } 38 | 39 | -------------------------------------------------------------------------------- /src/devtools/cmd/commands/InfoMailerCmd.php: -------------------------------------------------------------------------------- 1 | setProperties(explode(",", $fields)); 41 | $rArray->setObjects($mails); 42 | $tbl->setDatas($rArray->parse()); 43 | echo $tbl->getTable(); 44 | if ($rArray->hasMessages()) { 45 | echo ConsoleFormatter::showMessage(implode("\n", $rArray->getMessages()), 'error'); 46 | } 47 | echo ConsoleFormatter::showInfo(sizeof($mails) . " mails in {$what}\n"); 48 | } 49 | } 50 | 51 | -------------------------------------------------------------------------------- /src/devtools/cmd/commands/InfoMigrationsCmd.php: -------------------------------------------------------------------------------- 1 | $domain"; 22 | } 23 | 24 | $checker = new DatabaseChecker($dbOffset); 25 | $checker->checkAll(); 26 | 27 | if ($checker->hasErrors()) { 28 | echo ConsoleFormatter::showMessage("Migrations to operate for db at offset $dbOffset$domainStr:", 'info', 'Migrations'); 29 | $messages = []; 30 | $checker->displayAll(function ($type, $icons, $content) use (&$messages) { 31 | $messages[$icons][] = $content; 32 | }); 33 | foreach ($messages as $title => $msgs) { 34 | $content = \implode(PHP_EOL, $msgs); 35 | echo ConsoleFormatter::showMessage($content, 'warning', $title); 36 | } 37 | } else { 38 | echo ConsoleFormatter::showMessage("No migrations to operate for db at offset $dbOffset$domainStr!", 'info', 'Migrations'); 39 | } 40 | } 41 | } 42 | 43 | -------------------------------------------------------------------------------- /src/devtools/cmd/commands/InfoModelCmd.php: -------------------------------------------------------------------------------- 1 | {$model} does not exists!", 'error', 'info:model'); 22 | } 23 | } 24 | } 25 | 26 | -------------------------------------------------------------------------------- /src/devtools/cmd/commands/InfoModelsCmd.php: -------------------------------------------------------------------------------- 1 | " . $model . "\n"); 24 | self::displayModelInfo($fields, $infos, null, false); 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/devtools/cmd/commands/InfoRoutesCmd.php: -------------------------------------------------------------------------------- 1 | setProperties(explode(",", $fields)); 35 | $rArray->setObjects($routes); 36 | $tbl->setDatas($rArray->parse()); 37 | echo $tbl->getTable(); 38 | if ($rArray->hasMessages()) { 39 | echo ConsoleFormatter::showMessage(implode("\n", $rArray->getMessages()), 'error'); 40 | } 41 | echo ConsoleFormatter::showInfo(sizeof($routes) . " routes ({$type})\n"); 42 | } 43 | } 44 | 45 | -------------------------------------------------------------------------------- /src/devtools/cmd/commands/InfoValidationCmd.php: -------------------------------------------------------------------------------- 1 | {$model} does not exists!", 'error', 'info:model'); 19 | } 20 | } 21 | } 22 | 23 | -------------------------------------------------------------------------------- /src/devtools/cmd/commands/InitAclsCmd.php: -------------------------------------------------------------------------------- 1 | createModels($dbOffset); 48 | $classes=$dao->getModelClasses(); 49 | echo ConsoleFormatter::showMessage("ACLs models created", 'success', 'init-cache: models'); 50 | $tbl=new ConsoleTable(); 51 | $tbl->setIndent(5); 52 | $rArray=new ClassicArray($classes); 53 | $tbl->setDatas($rArray->parse()); 54 | echo $tbl->getTable(); 55 | ob_start(); 56 | CacheManager::initCache($config, 'models'); 57 | $res = ob_get_clean(); 58 | echo ConsoleFormatter::showMessage($res, 'success', 'init-cache: models'); 59 | } 60 | } 61 | 62 | 63 | CacheManager::start($config); 64 | AclManager::start(); 65 | AclManager::initFromProviders([ 66 | new AclCacheProvider() 67 | ]); 68 | ob_start(); 69 | AclManager::initCache($config); 70 | $res = ob_get_clean(); 71 | echo ConsoleFormatter::showMessage($res, 'success', 'init-acls'); 72 | } 73 | } 74 | 75 | -------------------------------------------------------------------------------- /src/devtools/cmd/commands/InitCacheCmd.php: -------------------------------------------------------------------------------- 1 | ' . $what . ' does not exists!', 'warning', 'Themes installation'); 19 | $answer = Console::question('Would-you like to create a new one ?', [ 20 | 'y', 21 | 'n' 22 | ]); 23 | if (Console::isYes($answer)) { 24 | NewThemeCmd::run($config, $options, $what, $activeDir); 25 | } 26 | } 27 | } 28 | 29 | public static function addTheme($name, $baseTheme, $themeConfig, $activeDir, $standalone = false, &$composer = []) { 30 | $baseDir = getcwd(); 31 | $dest = $baseDir . '/public/assets/' . $name; 32 | if (! file_exists($dest)) { 33 | echo ConsoleFormatter::showMessage('Files copy...', 'Info', 'Adding theme ' . $name); 34 | FileUtils::safeMkdir($dest); 35 | $source = $activeDir . '/devtools/project-files/public/themes/' . $baseTheme; 36 | FileUtils::xcopy($source, $dest); 37 | 38 | if (\class_exists(\Ubiquity\domains\DDDManager::class)) { 39 | $dest = DDDManager::getActiveViewFolder() . 'themes/' . $name; 40 | } else { 41 | $dest = $baseDir . '/app/views/themes/' . $name; 42 | } 43 | FileUtils::safeMkdir($dest); 44 | $source = $activeDir . '/devtools/project-files/app/views/themes/' . $baseTheme; 45 | FileUtils::xcopy($source, $dest); 46 | 47 | $composerRequires = $themeConfig['composer']; 48 | foreach ($composerRequires as $composerRequire => $version) { 49 | if ($standalone) { 50 | system('composer require ' . $composerRequire); 51 | } else { 52 | $composer['require'][$composerRequire] = $version; 53 | } 54 | } 55 | $vendorCopies = $themeConfig['vendor-copy'] ?? []; 56 | if ($standalone) { 57 | self::copyVendorFiles($name, $vendorCopies, $baseDir); 58 | self::saveActiveTheme($name); 59 | } 60 | return $vendorCopies; 61 | } 62 | 63 | echo ConsoleFormatter::showMessage(\sprintf('This theme seems to be already installed in %s!', $dest), 'warning', 'Theme installation'); 64 | return []; 65 | } 66 | 67 | public static function copyVendorFiles($theme, $vendorCopies, $baseDir) { 68 | foreach ($vendorCopies as $src => $dest) { 69 | $dest = \str_replace('%theme%', $theme, $dest); 70 | FileUtils::xcopy($baseDir . $src, $baseDir . $dest); 71 | echo ConsoleFormatter::showInfo("Copy from " . $src . " to " . $dest . "..."); 72 | } 73 | } 74 | } 75 | 76 | -------------------------------------------------------------------------------- /src/devtools/cmd/commands/LiveReloadCmd.php: -------------------------------------------------------------------------------- 1 | npm install -g livereload.\n", 'warning', 'live-reload'); 24 | echo ConsoleFormatter::showInfo("Trying to install livereload\n"); 25 | system('npm install -g livereload'); 26 | } 27 | echo ConsoleFormatter::showInfo($msg . "Press Ctrl+C to stop it!\n"); 28 | system($cmd . ' &'); 29 | } 30 | } 31 | 32 | -------------------------------------------------------------------------------- /src/devtools/cmd/commands/MigrationsCmd.php: -------------------------------------------------------------------------------- 1 | $domain"; 30 | } 31 | 32 | $generator = new DatabaseReversor(new DbGenerator(), $dbOffset); 33 | $generator->migrate(); 34 | $script = $generator->getScript(); 35 | if (\count($script) === 0) { 36 | echo ConsoleFormatter::showMessage("No migrations to operate for db at offset $dbOffset$domainStr!", 'info', 'Migrations'); 37 | } else { 38 | echo ConsoleFormatter::showMessage("Migrations to operate for db at offset $dbOffset$domainStr:", 'info', 'Migrations'); 39 | do { 40 | self::displayScript(self::scriptToLineArray($script)); 41 | $rep = Console::question('Select your choices:', [ 42 | 'Execute all commands', 43 | 'Delete a row', 44 | 'Quit' 45 | ]); 46 | switch ($rep) { 47 | case 'Delete a row': 48 | $count = \count($script); 49 | $row = Console::question("Enter a valid row between 1 and $count:"); 50 | $delete = self::deleteScriptRow($row, $script); 51 | if ($delete !== false) { 52 | $script = $delete; 53 | } 54 | break; 55 | case 'Execute all commands': 56 | self::executeSQLTransaction($dbOffset, implode(';', $script), 'Database migrations'); 57 | $rep = 'Quit'; 58 | break; 59 | default: 60 | echo ConsoleFormatter::showInfo('Operation terminated, Bye!'); 61 | } 62 | } while ($rep !== 'Quit'); 63 | } 64 | } 65 | 66 | private static function deleteScriptRow(int $rowNum, array $script) { 67 | $rowNum --; 68 | if ($rowNum >= 0 && $rowNum < \count($script)) { 69 | unset($script[$rowNum]); 70 | return array_values($script); 71 | } 72 | return false; 73 | } 74 | 75 | private static function displayScript(array $script) { 76 | $tbl = new ConsoleTable(); 77 | $tbl->setIndent(5); 78 | $tbl->setPadding(1); 79 | $tbl->setDatas($script); 80 | echo $tbl->getTable(); 81 | } 82 | 83 | private static function scriptToLineArray(array $script): array { 84 | $result = []; 85 | $line = 1; 86 | $width = Screen::getWidth() - 20; 87 | foreach ($script as $sql) { 88 | $result[] = [ 89 | 'line' => $line ++, 90 | 'sql' => \wordwrap($sql, $width, PHP_EOL) 91 | ]; 92 | } 93 | return $result; 94 | } 95 | 96 | private static function executeSQLTransaction(string $activeDbOffset, string $sql, string $title) { 97 | $isValid = true; 98 | if (isset($sql)) { 99 | $db = DAO::getDatabase($activeDbOffset ?? 'default'); 100 | if (! $db->isConnected()) { 101 | $db->setDbName(''); 102 | try { 103 | $db->connect(); 104 | } catch (\Exception $e) { 105 | $isValid = false; 106 | echo ConsoleFormatter::showMessage($e->getMessage(), 'error', $title); 107 | } 108 | } 109 | if ($isValid) { 110 | if ($db->beginTransaction()) { 111 | try { 112 | $db->execute($sql); 113 | if ($db->inTransaction()) { 114 | $db->commit(); 115 | } 116 | echo ConsoleFormatter::showMessage("Database created/updated with success at offset $activeDbOffset!", 'success', $title); 117 | } catch (\Error $e) { 118 | if ($db->inTransaction()) { 119 | $db->rollBack(); 120 | } 121 | echo ConsoleFormatter::showMessage($e->getMessage(), 'error', $title); 122 | } 123 | } else { 124 | $db->execute($sql); 125 | echo ConsoleFormatter::showMessage("Database created/updated with success at offset $activeDbOffset!", 'success', $title); 126 | } 127 | } 128 | } 129 | } 130 | } 131 | 132 | -------------------------------------------------------------------------------- /src/devtools/cmd/commands/NewActionCmd.php: -------------------------------------------------------------------------------- 1 | setConfig($config); 14 | @list ($controller, $action) = explode('.', $what); 15 | $domain = self::getOption($options, 'o', 'domain', ''); 16 | if ($domain != '') { 17 | DDDManager::setDomain($domain); 18 | } 19 | if ($controller != null && $action != null) { 20 | $controller = self::getCompleteClassname($config, $controller, 'controllers'); 21 | if (\class_exists($controller)) { 22 | $parameters = self::getOption($options, 'p', 'params'); 23 | $routePath = self::getOption($options, 'r', 'route'); 24 | $createView = self::getOption($options, 'v', 'create-view', false); 25 | $theme = self::getOption($options, 't', 'theme'); 26 | $routeInfo = null; 27 | if ($routePath != null) { 28 | $routeInfo = [ 29 | "path" => $routePath, 30 | "methods" => null 31 | ]; 32 | } 33 | CacheManager::start($config); 34 | $scaffold->_newAction($controller, $action, $parameters, '', $routeInfo, $createView, $theme); 35 | } else { 36 | echo ConsoleFormatter::showMessage("The controller class {$controller} does not exists!", 'error', 'new-action'); 37 | } 38 | } else { 39 | echo ConsoleFormatter::showMessage("You must use controller.action notation!", 'error', 'new-action'); 40 | } 41 | } 42 | } 43 | 44 | -------------------------------------------------------------------------------- /src/devtools/cmd/commands/NewClassCmd.php: -------------------------------------------------------------------------------- 1 | setConfig($config); 22 | $msg = $scaffold->_createClass('class.tpl', $classname, $ns, '', $parent, ''); 23 | echo ConsoleFormatter::showMessage("Class {$classname} created!", 'success', 'new-class'); 24 | } else { 25 | echo ConsoleFormatter::showMessage("Class namespace must not be empty!", 'error', 'new-class'); 26 | } 27 | } 28 | } 29 | 30 | -------------------------------------------------------------------------------- /src/devtools/cmd/commands/NewDomainCmd.php: -------------------------------------------------------------------------------- 1 | $originalBase, which is different from $base.\nWould you like to rename the base to $base?"), [ 18 | 'y', 19 | 'n' 20 | ]); 21 | if (Console::isYes($rep)) { 22 | if (! DDDManager::setBase($base)) { 23 | echo ConsoleFormatter::showMessage("There was a problem during the base renaming to {$base}!", 'error', 'new-domain'); 24 | } else { 25 | echo ConsoleFormatter::showMessage("Domains base was renamed to {$base}!", 'success', 'new-domain'); 26 | } 27 | } 28 | } 29 | 30 | $domain = UString::cleanAttribute($what, '_'); 31 | if (! DDDManager::domainExists($domain)) { 32 | if (DDDManager::createDomain($domain)) { 33 | $domainBase = DDDManager::getDomainBase($domain); 34 | echo ConsoleFormatter::showMessage("The domain {$domain} was successfully created in $domainBase!", 'success', 'new-domain'); 35 | } else { 36 | echo ConsoleFormatter::showMessage("There was a problem during the creation of the domain {$domain}!", 'error', 'new-domain'); 37 | } 38 | } else { 39 | echo ConsoleFormatter::showMessage("The domain {$domain} already exists!", 'error', 'new-domain'); 40 | } 41 | } 42 | } 43 | 44 | -------------------------------------------------------------------------------- /src/devtools/cmd/commands/NewMailCmd.php: -------------------------------------------------------------------------------- 1 | setConfig($config); 19 | $msg = $scaffold->_createClass('mailer.tpl', $classname, $ns, 'use Ubiquity\\mailer\\MailerManager;', $parent, ''); 20 | if ($hasView) { 21 | $vName = $scaffold->_createViewOp('mailer', $classname); 22 | } 23 | echo ConsoleFormatter::showMessage("Mailer class {$classname} created!", 'success', 'new-mailer-class'); 24 | } 25 | } 26 | 27 | -------------------------------------------------------------------------------- /src/devtools/cmd/commands/NewModelCmd.php: -------------------------------------------------------------------------------- 1 | $model) { 71 | $oName = $name; 72 | if ($model->isUpdated()) { 73 | $name .= '*'; 74 | } 75 | if (\strtolower($oName) === \strtolower(self::$currentModelName)) { 76 | $result[] = "$name"; 77 | } else { 78 | $result[] = $name; 79 | } 80 | } 81 | return \implode(',', $result); 82 | } 83 | 84 | private static function addPk($pk) { 85 | $class = self::$currentModel; 86 | $class->addPk($pk); 87 | 88 | if (! $class->hasField($pk)) { 89 | echo ConsoleFormatter::showMessage("$pk is not in field list", 'warning', 'Add primary keys'); 90 | $q = Console::yesNoQuestion("Would you like to add $pk in field list?", [ 91 | 'yes', 92 | 'no' 93 | ]); 94 | if (Console::isYes($q)) { 95 | $fieldType = Console::question("Enter field type : "); 96 | self::addFields($pk, $fieldType, ''); 97 | } 98 | } 99 | } 100 | 101 | private static function getFieldNames() { 102 | return self::$currentModel->getFieldNames(); 103 | } 104 | 105 | private static function addFields($fields, $fieldTypes, $nullables) { 106 | $fields = Console::explodeResponse($fields); 107 | $fieldTypes = Console::explodeResponse($fieldTypes); 108 | $nullables = Console::explodeResponse($nullables); 109 | $newModel = self::$currentModel; 110 | foreach ($fields as $index => $field) { 111 | $field = \trim($field); 112 | if ($field != '') { 113 | $nullable = \array_search($field, $nullables) !== false; 114 | $newModel->addField($field, [ 115 | 'Type' => $fieldTypes[$index] ?? DbTypes::DEFAULT_TYPE, 116 | 'Nullable' => $nullable ? 'true' : 'false' 117 | ]); 118 | } 119 | } 120 | } 121 | 122 | private static function generateClasses(string $namespace, string $dbOffset) { 123 | $messages = []; 124 | $classes = []; 125 | foreach (self::$allModels as $name => $newModel) { 126 | $class = $newModel->generateClass($name, $namespace, $dbOffset); 127 | $classes[$name] = $class; 128 | } 129 | 130 | self::createRelations($classes, $namespace); 131 | 132 | foreach (self::$allModels as $name => $newModel) { 133 | if ($newModel->isUpdated()) { 134 | $class = $classes[$name]; 135 | $msg = self::createClass($class, $newModel, $name, $namespace); 136 | if ($msg['type'] === 'success') { 137 | $messages['success'][] = $msg['message']; 138 | } else { 139 | $messages['error'][] = $msg['message']; 140 | } 141 | } 142 | } 143 | self::showMessages('success', $messages); 144 | self::showMessages('error', $messages); 145 | $rep = Console::yesNoQuestion('Do you want to re-init models cache?', [ 146 | 'yes', 147 | 'no' 148 | ]); 149 | if (Console::isYes($rep)) { 150 | global $argv; 151 | echo shell_exec($argv[0] . ' init-cache -t=models'); 152 | } 153 | self::saveModelsInCache(); 154 | die(); 155 | } 156 | 157 | private static function createRelations($classes, $namespace) { 158 | foreach (self::$allModels as $name => $newModel) { 159 | $manyToOnes = $newModel->getManyToOne(); 160 | $oneToManys = $newModel->getOneToMany(); 161 | $manyToManys = $newModel->getManyToMany(); 162 | $class = $classes[$name]; 163 | foreach ($manyToOnes as $member => $manyToOne) { 164 | $class->addManyToOne($member, $manyToOne['fkField'], $namespace . $manyToOne['className'], $member); 165 | } 166 | foreach ($oneToManys as $member => $oneToMany) { 167 | $class->addOneToMany($member, $oneToMany['mappedBy'], $namespace . $oneToMany['className'], $member); 168 | } 169 | 170 | foreach ($manyToManys as $member => $manyToMany) { 171 | $class->addManyToMany($member, $namespace . $manyToMany['otherClassName'], $manyToMany['otherMember'], $manyToMany['joinTable'], $manyToMany['joinColumn'], $manyToMany['otherJoinColumn']); 172 | } 173 | } 174 | } 175 | 176 | private static function showMessages(string $type, array $messages): void { 177 | if (isset($messages[$type])) { 178 | echo ConsoleFormatter::showMessage(\implode(PHP_EOL, $messages[$type]), $type, 'Classes creation'); 179 | } 180 | } 181 | 182 | private static function store(string $className, NewModel $newModel): void { 183 | $content = [ 184 | 'defaultPk' => ($newModel->getDefaultPk() ?? ''), 185 | 'pks' => $newModel->getPks(), 186 | 'fields' => $newModel->getFields(), 187 | 'manyToOne' => $newModel->getManyToOne(), 188 | 'oneToMany' => $newModel->getOneToMany(), 189 | 'manyToMany' => $newModel->getManyToMany() 190 | ]; 191 | CacheManager::$cache->store(self::CACHE_KEY . $className, $content); 192 | } 193 | 194 | private static function loadFromCache(string $className, ?NewModel $newModel = null): void { 195 | $result = CacheManager::$cache->fetch(self::CACHE_KEY . $className); 196 | $newModel ??= self::$currentModel; 197 | $newModel->setFields($result['fields']); 198 | $newModel->setDefaultPk($result['defaultPk']); 199 | $newModel->setPks($result['pks']); 200 | $newModel->setManyToOne($result['manyToOne'] ?? []); 201 | $newModel->setOneToMany($result['oneToMany'] ?? []); 202 | $newModel->setManyToMany($result['manyToMany'] ?? []); 203 | $newModel->setLoadedFromCache(true); 204 | } 205 | 206 | private static function reloadFromExistingClass(string $completeClassName): bool { 207 | if (CacheManager::modelCacheExists($completeClassName)) { 208 | $newModel = self::$currentModel; 209 | $metaDatas = CacheManager::getOrmModelCache($completeClassName); 210 | self::checkAutoInc($newModel, $completeClassName); 211 | $newModel->setPks(\array_keys($metaDatas['#primaryKeys'])); 212 | $memberNames = \array_keys($metaDatas['#fieldNames']); 213 | $types = $metaDatas['#fieldTypes']; 214 | $nullables = $metaDatas['#nullable']; 215 | $fields = []; 216 | foreach ($memberNames as $memberName) { 217 | $fields[$memberName] = [ 218 | 'Type' => $types[$memberName] ?? 'mixed', 219 | 'Nullable' => in_array($memberName, $nullables) ? 'true' : 'false' 220 | ]; 221 | } 222 | $newModel->setFields($fields); 223 | $newModel->setTableName($metaDatas['#tableName']); 224 | self::reloadFromExistingClassRelations($newModel, $metaDatas); 225 | $newModel->setLoadedFromCache(true); 226 | $newModel->setLoaded(true); 227 | return true; 228 | } 229 | return false; 230 | } 231 | 232 | private static function reloadFromExistingClassRelations(NewModel $newModel, array $metaDatas) { 233 | $manyToOnes = $metaDatas['#manyToOne'] ?? []; 234 | $joinColumns = $metaDatas['#joinColumn'] ?? []; 235 | foreach ($manyToOnes as $manyToOne) { 236 | $joinColumn = $joinColumns[$manyToOne]; 237 | $newModel->addManyToOne($manyToOne, $joinColumn['name'], ClassUtils::getClassSimpleName($joinColumn['className'])); 238 | } 239 | 240 | $oneToManys = $metaDatas['#oneToMany'] ?? []; 241 | foreach ($oneToManys as $member => $oneToMany) { 242 | $newModel->addOneToMany($member, $oneToMany['mappedBy'], ClassUtils::getClassSimpleName($oneToMany['className'])); 243 | } 244 | 245 | $manyToManys = $metaDatas['#manyToMany'] ?? []; 246 | $joinTables = $metaDatas['#joinTable'] ?? []; 247 | foreach ($manyToManys as $member => $manyToMany) { 248 | $jointable = $joinTables[$member]; 249 | $joinColumn = $jointable['joinColumns'] ?? []; 250 | $inverseJoinColumn = $jointable['inverseJoinColumns'] ?? []; 251 | $newModel->addManyToMany($member, ClassUtils::getClassSimpleName($manyToMany['targetEntity']), $manyToMany['inversedBy'], $jointable['name'], $joinColumn, $inverseJoinColumn); 252 | } 253 | } 254 | 255 | private static function checkAutoInc(NewModel $newModel, string $completeClassName) { 256 | $validationMetas = ValidatorsManager::getCacheInfo($completeClassName); 257 | foreach ($validationMetas as $member => $validators) { 258 | foreach ($validators as $infos) { 259 | if ($infos['type'] === 'id') { 260 | if (($infos['constraints']['autoinc'] ?? false) === true) { 261 | $newModel->setDefaultPk($member); 262 | return; 263 | } 264 | } 265 | } 266 | } 267 | } 268 | 269 | private static function createClass(Model $model, NewModel $newModel, string $modelName, string $namespace): array { 270 | $className = $model->getName(); 271 | $modelsDir = UFileSystem::getDirFromNamespace($namespace); 272 | echo ConsoleFormatter::showInfo("Creating the {$className} class"); 273 | $classContent = $model->__toString(); 274 | if (UFileSystem::save($modelsDir . \DS . $model->getSimpleName() . '.php', $classContent)) { 275 | return [ 276 | 'type' => 'success', 277 | 'message' => "Class $className created with success!" 278 | ]; 279 | } 280 | return [ 281 | 'type' => 'error', 282 | 'message' => "Class $className not generated!" 283 | ]; 284 | } 285 | 286 | private static function loadModel(NewModel $newModel, string $modelName, string $namespace): bool { 287 | $modelCompleteName = $namespace . $modelName; 288 | 289 | if (self::$loadCurrentModels && ! $newModel->isLoadedFromCache()) { 290 | self::reloadFromExistingClass($modelCompleteName); 291 | return false; 292 | } 293 | $restrict = false; 294 | if (! $newModel->isLoaded()) { 295 | if (CacheManager::$cache->exists(self::CACHE_KEY . $modelName) && ! \class_exists($modelCompleteName)) { 296 | $rep = Console::yesNoQuestion("A model with the name $modelName was already created.\nWould you like to reload it from cache?", [ 297 | 'yes', 298 | 'no' 299 | ]); 300 | if (Console::isYes($rep)) { 301 | self::loadFromCache($modelName); 302 | } 303 | } 304 | if (\class_exists($modelCompleteName)) { 305 | echo ConsoleFormatter::showMessage("The class $modelCompleteName already exists!", 'warning', 'Update model'); 306 | $rep = Console::yesNoQuestion('Would you like to modify the existing class?', [ 307 | 'yes', 308 | 'no' 309 | ]); 310 | if (Console::isYes($rep)) { 311 | if (self::reloadFromExistingClass($modelCompleteName)) { 312 | echo ConsoleFormatter::showMessage("Loading infos for class $modelCompleteName from DAO cache.", 'info', 'Update model'); 313 | } else { 314 | echo ConsoleFormatter::showMessage("No cache infos for $modelCompleteName.", 'error', 'Update model'); 315 | die(); 316 | } 317 | } else { 318 | $restrict = true; 319 | } 320 | } 321 | $newModel->setLoaded(true); 322 | 323 | if (! $newModel->isLoadedFromCache() && isset(self::$defaultPkValue)) { 324 | $newModel->setDefaultPk(self::$defaultPkValue); 325 | } 326 | } 327 | 328 | return $restrict; 329 | } 330 | 331 | private static function firstLoadAllModels(array $models) { 332 | foreach ($models as $index => $modelName) { 333 | self::getNewModel($modelName, $index === 0); 334 | } 335 | } 336 | 337 | private static function loadModelsFrom(array $config, string $dbOffset = 'default'): array { 338 | $models = CacheManager::getModels($config, true, $dbOffset); 339 | if (\count($models) > 0) { 340 | return \array_map(function ($model) { 341 | return ClassUtils::getClassSimpleName($model); 342 | }, $models); 343 | } 344 | return []; 345 | } 346 | 347 | public static function run(&$config, $options, $what) { 348 | $domain = self::updateDomain($options); 349 | $dbOffset = self::getOption($options, 'd', 'database', 'default'); 350 | self::$defaultPkValue = self::getOption($options, 'k', 'autoincPk', 'id'); 351 | self::checkDbOffset($config, $dbOffset); 352 | 353 | CacheManager::start($config); 354 | 355 | $models = Console::explodeResponse($what ?? '', function ($item) { 356 | return \ucfirst(\trim($item)); 357 | }); 358 | 359 | if (\count($models) === 0) { 360 | $models = self::loadModelsFrom($config, $dbOffset); 361 | if (count($models) > 0) { 362 | $rep = Console::yesNoQuestion("Would you like to load the current classes [" . \implode(',', $models) . "]?"); 363 | if (Console::isNo($rep)) { 364 | $models = []; 365 | } else { 366 | self::$loadCurrentModels = true; 367 | } 368 | } 369 | } 370 | if (\count($models) > 0) { 371 | self::firstLoadAllModels($models); 372 | 373 | $modelName = self::$currentModelName; 374 | $newModel = self::$currentModel; 375 | } else { 376 | $modelName = Console::question("Enter a model name: "); 377 | $newModel = self::getNewModel($modelName); 378 | } 379 | 380 | $fields = ''; 381 | $checkExisting = []; 382 | do { 383 | $namespace = self::getModelNamespace($domain, $dbOffset); 384 | $modelCompleteName = $namespace . $modelName; 385 | 386 | $restrict = self::loadModel($newModel, $modelName, $namespace); 387 | $tableName = $newModel->getTableName(); 388 | 389 | echo ConsoleFormatter::showMessage("Model: $modelCompleteName", 'info', 'Model add/update'); 390 | 391 | $caseChangeDbOffset = "Change dbOffset [$dbOffset]"; 392 | $caseChangeActiveDomain = "Change active Domain [$domain]"; 393 | $caseSwitchModel = "Add/switch to model [" . self::getAllModelsAsString() . "]"; 394 | 395 | $fields = \implode(',', $newModel->getFieldNames()); 396 | $caseAddFields = "Add fields [$fields]"; 397 | $caseAddDefaultPk = "Add default auto-inc primary key [" . ($newModel->getDefaultPk() ?? '') . "]"; 398 | $caseChangeTableName = "Change table name [$tableName]"; 399 | $caseAddRelations = "Add relations [" . $newModel->getRelationsAsString() . "]"; 400 | 401 | if (! $restrict) { 402 | $choices = [ 403 | $caseAddFields, 404 | $caseAddDefaultPk, 405 | 'Add primary keys', 406 | $caseAddRelations, 407 | $caseChangeTableName, 408 | $caseChangeDbOffset, 409 | $caseChangeActiveDomain, 410 | $caseSwitchModel, 411 | 'Generate classes', 412 | 'Quit' 413 | ]; 414 | } else { 415 | $choices = [ 416 | 'Change class name', 417 | $caseChangeDbOffset, 418 | $caseChangeActiveDomain, 419 | 'Quit' 420 | ]; 421 | } 422 | $rep = Console::question('Select your choices:', $choices); 423 | 424 | switch ($rep) { 425 | 426 | case 'Change class name': 427 | $modelName = Console::question("Enter model name: "); 428 | $modelName = \ucfirst($modelName); 429 | unset(self::$allModels[self::$currentModelName]); 430 | self::$allModels[$modelName] = self::$currentModel; 431 | self::$currentModelName = $modelName; 432 | $newModel->setUpdated(true); 433 | break; 434 | 435 | case $caseChangeTableName: 436 | $tbl = Console::question('Enter table name:'); 437 | $newModel->setTableName(($tbl == '') ? null : $tbl); 438 | $newModel->setUpdated(true); 439 | break; 440 | 441 | case $caseAddFields: 442 | $field = Console::question("Enter field names: "); 443 | if ($field != '') { 444 | $fieldTypes = Console::question("Enter field types: "); 445 | $nullables = Console::question("Nullable fields: "); 446 | self::addFields($field, $fieldTypes, $nullables); 447 | $newModel->setUpdated(true); 448 | } 449 | break; 450 | 451 | case $caseSwitchModel: 452 | $modelName = Console::question('Enter an existing or a new model name:'); 453 | $modelName = \ucfirst($modelName); 454 | $newModel = self::getNewModel($modelName); 455 | break; 456 | 457 | case 'Add primary keys': 458 | $pks = Console::question('Enter primary keys: '); 459 | $newModel->updatePks($pks); 460 | $newModel->setUpdated(true); 461 | break; 462 | 463 | case $caseAddRelations: 464 | $rType = Console::question('Type: ', [ 465 | 'manyToOne', 466 | 'oneToMany', 467 | 'manyToMany' 468 | ]); 469 | self::addRelation($rType, $newModel, $namespace); 470 | break; 471 | 472 | case $caseAddDefaultPk: 473 | $newModel->setDefaultPk(Console::question('Primary key name: ')); 474 | $newModel->setUpdated(true); 475 | break; 476 | 477 | case $caseChangeDbOffset: 478 | $dbOffset = Console::question('Database offset: '); 479 | self::checkDbOffset($config, $dbOffset); 480 | break; 481 | 482 | case $caseChangeActiveDomain: 483 | $newDomain = Console::question('Domain: '); 484 | $domain = self::updateDomain([ 485 | 'o' => $newDomain 486 | ]); 487 | if ($domain == '') { 488 | DDDManager::resetActiveDomain(); 489 | } 490 | break; 491 | 492 | case 'Generate classes': 493 | self::generateClasses(self::getModelNamespace($domain, $dbOffset), $dbOffset); 494 | break; 495 | 496 | default: 497 | self::saveModelsInCache(); 498 | echo ConsoleFormatter::showInfo('Operation terminated, Bye!'); 499 | } 500 | } while ($rep !== 'Quit'); 501 | } 502 | 503 | private static function saveModelsInCache() { 504 | $cached = []; 505 | foreach (self::$allModels as $modelName => $newModel) { 506 | if ($newModel->isUpdated()) { 507 | self::store($modelName, $newModel); 508 | $cached[] = $modelName; 509 | } 510 | } 511 | if (\count($cached) > 0) { 512 | echo ConsoleFormatter::showInfo("Data caching for the models: " . \implode(',', $cached)); 513 | } 514 | } 515 | 516 | private static function addRelation(string $rType, NewModel $newModel, string $namespace) { 517 | $modelName = $newModel->getOriginalModelName(); 518 | 519 | switch ($rType) { 520 | case 'manyToOne': 521 | $fkClass = Console::question('Foreign member className:', \array_keys(self::$allModels), [ 522 | 'ignoreCase' => true 523 | ]); 524 | $otherModel = self::getNewModel($fkClass, false); 525 | $otherModelName = $otherModel->getOriginalModelName(); 526 | 527 | $padmax = \strlen("OneToMany member name in $otherModelName:"); 528 | 529 | $fkField = Console::question(\str_pad('Foreign key name:', $padmax), null, [ 530 | 'default' => 'id' . \ucfirst($otherModelName) 531 | ]); 532 | $member = Console::question(\str_pad('Member name:', $padmax), null, [ 533 | 'default' => \lcfirst($otherModelName) 534 | ]); 535 | 536 | $manyMember = Console::question(\str_pad("OneToMany member name in $otherModelName:", $padmax), null, [ 537 | 'default' => \lcfirst($modelName) . 's' 538 | ]); 539 | 540 | $newModel->addManyToOne($member, $fkField, $otherModelName); 541 | if (! $otherModel->isLoaded()) { 542 | self::loadModel($otherModel, $otherModelName, $namespace); 543 | } 544 | $otherModel->addOneToMany($manyMember, $member, $modelName); 545 | 546 | $newModel->setUpdated(true); 547 | $otherModel->setUpdated(true); 548 | break; 549 | case 'manyToMany': 550 | $padmax = 45; 551 | $fkClass = Console::question(\str_pad('Associated className:', $padmax), \array_keys(self::$allModels), [ 552 | 'ignoreCase' => true 553 | ]); 554 | $otherModel = self::getNewModel($fkClass, false); 555 | $otherModelName = $otherModel->getOriginalModelName(); 556 | 557 | $member = Console::question(\str_pad("Associated member name in $modelName:", $padmax), null, [ 558 | 'default' => \lcfirst($otherModelName) . 's' 559 | ]); 560 | $otherAssociatedFk = Console::question(\str_pad("Associated fk name for $otherModelName:", $padmax), null, [ 561 | 'default' => 'id' . \ucfirst($otherModelName) 562 | ]); 563 | 564 | $otherMember = Console::question(\str_pad("Associated member name in $otherModelName:", $padmax), null, [ 565 | 'default' => \lcfirst($modelName) . 's' 566 | ]); 567 | $associatedFk = Console::question(\str_pad("Associated fk name for $modelName:", $padmax), null, [ 568 | 'default' => 'id' . \ucfirst($modelName) 569 | ]); 570 | $jointable = Console::question(\str_pad('Jointable:', $padmax), null, [ 571 | 'default' => \lcfirst($modelName) . '_' . \lcfirst($otherModelName) . 's' 572 | ]); 573 | 574 | $joinColumn = ($associatedFk !== $newModel->getDefaultFk()) ? [ 575 | 'name' => $associatedFk, 576 | 'referencedColumnName' => $newModel->getFirstPk() 577 | ] : []; 578 | $otherJoinColumn = ($otherAssociatedFk !== $otherModel->getDefaultFk()) ? [ 579 | 'name' => $otherAssociatedFk, 580 | 'referencedColumnName' => $otherModel->getFirstPk() 581 | ] : []; 582 | 583 | $newModel->addManyToMany($member, $otherModelName, $otherMember, $jointable, $joinColumn, $otherJoinColumn); 584 | if (! $otherModel->isLoaded()) { 585 | self::loadModel($otherModel, $otherModelName, $namespace); 586 | } 587 | $otherModel->addManyToMany($otherMember, $modelName, $member, $jointable, $otherJoinColumn, $joinColumn); 588 | $newModel->setUpdated(true); 589 | $otherModel->setUpdated(true); 590 | 591 | break; 592 | case 'oneToMany': 593 | $padmax = 45; 594 | $fkClass = Console::question(\str_pad('Associated member className:', $padmax), \array_keys(self::$allModels), [ 595 | 'ignoreCase' => true 596 | ]); 597 | $otherModel = self::getNewModel($fkClass, false); 598 | $otherModelName = $otherModel->getOriginalModelName(); 599 | 600 | $fkField = Console::question(\str_pad('Foreign key name:', $padmax), null, [ 601 | 'default' => 'id' . \ucfirst($modelName) 602 | ]); 603 | $member = Console::question(\str_pad('Member name:', $padmax), null, [ 604 | 'default' => \lcfirst($otherModelName) . 's' 605 | ]); 606 | $mappedBy = Console::question(\str_pad("MappedBy member name in $otherModelName:", $padmax), null, [ 607 | 'default' => \lcfirst($modelName) 608 | ]); 609 | 610 | $newModel->addOneToMany($member, $mappedBy, $otherModelName); 611 | if (! $otherModel->isLoaded()) { 612 | self::loadModel($otherModel, $otherModelName, $namespace); 613 | } 614 | $otherModel->addManyToOne($mappedBy, $fkField, $modelName); 615 | $newModel->setUpdated(true); 616 | $otherModel->setUpdated(true); 617 | break; 618 | } 619 | } 620 | } 621 | -------------------------------------------------------------------------------- /src/devtools/cmd/commands/NewThemeCmd.php: -------------------------------------------------------------------------------- 1 | %s from %s', $what, $extend)); 21 | InstallThemeCmd::addTheme($what, $extend, $themesConfig[$extend], $activeDir, true); 22 | } else { 23 | echo ConsoleFormatter::showMessage(sprintf('The theme %s does not exists!', $extend), 'error', 'Theme creation'); 24 | } 25 | } 26 | } else { 27 | echo ConsoleFormatter::showMessage(sprintf('The theme %s is a reserved theme name!', $what), 'error', 'Theme creation'); 28 | } 29 | } 30 | 31 | public static function addNew($what, $activeDir) { 32 | $msg = ""; 33 | $baseDir = getcwd(); 34 | $dest = $baseDir . '/public/assets/' . $what; 35 | if (! file_exists($dest)) { 36 | $sourceAssets = $activeDir . '/devtools/project-files/public/themes/model/'; 37 | echo ConsoleFormatter::showInfo("Assets creation..."); 38 | FileUtils::xcopy($sourceAssets, $dest); 39 | } else { 40 | $msg = sprintf("Assets creation failed : %s directory exists!\n", $dest); 41 | } 42 | $sourceView = $activeDir . '/devtools/project-files/app/views/themes/model/'; 43 | $dest = DDDManager::getActiveViewFolder() . "themes/" . $what; 44 | if (! file_exists($dest)) { 45 | echo ConsoleFormatter::showInfo("Views creation..."); 46 | FileUtils::xcopy($sourceView, $dest); 47 | } else { 48 | $msg = sprintf("Views creation failed : %s directory exists!\n", $dest); 49 | } 50 | if ($msg !== "") { 51 | echo ConsoleFormatter::showMessage($msg, "error", "Theme creation"); 52 | } else { 53 | self::saveActiveTheme($what); 54 | echo ConsoleFormatter::showMessage(sprintf('Theme %s created with success!', $what), "success", "Theme creation"); 55 | } 56 | } 57 | } 58 | 59 | -------------------------------------------------------------------------------- /src/devtools/cmd/commands/RestApiCmd.php: -------------------------------------------------------------------------------- 1 | addJsonRestController($what, $routePath); 17 | } else { 18 | $scaffold->addRestApiController($what, $routePath); 19 | } 20 | } 21 | } 22 | 23 | -------------------------------------------------------------------------------- /src/devtools/cmd/commands/RestCmd.php: -------------------------------------------------------------------------------- 1 | addRestController($what, RestResourceController::class, $resource, $routePath); 19 | } else { 20 | echo ConsoleFormatter::showMessage("The models class {$resource} does not exists!", 'error', 'rest-controller'); 21 | } 22 | } 23 | } 24 | 25 | -------------------------------------------------------------------------------- /src/devtools/cmd/commands/SendMailQueueCmd.php: -------------------------------------------------------------------------------- 1 | 0) { 22 | MailerManager::saveQueue(); 23 | echo ConsoleFormatter::showMessage($count . ' email(s) sent with success!', 'success', 'Send mails from Queue'); 24 | } else { 25 | echo ConsoleFormatter::showMessage('No mail sent!', 'info', 'Send mails from Queue'); 26 | } 27 | } 28 | } 29 | 30 | private static function _sendMailQueue($index) { 31 | if (MailerManager::sendQueuedMail(-- $index)) { 32 | MailerManager::saveQueue(); 33 | echo ConsoleFormatter::showMessage('Email sent with success!', 'success', 'Send mail from Queue'); 34 | } else { 35 | echo ConsoleFormatter::showMessage(MailerManager::getErrorInfo(), 'error', 'Send mail from Queue'); 36 | } 37 | } 38 | } 39 | 40 | -------------------------------------------------------------------------------- /src/devtools/cmd/commands/TemplateParserCmd.php: -------------------------------------------------------------------------------- 1 | generateTemplateSource($fileContent); 33 | $dDest = $destination . $ds . $realPath . $ds; 34 | UFileSystem::safeMkdir($dDest); 35 | \file_put_contents($dDest . $filename, $code); 36 | echo ConsoleFormatter::showInfo("$filename parsed to $destEngine in $destination"); 37 | } 38 | } else { 39 | echo ConsoleFormatter::showMessage("Invalid template $destEngine", 'error', 'Template parser'); 40 | } 41 | } 42 | 43 | private static function runComposer(array $commands, string $name) { 44 | if (isset($commands['repositories'])) { 45 | $repositories = $commands['repositories']; 46 | foreach ($repositories as $index => $repository) { 47 | $type = $repository['type']; 48 | $url = $repository['url']; 49 | \system("composer config repositories.{$name}{$index} $type $url"); 50 | } 51 | } 52 | if (isset($commands['require'])) { 53 | $requires = $commands['require']; 54 | foreach ($requires as $require => $version) { 55 | \system('composer require ' . $require . ':' . $version); 56 | } 57 | } 58 | if (isset($commands['require-dev'])) { 59 | $requires = $commands['require-dev']; 60 | foreach ($requires as $require => $version) { 61 | \system('composer require ' . $require . ':' . $version . ' --dev'); 62 | } 63 | } 64 | } 65 | } 66 | 67 | -------------------------------------------------------------------------------- /src/devtools/cmd/commands/popo/NewModel.php: -------------------------------------------------------------------------------- 1 | originalModelName = $modelName; 34 | } 35 | 36 | /** 37 | * 38 | * @return string 39 | */ 40 | public function getOriginalModelName(): string { 41 | return $this->originalModelName; 42 | } 43 | 44 | /** 45 | * 46 | * @param string $originalModelName 47 | */ 48 | public function setOriginalModelName(string $originalModelName): void { 49 | $this->originalModelName = $originalModelName; 50 | } 51 | 52 | /** 53 | * 54 | * @return string 55 | */ 56 | public function getTableName(): string { 57 | return $this->tableName ?? (\lcfirst($this->originalModelName)); 58 | } 59 | 60 | /** 61 | * 62 | * @param string|null $tableName 63 | */ 64 | public function setTableName(?string $tableName): void { 65 | $this->tableName = $tableName; 66 | } 67 | 68 | /** 69 | * 70 | * @return string|null 71 | */ 72 | public function getDefaultPk(): ?string { 73 | return $this->defaultPk; 74 | } 75 | 76 | public function getDefaultFk(): string { 77 | return 'id' . \ucfirst($this->originalModelName); 78 | } 79 | 80 | public function hasDefaultPk(): bool { 81 | return isset($this->defaultPk) && $this->defaultPk != ''; 82 | } 83 | 84 | /** 85 | * 86 | * @param string|null $defaultPk 87 | */ 88 | public function setDefaultPk(?string $defaultPk): void { 89 | $this->defaultPk = $defaultPk; 90 | } 91 | 92 | /** 93 | * 94 | * @return array 95 | */ 96 | public function getPks(): array { 97 | return $this->pks; 98 | } 99 | 100 | public function resetPks() { 101 | $this->pks = []; 102 | } 103 | 104 | /** 105 | * 106 | * @param array $pks 107 | */ 108 | public function setPks(array $pks): void { 109 | $this->pks = $pks; 110 | } 111 | 112 | public function addPk(string $pk): bool { 113 | if (! \in_array($pk, $this->pks)) { 114 | $this->pks[] = $pk; 115 | return true; 116 | } 117 | return false; 118 | } 119 | 120 | /** 121 | * 122 | * @return array 123 | */ 124 | public function getFields(): array { 125 | return $this->fields; 126 | } 127 | 128 | /** 129 | * 130 | * @param array $fields 131 | */ 132 | public function setFields(array $fields): void { 133 | $this->fields = $fields; 134 | } 135 | 136 | public function addField(string $name, array $fieldInfos) { 137 | $this->fields[$name] = $fieldInfos; 138 | } 139 | 140 | public function hasField(string $name): bool { 141 | return isset($this->fields[$name]); 142 | } 143 | 144 | public function getFieldNames(): array { 145 | if (\is_array($this->fields)) { 146 | return \array_keys($this->fields); 147 | } 148 | return []; 149 | } 150 | 151 | public function updateFirstPk() { 152 | if ($this->hasDefaultPk()) { 153 | $this->addField($this->defaultPk, [ 154 | 'Type' => 'int', 155 | 'Nullable' => 'false' 156 | ]); 157 | $this->addPk($this->defaultPk); 158 | } 159 | } 160 | 161 | public function getFirstPk(): ?string { 162 | return $this->defaultPk ?? ($this->pks[0] ?? null); 163 | } 164 | 165 | public function updatePks($pks) { 166 | $pks = \explode(',', $pks); 167 | $this->pks = []; 168 | $this->updateFirstPk(); 169 | foreach ($pks as $pk) { 170 | $this->addPk($pk); 171 | } 172 | } 173 | 174 | public function setFieldsOrder() { 175 | $result = []; 176 | $fields = $this->fields; 177 | $pks = $this->getPks(); 178 | foreach ($pks as $pk) { 179 | $result[$pk] = $fields[$pk]; 180 | unset($fields[$pk]); 181 | } 182 | foreach ($fields as $field => $fieldInfos) { 183 | $result[$field] = $fieldInfos; 184 | } 185 | $this->fields = $result; 186 | } 187 | 188 | public function getSimpleMembers() { 189 | $members = []; 190 | foreach ($this->fields as $name => $fieldInfos) { 191 | if ($fieldInfos['Type'] !== 'mixed') { 192 | $members[] = $name; 193 | } 194 | } 195 | return $members; 196 | } 197 | 198 | public function generateClass($className, $namespace, $dbOffset): Model { 199 | $memberAccess = 'private'; 200 | $this->updateFirstPk(); 201 | $this->setFieldsOrder(); 202 | $engine = CacheManager::getAnnotationsEngineInstance(); 203 | $class = new Model($engine, \lcfirst($className), $namespace, $memberAccess); 204 | $class->setTable($this->getTableName()); 205 | $class->setDatabase($dbOffset); 206 | $fieldsInfos = $this->selectFieldsForGeneration(); 207 | $class->setSimpleMembers($this->getSimpleMembers()); 208 | $keys = $this->pks; 209 | foreach ($fieldsInfos as $field => $info) { 210 | $member = new Member($class, $engine, $field, $memberAccess); 211 | if (\in_array($field, $keys)) { 212 | $member->setPrimary(); 213 | } 214 | $member->setDbType($info); 215 | $member->addValidators(); 216 | $member->setTransformer(); 217 | $class->addMember($member); 218 | } 219 | $class->addMainAnnots(); 220 | return $class; 221 | } 222 | 223 | private function selectFieldsForGeneration() { 224 | $fieldsInRelation = $this->getFieldsInRelations(); 225 | $result = []; 226 | foreach ($this->fields as $f => $infos) { 227 | if (! in_array($f, $fieldsInRelation)) { 228 | $result[$f] = $infos; 229 | } 230 | } 231 | return $result; 232 | } 233 | 234 | private function getFieldsInRelations() { 235 | $result = []; 236 | foreach ($this->manyToOne as $f => $_) { 237 | $result[] = $f; 238 | } 239 | foreach ($this->oneToMany as $f => $_) { 240 | $result[] = $f; 241 | } 242 | foreach ($this->manyToMany as $f => $_) { 243 | $result[] = $f; 244 | } 245 | return $result; 246 | } 247 | 248 | public function addManyToOne($member, $fkField, $className) { 249 | $this->manyToOne[$member] = \compact('fkField', 'className'); 250 | } 251 | 252 | public function addOneToMany($member, $mappedBy, $className) { 253 | $this->oneToMany[$member] = \compact('mappedBy', 'className'); 254 | } 255 | 256 | public function addManyToMany($member, $otherClassName, $otherMember, $joinTable, $joinColumn, $otherJoinColumn) { 257 | $this->manyToMany[$member] = compact('otherClassName', 'otherMember', 'joinTable', 'joinColumn', 'otherJoinColumn'); 258 | } 259 | 260 | /** 261 | * 262 | * @return array 263 | */ 264 | public function getManyToOne(): array { 265 | return $this->manyToOne; 266 | } 267 | 268 | /** 269 | * 270 | * @return array 271 | */ 272 | public function getOneToMany(): array { 273 | return $this->oneToMany; 274 | } 275 | 276 | /** 277 | * 278 | * @return array 279 | */ 280 | public function getManyToMany(): array { 281 | return $this->manyToMany; 282 | } 283 | 284 | /** 285 | * 286 | * @return bool 287 | */ 288 | public function isLoaded(): bool { 289 | return $this->loaded; 290 | } 291 | 292 | /** 293 | * 294 | * @param bool $loaded 295 | */ 296 | public function setLoaded(bool $loaded): void { 297 | $this->loaded = $loaded; 298 | } 299 | 300 | /** 301 | * 302 | * @return bool 303 | */ 304 | public function isUpdated(): bool { 305 | return $this->updated; 306 | } 307 | 308 | /** 309 | * 310 | * @param bool $updated 311 | */ 312 | public function setUpdated(bool $updated): void { 313 | $this->updated = $updated; 314 | } 315 | 316 | /** 317 | * 318 | * @param array $manyToOne 319 | */ 320 | public function setManyToOne(array $manyToOne): void { 321 | $this->manyToOne = $manyToOne; 322 | } 323 | 324 | /** 325 | * 326 | * @param array $oneToMany 327 | */ 328 | public function setOneToMany(array $oneToMany): void { 329 | $this->oneToMany = $oneToMany; 330 | } 331 | 332 | /** 333 | * 334 | * @param array $manyToMany 335 | */ 336 | public function setManyToMany(array $manyToMany): void { 337 | $this->manyToMany = $manyToMany; 338 | } 339 | 340 | public function getRelationsAsString() { 341 | $result = ''; 342 | if (\count($this->manyToOne) > 0) { 343 | $result .= ' (1)=>(' . \implode(',', \array_keys($this->manyToOne)) . ')'; 344 | } 345 | if (\count($this->oneToMany) > 0) { 346 | $result .= ' (1-*)=>(' . \implode(',', \array_keys($this->oneToMany)) . ')'; 347 | } 348 | if (\count($this->manyToMany) > 0) { 349 | $result .= ' (*-*)=>(' . \implode(',', \array_keys($this->manyToMany)) . ')'; 350 | } 351 | return $result; 352 | } 353 | 354 | /** 355 | * 356 | * @return bool 357 | */ 358 | public function isLoadedFromCache(): bool { 359 | return $this->loadedFromCache; 360 | } 361 | 362 | /** 363 | * 364 | * @param bool $loadedFromCache 365 | */ 366 | public function setLoadedFromCache(bool $loadedFromCache): void { 367 | $this->loadedFromCache = $loadedFromCache; 368 | } 369 | } 370 | -------------------------------------------------------------------------------- /src/devtools/cmd/commands/traits/DbCheckTrait.php: -------------------------------------------------------------------------------- 1 | 0) { 21 | ob_start(); 22 | CacheManager::initCache($config, 'models'); 23 | $res = ob_get_clean(); 24 | echo ConsoleFormatter::showMessage($res, 'success', 'init-cache: models'); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/devtools/core/ConsoleScaffoldController.php: -------------------------------------------------------------------------------- 1 | create($this, $reInit); 37 | } 38 | 39 | public function addRestApiController($restControllerName, $routePath = "", $reInit = true) { 40 | $this->addRestController($restControllerName, JsonApiRestController::class, '', $routePath, $reInit); 41 | } 42 | 43 | public function addJsonRestController($restControllerName, $routePath = "", $reInit = true) { 44 | $this->addRestController($restControllerName, JsonRestController::class, '', $routePath, $reInit); 45 | } 46 | 47 | public function initRestCache($refresh = true) { 48 | $config = Startup::getConfig(); 49 | \ob_start(); 50 | CacheManager::initCache($config, "rest"); 51 | CacheManager::initCache($config, "controllers"); 52 | $message = \ob_get_clean(); 53 | echo $this->showSimpleMessage($message, "info", "Rest", "info cache re-init"); 54 | } 55 | } 56 | 57 | -------------------------------------------------------------------------------- /src/devtools/core/themesConfig.php: -------------------------------------------------------------------------------- 1 | [ 4 | 'composer'=>['twitter/bootstrap'=>'^4.3','fortawesome/font-awesome'=>'^5.7'], 5 | 'vendor-copy'=>[ 6 | '/vendor/fortawesome/font-awesome/css/all.min.css'=>'/public/assets/%theme%/css/all.min.css', 7 | '/vendor/fortawesome/font-awesome/webfonts'=>'/public/assets/%theme%/webfonts', 8 | ] 9 | ], 10 | 'foundation'=>[ 11 | 'composer'=>['zurb/foundation'=>'^6.5'] 12 | ], 13 | 'semantic'=>[ 14 | 'composer'=>['fomantic/ui'=>'^2.8','frameworks/jquery'=> '~2.1'], 15 | 'vendor-copy'=>[ 16 | '/vendor/fomantic/ui/dist/semantic.min.css'=>'/public/assets/%theme%/css/semantic.min.css', 17 | '/vendor/fomantic/ui/dist/semantic.min.js'=>'/public/assets/%theme%/js/semantic.min.js', 18 | '/vendor/frameworks/jquery/jquery.min.js'=>'/public/assets/%theme%/js/jquery.min.js' 19 | ] 20 | ] 21 | ]; 22 | -------------------------------------------------------------------------------- /src/devtools/core/toolsConfig.php: -------------------------------------------------------------------------------- 1 | [ 4 | "jquery" => "https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js", 5 | "bootstrap" => [ 6 | "css" => "https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css", 7 | "js" => "https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js" 8 | ], 9 | "semantic" => [ 10 | "css" => "https://cdn.jsdelivr.net/npm/fomantic-ui@2.9.3/dist/semantic.min.css", 11 | "js" => "https://cdn.jsdelivr.net/npm/fomantic-ui@2.9.3/dist/semantic.min.js" 12 | ], 13 | "diff2html" => [ 14 | "css" => "https://cdnjs.cloudflare.com/ajax/libs/diff2html/2.12.2/diff2html.min.css" 15 | ] 16 | ], 17 | "composer" => [ 18 | "require" => [ 19 | "php" => ">=7.4", 20 | "twig/twig" => "^3.0", 21 | "phpmv/ubiquity" => "^2.5" 22 | ], 23 | "require-dev" => [ 24 | "monolog/monolog" => "^2.2", 25 | "phpmv/ubiquity-dev" => "^0.1", 26 | "phpmv/ubiquity-debug" => "^0.0" 27 | ], 28 | "autoload" => [ 29 | "psr-4" => [ 30 | "" => "app/" 31 | ] 32 | ] 33 | ] 34 | ]; 35 | -------------------------------------------------------------------------------- /src/devtools/project-files/.htaccess: -------------------------------------------------------------------------------- 1 | AddDefaultCharset UTF-8 2 | 3 | 4 | RewriteEngine On 5 | RewriteBase /%rewriteBase%/ 6 | 7 | RewriteCond %{REQUEST_FILENAME} !-f 8 | RewriteCond %{HTTP_ACCEPT} !(.*images.*) 9 | RewriteRule ^(.*)$ index.php?c=$1 [L,QSA] 10 | 11 | -------------------------------------------------------------------------------- /src/devtools/project-files/README.md: -------------------------------------------------------------------------------- 1 | # %projectName% 2 | 3 | This README outlines the details of collaborating on this Ubiquity application. 4 | A short introduction of this app could easily go here. 5 | 6 | ## Prerequisites 7 | 8 | You will need the following things properly installed on your computer. 9 | 10 | * php >=7.4 11 | * [Git](https://git-scm.com/) 12 | * [Composer](https://getcomposer.org) 13 | * [Ubiquity devtools](https://ubiquity.kobject.net/) 14 | 15 | ## Installation 16 | 17 | * `git clone ` this repository 18 | * `cd %projectName%` 19 | * `composer install` 20 | 21 | ## Running / Development 22 | 23 | * `Ubiquity serve` 24 | * Visit your app at [http://127.0.0.1:8090](http://127.0.0.1:8090). 25 | 26 | ### devtools 27 | 28 | Make use of the many generators for code, try `Ubiquity help` for more details 29 | 30 | ### Optimization for production 31 | 32 | Run: 33 | `composer install --optimize --no-dev --classmap-authoritative` 34 | 35 | ### Deploying 36 | 37 | Specify what it takes to deploy your app. 38 | 39 | ## Further Reading / Useful Links 40 | 41 | * [Ubiquity website](https://ubiquity.kobject.net/) 42 | * [Guide](http://micro-framework.readthedocs.io/en/latest/?badge=latest) 43 | * [Doc API](https://api.kobject.net/ubiquity/) 44 | * [Twig documentation](https://twig.symfony.com) 45 | * [Semantic-UI](https://semantic-ui.com) 46 | -------------------------------------------------------------------------------- /src/devtools/project-files/app/.htaccess: -------------------------------------------------------------------------------- 1 | deny from all -------------------------------------------------------------------------------- /src/devtools/project-files/app/controllers/Admin.php: -------------------------------------------------------------------------------- 1 | loadView($this->headerView); 19 | } 20 | } 21 | 22 | public function finalize() { 23 | if (! URequest::isAjax()) { 24 | $this->loadView($this->footerView); 25 | } 26 | } 27 | } 28 | 29 | -------------------------------------------------------------------------------- /src/devtools/project-files/app/controllers/IndexController.php: -------------------------------------------------------------------------------- 1 | 0) { 21 | $this->loadView('@activeTheme/main/vMenu.html', \compact('themes', 'activeTheme')); 22 | } 23 | $this->loadView($defaultPage, \compact('defaultPage', 'links', 'infos', 'activeTheme')); 24 | } 25 | 26 | public function ct($theme) { 27 | $themes = Display::getThemes(); 28 | if ($theme != null && \array_search($theme, $themes) !== false) { 29 | $config = ThemesManager::saveActiveTheme($theme); 30 | \header('Location: ' . $config['siteUrl']); 31 | } else { 32 | Logger::warn('Themes', \sprintf('The theme %s does not exists!', $theme), 'changeTheme(ct)'); 33 | $this->forward(IndexController::class); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/devtools/project-files/app/views/themes/bootstrap/main/vFooter.html: -------------------------------------------------------------------------------- 1 | {% block footer %} 2 | {% endblock %} 3 | {% block scripts %} 4 | 5 | 6 | 7 | {% endblock %} 8 | 9 | -------------------------------------------------------------------------------- /src/devtools/project-files/app/views/themes/bootstrap/main/vHeader.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {% block header %} 5 | 6 | 7 | ubi-projects Bootstrap 8 | {% endblock %} 9 | {% block css %} 10 | {{css('@activeTheme/css/style.css',{nonce: nonce})}} 11 | {{css('@activeTheme/css/all.min.css',{nonce: nonce})}} 12 | 13 | {% endblock %} 14 | 15 | 16 | {% block head %} 17 | {% endblock %} 18 | -------------------------------------------------------------------------------- /src/devtools/project-files/app/views/themes/bootstrap/main/vMenu.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/devtools/project-files/app/views/themes/foundation/main/vFooter.html: -------------------------------------------------------------------------------- 1 | {% block footer %} 2 | 3 | {% endblock %} 4 | {% block scripts %} 5 | {{js('https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js',{nonce: nonce})}} 6 | {{js('https://cdn.jsdelivr.net/npm/foundation-sites@6.5.3/dist/js/foundation.min.js',{nonce: nonce})}} 7 | 10 | {% endblock %} 11 | 12 | -------------------------------------------------------------------------------- /src/devtools/project-files/app/views/themes/foundation/main/vHeader.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {% block header %} 5 | 6 | 7 | ubi-projects Foundation 8 | {% endblock %} 9 | {% block css %} 10 | {{css('@activeTheme/css/style.css',{nonce: nonce})}} 11 | {{css('https://cdnjs.cloudflare.com/ajax/libs/foundicons/3.0.0/foundation-icons.min.css',{nonce: nonce})}} 12 | {% endblock %} 13 | 14 | 15 | {% block head %} 16 | 17 | {% endblock %} -------------------------------------------------------------------------------- /src/devtools/project-files/app/views/themes/foundation/main/vMenu.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 12 |
13 |
14 |
-------------------------------------------------------------------------------- /src/devtools/project-files/app/views/themes/model/main/vFooter.html: -------------------------------------------------------------------------------- 1 | {% block footer %} 2 | 3 | {% endblock %} 4 | {% block scripts %} 5 | 6 | {% endblock %} 7 | 8 | -------------------------------------------------------------------------------- /src/devtools/project-files/app/views/themes/model/main/vHeader.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {% block header %} 5 | 6 | 7 | Custom theme 8 | {% endblock %} 9 | {% block css %} 10 | 11 | {% endblock %} 12 | 13 | 14 | {% block head %} 15 | 16 | {% endblock %} -------------------------------------------------------------------------------- /src/devtools/project-files/app/views/themes/model/main/vMenu.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 12 |
13 |
14 |
-------------------------------------------------------------------------------- /src/devtools/project-files/app/views/themes/semantic/main/vFooter.html: -------------------------------------------------------------------------------- 1 | {% block footer %} 2 | {% endblock %} 3 | {% block scripts %} 4 | 5 | 6 | {{script_foot | raw }} 7 | {% endblock %} 8 | 9 | -------------------------------------------------------------------------------- /src/devtools/project-files/app/views/themes/semantic/main/vHeader.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {% block header %} 5 | 6 | 7 | ubi-projects semantic-UI 8 | {% endblock %} 9 | {% block css %} 10 | 11 | {{css('@activeTheme/css/style.css',{nonce:nonce}) | raw}} 12 | {% endblock %} 13 | 14 | 15 | {% block head %} 16 | {% endblock %} -------------------------------------------------------------------------------- /src/devtools/project-files/app/views/themes/semantic/main/vMenu.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 13 |
14 |
-------------------------------------------------------------------------------- /src/devtools/project-files/index.php: -------------------------------------------------------------------------------- 1 | run('composer','optimize'); 23 | } 24 | 25 | //Executed before all modes 26 | function bs_before($devtools,$config){ 27 | 28 | } 29 | 30 | //Executed after all modes 31 | function bs_after($devtools,$config){ 32 | //Initialize all caches 33 | $devtools->run('init-cache'); 34 | } -------------------------------------------------------------------------------- /src/devtools/project-files/templates/config.tpl: -------------------------------------------------------------------------------- 1 | "%siteUrl%", 4 | "database"=>[ 5 | "type"=>"%dbType%", 6 | "wrapper"=>"%dbWrapper%", 7 | "dbName"=>getenv('DB_NAME'), 8 | "serverName"=>"%serverName%", 9 | "port"=>"%port%", 10 | "user"=>getenv('DB_USER'), 11 | "password"=>getenv('DB_PASS'), 12 | "options"=>[], 13 | "cache"=>false 14 | ], 15 | "sessionName"=>"%sessionName%", 16 | "namespaces"=>[], 17 | "templateEngine"=>'%templateEngine%', 18 | "templateEngineOptions"=>array("cache"=>false%activeTheme%), 19 | "test"=>false, 20 | "debug"=>false, 21 | "logger"=>function(){return new \Ubiquity\log\libraries\UMonolog("%projectName%",\Monolog\Logger::INFO);}, 22 | "di"=>[%injections%], 23 | "cache"=>["directory"=>"cache/","system"=>"Ubiquity\\cache\\system\\ArrayCache","params"=>[]], 24 | "mvcNS"=>["models"=>"models","controllers"=>"controllers","rest"=>""] 25 | ); 26 | -------------------------------------------------------------------------------- /src/devtools/project-files/templates/controller.tpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {% block header %} 5 | 6 | 7 | %projectName% 8 | {% endblock %} 9 | {% block css %} 10 | %cssFiles% 11 | {% endblock %} 12 | 13 | 14 | {% block body %} 15 |
16 |
17 | {% endblock %} 18 | {% block scripts %} 19 | %jsFiles% 20 | {% endblock %} 21 | 22 | -------------------------------------------------------------------------------- /src/devtools/project-files/templates/indexThemes.tpl: -------------------------------------------------------------------------------- 1 | {% extends "@activeTheme/main.html"%} 2 | {%block body%} 3 | {% include [defaultPage,'@framework/index/index.html'] %} 4 | {% endblock %} -------------------------------------------------------------------------------- /src/devtools/project-files/templates/preloader.config.tpl: -------------------------------------------------------------------------------- 1 | array(), 4 | "classes" => array(), 5 | "paths" => array(), 6 | "excludeds" => array(), 7 | "libraries-parts" => array(), 8 | "callback" => function (\Ubiquity\cache\Preloader $preloader) { 9 | $preloader->addUbiquityBasics(%hasDatabase%); 10 | } 11 | ); -------------------------------------------------------------------------------- /src/devtools/project-files/templates/preloader.script.tpl: -------------------------------------------------------------------------------- 1 | 3 | 4 | 10 | 11 | {% endblock %} 12 | {% block scripts %} 13 | %jsFiles% 14 | {% endblock %} 15 | 16 | -------------------------------------------------------------------------------- /src/devtools/project-files/templates/vHeader.tpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {% block header %} 5 | 6 | 7 | 8 | %projectName% 9 | {% endblock %} 10 | {% block css %} 11 | %cssFiles% 12 | {{css('css/style.css', {nonce: nonce})}} 13 | {% endblock %} 14 | 15 | 16 | {% block head %} 17 |
18 |
19 |
20 | 24 |
25 |
26 |
27 |
28 | {% endblock %} 29 | -------------------------------------------------------------------------------- /src/devtools/project-files/templates/view.tpl: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/devtools/server/.htrouter.php: -------------------------------------------------------------------------------- 1 | 'application/x-javascript', 7 | 'css' => 'text/css' 8 | ]; 9 | $pathInfo = \pathinfo($uri); 10 | \header("Content-Type: " . $fileExts[$pathInfo['extension']]); 11 | \readfile(__DIR__ . '/../' . $uri); 12 | } elseif ($uri !== 'favicon.ico' && ($uri == null || ! \file_exists(__DIR__ . '/../public/' . $uri))) { 13 | $_GET['c'] = $uri; 14 | include_once '_index.php'; 15 | return true; 16 | } else { 17 | $_GET['c'] = ''; 18 | return false; 19 | } 20 | -------------------------------------------------------------------------------- /src/devtools/server/_index.php: -------------------------------------------------------------------------------- 1 | init($config, realpath(__DIR__.\DS.'..'.\DS.'public'.\DS)); 17 | require ROOT.'config/services.php'; 18 | $reactServer->run($address); 19 | -------------------------------------------------------------------------------- /src/devtools/server/_swoole.php: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | init($config, realpath(__DIR__.\DS.'..'.\DS.'public'.\DS)); 17 | require ROOT.'config/services.php'; 18 | $swooleServer->run($sConfig['host'],$sConfig['port'],$sConfig['options']??[]); 19 | -------------------------------------------------------------------------------- /src/devtools/server/_swow.php: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | init($config, realpath(__DIR__.\DS.'..'.\DS.'public'.\DS)); 17 | require ROOT.'config/services.php'; 18 | $swowServer->run($sConfig['host'],$sConfig['port'],$sConfig['socket']??[]); 19 | -------------------------------------------------------------------------------- /src/devtools/server/_workerman.php: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | init($config, realpath(__DIR__.\DS.'..'.\DS.'public'.\DS)); 17 | $workerServer->setDefaultCount(); 18 | require ROOT.'config/services.php'; 19 | $workerServer->run($sConfig['host'],$sConfig['port'],$sConfig['socket']??[]); 20 | -------------------------------------------------------------------------------- /src/devtools/utils/FrameworkParts.php: -------------------------------------------------------------------------------- 1 |