├── .github ├── FUNDING.yml ├── sequel_ace_file_perms.png ├── ISSUE_TEMPLATE.md ├── PULL_REQUEST_TEMPLATE.md ├── workflows │ └── release.yml └── jetbrains.svg ├── .gitignore ├── .semver ├── TODO.md ├── src ├── parse.php ├── foreign_key.stub ├── create.stub ├── command.plist ├── parse.sh └── MigrationParser.php ├── LICENSE.md ├── CONTRIBUTING.md ├── README.md └── CHANGELOG.md /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: cviebrock 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.tsv 2 | .idea 3 | /build/ 4 | -------------------------------------------------------------------------------- /.semver: -------------------------------------------------------------------------------- 1 | --- 2 | :major: 2 3 | :minor: 0 4 | :patch: 2 5 | :special: '' 6 | -------------------------------------------------------------------------------- /.github/sequel_ace_file_perms.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cviebrock/sequel-pro-laravel-export/master/.github/sequel_ace_file_perms.png -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | # Todo 2 | 3 | - [x] Better foreign key handling (cascade, etc.) 4 | - [ ] Don't specify key/index names if they match Laravel's defaults 5 | - [ ] Handle `morphs()` 6 | - [ ] Support for selecting multiple tables (and using Sequel Pro's `SP_SELECTED_TABLES` environment variable) 7 | - [ ] Support for other key types: 8 | - [x] FULLTEXT 9 | - [ ] SPATIAL 10 | - [ ] ??? -------------------------------------------------------------------------------- /src/parse.php: -------------------------------------------------------------------------------- 1 | makeMigration(); 22 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Please be sure you include all the relevant information in your issue so we can help you: 2 | 3 | - [ ] steps taken to reproduce your issue 4 | - [ ] your configuration file(s), where relevant 5 | - [ ] any other code we might need to help 6 | 7 | Please use a descriptive title for your issue. "Why doesn't this work?" doesn't provide 8 | other users much information if they are scanning the list of issues. 9 | 10 | Also, *please* use [fenced code blocks](https://help.github.com/articles/creating-and-highlighting-code-blocks/) 11 | when pasting more than one line of code. It makes it so much more readable for everyone! 12 | 13 | **Thank you!** 14 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Thank you for helping to make this package better! 2 | 3 | Please make sure you've read [CONTRIBUTING.md](https://github.com/cviebrock/sequel-pro-laravel-export/blob/master/CONTRIBUTING.md) 4 | before submitting your pull request, and that you have: 5 | 6 | - [ ] provided a rationale for your change (I try not to add features that are going to have a limited user-base) 7 | - [ ] used the [PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md) 8 | - [ ] added tests 9 | - [ ] documented any change in behaviour (e.g. updated the `README.md`, etc.) 10 | - [ ] only submitted one pull request per feature 11 | 12 | **Thank you!** 13 | -------------------------------------------------------------------------------- /src/foreign_key.stub: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | author 6 | Colin Viebrock 7 | category 8 | Export 9 | command 10 | sh parse.sh 11 | contact 12 | uggcf://tvguho.pbz/pivroebpx/RkcbegGbYneniryZvtengvba.fcOhaqyr 13 | description 14 | Exports the selected table(s) to Laravel migration files on the desktop. 15 | keyEquivalent 16 | ^~@m 17 | name 18 | Export To Laravel Migration(s) 19 | output 20 | showashtml 21 | scope 22 | general 23 | tooltip 24 | Export the selected table(s) to Laravel migration file(s) in a Desktop folder 25 | uuid 26 | BAAD749B-F050-4F02-879C-333B581D2E23 27 | 28 | 29 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Colin Viebrock 4 | 5 | > Permission is hereby granted, free of charge, to any person obtaining a copy 6 | > of this software and associated documentation files (the "Software"), to deal 7 | > in the Software without restriction, including without limitation the rights 8 | > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | > copies of the Software, and to permit persons to whom the Software is 10 | > furnished to do so, subject to the following conditions: 11 | > 12 | > The above copyright notice and this permission notice shall be included in all 13 | > copies or substantial portions of the Software. 14 | > 15 | > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | > SOFTWARE. 22 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Contributions are **welcome** and will be fully **credited**. 4 | 5 | We accept contributions via pull requests via 6 | [Github](https://github.com/cviebrock/sequel-pro-laravel-export). 7 | 8 | 1. Fork the project. 9 | 2. Create your bugfix/feature branch and write your (well-commented) code. 10 | 3. Create unit tests for your code (if applicable) 11 | - Run `composer install --dev` in the root directory to install required testing packages. 12 | - Add your test classes/methods to the `/tests/` directory. 13 | - Run `vendor/bin/phpunit` and make sure everything passes (new and old tests). 14 | 3. Commit your changes (and your tests) and push to your branch. 15 | 4. Create a new pull request against this package's `master` branch. 16 | 17 | 18 | ## Pull Requests 19 | 20 | - **Use the [PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md).** 21 | The easiest way to apply the conventions is to install [PHP Code Sniffer](http://pear.php.net/package/PHP_CodeSniffer). 22 | 23 | - **Add tests!** Your pull request won't be accepted if it doesn't have tests. 24 | 25 | - **Document any change in behaviour.** Make sure the `README.md` and any other relevant 26 | documentation are kept up-to-date. 27 | 28 | - **Consider our release cycle.** We try to follow [SemVer v2.0.0](http://semver.org/). 29 | Randomly breaking public APIs is not an option. 30 | 31 | - **Create feature branches.** Don't ask us to pull from your master branch. 32 | 33 | - **One pull request per feature.** If you want to do more than one thing, send multiple pull requests. 34 | 35 | - **Send coherent history.** - Make sure each individual commit in your pull request is meaningful. 36 | If you had to make multiple intermediate commits while developing, please 37 | [squash them](http://www.git-scm.com/book/en/v2/Git-Tools-Rewriting-History#Changing-Multiple-Commit-Messages) 38 | before submitting. 39 | 40 | - Don't worry about updating `CHANGELOG.md` or `.semver`. The package administrator 41 | will handle updating those when new releases are created. 42 | 43 | 44 | **Thank you!** 45 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Laravel Migration Exporter for Sequel Pro and Sequel Ace 2 | 3 | A bundle for [Sequel Pro](https://www.sequelpro.com/) and 4 | [Sequel Ace](https://sequel-ace.com/) that lets you generate 5 | Laravel migration files from existing tables. 6 | 7 | 8 | ## Installation 9 | 10 | 1. Download the latest release and unzip the appropriate file, 11 | depending on whether you are using Sequel Pro or Sequel Ace. 12 | 2. Double-click on the bundle package to install the bundle. 13 | 3. Launch Sequel Pro or Ace! 14 | 15 | 16 | ## Installation from Source 17 | 18 | 1. Clone the repository 19 | 2. Run `./build.sh` to create Sequel Pro and Sequel Ace versions of the bundle 20 | 3. Use the appropriate bundle in the `build` directory 21 | 22 | 23 | ## Usage 24 | 25 | Connect to a database, and select a table in the left-hand column. From the application menu, choose 26 | **Bundles › Export › Export to Laravel Migration**, or use the keyboard shortcut **⌃⌥⌘M** (that's 27 | CTRL + OPTION + CMD + M). 28 | 29 | The resulting Laravel migration file will be saved in a new directory called _SequelProLaravelExport_ on your desktop. 30 | You can then move this file into your Laravel project (usually `/database/migrations`) and then run `artisan migrate`. 31 | 32 | 33 | ## Sequel Ace Usage 34 | 35 | The Sequel Ace bundle will only work with version 3.0.0 and later of Sequel Ace. 36 | 37 | You will also need to give Sequel Ace permission to write to the Desktop folder 38 | via the application's preferences: 39 | 40 | ![](./.github/sequel_ace_file_perms.png) 41 | 42 | ## Caveats 43 | 44 | Auto-generated migration files will likely need manual adjustments. Be sure to look at the code before 45 | running `artisan migrate`! 46 | 47 | 48 | ## Bugs, Suggestions and Contributions 49 | 50 | Thanks to [everyone](https://github.com/cviebrock/sequel-pro-laravel-export/graphs/contributors) 51 | who has contributed to this project! 52 | 53 | Please use [Github issues](https://github.com/cviebrock/sequel-pro-laravel-export/issues) for reporting bugs, 54 | and making comments or suggestions. 55 | 56 | See [CONTRIBUTING.md](CONTRIBUTING.md) for how to contribute changes. 57 | 58 | ## Copyright and License 59 | 60 | [sequel-pro-laravel-export](https://github.com/cviebrock/sequel-pro-laravel-export) 61 | was written by [Colin Viebrock](http://viebrock.ca) and is released under the 62 | [MIT License](LICENSE.md). 63 | 64 | Copyright (c) 2016 Colin Viebrock 65 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 2.0.2 - 05-Aug-2022 4 | 5 | - Fix the version as reported in export files (#41, thanks @pemedina) 6 | 7 | 8 | ## 2.0.1 - 28-Dec-2020 9 | 10 | - Create separate migrations to handle foreign keys (#37, thanks @rootrus) 11 | - BIGINTEGER AUTO_INCREMENT columns are now exported as `->id()` with 12 | optional column name if it isn't `id` 13 | 14 | 15 | ## 2.0.0 - 02-Dec-2020 16 | 17 | - Bundle now supports [Sequel Pro](https://www.sequelpro.com/) 18 | and [Sequel Ace](https://sequel-ace.com/) 19 | 20 | 21 | ## 1.8.1 - 26-Nov-2020 22 | 23 | - Minor tweak to unsigned or auto-incrementing integers to use 24 | the more compact migration methods 25 | 26 | 27 | ## 1.8.0 - 26-Nov-2020 28 | 29 | - Reworked handling of signed autoincrement integers and 30 | unsigned floating-point types (#36, thanks @nick15marketing) 31 | - Adds support for SET columns 32 | - Adds support for NUMERIC and FIXED columns (exported as `->decimal()`), 33 | and DOUBLE PRECISION and REAL columns (exported as `->double()`) 34 | - Table columns are now ordered in the migration the same way 35 | they are in the database 36 | 37 | 38 | ## 1.7.0 - 09-Mar-2020 39 | 40 | - Adds support for timestamp columns with `ON UPDATE CURRENT_TIMESTAMP` 41 | - Suppresses `->characterSet()` and `->collation()` on text columns 42 | that share the table's default character set and/or collation 43 | - Removes some extra blank lines from the resulting migration file 44 | - A bit of code cleanup 45 | 46 | 47 | ## 1.6.0 - 20-Jan-2020 48 | 49 | - Adds charset and collation information for tables/columns 50 | - Fix for default values being double-quoted 51 | 52 | 53 | ## 1.5.0 - 24-Feb-2019 54 | 55 | - Fixes for: 56 | - compound foreign keys 57 | - ENUM fields with default strings 58 | - quotes in comments 59 | 60 | 61 | ## 1.4.1 - 24-Nov-2017 62 | 63 | - Real fix for handling FULLTEXT indices 64 | 65 | 66 | ## 1.4.0 - 21-Nov-2017 67 | 68 | - Broken fix for FULLTEXT (version deleted) 69 | 70 | 71 | ## 1.3.1 - 01-Nov-2017 72 | 73 | - Fix for ENUM handling and default values 74 | 75 | 76 | ## 1.3.0 - 16-Oct-2017 77 | 78 | - Check that `REFERENTIAL_CONSTRAINTS` table exists before using it; 79 | should make bundle work with MySQL 5.1 80 | 81 | 82 | ## 1.2.0 - 14-Jul-2017 83 | 84 | - Fix for listing indices when the table name is a reserved word 85 | - Nicer output (with clickable links to generated files) 86 | - Parsing script moved into separate bash file, rather than stored 87 | in the plist (easier to maintain) 88 | 89 | 90 | ## 1.1.0 - 17-May-2017 91 | 92 | - Added support for `tinytext()` columns 93 | - Migrations are now saved to `~/Desktop/SequelProLaravelExport/` 94 | instead of directly on the desktop 95 | 96 | 97 | ## 1.0.2 - 18-Nov-2016 98 | 99 | - Fix for when there is more than one database with the same table name(s) 100 | 101 | 102 | ## 1.0.1 - 16-Nov-2016 103 | 104 | - Added support for `comment()` 105 | 106 | 107 | ## 1.0.0 - 18-Oct-2016 108 | 109 | - First stable release 110 | - Added support for exporting multiple tables 111 | - Fix primary keys using multiple columns 112 | - Better handling of default values for numeric and boolean columns 113 | 114 | 115 | ## 1.0-beta.3 - 17-Oct-2016 116 | 117 | - Added support for `json` columns 118 | - Fixed `enum` column output 119 | - Fixed `unsignedIncrements()` bug 120 | - Bug fixes 121 | 122 | 123 | ## 1.0-beta.2 - 13-Oct-2016 124 | 125 | - Better foreign key handling (cascade, etc.) 126 | - Bug fixes 127 | 128 | 129 | ## 1.0-beta - 06-Oct-2016 130 | 131 | ## 1.0-alpha.2 - 05-Oct-2016 132 | 133 | ## 1.0-alpha - 05-Oct-2016 134 | 135 | - Initial release 136 | -------------------------------------------------------------------------------- /.github/jetbrains.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 10 | 11 | 14 | 15 | 16 | 17 | 18 | 19 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 31 | 32 | 33 | 34 | 35 | 36 | 39 | 40 | 41 | 42 | 43 | 45 | 47 | 48 | 51 | 54 | 56 | 57 | 59 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /src/parse.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # set up some functions 4 | clear_temp() 5 | { 6 | rm -f "$SP_QUERY_RESULT_FILE" 7 | rm -f "$SP_QUERY_FILE" 8 | rm -f "$SP_QUERY_RESULT_STATUS_FILE" 9 | } 10 | 11 | execute_sql() 12 | { 13 | # execute the SQL statement; the result will be available in the file $SP_QUERY_RESULT_FILE 14 | open "sequelpro://$SP_PROCESS_ID@passToDoc/ExecuteQuery" 15 | 16 | # wait for results; status file will be written to disk if query was finished 17 | while [ 1 ] 18 | do 19 | [[ -e "$SP_QUERY_RESULT_STATUS_FILE" ]] && break 20 | sleep 0.01 21 | done 22 | 23 | # check for errors 24 | if [ `cat "$SP_QUERY_RESULT_STATUS_FILE"` == 1 ]; then 25 | echo "

Query error:

"
 26 |         cat "$SP_QUERY_RESULT_FILE"
 27 |         echo "
" 28 | echo "" 29 | exit "$SP_BUNDLE_EXIT_SHOW_AS_HTML" 30 | fi 31 | } 32 | 33 | # set up HTML styles 34 | echo " 35 | 45 | " 46 | 47 | # start clean 48 | clear_temp 49 | 50 | # Check if one table is selected 51 | if [ -z "$SP_SELECTED_TABLES" ]; then 52 | echo "

Error

No table selected.

" 53 | echo "" 54 | exit "$SP_BUNDLE_EXIT_SHOW_AS_HTML" 55 | fi 56 | 57 | # build dest dir 58 | DESTDIR=~/Desktop/SequelProLaravelExport 59 | if mkdir -p $DESTDIR; then 60 | echo "

Output directory: $DESTDIR

"; 61 | else 62 | echo "

Error

Could not create directory: $DESTDIR

" 63 | echo "" 64 | exit "$SP_BUNDLE_EXIT_SHOW_AS_HTML" 65 | fi 66 | 67 | CONSTRAINTS_TABLE="no" 68 | 69 | echo " 70 | SELECT * 71 | FROM information_schema.tables 72 | WHERE table_schema = 'information_schema' 73 | AND table_name = 'REFERENTIAL_CONSTRAINTS' 74 | LIMIT 1;" > "$SP_QUERY_FILE" 75 | execute_sql 76 | 77 | if [ `cat "$SP_QUERY_RESULT_STATUS_FILE"` -gt 0 ] && [[ $(wc -l < "$SP_QUERY_RESULT_FILE") -ge 2 ]]; then 78 | CONSTRAINTS_TABLE="yes" 79 | fi 80 | clear_temp 81 | 82 | # Split by tab 83 | IFS=$'\t' 84 | read -r -a tables <<< "$SP_SELECTED_TABLES" 85 | 86 | # Loop through tables 87 | for table in "${tables[@]}" 88 | do 89 | 90 | # get the table structure, including field comments 91 | echo " 92 | SELECT 93 | COLUMN_NAME, COLUMN_TYPE, IS_NULLABLE, COLUMN_KEY, COLUMN_DEFAULT, CHARACTER_SET_NAME, COLLATION_NAME, EXTRA, COLUMN_COMMENT 94 | FROM 95 | information_schema.COLUMNS 96 | WHERE 97 | TABLE_SCHEMA = '${SP_SELECTED_DATABASE}' 98 | AND 99 | TABLE_NAME = '${table}' 100 | ORDER BY ORDINAL_POSITION;" > "$SP_QUERY_FILE" 101 | 102 | # execute and save the table structure result 103 | execute_sql 104 | cp "$SP_QUERY_RESULT_FILE" "$SP_BUNDLE_PATH/rowsStructure.tsv" 105 | 106 | clear_temp 107 | 108 | # build SHOW INDEXES query 109 | echo "SHOW INDEXES FROM \`${table}\`" > "$SP_QUERY_FILE" 110 | 111 | # execute and save the SHOW INDEXES result 112 | execute_sql 113 | cp "$SP_QUERY_RESULT_FILE" "$SP_BUNDLE_PATH/rowsKeys.tsv" 114 | 115 | clear_temp 116 | 117 | # get character set and collation name 118 | echo " 119 | SELECT 120 | CHARACTER_SET_NAME, TABLE_COLLATION 121 | FROM 122 | information_schema.TABLES, information_schema.COLLATION_CHARACTER_SET_APPLICABILITY 123 | WHERE 124 | COLLATION_NAME = TABLE_COLLATION 125 | AND 126 | TABLE_SCHEMA = '${SP_SELECTED_DATABASE}' 127 | AND 128 | TABLE_NAME = '${table}';" > "$SP_QUERY_FILE" 129 | 130 | # execute and save the character set and collation name result 131 | execute_sql 132 | cp "$SP_QUERY_RESULT_FILE" "$SP_BUNDLE_PATH/rowsTableCharsetAndCollation.tsv" 133 | 134 | clear_temp 135 | 136 | if [ "$CONSTRAINTS_TABLE" == "yes" ]; then 137 | 138 | # check if CONSTRAINTS exists 139 | echo " 140 | SELECT count(kcu.CONSTRAINT_NAME) 141 | FROM 142 | information_schema.REFERENTIAL_CONSTRAINTS rc 143 | LEFT JOIN 144 | information_schema.KEY_COLUMN_USAGE kcu 145 | ON 146 | (rc.CONSTRAINT_NAME=kcu.CONSTRAINT_NAME) 147 | WHERE 148 | kcu.CONSTRAINT_SCHEMA = '${SP_SELECTED_DATABASE}' 149 | AND 150 | rc.TABLE_NAME = '${table}';" > "$SP_QUERY_FILE" 151 | 152 | # check for errors 153 | execute_sql 154 | 155 | fi 156 | 157 | if [ "$CONSTRAINTS_TABLE" == "yes" ] && [ `cat "$SP_QUERY_RESULT_STATUS_FILE"` -gt 0 ]; then 158 | clear_temp 159 | 160 | # build CONSTRAINTS query 161 | echo " 162 | SELECT 163 | kcu.CONSTRAINT_NAME, kcu.COLUMN_NAME, kcu.REFERENCED_TABLE_NAME, kcu.REFERENCED_COLUMN_NAME, rc.UPDATE_RULE, rc.DELETE_RULE 164 | FROM 165 | information_schema.REFERENTIAL_CONSTRAINTS rc 166 | LEFT JOIN 167 | information_schema.KEY_COLUMN_USAGE kcu 168 | ON 169 | (rc.CONSTRAINT_NAME=kcu.CONSTRAINT_NAME) 170 | WHERE 171 | kcu.CONSTRAINT_SCHEMA = '${SP_SELECTED_DATABASE}' 172 | AND 173 | rc.TABLE_NAME = '${table}';" > "$SP_QUERY_FILE" 174 | 175 | # save the CONSTRAINTS result 176 | execute_sql 177 | cp $SP_QUERY_RESULT_FILE "$SP_BUNDLE_PATH/rowsConstraints.tsv" 178 | else 179 | echo -n "" > "$SP_BUNDLE_PATH/rowsConstraints.tsv" 180 | fi 181 | 182 | 183 | # process the results and save to the desktop 184 | FILENAME=$(date "+%Y_%m_%d_%H%M%S_create_${table}_table.php") 185 | /usr/bin/php "$SP_BUNDLE_PATH/parse.php" "${table}" > $DESTDIR/$FILENAME 186 | echo "

Migration saved: $FILENAME

" 187 | # clean up 188 | clear_temp 189 | 190 | # end loop through tables 191 | done 192 | 193 | # ensure timestamps for any foreign key migrations occur after creation migrations 194 | sleep 1 195 | 196 | # Loop through tables 197 | for table in "${tables[@]}" 198 | do 199 | # get the table foreign key 200 | echo "SELECT 201 | TABLE_NAME,COLUMN_NAME,CONSTRAINT_NAME, REFERENCED_TABLE_NAME,REFERENCED_COLUMN_NAME 202 | FROM 203 | INFORMATION_SCHEMA.KEY_COLUMN_USAGE 204 | WHERE 205 | REFERENCED_TABLE_SCHEMA = '${SP_SELECTED_DATABASE}' AND TABLE_NAME = '${table}';" > "$SP_QUERY_FILE" 206 | 207 | # execute and save the table structure result 208 | execute_sql 209 | cp $SP_QUERY_RESULT_FILE "$SP_BUNDLE_PATH/rowsForeignStructure.tsv" 210 | 211 | hasForeignKey=`cat "$SP_BUNDLE_PATH/rowsForeignStructure.tsv" | grep -v "TABLE_NAME" | wc -l | awk '{print $1}'`; 212 | if [ $hasForeignKey != 0 ]; then 213 | FILENAME=$(date "+%Y_%m_%d_%H%M%S_add_foreign_key_to_${table}_table.php") 214 | /usr/bin/php "$SP_BUNDLE_PATH/parse.php" "${table}" "foreignkey" > $DESTDIR/$FILENAME 215 | echo "

Migration for foreign key saved: $FILENAME

" 216 | # clean up 217 | clear_temp 218 | fi 219 | clear_temp 220 | # end loop through tables 221 | done 222 | 223 | echo "" 224 | exit $SP_BUNDLE_EXIT_SHOW_AS_HTML 225 | -------------------------------------------------------------------------------- /src/MigrationParser.php: -------------------------------------------------------------------------------- 1 | 'integer', 48 | 'bigint' => 'bigInteger', 49 | 'mediumint' => 'mediumInteger', 50 | 'smallint' => 'smallInteger', 51 | 'tinyint' => 'tinyInteger', 52 | ]; 53 | 54 | /** 55 | * @var string 56 | */ 57 | protected $tableName; 58 | 59 | /** 60 | * @var string 61 | */ 62 | protected $structureFile; 63 | 64 | /** 65 | * @var string 66 | */ 67 | protected $keysFile; 68 | 69 | /** 70 | * @var string 71 | */ 72 | protected $constraintsFile; 73 | 74 | /** 75 | * @var string 76 | */ 77 | protected $tableCharsetAndCollationFile; 78 | 79 | /** 80 | * @var string 81 | */ 82 | protected $foreignStructureFile; 83 | 84 | /** 85 | * @var string 86 | */ 87 | protected $hasForeign; 88 | 89 | /** 90 | * MigrationParser constructor. 91 | * 92 | * @param string $tableName 93 | * @param string $structureFile 94 | * @param string $keysFile 95 | * @param string $constraintsFile 96 | * @param string $tableCharsetAndCollationFile 97 | * @param string $foreignStructureFile 98 | * @param string $hasForeign 99 | */ 100 | public function __construct($tableName, $structureFile, $keysFile, $constraintsFile, $tableCharsetAndCollationFile, $foreignStructureFile, $hasForeign) 101 | { 102 | $this->tableName = $tableName; 103 | $this->structureFile = $structureFile; 104 | $this->keysFile = $keysFile; 105 | $this->constraintsFile = $constraintsFile; 106 | $this->tableCharsetAndCollationFile = $tableCharsetAndCollationFile; 107 | $this->foreignStructureFile = $foreignStructureFile; 108 | $this->hasForeign = $hasForeign; 109 | } 110 | 111 | public function makeMigration() 112 | { 113 | $this->buildTableCollationAndCharset(); 114 | $this->buildStructure(); 115 | $this->buildKeys(); 116 | $this->buildConstraints(); 117 | 118 | $indent8 = str_repeat(' ', 8); 119 | $indent12 = str_repeat(' ', 12); 120 | $eol = "\n"; 121 | 122 | $structure = trim(implode($eol . $indent12, $this->formatStructure())) . $eol; 123 | $keys = trim(implode($eol . $indent12, $this->formatKeys())) . $eol; 124 | $constraints = trim(implode($eol . $indent12, $this->formatConstraints())) . $eol; 125 | $tableCollationAndCharset = trim(implode($eol . $indent12, $this->formatTableCollationAndCharset())) . $eol; 126 | $extras = trim(implode($eol . $indent8, $this->formatExtras())) . $eol; 127 | 128 | if ($this->hasForeign === "true") { 129 | $foreign = trim(implode($eol . $indent12, $this->formatForeign())) . $eol; 130 | $foreignDrop = trim(implode($eol . $indent12, $this->formatForeignDrop())) . $eol; 131 | $className = 'AddForeignKeyTo' . $this->studly($this->tableName) . 'Table'; 132 | $output = file_get_contents(__DIR__ . '/foreign_key.stub'); 133 | $output = str_replace( 134 | [ 135 | ':VERSION:', 136 | 'DummyClass', 137 | 'DummyTable', 138 | "// foreign\n", 139 | "// foreignDrop\n", 140 | ], 141 | [ 142 | $this->version, 143 | $className, 144 | $this->tableName, 145 | $foreign, 146 | $foreignDrop, 147 | ], 148 | $output 149 | ); 150 | } else { 151 | $className = 'Create' . $this->studly($this->tableName) . 'Table'; 152 | $output = file_get_contents(__DIR__ . '/create.stub'); 153 | $output = str_replace( 154 | [ 155 | ':VERSION:', 156 | 'DummyClass', 157 | 'DummyTable', 158 | "// structure\n", 159 | "// keys\n", 160 | "// constraints\n", 161 | "// tableCollationAndCharset\n", 162 | "// extras\n", 163 | ], 164 | [ 165 | $this->version, 166 | $className, 167 | $this->tableName, 168 | $structure, 169 | $keys, 170 | $constraints, 171 | $tableCollationAndCharset, 172 | $extras, 173 | ], 174 | $output 175 | ); 176 | } 177 | 178 | 179 | $output = preg_replace("/^(\s*\R){2,}/m", "\n", $output); 180 | 181 | return $output; 182 | } 183 | 184 | public function formatForeign() 185 | { 186 | $fields = []; 187 | 188 | $rows = file($this->foreignStructureFile); 189 | array_shift($rows); 190 | 191 | foreach ($rows as $row) { 192 | list($table, $colName, $constName, $refTable, $refColumnName) = explode("\t", 193 | $row, 5); 194 | $fields[] = '$table->foreign(\''. trim($colName) .'\')->references(\''. trim($refColumnName) .'\')->on(\''. trim($refTable) .'\');'; 195 | } 196 | return array_filter($fields); 197 | } 198 | 199 | public function formatForeignDrop() 200 | { 201 | $fields = []; 202 | 203 | $rows = file($this->foreignStructureFile); 204 | array_shift($rows); 205 | 206 | foreach ($rows as $row) { 207 | list($table, $colName, $constName, $refTable, $refColumnName) = explode("\t", 208 | $row, 5); 209 | $fields[] = '$table->dropForeign(\''. trim($table) .'_'. trim($colName) .'_foreign\');'; 210 | } 211 | return array_filter($fields); 212 | } 213 | 214 | protected function studly($value) 215 | { 216 | $value = ucwords(str_replace(['-', '_'], ' ', $value)); 217 | 218 | return str_replace(' ', '', $value); 219 | } 220 | 221 | public function buildStructure() 222 | { 223 | $this->structure = []; 224 | 225 | $rows = file($this->structureFile); 226 | array_shift($rows); 227 | 228 | foreach ($rows as $row) { 229 | 230 | list($field, $colType, $null, $key, $default, $characterSet, $collation, $extra, $comment) = explode("\t", 231 | $row); 232 | 233 | if (preg_match('#^(\w+)(\((.*?)\))?(.*?)?$#', $colType, $matches)) { 234 | 235 | $type = strtolower($matches[1]); 236 | $args = $matches[3] ?: null; 237 | $typeExtra = trim($matches[4]) ?: null; 238 | 239 | if (strpos($args, ',') === false) { 240 | $args = $args ?: null; 241 | } else { 242 | $args = explode(',', $args); 243 | } 244 | 245 | $data = [ 246 | 'field' => $field, 247 | 'nullable' => ($null === 'YES'), 248 | 'default' => ($default !== 'NULL') ? $default : null, 249 | 'characterSet' => ($characterSet !== 'NULL' && $characterSet !== $this->tableCharset) ? $characterSet : null, 250 | 'collation' => ($collation !== 'NULL' && $collation !== $this->tableCollation) ? $collation : null, 251 | '_colType' => $colType, 252 | ]; 253 | 254 | $method = 'parse' . ucfirst($type); 255 | 256 | if (method_exists($this, $method)) { 257 | $data = array_merge( 258 | $data, 259 | $this->{$method}($type, $args, $typeExtra, $extra) 260 | ); 261 | } else { 262 | $data['method'] = 'UNKNOWN:' . $type; 263 | } 264 | 265 | $data['comment'] = trim(str_replace(["\r", "\n"], '', $comment)); 266 | if ($data['comment']==='') { 267 | $data['comment'] = null; 268 | } 269 | 270 | $this->structure[$field] = $data; 271 | } 272 | } 273 | 274 | // look for softDeletes 275 | if ( 276 | array_key_exists('deleted_at', $this->structure) 277 | && $this->structure['deleted_at']['method'] === 'timestamp' 278 | ) { 279 | $this->structure['deleted_at']['method'] = 'softDeletes'; 280 | $this->structure['deleted_at']['args'] = null; 281 | $this->structure['deleted_at']['default'] = null; 282 | $this->structure['deleted_at']['nullable'] = false; 283 | $this->structure['deleted_at']['field'] = null; 284 | } 285 | 286 | // look for timestamps 287 | if ( 288 | array_key_exists('created_at', $this->structure) 289 | && $this->structure['created_at']['method'] === 'timestamp' 290 | && array_key_exists('updated_at', $this->structure) 291 | && $this->structure['updated_at']['method'] === 'timestamp' 292 | ) { 293 | unset($this->structure['updated_at']); 294 | $method = $this->structure['created_at']['nullable'] ? 'nullableTimestamps' : 'timestamps'; 295 | $this->structure['created_at']['method'] = $method; 296 | $this->structure['created_at']['args'] = null; 297 | $this->structure['created_at']['default'] = null; 298 | $this->structure['created_at']['nullable'] = false; 299 | $this->structure['created_at']['field'] = null; 300 | } 301 | 302 | // look for rememberToken 303 | if ( 304 | array_key_exists('remember_token', $this->structure) 305 | && $this->structure['remember_token']['method'] === 'string' 306 | && $this->structure['remember_token']['nullable'] === true 307 | && $this->structure['remember_token']['args'] === '100' 308 | ) { 309 | $this->structure['remember_token']['method'] = 'rememberToken'; 310 | $this->structure['remember_token']['args'] = null; 311 | $this->structure['remember_token']['default'] = null; 312 | $this->structure['remember_token']['nullable'] = false; 313 | $this->structure['remember_token']['field'] = null; 314 | } 315 | 316 | // look for id 317 | foreach ($this->structure as $field=>$struct) { 318 | if ( 319 | $struct['method'] === 'bigInteger' 320 | && $struct['autoIncrement'] === true 321 | && $struct['args'] === null 322 | ) { 323 | $this->structure[$field]['method'] = 'id'; 324 | $this->structure[$field]['args'] = null; 325 | $this->structure[$field]['default'] = null; 326 | $this->structure[$field]['nullable'] = false; 327 | $this->structure[$field]['autoIncrement'] = null; 328 | $this->structure[$field]['unsigned'] = null; 329 | if ($field==='id') { 330 | $this->structure[$field]['field'] = null; 331 | } 332 | } 333 | } 334 | } 335 | 336 | public function formatStructure() 337 | { 338 | $fields = []; 339 | foreach ($this->structure as $field => $data) { 340 | 341 | $method = $data['method']; 342 | $isNumeric = $this->isNumeric($method); 343 | $isInteger = $this->isInteger($method); 344 | 345 | if ($isInteger) { 346 | if ($data['autoIncrement']) { 347 | $method = str_replace('nteger', 'ncrements', $method); 348 | } elseif ($data['unsigned']) { 349 | $method = 'unsigned' . ucfirst($method); 350 | } 351 | } 352 | 353 | if ($method === 'timestamp' && $data['args'] === self::TS_UPDATE_STRING) { 354 | $data['default'] .= ' ' . $data['args']; 355 | $data['args'] = null; 356 | } 357 | 358 | $temp = '$table->' . $method; 359 | if ($data['field']) { 360 | $temp .= '(\'' . $field . '\''; 361 | if ($method === 'enum' || $method === 'set') { 362 | $temp .= ', [' . implode(', ', (array) $data['args']) . '])'; 363 | } elseif ($data['args']) { 364 | $temp .= ', ' . implode(', ', (array) $data['args']) . ')'; 365 | } else { 366 | $temp .= ')'; 367 | } 368 | } else { 369 | $temp .= '()'; 370 | } 371 | if (!$isInteger) { 372 | if ($data['autoIncrement']) { 373 | $temp .= '->autoIncrement()'; 374 | } 375 | if ($data['unsigned']) { 376 | $temp .= '->unsigned()'; 377 | } 378 | } 379 | if ($data['nullable']) { 380 | $temp .= '->nullable()'; 381 | } 382 | if ($data['characterSet']) { 383 | $temp .= "->charset('" . $data['characterSet'] . "')"; 384 | } 385 | if ($data['collation']) { 386 | $temp .= "->collation('" . $data['collation'] . "')"; 387 | } 388 | if (isset($data['default'])) { 389 | if ($isNumeric || (($method === 'enum' || $method === 'set') && is_numeric($data['default']))) { 390 | $temp .= '->default(' . $data['default'] . ')'; 391 | } elseif ($method === 'boolean') { 392 | $temp .= '->default(' . ($data['default'] ? 'true' : 'false') . ')'; 393 | } elseif (stripos(trim($data['default']), 'CURRENT_TIMESTAMP') !== false) { 394 | $temp .= '->default(\DB::raw(\'' . trim($data['default']) . '\'))'; 395 | } else { 396 | $temp .= '->default(\'' . $this->trimStringQuotes($data['default']) . '\')'; 397 | } 398 | } 399 | 400 | // If isn't empty, set the comment 401 | if ($data['comment'] !== null) { 402 | $temp .= '->comment(\'' . addslashes($data['comment']) . '\')'; 403 | } 404 | 405 | $fields[$field] = $temp . ';'; 406 | } 407 | 408 | return array_filter($fields); 409 | } 410 | 411 | public function buildKeys() 412 | { 413 | $this->keys = []; 414 | 415 | $rows = file($this->keysFile); 416 | array_shift($rows); 417 | 418 | foreach ($rows as $row) { 419 | list($table, $nonUnique, $keyName, $seq, $colName, $collation, $cardinality, $subPart, $packed, $null, $indexType, $extra) = explode("\t", 420 | $row, 12); 421 | 422 | if ($indexType === 'FULLTEXT') { 423 | if (!array_key_exists($keyName, $this->extras)) { 424 | $this->extras[$keyName] = [ 425 | 'method' => 'fulltext', 426 | 'table' => $table, 427 | 'columns' => [], 428 | ]; 429 | $this->extras[$keyName]['columns'][$seq] = $colName; 430 | } 431 | } else { 432 | if (!array_key_exists($keyName, $this->keys)) { 433 | $this->keys[$keyName] = [ 434 | 'method' => $nonUnique ? 'index' : 'unique', 435 | 'table' => $table, 436 | 'columns' => [], 437 | ]; 438 | } 439 | $this->keys[$keyName]['columns'][$seq] = $colName; 440 | } 441 | } 442 | 443 | // if we have a primary key ... 444 | if (array_key_exists('PRIMARY', $this->keys)) { 445 | $primary = $this->keys['PRIMARY']; 446 | // and it's for one columns ... 447 | if (count($primary['columns']) === 1) { 448 | $primaryColumn = reset($primary['columns']); 449 | $field = $this->structure[$primaryColumn]; 450 | // and that column is an "increments" field ... 451 | if (isset($field['args']['autoIncrement']) && $field['args']['autoIncrement'] === 'true') { 452 | // then don't build the primary key, since Laravel takes care of it 453 | unset($this->keys['PRIMARY']); 454 | } 455 | } 456 | } 457 | } 458 | 459 | public function formatKeys() 460 | { 461 | $fields = []; 462 | 463 | foreach ($this->keys as $field => $data) { 464 | $columns = $this->escapeArray($data['columns']); 465 | 466 | if ($field === 'PRIMARY') { 467 | //$fields[$field] = sprintf('$table->primary(%s);', $columns); 468 | } else { 469 | $fields[$field] = sprintf('$table->%s(%s, \'%s\');', 470 | $data['method'], 471 | $columns, 472 | $field 473 | ); 474 | } 475 | } 476 | 477 | return array_filter($fields); 478 | } 479 | 480 | public function formatExtras() 481 | { 482 | $fields = []; 483 | 484 | foreach ($this->extras as $field => $data) { 485 | if ($data['method'] === 'fulltext') { 486 | $columns = $this->escapeColumnList($data['columns']); 487 | $fields[$field] = sprintf('\\DB::statement("ALTER TABLE `%s` ADD FULLTEXT INDEX `%s` (%s)");', 488 | $data['table'], 489 | $field, 490 | $columns 491 | ); 492 | } 493 | } 494 | 495 | return array_filter($fields); 496 | } 497 | 498 | public function buildConstraints() 499 | { 500 | $this->constraints = []; 501 | 502 | $rows = file($this->constraintsFile); 503 | array_shift($rows); 504 | 505 | foreach ($rows as $row) { 506 | $row = preg_replace('/\n+$/', '', $row); 507 | list($constraint, $colName, $refTable, $refColumn, $updateRule, $deleteRule) = explode("\t", $row); 508 | 509 | if (array_key_exists($constraint, $this->keys)) { 510 | unset($this->keys[$constraint]); 511 | } 512 | 513 | $this->constraints[$constraint][] = compact('colName', 'refTable', 'refColumn', 'updateRule', 'deleteRule'); 514 | } 515 | } 516 | 517 | public function formatConstraints() 518 | { 519 | $fields = []; 520 | foreach ($this->constraints as $field => $data) { 521 | $colNames = $this->escapeArray(array_map(function($entry) { return $entry['colName']; }, $data)); 522 | $refColumns = $this->escapeArray(array_map(function($entry) { return $entry['refColumn']; }, $data)); 523 | $temp = '$table->foreign(' . $colNames . ', \'' . $field . '\')' . 524 | '->references(' . $refColumns . ')' . 525 | '->on(\'' . $data[0]['refTable'] . '\')' . 526 | '->onDelete(\'' . $data[0]['deleteRule'] . '\')' . 527 | '->onUpdate(\'' . $data[0]['updateRule'] . '\')'; 528 | 529 | $fields[$field] = $temp . ';'; 530 | } 531 | 532 | return array_filter($fields); 533 | } 534 | 535 | public function buildTableCollationAndCharset() 536 | { 537 | $this->constraints = []; 538 | 539 | $rows = file($this->tableCharsetAndCollationFile); 540 | array_shift($rows); 541 | 542 | if (!empty($rows)) { 543 | $row = array_shift($rows); 544 | $row = preg_replace('/\n+$/', '', $row); 545 | list($this->tableCharset, $this->tableCollation) = explode("\t", $row); 546 | } 547 | } 548 | 549 | public function formatTableCollationAndCharset() 550 | { 551 | $output = []; 552 | 553 | if ($this->tableCharset) { 554 | $output[] = '$table->charset = \'' . $this->tableCharset . "';"; 555 | } 556 | 557 | if ($this->tableCollation) { 558 | $output[] = '$table->collation = \'' . $this->tableCollation . "';"; 559 | } 560 | 561 | return $output; 562 | } 563 | 564 | protected function copyToClipboard($content) 565 | { 566 | $cmd = 'echo ' . escapeshellarg($content) . ' | __CF_USER_TEXT_ENCODING=' . posix_getuid() . ':0x8000100:0x8000100 pbcopy'; 567 | shell_exec($cmd); 568 | } 569 | 570 | protected function escapeArray($array) 571 | { 572 | $array = (array) $array; 573 | array_walk($array, function(&$value, $idx) { 574 | if (!is_numeric($value)) { 575 | $value = '\'' . str_replace('\'', '\\\'', $value) . '\''; 576 | } 577 | }); 578 | 579 | $string = implode(', ', $array); 580 | 581 | if (count($array) > 1) { 582 | return '[' . $string . ']'; 583 | } 584 | 585 | return $string; 586 | } 587 | 588 | protected function escapeColumnList($array) 589 | { 590 | $array = (array) $array; 591 | array_walk($array, function(&$value, $idx) { 592 | $value = '`' . $value . '`'; 593 | }); 594 | 595 | return implode(', ', $array); 596 | } 597 | 598 | // protected function getAutoIncrementArgument($extra) 599 | // { 600 | // $arguments = [ 601 | // 'autoIncrement' => false, 602 | // ]; 603 | // 604 | // if (strpos($extra, 'auto_increment') !== false) { 605 | // $arguments['autoIncrement'] = true; 606 | // } 607 | // 608 | // return $arguments; 609 | // } 610 | // 611 | 612 | protected function isAutoIncrement($extra) 613 | { 614 | return strpos($extra, 'auto_increment') !== false; 615 | } 616 | 617 | // protected function getUnsignedArgument($typeExtra) 618 | // { 619 | // $arguments = [ 620 | // 'unsigned' => false 621 | // ]; 622 | // 623 | // if (strpos($typeExtra, 'unsigned') !== false) { 624 | // $arguments['unsigned'] = true; 625 | // } 626 | // 627 | // return $arguments; 628 | // } 629 | 630 | protected function isUnsigned($typeExtra) 631 | { 632 | return strpos($typeExtra, 'unsigned') !== false; 633 | } 634 | 635 | protected function parseInt($type, $args, $typeExtra, $extra) 636 | { 637 | return [ 638 | 'method' => $this->integerMaps[$type], 639 | 'args' => null, 640 | 'autoIncrement' => $this->isAutoIncrement($extra), 641 | 'unsigned' => $this->isUnsigned($typeExtra), 642 | ]; 643 | } 644 | 645 | protected function parseBigint($type, $args, $typeExtra, $extra) 646 | { 647 | return $this->parseInt($type, $args, $typeExtra, $extra); 648 | } 649 | 650 | protected function parseMediumint($type, $args, $typeExtra, $extra) 651 | { 652 | return $this->parseInt($type, $args, $typeExtra, $extra); 653 | } 654 | 655 | protected function parseSmallint($type, $args, $typeExtra, $extra) 656 | { 657 | return $this->parseInt($type, $args, $typeExtra, $extra); 658 | } 659 | 660 | protected function parseTinyint($type, $args, $typeExtra, $extra) 661 | { 662 | if ($args === 1) { 663 | $method = 'boolean'; 664 | $args = null; 665 | $unsigned = false; 666 | 667 | return compact('method', 'args', 'unsigned'); 668 | } 669 | 670 | return $this->parseInt($type, $args, $typeExtra, $extra); 671 | } 672 | 673 | protected function parseBlob($type, $args, $typeExtra, $extra) 674 | { 675 | return $this->defaultParse('binary', $args); 676 | } 677 | 678 | protected function parseChar($type, $args, $typeExtra, $extra) 679 | { 680 | return $this->defaultParse('char', $args); 681 | } 682 | 683 | protected function parseDate($type, $args, $typeExtra, $extra) 684 | { 685 | return $this->defaultParse('date'); 686 | } 687 | 688 | protected function parseDatetime($type, $args, $typeExtra, $extra) 689 | { 690 | return $this->defaultParse('dateTime'); 691 | } 692 | 693 | protected function parseDecimal($type, $args, $typeExtra, $extra) 694 | { 695 | return [ 696 | 'method' => 'decimal', 697 | 'args' => $args, 698 | 'unsigned' => $this->isUnsigned($typeExtra), 699 | ]; 700 | } 701 | 702 | protected function parseNumeric($type, $args, $typeExtra, $extra) 703 | { 704 | return $this->parseDecimal($type, $args, $typeExtra, $extra); 705 | } 706 | 707 | protected function parseFixed($type, $args, $typeExtra, $extra) 708 | { 709 | return $this->parseDecimal($type, $args, $typeExtra, $extra); 710 | } 711 | 712 | protected function parseDouble($type, $args, $typeExtra, $extra) 713 | { 714 | return [ 715 | 'method' => 'double', 716 | 'args' => $args, 717 | 'unsigned' => $this->isUnsigned($typeExtra), 718 | ]; 719 | } 720 | 721 | protected function parseDoublePrecision($type, $args, $typeExtra, $extra) 722 | { 723 | return $this->parseDouble($type, $args, $typeExtra, $extra); 724 | } 725 | 726 | protected function parseReal($type, $args, $typeExtra, $extra) 727 | { 728 | return $this->parseDouble($type, $args, $typeExtra, $extra); 729 | } 730 | 731 | protected function parseFloat($type, $args, $typeExtra, $extra) 732 | { 733 | return [ 734 | 'method' => 'float', 735 | 'args' => $args, 736 | 'unsigned' => $this->isUnsigned($typeExtra), 737 | ]; 738 | } 739 | 740 | protected function parseLongtext($type, $args, $typeExtra, $extra) 741 | { 742 | return $this->defaultParse('longText', $args); 743 | } 744 | 745 | protected function parseMediumtext($type, $args, $typeExtra, $extra) 746 | { 747 | return $this->defaultParse('mediumText', $args); 748 | } 749 | 750 | protected function parseTinytext($type, $args, $typeExtra, $extra) 751 | { 752 | return $this->defaultParse('tinyText', $args); 753 | } 754 | 755 | protected function parseText($type, $args, $typeExtra, $extra) 756 | { 757 | return $this->defaultParse('text', $args); 758 | } 759 | 760 | protected function parseVarchar($type, $args, $typeExtra, $extra) 761 | { 762 | return $this->defaultParse('string', $args); 763 | } 764 | 765 | protected function parseEnum($type, $args, $typeExtra, $extra) 766 | { 767 | return $this->defaultParse('enum', $args); 768 | } 769 | 770 | protected function parseSet($type, $args, $typeExtra, $extra) 771 | { 772 | return $this->defaultParse('set', $args); 773 | } 774 | 775 | protected function parseTime($type, $args, $typeExtra, $extra) 776 | { 777 | return $this->defaultParse('time', $args); 778 | } 779 | 780 | protected function parseTimestamp($type, $args, $typeExtra, $extra) 781 | { 782 | if (stripos($extra, self::TS_UPDATE_STRING) !== false) { 783 | $args = self::TS_UPDATE_STRING; 784 | } 785 | return $this->defaultParse('timestamp', $args); 786 | } 787 | 788 | protected function parseJson($type, $args, $typeExtra, $extra) 789 | { 790 | return $this->defaultParse('json', $args); 791 | } 792 | 793 | private function defaultParse($method, $args = null) 794 | { 795 | return compact('method', 'args'); 796 | } 797 | 798 | private function trimStringQuotes($string) 799 | { 800 | return trim( 801 | trim($string, '"\'') 802 | ); 803 | } 804 | 805 | private function isInteger($method) 806 | { 807 | return stripos($method, 'integer') !== false; 808 | } 809 | 810 | private function isNumeric($method) 811 | { 812 | return $this->isInteger($method) 813 | || $method === 'decimal' 814 | || $method === 'double' 815 | || $method === 'float' 816 | || $method === 'real'; 817 | } 818 | } 819 | --------------------------------------------------------------------------------