├── .github └── workflows │ └── php.yml ├── .gitignore ├── .readthedocs.yml ├── .travis.yml ├── README.md ├── build-library.bash ├── build.sh ├── build.xml ├── composer.json ├── composer.lock ├── docs ├── .gitignore ├── dev-internals-build.md ├── dev-internals-enviornment.md ├── dev-internals-introduction.md ├── dev-internals-pestle-import.md ├── extra.css ├── index.md ├── magento2-composer.md ├── magento2-database.md ├── magento2-di-observers.md ├── magento2-generate-acl.md ├── magento2-generate-full-module.md ├── magento2-generate-ui.md ├── magento2-introduction.md ├── magento2-module-setup.md ├── magento2-mvc.md ├── magento2-other-introduction.md ├── magento2-other-other.md ├── magento2-others.md ├── magento2-quick-conversions.md ├── magento2-scans-and-reports.md ├── pestle-generate.md ├── pestle-io.md └── pestle-third-party.md ├── gen-event-list.sh ├── library ├── all.php └── autoload.php ├── license.txt ├── mkdocs.yml ├── modules └── pulsestorm │ ├── alanstormdotcom │ └── rsync │ │ └── module.php │ ├── cli │ ├── ascii_table │ │ └── module.php │ ├── build_command_list │ │ └── module.php │ ├── code_generation │ │ └── module.php │ ├── format_php │ │ └── module.php │ ├── md_to_say │ │ └── module.php │ ├── monty_hall_problem │ │ └── module.php │ ├── self_update │ │ └── module.php │ └── token_parse │ │ └── module.php │ ├── faker │ └── names │ │ └── module.php │ ├── financial │ └── parse_citicard │ │ └── module.php │ ├── generate │ └── pestle │ │ └── command │ │ └── module.php │ ├── gs │ └── combine │ │ └── module.php │ ├── magento1 │ └── convert │ │ ├── generatemaps │ │ └── module.php │ │ ├── magentoinc │ │ └── module.php │ │ └── unirgy │ │ └── module.php │ ├── magento2 │ ├── cli │ │ ├── base_directory │ │ │ └── module.php │ │ ├── baz_bar │ │ │ ├── Baz_Bar │ │ │ └── module.php │ │ ├── check_acl │ │ │ └── module.php │ │ ├── check_class_and_namespace │ │ │ └── module.php │ │ ├── check_htaccess │ │ │ └── module.php │ │ ├── check_registration │ │ │ └── module.php │ │ ├── check_templates │ │ │ └── module.php │ │ ├── class_from_path │ │ │ └── module.php │ │ ├── class_list │ │ │ └── module.php │ │ ├── convert_class │ │ │ └── module.php │ │ ├── convert_observers_xml │ │ │ └── module.php │ │ ├── convert_selenium_id_for_codecept │ │ │ └── module.php │ │ ├── convert_system_xml │ │ │ └── module.php │ │ ├── dev_import │ │ │ └── module.php │ │ ├── dev_namespace │ │ │ └── module.php │ │ ├── export_module │ │ │ └── module.php │ │ ├── extract_mage2_system_xml_paths │ │ │ └── module.php │ │ ├── extract_session │ │ │ └── module.php │ │ ├── fix_direct_om │ │ │ └── module.php │ │ ├── fix_permissions_modphp │ │ │ └── module.php │ │ ├── foo_bar │ │ │ └── module.php │ │ ├── format_xml_string │ │ │ └── module.php │ │ ├── generate │ │ │ ├── acl │ │ │ │ └── module.php │ │ │ ├── command │ │ │ │ └── module.php │ │ │ ├── config_helper │ │ │ │ └── module.php │ │ │ ├── crud │ │ │ │ └── model │ │ │ │ │ └── module.php │ │ │ ├── di │ │ │ │ └── module.php │ │ │ ├── install │ │ │ │ └── module.php │ │ │ ├── layout_xml │ │ │ │ └── module.php │ │ │ ├── mage2_command │ │ │ │ └── module.php │ │ │ ├── menu │ │ │ │ └── module.php │ │ │ ├── module │ │ │ │ └── module.php │ │ │ ├── observer │ │ │ │ └── module.php │ │ │ ├── plugin_xml │ │ │ │ └── module.php │ │ │ ├── psr_log_level │ │ │ │ └── module.php │ │ │ ├── registration │ │ │ │ └── module.php │ │ │ ├── route │ │ │ │ └── module.php │ │ │ ├── theme │ │ │ │ └── module.php │ │ │ └── view │ │ │ │ └── module.php │ │ ├── hello_argument │ │ │ └── module.php │ │ ├── hello_world │ │ │ └── module.php │ │ ├── help │ │ │ └── module.php │ │ ├── library │ │ │ └── module.php │ │ ├── list_commands │ │ │ └── module.php │ │ ├── magento2 │ │ │ └── generate │ │ │ │ ├── acl │ │ │ │ ├── change_title │ │ │ │ │ └── module.php │ │ │ │ └── module.php │ │ │ │ ├── command │ │ │ │ └── module.php │ │ │ │ ├── config_helper │ │ │ │ └── module.php │ │ │ │ ├── controller_edit_acl │ │ │ │ └── module.php │ │ │ │ ├── crud_model │ │ │ │ └── module.php │ │ │ │ ├── di │ │ │ │ └── module.php │ │ │ │ ├── full_module │ │ │ │ └── module.php │ │ │ │ ├── install │ │ │ │ └── module.php │ │ │ │ ├── menu │ │ │ │ └── module.php │ │ │ │ ├── module │ │ │ │ └── module.php │ │ │ │ ├── observer │ │ │ │ └── module.php │ │ │ │ ├── plugin_xml │ │ │ │ └── module.php │ │ │ │ ├── preference │ │ │ │ └── module.php │ │ │ │ ├── psr_log_level │ │ │ │ └── module.php │ │ │ │ ├── registration │ │ │ │ └── module.php │ │ │ │ ├── route │ │ │ │ └── module.php │ │ │ │ ├── theme │ │ │ │ └── module.php │ │ │ │ ├── ui │ │ │ │ ├── add-column-actions │ │ │ │ │ └── module.php │ │ │ │ ├── add-column-sections │ │ │ │ │ └── module.php │ │ │ │ ├── add_to_layout │ │ │ │ │ └── module.php │ │ │ │ ├── form │ │ │ │ │ └── module.php │ │ │ │ └── grid │ │ │ │ │ └── module.php │ │ │ │ └── view │ │ │ │ └── module.php │ │ ├── orphan_content │ │ │ └── module.php │ │ ├── pandoc_md │ │ │ └── module.php │ │ ├── path_from_class │ │ │ └── module.php │ │ ├── pestle_clear_cache │ │ │ └── module.php │ │ ├── read_rest_schema │ │ │ └── module.php │ │ ├── search_controllers │ │ │ └── module.php │ │ ├── test_namespace_integrity │ │ │ └── module.php │ │ ├── test_output │ │ │ └── module.php │ │ ├── testbed │ │ │ └── module.php │ │ └── xml_template │ │ │ └── module.php │ ├── codemigration │ │ └── rename │ │ │ └── module.php │ └── generate │ │ ├── classchild │ │ └── module.php │ │ ├── registerpackage │ │ └── module.php │ │ ├── remove_named_node │ │ └── module.php │ │ ├── schemaaddcolumn │ │ └── module.php │ │ ├── schemaupgrade │ │ └── module.php │ │ ├── servicecontract │ │ └── module.php │ │ └── ui │ │ ├── addcolumntext │ │ └── module.php │ │ ├── addformfield │ │ └── module.php │ │ ├── addformfieldset │ │ └── module.php │ │ └── addschemacolumn │ │ └── module.php │ ├── mysql │ └── keycheck │ │ └── module.php │ ├── nexmo │ ├── sendtext │ │ └── module.php │ ├── storecredentials │ │ └── module.php │ ├── verifyrequest │ │ └── module.php │ └── verifysendcode │ │ └── module.php │ ├── nofrills │ └── build_book │ │ └── module.php │ ├── paypal │ └── csv_to_iif │ │ └── module.php │ ├── pestle │ ├── clear_cache │ │ └── module.php │ ├── config │ │ └── module.php │ ├── exportassymfony │ │ └── module.php │ ├── importer │ │ └── module.php │ ├── library │ │ └── module.php │ ├── run_file │ │ └── module.php │ ├── runner │ │ └── module.php │ └── version │ │ └── module.php │ ├── phpdotnet │ └── module.php │ ├── postscript │ └── check │ │ └── module.php │ ├── solonoble │ └── module.php │ └── xml_library │ └── module.php ├── pestle-autocomplete.sh ├── pestle_dev ├── phar-stub.php ├── phar.readonly.ini ├── runner.php ├── tests-integration ├── GenerateModuleTest.php ├── GenerateRouteTest.php ├── HelloWorldTest.php └── PestleTestIntegration.php ├── tests ├── AdminClassNameTest.php ├── AppCodeRefactorTest.php ├── ArgumentParsingTest.php ├── ClassParsingTest.php ├── CommandExistsTest.php ├── ComposerPackageTest.php ├── ConfigTest.php ├── DoubleImportTest.php ├── FirstTest.php ├── FunctionNameParsingTest.php ├── GenerateInstallSchemaTest.php ├── GenerateMage2CommandTest.php ├── GenerateRouteTest.php ├── GenerateWithColonTest.php ├── LibraryTest.php ├── NamespaceRefactoringTest.php ├── PestleBaseTest.php ├── PhpCollideTest.php ├── PostAppCodeRefactorTest.php ├── RunnerTestHarnessTest.php ├── SimpleXmlAddNodesXpathTest.php ├── WindowsTest.php └── fixtures │ ├── AdminClassName │ ├── BaseAdminArgs.php │ └── BaseFrontendArgs.php │ └── FunctionNameParsing │ ├── Application.php │ ├── Command.php │ ├── ConfirmableTrait.php │ ├── DetectsApplicationNamespace.php │ ├── GeneratorCommand.php │ ├── OutputStyle.php │ └── Parser.php └── travis ├── for-lint.sh └── travis-ci-apache /.github/workflows/php.yml: -------------------------------------------------------------------------------- 1 | name: PHP Composer 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v2 16 | - uses: shivammathur/setup-php@master 17 | with: 18 | php-version: '7.4' 19 | 20 | - name: Validate composer.json and composer.lock 21 | run: composer validate 22 | 23 | - name: Cache Composer packages 24 | id: composer-cache 25 | uses: actions/cache@v2 26 | with: 27 | path: vendor 28 | key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }} 29 | restore-keys: | 30 | ${{ runner.os }}-php- 31 | 32 | - name: Install dependencies 33 | if: steps.composer-cache.outputs.cache-hit != 'true' 34 | run: composer install --prefer-dist --no-progress --no-suggest 35 | 36 | # Add a test script to composer.json, for instance: "test": "vendor/bin/phpunit" 37 | # Docs: https://getcomposer.org/doc/articles/scripts.md 38 | 39 | - name: Run test suite 40 | run: vendor/bin/phpunit tests 41 | 42 | - name: Run PHP version 43 | run: php --version 44 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | vendor/ 2 | .DS_Store 3 | build/ 4 | pestle.phar 5 | build2.sh 6 | test.php 7 | .idea 8 | .vscode 9 | modules/pulsestorm/parsing 10 | tags 11 | site/ 12 | -------------------------------------------------------------------------------- /.readthedocs.yml: -------------------------------------------------------------------------------- 1 | # .readthedocs.yml 2 | # Read the Docs configuration file 3 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 4 | 5 | # Required 6 | version: 2 7 | 8 | # Build documentation in the docs/ directory with Sphinx 9 | #sphinx: 10 | # configuration: docs/conf.py 11 | 12 | # Build documentation with MkDocs 13 | mkdocs: 14 | configuration: mkdocs.yml 15 | -------------------------------------------------------------------------------- /build-library.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | VER_FROM_TAG=`git tag | tail -n 1 | xargs echo 'pestle Ver'` 3 | VER_FROM_PESTLE=`pestle_dev version` 4 | 5 | #if [ "$VER_FROM_TAG" != "$VER_FROM_PESTLE" ] 6 | #then 7 | # echo "pestle version and latest tag do not match, bailing" 8 | # exit 9 | #fi 10 | 11 | echo " library/all.php 12 | find modules/ -name module.php | xargs pestle_dev pestle:export_module >> library/all.php -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | VER_FROM_TAG=`git tag | tail -n 1 | xargs echo 'pestle Ver'` 4 | VER_FROM_PESTLE=`php pestle_dev version` 5 | 6 | if [ "$VER_FROM_TAG" != "$VER_FROM_PESTLE" ] 7 | then 8 | echo "pestle version and latest tag do not match, bailing" 9 | exit 10 | fi 11 | 12 | php -d phar.readonly=0 vendor/bin/phing package_phar 13 | chmod +x pestle.phar 14 | #mv pestle.phar ~/bin/pestle.phar 15 | -------------------------------------------------------------------------------- /build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pulsestorm/pestle", 3 | "description":"A CLI framework for module based PHP code. Also has numerous Magento 2 code generation commands. ", 4 | "require": { 5 | "michelf/php-markdown": "1.6.0", 6 | "ext-xml": "*", 7 | "abraham/twitteroauth": "0.7.2", 8 | "fzaninotto/faker": "^1.6.0", 9 | "nexmo/client":"@beta", 10 | "pear/numbers_words":"0.18.1" 11 | }, 12 | 13 | "require-dev": { 14 | "phpunit/phpunit": "^6.5", 15 | "phing/phing": "2.*", 16 | "phpspec/prophecy":"1.7.0", 17 | "magento/magento-coding-standard": "^4.0" 18 | }, 19 | "autoload": { 20 | "files": ["library/autoload.php"] 21 | }, 22 | "license": "MIT", 23 | "scripts":{ 24 | "test":"php vendor/bin/phpunit tests" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | site/ 2 | -------------------------------------------------------------------------------- /docs/dev-internals-build.md: -------------------------------------------------------------------------------- 1 | ## Building Pestle 2 | 3 | Alright! You've made your changes and you're ready to do some end-to-end testing. In other words, you want to build pestle's `.phar` file and see if your stuff actually works. 4 | 5 | Pestle uses the [venerable phing build tool](https://www.phing.info/) to create its `phar` file. Unfortunately, when PHP started shipping with the ini setting `phar.readonly` set to `1`, they semi-broke our build system. In order to build a `.phar`, you'll need to invoke `phing` with the following. 6 | 7 | ``` 8 | $ php -d phar.readonly=0 vendor/bin/phing package_phar 9 | ``` 10 | 11 | This uses the PHP `-d` command line option to set the `phar.readonly=0` value to zero, and then invokes the `package_phar` build step. 12 | 13 | Once this command finishes running, you should have a brand new `pestle.phar` in your root project directory. 14 | 15 | ``` 16 | $ ls pestle.phar 17 | pestle.phar 18 | ``` 19 | 20 | ## Build a Release 21 | 22 | Right now the release process is only semi-automated. We're [working towards 100% automation](https://github.com/astorm/pestle/issues/472), but something something cobbler's children. 23 | 24 | To build a release, we 25 | 26 | 1. Create a fresh clone of the repo 27 | 2. Run `composer install` 28 | 3. Update the version string in `modules/pulsestorm/pestle/importer/module.php` 29 | 4. Build the library by running `./build-library.bash` 30 | 5. Commit your changes. 31 | 6. Tag the current commit with the version from #3 32 | 7. Push the tags (`git push --tags`) 33 | 8. Check Travis 34 | 9. Once travis is passing, run `build.sh` to build the latest `.phar` 35 | 10. Upload the `phar` to `http://pestle.pulsestorm.net/pestle.phar` 36 | 11. Once uploaded, make a copy in the form of pestle-x-x-x.phar to capture the version 37 | 38 | Right now, every step here can be completed by anyone _except_ #10 and #11, which requires access credentials to pestle.pulsestorm.net. 39 | 40 | If you love build systems and have opinions on way to automate this, [your feedback and participation is welcome](https://github.com/astorm/pestle/issues/472). 41 | -------------------------------------------------------------------------------- /docs/dev-internals-introduction.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/extra.css: -------------------------------------------------------------------------------- 1 | code.plaintext span.hljs-keyword, 2 | code.plaintext span.hljs-symbol, 3 | code.plaintext span.hljs-string 4 | { 5 | font-weight:normal; 6 | color:black; 7 | } 8 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | ## Introduction 2 | 3 | Pestle is two, (or maybe three), different things. 4 | 5 | **Number 1**: Pestle is a set of code generation tools for the PHP framework that powers the open source version of Magento 2. 6 | 7 | **Number 2**: Pestle is, itself, a framework for writing command line PHP programs and modules that can import **functions** from other programs and modules _w 8 | 9 | **Number 3**: Pestle is how I, Alan Storm, organize many of the the one-off command line PHP Programs that have helped me throughout my career. 10 | 11 | This documentation is also split into three sections. 12 | 13 | First, we'll cover [Pestle's code and configuration generation ability w/r/t Magento two](https://pestle.readthedocs.io/en/latest/magento2-introduction/). 14 | 15 | Second, we'll cover some of the [one-off Magento 2 scripts](https://pestle.readthedocs.io/en/latest/magento2-other-introduction/) that ship with pestle. Many of these aren't as robust as they might be, but still offer useful functionality or a good start **towards** a more robust solution. 16 | 17 | Finally, we'll close with some information about developing the core pestle code base itself -- both how to *use* pestle for your own command line programs, as well as work with the internals of pestle's framework code. 18 | 19 | ## Getting Started 20 | 21 | The easiest way to get started is to grab the latest build using curl 22 | 23 | ```plaintext 24 | $ curl -LO http://pestle.pulsestorm.net/pestle.phar 25 | ``` 26 | 27 | Pestle is distributed as a PHP `phar` file -- [that's short for PHP archive](https://www.php.net/manual/en/book.phar.php). A `phar` file allows you to bundle up a bunch of PHP and distribute it as a single program. You should be able to run a `phar` with a specific version of PHP, *or* execute the `phar` file itself. 28 | 29 | ```plaintext 30 | $ php pestle.phar 31 | $ chmod +x pestle.phar 32 | $ ./pestle.phar 33 | $ mv pestle.phar /usr/local/bin 34 | $ pestle.phar # assumes /usr/local/bin is in your $PATH 35 | ``` 36 | 37 | Most of these docs will presume you're executing `pestle.phar` directly via a directory that's in your shell's path. 38 | 39 | You can see a list of available commands with the following 40 | 41 | ```plaintext 42 | $ pestle.phar list-commands 43 | ``` 44 | 45 | and get help for a specific command (`magento2:generate:module` below) with 46 | 47 | ```plaintext 48 | $ pestle.phar help magento2:generate:module 49 | ``` 50 | -------------------------------------------------------------------------------- /docs/magento2-database.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/magento2-introduction.md: -------------------------------------------------------------------------------- 1 | ## What is Magento 2? 2 | 3 | The open-source version of Magento 2 (variously called Magento Community Edition or Magento Open Source) and the "on-premises" version (variously called Enterprise Edition or Magento Commerce) is written using the PHP programming language. It's an evolution of the Magento 1 codebase, which was also written using PHP, and incorporated components of Zend Framework -- a third party framework for developing web applications in PHP. 4 | 5 | The original core Magento 1 developers built *their own* MVC framework. The various teams that have worked on Magento since evolved that framework slightly, but in Magento 2 the core concepts remained the same -- they just became more verbose. 6 | 7 | Magento code is organized into modules. These modules share a set of global configuration objects -- each module can read/write to these global configuration objects by adding XML configuration files to its own `etc` folder. These files are merged to create the global configuration. Magento provides core modules for doing web application-y things like MVC, HTML Layout rendering, monkey-patching PHP class files, etc. They also provide core modules that implement a web-based online retail store. 8 | 9 | If developers want to change or build-on Magento 2's functionality, they'll need to create their own modules. 10 | 11 | ## Pestle's magento:generate:... Commands 12 | 13 | Pestle commands in the `magento:generate` namespace allow users to automatically generate the myriad files needed for basic Magento module functionality. This includes things like the basic module structure, controllers and routing files, view files, observers, upgrade migrations, UI Components, etc. Pestle takes the grunt work out of remembering which files make up a module's structure, 14 | 15 | In addition to the finely grained code generation commands, pestle also features a command to generate a "complete skeleton" module that contains everything a developer would need to persist information to the database and a backend UI for doing the same. To learn more read the [Generate Full Module](https://pestle.readthedocs.io/en/latest/magento2-generate-full-module/) section of the docs. 16 | -------------------------------------------------------------------------------- /docs/magento2-other-introduction.md: -------------------------------------------------------------------------------- 1 | TODO: write docs 2 | -------------------------------------------------------------------------------- /docs/magento2-other-other.md: -------------------------------------------------------------------------------- 1 | ## fix-permissions-modphp 2 | 3 | TODO: WRITE THE DOCS! 4 | 5 | ```plaintext 6 | Usage: 7 | $ pestle.phar magento2:fix-permissions-modphp 8 | 9 | Arguments: 10 | 11 | Options: 12 | 13 | Help: 14 | ALPHA: "Fixes" permissions for development boxes 15 | running mod_php by setting things to 777. 16 | @command magento2:fix-permissions-modphp 17 | ``` 18 | 19 | ## code-migration:rename 20 | 21 | TODO: WRITE THE DOCS! 22 | 23 | ```plaintext 24 | Usage: 25 | $ pestle.phar magento2:code-migration:rename 26 | 27 | Arguments: 28 | 29 | Options: 30 | 31 | Help: 32 | ALPHA: Rename .converted files 33 | 34 | @command magento2:code-migration:rename 35 | @argument path Path to module? [app/code/Package/Module] 36 | ``` 37 | -------------------------------------------------------------------------------- /docs/magento2-quick-conversions.md: -------------------------------------------------------------------------------- 1 | ## class-from-path 2 | 3 | TODO: WRITE THE DOCS! 4 | 5 | ```plaintext 6 | Usage: 7 | $ pestle.phar magento2:class-from-path 8 | 9 | Arguments: 10 | 11 | Options: 12 | 13 | Help: 14 | Turns a Magento file path into a PHP class 15 | Long 16 | Description 17 | @command magento2:class-from-path 18 | ``` 19 | 20 | ## convert-class 21 | 22 | TODO: WRITE THE DOCS! 23 | 24 | ```plaintext 25 | Usage: 26 | $ pestle.phar magento2:convert-class 27 | 28 | Arguments: 29 | 30 | Options: 31 | 32 | Help: 33 | ALPHA: Partially converts Magento 1 class to Magento 2 34 | Long 35 | Description 36 | @command magento2:convert-class 37 | ``` 38 | 39 | ## convert-observers-xml 40 | 41 | TODO: WRITE THE DOCS! 42 | 43 | ```plaintext 44 | Usage: 45 | $ pestle.phar magento2:convert-observers-xml 46 | 47 | Arguments: 48 | 49 | Options: 50 | 51 | Help: 52 | ALPHA: Partially converts Magento 1 config.xml to Magento 2 53 | Long 54 | Description 55 | @command magento2:convert-observers-xml 56 | ``` 57 | 58 | ## convert-system-xml 59 | 60 | TODO: WRITE THE DOCS! 61 | 62 | ```plaintext 63 | Usage: 64 | $ pestle.phar magento2:convert-system-xml 65 | 66 | Arguments: 67 | 68 | Options: 69 | 70 | Help: 71 | ALPHA: Partially Converts Magento 1 system.xml into Magento 2 72 | system.xml 73 | @command magento2:convert-system-xml 74 | ``` 75 | 76 | ## extract-mage2-system-xml-paths 77 | 78 | TODO: WRITE THE DOCS! 79 | 80 | ```plaintext 81 | Usage: 82 | $ pestle.phar magento2:extract-mage2-system-xml-paths 83 | 84 | Arguments: 85 | 86 | Options: 87 | 88 | Help: 89 | Generates Mage2 config.xml 90 | Extracts configuration path's from a Magento 2 module's 91 | system.xml file, and then generates a config.xml file 92 | for the creation of default values 93 | 94 | @command magento2:extract-mage2-system-xml-paths 95 | ``` 96 | 97 | ## fix-direct-om 98 | 99 | TODO: WRITE THE DOCS! 100 | 101 | ```plaintext 102 | Usage: 103 | $ pestle.phar magento2:fix-direct-om 104 | 105 | Arguments: 106 | 107 | Options: 108 | 109 | Help: 110 | ALPHA: Fixes direct use of PHP Object Manager 111 | argument foobar @callback exampleOfACallback 112 | @command magento2:fix-direct-om 113 | @argument folder Folder to scan 114 | @argument extensions File extensions? [php, phtml] 115 | ``` 116 | 117 | ## path-from-class 118 | 119 | TODO: WRITE THE DOCS! 120 | 121 | ```plaintext 122 | Usage: 123 | $ pestle.phar magento2:path-from-class 124 | 125 | Arguments: 126 | 127 | Options: 128 | 129 | Help: 130 | Turns a PHP class into a Magento 2 path 131 | Long 132 | Description 133 | @command magento2:path-from-class 134 | ``` 135 | -------------------------------------------------------------------------------- /docs/magento2-scans-and-reports.md: -------------------------------------------------------------------------------- 1 | ## base-dir 2 | 3 | TODO: WRITE THE DOCS! 4 | 5 | ```plaintext 6 | Usage: 7 | $ pestle.phar magento2:base-dir 8 | 9 | Arguments: 10 | 11 | Options: 12 | 13 | Help: 14 | Output the base magento2 directory 15 | 16 | @command magento2:base-dir 17 | ``` 18 | 19 | ## check-templates 20 | 21 | TODO: WRITE THE DOCS! 22 | 23 | ```plaintext 24 | Usage: 25 | $ pestle.phar magento2:check-templates 26 | 27 | Arguments: 28 | 29 | Options: 30 | 31 | Help: 32 | Checks for incorrectly named template folder 33 | Long 34 | Description 35 | @command magento2:check-templates 36 | ``` 37 | 38 | ## class-list 39 | 40 | TODO: WRITE THE DOCS! 41 | 42 | ```plaintext 43 | Usage: 44 | $ pestle.phar magento2:class-list 45 | 46 | Arguments: 47 | 48 | Options: 49 | 50 | Help: 51 | Get a list of all of magento2's extensible classes 52 | 53 | @command magento2:class-list 54 | ``` 55 | 56 | ## read-rest-schema 57 | 58 | TODO: WRITE THE DOCS! 59 | 60 | ```plaintext 61 | Usage: 62 | $ pestle.phar magento2:read-rest-schema 63 | 64 | Arguments: 65 | 66 | Options: 67 | 68 | Help: 69 | BETA: Magento command, reads the rest schema on a Magento system 70 | 71 | @command magento2:read-rest-schema 72 | @argument url Base Url? [http://magento-2-with-keys.dev/] 73 | ``` 74 | 75 | ## scan:acl-used 76 | 77 | TODO: WRITE THE DOCS! 78 | 79 | ```plaintext 80 | Usage: 81 | $ pestle.phar magento2:scan:acl-used 82 | 83 | Arguments: 84 | 85 | Options: 86 | 87 | Help: 88 | Scans modules for ACL rule ids, makes sure they're all used/defined 89 | 90 | @command magento2:scan:acl-used 91 | @argument dir Which Directory? 92 | ``` 93 | 94 | ## scan:class-and-namespace 95 | 96 | TODO: WRITE THE DOCS! 97 | 98 | ```plaintext 99 | Usage: 100 | $ pestle.phar magento2:scan:class-and-namespace 101 | 102 | Arguments: 103 | 104 | Options: 105 | 106 | Help: 107 | BETA: Scans a Magento 2 module for misnamed PHP classes 108 | @command magento2:scan:class-and-namespace 109 | @argument folder Which Folder? 110 | ``` 111 | 112 | ## scan:htaccess 113 | 114 | TODO: WRITE THE DOCS! 115 | 116 | ```plaintext 117 | Usage: 118 | $ pestle.phar magento2:scan:htaccess 119 | 120 | Arguments: 121 | 122 | Options: 123 | 124 | Help: 125 | ALPHA: Checks for missing Magento 2 HTACCESS files from a hard coded 126 | list 127 | @command magento2:scan:htaccess 128 | ``` 129 | 130 | ## scan:registration 131 | 132 | TODO: WRITE THE DOCS! 133 | 134 | ```plaintext 135 | Usage: 136 | $ pestle.phar magento2:scan:registration 137 | 138 | Arguments: 139 | 140 | Options: 141 | 142 | Help: 143 | Scans Magento 2 directories for missing registration.php files 144 | Long 145 | Description 146 | @command magento2:scan:registration 147 | ``` 148 | 149 | ## search:search-controllers 150 | 151 | TODO: WRITE THE DOCS! 152 | 153 | ```plaintext 154 | Usage: 155 | $ pestle.phar magento2:search:search-controllers 156 | 157 | Arguments: 158 | 159 | Options: 160 | 161 | Help: 162 | Searches controllers 163 | @command magento2:search:search-controllers 164 | ``` 165 | -------------------------------------------------------------------------------- /docs/pestle-third-party.md: -------------------------------------------------------------------------------- 1 | TODO: write docs 2 | -------------------------------------------------------------------------------- /gen-event-list.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #requires pcre2grep 3 | #run this command from a magento root directory to generate a (incomplete?) list of emitted events 4 | #to be used with observer generate autocomplete 5 | 6 | MAGE_ROOT=app/code/Magento 7 | 8 | pcre2grep --buffer-size=50M -M -r -o1 "eventManager->dispatch\s*\(\s*([\'\"][^\'\"]*[\'\"])" $MAGE_ROOT \ 9 | | sed -e 's/.*://g' \ 10 | | xargs --replace=EVENT echo 'echo "EVENT"' 11 | 12 | #-M is for multiline match 13 | #-r recusrive search 14 | #-o1 outputs only the first capture group (our event) 15 | 16 | #regex matches all dispatched events that match regex 17 | #regex matches eventManager->dispatch 18 | #followed by white space then a literal ( 19 | #then any number of white space 20 | #then we capture the first string that appears 21 | # capture a ' or a " 22 | # followed by any number of anything that's not a ' or a " 23 | # followed by the matching ' or a " 24 | 25 | #this regex will also capture php code within "" that's meant to be evaluated 26 | # such as "admin_system_config_changed_section_{$this->getSection()}" (so far the only match) 27 | #it will also capture strings that begin with a ' and end with a " or vice versa (minor todo: we don't want that, but it shouldn't matter) 28 | 29 | #the sed erases the directory paths 30 | #the xargs generates the final echo command list to be used -------------------------------------------------------------------------------- /library/autoload.php: -------------------------------------------------------------------------------- 1 | $value) { 20 | $length = strlen($key) + strlen($value); 21 | $longestLine = ($length > $longestLine) ? $length : $longestLine; 22 | } 23 | 24 | $longestLine += 5; 25 | 26 | $containerLine = '+'.str_repeat('-', $longestLine) . '+'; 27 | output($containerLine); 28 | 29 | foreach($accounts as $key=>$value) { 30 | $paddingKey = str_repeat(' ', $longestKey - strlen($key) + 1); 31 | $paddingValue = str_repeat(' ', 32 | $longestLine - strlen($paddingKey . $key . $value . ' | ')); 33 | 34 | // $paddingValue = ' '; 35 | output( '| ' . 36 | $key . 37 | $paddingKey . '| '. 38 | $value . 39 | $paddingValue . '|'); 40 | } 41 | output($containerLine); 42 | $print = 'SUM: ' . number_format($sum); 43 | $length = $longestLine - strlen($print) - 1; 44 | $padding = str_repeat(' ', $length); 45 | // $padding = ' '; 46 | output('| ' . $print . $padding . '|'); 47 | output($containerLine); 48 | } 49 | 50 | /** 51 | * @command library 52 | */ 53 | function pestle_cli() 54 | { 55 | } 56 | -------------------------------------------------------------------------------- /modules/pulsestorm/cli/build_command_list/module.php: -------------------------------------------------------------------------------- 1 | append($objects); 25 | } 26 | return $iterator; 27 | // return $objects; 28 | } 29 | 30 | function includeAllModuleFiles() 31 | { 32 | $objects = getListOfFilesInModuleFolder(); 33 | // $path = realpath('modules/'); 34 | // $objects = new RecursiveIteratorIterator( 35 | // new RecursiveDirectoryIterator($path), 36 | // RecursiveIteratorIterator::SELF_FIRST 37 | // ); 38 | foreach($objects as $name => $object){ 39 | $info = pathinfo($name); 40 | if($info['basename'] == 'module.php') 41 | { 42 | require_once $name; 43 | } 44 | } 45 | 46 | } 47 | 48 | function buildCommandList() 49 | { 50 | includeAllModuleFiles(); 51 | 52 | $functions = get_defined_functions(); 53 | $lookup = []; 54 | foreach($functions['user'] as $function) 55 | { 56 | if(strpos($function, 'pestle_cli') === false) 57 | { 58 | continue; 59 | } 60 | $r = new ReflectionFunction($function); 61 | // $doc_comment = getDocCommentAsString($function); 62 | $parsed_doc_command = parseDocBlockIntoParts($r->getDocComment()); 63 | 64 | $command = array_key_exists('command', $parsed_doc_command) 65 | ? $parsed_doc_command['command'] : ['pestle-none-set']; 66 | 67 | $command = array_shift($command); 68 | 69 | $lookup[$command] = $r->getFilename(); 70 | } 71 | cacheCommandList($lookup); 72 | return $lookup; 73 | } 74 | 75 | function cacheCommandList($lookup) 76 | { 77 | $cache_dir = getCacheDir(); 78 | file_put_contents($cache_dir . '/command-list.ser', serialize($lookup)); 79 | } 80 | 81 | /** 82 | * Builds the command list 83 | * @command pestle:build-command-list 84 | */ 85 | function pestle_cli($argv) 86 | { 87 | $lookup = buildCommandList(); 88 | foreach($lookup as $command=>$file) 89 | { 90 | output($command); 91 | } 92 | 93 | } 94 | 95 | -------------------------------------------------------------------------------- /modules/pulsestorm/cli/format_php/module.php: -------------------------------------------------------------------------------- 1 | token_value === ';' && $next_token->token_name !== 'T_CLOSE_TAG') 21 | { 22 | return true; 23 | } 24 | 25 | return false; 26 | } 27 | 28 | /** 29 | * ALPHA: Experiments with a PHP formatter. 30 | * 31 | * @command php:format-php 32 | * @argument file Which file? 33 | */ 34 | function pestle_cli($argv) 35 | { 36 | define('START', 0); 37 | define('PARSE_IF', 1); 38 | define('INSIDE_IF_BLOCK', 2); 39 | 40 | $file = $argv['file']; 41 | $tokens = pestle_token_get_all(file_get_contents($file)); 42 | 43 | //remove whitespace tokens 44 | $tokens = array_filter($tokens, function($token){ 45 | return $token->token_name !== 'T_WHITESPACE'; 46 | }); 47 | $tokens = array_values($tokens); 48 | 49 | $state = 0; 50 | $indent_level = 0; 51 | foreach($tokens as $key=>$token) 52 | { 53 | $before = ''; 54 | $after = ''; 55 | 56 | //state switching 57 | if($token->token_name == 'T_IF') 58 | { 59 | $state = PARSE_IF; 60 | } 61 | 62 | if($state == PARSE_IF && $token->token_value === ':') 63 | { 64 | $indent_level++; 65 | $state = INSIDE_IF_BLOCK; 66 | } 67 | 68 | if($state == INSIDE_IF_BLOCK && $token->token_name === 'T_ENDIF') 69 | { 70 | $state = START; 71 | $indent_level--; 72 | } 73 | 74 | //manipuate extra output tokens 75 | if($token->token_value === '{') 76 | { 77 | $indent_level++; 78 | $after = "\n" . str_repeat(" ", $indent_level); 79 | } 80 | 81 | if($token->token_value === '}') 82 | { 83 | $indent_level--; 84 | $after = "\n" . str_repeat(" ", $indent_level); 85 | } 86 | 87 | if($token->token_name === 'T_CLOSE_TAG') 88 | { 89 | $after = "\n" . str_repeat(" ", $indent_level); 90 | } 91 | 92 | if(tokenIsSemiColonAndNextTokenIsNotTCloseTag($tokens, $key)) 93 | { 94 | $after = "\n" . str_repeat(" ", $indent_level); 95 | } 96 | 97 | if($token->token_name === 'T_INLINE_HTML' && !trim($token->token_value)) 98 | { 99 | continue; 100 | } 101 | //do output 102 | echo $before; 103 | echo $token->token_value; 104 | echo $after; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /modules/pulsestorm/cli/md_to_say/module.php: -------------------------------------------------------------------------------- 1 | .+?%six', 25 | '

[CODE SNIPPED].

', 26 | $html 27 | ); 28 | $html = str_replace('

','


',$html); 29 | 30 | $tmp = tempnam('/tmp', 'md_to_say') . '.html'; 31 | file_put_contents($tmp, $html); 32 | 33 | $cmd = 'textutil -convert txt ' . $tmp; 34 | `$cmd`; 35 | 36 | $tmp_txt = swapExtension($tmp, 'html','txt'); 37 | $tmp_aiff = swapExtension($tmp, 'html','aiff'); 38 | 39 | $cmd = "say -f $tmp_txt -o $tmp_aiff"; 40 | output($cmd); 41 | // `$cmd`; 42 | // $tmp_txt = preg_replace('%\.html$%','.txt', $tmp); 43 | 44 | output($tmp_aiff); 45 | output("Done"); 46 | } 47 | -------------------------------------------------------------------------------- /modules/pulsestorm/cli/self_update/module.php: -------------------------------------------------------------------------------- 1 | name; 24 | $name = $faker->name; 25 | $email = preg_replace('%[^a-zA-Z0-9_-]%','',$name) . '@' . $domain; 26 | output($name . "\t" . $email); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /modules/pulsestorm/financial/parse_citicard/module.php: -------------------------------------------------------------------------------- 1 | $value) 17 | { 18 | if(is_numeric($key)) 19 | { 20 | unset($data[$key]); 21 | } 22 | } 23 | return $data; 24 | } 25 | 26 | function file_get_contents_csv($filename,$has_headers=true) 27 | { 28 | $all = array(); 29 | $file = fopen($filename,'r'); 30 | if($has_headers) 31 | { 32 | apply_column_headers(fgetcsv($file)); 33 | } 34 | while($data = fgetcsv($file)) 35 | { 36 | if($has_headers) 37 | { 38 | $all[] = apply_column_headers($data); 39 | } 40 | else 41 | { 42 | $all[] = $data; 43 | } 44 | 45 | } 46 | fclose($file); 47 | 48 | return $all; 49 | } 50 | 51 | function parseDescription($string) 52 | { 53 | return [ 54 | 'description'=>trim($string) 55 | ]; 56 | // preg_match('%\d\d\d-\d\d\d-\d\d\d\d%', $string, $matches); 57 | // $phone = array_pop($matches); 58 | // 59 | // $state = 60 | } 61 | 62 | /** 63 | * BETA: Parses Citicard's CSV files into yaml 64 | * 65 | * @command parsing:citicard 66 | * @argument file File to Parse? 67 | * @argument count Starting Count? 68 | */ 69 | function pestle_cli($argv) 70 | { 71 | $file = $argv['file']; 72 | $count = $argv['count']; 73 | $items = file_get_contents_csv($file); 74 | foreach($items as $item) 75 | { 76 | $parts = parseDescription($item['Description']); 77 | $description = $parts['description']; 78 | if($description === 'ELECTRONIC PAYMENT-THANK YOU') 79 | { 80 | continue; 81 | } 82 | // 120-Paid On 03/10/2016:028.28 Do it Best Hardware 83 | output($count,'-Paid On ', $item['Date'],':',$item['Debit'], 84 | ' ', $description); 85 | $count++; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /modules/pulsestorm/generate/pestle/command/module.php: -------------------------------------------------------------------------------- 1 | 0) 17 | { 18 | $Path = $argv[0]; 19 | } 20 | 21 | foreach(glob($path . '/*/*') as $file) 22 | { 23 | $parts = explode('/', $file); 24 | $module = implode('_', array_slice($parts, count($parts) - 2)); 25 | 26 | $file = $file . '/' . 'registration.php'; 27 | if(file_exists($file)) 28 | { 29 | output("Registration Exists"); 30 | $contents = file_get_contents($file); 31 | if(strpos($contents, "'" . $module . "'") !== false) 32 | { 33 | output("Registration contains $module string"); 34 | continue; 35 | } 36 | output("However, it's missing single quoted '$module' string"); 37 | output(""); 38 | continue; 39 | } 40 | output("No $file"); 41 | $answer = input("Create? [Y/n]", 'n'); 42 | if($answer !== 'Y') 43 | { 44 | continue; 45 | } 46 | file_put_contents($file, templateRegistrationPhp($module)); 47 | output("Created $file"); 48 | output(""); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /modules/pulsestorm/magento2/cli/check_templates/module.php: -------------------------------------------------------------------------------- 1 | 0) 21 | { 22 | $class[] = $part; 23 | } 24 | } 25 | array_shift($class); 26 | 27 | $class_name = array_pop($class); 28 | $body = '<' . '?' . 'php' . "\n" . 29 | 'namespace ' . implode('\\', $class) . ";\n" . 30 | 'class ' . str_replace('.php','',$class_name) . "\n" . '{}'; 31 | 32 | output($body); 33 | } -------------------------------------------------------------------------------- /modules/pulsestorm/magento2/cli/convert_class/module.php: -------------------------------------------------------------------------------- 1 | {$scope}, $xml); 28 | output($scope); 29 | output($xml_new->asXml()); 30 | output('--------------------------------------------------'); 31 | } 32 | } 33 | 34 | } -------------------------------------------------------------------------------- /modules/pulsestorm/magento2/cli/dev_import/module.php: -------------------------------------------------------------------------------- 1 | '); 31 | foreach($tree as $section=>$groups) 32 | { 33 | $section = $xml->default->addChild($section); 34 | foreach($groups as $group=>$fields) 35 | { 36 | $group = $section->addChild($group); 37 | foreach($fields as $field) 38 | { 39 | $group->addChild($field, 'DEFAULTVALUE'); 40 | } 41 | } 42 | } 43 | echo $xml->asXml(); 44 | } 45 | -------------------------------------------------------------------------------- /modules/pulsestorm/magento2/cli/extract_session/module.php: -------------------------------------------------------------------------------- 1 | preserveWhitespace = false; 16 | $dom->loadXml($xml_string); 17 | $dom->formatOutput = true; 18 | $output = $dom->saveXml(); 19 | 20 | return $output; 21 | } 22 | -------------------------------------------------------------------------------- /modules/pulsestorm/magento2/cli/generate/acl/module.php: -------------------------------------------------------------------------------- 1 | ::top,<$module_name$>::config,] 19 | */ 20 | function pestle_cli($argv) 21 | { 22 | extract($argv); 23 | $rule_ids = explode(',', $rule_ids); 24 | $rule_ids = array_filter($rule_ids); 25 | 26 | $path = getBaseModuleDir($module_name) . '/etc/acl.xml'; 27 | if(!file_exists($path)) 28 | { 29 | $xml = simplexml_load_string(getBlankXml('acl')); 30 | writeStringToFile($path, $xml->asXml()); 31 | } 32 | $xml = simplexml_load_file($path); 33 | 34 | $xpath = 'acl/resources/resource[@id=Magento_Backend::admin]'; 35 | 36 | foreach($rule_ids as $id) 37 | { 38 | $id = trim($id); 39 | $xpath .= '/resource[@id='.$id.',@title=TITLE HERE FOR]'; 40 | } 41 | simpleXmlAddNodesXpath($xml,$xpath); 42 | 43 | writeStringToFile($path, formatXmlString($xml->asXml())); 44 | output("Created $path"); 45 | } 46 | 47 | function exported_pestle_cli($argv) 48 | { 49 | return pestle_cli($argv); 50 | } -------------------------------------------------------------------------------- /modules/pulsestorm/magento2/cli/generate/command/module.php: -------------------------------------------------------------------------------- 1 | asXml())); 36 | } 37 | return $path_di_xml; 38 | } 39 | 40 | /** 41 | * Generates bin/magento command files 42 | * This command generates the necessary files and configuration 43 | * for a new command for Magento 2's bin/magento command line program. 44 | * 45 | * pestle.phar generate_command Pulsestorm_Generate Example 46 | * 47 | * Creates 48 | * app/code/Pulsestorm/Generate/Command/Example.php 49 | * app/code/Pulsestorm/Generate/etc/di.xml 50 | * 51 | * @command generate-command 52 | * @argument module_name In which module? [Pulsestorm_Helloworld] 53 | * @argument command_name Command Name? [Testbed] 54 | */ 55 | function pestle_cli($argv) 56 | { 57 | $module_info = getModuleInformation($argv['module_name']); 58 | $namespace = $module_info->vendor; 59 | $module_name = $module_info->name; 60 | $module_shortname = $module_info->short_name; 61 | $module_dir = $module_info->folder; 62 | $command_name = $argv['command_name']; 63 | // $command_name = input("Command Name?", 'Testbed'); 64 | 65 | output($module_dir); 66 | 67 | createPhpClass($module_dir, $namespace, $module_shortname, $command_name); 68 | 69 | $path_di_xml = createDiIfNeeded($module_dir); 70 | 71 | $xml_di = simplexml_load_file($path_di_xml); 72 | 73 | //get commandlist node 74 | $nodes = $xml_di->xpath('/config/type[@name="Magento\Framework\Console\CommandList"]'); 75 | $xml_type_commandlist = array_shift($nodes); 76 | if(!$xml_type_commandlist) 77 | { 78 | $xml_type_commandlist = $xml_di->addChild('type'); 79 | $xml_type_commandlist['name'] = 'Magento\Framework\Console\CommandList'; 80 | } 81 | 82 | $argument = simpleXmlAddNodesXpath($xml_type_commandlist, 83 | '/arguments/argument[@name=commands,@xsi:type=array]'); 84 | 85 | $full_class = $namespace.'\\'.$module_shortname.'\\Command\\' . $command_name; 86 | $item_name = str_replace('\\', '_', strToLower($full_class)); 87 | $item = $argument->addChild('item', $full_class); 88 | $item->addAttribute('name', $item_name); 89 | $item->addAttribute('xsi:type', 'object', 'http://www.w3.org/2001/XMLSchema-instance'); 90 | 91 | $xml_di = formatXmlString($xml_di->asXml()); 92 | 93 | writeStringToFile($path_di_xml, $xml_di); 94 | 95 | } 96 | 97 | function exported_pestle_cli($argv) 98 | { 99 | return pestle_cli($argv); 100 | } -------------------------------------------------------------------------------- /modules/pulsestorm/magento2/cli/generate/config_helper/module.php: -------------------------------------------------------------------------------- 1 | scopeConfig = $scopeConfig; 32 | } 33 | 34 | public function get($path=null) 35 | { 36 | $config = $this->scopeConfig->getValue($this->getTopLevelName()); 37 | if($config === null) 38 | { 39 | return null; 40 | } 41 | if(!$path) 42 | { 43 | return $config; 44 | } 45 | $parts = explode(\'/\',$path); 46 | 47 | foreach($parts as $part) 48 | { 49 | if(!array_key_exists($part, $config)) 50 | { 51 | return null; 52 | } 53 | $config = $config[$part]; 54 | } 55 | 56 | return $config; 57 | } 58 | 59 | protected function getTopLevelName() 60 | { 61 | return self::CONFIG_TOP; 62 | } 63 | } 64 | '); 65 | 66 | output($template); 67 | } 68 | 69 | function exported_pestle_cli($argv) 70 | { 71 | return pestle_cli($argv); 72 | } -------------------------------------------------------------------------------- /modules/pulsestorm/magento2/cli/generate/install/module.php: -------------------------------------------------------------------------------- 1 | > magento_umask"; 38 | $cmds[] = "echo \"We're about to ask for your MySQL password so we can create the database\""; 39 | $cmds[] = "echo 'CREATE DATABASE $db_name' | mysql -uroot -p"; 40 | 41 | $cmds[] = "php bin/magento setup:install --admin-email $admin_email --admin-firstname $admin_first_name --admin-lastname $admin_last_name --admin-password $admin_password --admin-user $admin_user --backend-frontname admin --base-url http://$url --db-host 127.0.0.1 --db-name $db_name --db-password $db_pass --db-user $db_user --session-save files --use-rewrites 1 --use-secure 0 -vvv"; 42 | $cmds[] = 'php bin/magento sampledata:deploy'; 43 | $cmds[] = 'php bin/magento cache:enable'; 44 | 45 | array_map(function($cmd){ 46 | output($cmd); 47 | }, $cmds); 48 | } 49 | 50 | function exported_pestle_cli($argv) 51 | { 52 | return pestle_cli($argv); 53 | } -------------------------------------------------------------------------------- /modules/pulsestorm/magento2/cli/generate/layout_xml/module.php: -------------------------------------------------------------------------------- 1 | folder; 17 | } 18 | 19 | function getPackageDir($base_dir, $namespace, $name) { 20 | $result = getModuleInformation(implode('_', [$namespace,$name]), $base_dir); 21 | return $result->folder_package; 22 | } 23 | 24 | 25 | /** 26 | * Generates new module XML, adds to file system 27 | * This command generates the necessary files and configuration 28 | * to add a new module to a Magento 2 system. 29 | * 30 | * pestle.phar Pulsestorm TestingCreator 0.0.1 31 | * 32 | * @argument namespace Vendor Namespace? [Pulsestorm] 33 | * @argument name Module Name? [Testbed] 34 | * @argument version Version? [0.0.1] 35 | * @command generate-module 36 | */ 37 | function pestle_cli($argv) 38 | { 39 | $namespace = $argv['namespace']; 40 | $name = $argv['name']; 41 | $version = $argv['version']; 42 | 43 | $full_module_name = implode('_', [$namespace, $name]); 44 | 45 | $config = simplexml_load_string(getBlankXml('module')); 46 | $module = $config->addChild('module'); 47 | $module->addAttribute('name' , $full_module_name); 48 | $module->addAttribute('setup_version', $version); 49 | $xml = $config->asXml(); 50 | 51 | $base_dir = getBaseMagentoDir(); 52 | $module_dir = getModuleDir($base_dir, $namespace, $name); 53 | $package_dir = getPackageDir($base_dir, $namespace, $name); 54 | $etc_dir = $module_dir . '/etc'; 55 | $reg_path = $module_dir . '/registration.php'; 56 | 57 | if(is_dir($etc_dir)) 58 | { 59 | output("Module directory [$etc_dir] already exists"); 60 | } else { 61 | output("Creating [$etc_dir] "); 62 | mkdir($etc_dir, 0755, $etc_dir); 63 | } 64 | 65 | writeFormattedXmlStringToFile($etc_dir . '/module.xml', $xml); 66 | output("Created: " . $etc_dir . '/module.xml'); 67 | 68 | $register = templateRegistrationPhp($full_module_name); 69 | writeStringToFile($reg_path, $register); 70 | output("Created: " . $reg_path); 71 | } 72 | 73 | function exported_pestle_cli($argv) 74 | { 75 | return pestle_cli($argv); 76 | } 77 | 78 | -------------------------------------------------------------------------------- /modules/pulsestorm/magento2/cli/generate/observer/module.php: -------------------------------------------------------------------------------- 1 | _listener] 21 | * @argument model_name Class Name? [<$module$>\Model\Observer] 22 | */ 23 | function pestle_cli($argv) 24 | { 25 | $module = $argv['module']; 26 | $event_name = $argv['event_name']; 27 | $observer_name = $argv['observer_name']; 28 | $model_name = $argv['model_name']; 29 | $method_name = 'execute'; 30 | 31 | $path_xml_event = initilizeModuleConfig( 32 | $module, 33 | 'events.xml', 34 | 'urn:magento:framework:Event/etc/events.xsd' 35 | ); 36 | 37 | $xml = simplexml_load_file($path_xml_event); 38 | $nodes = $xml->xpath('//event[@name="' . $event_name . '"]'); 39 | $node = array_shift($nodes); 40 | $event = $node; 41 | if(!$node) 42 | { 43 | $event = $node ? $node : $xml->addChild('event'); 44 | $event->addAttribute('name', $event_name); 45 | } 46 | $observer = $event->addChild('observer'); 47 | $observer->addAttribute('name', $observer_name); 48 | $observer->addAttribute('instance', $model_name); 49 | // $observer->addAttribute('method', $method_name); 50 | 51 | output("Creating: $path_xml_event"); 52 | $path = writeStringToFile($path_xml_event, $xml->asXml()); 53 | 54 | output("Creating: $model_name"); 55 | $contents = createClassTemplate($model_name, false, '\Magento\Framework\Event\ObserverInterface'); 56 | $contents = str_replace('<$body$>', 57 | "\n" . 58 | ' public function execute(\Magento\Framework\Event\Observer $observer){exit(__FILE__);}' . 59 | "\n" , $contents); 60 | createClassFile($model_name, $contents); 61 | } 62 | 63 | function exported_pestle_cli($argv) 64 | { 65 | return pestle_cli($argv); 66 | } -------------------------------------------------------------------------------- /modules/pulsestorm/magento2/cli/generate/psr_log_level/module.php: -------------------------------------------------------------------------------- 1 | $value) 19 | { 20 | output($key . "\t\t" . $value); 21 | } 22 | } 23 | 24 | function exported_pestle_cli($argv) 25 | { 26 | return pestle_cli($argv); 27 | } -------------------------------------------------------------------------------- /modules/pulsestorm/magento2/cli/generate/registration/module.php: -------------------------------------------------------------------------------- 1 | folder . '/view/' . 17 | $area . '/templates/' . $template; 18 | 19 | output("Creating $path"); 20 | writeStringToFile($path, '

This is my template, there are many like it, but this one is mine.

'); 21 | 22 | } 23 | 24 | function createHandleFile($module_info, $area, $template, $class, $handle, $layout) 25 | { 26 | $xml = simplexml_load_string(getBlankXml('layout_handle')); 27 | $name = strToLower($module_info->name) . 28 | '_block_' . 29 | strToLower(getShortClassNameFromClass($class)); 30 | 31 | simpleXmlAddNodesXpath($xml, 32 | 'referenceContainer[@name=content]/block[' . 33 | '@template=' . $template . ',' . 34 | '@class=' . $class . ',' . 35 | '@name=' . $name . ']' 36 | ); 37 | 38 | $xml['layout'] = $layout; 39 | if($layout === '' || $area === 'adminhtml') 40 | { 41 | unset($xml['layout']); 42 | } 43 | 44 | $path = $module_info->folder . '/view/' . 45 | $area . '/layout/' . $handle . '.xml'; 46 | 47 | output("Creating: $path"); 48 | writeStringToFile($path, $xml->asXml()); 49 | 50 | } 51 | 52 | function createBlockClass($module_info, $block_name, $area='frontname') 53 | { 54 | $class_name = str_replace('_', '\\', $module_info->name) . 55 | '\Block\\'; 56 | if($area === 'adminhtml') 57 | { 58 | $class_name .= 'Adminhtml\\'; 59 | } 60 | $class_name .= ucwords($block_name); 61 | 62 | output("Creating: " . $class_name); 63 | $baseClass = '\Magento\Framework\View\Element\Template'; 64 | if($area === 'adminhtml') 65 | { 66 | $baseClass = '\Magento\Backend\Block\Template'; 67 | } 68 | $contents = createClassTemplate($class_name, $baseClass); 69 | $contents = str_replace('<$body$>', "\n".' function _prepareLayout(){}'."\n", $contents); 70 | createClassFile($class_name, $contents); 71 | return $class_name; 72 | } 73 | 74 | /** 75 | * Generates a Magento 2 view 76 | * 77 | * Wrapped by magento:... version of command 78 | * 79 | * @command generate-view 80 | * @argument module_name Which Module? [Pulsestorm_HelloGenerate] 81 | * @argument area Which Area? [frontend] 82 | * @argument handle Which Handle? [<$module_name$>_index_index] 83 | * @argument block_name Block Name? [Main] 84 | * @argument template Template File? [content.phtml] 85 | * @argument layout Layout (ignored for adminhtml) ? [1column] 86 | */ 87 | function pestle_cli($argv) 88 | { 89 | $module_name = $argv['module_name']; 90 | $area = $argv['area']; 91 | $handle = $argv['handle']; 92 | $block_name = $argv['block_name']; 93 | $template = $argv['template']; 94 | $layout = $argv['layout']; 95 | 96 | $module_info = getModuleInformation($module_name); 97 | 98 | createTemplateFile($module_info, $area, $template); 99 | $class = createBlockClass($module_info, $block_name, $area); 100 | createHandleFile($module_info, $area, $template, $class, $handle, $layout); 101 | 102 | } 103 | 104 | function exported_pestle_cli($argv) 105 | { 106 | return pestle_cli($argv); 107 | } -------------------------------------------------------------------------------- /modules/pulsestorm/magento2/cli/hello_argument/module.php: -------------------------------------------------------------------------------- 1 | 1) 25 | { 26 | exitWithErrorMessage("Found more than one node with {$argv['acl_rule_id']}"); 27 | } 28 | 29 | $node = array_pop($nodes); 30 | $node['title'] = $argv['title']; 31 | 32 | writeStringToFile($argv['path_acl'], $xml->asXml()); 33 | output("Changed Title"); 34 | } 35 | -------------------------------------------------------------------------------- /modules/pulsestorm/magento2/cli/magento2/generate/acl/module.php: -------------------------------------------------------------------------------- 1 | ::top,<$module_name$>::config,] 13 | */ 14 | function pestle_cli($argv) 15 | { 16 | return exported_pestle_cli($argv); 17 | } 18 | -------------------------------------------------------------------------------- /modules/pulsestorm/magento2/cli/magento2/generate/command/module.php: -------------------------------------------------------------------------------- 1 | ::unique_identifier] 32 | * @argument resource ACL Resource [<$id$>] 33 | * @argument title Link Title [My Link Title] 34 | * @argument action Three Segment Action [frontname/index/index] 35 | * @argument sortOrder Sort Order? [10] 36 | */ 37 | 38 | function pestle_cli($argv) 39 | { 40 | // output("Hi"); 41 | return exported_pestle_cli($argv); 42 | } 43 | -------------------------------------------------------------------------------- /modules/pulsestorm/magento2/cli/magento2/generate/module/module.php: -------------------------------------------------------------------------------- 1 | _listener] 44 | * @argument model_name @callback getModelName 45 | */ 46 | function pestle_cli($argv) 47 | { 48 | //* @argument model_name Class Name? [<$module$>\Model\Observer] 49 | return exported_pestle_cli($argv); 50 | } 51 | -------------------------------------------------------------------------------- /modules/pulsestorm/magento2/cli/magento2/generate/plugin_xml/module.php: -------------------------------------------------------------------------------- 1 | \Plugin\<$class$>] 16 | * @option use-type-hint Add type hint to subject? 17 | * @command magento2:generate:plugin-xml 18 | */ 19 | function pestle_cli($argv, $options) 20 | { 21 | return exported_pestle_cli($argv, $options); 22 | } 23 | -------------------------------------------------------------------------------- /modules/pulsestorm/magento2/cli/magento2/generate/preference/module.php: -------------------------------------------------------------------------------- 1 | folder . '/etc/di.xml'; 15 | if(!file_exists($path_di)) 16 | { 17 | $xml = simplexml_load_string(getBlankXml('di')); 18 | writeStringToFile($path_di, $xml->asXml()); 19 | output("Created new $path_di"); 20 | } 21 | $xml = simplexml_load_file($path_di); 22 | return [ 23 | 'path'=>$path_di, 24 | 'xml'=>$xml 25 | ]; 26 | } 27 | 28 | function generateDiConfiguration($argv) 29 | { 30 | $moduleInfo = getModuleInformation($argv['module']); 31 | $pathAndXml = loadOrCreateDiXml($moduleInfo); 32 | $path = $pathAndXml['path']; 33 | $di_xml = $pathAndXml['xml']; 34 | 35 | $preference = $di_xml->addChild('preference'); 36 | $preference['for'] = $argv['for']; 37 | $preference['type'] = $argv['type']; 38 | 39 | writeStringToFile($path, formatXmlString($di_xml->asXml())); 40 | 41 | } 42 | 43 | function isTypeInterface($type) 44 | { 45 | //string detection for now -- change to actually examine system? 46 | return strpos($type, 'Interface') !== false; 47 | } 48 | 49 | function generateNewClass($argv) 50 | { 51 | $pathType = getPathFromClass($argv['type']); 52 | 53 | $typeGlobalNs = '\\' . trim($argv['for'],'\\'); 54 | $classContents = createClassTemplate($argv['type'], $typeGlobalNs); 55 | if(isTypeInterface($typeGlobalNs)) 56 | { 57 | $classContents = createClassTemplate($argv['type'], null, $typeGlobalNs); 58 | } 59 | 60 | $classContents = str_replace('<$body$>', '',$classContents); 61 | 62 | if(!file_exists($pathType)) 63 | { 64 | output("Creating $pathType"); 65 | writeStringToFile($pathType, $classContents); 66 | } 67 | else 68 | { 69 | output("$pathType already exists, skipping creation"); 70 | } 71 | } 72 | 73 | /** 74 | * Generates a Magento 2.1 ui grid listing and support classes. 75 | * 76 | * @command magento2:generate:preference 77 | * @argument module Which Module? [Pulsestorm_Helloworld] 78 | * @argument for For which Class/Interface/Type? [Pulsestorm\Helloworld\Model\FooInterface] 79 | * @argument type New Concrete Class? [Pulsestorm\Helloworld\Model\NewModel] 80 | */ 81 | function pestle_cli($argv) 82 | { 83 | generateDiConfiguration($argv); 84 | generateNewClass($argv); 85 | 86 | // output("Created file $path_plugin"); 87 | // output("This command will add to di.xml (create if needed)"); 88 | // output("This command will also generate a class"); 89 | // output("If passed an interface, class will implement"); 90 | // output("If passed a class, class will extend"); 91 | // output("Simple text matching for interface detection?"); 92 | // generateUiComponentXmlFile( 93 | // $argv['grid_id'], $argv['db_id_column'], $module_info); 94 | // 95 | // generateDataProviderClass( 96 | // $module_info, $argv['grid_id'], $argv['collection_resource'] . 'Factory'); 97 | // 98 | // generatePageActionClass( 99 | // $module_info, $argv['grid_id'], $argv['db_id_column']); 100 | // 101 | // output("Don't forget to add this to your layout XML with "); 102 | } 103 | -------------------------------------------------------------------------------- /modules/pulsestorm/magento2/cli/magento2/generate/psr_log_level/module.php: -------------------------------------------------------------------------------- 1 | addChild('actionsColumn'); 61 | $actionsColumn->addAttribute('name', 'actions'); 62 | $actionsColumn->addAttribute('class', $actionsClass); 63 | $argument = addArgument($actionsColumn, 'data', 'array'); 64 | $configItem = addItem($argument, 'config', 'array'); 65 | $indexField = addItem($configItem, 'indexField', 'string', $argv['index_field']); 66 | 67 | output( 68 | formatXmlString($xml->asXml()) 69 | ); 70 | 71 | // 72 | // 73 | // 74 | // false 75 | // 107 76 | // pulsestorm_todocrud_todoitem_id 77 | // 78 | // 79 | // 80 | 81 | } 82 | -------------------------------------------------------------------------------- /modules/pulsestorm/magento2/cli/magento2/generate/ui/add-column-sections/module.php: -------------------------------------------------------------------------------- 1 | addChild('selectionsColumn'); 35 | $sectionsColumn->addAttribute('name', $argv['column_name']); 36 | $argument = addArgument($sectionsColumn, 'data', 'array'); 37 | $configItem = addItem($argument, 'config', 'array'); 38 | $indexField = addItem($configItem, 'indexField', 'string', $argv['index_field']); 39 | 40 | writeStringToFile($argv['listing_file'], formatXmlString($xml->asXml())); 41 | 42 | } 43 | -------------------------------------------------------------------------------- /modules/pulsestorm/magento2/cli/magento2/generate/ui/add_to_layout/module.php: -------------------------------------------------------------------------------- 1 | 1) 35 | { 36 | exitWithErrorMessage("BAILING: Found more than one name=\"".$argv['block_name']."\" node.\n"); 37 | } 38 | return array_pop($nodes); 39 | } 40 | 41 | /** 42 | * Adds a node to a named node in a layout update XML file 43 | * 44 | * @command magento2:generate:ui:add-to-layout 45 | * @argument path_layout Layout XML File? 46 | * @argument block_name Block or Reference Name? 47 | * @argument ui_component_name UI Component Name? 48 | */ 49 | function pestle_cli($argv) 50 | { 51 | $xml = simplexml_load_file($argv['path_layout']); 52 | validateNoSuchComponent($xml, $argv['ui_component_name']); 53 | $node = getContentNode($xml, $argv); 54 | 55 | $node->addChild('uiComponent') 56 | ->addAttribute('name', $argv['ui_component_name']); 57 | $xmlString = formatXmlString($xml->asXml()); 58 | writeStringToFile($argv['path_layout'], $xmlString); 59 | output("Added Component"); 60 | } 61 | -------------------------------------------------------------------------------- /modules/pulsestorm/magento2/cli/magento2/generate/view/module.php: -------------------------------------------------------------------------------- 1 | _index_index] 14 | * @argument block_name Block Name? [Main] 15 | * @argument template Template File? [content.phtml] 16 | * @argument layout Layout (ignored for adminhtml) ? [1column] 17 | */ 18 | function pestle_cli($argv) 19 | { 20 | return exported_pestle_cli($argv); 21 | } 22 | -------------------------------------------------------------------------------- /modules/pulsestorm/magento2/cli/pandoc_md/module.php: -------------------------------------------------------------------------------- 1 | $items) 29 | { 30 | foreach($items as $item) 31 | { 32 | $contents = file_get_contents($item); 33 | if(strpos($contents, 'execute') !== false) 34 | { 35 | $return[$item] = $contents; 36 | } 37 | } 38 | } 39 | 40 | return $return; 41 | 42 | } 43 | 44 | function getExecuteMethods($controllers) 45 | { 46 | foreach($controllers as $file=>$contents) 47 | { 48 | $execute = getFunctionFromClass($contents, 'execute'); 49 | output($file); 50 | output('--------------------------------------------------'); 51 | output($execute); 52 | output(''); 53 | 54 | } 55 | } 56 | 57 | /** 58 | * Searches controllers 59 | * @command magento2:search:search-controllers 60 | */ 61 | function pestle_cli($argv) 62 | { 63 | $base = inputOrIndex("Which folder to search?",'vendor/magento',$argv,0); 64 | $controllers = getAllControllerFiles($base); 65 | $controllers = getControllersWithExecuteMethod($controllers); 66 | $controllers = getExecuteMethods($controllers); 67 | } 68 | -------------------------------------------------------------------------------- /modules/pulsestorm/magento2/cli/test_output/module.php: -------------------------------------------------------------------------------- 1 | 8 | 9 | '; 10 | 11 | } 12 | 13 | function getBlankXmlView() 14 | { 15 | return ''; 16 | } 17 | 18 | function getBlankXmlAcl() 19 | { 20 | return ' 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | '; 29 | } 30 | 31 | function getBlankXmlMenu() 32 | { 33 | return ' 34 | 35 | 36 | 37 | '; 38 | } 39 | 40 | function getBlankXmlUiGrid() 41 | { 42 | return ''; 43 | } 44 | 45 | function getBlankXmlTheme() 46 | { 47 | return ''; 48 | } 49 | 50 | function getBlankXmlRoutes() 51 | { 52 | $config_attributes = 'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd"'; 53 | return trim(''); 54 | 55 | } 56 | 57 | function getBlankXmlDi() 58 | { 59 | return ' 60 | 61 | '; 62 | 63 | } 64 | 65 | function getBlankXml($type) 66 | { 67 | $function = 'Pulsestorm\Magento2\Cli\Xml_Template'; 68 | $function .= '\getBlankXml' . ucWords(strToLower($type)); 69 | if(function_exists($function)) 70 | { 71 | return call_user_func($function); 72 | } 73 | throw new Exception("No such type, $type ($function)"); 74 | } 75 | 76 | function getBlankXmlLayout_handle() 77 | { 78 | return ' 79 | 80 | '; 81 | } 82 | 83 | function getBlankXmlWebapi() 84 | { 85 | return ' 87 | '; 88 | } 89 | /** 90 | * Converts Zend Log Level into PSR Log Level 91 | * @command library 92 | */ 93 | function pestle_cli($argv) 94 | { 95 | } -------------------------------------------------------------------------------- /modules/pulsestorm/magento2/codemigration/rename/module.php: -------------------------------------------------------------------------------- 1 | 0) 34 | { 35 | exitWithErrorMessage("BAILING: Found *.php.old files -- looks like you already ran this command."); 36 | } 37 | 38 | // var_dump($olds); 39 | // exit(__FUNCTION__ . "\n"); 40 | // $path = 'm2-converted'; 41 | // $path = 'app/code/LCG/Ambassador'; 42 | $oldFiles = `find $path/ -name '*.php'`; 43 | $convertedFiles = `find $path/ -name '*.php.converted'`; 44 | 45 | 46 | 47 | $oldFiles = explode("\n", $oldFiles); 48 | $oldFiles = array_filter($oldFiles); 49 | foreach($oldFiles as $file) 50 | { 51 | $cmd = sprintf('mv %s %s', $file, $file . '.old'); 52 | runCommand($cmd); 53 | } 54 | 55 | $convertedFiles = explode("\n", $convertedFiles); 56 | $convertedFiles = array_filter($convertedFiles); 57 | foreach($convertedFiles as $file) 58 | { 59 | $newPhpFile = preg_replace('%.php.converted$%', '.php', $file); 60 | $cmd = sprintf('mv %s %s', $file, $newPhpFile); 61 | runCommand($cmd); 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /modules/pulsestorm/magento2/generate/remove_named_node/module.php: -------------------------------------------------------------------------------- 1 | ? [block] 16 | * @argument name The {node_name}="" value? [] 17 | */ 18 | function pestle_cli($argv) 19 | { 20 | $xml = simplexml_load_file($argv['path_xml']); 21 | $nodes = getByAttributeXmlBlockWithNodeNames( 22 | 'name', $xml, $argv['name'], [$argv['node_name']]); 23 | 24 | if(count($nodes) === 0) 25 | { 26 | exitWithErrorMessage("Bailing: No such node."); 27 | } 28 | 29 | if(count($nodes) > 1) 30 | { 31 | exitWithErrorMessage("Bailing: Found more than one node."); 32 | } 33 | 34 | $node = $nodes[0]; 35 | 36 | if(count($node->children()) > 0) 37 | { 38 | exitWithErrorMessage("Bailing: Contains child nodes"); 39 | } 40 | 41 | unset($node[0]); //http://stackoverflow.com/questions/262351/remove-a-child-with-a-specific-attribute-in-simplexml-for-php/16062633#16062633 42 | 43 | writeStringToFile( 44 | $argv['path_xml'],formatXmlString($xml->asXml()) 45 | ); 46 | output("Node Removed"); 47 | } 48 | -------------------------------------------------------------------------------- /modules/pulsestorm/magento2/generate/schemaaddcolumn/module.php: -------------------------------------------------------------------------------- 1 | getTable('table_name'))->addColumn 17 | * and if found, scanning to the ; and inserting the addColumn 18 | * 19 | * @command magento2:generate:schema-add-column 20 | * @argument php_file PHP file with newTable call? [skip] 21 | * @argument table Database Table? (packagename_modulename_modelnames) 22 | * @argument column Columns Name? (new_column) 23 | * @argument column_type @callback selectColumnType 24 | */ 25 | function pestle_cli($argv, $options) 26 | { 27 | return exported_pestle_cli($argv, $options); 28 | } 29 | 30 | function selectColumnType($arguments, $index, $fullArguments) 31 | { 32 | if(isset($arguments[$index])) 33 | { 34 | return $arguments[$index]; 35 | } 36 | $types = array_values(getColumnTypes()); 37 | $value = inputFromArray("Column Type?", $types, 1); 38 | return $value; 39 | } 40 | -------------------------------------------------------------------------------- /modules/pulsestorm/magento2/generate/ui/addformfield/module.php: -------------------------------------------------------------------------------- 1 | getName() !== 'form') 13 | { 14 | exitWithErrorMessage('ERROR: This does not look like a
file.'); 15 | } 16 | 17 | $fieldsets = $xml->xpath('/form/fieldset[@name="'.$argv['fieldset'].'"]'); 18 | if(count($fieldsets) !== 1) 19 | { 20 | exitWithErrorMessage('ERROR: XML file should have exactly one name="'.$argv['fieldset'].'" fieldset.'); 21 | } 22 | 23 | $fields = $xml->xpath('/form/fieldset/field[@name="'.$argv['field'].'"]'); 24 | if(count($fields) > 0) 25 | { 26 | exitWithErrorMessage("ERROR: XML file already has a name=\"{$argv['field']}\" field."); 27 | } 28 | } 29 | 30 | function getNextSortOrderFromXml($xml) 31 | { 32 | $nodes = $xml->xpath('//item[@name="sortOrder"]'); 33 | $max = array_reduce($nodes, function($carry, $item){ 34 | $item = (int) $item; 35 | if($carry > $item) 36 | { 37 | return $carry; 38 | } 39 | return $item; 40 | }, 0); 41 | 42 | return $max + 10; 43 | } 44 | 45 | 46 | /** 47 | * Adds a Form Field 48 | * 49 | * @command magento2:generate:ui:add-form-field 50 | * @argument path_xml Path to Form XML File? 51 | * @argument field Field Name? [title] 52 | * @argument label Label? [Title] 53 | * @argument fieldset Fieldset Name? [general] 54 | * @option is-required Is field required? 55 | */ 56 | function pestle_cli($argv, $options) 57 | { 58 | $xml = simplexml_load_file($argv['path_xml']); 59 | validateXml($xml, $argv); 60 | $fieldsets = $xml->xpath('/form/fieldset[@name="'.$argv['fieldset'].'"]'); 61 | $fieldset = array_shift($fieldsets); 62 | 63 | $dataType = 'text'; 64 | $formElement = 'input'; 65 | $sortOrder = '25'; 66 | 67 | $field = $fieldset->addChild('field'); 68 | $field->addAttribute('name', $argv['field']); 69 | // addSpecificChild('field', $fieldset,); 70 | $argument = addSpecificChild('argument', $field, 'data', 'array'); 71 | $itemConfig = addSpecificChild('item', $argument, 'config', 'array'); 72 | $itemDataType = addSpecificChild('item', $itemConfig, 'dataType', 'string', $dataType); 73 | $itemLabel = addSpecificChild('item', $itemConfig, 'label', 'string', $argv['label']); 74 | $itemFormElement = addSpecificChild('item', $itemConfig, 'formElement', 'string', $formElement); 75 | $itemSortOrder = addSpecificChild('item', $itemConfig, 'sortOrder', 'string', getNextSortOrderFromXml($fieldset)); 76 | $itemDataScope = addSpecificChild('item', $itemConfig, 'dataScope', 'string', $argv['field']); 77 | 78 | $itemValidation = addSpecificChild('item', $itemConfig, 'validation', 'array'); 79 | $required = is_null($options['is-required']) ? 'false' : 'true'; 80 | $itemRequiredEntry = addSpecificChild('item', $itemValidation, 'required-entry', 'boolean', $required); 81 | 82 | writeStringToFile( 83 | $argv['path_xml'], 84 | formatXmlString($xml->asXml()) 85 | ); 86 | } 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /modules/pulsestorm/magento2/generate/ui/addformfieldset/module.php: -------------------------------------------------------------------------------- 1 | getName() !== 'form') 13 | { 14 | exitWithErrorMessage('ERROR: This does not look like a file.'); 15 | } 16 | 17 | $fieldsets = $xml->xpath('/form/fieldset[@name="'.$argv['fieldset'].'"]'); 18 | if(count($fieldsets) !== 0) 19 | { 20 | exitWithErrorMessage('ERROR: XML file already has one name="'.$argv['fieldset'].'" fieldset.'); 21 | } 22 | 23 | } 24 | /** 25 | * Add a Fieldset to a Form 26 | * 27 | * @command magento2:generate:ui:add-form-fieldset 28 | * @argument path_xml Path to Form XML File? 29 | * @argument fieldset Fieldset Name? [newfieldset] 30 | * @argument label Label? [NewFieldset] 31 | */ 32 | function pestle_cli($argv) 33 | { 34 | $xml = simplexml_load_file($argv['path_xml']); 35 | validateXml($xml, $argv); 36 | $formels = $xml->xpath('/form'); 37 | $formel = array_shift($formels); 38 | $fieldset = $formel->addChild('fieldset'); 39 | $fieldset->addAttribute('name', $argv['fieldset']); 40 | $argument = addSpecificChild('argument', $fieldset, 'data', 'array'); 41 | $itemConfig = addSpecificChild('item', $argument, 'config', 'array'); 42 | $itemLabel = addSpecificChild('item', $itemConfig, 'label', 'string', $argv['label']); 43 | $itemCollaps = addSpecificChild('item', $itemConfig, 'collapsible', 'boolean', 'true'); 44 | 45 | //output(formatXmlString($xml->asXml())); 46 | writeStringToFile( 47 | $argv['path_xml'], 48 | formatXmlString($xml->asXml()) 49 | ); 50 | } 51 | -------------------------------------------------------------------------------- /modules/pulsestorm/nexmo/sendtext/module.php: -------------------------------------------------------------------------------- 1 | getMessage()); 13 | } 14 | /** 15 | * Sends a text message 16 | * 17 | * @command nexmo:send-text 18 | * @argument to Send to phone number? 19 | * @argument from From phone number? [12155167753] 20 | * @argument text Text to send? [You are the best!] 21 | */ 22 | function pestle_cli($argv) 23 | { 24 | $client = getClient(); 25 | $message = false; 26 | try 27 | { 28 | $message = $client->message()->send([ 29 | 'to' => $argv['to'], 30 | 'from' => $argv['from'], 31 | 'text' => $argv['text'] 32 | ]); 33 | } 34 | catch(Exception $e) 35 | { 36 | handleException($e); 37 | } 38 | if($message) 39 | { 40 | output($message->getResponseData()); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /modules/pulsestorm/nexmo/storecredentials/module.php: -------------------------------------------------------------------------------- 1 | key; 12 | $secret = $data->secret; 13 | $client = new \Nexmo\Client(new \Nexmo\Client\Credentials\Basic($key, $secret)); 14 | return $client; 15 | } 16 | 17 | function getCredentialFilePath() 18 | { 19 | return '/tmp/.nexmo'; 20 | } 21 | 22 | function readFromCredentialFile() 23 | { 24 | $path = getCredentialFilePath(); 25 | $o = false; 26 | if(file_exists(getCredentialFilePath())) 27 | { 28 | $o = json_decode( 29 | file_get_contents( 30 | $path 31 | ) 32 | ); 33 | } 34 | if(!$o) 35 | { 36 | $o = new stdClass; 37 | } 38 | 39 | return $o; 40 | } 41 | 42 | function writeToCredentialFile($data) 43 | { 44 | $path = getCredentialFilePath(); 45 | $result = file_put_contents($path, json_encode($data)); 46 | chmod($path, 0600); 47 | return $result; 48 | } 49 | 50 | /** 51 | * Stores Nexmo API in temp file 52 | * 53 | * @command nexmo:store-credentials 54 | * @argument key Key? [] 55 | * @argument password Secret/Password? [] 56 | */ 57 | function pestle_cli($argv) 58 | { 59 | $data = readFromCredentialFile(); 60 | $data->key = $argv['key']; 61 | $data->secret = $argv['password']; 62 | writeToCredentialFile($data); 63 | } 64 | -------------------------------------------------------------------------------- /modules/pulsestorm/nexmo/verifyrequest/module.php: -------------------------------------------------------------------------------- 1 | getMessage()); 13 | } 14 | 15 | function sendVerifyRequest($client, $number, $brand) 16 | { 17 | $clientVerify = $client->verify(); 18 | $verification = [ 19 | 'number' => $number, 20 | 'brand' => $brand 21 | ]; 22 | 23 | $response = false; 24 | try 25 | { 26 | $response = $clientVerify->start($verification); 27 | } 28 | catch(Exception $e) 29 | { 30 | handleException($e); 31 | } 32 | return $response; 33 | } 34 | 35 | /** 36 | * Sends initial request to verify user's phone number 37 | * 38 | * @command nexmo:verify-request 39 | * @argument to Phone number to verify? 40 | * @argument brand Brand/Prefix string for code message? [MyApp] 41 | */ 42 | function pestle_cli($argv) 43 | { 44 | $client = getClient(); 45 | $verifyRequestResponse = sendVerifyRequest( 46 | $client, $argv['to'], $argv['brand']); 47 | if($verifyRequestResponse) 48 | { 49 | $json = $verifyRequestResponse->getResponseData(); 50 | output($json); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /modules/pulsestorm/nexmo/verifysendcode/module.php: -------------------------------------------------------------------------------- 1 | verify(); 12 | $result = false; 13 | try 14 | { 15 | $result = $clientVerify->check( 16 | $verificationRequestId, 17 | $code 18 | ); 19 | } 20 | catch(\Exception $e) 21 | { 22 | output(get_class($e)); 23 | output($e->getMessage()); 24 | } 25 | return $result; 26 | } 27 | 28 | /** 29 | * Nexmo Verify API: Second Step 30 | * 31 | * @command nexmo:verify-sendcode 32 | * @argument request_id Request ID? (from nexmo:verify-request) [] 33 | * @argument code The four or six digit code? [] 34 | */ 35 | function pestle_cli($argv) 36 | { 37 | $client = getClient(); 38 | $result = sendVerifyVerification($client, $argv['request_id'], $argv['code']); 39 | if($result) 40 | { 41 | output($result->getResponseData()); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /modules/pulsestorm/pestle/clear_cache/module.php: -------------------------------------------------------------------------------- 1 | token_value; 45 | $functionNameToBody[$functionName] = getFunctionFromCode($contents, $functionName); 46 | } 47 | 48 | return $functionNameToBody; 49 | } 50 | 51 | function getPestleImportsFunctionBodiesFromContents($contents) 52 | { 53 | $imports = getPestleImportsFromCode($contents); 54 | $importedFunctionsToFiles = array_combine($imports, 55 | array_map(function($function){ 56 | return getPathFromFunctionName($function); 57 | }, $imports)); 58 | $importedFunctionsToContents = array_map(function($file){ 59 | return file_get_contents($file); 60 | }, $importedFunctionsToFiles); 61 | 62 | $functionsFromImport = []; 63 | foreach($importedFunctionsToContents as $function=>$contents) 64 | { 65 | $parts = explode('\\', $function); 66 | $functionName = array_pop($parts); 67 | $functionsFromImport[$functionName] = getFunctionFromCode($contents, $functionName); 68 | } 69 | return $functionsFromImport; 70 | } 71 | 72 | /** 73 | * Exports a Pestle Module as a Symfony Console Command 74 | * 75 | * @command pestle:export-as-symfony 76 | * @argument command_to_export Export Which Pestle Command? [hello-world] 77 | * @argument full_class_name Full Symfony Class Name [Pulsestorm\SymfonyConsole\TestCommand] 78 | */ 79 | function pestle_cli($argv) 80 | { 81 | output("@TODO: replace function calls with $this->functionCall"); 82 | output("@TODO: Functions from pestle import: Need to rename to avoid naming conflicts"); 83 | output(" Maybe use a slashless full namespace name?"); 84 | // $list = loadSerializedCommandListFromCache(); 85 | $commandModule = loadSerializedCommandListFromCache()[$argv['command_to_export']]; 86 | $contents = file_get_contents($commandModule); 87 | 88 | $functions = getFunctionBodiesFromCommandModueContents($contents); 89 | $functionsFromImports = getPestleImportsFunctionBodiesFromContents($contents); 90 | 91 | $classBody = getSymfonyConsoleBaseBody() . 92 | implode("\n\n", $functions) . 93 | implode("\n\n", $functionsFromImports); 94 | 95 | $class = createClassTemplateWithUse($argv['full_class_name'], 'Command'); 96 | $class = str_replace('<$use$>' , getSymfonyConsoleBaseUse(), $class); 97 | $class = str_replace('<$body$>' , $classBody, $class); 98 | output($class); 99 | output("Done"); 100 | } 101 | -------------------------------------------------------------------------------- /modules/pulsestorm/pestle/run_file/module.php: -------------------------------------------------------------------------------- 1 | ', 20 | '', 21 | $xmlString); 22 | return $xml; 23 | } 24 | 25 | function getXmlNamespaceFromPrefix($xml, $prefix) 26 | { 27 | $namespaces = $xml->getDocNamespaces(); 28 | if(array_key_exists($prefix, $namespaces)) 29 | { 30 | return $namespaces[$prefix]; 31 | } 32 | 33 | throw new Exception("Unkonwn namespace in " . __FILE__); 34 | } 35 | 36 | function simpleXmlAddNodesXpathReturnOriginal($xml, $path) 37 | { 38 | $result = simpleXmlAddNodesXpathWorker($xml, $path); 39 | return $result['original']; 40 | } 41 | 42 | function simpleXmlAddNodesXpath($xml, $path) 43 | { 44 | $result = simpleXmlAddNodesXpathWorker($xml, $path); 45 | return $result['child']; 46 | } 47 | 48 | function simpleXmlAddNodesXpathWorker($xml, $path) 49 | { 50 | $path = trim($path,'/'); 51 | $node = $xml; 52 | foreach(explode('/',$path) as $part) 53 | { 54 | $parts = explode('[', $part); 55 | $node_name = array_shift($parts); 56 | $is_new_node = true; 57 | if(isset($node->{$node_name})) 58 | { 59 | $is_new_node = false; 60 | $node = $node->{$node_name}; 61 | } 62 | else 63 | { 64 | $node = $node->addChild($node_name); 65 | } 66 | 67 | 68 | $attribute_string = trim(array_pop($parts),']'); 69 | if(!$attribute_string) { continue; } 70 | $pairs = explode(',',$attribute_string); 71 | foreach($pairs as $pair) 72 | { 73 | if(!$is_new_node) { continue; } 74 | list($key,$value) = explode('=',$pair); 75 | if(strpos($key, '@') !== 0) 76 | { 77 | throw new Exception("Invalid Attribute Key"); 78 | } 79 | $key = trim($key, '@'); 80 | if(strpos($key, ':') !== false) 81 | { 82 | list($namespace_prefix, $rest) = explode(':', $key); 83 | $namespace = getXmlNamespaceFromPrefix($xml, $namespace_prefix); 84 | $node->addAttribute($key, $value, $namespace); 85 | } 86 | else 87 | { 88 | $node->addAttribute($key, $value); 89 | } 90 | 91 | } 92 | // exit; 93 | } 94 | 95 | return [ 96 | 'original'=>$xml, 97 | 'child'=>$node 98 | ]; 99 | } 100 | 101 | function getByAttributeXmlBlockWithNodeNames($attributeName, $xml, $value, $names=null) 102 | { 103 | $search = '//*[@'.$attributeName.'="' . $value . '"]'; 104 | $nodes = $xml->xpath($search); 105 | $nodes = array_filter($nodes, function($node) use ($names){ 106 | if(!$names) { return true; } 107 | return in_array($node->getName(), $names); 108 | }); 109 | return $nodes; 110 | } 111 | 112 | function getNamedXmlBlockWithNodeNames($xml, $name, $names) 113 | { 114 | return getByAttributeXmlBlockWithNodeNames('name', $xml, $name, $names); 115 | } 116 | 117 | function formatXmlString($string) 118 | { 119 | $dom = new DomDocument; 120 | $dom->preserveWhiteSpace = false; 121 | $dom->formatOutput = true; 122 | $dom->loadXml($string); 123 | $string = $dom->saveXml(); 124 | 125 | $string = preg_replace('%(^\s*)%m', '$1$1', $string); 126 | 127 | return $string; 128 | } -------------------------------------------------------------------------------- /pestle_dev: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | result = $this->runCommand(); 24 | } 25 | 26 | /** 27 | * Check module declaration file exists. 28 | * 29 | * @test 30 | */ 31 | // public function xtestModuleFileExists() 32 | // { 33 | // $result = file_exists(__DIR__.'/../app/code/Pulsestore/Testbed/etc/module.xml'); 34 | // $this->assertTrue($result); 35 | // } 36 | // 37 | // /** 38 | // * Check module registration file exists. 39 | // * 40 | // * @test 41 | // */ 42 | // public function xtestRegistrationFileExists() 43 | // { 44 | // $result = file_exists(__DIR__.'/../app/code/Pulsestore/Testbed/registration.php'); 45 | // $this->assertTrue($result); 46 | // } 47 | } 48 | -------------------------------------------------------------------------------- /tests-integration/GenerateRouteTest.php: -------------------------------------------------------------------------------- 1 | runCommand(self::COMMAND); 24 | // $this->result = $this->runCommand(); 25 | } 26 | 27 | /** 28 | * Check routes declaration file exists. 29 | * 30 | * @test 31 | */ 32 | // public function xtestRoutesFileExists() 33 | // { 34 | // $result = file_exists(__DIR__.'/../app/code/Pulsestorm/HelloWorld/etc/frontend/routes.xml'); 35 | // $this->assertTrue($result); 36 | // } 37 | // 38 | // /** 39 | // * Check module registration file exists. 40 | // * 41 | // * @test 42 | // */ 43 | // public function xtestControllerFileExists() 44 | // { 45 | // $result = file_exists(__DIR__.'/../app/code/Pulsestorm/HelloWorld/Controller/Index/Index.php'); 46 | // $this->assertTrue($result); 47 | // } 48 | } 49 | -------------------------------------------------------------------------------- /tests-integration/HelloWorldTest.php: -------------------------------------------------------------------------------- 1 | runCommand()); 15 | $this->assertEquals($results, 'Hello Sailor'); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests-integration/PestleTestIntegration.php: -------------------------------------------------------------------------------- 1 | createFakeMagentoInstance(); 34 | $this->removeApp = true; 35 | } 36 | } 37 | 38 | /** 39 | * Tear down the integration tests. 40 | */ 41 | protected function tearDown() 42 | { 43 | parent::tearDown(); 44 | 45 | if ($this->removeApp) { 46 | $this->deleteDirectoryTree('app'); 47 | } 48 | } 49 | 50 | /** 51 | * Create `app/etc/di.xml` so pestle.phar can work. 52 | * 53 | * @return $this 54 | */ 55 | protected function createFakeMagentoInstance() 56 | { 57 | mkdir('app'); 58 | mkdir('app/etc'); 59 | touch('app/etc/di.xml'); 60 | 61 | return $this; 62 | } 63 | 64 | /** 65 | * Delete a directory tree: http://php.net/manual/en/function.rmdir.php 66 | * 67 | * @param $directory 68 | * 69 | * @return bool 70 | */ 71 | protected function deleteDirectoryTree($directory) { 72 | $files = array_diff(scandir($directory), array('.','..')); 73 | foreach ($files as $file) { 74 | (is_dir("$directory/$file")) ? $this->deleteDirectoryTree("$directory/$file") : unlink("$directory/$file"); 75 | } 76 | 77 | return rmdir($directory); 78 | } 79 | 80 | /** 81 | * Check the pestle command is available in the current environment. 82 | * 83 | * @test 84 | */ 85 | public function testPestleIsAvailable() 86 | { 87 | $this->assertNotFalse($this->getPestlePackage()); 88 | } 89 | 90 | /** 91 | * Check the di.xml exists, if it does not then something is 92 | * wrong with the install. 93 | * 94 | * @test 95 | */ 96 | public function testDiXmlExists() 97 | { 98 | $this->assertFileExists('app/etc/di.xml'); 99 | } 100 | 101 | /** 102 | * Run a command from users pestle implementation. 103 | * 104 | * @param $cmd 105 | * 106 | * @return mixed 107 | */ 108 | protected function runCommand($cmd = false) 109 | { 110 | if (!$cmd) { 111 | $cmd = static::COMMAND; 112 | } 113 | 114 | $pestle = $this->getPestlePackage(); 115 | return `$pestle $cmd`; 116 | } 117 | 118 | /** 119 | * Check if a package is available. 120 | * 121 | * @param $package 122 | * 123 | * @return bool 124 | */ 125 | protected function isPackageAvailable($package) { 126 | return (empty(`which $package`) ? false : true); 127 | } 128 | 129 | /** 130 | * Get the correct pestle package name from the users system. 131 | * 132 | * @return string|bool 133 | */ 134 | protected function getPestlePackage() 135 | { 136 | if(!$this->packageName === null) { 137 | return $this->packageName; 138 | } 139 | 140 | $this->packageName = false; 141 | 142 | foreach($this->packageNames as $packageName) { 143 | if ($this->isPackageAvailable($packageName)) { 144 | $this->packageName = $packageName; 145 | break; 146 | } 147 | } 148 | 149 | return $this->packageName; 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /tests/AdminClassNameTest.php: -------------------------------------------------------------------------------- 1 | assertEquals(-1, -1); 12 | } 13 | 14 | public function testBaseFrontendArgs() 15 | { 16 | $controllerClass = createControllerClass( 17 | 'Pulsestorm\HelloWorld\Controller\Index\Index', 18 | 'frontend', 19 | 'some-acl-rule-name'); 20 | $fixture = $this->loadFixture(__METHOD__); 21 | $this->assertEquals($fixture, $controllerClass); 22 | // echo $controllerClass; 23 | } 24 | 25 | public function testBaseAdminArgs() 26 | { 27 | $controllerClass = createControllerClass( 28 | 'Pulsestorm\HelloWorld\Controller\Adminhtml\Index\Index', 29 | 'adminhtml', 30 | 'some-acl-rule-name'); 31 | $fixture = $this->loadFixture(__METHOD__); 32 | $this->assertEquals($fixture, $controllerClass); 33 | // echo $controllerClass; 34 | } 35 | 36 | protected function loadFixture($method) 37 | { 38 | return file_get_contents(__DIR__ . '/fixtures/AdminClassName/' . 39 | preg_replace('%^.*?::test%','',$method) . '.php' ); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /tests/AppCodeRefactorTest.php: -------------------------------------------------------------------------------- 1 | assertEquals(-1, -1); 34 | } 35 | 36 | public function testGetModulePathInFullModuleGeneration() { 37 | $result = getRelativeModulePath('Foo', 'Bar', self::PATH_FAKE_BASE); 38 | $this->assertEquals('app/code/Foo/Bar', $result); 39 | } 40 | 41 | public function testGetFullModulePath() { 42 | $result = getFullModulePath('Foo', 'Bar', self::PATH_FAKE_BASE); 43 | $this->assertEquals('/fake/base/app/code/Foo/Bar', $result); 44 | } 45 | 46 | public function testGetModuleBaseDir() { 47 | $result = getModuleBaseDir('Foo_Bar', self::PATH_FAKE_BASE); 48 | $this->assertEquals('/fake/base/app/code/Foo/Bar', $result); 49 | // $this->assertEquals('/fake/base/app/code/Foo/Bar', $result); 50 | } 51 | 52 | public function testCreateClassFilePath() { 53 | $result = createClassFilePath('Foo\Bar\Baz\Bap', self::PATH_FAKE_BASE); 54 | $this->assertEquals('/fake/base/app/code/Foo/Bar/Baz/Bap.php', $result); 55 | } 56 | 57 | public function testGetPathFromClass() { 58 | $result = getPathFromClass('Foo\Bar\Baz\Bap', self::PATH_FAKE_BASE); 59 | $this->assertEquals('/fake/base/app/code/Foo/Bar/Baz/Bap.php', $result); 60 | } 61 | 62 | public function testGetAppCode() { 63 | // should always return app/code, since that's the function's 64 | // name. When we get to creating stuff in someone's folder 65 | // we'll want to use a different function. This test holds 66 | // us to that. 67 | $this->assertEquals('app/code', getAppCodePath()); 68 | } 69 | 70 | public function testGetBaseMagentoDirFromFile() { 71 | $path1 = self::PATH_FAKE_BASE . '/app/code/Foo/Bar/Model/Thing.php'; 72 | $path2 = self::PATH_FAKE_BASE . '/vendor/some-vendor/some-module/src/Foo/Bar/Model/Thing.php'; 73 | 74 | $result1 = getBaseMagentoDirFromFile($path1, true); 75 | $result2 = getBaseMagentoDirFromFile($path2, true); 76 | 77 | $this->assertEquals(self::PATH_FAKE_BASE . '/app/code', $result1); 78 | $this->assertEquals(self::PATH_FAKE_BASE . '/vendor', $result2); 79 | } 80 | 81 | public function testGetModuleDir() { 82 | $result = getModuleDir(self::PATH_FAKE_BASE, 'Foo', 'Bar'); 83 | $this->assertEquals('/fake/base/app/code/Foo/Bar', $result); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /tests/ClassParsingTest.php: -------------------------------------------------------------------------------- 1 | assertEquals($information['full-class'], 'Foo\Bar\Baz\Test'); 20 | $this->assertEquals($information['full-extends'], 'Science\Fair'); 21 | } 22 | 23 | public function testTwo() 24 | { 25 | $information = extractClassInformationFromClassContents('<' . '?php' . "\n" .' 26 | namespace Foo\Bar; 27 | 28 | use Baz\Bing\Boo; 29 | use Baz\Bing\Magic; 30 | class Test extends Boo{ 31 | }'); 32 | $this->assertEquals($information['full-class'], 'Foo\Bar\Test'); 33 | $this->assertEquals($information['full-extends'], 'Baz\Bing\Boo'); 34 | } 35 | 36 | public function testThree() 37 | { 38 | $information = extractClassInformationFromClassContents('<' . '?php' . "\n" .' 39 | namespace Foo\Bar; 40 | 41 | use Baz\Bing\Boo; 42 | use Baz\Bing\Magic; 43 | class Test extends Bar\Fee{ 44 | }'); 45 | $this->assertEquals($information['full-class'], 'Foo\Bar\Test'); 46 | $this->assertEquals($information['full-extends'], 'Foo\Bar\Fee'); 47 | } 48 | 49 | public function testFour() 50 | { 51 | $information = extractClassInformationFromClassContents('<' . '?php' . "\n" .' 52 | namespace Foo\Bar; 53 | 54 | use Baz\Bing\Boo; 55 | use Baz\Bing\Magic; 56 | 57 | class Test extends Magic\Fi{ 58 | }'); 59 | $this->assertEquals($information['full-class'], 'Foo\Bar\Test'); 60 | $this->assertEquals($information['full-extends'], 'Baz\Bing\Magic\Fi'); 61 | } 62 | 63 | } -------------------------------------------------------------------------------- /tests/ComposerPackageTest.php: -------------------------------------------------------------------------------- 1 | getPathToModuleFileUnderTest( 13 | // 'modules/pulsestorm/magento2/cli/library/module.php'); 14 | // require_once $path; 15 | // } 16 | 17 | public function testSetup() 18 | { 19 | $this->assertEquals(-1, -1); 20 | } 21 | 22 | public function testConfigLoading() 23 | { 24 | $path = getPathConfig(); 25 | $this->assertTrue(is_string($path)); 26 | $this->assertTrue(is_dir($path)); 27 | 28 | $path = getPathConfig('test'); 29 | $parts = explode('/', $path); 30 | 31 | $testDotJson = array_pop($parts); 32 | $dotPestle = array_pop($parts); 33 | 34 | $this->assertEquals('test.json', $testDotJson); 35 | $this->assertEquals('.pestle', $dotPestle); 36 | 37 | $object = loadConfig('test'); 38 | $this->assertTrue(is_object($object)); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /tests/ConfigTest.php: -------------------------------------------------------------------------------- 1 | baseDirName = '/tmp/' . uniqid(); 26 | } 27 | 28 | public function testStorage() { 29 | $this->assertEquals('file', storageMethod()); 30 | } 31 | 32 | public function testStorageSetMemory() { 33 | storageMethod('memory'); 34 | $this->assertEquals('memory', storageMethod()); 35 | $this->configTests(); 36 | } 37 | 38 | public function testStorageSetFile() { 39 | storageMethod('file'); 40 | $this->assertEquals('file', storageMethod()); 41 | getOrSetConfigBase($this->baseDirName); 42 | $this->assertEquals($this->baseDirName, getOrSetConfigBase()); 43 | $this->configTests(); 44 | } 45 | 46 | private function configTests() { 47 | $type = 'some-config'; 48 | 49 | // loadng a blank config returns a stdClass 50 | $config = loadConfig($type); 51 | $this->assertTrue(is_object($config)); 52 | $this->assertEquals([], get_object_vars($config)); 53 | 54 | $config->Pulsestorm_Science = '/foo/baz/bar'; 55 | saveConfig($type, $config); 56 | 57 | $config = loadConfig($type); 58 | $this->assertEquals('/foo/baz/bar', $config->Pulsestorm_Science); 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /tests/DoubleImportTest.php: -------------------------------------------------------------------------------- 1 | assertEquals($string,'Hello' . "\n"); 19 | } 20 | 21 | public function testSecondOutput() 22 | { 23 | pestle_import('Pulsestorm\Magento2\Cli\Test_Output\output'); 24 | ob_start(); 25 | output("Hello"); 26 | $string = ob_get_clean(); 27 | $this->assertEquals($string,'I am hard coded and here for a test.'); 28 | } 29 | 30 | public function testBothAtOne() 31 | { 32 | pestle_import('Pulsestorm\Pestle\Library\output'); 33 | ob_start(); 34 | output("Hello"); 35 | $string = ob_get_clean(); 36 | $this->assertEquals($string,'Hello' . "\n"); 37 | 38 | pestle_import('Pulsestorm\Magento2\Cli\Test_Output\output'); 39 | ob_start(); 40 | output("Hello"); 41 | $string = ob_get_clean(); 42 | $this->assertEquals($string,'I am hard coded and here for a test.'); 43 | } 44 | 45 | } -------------------------------------------------------------------------------- /tests/FirstTest.php: -------------------------------------------------------------------------------- 1 | assertEquals(-1, -1); 10 | } 11 | } -------------------------------------------------------------------------------- /tests/GenerateInstallSchemaTest.php: -------------------------------------------------------------------------------- 1 | assertTrue(is_string($result)); 12 | } 13 | 14 | public function testGenerateBlank() 15 | { 16 | $result = generateInstallSchemaTable( 17 | 'unit_test', 'ModelTest', [], 'A testing table' 18 | ); 19 | $fixture = ' $table = $installer->getConnection()->newTable( 20 | $installer->getTable(\'unit_test\') 21 | )->addColumn( 22 | \'modeltest_id\', 23 | \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, 24 | null, 25 | [ \'identity\' => true, \'nullable\' => false, \'primary\' => true, \'unsigned\' => true ], 26 | \'Entity ID\' 27 | )->addColumn( 28 | \'title\', 29 | \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, 30 | 255, 31 | [ \'nullable\' => false ], 32 | \'Demo Title\' 33 | )->addColumn( 34 | \'creation_time\', 35 | \Magento\Framework\DB\Ddl\Table::TYPE_TIMESTAMP, 36 | null, 37 | [ \'nullable\' => false, \'default\' => \Magento\Framework\DB\Ddl\Table::TIMESTAMP_INIT ], 38 | \'Creation Time\' 39 | )->addColumn( 40 | \'update_time\', 41 | \Magento\Framework\DB\Ddl\Table::TYPE_TIMESTAMP, 42 | null, 43 | [ \'nullable\' => false, \'default\' => \Magento\Framework\DB\Ddl\Table::TIMESTAMP_INIT_UPDATE ], 44 | \'Modification Time\' 45 | )->addColumn( 46 | \'is_active\', 47 | \Magento\Framework\DB\Ddl\Table::TYPE_SMALLINT, 48 | null, 49 | [ \'nullable\' => false, \'default\' => \'1\' ], 50 | \'Is Active\' 51 | )->setComment( 52 | \'A testing table\' 53 | ); 54 | $installer->getConnection()->createTable($table);'; 55 | $this->assertEquals( 56 | $result, 57 | $fixture 58 | ); 59 | } 60 | } -------------------------------------------------------------------------------- /tests/GenerateMage2CommandTest.php: -------------------------------------------------------------------------------- 1 | assertEquals('Pulsestorm\Magento2\Cli\Science', $path); 15 | } 16 | 17 | public function testNamespaceGenerate2() 18 | { 19 | $path = createNamespaceFromNamespaceAndCommandName('Pulsestorm\Magento2\Cli','generate_science'); 20 | $this->assertEquals('Pulsestorm\Magento2\Cli\Generate\Science', $path); 21 | } 22 | 23 | public function testNamespaceGenerate3() 24 | { 25 | $path = createNamespaceFromNamespaceAndCommandName('Pulsestorm\Magento2\Cli','foo_science'); 26 | $this->assertEquals('Pulsestorm\Magento2\Cli\Foo_Science', $path); 27 | } 28 | } -------------------------------------------------------------------------------- /tests/GenerateRouteTest.php: -------------------------------------------------------------------------------- 1 | assertEquals( 14 | $class, 15 | 'Pulsestorm\Hellotest\Controller\Index\Index' 16 | ); 17 | } 18 | 19 | public function testFrontendWithArg() 20 | { 21 | $module = 'Pulsestorm_Hellotest'; 22 | $area = 'frontend'; 23 | $class = createControllerClassName($module, $area); 24 | $this->assertEquals( 25 | $class, 26 | 'Pulsestorm\Hellotest\Controller\Index\Index' 27 | ); 28 | } 29 | 30 | public function testAdminhtmlWithArg() 31 | { 32 | $module = 'Pulsestorm_Hellotest'; 33 | $area = 'adminhtml'; 34 | $class = createControllerClassName($module, $area); 35 | $this->assertEquals( 36 | $class, 37 | 'Pulsestorm\Hellotest\Controller\Adminhtml\Index\Index' 38 | ); 39 | } 40 | 41 | public function testGetRouterIdFromAreaFrontend() 42 | { 43 | $this->assertEquals('standard', getRouterIdFromArea('frontend')); 44 | } 45 | 46 | public function testGetRouterIdFromAreaAdminhtml() 47 | { 48 | $this->assertEquals('admin', getRouterIdFromArea('adminhtml')); 49 | } 50 | 51 | } -------------------------------------------------------------------------------- /tests/GenerateWithColonTest.php: -------------------------------------------------------------------------------- 1 | assertEquals('Foo\Baz\Bar\Test', $value); 14 | } 15 | 16 | public function testBaseline2() 17 | { 18 | //createNamespaceFromNamespaceAndCommandName($namespace_module, $command_name) 19 | $value = createNamespaceFromNamespaceAndCommandName('Foo\Baz\Bar', 'test_command'); 20 | $this->assertEquals('Foo\Baz\Bar\Test_Command', $value); 21 | } 22 | 23 | public function testBaseline3() 24 | { 25 | //createNamespaceFromNamespaceAndCommandName($namespace_module, $command_name) 26 | $value = createNamespaceFromNamespaceAndCommandName('Foo\Baz\Bar', 'generate_test_command_thing'); 27 | $this->assertEquals('Foo\Baz\Bar\Generate\Test\Command\Thing', $value); 28 | } 29 | 30 | // public function testCommandWithColon() 31 | // { 32 | // //createNamespaceFromNamespaceAndCommandName($namespace_module, $command_name) 33 | // $value = createNamespaceFromNamespaceAndCommandName('Foo\Baz\Bar', 'test:command'); 34 | // $this->assertEquals('Foo\Baz\Bar\Test\Command', $value); 35 | // } 36 | } -------------------------------------------------------------------------------- /tests/LibraryTest.php: -------------------------------------------------------------------------------- 1 | getPathToModuleFileUnderTest( 13 | 'modules/pulsestorm/magento2/cli/library/module.php'); 14 | require_once $path; 15 | } 16 | 17 | public function testSetup() 18 | { 19 | $this->assertEquals(-1, -1); 20 | } 21 | 22 | public function testCreateClassTemplate() 23 | { 24 | $fixture = '<' . '?php 25 | namespace ; 26 | 27 | /** 28 | * Class Foo 29 | */ 30 | class Foo 31 | {<$body$>}' . "\n"; 32 | 33 | $template = createClassTemplate('Foo'); 34 | $this->assertEquals($template, $fixture); 35 | } 36 | 37 | public function testIsAboveRoot1() 38 | { 39 | $path = '/foo/baz/bar/../../../../'; 40 | $this->assertTrue(isAboveRoot($path)); 41 | } 42 | 43 | public function testIsAboveRoot2() 44 | { 45 | $path = '/foo/baz/bar/../../../..'; 46 | $this->assertTrue(isAboveRoot($path)); 47 | } 48 | 49 | public function testIsAboveRoot3() 50 | { 51 | $path = '/foo/baz/bar/../../..'; 52 | $this->assertTrue(!isAboveRoot($path)); 53 | } 54 | 55 | public function testIsAboveRoot4() 56 | { 57 | $path = '/foo/baz/bar/../..'; 58 | $this->assertTrue(!isAboveRoot($path)); 59 | } 60 | } -------------------------------------------------------------------------------- /tests/NamespaceRefactoringTest.php: -------------------------------------------------------------------------------- 1 | assertEquals(trim($results), "Hello"); 20 | } 21 | 22 | public function testsFunctionExists() 23 | { 24 | $this->assertTrue(function_exists('glob_recursive')); 25 | } 26 | 27 | // public function testNamespaceCalledFrom() 28 | // { 29 | // $namespace = getNamespaceCalledFrom(); 30 | // $this->assertEquals($namespace, __NAMESPACE__); 31 | // } 32 | // 33 | // public function testNamespaceCalledFromFunction() 34 | // { 35 | // $namespace = cleverHackToTestReflectionFunction(); 36 | // $this->assertEquals($namespace, __NAMESPACE__); 37 | // } 38 | } 39 | 40 | function cleverHackToTestReflectionFunction() 41 | { 42 | return getNamespaceCalledFrom(); 43 | } 44 | 45 | /** 46 | * @command library 47 | */ 48 | function pestle_cli() 49 | { 50 | } -------------------------------------------------------------------------------- /tests/PestleBaseTest.php: -------------------------------------------------------------------------------- 1 | assertTrue(true); 25 | } 26 | 27 | protected function getPathToModuleFileUnderTest($file) 28 | { 29 | return __DIR__ . '/../' . $file; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tests/PhpCollideTest.php: -------------------------------------------------------------------------------- 1 | assertTrue($function_exists); 12 | //undoing magic conversion of php global 13 | //functions for the time being. 14 | $this->assertTrue(true); 15 | } 16 | } -------------------------------------------------------------------------------- /tests/RunnerTestHarnessTest.php: -------------------------------------------------------------------------------- 1 | runCommand('hello_world')); 9 | $this->assertEquals('Hello Sailor', $results); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/SimpleXmlAddNodesXpathTest.php: -------------------------------------------------------------------------------- 1 | assertEquals(-1, -1); 13 | } 14 | 15 | public function testBaseline() 16 | { 17 | $xml = simplexml_load_string(''); 18 | $node = simpleXmlAddNodesXpath($xml, 'foo/bar[@baz=hello]/science'); 19 | 20 | $this->assertTrue( 21 | strpos( 22 | $xml->asXml(), 23 | '' 24 | ) !== false 25 | ); 26 | 27 | $this->assertEquals($node->getName(), 'science'); 28 | } 29 | 30 | public function testSimpleXmlAddNodesXpathReturnOriginal() 31 | { 32 | $xml = simplexml_load_string(''); 33 | $node = simpleXmlAddNodesXpathReturnOriginal($xml, 'foo/bar[@baz=hello]/science'); 34 | 35 | $this->assertTrue( 36 | strpos( 37 | $xml->asXml(), 38 | '' 39 | ) !== false 40 | ); 41 | 42 | $this->assertEquals($node->getName(), 'root'); 43 | } 44 | } -------------------------------------------------------------------------------- /tests/WindowsTest.php: -------------------------------------------------------------------------------- 1 | assertTrue(is_dir($dir)); 12 | } 13 | 14 | public function testGetExecutableFromPath() { 15 | $unix = pestleGetExecutableFromPath('/foo/baz/bar'); 16 | $windows = pestleGetExecutableFromPath('\sing\a\song'); 17 | 18 | $this->assertEquals($unix, 'bar'); 19 | $this->assertEquals($windows, 'song'); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /tests/fixtures/AdminClassName/BaseAdminArgs.php: -------------------------------------------------------------------------------- 1 | resultPageFactory = $resultPageFactory; 14 | parent::__construct($context); 15 | } 16 | 17 | public function execute() 18 | { 19 | return $this->resultPageFactory->create(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /tests/fixtures/AdminClassName/BaseFrontendArgs.php: -------------------------------------------------------------------------------- 1 | resultPageFactory = $resultPageFactory; 12 | parent::__construct($context); 13 | } 14 | 15 | public function execute() 16 | { 17 | return $this->resultPageFactory->create(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /tests/fixtures/FunctionNameParsing/ConfirmableTrait.php: -------------------------------------------------------------------------------- 1 | getDefaultConfirmCallback() : $callback; 31 | 32 | $shouldConfirm = $callback instanceof Closure ? call_user_func($callback) : $callback; 33 | 34 | if ($shouldConfirm) { 35 | if ($this->option('force')) { 36 | return true; 37 | } 38 | 39 | $this->alert($warning); 40 | 41 | $confirmed = $this->confirm('Do you really wish to run this command?'); 42 | 43 | if (! $confirmed) { 44 | $this->comment('Command Cancelled!'); 45 | 46 | return false; 47 | } 48 | } 49 | 50 | return true; 51 | } 52 | 53 | /** 54 | * Get the default confirmation callback. 55 | * 56 | * @return \Closure 57 | */ 58 | protected function getDefaultConfirmCallback() 59 | { 60 | return function () { 61 | return $this->getLaravel()->environment() == 'production'; 62 | }; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /tests/fixtures/FunctionNameParsing/DetectsApplicationNamespace.php: -------------------------------------------------------------------------------- 1 | getNamespace(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /tests/fixtures/FunctionNameParsing/OutputStyle.php: -------------------------------------------------------------------------------- 1 | output = $output; 38 | 39 | parent::__construct($input, $output); 40 | } 41 | 42 | /** 43 | * Returns whether verbosity is quiet (-q). 44 | * 45 | * @return bool 46 | */ 47 | public function isQuiet() 48 | { 49 | return $this->output->isQuiet(); 50 | } 51 | 52 | /** 53 | * Returns whether verbosity is verbose (-v). 54 | * 55 | * @return bool 56 | */ 57 | public function isVerbose() 58 | { 59 | return $this->output->isVerbose(); 60 | } 61 | 62 | /** 63 | * Returns whether verbosity is very verbose (-vv). 64 | * 65 | * @return bool 66 | */ 67 | public function isVeryVerbose() 68 | { 69 | return $this->output->isVeryVerbose(); 70 | } 71 | 72 | /** 73 | * Returns whether verbosity is debug (-vvv). 74 | * 75 | * @return bool 76 | */ 77 | public function isDebug() 78 | { 79 | return $this->output->isDebug(); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /travis/for-lint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ## Our travis CI/CD will run this script from the root of a Magento 4 | ## folder. Put pestle commands here to generate code in the 5 | ## Pulsestorm_Travis module. At the end of the CI we'll run phpcs 6 | ## against this folder to ensure generate code 7 | 8 | 9 | ## putting some basic files in place so we can merge and tackle 10 | ## the "phpcs-ification" of things in stages 11 | mkdir -p app/code/Pulsestorm/Travis 12 | printf " app/code/Pulsestorm/Travis/Test.php 13 | 14 | ## test generate:crud-model, rm InstallSchema backup file 15 | pestle.phar magento2:generate:crud-model Pulsestorm_Travis Thing 16 | find app/code/Pulsestorm/Travis -type f -name '*.bak*' -exec rm '{}' \; -------------------------------------------------------------------------------- /travis/travis-ci-apache: -------------------------------------------------------------------------------- 1 | 2 | # [...] 3 | 4 | 5 | Options FollowSymLinks MultiViews ExecCGI 6 | AllowOverride All 7 | Order deny,allow 8 | Allow from all 9 | Require all granted 10 | 11 | 12 | # Wire up Apache to use Travis CI's php-fpm. 13 | 14 | 15 | Require all granted 16 | 17 | AddHandler php5-fcgi .php 18 | Action php5-fcgi /php5-fcgi 19 | Alias /php5-fcgi /usr/lib/cgi-bin/php5-fcgi 20 | FastCgiExternalServer /usr/lib/cgi-bin/php5-fcgi -host 127.0.0.1:9000 -pass-header Authorization 21 | 22 | 23 | ServerName magento-2-travis.dev 24 | ServerAlias www.magento-2-travis.dev 25 | DocumentRoot %TRAVIS_BUILD_DIR%/magento2/pub 26 | 27 | 28 | # [...] 29 | --------------------------------------------------------------------------------