├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── behat.yml.dist ├── circle.yml ├── composer.json ├── composer.lock ├── config ├── docker │ ├── fpm.conf │ ├── mysql.cnf │ ├── nginx.conf │ └── php.ini └── sync │ ├── .gitkeep │ └── .htaccess ├── docker-compose.yml.dist ├── drush ├── README.md └── policy.drush.inc ├── phpunit.xml.dist ├── scripts ├── composer │ └── ScriptHandler.php ├── docker-up.sh └── install-demo.sh ├── tests ├── failures │ └── .gitkeep └── features │ ├── bootstrap │ ├── FailureContext.php │ └── FeatureContext.php │ ├── cart_block.feature │ ├── checkout.feature │ ├── digital_checkout.feature │ └── product.feature └── web ├── .csslintrc ├── .editorconfig ├── .eslintignore ├── .eslintrc ├── .eslintrc.json ├── .gitattributes ├── .htaccess ├── autoload.php ├── index.php ├── robots.txt ├── sites ├── default │ ├── default.services.yml │ ├── default.settings.php │ ├── services.yml │ ├── settings.local.php │ └── settings.php ├── development.services.yml ├── example.settings.local.php └── example.sites.php ├── themes └── .gitkeep ├── update.php └── web.config /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore directories generated by Composer 2 | /bin/ 3 | /drush/contrib/ 4 | /vendor/ 5 | /web/core/ 6 | /web/modules/contrib/ 7 | /web/themes/contrib/ 8 | /web/profiles/contrib/ 9 | 10 | # Ignore Drupal's file directory 11 | /web/sites/*/files/ 12 | 13 | # Ignore SimpleTest multi-site environment. 14 | /web/sites/simpletest/ 15 | 16 | # Ignore files generated by PhpStorm 17 | /.idea/ 18 | 19 | # Ignore Behat test failures 20 | /tests/failures 21 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | php: 3 | - 5.6 4 | - 7.0 5 | 6 | sudo: false 7 | 8 | services: 9 | - docker 10 | 11 | addons: 12 | hosts: 13 | - commerce2.dev 14 | 15 | before_install: 16 | - echo 'sendmail_path = /bin/true' >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini 17 | - phpenv config-rm xdebug.ini 18 | - composer --version 19 | - docker-compose -f docker-compose.yml.dist build 20 | - docker-compose -f docker-compose.yml.dist pull 21 | - docker-compose -p commerce2 -f docker-compose.yml.dist up > /tmp/docker-compose.log & 22 | # Remove ~/travis/.my.cnf. Drush picks this up and ignores settings.local.php dburl for some reason. 23 | - rm ~travis/.my.cnf 24 | 25 | install: 26 | - git config --global github.accesstoken $GITHUB_OAUTH_TOKEN 27 | - composer config -g github-oauth.github.com $GITHUB_OAUTH_TOKEN 28 | - composer install --prefer-dist --no-interaction 29 | - phantomjs --webdriver=4444 & 30 | - mkdir web/sites/simpletest 31 | - docker inspect --format='{{(index (index .NetworkSettings.Ports "3306/tcp") 0).HostPort}}' commerce2_mariadb_1 32 | - ./bin/drush --root=$(pwd)/web si commerce_base --site-name="Commerce 2" --account-pass=admin --yes 33 | - ./scripts/install-demo.sh 34 | - curl -I http://commerce2.dev/ 35 | 36 | script: 37 | - cd $TRAVIS_BUILD_DIR 38 | - ./bin/phpunit --testsuite unit --group commerce 39 | - ./bin/phpunit --testsuite kernel --group commerce 40 | - ./bin/behat 41 | 42 | after_failure: 43 | - cat /tmp/docker-compose.log 44 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Drupal Commerce 2 Tests First project template 2 | 3 | [![CircleCI](https://circleci.com/gh/mglaman/commerce-project-template.svg?style=shield&circle-token=:circle-token)](https://circleci.com/gh/mglaman/commerce-project-template) [![Build Status](https://travis-ci.org/mglaman/commerce-project-template.svg?branch=master)](https://travis-ci.org/mglaman/commerce-project-template) 4 | 5 | Use [Composer](https://getcomposer.org/) to get Drupal + Commerce 2 + Testing with all dependencies. 6 | 7 | Based on [drupal-composer/drupal-project](https://github.com/drupalcommerce/project-base). 8 | 9 | ## Usage 10 | 11 | First you need to [install composer](https://getcomposer.org/doc/00-intro.md#installation-linux-unix-osx). 12 | 13 | > Note: The instructions below refer to the [global composer installation](https://getcomposer.org/doc/00-intro.md#globally). 14 | You might need to replace `composer` with `php composer.phar` (or similar) 15 | for your setup. 16 | 17 | After that you can create the project: 18 | 19 | ``` 20 | composer create-project mglaman/commerce-project-template some-dir --stability dev --no-interaction 21 | ``` 22 | 23 | Done! Use `composer require ...` to download additional modules and themes: 24 | 25 | ``` 26 | cd some-dir 27 | composer require "drupal/commerce_paypal:1.x-dev" 28 | ``` 29 | 30 | The `composer create-project` command passes ownership of all files to the 31 | project that is created. You should create a new git repository, and commit 32 | all files not excluded by the .gitignore file. 33 | 34 | ## What does the template do? 35 | 36 | * Drupal is installed in the `web` directory. 37 | * Modules (packages of type `drupal-module`) are placed in `web/modules/contrib/` 38 | * Theme (packages of type `drupal-theme`) are placed in `web/themes/contrib/` 39 | * Profiles (packages of type `drupal-profile`) are placed in `web/profiles/contrib/` 40 | * Creates default writable versions of `settings.php` and `services.yml`. 41 | * Creates the `sites/default/files` directory. 42 | * Latest version of DrupalConsole is installed locally for use at `bin/drupal`. 43 | * Initializes baseline Behat tests for Drupal Commerce. 44 | * Allows you to easily install a demo of Drupal Commerce. 45 | 46 | ## Updating Drupal Core 47 | 48 | This project will attempt to keep all of your Drupal Core files up-to-date; the 49 | project [drupal-composer/drupal-scaffold](https://github.com/drupal-composer/drupal-scaffold) 50 | is used to ensure that your scaffold files are updated every time drupal/core is 51 | updated. If you customize any of the "scaffolding" files (commonly .htaccess), 52 | you may need to merge conflicts if any of your modified files are updated in a 53 | new release of Drupal core. 54 | 55 | Follow the steps below to update your core files. 56 | 57 | 1. Run `composer update drupal/core --with-dependencies` to update Drupal Core and its dependencies. 58 | 1. Run `git diff` to determine if any of the scaffolding files have changed. 59 | Review the files for any changes and restore any customizations to 60 | `.htaccess` or `robots.txt`. 61 | 1. Commit everything all together in a single commit, so `web` will remain in 62 | sync with the `core` when checking out branches or running `git bisect`. 63 | 1. In the event that there are non-trivial conflicts in step 2, you may wish 64 | to perform these steps on a branch, and use `git merge` to combine the 65 | updated core files with your customized files. This facilitates the use 66 | of a [three-way merge tool such as kdiff3](http://www.gitshah.com/2010/12/how-to-setup-kdiff-as-diff-tool-for-git.html). This setup is not necessary if your changes are simple; 67 | keeping all of your modifications at the beginning or end of the file is a 68 | good strategy to keep merges easy. 69 | 70 | ## Generate composer.json from existing project 71 | 72 | With using [the "Composer Generate" drush extension](https://www.drupal.org/project/composer_generate) 73 | you can now generate a basic `composer.json` file from an existing project. Note 74 | that the generated `composer.json` might differ from this project's file. 75 | 76 | ## FAQ 77 | 78 | ### Should I commit the contrib modules I download? 79 | 80 | Composer recommends **no**. They provide [argumentation against but also 81 | workrounds if a project decides to do it anyway](https://getcomposer.org/doc/faqs/should-i-commit-the-dependencies-in-my-vendor-directory.md). 82 | 83 | ### Should I commit the scaffolding files? 84 | 85 | The [drupal-scaffold](https://github.com/drupal-composer/drupal-scaffold) plugin can download the scaffold files (like 86 | index.php, update.php, …) to the web/ directory of your project. If you have not customized those files you could choose 87 | to not check them into your version control system (e.g. git). If that is the case for your project it might be 88 | convenient to automatically run the drupal-scaffold plugin after every install or update of your project. You can 89 | achieve that by registering `@drupal-scaffold` as post-install and post-update command in your composer.json: 90 | 91 | ```json 92 | "scripts": { 93 | "drupal-scaffold": "DrupalComposer\\DrupalScaffold\\Plugin::scaffold", 94 | "post-install-cmd": [ 95 | "@drupal-scaffold", 96 | "..." 97 | ], 98 | "post-update-cmd": [ 99 | "@drupal-scaffold", 100 | "..." 101 | ] 102 | }, 103 | ``` 104 | ### How can I apply patches to downloaded modules? 105 | 106 | If you need to apply patches (depending on the project being modified, a pull 107 | request is often a better solution), you can do so with the 108 | [composer-patches](https://github.com/cweagans/composer-patches) plugin. 109 | 110 | To add a patch to drupal module foobar insert the patches section in the extra 111 | section of composer.json: 112 | ```json 113 | "extra": { 114 | "patches": { 115 | "drupal/foobar": { 116 | "Patch description": "URL to patch" 117 | } 118 | } 119 | } 120 | ``` 121 | -------------------------------------------------------------------------------- /behat.yml.dist: -------------------------------------------------------------------------------- 1 | default: 2 | autoload: 3 | - '%paths.base%/tests/features/bootstrap' 4 | suites: 5 | default: 6 | failure_path: '%paths.base%/tests/failures' 7 | paths: 8 | features: '%paths.base%/tests/features' 9 | contexts: 10 | - FailureContext 11 | - FeatureContext 12 | - Drupal\DrupalExtension\Context\DrupalContext 13 | - Drupal\DrupalExtension\Context\MinkContext 14 | - Drupal\DrupalExtension\Context\MessageContext 15 | - Drupal\DrupalExtension\Context\DrushContext 16 | - Drupal\CommerceBehat\Context\DrupalCommerceContext 17 | - Drupal\CommerceBehat\Context\DrupalCommerceCheckoutContext 18 | - Drupal\CommerceBehat\Context\DrupalCommerceProductContext 19 | extensions: 20 | Behat\MinkExtension: 21 | goutte: ~ 22 | selenium2: 23 | browser: phantomjs 24 | base_url: http://commerce2.dev 25 | Drupal\DrupalExtension: 26 | blackbox: ~ 27 | api_driver: 'drupal' 28 | drupal: 29 | drupal_root: 'web' 30 | -------------------------------------------------------------------------------- /circle.yml: -------------------------------------------------------------------------------- 1 | machine: 2 | php: 3 | version: 7.0.7 4 | pre: 5 | - curl -sSL https://s3.amazonaws.com/circle-downloads/install-circleci-docker.sh | bash -s -- 1.10.0 6 | services: 7 | - docker 8 | hosts: 9 | commerce2.dev: 127.0.0.1 10 | dependencies: 11 | cache_directories: 12 | - ~/.composer/cache 13 | pre: 14 | - echo "date.timezone = 'America/Chicago'" > /opt/circleci/php/7.0.7/etc/conf.d/xdebug.ini 15 | override: 16 | - pip install docker-compose 17 | - docker-compose -f docker-compose.yml.dist build 18 | - docker-compose -f docker-compose.yml.dist pull 19 | - docker-compose -p commerce2 -f docker-compose.yml.dist up: 20 | background: true 21 | - composer global require "hirak/prestissimo:^0.3" 22 | - git config --global github.accesstoken $GITHUB_OAUTH_TOKEN 23 | - composer config -g github-oauth.github.com $GITHUB_OAUTH_TOKEN 24 | - composer install --prefer-dist --no-interaction 25 | test: 26 | pre: 27 | - phantomjs --webdriver=4444: 28 | background: true 29 | - mkdir web/sites/simpletest 30 | - ./bin/drush --root=$(pwd)/web si commerce_base --site-name="Commerce 2" --account-pass=admin --yes 31 | - ./scripts/install-demo.sh 32 | - curl -I http://commerce2.dev/ 33 | override: 34 | - ./bin/phpunit --testsuite unit --group commerce 35 | - ./bin/phpunit --testsuite kernel --group commerce 36 | - ./bin/behat -f junit -o $CIRCLE_TEST_REPORTS -f pretty -o std 37 | general: 38 | artifacts: 39 | - "tests/failures" 40 | 41 | # deployment: 42 | # prod: 43 | # branch: master 44 | # commands: 45 | # - DRUPALVM_ENV=prod ansible-playbook \ 46 | # -i vm/inventory \ 47 | # vendor/geerlingguy/drupal-vm/provisioning/playbook.yml \ 48 | # -e "config_dir=$(pwd)/vm" \ 49 | # --sudo 50 | # --tags=drupal 51 | # --extra-vars "ansible_become_pass=${ANSIBLE_VAULT_PASSWORD}" 52 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mglaman/commerce-project-template", 3 | "description": "Commerce 2.x project template with Behat testing", 4 | "type": "project", 5 | "license": "GPL-2.0+", 6 | "authors": [ 7 | { 8 | "name": "Matt Glaman", 9 | "role": "" 10 | } 11 | ], 12 | "repositories": { 13 | "drupal": { 14 | "type": "composer", 15 | "url": "https://packages.drupal.org/8" 16 | }, 17 | "commerce_base": { 18 | "type": "vcs", 19 | "url": "https://github.com/drupalcommerce/commerce_base" 20 | }, 21 | "commerce_demo": { 22 | "type": "vcs", 23 | "url": "https://github.com/mglaman/commerce_demo" 24 | }, 25 | "commerce_behat": { 26 | "type": "vcs", 27 | "url": "https://github.com/mglaman/drupal-commerce-behat" 28 | } 29 | }, 30 | "config": { 31 | "bin-dir": "bin" 32 | }, 33 | "require": { 34 | "ext-curl": "*", 35 | "composer/installers": "^1.2", 36 | "drupal-composer/drupal-scaffold": "^2.2", 37 | "cweagans/composer-patches": "~1.0", 38 | "drupal/core": "~8.3.0", 39 | "drupal/console": "^1.0", 40 | "drush/drush": "^8.1", 41 | "drupal/commerce": "^2", 42 | "drupal/swiftmailer": "^1", 43 | "drupalcommerce/commerce_base": "dev-8.x-1.x", 44 | "drupal/admin_toolbar": "^1.20" 45 | }, 46 | "require-dev": { 47 | "behat/mink": "~1.7", 48 | "behat/mink-goutte-driver": "~1.2", 49 | "jcalderonzumba/gastonjs": "~1.0.2", 50 | "jcalderonzumba/mink-phantomjs-driver": "~0.3.1", 51 | "mikey179/vfsStream": "~1.2", 52 | "phpunit/phpunit": "~4.8", 53 | "symfony/css-selector": "~2.8", 54 | "drupal/drupal-extension": "^3.2", 55 | "drupal/commerce_behat": "dev-8.x-1.x" 56 | }, 57 | "conflict": { 58 | "drupal/drupal": "*" 59 | }, 60 | "minimum-stability": "dev", 61 | "prefer-stable": true, 62 | "autoload": { 63 | "classmap": [ 64 | "scripts/composer/ScriptHandler.php" 65 | ] 66 | }, 67 | "scripts": { 68 | "drupal-scaffold": "DrupalComposer\\DrupalScaffold\\Plugin::scaffold", 69 | "pre-install-cmd": [ 70 | "DrupalProject\\composer\\ScriptHandler::checkComposerVersion" 71 | ], 72 | "pre-update-cmd": [ 73 | "DrupalProject\\composer\\ScriptHandler::checkComposerVersion" 74 | ], 75 | "post-install-cmd": [ 76 | "DrupalProject\\composer\\ScriptHandler::createRequiredFiles" 77 | ], 78 | "post-update-cmd": [ 79 | "DrupalProject\\composer\\ScriptHandler::createRequiredFiles" 80 | ] 81 | }, 82 | "extra": { 83 | "installer-paths": { 84 | "web/core": [ 85 | "type:drupal-core" 86 | ], 87 | "web/libraries/{$name}": [ 88 | "type:drupal-library" 89 | ], 90 | "web/modules/contrib/{$name}": [ 91 | "type:drupal-module" 92 | ], 93 | "web/profiles/contrib/{$name}": [ 94 | "type:drupal-profile" 95 | ], 96 | "web/themes/contrib/{$name}": [ 97 | "type:drupal-theme" 98 | ], 99 | "drush/contrib/{$name}": [ 100 | "type:drupal-drush" 101 | ] 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /config/docker/fpm.conf: -------------------------------------------------------------------------------- 1 | [global] 2 | error_log = /proc/self/fd/2 3 | daemonize = no 4 | [www] 5 | user = root 6 | group = root 7 | 8 | php_admin_value[date.timezone] = 'America/New_York' 9 | php_admin_flag[short_open_tag] = off 10 | 11 | access.log = /proc/self/fd/2 12 | listen = [::]:9000 13 | pm = dynamic 14 | pm.max_children = 100 15 | pm.start_servers = 30 16 | pm.min_spare_servers = 10 17 | pm.max_spare_servers = 50 18 | catch_workers_output = yes 19 | -------------------------------------------------------------------------------- /config/docker/mysql.cnf: -------------------------------------------------------------------------------- 1 | [client] 2 | port = 3306 3 | socket = /var/run/mysqld/mysqld.sock 4 | 5 | [mysqld_safe] 6 | pid-file = /var/run/mysqld/mysqld.pid 7 | socket = /var/run/mysqld/mysqld.sock 8 | nice = 0 9 | 10 | [mysqld] 11 | user = mysql 12 | pid-file = /var/run/mysqld/mysqld.pid 13 | socket = /var/run/mysqld/mysqld.sock 14 | port = 3306 15 | basedir = /usr 16 | datadir = /var/lib/mysql 17 | tmpdir = /tmp 18 | lc-messages-dir = /usr/share/mysql 19 | explicit_defaults_for_timestamp 20 | 21 | # Instead of skip-networking the default is now to listen only on 22 | # localhost which is more compatible and is not less secure. 23 | bind-address = 0.0.0.0 24 | 25 | log-error = /var/log/mysql/error.log 26 | 27 | # Recommended in standard MySQL setup 28 | sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES 29 | 30 | # Disabling symbolic-links is recommended to prevent assorted security risks 31 | symbolic-links=0 32 | 33 | # Drupal DB tweaks - https://groups.drupal.org/node/289613 34 | key_buffer_size = 32M 35 | max_allowed_packet = 16M 36 | tmp_table_size = 64M 37 | max_heap_table_size = 64M 38 | query_cache_size = 16M 39 | query_cache_limit = 1m 40 | thread_cache_size = 128 41 | 42 | # * IMPORTANT: Additional settings that can override those from this file! 43 | # The files must end with '.cnf', otherwise they'll be ignored. 44 | # 45 | !includedir /etc/mysql/conf.d/ 46 | -------------------------------------------------------------------------------- /config/docker/nginx.conf: -------------------------------------------------------------------------------- 1 | upstream phpfcgi { 2 | server phpfpm:9000; 3 | } 4 | 5 | server { 6 | listen 80 default_server; 7 | listen [::]:80 default_server ipv6only=on; 8 | 9 | server_name commerce2.dev; 10 | 11 | root /app/web; 12 | 13 | # strip index.php/ prefix if it is present 14 | rewrite ^/index\.php/?(.*)$ /$1 permanent; 15 | 16 | 17 | location / { 18 | sendfile off; 19 | index index.php; 20 | try_files $uri @rewriteapp; 21 | } 22 | 23 | location @rewriteapp { 24 | rewrite ^(.*)$ /index.php/$1 last; 25 | } 26 | 27 | # pass the PHP scripts to FastCGI server from upstream phpfcgi 28 | location ~ \.php(/|$) { 29 | fastcgi_pass phpfcgi; 30 | fastcgi_split_path_info ^(.+\.php)(/.*)$; 31 | fastcgi_read_timeout 180; 32 | include fastcgi_params; 33 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 34 | fastcgi_param HTTPS off; 35 | # Allow access to /app_dev.php & /config.php 36 | fastcgi_param REMOTE_ADDR 127.0.0.1; 37 | fastcgi_param APP_DOCKER "APP_DOCKER"; 38 | fastcgi_param PHP_IDE_CONFIG "serverName=commerce2.dev"; 39 | fastcgi_buffers 16 16k; 40 | fastcgi_buffer_size 32k; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /config/docker/php.ini: -------------------------------------------------------------------------------- 1 | memory_limit=512M 2 | date.timezone=America/Chicago 3 | max_execution_time = 180 4 | [xdebug] 5 | zend_extension=xdebug.so 6 | xdebug.max_nesting_level=256 7 | xdebug.remote_enable=1 8 | xdebug.remote_autostart=0 9 | xdebug.remote_connect_back=0 10 | ; This is IP for Docker for Mac. 11 | xdebug.remote_host=192.168.65.1 12 | xdebug.remote_port=9000 13 | xdebug.remote_log=/tmp/php5-xdebug.log 14 | 15 | [opcache] 16 | opcache.enable=1 17 | opcache.memory_consumption=192 18 | opcache.interned_strings_buffer=16 19 | opcache.max_accelerated_files=4000 20 | opcache.fast_shutdown=1 21 | opcache.validate_timestamps=1 22 | opcache.revalidate_freq=0 23 | -------------------------------------------------------------------------------- /config/sync/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mglaman/commerce-project-template/4e5416869ddfbc318f3219c4fa6234945bbe0e7c/config/sync/.gitkeep -------------------------------------------------------------------------------- /config/sync/.htaccess: -------------------------------------------------------------------------------- 1 | # Deny all requests from Apache 2.4+. 2 | 3 | Require all denied 4 | 5 | 6 | # Deny all requests from Apache 2.0-2.2. 7 | 8 | Deny from all 9 | 10 | # Turn off all options we don't need. 11 | Options -Indexes -ExecCGI -Includes -MultiViews 12 | 13 | # Set the catch-all handler to prevent scripts from being executed. 14 | SetHandler Drupal_Security_Do_Not_Remove_See_SA_2006_006 15 | 16 | # Override the handler again if we're run later in the evaluation list. 17 | SetHandler Drupal_Security_Do_Not_Remove_See_SA_2013_003 18 | 19 | 20 | # If we know how to do it safely, disable the PHP engine entirely. 21 | 22 | php_flag engine off 23 | -------------------------------------------------------------------------------- /docker-compose.yml.dist: -------------------------------------------------------------------------------- 1 | phpfpm: 2 | command: 'php-fpm --allow-to-run-as-root' 3 | image: 'mglaman/docker-php-bcmath:7.0-fpm' 4 | volumes: 5 | - './:/app' 6 | - './config/docker/fpm.conf:/usr/local/etc/php-fpm.conf' 7 | - './config/docker/php.ini:/usr/local/etc/php/conf.d/local.ini' 8 | links: 9 | - mariadb 10 | #- solr 11 | - mailhog 12 | environment: { APP_DOCKER: commerce2, PHP_IDE_CONFIG: serverName=commerce2.dev } 13 | mariadb: 14 | command: 'mysqld --verbose' 15 | image: mariadb 16 | ports: 17 | - 3306 18 | volumes: 19 | - './config/docker/mysql.cnf:/etc/mysql/my.cnf' 20 | environment: { MYSQL_DATABASE: data, MYSQL_USER: mysql, MYSQL_PASSWORD: mysql, MYSQL_ALLOW_EMPTY_PASSWORD: 'yes', MYSQL_ROOT_PASSWORD: 'root' } 21 | nginx: 22 | image: 'nginx:1.9.0' 23 | volumes: 24 | - './config/docker/nginx.conf:/etc/nginx/conf.d/default.conf' 25 | - './:/app' 26 | ports: 27 | - 80:80 28 | links: 29 | - phpfpm 30 | environment: { VIRTUAL_HOST: commerce2, APP_DOCKER: commerce2 } 31 | #solr: 32 | # image: 'makuk66/docker-solr:4.10.4' 33 | # ports: ['8080'] 34 | # volumes: ['./config/solr:/opt/solr/example/solr/collection1/conf'] 35 | # entrypoint: ["/bin/bash", "-c", "/opt/solr/bin/solr -f -p 8080"] 36 | mailhog: 37 | image: 'mailhog/mailhog' 38 | ports: 39 | - 8025 40 | -------------------------------------------------------------------------------- /drush/README.md: -------------------------------------------------------------------------------- 1 | This directory contains commands, configuration and site aliases for Drush. See http://packages.drush.org/ for a directory of Drush commands installable via Composer. 2 | -------------------------------------------------------------------------------- /drush/policy.drush.inc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 12 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | ./web/core/tests/TestSuites/UnitTestSuite.php 35 | 36 | 37 | ./web/core/tests/TestSuites/KernelTestSuite.php 38 | 39 | 40 | ./web/core/tests/TestSuites/FunctionalTestSuite.php 41 | 42 | 43 | ./web/core/tests/TestSuites/FunctionalJavascriptTestSuite.php 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | ./web/core/includes 54 | ./web/core/lib 55 | ./web/core/modules 56 | ../web/modules 57 | ../web/sites 58 | 59 | 60 | ./ 61 | ./ 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /scripts/composer/ScriptHandler.php: -------------------------------------------------------------------------------- 1 | exists($root . '/'. $dir)) { 33 | $fs->mkdir($root . '/'. $dir); 34 | $fs->touch($root . '/'. $dir . '/.gitkeep'); 35 | } 36 | } 37 | 38 | // Prepare the settings file for installation 39 | if (!$fs->exists($root . '/sites/default/settings.php') and $fs->exists($root . '/sites/default/default.settings.php')) { 40 | $fs->copy($root . '/sites/default/default.settings.php', $root . '/sites/default/settings.php'); 41 | $fs->chmod($root . '/sites/default/settings.php', 0666); 42 | $event->getIO()->write("Create a sites/default/settings.php file with chmod 0666"); 43 | } 44 | 45 | // Prepare the services file for installation 46 | if (!$fs->exists($root . '/sites/default/services.yml') and $fs->exists($root . '/sites/default/default.services.yml')) { 47 | $fs->copy($root . '/sites/default/default.services.yml', $root . '/sites/default/services.yml'); 48 | $fs->chmod($root . '/sites/default/services.yml', 0666); 49 | $event->getIO()->write("Create a sites/default/services.yml file with chmod 0666"); 50 | } 51 | 52 | // Create the files directory with chmod 0777 53 | if (!$fs->exists($root . '/sites/default/files')) { 54 | $oldmask = umask(0); 55 | $fs->mkdir($root . '/sites/default/files', 0777); 56 | umask($oldmask); 57 | $event->getIO()->write("Create a sites/default/files directory with chmod 0777"); 58 | } 59 | } 60 | 61 | /** 62 | * Checks if the installed version of Composer is compatible. 63 | * 64 | * Composer 1.0.0 and higher consider a `composer install` without having a 65 | * lock file present as equal to `composer update`. We do not ship with a lock 66 | * file to avoid merge conflicts downstream, meaning that if a project is 67 | * installed with an older version of Composer the scaffolding of Drupal will 68 | * not be triggered. We check this here instead of in drupal-scaffold to be 69 | * able to give immediate feedback to the end user, rather than failing the 70 | * installation after going through the lengthy process of compiling and 71 | * downloading the Composer dependencies. 72 | * 73 | * @see https://github.com/composer/composer/pull/5035 74 | */ 75 | public static function checkComposerVersion(Event $event) { 76 | $composer = $event->getComposer(); 77 | $io = $event->getIO(); 78 | 79 | $version = $composer::VERSION; 80 | 81 | // The dev-channel of composer uses the git revision as version number, 82 | // try to the branch alias instead. 83 | if (preg_match('/^[0-9a-f]{40}$/i', $version)) { 84 | $version = $composer::BRANCH_ALIAS_VERSION; 85 | } 86 | 87 | // If Composer is installed through git we have no easy way to determine if 88 | // it is new enough, just display a warning. 89 | if ($version === '@package_version@' || $version === '@package_branch_alias_version@') { 90 | $io->writeError('You are running a development version of Composer. If you experience problems, please update Composer to the latest stable version.'); 91 | } 92 | elseif (Comparator::lessThan($version, '1.0.0')) { 93 | $io->writeError('Drupal-project requires Composer version 1.0.0 or higher. Please update your Composer before continuing.'); 94 | exit(1); 95 | } 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /scripts/docker-up.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | docker-compose -p commerce2 -f docker-compose.yml.dist build 3 | docker-compose -p commerce2 -f docker-compose.yml.dist pull 4 | docker-compose -p commerce2 -f docker-compose.yml.dist up -d 5 | -------------------------------------------------------------------------------- /scripts/install-demo.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | composer config repositories.commerce_demo vcs https://github.com/mglaman/commerce_demo 3 | composer require drupal/commerce_demo *@dev 4 | echo $(pwd) 5 | ./bin/drush --root=$(pwd)/web en -y commerce_demo -y 6 | ./bin/drush --root=$(pwd)/web cr 7 | ./bin/drush --root=$(pwd)/web cc drush 8 | ./bin/drush --root=$(pwd)/web mi --all 9 | -------------------------------------------------------------------------------- /tests/failures/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mglaman/commerce-project-template/4e5416869ddfbc318f3219c4fa6234945bbe0e7c/tests/failures/.gitkeep -------------------------------------------------------------------------------- /tests/features/bootstrap/FailureContext.php: -------------------------------------------------------------------------------- 1 | contexts['mink'] = $scope->getEnvironment()->getContext('Drupal\DrupalExtension\Context\MinkContext'); 21 | $this->failurePath = $scope->getEnvironment()->getSuite()->getSetting('failure_path'); 22 | } 23 | 24 | /** 25 | * @AfterStep 26 | */ 27 | public function handleFailure(AfterStepScope $scope) { 28 | 29 | if (99 !== $scope->getTestResult()->getResultCode()) { 30 | return; 31 | } 32 | 33 | $fileName = $this->fileName($scope); 34 | $this->dumpMarkup($fileName); 35 | $this->screenShot($fileName); 36 | } 37 | 38 | /** 39 | * @Then /^I take an awesome screenshot$/ 40 | */ 41 | public function takeScreenShot() { 42 | $fileName = $this->fileName(); 43 | $this->dumpMarkup($fileName); 44 | $this->screenShot($fileName); 45 | } 46 | 47 | /** 48 | * @Then /^I take a markup dump$/ 49 | */ 50 | public function takeMarkupDump() { 51 | $this->dumpMarkup($this->fileName()); 52 | } 53 | 54 | /** 55 | * Compute a file name for the output. 56 | */ 57 | protected function fileName($scope = NULL) { 58 | if ($scope) { 59 | $baseName = pathinfo($scope->getFeature()->getFile()); 60 | $baseName = substr($baseName['basename'], 0 , strlen($baseName['basename']) - strlen($baseName['extension']) - 1); 61 | $baseName .= '-' . $scope->getStep()->getLine(); 62 | } 63 | else { 64 | $baseName = 'failure'; 65 | } 66 | 67 | $baseName .= '-' . date('YmdHis'); 68 | $baseName = $this->failurePath . '/' . $baseName; 69 | return $baseName; 70 | } 71 | 72 | /** 73 | * Save the markup from the failed step. 74 | */ 75 | protected function dumpMarkup($fileName) { 76 | $fileName .= '.html'; 77 | $html = $this->contexts['mink']->getSession()->getPage()->getContent(); 78 | file_put_contents($fileName, $html); 79 | sprintf("HTML available at: %s\n", $fileName); 80 | } 81 | 82 | /** 83 | * Save a screen shot from the failed step. 84 | */ 85 | protected function screenShot($fileName) { 86 | $fileName .= '.png'; 87 | $driver = $this->contexts['mink']->getSession()->getDriver(); 88 | 89 | if ($driver instanceof Selenium2Driver) { 90 | file_put_contents($fileName, $this->contexts['mink']->getSession()->getDriver()->getScreenshot()); 91 | sprintf("Screen shot available at: %s\n", $fileName); 92 | return; 93 | } 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /tests/features/bootstrap/FeatureContext.php: -------------------------------------------------------------------------------- 1 | getSession(); 31 | $element = $session->getPage()->find( 32 | 'xpath', 33 | $session->getSelectorsHandler()->selectorToXpath('xpath', $selector) 34 | ); 35 | if (null === $element) { 36 | throw new \InvalidArgumentException(sprintf('Cannot find: "%s"', $selector)); 37 | } 38 | 39 | $element->click(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /tests/features/cart_block.feature: -------------------------------------------------------------------------------- 1 | Feature: Cart block 2 | I should see the cart block 3 | As a customer 4 | So that I can work with my order 5 | 6 | Scenario: I can see the cart block 7 | Given I am on the homepage 8 | Then I should see "0 items" 9 | -------------------------------------------------------------------------------- /tests/features/checkout.feature: -------------------------------------------------------------------------------- 1 | Feature: I can checkout 2 | I can access checkout 3 | As a customer 4 | So I can buy stuff 5 | 6 | Scenario: Anonymous users can access checkout 7 | When anonymous checkout is enabled 8 | And I am on "/product/1" 9 | Then I should see "Commerce Guys Hoodie" 10 | When I press "Add to cart" 11 | Then I should see "Commerce Guys Hoodie - Cyan, Small added to your cart." 12 | And I click "your cart" 13 | Then I press "Checkout" 14 | 15 | Scenario: Anonymous users cannot access checkout 16 | When anonymous checkout is disabled 17 | And I am on "/product/1" 18 | Then I should see "Commerce Guys Hoodie" 19 | When I press "Add to cart" 20 | Then I should see "Commerce Guys Hoodie - Cyan, Small added to your cart." 21 | And I click "your cart" 22 | Then I should not see the button "Checkout" 23 | -------------------------------------------------------------------------------- /tests/features/digital_checkout.feature: -------------------------------------------------------------------------------- 1 | Feature: Digital order checkout 2 | I can buy an ebook 3 | As a customer 4 | Without entering shipping information 5 | 6 | 7 | Scenario: I can buy an eBook 8 | When anonymous checkout is enabled 9 | Given I am on "/product/3" 10 | Then I should see "Drupal 8 Development Cookbook" 11 | When I press "Add to cart" 12 | Then I should see "Drupal 8 Development Cookbook added to your cart." 13 | And I click "your cart" 14 | And I press "Checkout" 15 | Then I press "Continue as Guest" 16 | Then I fill in the following: 17 | | payment_information[add_payment_method][payment_details][security_code] | 123 | 18 | | contact_information[email] | test@example | 19 | | contact_information[email_confirm] | test@example | 20 | | payment_information[add_payment_method][billing_information][address][0][address][given_name] | John | 21 | | payment_information[add_payment_method][billing_information][address][0][address][family_name] | Doe | 22 | | payment_information[add_payment_method][billing_information][address][0][address][address_line1] | 222222 | 23 | | payment_information[add_payment_method][billing_information][address][0][address][postal_code] | 94043 | 24 | | payment_information[add_payment_method][billing_information][address][0][address][locality] | Mountain View | 25 | | payment_information[add_payment_method][billing_information][address][0][address][administrative_area] | CA | 26 | And I press "Continue to review" 27 | And I press "Pay and complete purchase" 28 | Then I should see "You can view your order on your account page when logged in" 29 | -------------------------------------------------------------------------------- /tests/features/product.feature: -------------------------------------------------------------------------------- 1 | Feature: View a product 2 | I can view a product 3 | As a customer 4 | So I can give you my money. 5 | 6 | Scenario: Viewing product 7 | Given I am on "/product/1" 8 | Then I should see "Commerce Guys Hoodie" 9 | And I should see "Commerce Guys Hoodie - Cyan, Small" 10 | And I should see "15080-009-SC" 11 | 12 | @javascript 13 | Scenario: Changing product attributes in the cart 14 | Given I am on "/product/1" 15 | When I click on the text "//label[.//span[text()='Yellow']]" 16 | And I wait for AJAX to finish 17 | Then I should see "Commerce Guys Hoodie - Yellow, Small" 18 | And I should see "15080-009-SY" 19 | When I select "Large" from "Size" 20 | And I wait for AJAX to finish 21 | Then I should see "Commerce Guys Hoodie - Yellow, Large" 22 | And I should see "15080-009-LY" 23 | When I click on the text "//label[.//span[text()='Cyan']]" 24 | And I wait for AJAX to finish 25 | Then I should see "Commerce Guys Hoodie - Cyan, Large" 26 | And I should see "15080-009-LC" 27 | 28 | @javascript 29 | Scenario: Select a variation and add to cart 30 | Given I am on "/product/1" 31 | When I select "Large" from "Size" 32 | And I wait for AJAX to finish 33 | Then I should see "Commerce Guys Hoodie - Cyan, Large" 34 | And I should see "15080-009-LC" 35 | When I press "Add to cart" 36 | Then I should see "Commerce Guys Hoodie - Cyan, Large added to your cart." 37 | -------------------------------------------------------------------------------- /web/.csslintrc: -------------------------------------------------------------------------------- 1 | --errors=box-model, 2 | display-property-grouping, 3 | duplicate-background-images, 4 | duplicate-properties, 5 | empty-rules, 6 | ids, 7 | import, 8 | important, 9 | known-properties, 10 | outline-none, 11 | overqualified-elements, 12 | qualified-headings, 13 | shorthand, 14 | star-property-hack, 15 | text-indent, 16 | underscore-property-hack, 17 | unique-headings, 18 | unqualified-attributes, 19 | vendor-prefix, 20 | zero-units 21 | --ignore=adjoining-classes, 22 | box-sizing, 23 | bulletproof-font-face, 24 | compatible-vendor-prefixes, 25 | errors, 26 | fallback-colors, 27 | floats, 28 | font-faces, 29 | font-sizes, 30 | gradients, 31 | import-ie-limit, 32 | order-alphabetical, 33 | regex-selectors, 34 | rules-count, 35 | selector-max, 36 | selector-max-approaching, 37 | selector-newline, 38 | universal-selector 39 | --exclude-list=core/assets, 40 | vendor 41 | -------------------------------------------------------------------------------- /web/.editorconfig: -------------------------------------------------------------------------------- 1 | # Drupal editor configuration normalization 2 | # @see http://editorconfig.org/ 3 | 4 | # This is the top-most .editorconfig file; do not search in parent directories. 5 | root = true 6 | 7 | # All files. 8 | [*] 9 | end_of_line = LF 10 | indent_style = space 11 | indent_size = 2 12 | charset = utf-8 13 | trim_trailing_whitespace = true 14 | insert_final_newline = true 15 | 16 | [composer.json] 17 | indent_size = 4 18 | -------------------------------------------------------------------------------- /web/.eslintignore: -------------------------------------------------------------------------------- 1 | core/assets/vendor/**/* 2 | core/modules/locale/tests/locale_test.js 3 | vendor/**/* 4 | sites/**/files/**/* 5 | libraries/**/* 6 | sites/**/libraries/**/* 7 | profiles/**/libraries/**/* 8 | **/js_test_files/**/* 9 | **/node_modules/**/* 10 | -------------------------------------------------------------------------------- /web/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./core/.eslintrc" 3 | } 4 | -------------------------------------------------------------------------------- /web/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./core/.eslintrc.json" 3 | } 4 | -------------------------------------------------------------------------------- /web/.gitattributes: -------------------------------------------------------------------------------- 1 | # Drupal git normalization 2 | # @see https://www.kernel.org/pub/software/scm/git/docs/gitattributes.html 3 | # @see https://www.drupal.org/node/1542048 4 | 5 | # Normally these settings would be done with macro attributes for improved 6 | # readability and easier maintenance. However macros can only be defined at the 7 | # repository root directory. Drupal avoids making any assumptions about where it 8 | # is installed. 9 | 10 | # Define text file attributes. 11 | # - Treat them as text. 12 | # - Ensure no CRLF line-endings, neither on checkout nor on checkin. 13 | # - Detect whitespace errors. 14 | # - Exposed by default in `git diff --color` on the CLI. 15 | # - Validate with `git diff --check`. 16 | # - Deny applying with `git apply --whitespace=error-all`. 17 | # - Fix automatically with `git apply --whitespace=fix`. 18 | 19 | *.config text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 20 | *.css text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 21 | *.dist text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 22 | *.engine text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php 23 | *.html text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=html 24 | *.inc text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php 25 | *.install text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php 26 | *.js text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 27 | *.json text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 28 | *.lock text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 29 | *.map text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 30 | *.md text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 31 | *.module text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php 32 | *.php text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php 33 | *.po text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 34 | *.profile text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php 35 | *.script text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 36 | *.sh text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php 37 | *.sql text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 38 | *.svg text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 39 | *.theme text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php 40 | *.twig text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 41 | *.txt text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 42 | *.xml text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 43 | *.yml text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 44 | 45 | # Define binary file attributes. 46 | # - Do not treat them as text. 47 | # - Include binary diff in patches instead of "binary files differ." 48 | *.gif -text diff 49 | *.gz -text diff 50 | *.ico -text diff 51 | *.jpeg -text diff 52 | *.jpg -text diff 53 | *.png -text diff 54 | *.phar -text diff 55 | *.exe -text diff 56 | *.svgz -text diff 57 | *.ttf -text diff 58 | -------------------------------------------------------------------------------- /web/.htaccess: -------------------------------------------------------------------------------- 1 | # 2 | # Apache/PHP/Drupal settings: 3 | # 4 | 5 | # Protect files and directories from prying eyes. 6 | 7 | 8 | Require all denied 9 | 10 | 11 | Order allow,deny 12 | 13 | 14 | 15 | # Don't show directory listings for URLs which map to a directory. 16 | Options -Indexes 17 | 18 | # Set the default handler. 19 | DirectoryIndex index.php index.html index.htm 20 | 21 | # Add correct encoding for SVGZ. 22 | AddType image/svg+xml svg svgz 23 | AddEncoding gzip svgz 24 | 25 | # Most of the following PHP settings cannot be changed at runtime. See 26 | # sites/default/default.settings.php and 27 | # Drupal\Core\DrupalKernel::bootEnvironment() for settings that can be 28 | # changed at runtime. 29 | 30 | # PHP 5, Apache 1 and 2. 31 | 32 | php_value assert.active 0 33 | php_flag session.auto_start off 34 | php_value mbstring.http_input pass 35 | php_value mbstring.http_output pass 36 | php_flag mbstring.encoding_translation off 37 | # PHP 5.6 has deprecated $HTTP_RAW_POST_DATA and produces warnings if this is 38 | # not set. 39 | php_value always_populate_raw_post_data -1 40 | 41 | 42 | # Requires mod_expires to be enabled. 43 | 44 | # Enable expirations. 45 | ExpiresActive On 46 | 47 | # Cache all files for 2 weeks after access (A). 48 | ExpiresDefault A1209600 49 | 50 | 51 | # Do not allow PHP scripts to be cached unless they explicitly send cache 52 | # headers themselves. Otherwise all scripts would have to overwrite the 53 | # headers set by mod_expires if they want another caching behavior. This may 54 | # fail if an error occurs early in the bootstrap process, and it may cause 55 | # problems if a non-Drupal PHP file is installed in a subdirectory. 56 | ExpiresActive Off 57 | 58 | 59 | 60 | # Set a fallback resource if mod_rewrite is not enabled. This allows Drupal to 61 | # work without clean URLs. This requires Apache version >= 2.2.16. If Drupal is 62 | # not accessed by the top level URL (i.e.: http://example.com/drupal/ instead of 63 | # http://example.com/), the path to index.php will need to be adjusted. 64 | 65 | FallbackResource /index.php 66 | 67 | 68 | # Various rewrite rules. 69 | 70 | RewriteEngine on 71 | 72 | # Set "protossl" to "s" if we were accessed via https://. This is used later 73 | # if you enable "www." stripping or enforcement, in order to ensure that 74 | # you don't bounce between http and https. 75 | RewriteRule ^ - [E=protossl] 76 | RewriteCond %{HTTPS} on 77 | RewriteRule ^ - [E=protossl:s] 78 | 79 | # Make sure Authorization HTTP header is available to PHP 80 | # even when running as CGI or FastCGI. 81 | RewriteRule ^ - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] 82 | 83 | # Block access to "hidden" directories whose names begin with a period. This 84 | # includes directories used by version control systems such as Subversion or 85 | # Git to store control files. Files whose names begin with a period, as well 86 | # as the control files used by CVS, are protected by the FilesMatch directive 87 | # above. 88 | # 89 | # NOTE: This only works when mod_rewrite is loaded. Without mod_rewrite, it is 90 | # not possible to block access to entire directories from .htaccess because 91 | # is not allowed here. 92 | # 93 | # If you do not have mod_rewrite installed, you should remove these 94 | # directories from your webroot or otherwise protect them from being 95 | # downloaded. 96 | RewriteRule "/\.|^\.(?!well-known/)" - [F] 97 | 98 | # If your site can be accessed both with and without the 'www.' prefix, you 99 | # can use one of the following settings to redirect users to your preferred 100 | # URL, either WITH or WITHOUT the 'www.' prefix. Choose ONLY one option: 101 | # 102 | # To redirect all users to access the site WITH the 'www.' prefix, 103 | # (http://example.com/foo will be redirected to http://www.example.com/foo) 104 | # uncomment the following: 105 | # RewriteCond %{HTTP_HOST} . 106 | # RewriteCond %{HTTP_HOST} !^www\. [NC] 107 | # RewriteRule ^ http%{ENV:protossl}://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301] 108 | # 109 | # To redirect all users to access the site WITHOUT the 'www.' prefix, 110 | # (http://www.example.com/foo will be redirected to http://example.com/foo) 111 | # uncomment the following: 112 | # RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC] 113 | # RewriteRule ^ http%{ENV:protossl}://%1%{REQUEST_URI} [L,R=301] 114 | 115 | # Modify the RewriteBase if you are using Drupal in a subdirectory or in a 116 | # VirtualDocumentRoot and the rewrite rules are not working properly. 117 | # For example if your site is at http://example.com/drupal uncomment and 118 | # modify the following line: 119 | # RewriteBase /drupal 120 | # 121 | # If your site is running in a VirtualDocumentRoot at http://example.com/, 122 | # uncomment the following line: 123 | # RewriteBase / 124 | 125 | # Redirect common PHP files to their new locations. 126 | RewriteCond %{REQUEST_URI} ^(.*)?/(install.php) [OR] 127 | RewriteCond %{REQUEST_URI} ^(.*)?/(rebuild.php) 128 | RewriteCond %{REQUEST_URI} !core 129 | RewriteRule ^ %1/core/%2 [L,QSA,R=301] 130 | 131 | # Rewrite install.php during installation to see if mod_rewrite is working 132 | RewriteRule ^core/install.php core/install.php?rewrite=ok [QSA,L] 133 | 134 | # Pass all requests not referring directly to files in the filesystem to 135 | # index.php. 136 | RewriteCond %{REQUEST_FILENAME} !-f 137 | RewriteCond %{REQUEST_FILENAME} !-d 138 | RewriteCond %{REQUEST_URI} !=/favicon.ico 139 | RewriteRule ^ index.php [L] 140 | 141 | # For security reasons, deny access to other PHP files on public sites. 142 | # Note: The following URI conditions are not anchored at the start (^), 143 | # because Drupal may be located in a subdirectory. To further improve 144 | # security, you can replace '!/' with '!^/'. 145 | # Allow access to PHP files in /core (like authorize.php or install.php): 146 | RewriteCond %{REQUEST_URI} !/core/[^/]*\.php$ 147 | # Allow access to test-specific PHP files: 148 | RewriteCond %{REQUEST_URI} !/core/modules/system/tests/https?.php 149 | # Allow access to Statistics module's custom front controller. 150 | # Copy and adapt this rule to directly execute PHP files in contributed or 151 | # custom modules or to run another PHP application in the same directory. 152 | RewriteCond %{REQUEST_URI} !/core/modules/statistics/statistics.php$ 153 | # Deny access to any other PHP files that do not match the rules above. 154 | # Specifically, disallow autoload.php from being served directly. 155 | RewriteRule "^(.+/.*|autoload)\.php($|/)" - [F] 156 | 157 | # Rules to correctly serve gzip compressed CSS and JS files. 158 | # Requires both mod_rewrite and mod_headers to be enabled. 159 | 160 | # Serve gzip compressed CSS files if they exist and the client accepts gzip. 161 | RewriteCond %{HTTP:Accept-encoding} gzip 162 | RewriteCond %{REQUEST_FILENAME}\.gz -s 163 | RewriteRule ^(.*)\.css $1\.css\.gz [QSA] 164 | 165 | # Serve gzip compressed JS files if they exist and the client accepts gzip. 166 | RewriteCond %{HTTP:Accept-encoding} gzip 167 | RewriteCond %{REQUEST_FILENAME}\.gz -s 168 | RewriteRule ^(.*)\.js $1\.js\.gz [QSA] 169 | 170 | # Serve correct content types, and prevent mod_deflate double gzip. 171 | RewriteRule \.css\.gz$ - [T=text/css,E=no-gzip:1] 172 | RewriteRule \.js\.gz$ - [T=text/javascript,E=no-gzip:1] 173 | 174 | 175 | # Serve correct encoding type. 176 | Header set Content-Encoding gzip 177 | # Force proxies to cache gzipped & non-gzipped css/js files separately. 178 | Header append Vary Accept-Encoding 179 | 180 | 181 | 182 | 183 | # Various header fixes. 184 | 185 | # Disable content sniffing, since it's an attack vector. 186 | Header always set X-Content-Type-Options nosniff 187 | # Disable Proxy header, since it's an attack vector. 188 | RequestHeader unset Proxy 189 | 190 | -------------------------------------------------------------------------------- /web/autoload.php: -------------------------------------------------------------------------------- 1 | handle($request); 20 | $response->send(); 21 | 22 | $kernel->terminate($request, $response); 23 | -------------------------------------------------------------------------------- /web/robots.txt: -------------------------------------------------------------------------------- 1 | # 2 | # robots.txt 3 | # 4 | # This file is to prevent the crawling and indexing of certain parts 5 | # of your site by web crawlers and spiders run by sites like Yahoo! 6 | # and Google. By telling these "robots" where not to go on your site, 7 | # you save bandwidth and server resources. 8 | # 9 | # This file will be ignored unless it is at the root of your host: 10 | # Used: http://example.com/robots.txt 11 | # Ignored: http://example.com/site/robots.txt 12 | # 13 | # For more information about the robots.txt standard, see: 14 | # http://www.robotstxt.org/robotstxt.html 15 | 16 | User-agent: * 17 | # CSS, JS, Images 18 | Allow: /core/*.css$ 19 | Allow: /core/*.css? 20 | Allow: /core/*.js$ 21 | Allow: /core/*.js? 22 | Allow: /core/*.gif 23 | Allow: /core/*.jpg 24 | Allow: /core/*.jpeg 25 | Allow: /core/*.png 26 | Allow: /core/*.svg 27 | Allow: /profiles/*.css$ 28 | Allow: /profiles/*.css? 29 | Allow: /profiles/*.js$ 30 | Allow: /profiles/*.js? 31 | Allow: /profiles/*.gif 32 | Allow: /profiles/*.jpg 33 | Allow: /profiles/*.jpeg 34 | Allow: /profiles/*.png 35 | Allow: /profiles/*.svg 36 | # Directories 37 | Disallow: /core/ 38 | Disallow: /profiles/ 39 | # Files 40 | Disallow: /README.txt 41 | Disallow: /web.config 42 | # Paths (clean URLs) 43 | Disallow: /admin/ 44 | Disallow: /comment/reply/ 45 | Disallow: /filter/tips/ 46 | Disallow: /node/add/ 47 | Disallow: /search/ 48 | Disallow: /user/register/ 49 | Disallow: /user/password/ 50 | Disallow: /user/login/ 51 | Disallow: /user/logout/ 52 | # Paths (no clean URLs) 53 | Disallow: /index.php/admin/ 54 | Disallow: /index.php/comment/reply/ 55 | Disallow: /index.php/filter/tips/ 56 | Disallow: /index.php/node/add/ 57 | Disallow: /index.php/search/ 58 | Disallow: /index.php/user/password/ 59 | Disallow: /index.php/user/register/ 60 | Disallow: /index.php/user/login/ 61 | Disallow: /index.php/user/logout/ 62 | -------------------------------------------------------------------------------- /web/sites/default/default.services.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | session.storage.options: 3 | # Default ini options for sessions. 4 | # 5 | # Some distributions of Linux (most notably Debian) ship their PHP 6 | # installations with garbage collection (gc) disabled. Since Drupal depends 7 | # on PHP's garbage collection for clearing sessions, ensure that garbage 8 | # collection occurs by using the most common settings. 9 | # @default 1 10 | gc_probability: 1 11 | # @default 100 12 | gc_divisor: 100 13 | # 14 | # Set session lifetime (in seconds), i.e. the time from the user's last 15 | # visit to the active session may be deleted by the session garbage 16 | # collector. When a session is deleted, authenticated users are logged out, 17 | # and the contents of the user's $_SESSION variable is discarded. 18 | # @default 200000 19 | gc_maxlifetime: 200000 20 | # 21 | # Set session cookie lifetime (in seconds), i.e. the time from the session 22 | # is created to the cookie expires, i.e. when the browser is expected to 23 | # discard the cookie. The value 0 means "until the browser is closed". 24 | # @default 2000000 25 | cookie_lifetime: 2000000 26 | # 27 | # Drupal automatically generates a unique session cookie name based on the 28 | # full domain name used to access the site. This mechanism is sufficient 29 | # for most use-cases, including multi-site deployments. However, if it is 30 | # desired that a session can be reused across different subdomains, the 31 | # cookie domain needs to be set to the shared base domain. Doing so assures 32 | # that users remain logged in as they cross between various subdomains. 33 | # To maximize compatibility and normalize the behavior across user agents, 34 | # the cookie domain should start with a dot. 35 | # 36 | # @default none 37 | # cookie_domain: '.example.com' 38 | # 39 | twig.config: 40 | # Twig debugging: 41 | # 42 | # When debugging is enabled: 43 | # - The markup of each Twig template is surrounded by HTML comments that 44 | # contain theming information, such as template file name suggestions. 45 | # - Note that this debugging markup will cause automated tests that directly 46 | # check rendered HTML to fail. When running automated tests, 'debug' 47 | # should be set to FALSE. 48 | # - The dump() function can be used in Twig templates to output information 49 | # about template variables. 50 | # - Twig templates are automatically recompiled whenever the source code 51 | # changes (see auto_reload below). 52 | # 53 | # For more information about debugging Twig templates, see 54 | # https://www.drupal.org/node/1906392. 55 | # 56 | # Not recommended in production environments 57 | # @default false 58 | debug: false 59 | # Twig auto-reload: 60 | # 61 | # Automatically recompile Twig templates whenever the source code changes. 62 | # If you don't provide a value for auto_reload, it will be determined 63 | # based on the value of debug. 64 | # 65 | # Not recommended in production environments 66 | # @default null 67 | auto_reload: null 68 | # Twig cache: 69 | # 70 | # By default, Twig templates will be compiled and stored in the filesystem 71 | # to increase performance. Disabling the Twig cache will recompile the 72 | # templates from source each time they are used. In most cases the 73 | # auto_reload setting above should be enabled rather than disabling the 74 | # Twig cache. 75 | # 76 | # Not recommended in production environments 77 | # @default true 78 | cache: true 79 | renderer.config: 80 | # Renderer required cache contexts: 81 | # 82 | # The Renderer will automatically associate these cache contexts with every 83 | # render array, hence varying every render array by these cache contexts. 84 | # 85 | # @default ['languages:language_interface', 'theme', 'user.permissions'] 86 | required_cache_contexts: ['languages:language_interface', 'theme', 'user.permissions'] 87 | # Renderer automatic placeholdering conditions: 88 | # 89 | # Drupal allows portions of the page to be automatically deferred when 90 | # rendering to improve cache performance. That is especially helpful for 91 | # cache contexts that vary widely, such as the active user. On some sites 92 | # those may be different, however, such as sites with only a handful of 93 | # users. If you know what the high-cardinality cache contexts are for your 94 | # site, specify those here. If you're not sure, the defaults are fairly safe 95 | # in general. 96 | # 97 | # For more information about rendering optimizations see 98 | # https://www.drupal.org/developing/api/8/render/arrays/cacheability#optimizing 99 | auto_placeholder_conditions: 100 | # Max-age at or below which caching is not considered worthwhile. 101 | # 102 | # Disable by setting to -1. 103 | # 104 | # @default 0 105 | max-age: 0 106 | # Cache contexts with a high cardinality. 107 | # 108 | # Disable by setting to []. 109 | # 110 | # @default ['session', 'user'] 111 | contexts: ['session', 'user'] 112 | # Tags with a high invalidation frequency. 113 | # 114 | # Disable by setting to []. 115 | # 116 | # @default [] 117 | tags: [] 118 | # Cacheability debugging: 119 | # 120 | # Responses with cacheability metadata (CacheableResponseInterface instances) 121 | # get X-Drupal-Cache-Tags and X-Drupal-Cache-Contexts headers. 122 | # 123 | # For more information about debugging cacheable responses, see 124 | # https://www.drupal.org/developing/api/8/response/cacheable-response-interface 125 | # 126 | # Not recommended in production environments 127 | # @default false 128 | http.response.debug_cacheability_headers: false 129 | factory.keyvalue: 130 | {} 131 | # Default key/value storage service to use. 132 | # @default keyvalue.database 133 | # default: keyvalue.database 134 | # Collection-specific overrides. 135 | # state: keyvalue.database 136 | factory.keyvalue.expirable: 137 | {} 138 | # Default key/value expirable storage service to use. 139 | # @default keyvalue.database.expirable 140 | # default: keyvalue.database.expirable 141 | # Allowed protocols for URL generation. 142 | filter_protocols: 143 | - http 144 | - https 145 | - ftp 146 | - news 147 | - nntp 148 | - tel 149 | - telnet 150 | - mailto 151 | - irc 152 | - ssh 153 | - sftp 154 | - webcal 155 | - rtsp 156 | 157 | # Configure Cross-Site HTTP requests (CORS). 158 | # Read https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS 159 | # for more information about the topic in general. 160 | # Note: By default the configuration is disabled. 161 | cors.config: 162 | enabled: false 163 | # Specify allowed headers, like 'x-allowed-header'. 164 | allowedHeaders: [] 165 | # Specify allowed request methods, specify ['*'] to allow all possible ones. 166 | allowedMethods: [] 167 | # Configure requests allowed from specific origins. 168 | allowedOrigins: ['*'] 169 | # Sets the Access-Control-Expose-Headers header. 170 | exposedHeaders: false 171 | # Sets the Access-Control-Max-Age header. 172 | maxAge: false 173 | # Sets the Access-Control-Allow-Credentials header. 174 | supportsCredentials: false 175 | -------------------------------------------------------------------------------- /web/sites/default/default.settings.php: -------------------------------------------------------------------------------- 1 | 'databasename', 79 | * 'username' => 'sqlusername', 80 | * 'password' => 'sqlpassword', 81 | * 'host' => 'localhost', 82 | * 'port' => '3306', 83 | * 'driver' => 'mysql', 84 | * 'prefix' => '', 85 | * 'collation' => 'utf8mb4_general_ci', 86 | * ); 87 | * @endcode 88 | */ 89 | $databases = array(); 90 | 91 | /** 92 | * Customizing database settings. 93 | * 94 | * Many of the values of the $databases array can be customized for your 95 | * particular database system. Refer to the sample in the section above as a 96 | * starting point. 97 | * 98 | * The "driver" property indicates what Drupal database driver the 99 | * connection should use. This is usually the same as the name of the 100 | * database type, such as mysql or sqlite, but not always. The other 101 | * properties will vary depending on the driver. For SQLite, you must 102 | * specify a database file name in a directory that is writable by the 103 | * webserver. For most other drivers, you must specify a 104 | * username, password, host, and database name. 105 | * 106 | * Transaction support is enabled by default for all drivers that support it, 107 | * including MySQL. To explicitly disable it, set the 'transactions' key to 108 | * FALSE. 109 | * Note that some configurations of MySQL, such as the MyISAM engine, don't 110 | * support it and will proceed silently even if enabled. If you experience 111 | * transaction related crashes with such configuration, set the 'transactions' 112 | * key to FALSE. 113 | * 114 | * For each database, you may optionally specify multiple "target" databases. 115 | * A target database allows Drupal to try to send certain queries to a 116 | * different database if it can but fall back to the default connection if not. 117 | * That is useful for primary/replica replication, as Drupal may try to connect 118 | * to a replica server when appropriate and if one is not available will simply 119 | * fall back to the single primary server (The terms primary/replica are 120 | * traditionally referred to as master/slave in database server documentation). 121 | * 122 | * The general format for the $databases array is as follows: 123 | * @code 124 | * $databases['default']['default'] = $info_array; 125 | * $databases['default']['replica'][] = $info_array; 126 | * $databases['default']['replica'][] = $info_array; 127 | * $databases['extra']['default'] = $info_array; 128 | * @endcode 129 | * 130 | * In the above example, $info_array is an array of settings described above. 131 | * The first line sets a "default" database that has one primary database 132 | * (the second level default). The second and third lines create an array 133 | * of potential replica databases. Drupal will select one at random for a given 134 | * request as needed. The fourth line creates a new database with a name of 135 | * "extra". 136 | * 137 | * You can optionally set prefixes for some or all database table names 138 | * by using the 'prefix' setting. If a prefix is specified, the table 139 | * name will be prepended with its value. Be sure to use valid database 140 | * characters only, usually alphanumeric and underscore. If no prefixes 141 | * are desired, leave it as an empty string ''. 142 | * 143 | * To have all database names prefixed, set 'prefix' as a string: 144 | * @code 145 | * 'prefix' => 'main_', 146 | * @endcode 147 | * 148 | * Per-table prefixes are deprecated as of Drupal 8.2, and will be removed in 149 | * Drupal 9.0. After that, only a single prefix for all tables will be 150 | * supported. 151 | * 152 | * To provide prefixes for specific tables, set 'prefix' as an array. 153 | * The array's keys are the table names and the values are the prefixes. 154 | * The 'default' element is mandatory and holds the prefix for any tables 155 | * not specified elsewhere in the array. Example: 156 | * @code 157 | * 'prefix' => array( 158 | * 'default' => 'main_', 159 | * 'users' => 'shared_', 160 | * 'sessions' => 'shared_', 161 | * 'role' => 'shared_', 162 | * 'authmap' => 'shared_', 163 | * ), 164 | * @endcode 165 | * You can also use a reference to a schema/database as a prefix. This may be 166 | * useful if your Drupal installation exists in a schema that is not the default 167 | * or you want to access several databases from the same code base at the same 168 | * time. 169 | * Example: 170 | * @code 171 | * 'prefix' => array( 172 | * 'default' => 'main.', 173 | * 'users' => 'shared.', 174 | * 'sessions' => 'shared.', 175 | * 'role' => 'shared.', 176 | * 'authmap' => 'shared.', 177 | * ); 178 | * @endcode 179 | * NOTE: MySQL and SQLite's definition of a schema is a database. 180 | * 181 | * Advanced users can add or override initial commands to execute when 182 | * connecting to the database server, as well as PDO connection settings. For 183 | * example, to enable MySQL SELECT queries to exceed the max_join_size system 184 | * variable, and to reduce the database connection timeout to 5 seconds: 185 | * @code 186 | * $databases['default']['default'] = array( 187 | * 'init_commands' => array( 188 | * 'big_selects' => 'SET SQL_BIG_SELECTS=1', 189 | * ), 190 | * 'pdo' => array( 191 | * PDO::ATTR_TIMEOUT => 5, 192 | * ), 193 | * ); 194 | * @endcode 195 | * 196 | * WARNING: The above defaults are designed for database portability. Changing 197 | * them may cause unexpected behavior, including potential data loss. See 198 | * https://www.drupal.org/developing/api/database/configuration for more 199 | * information on these defaults and the potential issues. 200 | * 201 | * More details can be found in the constructor methods for each driver: 202 | * - \Drupal\Core\Database\Driver\mysql\Connection::__construct() 203 | * - \Drupal\Core\Database\Driver\pgsql\Connection::__construct() 204 | * - \Drupal\Core\Database\Driver\sqlite\Connection::__construct() 205 | * 206 | * Sample Database configuration format for PostgreSQL (pgsql): 207 | * @code 208 | * $databases['default']['default'] = array( 209 | * 'driver' => 'pgsql', 210 | * 'database' => 'databasename', 211 | * 'username' => 'sqlusername', 212 | * 'password' => 'sqlpassword', 213 | * 'host' => 'localhost', 214 | * 'prefix' => '', 215 | * ); 216 | * @endcode 217 | * 218 | * Sample Database configuration format for SQLite (sqlite): 219 | * @code 220 | * $databases['default']['default'] = array( 221 | * 'driver' => 'sqlite', 222 | * 'database' => '/path/to/databasefilename', 223 | * ); 224 | * @endcode 225 | */ 226 | 227 | /** 228 | * Location of the site configuration files. 229 | * 230 | * The $config_directories array specifies the location of file system 231 | * directories used for configuration data. On install, the "sync" directory is 232 | * created. This is used for configuration imports. The "active" directory is 233 | * not created by default since the default storage for active configuration is 234 | * the database rather than the file system. (This can be changed. See "Active 235 | * configuration settings" below). 236 | * 237 | * The default location for the "sync" directory is inside a randomly-named 238 | * directory in the public files path. The setting below allows you to override 239 | * the "sync" location. 240 | * 241 | * If you use files for the "active" configuration, you can tell the 242 | * Configuration system where this directory is located by adding an entry with 243 | * array key CONFIG_ACTIVE_DIRECTORY. 244 | * 245 | * Example: 246 | * @code 247 | * $config_directories = array( 248 | * CONFIG_SYNC_DIRECTORY => '/directory/outside/webroot', 249 | * ); 250 | * @endcode 251 | */ 252 | $config_directories = array(); 253 | 254 | /** 255 | * Settings: 256 | * 257 | * $settings contains environment-specific configuration, such as the files 258 | * directory and reverse proxy address, and temporary configuration, such as 259 | * security overrides. 260 | * 261 | * @see \Drupal\Core\Site\Settings::get() 262 | */ 263 | 264 | /** 265 | * The active installation profile. 266 | * 267 | * Changing this after installation is not recommended as it changes which 268 | * directories are scanned during extension discovery. If this is set prior to 269 | * installation this value will be rewritten according to the profile selected 270 | * by the user. 271 | * 272 | * @see install_select_profile() 273 | * 274 | * @deprecated in Drupal 8.3.0 and will be removed before Drupal 9.0.0. The 275 | * install profile is written to the core.extension configuration. If a 276 | * service requires the install profile use the 'install_profile' container 277 | * parameter. Functional code can use \Drupal::installProfile(). 278 | */ 279 | # $settings['install_profile'] = ''; 280 | 281 | /** 282 | * Salt for one-time login links, cancel links, form tokens, etc. 283 | * 284 | * This variable will be set to a random value by the installer. All one-time 285 | * login links will be invalidated if the value is changed. Note that if your 286 | * site is deployed on a cluster of web servers, you must ensure that this 287 | * variable has the same value on each server. 288 | * 289 | * For enhanced security, you may set this variable to the contents of a file 290 | * outside your document root; you should also ensure that this file is not 291 | * stored with backups of your database. 292 | * 293 | * Example: 294 | * @code 295 | * $settings['hash_salt'] = file_get_contents('/home/example/salt.txt'); 296 | * @endcode 297 | */ 298 | $settings['hash_salt'] = ''; 299 | 300 | /** 301 | * Deployment identifier. 302 | * 303 | * Drupal's dependency injection container will be automatically invalidated and 304 | * rebuilt when the Drupal core version changes. When updating contributed or 305 | * custom code that changes the container, changing this identifier will also 306 | * allow the container to be invalidated as soon as code is deployed. 307 | */ 308 | # $settings['deployment_identifier'] = \Drupal::VERSION; 309 | 310 | /** 311 | * Access control for update.php script. 312 | * 313 | * If you are updating your Drupal installation using the update.php script but 314 | * are not logged in using either an account with the "Administer software 315 | * updates" permission or the site maintenance account (the account that was 316 | * created during installation), you will need to modify the access check 317 | * statement below. Change the FALSE to a TRUE to disable the access check. 318 | * After finishing the upgrade, be sure to open this file again and change the 319 | * TRUE back to a FALSE! 320 | */ 321 | $settings['update_free_access'] = FALSE; 322 | 323 | /** 324 | * External access proxy settings: 325 | * 326 | * If your site must access the Internet via a web proxy then you can enter the 327 | * proxy settings here. Set the full URL of the proxy, including the port, in 328 | * variables: 329 | * - $settings['http_client_config']['proxy']['http']: The proxy URL for HTTP 330 | * requests. 331 | * - $settings['http_client_config']['proxy']['https']: The proxy URL for HTTPS 332 | * requests. 333 | * You can pass in the user name and password for basic authentication in the 334 | * URLs in these settings. 335 | * 336 | * You can also define an array of host names that can be accessed directly, 337 | * bypassing the proxy, in $settings['http_client_config']['proxy']['no']. 338 | */ 339 | # $settings['http_client_config']['proxy']['http'] = 'http://proxy_user:proxy_pass@example.com:8080'; 340 | # $settings['http_client_config']['proxy']['https'] = 'http://proxy_user:proxy_pass@example.com:8080'; 341 | # $settings['http_client_config']['proxy']['no'] = ['127.0.0.1', 'localhost']; 342 | 343 | /** 344 | * Reverse Proxy Configuration: 345 | * 346 | * Reverse proxy servers are often used to enhance the performance 347 | * of heavily visited sites and may also provide other site caching, 348 | * security, or encryption benefits. In an environment where Drupal 349 | * is behind a reverse proxy, the real IP address of the client should 350 | * be determined such that the correct client IP address is available 351 | * to Drupal's logging, statistics, and access management systems. In 352 | * the most simple scenario, the proxy server will add an 353 | * X-Forwarded-For header to the request that contains the client IP 354 | * address. However, HTTP headers are vulnerable to spoofing, where a 355 | * malicious client could bypass restrictions by setting the 356 | * X-Forwarded-For header directly. Therefore, Drupal's proxy 357 | * configuration requires the IP addresses of all remote proxies to be 358 | * specified in $settings['reverse_proxy_addresses'] to work correctly. 359 | * 360 | * Enable this setting to get Drupal to determine the client IP from 361 | * the X-Forwarded-For header (or $settings['reverse_proxy_header'] if set). 362 | * If you are unsure about this setting, do not have a reverse proxy, 363 | * or Drupal operates in a shared hosting environment, this setting 364 | * should remain commented out. 365 | * 366 | * In order for this setting to be used you must specify every possible 367 | * reverse proxy IP address in $settings['reverse_proxy_addresses']. 368 | * If a complete list of reverse proxies is not available in your 369 | * environment (for example, if you use a CDN) you may set the 370 | * $_SERVER['REMOTE_ADDR'] variable directly in settings.php. 371 | * Be aware, however, that it is likely that this would allow IP 372 | * address spoofing unless more advanced precautions are taken. 373 | */ 374 | # $settings['reverse_proxy'] = TRUE; 375 | 376 | /** 377 | * Specify every reverse proxy IP address in your environment. 378 | * This setting is required if $settings['reverse_proxy'] is TRUE. 379 | */ 380 | # $settings['reverse_proxy_addresses'] = array('a.b.c.d', ...); 381 | 382 | /** 383 | * Set this value if your proxy server sends the client IP in a header 384 | * other than X-Forwarded-For. 385 | */ 386 | # $settings['reverse_proxy_header'] = 'X_CLUSTER_CLIENT_IP'; 387 | 388 | /** 389 | * Set this value if your proxy server sends the client protocol in a header 390 | * other than X-Forwarded-Proto. 391 | */ 392 | # $settings['reverse_proxy_proto_header'] = 'X_FORWARDED_PROTO'; 393 | 394 | /** 395 | * Set this value if your proxy server sends the client protocol in a header 396 | * other than X-Forwarded-Host. 397 | */ 398 | # $settings['reverse_proxy_host_header'] = 'X_FORWARDED_HOST'; 399 | 400 | /** 401 | * Set this value if your proxy server sends the client protocol in a header 402 | * other than X-Forwarded-Port. 403 | */ 404 | # $settings['reverse_proxy_port_header'] = 'X_FORWARDED_PORT'; 405 | 406 | /** 407 | * Set this value if your proxy server sends the client protocol in a header 408 | * other than Forwarded. 409 | */ 410 | # $settings['reverse_proxy_forwarded_header'] = 'FORWARDED'; 411 | 412 | /** 413 | * Page caching: 414 | * 415 | * By default, Drupal sends a "Vary: Cookie" HTTP header for anonymous page 416 | * views. This tells a HTTP proxy that it may return a page from its local 417 | * cache without contacting the web server, if the user sends the same Cookie 418 | * header as the user who originally requested the cached page. Without "Vary: 419 | * Cookie", authenticated users would also be served the anonymous page from 420 | * the cache. If the site has mostly anonymous users except a few known 421 | * editors/administrators, the Vary header can be omitted. This allows for 422 | * better caching in HTTP proxies (including reverse proxies), i.e. even if 423 | * clients send different cookies, they still get content served from the cache. 424 | * However, authenticated users should access the site directly (i.e. not use an 425 | * HTTP proxy, and bypass the reverse proxy if one is used) in order to avoid 426 | * getting cached pages from the proxy. 427 | */ 428 | # $settings['omit_vary_cookie'] = TRUE; 429 | 430 | 431 | /** 432 | * Cache TTL for client error (4xx) responses. 433 | * 434 | * Items cached per-URL tend to result in a large number of cache items, and 435 | * this can be problematic on 404 pages which by their nature are unbounded. A 436 | * fixed TTL can be set for these items, defaulting to one hour, so that cache 437 | * backends which do not support LRU can purge older entries. To disable caching 438 | * of client error responses set the value to 0. Currently applies only to 439 | * page_cache module. 440 | */ 441 | # $settings['cache_ttl_4xx'] = 3600; 442 | 443 | 444 | /** 445 | * Class Loader. 446 | * 447 | * If the APC extension is detected, the Symfony APC class loader is used for 448 | * performance reasons. Detection can be prevented by setting 449 | * class_loader_auto_detect to false, as in the example below. 450 | */ 451 | # $settings['class_loader_auto_detect'] = FALSE; 452 | 453 | /* 454 | * If the APC extension is not detected, either because APC is missing or 455 | * because auto-detection has been disabled, auto-loading falls back to 456 | * Composer's ClassLoader, which is good for development as it does not break 457 | * when code is moved in the file system. You can also decorate the base class 458 | * loader with another cached solution than the Symfony APC class loader, as 459 | * all production sites should have a cached class loader of some sort enabled. 460 | * 461 | * To do so, you may decorate and replace the local $class_loader variable. For 462 | * example, to use Symfony's APC class loader without automatic detection, 463 | * uncomment the code below. 464 | */ 465 | /* 466 | if ($settings['hash_salt']) { 467 | $prefix = 'drupal.' . hash('sha256', 'drupal.' . $settings['hash_salt']); 468 | $apc_loader = new \Symfony\Component\ClassLoader\ApcClassLoader($prefix, $class_loader); 469 | unset($prefix); 470 | $class_loader->unregister(); 471 | $apc_loader->register(); 472 | $class_loader = $apc_loader; 473 | } 474 | */ 475 | 476 | /** 477 | * Authorized file system operations: 478 | * 479 | * The Update Manager module included with Drupal provides a mechanism for 480 | * site administrators to securely install missing updates for the site 481 | * directly through the web user interface. On securely-configured servers, 482 | * the Update manager will require the administrator to provide SSH or FTP 483 | * credentials before allowing the installation to proceed; this allows the 484 | * site to update the new files as the user who owns all the Drupal files, 485 | * instead of as the user the webserver is running as. On servers where the 486 | * webserver user is itself the owner of the Drupal files, the administrator 487 | * will not be prompted for SSH or FTP credentials (note that these server 488 | * setups are common on shared hosting, but are inherently insecure). 489 | * 490 | * Some sites might wish to disable the above functionality, and only update 491 | * the code directly via SSH or FTP themselves. This setting completely 492 | * disables all functionality related to these authorized file operations. 493 | * 494 | * @see https://www.drupal.org/node/244924 495 | * 496 | * Remove the leading hash signs to disable. 497 | */ 498 | # $settings['allow_authorize_operations'] = FALSE; 499 | 500 | /** 501 | * Default mode for directories and files written by Drupal. 502 | * 503 | * Value should be in PHP Octal Notation, with leading zero. 504 | */ 505 | # $settings['file_chmod_directory'] = 0775; 506 | # $settings['file_chmod_file'] = 0664; 507 | 508 | /** 509 | * Public file base URL: 510 | * 511 | * An alternative base URL to be used for serving public files. This must 512 | * include any leading directory path. 513 | * 514 | * A different value from the domain used by Drupal to be used for accessing 515 | * public files. This can be used for a simple CDN integration, or to improve 516 | * security by serving user-uploaded files from a different domain or subdomain 517 | * pointing to the same server. Do not include a trailing slash. 518 | */ 519 | # $settings['file_public_base_url'] = 'http://downloads.example.com/files'; 520 | 521 | /** 522 | * Public file path: 523 | * 524 | * A local file system path where public files will be stored. This directory 525 | * must exist and be writable by Drupal. This directory must be relative to 526 | * the Drupal installation directory and be accessible over the web. 527 | */ 528 | # $settings['file_public_path'] = 'sites/default/files'; 529 | 530 | /** 531 | * Private file path: 532 | * 533 | * A local file system path where private files will be stored. This directory 534 | * must be absolute, outside of the Drupal installation directory and not 535 | * accessible over the web. 536 | * 537 | * Note: Caches need to be cleared when this value is changed to make the 538 | * private:// stream wrapper available to the system. 539 | * 540 | * See https://www.drupal.org/documentation/modules/file for more information 541 | * about securing private files. 542 | */ 543 | # $settings['file_private_path'] = ''; 544 | 545 | /** 546 | * Session write interval: 547 | * 548 | * Set the minimum interval between each session write to database. 549 | * For performance reasons it defaults to 180. 550 | */ 551 | # $settings['session_write_interval'] = 180; 552 | 553 | /** 554 | * String overrides: 555 | * 556 | * To override specific strings on your site with or without enabling the Locale 557 | * module, add an entry to this list. This functionality allows you to change 558 | * a small number of your site's default English language interface strings. 559 | * 560 | * Remove the leading hash signs to enable. 561 | * 562 | * The "en" part of the variable name, is dynamic and can be any langcode of 563 | * any added language. (eg locale_custom_strings_de for german). 564 | */ 565 | # $settings['locale_custom_strings_en'][''] = array( 566 | # 'forum' => 'Discussion board', 567 | # '@count min' => '@count minutes', 568 | # ); 569 | 570 | /** 571 | * A custom theme for the offline page: 572 | * 573 | * This applies when the site is explicitly set to maintenance mode through the 574 | * administration page or when the database is inactive due to an error. 575 | * The template file should also be copied into the theme. It is located inside 576 | * 'core/modules/system/templates/maintenance-page.html.twig'. 577 | * 578 | * Note: This setting does not apply to installation and update pages. 579 | */ 580 | # $settings['maintenance_theme'] = 'bartik'; 581 | 582 | /** 583 | * PHP settings: 584 | * 585 | * To see what PHP settings are possible, including whether they can be set at 586 | * runtime (by using ini_set()), read the PHP documentation: 587 | * http://php.net/manual/ini.list.php 588 | * See \Drupal\Core\DrupalKernel::bootEnvironment() for required runtime 589 | * settings and the .htaccess file for non-runtime settings. 590 | * Settings defined there should not be duplicated here so as to avoid conflict 591 | * issues. 592 | */ 593 | 594 | /** 595 | * If you encounter a situation where users post a large amount of text, and 596 | * the result is stripped out upon viewing but can still be edited, Drupal's 597 | * output filter may not have sufficient memory to process it. If you 598 | * experience this issue, you may wish to uncomment the following two lines 599 | * and increase the limits of these variables. For more information, see 600 | * http://php.net/manual/pcre.configuration.php. 601 | */ 602 | # ini_set('pcre.backtrack_limit', 200000); 603 | # ini_set('pcre.recursion_limit', 200000); 604 | 605 | /** 606 | * Active configuration settings. 607 | * 608 | * By default, the active configuration is stored in the database in the 609 | * {config} table. To use a different storage mechanism for the active 610 | * configuration, do the following prior to installing: 611 | * - Create an "active" directory and declare its path in $config_directories 612 | * as explained under the 'Location of the site configuration files' section 613 | * above in this file. To enhance security, you can declare a path that is 614 | * outside your document root. 615 | * - Override the 'bootstrap_config_storage' setting here. It must be set to a 616 | * callable that returns an object that implements 617 | * \Drupal\Core\Config\StorageInterface. 618 | * - Override the service definition 'config.storage.active'. Put this 619 | * override in a services.yml file in the same directory as settings.php 620 | * (definitions in this file will override service definition defaults). 621 | */ 622 | # $settings['bootstrap_config_storage'] = array('Drupal\Core\Config\BootstrapConfigStorageFactory', 'getFileStorage'); 623 | 624 | /** 625 | * Configuration overrides. 626 | * 627 | * To globally override specific configuration values for this site, 628 | * set them here. You usually don't need to use this feature. This is 629 | * useful in a configuration file for a vhost or directory, rather than 630 | * the default settings.php. 631 | * 632 | * Note that any values you provide in these variable overrides will not be 633 | * viewable from the Drupal administration interface. The administration 634 | * interface displays the values stored in configuration so that you can stage 635 | * changes to other environments that don't have the overrides. 636 | * 637 | * There are particular configuration values that are risky to override. For 638 | * example, overriding the list of installed modules in 'core.extension' is not 639 | * supported as module install or uninstall has not occurred. Other examples 640 | * include field storage configuration, because it has effects on database 641 | * structure, and 'core.menu.static_menu_link_overrides' since this is cached in 642 | * a way that is not config override aware. Also, note that changing 643 | * configuration values in settings.php will not fire any of the configuration 644 | * change events. 645 | */ 646 | # $config['system.site']['name'] = 'My Drupal site'; 647 | # $config['system.theme']['default'] = 'stark'; 648 | # $config['user.settings']['anonymous'] = 'Visitor'; 649 | 650 | /** 651 | * Fast 404 pages: 652 | * 653 | * Drupal can generate fully themed 404 pages. However, some of these responses 654 | * are for images or other resource files that are not displayed to the user. 655 | * This can waste bandwidth, and also generate server load. 656 | * 657 | * The options below return a simple, fast 404 page for URLs matching a 658 | * specific pattern: 659 | * - $config['system.performance']['fast_404']['exclude_paths']: A regular 660 | * expression to match paths to exclude, such as images generated by image 661 | * styles, or dynamically-resized images. The default pattern provided below 662 | * also excludes the private file system. If you need to add more paths, you 663 | * can add '|path' to the expression. 664 | * - $config['system.performance']['fast_404']['paths']: A regular expression to 665 | * match paths that should return a simple 404 page, rather than the fully 666 | * themed 404 page. If you don't have any aliases ending in htm or html you 667 | * can add '|s?html?' to the expression. 668 | * - $config['system.performance']['fast_404']['html']: The html to return for 669 | * simple 404 pages. 670 | * 671 | * Remove the leading hash signs if you would like to alter this functionality. 672 | */ 673 | # $config['system.performance']['fast_404']['exclude_paths'] = '/\/(?:styles)|(?:system\/files)\//'; 674 | # $config['system.performance']['fast_404']['paths'] = '/\.(?:txt|png|gif|jpe?g|css|js|ico|swf|flv|cgi|bat|pl|dll|exe|asp)$/i'; 675 | # $config['system.performance']['fast_404']['html'] = '404 Not Found

Not Found

The requested URL "@path" was not found on this server.

'; 676 | 677 | /** 678 | * Load services definition file. 679 | */ 680 | $settings['container_yamls'][] = $app_root . '/' . $site_path . '/services.yml'; 681 | 682 | /** 683 | * Override the default service container class. 684 | * 685 | * This is useful for example to trace the service container for performance 686 | * tracking purposes, for testing a service container with an error condition or 687 | * to test a service container that throws an exception. 688 | */ 689 | # $settings['container_base_class'] = '\Drupal\Core\DependencyInjection\Container'; 690 | 691 | /** 692 | * Override the default yaml parser class. 693 | * 694 | * Provide a fully qualified class name here if you would like to provide an 695 | * alternate implementation YAML parser. The class must implement the 696 | * \Drupal\Component\Serialization\SerializationInterface interface. 697 | */ 698 | # $settings['yaml_parser_class'] = NULL; 699 | 700 | /** 701 | * Trusted host configuration. 702 | * 703 | * Drupal core can use the Symfony trusted host mechanism to prevent HTTP Host 704 | * header spoofing. 705 | * 706 | * To enable the trusted host mechanism, you enable your allowable hosts 707 | * in $settings['trusted_host_patterns']. This should be an array of regular 708 | * expression patterns, without delimiters, representing the hosts you would 709 | * like to allow. 710 | * 711 | * For example: 712 | * @code 713 | * $settings['trusted_host_patterns'] = array( 714 | * '^www\.example\.com$', 715 | * ); 716 | * @endcode 717 | * will allow the site to only run from www.example.com. 718 | * 719 | * If you are running multisite, or if you are running your site from 720 | * different domain names (eg, you don't redirect http://www.example.com to 721 | * http://example.com), you should specify all of the host patterns that are 722 | * allowed by your site. 723 | * 724 | * For example: 725 | * @code 726 | * $settings['trusted_host_patterns'] = array( 727 | * '^example\.com$', 728 | * '^.+\.example\.com$', 729 | * '^example\.org$', 730 | * '^.+\.example\.org$', 731 | * ); 732 | * @endcode 733 | * will allow the site to run off of all variants of example.com and 734 | * example.org, with all subdomains included. 735 | */ 736 | 737 | /** 738 | * The default list of directories that will be ignored by Drupal's file API. 739 | * 740 | * By default ignore node_modules and bower_components folders to avoid issues 741 | * with common frontend tools and recursive scanning of directories looking for 742 | * extensions. 743 | * 744 | * @see file_scan_directory() 745 | * @see \Drupal\Core\Extension\ExtensionDiscovery::scanDirectory() 746 | */ 747 | $settings['file_scan_ignore_directories'] = [ 748 | 'node_modules', 749 | 'bower_components', 750 | ]; 751 | 752 | /** 753 | * Load local development override configuration, if available. 754 | * 755 | * Use settings.local.php to override variables on secondary (staging, 756 | * development, etc) installations of this site. Typically used to disable 757 | * caching, JavaScript/CSS compression, re-routing of outgoing emails, and 758 | * other things that should not happen on development and testing sites. 759 | * 760 | * Keep this code block at the end of this file to take full effect. 761 | */ 762 | # 763 | # if (file_exists($app_root . '/' . $site_path . '/settings.local.php')) { 764 | # include $app_root . '/' . $site_path . '/settings.local.php'; 765 | # } 766 | -------------------------------------------------------------------------------- /web/sites/default/services.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | session.storage.options: 3 | # Default ini options for sessions. 4 | # 5 | # Some distributions of Linux (most notably Debian) ship their PHP 6 | # installations with garbage collection (gc) disabled. Since Drupal depends 7 | # on PHP's garbage collection for clearing sessions, ensure that garbage 8 | # collection occurs by using the most common settings. 9 | # @default 1 10 | gc_probability: 1 11 | # @default 100 12 | gc_divisor: 100 13 | # 14 | # Set session lifetime (in seconds), i.e. the time from the user's last 15 | # visit to the active session may be deleted by the session garbage 16 | # collector. When a session is deleted, authenticated users are logged out, 17 | # and the contents of the user's $_SESSION variable is discarded. 18 | # @default 200000 19 | gc_maxlifetime: 200000 20 | # 21 | # Set session cookie lifetime (in seconds), i.e. the time from the session 22 | # is created to the cookie expires, i.e. when the browser is expected to 23 | # discard the cookie. The value 0 means "until the browser is closed". 24 | # @default 2000000 25 | cookie_lifetime: 2000000 26 | # 27 | # Drupal automatically generates a unique session cookie name based on the 28 | # full domain name used to access the site. This mechanism is sufficient 29 | # for most use-cases, including multi-site deployments. However, if it is 30 | # desired that a session can be reused across different subdomains, the 31 | # cookie domain needs to be set to the shared base domain. Doing so assures 32 | # that users remain logged in as they cross between various subdomains. 33 | # To maximize compatibility and normalize the behavior across user agents, 34 | # the cookie domain should start with a dot. 35 | # 36 | # @default none 37 | # cookie_domain: '.example.com' 38 | # 39 | twig.config: 40 | # Twig debugging: 41 | # 42 | # When debugging is enabled: 43 | # - The markup of each Twig template is surrounded by HTML comments that 44 | # contain theming information, such as template file name suggestions. 45 | # - Note that this debugging markup will cause automated tests that directly 46 | # check rendered HTML to fail. When running automated tests, 'debug' 47 | # should be set to FALSE. 48 | # - The dump() function can be used in Twig templates to output information 49 | # about template variables. 50 | # - Twig templates are automatically recompiled whenever the source code 51 | # changes (see auto_reload below). 52 | # 53 | # For more information about debugging Twig templates, see 54 | # https://www.drupal.org/node/1906392. 55 | # 56 | # Not recommended in production environments 57 | # @default false 58 | debug: false 59 | # Twig auto-reload: 60 | # 61 | # Automatically recompile Twig templates whenever the source code changes. 62 | # If you don't provide a value for auto_reload, it will be determined 63 | # based on the value of debug. 64 | # 65 | # Not recommended in production environments 66 | # @default null 67 | auto_reload: null 68 | # Twig cache: 69 | # 70 | # By default, Twig templates will be compiled and stored in the filesystem 71 | # to increase performance. Disabling the Twig cache will recompile the 72 | # templates from source each time they are used. In most cases the 73 | # auto_reload setting above should be enabled rather than disabling the 74 | # Twig cache. 75 | # 76 | # Not recommended in production environments 77 | # @default true 78 | cache: true 79 | renderer.config: 80 | # Renderer required cache contexts: 81 | # 82 | # The Renderer will automatically associate these cache contexts with every 83 | # render array, hence varying every render array by these cache contexts. 84 | # 85 | # @default ['languages:language_interface', 'theme', 'user.permissions'] 86 | required_cache_contexts: ['languages:language_interface', 'theme', 'user.permissions'] 87 | # Renderer automatic placeholdering conditions: 88 | # 89 | # Drupal allows portions of the page to be automatically deferred when 90 | # rendering to improve cache performance. That is especially helpful for 91 | # cache contexts that vary widely, such as the active user. On some sites 92 | # those may be different, however, such as sites with only a handful of 93 | # users. If you know what the high-cardinality cache contexts are for your 94 | # site, specify those here. If you're not sure, the defaults are fairly safe 95 | # in general. 96 | # 97 | # For more information about rendering optimizations see 98 | # https://www.drupal.org/developing/api/8/render/arrays/cacheability#optimizing 99 | auto_placeholder_conditions: 100 | # Max-age at or below which caching is not considered worthwhile. 101 | # 102 | # Disable by setting to -1. 103 | # 104 | # @default 0 105 | max-age: 0 106 | # Cache contexts with a high cardinality. 107 | # 108 | # Disable by setting to []. 109 | # 110 | # @default ['session', 'user'] 111 | contexts: ['session', 'user'] 112 | # Tags with a high invalidation frequency. 113 | # 114 | # Disable by setting to []. 115 | # 116 | # @default [] 117 | tags: [] 118 | # Cacheability debugging: 119 | # 120 | # Responses with cacheability metadata (CacheableResponseInterface instances) 121 | # get X-Drupal-Cache-Tags and X-Drupal-Cache-Contexts headers. 122 | # 123 | # For more information about debugging cacheable responses, see 124 | # https://www.drupal.org/developing/api/8/response/cacheable-response-interface 125 | # 126 | # Not recommended in production environments 127 | # @default false 128 | http.response.debug_cacheability_headers: false 129 | factory.keyvalue: 130 | {} 131 | # Default key/value storage service to use. 132 | # @default keyvalue.database 133 | # default: keyvalue.database 134 | # Collection-specific overrides. 135 | # state: keyvalue.database 136 | factory.keyvalue.expirable: 137 | {} 138 | # Default key/value expirable storage service to use. 139 | # @default keyvalue.database.expirable 140 | # default: keyvalue.database.expirable 141 | # Allowed protocols for URL generation. 142 | filter_protocols: 143 | - http 144 | - https 145 | - ftp 146 | - news 147 | - nntp 148 | - tel 149 | - telnet 150 | - mailto 151 | - irc 152 | - ssh 153 | - sftp 154 | - webcal 155 | - rtsp 156 | 157 | # Configure Cross-Site HTTP requests (CORS). 158 | # Read https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS 159 | # for more information about the topic in general. 160 | # Note: By default the configuration is disabled. 161 | cors.config: 162 | enabled: false 163 | # Specify allowed headers, like 'x-allowed-header'. 164 | allowedHeaders: [] 165 | # Specify allowed request methods, specify ['*'] to allow all possible ones. 166 | allowedMethods: [] 167 | # Configure requests allowed from specific origins. 168 | allowedOrigins: ['*'] 169 | # Sets the Access-Control-Expose-Headers header. 170 | exposedHeaders: false 171 | # Sets the Access-Control-Max-Age header. 172 | maxAge: false 173 | # Sets the Access-Control-Allow-Credentials header. 174 | supportsCredentials: false 175 | -------------------------------------------------------------------------------- /web/sites/default/settings.local.php: -------------------------------------------------------------------------------- 1 | 'mysql', 9 | 'host' => 'mariadb', 10 | 'username' => 'mysql', 11 | 'password' => 'mysql', 12 | 'database' => 'data', 13 | 'prefix' => '', 14 | ); 15 | $config['search_api.server.solr']['backend_config']['connector_config']['host'] = 'solr'; 16 | $config['search_api.server.solr']['backend_config']['connector_config']['port'] = '8080'; 17 | 18 | $settings['hash_salt'] = hash('sha256', serialize($databases)); 19 | 20 | // Database configuration. 21 | if (empty($_SERVER['APP_DOCKER'])) { 22 | 23 | $port_cmd = "docker inspect --format='{{(index (index .NetworkSettings.Ports \"3306/tcp\") 0).HostPort}}' commerce2_mariadb_1"; 24 | $port = trim(shell_exec($port_cmd)); 25 | 26 | // Default config within Docker container. 27 | $databases['default']['default'] = array( 28 | 'driver' => 'mysql', 29 | 'host' => 'commerce2.dev', 30 | 'port' => $port, 31 | 'username' => 'mysql', 32 | 'password' => 'mysql', 33 | 'database' => 'data', 34 | 'prefix' => '', 35 | ); 36 | 37 | // @todo add solr support 38 | // $port_cmd = "docker inspect --format='{{(index (index .NetworkSettings.Ports \"8080/tcp\") 0).HostPort}}' forkdin_solr_1"; 39 | // $port = trim(shell_exec($port_cmd)); 40 | // $config['search_api.server.solr']['backend_config']['connector_config']['host'] = 'localhost'; 41 | // $config['search_api.server.solr']['backend_config']['connector_config']['port'] = $port; 42 | } 43 | -------------------------------------------------------------------------------- /web/sites/default/settings.php: -------------------------------------------------------------------------------- 1 | 'databasename', 79 | * 'username' => 'sqlusername', 80 | * 'password' => 'sqlpassword', 81 | * 'host' => 'localhost', 82 | * 'port' => '3306', 83 | * 'driver' => 'mysql', 84 | * 'prefix' => '', 85 | * 'collation' => 'utf8mb4_general_ci', 86 | * ); 87 | * @endcode 88 | */ 89 | $databases = array(); 90 | 91 | /** 92 | * Customizing database settings. 93 | * 94 | * Many of the values of the $databases array can be customized for your 95 | * particular database system. Refer to the sample in the section above as a 96 | * starting point. 97 | * 98 | * The "driver" property indicates what Drupal database driver the 99 | * connection should use. This is usually the same as the name of the 100 | * database type, such as mysql or sqlite, but not always. The other 101 | * properties will vary depending on the driver. For SQLite, you must 102 | * specify a database file name in a directory that is writable by the 103 | * webserver. For most other drivers, you must specify a 104 | * username, password, host, and database name. 105 | * 106 | * Transaction support is enabled by default for all drivers that support it, 107 | * including MySQL. To explicitly disable it, set the 'transactions' key to 108 | * FALSE. 109 | * Note that some configurations of MySQL, such as the MyISAM engine, don't 110 | * support it and will proceed silently even if enabled. If you experience 111 | * transaction related crashes with such configuration, set the 'transactions' 112 | * key to FALSE. 113 | * 114 | * For each database, you may optionally specify multiple "target" databases. 115 | * A target database allows Drupal to try to send certain queries to a 116 | * different database if it can but fall back to the default connection if not. 117 | * That is useful for primary/replica replication, as Drupal may try to connect 118 | * to a replica server when appropriate and if one is not available will simply 119 | * fall back to the single primary server (The terms primary/replica are 120 | * traditionally referred to as master/slave in database server documentation). 121 | * 122 | * The general format for the $databases array is as follows: 123 | * @code 124 | * $databases['default']['default'] = $info_array; 125 | * $databases['default']['replica'][] = $info_array; 126 | * $databases['default']['replica'][] = $info_array; 127 | * $databases['extra']['default'] = $info_array; 128 | * @endcode 129 | * 130 | * In the above example, $info_array is an array of settings described above. 131 | * The first line sets a "default" database that has one primary database 132 | * (the second level default). The second and third lines create an array 133 | * of potential replica databases. Drupal will select one at random for a given 134 | * request as needed. The fourth line creates a new database with a name of 135 | * "extra". 136 | * 137 | * You can optionally set prefixes for some or all database table names 138 | * by using the 'prefix' setting. If a prefix is specified, the table 139 | * name will be prepended with its value. Be sure to use valid database 140 | * characters only, usually alphanumeric and underscore. If no prefixes 141 | * are desired, leave it as an empty string ''. 142 | * 143 | * To have all database names prefixed, set 'prefix' as a string: 144 | * @code 145 | * 'prefix' => 'main_', 146 | * @endcode 147 | * To provide prefixes for specific tables, set 'prefix' as an array. 148 | * The array's keys are the table names and the values are the prefixes. 149 | * The 'default' element is mandatory and holds the prefix for any tables 150 | * not specified elsewhere in the array. Example: 151 | * @code 152 | * 'prefix' => array( 153 | * 'default' => 'main_', 154 | * 'users' => 'shared_', 155 | * 'sessions' => 'shared_', 156 | * 'role' => 'shared_', 157 | * 'authmap' => 'shared_', 158 | * ), 159 | * @endcode 160 | * You can also use a reference to a schema/database as a prefix. This may be 161 | * useful if your Drupal installation exists in a schema that is not the default 162 | * or you want to access several databases from the same code base at the same 163 | * time. 164 | * Example: 165 | * @code 166 | * 'prefix' => array( 167 | * 'default' => 'main.', 168 | * 'users' => 'shared.', 169 | * 'sessions' => 'shared.', 170 | * 'role' => 'shared.', 171 | * 'authmap' => 'shared.', 172 | * ); 173 | * @endcode 174 | * NOTE: MySQL and SQLite's definition of a schema is a database. 175 | * 176 | * Advanced users can add or override initial commands to execute when 177 | * connecting to the database server, as well as PDO connection settings. For 178 | * example, to enable MySQL SELECT queries to exceed the max_join_size system 179 | * variable, and to reduce the database connection timeout to 5 seconds: 180 | * @code 181 | * $databases['default']['default'] = array( 182 | * 'init_commands' => array( 183 | * 'big_selects' => 'SET SQL_BIG_SELECTS=1', 184 | * ), 185 | * 'pdo' => array( 186 | * PDO::ATTR_TIMEOUT => 5, 187 | * ), 188 | * ); 189 | * @endcode 190 | * 191 | * WARNING: The above defaults are designed for database portability. Changing 192 | * them may cause unexpected behavior, including potential data loss. See 193 | * https://www.drupal.org/developing/api/database/configuration for more 194 | * information on these defaults and the potential issues. 195 | * 196 | * More details can be found in the constructor methods for each driver: 197 | * - \Drupal\Core\Database\Driver\mysql\Connection::__construct() 198 | * - \Drupal\Core\Database\Driver\pgsql\Connection::__construct() 199 | * - \Drupal\Core\Database\Driver\sqlite\Connection::__construct() 200 | * 201 | * Sample Database configuration format for PostgreSQL (pgsql): 202 | * @code 203 | * $databases['default']['default'] = array( 204 | * 'driver' => 'pgsql', 205 | * 'database' => 'databasename', 206 | * 'username' => 'sqlusername', 207 | * 'password' => 'sqlpassword', 208 | * 'host' => 'localhost', 209 | * 'prefix' => '', 210 | * ); 211 | * @endcode 212 | * 213 | * Sample Database configuration format for SQLite (sqlite): 214 | * @code 215 | * $databases['default']['default'] = array( 216 | * 'driver' => 'sqlite', 217 | * 'database' => '/path/to/databasefilename', 218 | * ); 219 | * @endcode 220 | */ 221 | 222 | /** 223 | * Location of the site configuration files. 224 | * 225 | * The $config_directories array specifies the location of file system 226 | * directories used for configuration data. On install, the "sync" directory is 227 | * created. This is used for configuration imports. The "active" directory is 228 | * not created by default since the default storage for active configuration is 229 | * the database rather than the file system. (This can be changed. See "Active 230 | * configuration settings" below). 231 | * 232 | * The default location for the "sync" directory is inside a randomly-named 233 | * directory in the public files path. The setting below allows you to override 234 | * the "sync" location. 235 | * 236 | * If you use files for the "active" configuration, you can tell the 237 | * Configuration system where this directory is located by adding an entry with 238 | * array key CONFIG_ACTIVE_DIRECTORY. 239 | * 240 | * Example: 241 | * @code 242 | * $config_directories = array( 243 | * CONFIG_SYNC_DIRECTORY => '/directory/outside/webroot', 244 | * ); 245 | * @endcode 246 | */ 247 | $config_directories = [ 248 | CONFIG_SYNC_DIRECTORY => '../config/sync', 249 | ]; 250 | 251 | /** 252 | * Settings: 253 | * 254 | * $settings contains environment-specific configuration, such as the files 255 | * directory and reverse proxy address, and temporary configuration, such as 256 | * security overrides. 257 | * 258 | * @see \Drupal\Core\Site\Settings::get() 259 | */ 260 | 261 | /** 262 | * The active installation profile. 263 | * 264 | * Changing this after installation is not recommended as it changes which 265 | * directories are scanned during extension discovery. If this is set prior to 266 | * installation this value will be rewritten according to the profile selected 267 | * by the user. 268 | * 269 | * @see install_select_profile() 270 | */ 271 | # $settings['install_profile'] = ''; 272 | 273 | /** 274 | * Salt for one-time login links, cancel links, form tokens, etc. 275 | * 276 | * This variable will be set to a random value by the installer. All one-time 277 | * login links will be invalidated if the value is changed. Note that if your 278 | * site is deployed on a cluster of web servers, you must ensure that this 279 | * variable has the same value on each server. 280 | * 281 | * For enhanced security, you may set this variable to the contents of a file 282 | * outside your document root; you should also ensure that this file is not 283 | * stored with backups of your database. 284 | * 285 | * Example: 286 | * @code 287 | * $settings['hash_salt'] = file_get_contents('/home/example/salt.txt'); 288 | * @endcode 289 | */ 290 | $settings['hash_salt'] = ''; 291 | 292 | /** 293 | * Deployment identifier. 294 | * 295 | * Drupal's dependency injection container will be automatically invalidated and 296 | * rebuilt when the Drupal core version changes. When updating contributed or 297 | * custom code that changes the container, changing this identifier will also 298 | * allow the container to be invalidated as soon as code is deployed. 299 | */ 300 | # $settings['deployment_identifier'] = \Drupal::VERSION; 301 | 302 | /** 303 | * Access control for update.php script. 304 | * 305 | * If you are updating your Drupal installation using the update.php script but 306 | * are not logged in using either an account with the "Administer software 307 | * updates" permission or the site maintenance account (the account that was 308 | * created during installation), you will need to modify the access check 309 | * statement below. Change the FALSE to a TRUE to disable the access check. 310 | * After finishing the upgrade, be sure to open this file again and change the 311 | * TRUE back to a FALSE! 312 | */ 313 | $settings['update_free_access'] = FALSE; 314 | 315 | /** 316 | * External access proxy settings: 317 | * 318 | * If your site must access the Internet via a web proxy then you can enter the 319 | * proxy settings here. Set the full URL of the proxy, including the port, in 320 | * variables: 321 | * - $settings['http_client_config']['proxy']['http']: The proxy URL for HTTP 322 | * requests. 323 | * - $settings['http_client_config']['proxy']['https']: The proxy URL for HTTPS 324 | * requests. 325 | * You can pass in the user name and password for basic authentication in the 326 | * URLs in these settings. 327 | * 328 | * You can also define an array of host names that can be accessed directly, 329 | * bypassing the proxy, in $settings['http_client_config']['proxy']['no']. 330 | */ 331 | # $settings['http_client_config']['proxy']['http'] = 'http://proxy_user:proxy_pass@example.com:8080'; 332 | # $settings['http_client_config']['proxy']['https'] = 'http://proxy_user:proxy_pass@example.com:8080'; 333 | # $settings['http_client_config']['proxy']['no'] = ['127.0.0.1', 'localhost']; 334 | 335 | /** 336 | * Reverse Proxy Configuration: 337 | * 338 | * Reverse proxy servers are often used to enhance the performance 339 | * of heavily visited sites and may also provide other site caching, 340 | * security, or encryption benefits. In an environment where Drupal 341 | * is behind a reverse proxy, the real IP address of the client should 342 | * be determined such that the correct client IP address is available 343 | * to Drupal's logging, statistics, and access management systems. In 344 | * the most simple scenario, the proxy server will add an 345 | * X-Forwarded-For header to the request that contains the client IP 346 | * address. However, HTTP headers are vulnerable to spoofing, where a 347 | * malicious client could bypass restrictions by setting the 348 | * X-Forwarded-For header directly. Therefore, Drupal's proxy 349 | * configuration requires the IP addresses of all remote proxies to be 350 | * specified in $settings['reverse_proxy_addresses'] to work correctly. 351 | * 352 | * Enable this setting to get Drupal to determine the client IP from 353 | * the X-Forwarded-For header (or $settings['reverse_proxy_header'] if set). 354 | * If you are unsure about this setting, do not have a reverse proxy, 355 | * or Drupal operates in a shared hosting environment, this setting 356 | * should remain commented out. 357 | * 358 | * In order for this setting to be used you must specify every possible 359 | * reverse proxy IP address in $settings['reverse_proxy_addresses']. 360 | * If a complete list of reverse proxies is not available in your 361 | * environment (for example, if you use a CDN) you may set the 362 | * $_SERVER['REMOTE_ADDR'] variable directly in settings.php. 363 | * Be aware, however, that it is likely that this would allow IP 364 | * address spoofing unless more advanced precautions are taken. 365 | */ 366 | # $settings['reverse_proxy'] = TRUE; 367 | 368 | /** 369 | * Specify every reverse proxy IP address in your environment. 370 | * This setting is required if $settings['reverse_proxy'] is TRUE. 371 | */ 372 | # $settings['reverse_proxy_addresses'] = array('a.b.c.d', ...); 373 | 374 | /** 375 | * Set this value if your proxy server sends the client IP in a header 376 | * other than X-Forwarded-For. 377 | */ 378 | # $settings['reverse_proxy_header'] = 'X_CLUSTER_CLIENT_IP'; 379 | 380 | /** 381 | * Set this value if your proxy server sends the client protocol in a header 382 | * other than X-Forwarded-Proto. 383 | */ 384 | # $settings['reverse_proxy_proto_header'] = 'X_FORWARDED_PROTO'; 385 | 386 | /** 387 | * Set this value if your proxy server sends the client protocol in a header 388 | * other than X-Forwarded-Host. 389 | */ 390 | # $settings['reverse_proxy_host_header'] = 'X_FORWARDED_HOST'; 391 | 392 | /** 393 | * Set this value if your proxy server sends the client protocol in a header 394 | * other than X-Forwarded-Port. 395 | */ 396 | # $settings['reverse_proxy_port_header'] = 'X_FORWARDED_PORT'; 397 | 398 | /** 399 | * Set this value if your proxy server sends the client protocol in a header 400 | * other than Forwarded. 401 | */ 402 | # $settings['reverse_proxy_forwarded_header'] = 'FORWARDED'; 403 | 404 | /** 405 | * Page caching: 406 | * 407 | * By default, Drupal sends a "Vary: Cookie" HTTP header for anonymous page 408 | * views. This tells a HTTP proxy that it may return a page from its local 409 | * cache without contacting the web server, if the user sends the same Cookie 410 | * header as the user who originally requested the cached page. Without "Vary: 411 | * Cookie", authenticated users would also be served the anonymous page from 412 | * the cache. If the site has mostly anonymous users except a few known 413 | * editors/administrators, the Vary header can be omitted. This allows for 414 | * better caching in HTTP proxies (including reverse proxies), i.e. even if 415 | * clients send different cookies, they still get content served from the cache. 416 | * However, authenticated users should access the site directly (i.e. not use an 417 | * HTTP proxy, and bypass the reverse proxy if one is used) in order to avoid 418 | * getting cached pages from the proxy. 419 | */ 420 | # $settings['omit_vary_cookie'] = TRUE; 421 | 422 | 423 | /** 424 | * Cache TTL for client error (4xx) responses. 425 | * 426 | * Items cached per-URL tend to result in a large number of cache items, and 427 | * this can be problematic on 404 pages which by their nature are unbounded. A 428 | * fixed TTL can be set for these items, defaulting to one hour, so that cache 429 | * backends which do not support LRU can purge older entries. To disable caching 430 | * of client error responses set the value to 0. Currently applies only to 431 | * page_cache module. 432 | */ 433 | # $settings['cache_ttl_4xx'] = 3600; 434 | 435 | 436 | /** 437 | * Class Loader. 438 | * 439 | * If the APC extension is detected, the Symfony APC class loader is used for 440 | * performance reasons. Detection can be prevented by setting 441 | * class_loader_auto_detect to false, as in the example below. 442 | */ 443 | # $settings['class_loader_auto_detect'] = FALSE; 444 | 445 | /* 446 | * If the APC extension is not detected, either because APC is missing or 447 | * because auto-detection has been disabled, auto-loading falls back to 448 | * Composer's ClassLoader, which is good for development as it does not break 449 | * when code is moved in the file system. You can also decorate the base class 450 | * loader with another cached solution than the Symfony APC class loader, as 451 | * all production sites should have a cached class loader of some sort enabled. 452 | * 453 | * To do so, you may decorate and replace the local $class_loader variable. For 454 | * example, to use Symfony's APC class loader without automatic detection, 455 | * uncomment the code below. 456 | */ 457 | /* 458 | if ($settings['hash_salt']) { 459 | $prefix = 'drupal.' . hash('sha256', 'drupal.' . $settings['hash_salt']); 460 | $apc_loader = new \Symfony\Component\ClassLoader\ApcClassLoader($prefix, $class_loader); 461 | unset($prefix); 462 | $class_loader->unregister(); 463 | $apc_loader->register(); 464 | $class_loader = $apc_loader; 465 | } 466 | */ 467 | 468 | /** 469 | * Authorized file system operations: 470 | * 471 | * The Update Manager module included with Drupal provides a mechanism for 472 | * site administrators to securely install missing updates for the site 473 | * directly through the web user interface. On securely-configured servers, 474 | * the Update manager will require the administrator to provide SSH or FTP 475 | * credentials before allowing the installation to proceed; this allows the 476 | * site to update the new files as the user who owns all the Drupal files, 477 | * instead of as the user the webserver is running as. On servers where the 478 | * webserver user is itself the owner of the Drupal files, the administrator 479 | * will not be prompted for SSH or FTP credentials (note that these server 480 | * setups are common on shared hosting, but are inherently insecure). 481 | * 482 | * Some sites might wish to disable the above functionality, and only update 483 | * the code directly via SSH or FTP themselves. This setting completely 484 | * disables all functionality related to these authorized file operations. 485 | * 486 | * @see https://www.drupal.org/node/244924 487 | * 488 | * Remove the leading hash signs to disable. 489 | */ 490 | # $settings['allow_authorize_operations'] = FALSE; 491 | 492 | /** 493 | * Default mode for directories and files written by Drupal. 494 | * 495 | * Value should be in PHP Octal Notation, with leading zero. 496 | */ 497 | # $settings['file_chmod_directory'] = 0775; 498 | # $settings['file_chmod_file'] = 0664; 499 | 500 | /** 501 | * Public file base URL: 502 | * 503 | * An alternative base URL to be used for serving public files. This must 504 | * include any leading directory path. 505 | * 506 | * A different value from the domain used by Drupal to be used for accessing 507 | * public files. This can be used for a simple CDN integration, or to improve 508 | * security by serving user-uploaded files from a different domain or subdomain 509 | * pointing to the same server. Do not include a trailing slash. 510 | */ 511 | # $settings['file_public_base_url'] = 'http://downloads.example.com/files'; 512 | 513 | /** 514 | * Public file path: 515 | * 516 | * A local file system path where public files will be stored. This directory 517 | * must exist and be writable by Drupal. This directory must be relative to 518 | * the Drupal installation directory and be accessible over the web. 519 | */ 520 | # $settings['file_public_path'] = 'sites/default/files'; 521 | 522 | /** 523 | * Private file path: 524 | * 525 | * A local file system path where private files will be stored. This directory 526 | * must be absolute, outside of the Drupal installation directory and not 527 | * accessible over the web. 528 | * 529 | * Note: Caches need to be cleared when this value is changed to make the 530 | * private:// stream wrapper available to the system. 531 | * 532 | * See https://www.drupal.org/documentation/modules/file for more information 533 | * about securing private files. 534 | */ 535 | # $settings['file_private_path'] = ''; 536 | 537 | /** 538 | * Session write interval: 539 | * 540 | * Set the minimum interval between each session write to database. 541 | * For performance reasons it defaults to 180. 542 | */ 543 | # $settings['session_write_interval'] = 180; 544 | 545 | /** 546 | * String overrides: 547 | * 548 | * To override specific strings on your site with or without enabling the Locale 549 | * module, add an entry to this list. This functionality allows you to change 550 | * a small number of your site's default English language interface strings. 551 | * 552 | * Remove the leading hash signs to enable. 553 | * 554 | * The "en" part of the variable name, is dynamic and can be any langcode of 555 | * any added language. (eg locale_custom_strings_de for german). 556 | */ 557 | # $settings['locale_custom_strings_en'][''] = array( 558 | # 'forum' => 'Discussion board', 559 | # '@count min' => '@count minutes', 560 | # ); 561 | 562 | /** 563 | * A custom theme for the offline page: 564 | * 565 | * This applies when the site is explicitly set to maintenance mode through the 566 | * administration page or when the database is inactive due to an error. 567 | * The template file should also be copied into the theme. It is located inside 568 | * 'core/modules/system/templates/maintenance-page.html.twig'. 569 | * 570 | * Note: This setting does not apply to installation and update pages. 571 | */ 572 | # $settings['maintenance_theme'] = 'bartik'; 573 | 574 | /** 575 | * PHP settings: 576 | * 577 | * To see what PHP settings are possible, including whether they can be set at 578 | * runtime (by using ini_set()), read the PHP documentation: 579 | * http://php.net/manual/ini.list.php 580 | * See \Drupal\Core\DrupalKernel::bootEnvironment() for required runtime 581 | * settings and the .htaccess file for non-runtime settings. 582 | * Settings defined there should not be duplicated here so as to avoid conflict 583 | * issues. 584 | */ 585 | 586 | /** 587 | * If you encounter a situation where users post a large amount of text, and 588 | * the result is stripped out upon viewing but can still be edited, Drupal's 589 | * output filter may not have sufficient memory to process it. If you 590 | * experience this issue, you may wish to uncomment the following two lines 591 | * and increase the limits of these variables. For more information, see 592 | * http://php.net/manual/pcre.configuration.php. 593 | */ 594 | # ini_set('pcre.backtrack_limit', 200000); 595 | # ini_set('pcre.recursion_limit', 200000); 596 | 597 | /** 598 | * Active configuration settings. 599 | * 600 | * By default, the active configuration is stored in the database in the 601 | * {config} table. To use a different storage mechanism for the active 602 | * configuration, do the following prior to installing: 603 | * - Create an "active" directory and declare its path in $config_directories 604 | * as explained under the 'Location of the site configuration files' section 605 | * above in this file. To enhance security, you can declare a path that is 606 | * outside your document root. 607 | * - Override the 'bootstrap_config_storage' setting here. It must be set to a 608 | * callable that returns an object that implements 609 | * \Drupal\Core\Config\StorageInterface. 610 | * - Override the service definition 'config.storage.active'. Put this 611 | * override in a services.yml file in the same directory as settings.php 612 | * (definitions in this file will override service definition defaults). 613 | */ 614 | # $settings['bootstrap_config_storage'] = array('Drupal\Core\Config\BootstrapConfigStorageFactory', 'getFileStorage'); 615 | 616 | /** 617 | * Configuration overrides. 618 | * 619 | * To globally override specific configuration values for this site, 620 | * set them here. You usually don't need to use this feature. This is 621 | * useful in a configuration file for a vhost or directory, rather than 622 | * the default settings.php. 623 | * 624 | * Note that any values you provide in these variable overrides will not be 625 | * viewable from the Drupal administration interface. The administration 626 | * interface displays the values stored in configuration so that you can stage 627 | * changes to other environments that don't have the overrides. 628 | * 629 | * There are particular configuration values that are risky to override. For 630 | * example, overriding the list of installed modules in 'core.extension' is not 631 | * supported as module install or uninstall has not occurred. Other examples 632 | * include field storage configuration, because it has effects on database 633 | * structure, and 'core.menu.static_menu_link_overrides' since this is cached in 634 | * a way that is not config override aware. Also, note that changing 635 | * configuration values in settings.php will not fire any of the configuration 636 | * change events. 637 | */ 638 | # $config['system.site']['name'] = 'My Drupal site'; 639 | # $config['system.theme']['default'] = 'stark'; 640 | # $config['user.settings']['anonymous'] = 'Visitor'; 641 | 642 | /** 643 | * Fast 404 pages: 644 | * 645 | * Drupal can generate fully themed 404 pages. However, some of these responses 646 | * are for images or other resource files that are not displayed to the user. 647 | * This can waste bandwidth, and also generate server load. 648 | * 649 | * The options below return a simple, fast 404 page for URLs matching a 650 | * specific pattern: 651 | * - $config['system.performance']['fast_404']['exclude_paths']: A regular 652 | * expression to match paths to exclude, such as images generated by image 653 | * styles, or dynamically-resized images. The default pattern provided below 654 | * also excludes the private file system. If you need to add more paths, you 655 | * can add '|path' to the expression. 656 | * - $config['system.performance']['fast_404']['paths']: A regular expression to 657 | * match paths that should return a simple 404 page, rather than the fully 658 | * themed 404 page. If you don't have any aliases ending in htm or html you 659 | * can add '|s?html?' to the expression. 660 | * - $config['system.performance']['fast_404']['html']: The html to return for 661 | * simple 404 pages. 662 | * 663 | * Remove the leading hash signs if you would like to alter this functionality. 664 | */ 665 | # $config['system.performance']['fast_404']['exclude_paths'] = '/\/(?:styles)|(?:system\/files)\//'; 666 | # $config['system.performance']['fast_404']['paths'] = '/\.(?:txt|png|gif|jpe?g|css|js|ico|swf|flv|cgi|bat|pl|dll|exe|asp)$/i'; 667 | # $config['system.performance']['fast_404']['html'] = '404 Not Found

Not Found

The requested URL "@path" was not found on this server.

'; 668 | 669 | /** 670 | * Load services definition file. 671 | */ 672 | $settings['container_yamls'][] = $app_root . '/' . $site_path . '/services.yml'; 673 | 674 | /** 675 | * Override the default service container class. 676 | * 677 | * This is useful for example to trace the service container for performance 678 | * tracking purposes, for testing a service container with an error condition or 679 | * to test a service container that throws an exception. 680 | */ 681 | # $settings['container_base_class'] = '\Drupal\Core\DependencyInjection\Container'; 682 | 683 | /** 684 | * Override the default yaml parser class. 685 | * 686 | * Provide a fully qualified class name here if you would like to provide an 687 | * alternate implementation YAML parser. The class must implement the 688 | * \Drupal\Component\Serialization\SerializationInterface interface. 689 | */ 690 | # $settings['yaml_parser_class'] = NULL; 691 | 692 | /** 693 | * Trusted host configuration. 694 | * 695 | * Drupal core can use the Symfony trusted host mechanism to prevent HTTP Host 696 | * header spoofing. 697 | * 698 | * To enable the trusted host mechanism, you enable your allowable hosts 699 | * in $settings['trusted_host_patterns']. This should be an array of regular 700 | * expression patterns, without delimiters, representing the hosts you would 701 | * like to allow. 702 | * 703 | * For example: 704 | * @code 705 | * $settings['trusted_host_patterns'] = array( 706 | * '^www\.example\.com$', 707 | * ); 708 | * @endcode 709 | * will allow the site to only run from www.example.com. 710 | * 711 | * If you are running multisite, or if you are running your site from 712 | * different domain names (eg, you don't redirect http://www.example.com to 713 | * http://example.com), you should specify all of the host patterns that are 714 | * allowed by your site. 715 | * 716 | * For example: 717 | * @code 718 | * $settings['trusted_host_patterns'] = array( 719 | * '^example\.com$', 720 | * '^.+\.example\.com$', 721 | * '^example\.org$', 722 | * '^.+\.example\.org$', 723 | * ); 724 | * @endcode 725 | * will allow the site to run off of all variants of example.com and 726 | * example.org, with all subdomains included. 727 | */ 728 | 729 | /** 730 | * The default list of directories that will be ignored by Drupal's file API. 731 | * 732 | * By default ignore node_modules and bower_components folders to avoid issues 733 | * with common frontend tools and recursive scanning of directories looking for 734 | * extensions. 735 | * 736 | * @see file_scan_directory() 737 | * @see \Drupal\Core\Extension\ExtensionDiscovery::scanDirectory() 738 | */ 739 | $settings['file_scan_ignore_directories'] = [ 740 | 'node_modules', 741 | 'bower_components', 742 | ]; 743 | 744 | /** 745 | * Load local development override configuration, if available. 746 | * 747 | * Use settings.local.php to override variables on secondary (staging, 748 | * development, etc) installations of this site. Typically used to disable 749 | * caching, JavaScript/CSS compression, re-routing of outgoing emails, and 750 | * other things that should not happen on development and testing sites. 751 | * 752 | * Keep this code block at the end of this file to take full effect. 753 | */ 754 | 755 | if (file_exists($app_root . '/' . $site_path . '/settings.local.php')) { 756 | include $app_root . '/' . $site_path . '/settings.local.php'; 757 | } 758 | $settings['install_profile'] = 'commerce_base'; 759 | -------------------------------------------------------------------------------- /web/sites/development.services.yml: -------------------------------------------------------------------------------- 1 | # Local development services. 2 | # 3 | # To activate this feature, follow the instructions at the top of the 4 | # 'example.settings.local.php' file, which sits next to this file. 5 | parameters: 6 | http.response.debug_cacheability_headers: true 7 | services: 8 | cache.backend.null: 9 | class: Drupal\Core\Cache\NullBackendFactory 10 | -------------------------------------------------------------------------------- /web/sites/example.settings.local.php: -------------------------------------------------------------------------------- 1 | ..' => 'directory'. As an 24 | * example, to map https://www.drupal.org:8080/mysite/test to the configuration 25 | * directory sites/example.com, the array should be defined as: 26 | * @code 27 | * $sites = array( 28 | * '8080.www.drupal.org.mysite.test' => 'example.com', 29 | * ); 30 | * @endcode 31 | * The URL, https://www.drupal.org:8080/mysite/test/, could be a symbolic link 32 | * or an Apache Alias directive that points to the Drupal root containing 33 | * index.php. An alias could also be created for a subdomain. See the 34 | * @link https://www.drupal.org/documentation/install online Drupal installation guide @endlink 35 | * for more information on setting up domains, subdomains, and subdirectories. 36 | * 37 | * The following examples look for a site configuration in sites/example.com: 38 | * @code 39 | * URL: http://dev.drupal.org 40 | * $sites['dev.drupal.org'] = 'example.com'; 41 | * 42 | * URL: http://localhost/example 43 | * $sites['localhost.example'] = 'example.com'; 44 | * 45 | * URL: http://localhost:8080/example 46 | * $sites['8080.localhost.example'] = 'example.com'; 47 | * 48 | * URL: https://www.drupal.org:8080/mysite/test/ 49 | * $sites['8080.www.drupal.org.mysite.test'] = 'example.com'; 50 | * @endcode 51 | * 52 | * @see default.settings.php 53 | * @see \Drupal\Core\DrupalKernel::getSitePath() 54 | * @see https://www.drupal.org/documentation/install/multi-site 55 | */ 56 | -------------------------------------------------------------------------------- /web/themes/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mglaman/commerce-project-template/4e5416869ddfbc318f3219c4fa6234945bbe0e7c/web/themes/.gitkeep -------------------------------------------------------------------------------- /web/update.php: -------------------------------------------------------------------------------- 1 | handle($request); 29 | $response->send(); 30 | 31 | $kernel->terminate($request, $response); 32 | -------------------------------------------------------------------------------- /web/web.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 13 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 48 | 51 | 60 | 61 | 64 | 73 | 74 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | --------------------------------------------------------------------------------