From 1a6f571e1537ff058095a4108081a9b9601dc4dc Mon Sep 17 00:00:00 2001 From: Bachir Soussi Chiadmi Date: Tue, 3 Apr 2018 23:06:38 +0200 Subject: [PATCH] added config_ignore contrib module to ignore performance and devel config --- .../contrib/dev/config_filter/.gitignore | 2 + .../contrib/dev/config_filter/.travis.yml | 41 +++ .../contrib/dev/config_filter/LICENSE.txt | 339 ++++++++++++++++++ .../contrib/dev/config_filter/README.md | 50 +++ .../contrib/dev/config_filter/composer.json | 31 ++ .../dev/config_filter/config_filter.info.yml | 11 + .../config_filter/config_filter.services.yml | 16 + .../src/Annotation/ConfigFilter.php | 62 ++++ .../src/Config/FilteredStorage.php | 248 +++++++++++++ .../src/Config/FilteredStorageInterface.php | 12 + .../src/Config/ReadOnlyStorage.php | 125 +++++++ .../src/Config/StorageFilterInterface.php | 223 ++++++++++++ .../src/ConfigFilterManagerInterface.php | 34 ++ .../src/ConfigFilterStorageFactory.php | 93 +++++ .../src/Exception/UnsupportedMethod.php | 9 + .../src/Plugin/ConfigFilterBase.php | 145 ++++++++ .../src/Plugin/ConfigFilterInterface.php | 13 + .../src/Plugin/ConfigFilterPluginManager.php | 80 +++++ .../src/Tests/FilteredStorageTest.php | 298 +++++++++++++++ .../src/Tests/ReadonlyStorageTest.php | 138 +++++++ .../src/Tests/TransparentFilter.php | 40 +++ .../dev/config_filter/tests/composer.json | 24 ++ .../config_filter_split_test/README.md | 40 +++ .../config_filter_split_test.info.yml | 12 + .../src/Config/ActiveMigrateStorage.php | 34 ++ .../Plugin/ConfigFilter/TestSplitFilter.php | 167 +++++++++ .../config_filter_test.info.yml | 12 + .../src/Plugin/ConfigFilter/PirateFilter.php | 40 +++ .../dev/config_filter/tests/phpunit.xml.dist | 13 + .../Kernel/ConfigFilterStorageFactoryTest.php | 88 +++++ .../contrib/dev/config_ignore/LICENSE.txt | 339 ++++++++++++++++++ .../contrib/dev/config_ignore/README.txt | 41 +++ .../contrib/dev/config_ignore/composer.json | 29 ++ .../config/install/config_ignore.settings.yml | 1 + .../config/schema/config_ignore.schema.yml | 9 + .../dev/config_ignore/config_ignore.api.php | 23 ++ .../dev/config_ignore/config_ignore.info.yml | 14 + .../dev/config_ignore/config_ignore.install | 13 + .../config_ignore.links.task.yml | 5 + .../dev/config_ignore/config_ignore.module | 70 ++++ .../config_ignore/config_ignore.routing.yml | 7 + .../dev/config_ignore/src/Form/Settings.php | 76 ++++ .../src/Plugin/ConfigFilter/IgnoreFilter.php | 236 ++++++++++++ .../config_ignore_hook_test.info.yml | 13 + .../config_ignore_hook_test.module | 13 + .../ConfigIgnoreBrowserTestBase.php | 66 ++++ .../src/Functional/ConfigIgnoreHookTest.php | 47 +++ .../tests/src/Functional/ConfigIgnoreTest.php | 196 ++++++++++ .../config/sync/config_ignore.settings.yml | 6 + sites/default/config/sync/core.extension.yml | 2 + .../config/sync/system.performance.yml | 6 +- 51 files changed, 3649 insertions(+), 3 deletions(-) create mode 100644 sites/all/modules/contrib/dev/config_filter/.gitignore create mode 100644 sites/all/modules/contrib/dev/config_filter/.travis.yml create mode 100644 sites/all/modules/contrib/dev/config_filter/LICENSE.txt create mode 100644 sites/all/modules/contrib/dev/config_filter/README.md create mode 100644 sites/all/modules/contrib/dev/config_filter/composer.json create mode 100644 sites/all/modules/contrib/dev/config_filter/config_filter.info.yml create mode 100644 sites/all/modules/contrib/dev/config_filter/config_filter.services.yml create mode 100644 sites/all/modules/contrib/dev/config_filter/src/Annotation/ConfigFilter.php create mode 100644 sites/all/modules/contrib/dev/config_filter/src/Config/FilteredStorage.php create mode 100644 sites/all/modules/contrib/dev/config_filter/src/Config/FilteredStorageInterface.php create mode 100644 sites/all/modules/contrib/dev/config_filter/src/Config/ReadOnlyStorage.php create mode 100644 sites/all/modules/contrib/dev/config_filter/src/Config/StorageFilterInterface.php create mode 100644 sites/all/modules/contrib/dev/config_filter/src/ConfigFilterManagerInterface.php create mode 100644 sites/all/modules/contrib/dev/config_filter/src/ConfigFilterStorageFactory.php create mode 100644 sites/all/modules/contrib/dev/config_filter/src/Exception/UnsupportedMethod.php create mode 100644 sites/all/modules/contrib/dev/config_filter/src/Plugin/ConfigFilterBase.php create mode 100644 sites/all/modules/contrib/dev/config_filter/src/Plugin/ConfigFilterInterface.php create mode 100644 sites/all/modules/contrib/dev/config_filter/src/Plugin/ConfigFilterPluginManager.php create mode 100644 sites/all/modules/contrib/dev/config_filter/src/Tests/FilteredStorageTest.php create mode 100644 sites/all/modules/contrib/dev/config_filter/src/Tests/ReadonlyStorageTest.php create mode 100644 sites/all/modules/contrib/dev/config_filter/src/Tests/TransparentFilter.php create mode 100644 sites/all/modules/contrib/dev/config_filter/tests/composer.json create mode 100644 sites/all/modules/contrib/dev/config_filter/tests/modules/config_filter_split_test/README.md create mode 100644 sites/all/modules/contrib/dev/config_filter/tests/modules/config_filter_split_test/config_filter_split_test.info.yml create mode 100644 sites/all/modules/contrib/dev/config_filter/tests/modules/config_filter_split_test/src/Config/ActiveMigrateStorage.php create mode 100644 sites/all/modules/contrib/dev/config_filter/tests/modules/config_filter_split_test/src/Plugin/ConfigFilter/TestSplitFilter.php create mode 100644 sites/all/modules/contrib/dev/config_filter/tests/modules/config_filter_test/config_filter_test.info.yml create mode 100644 sites/all/modules/contrib/dev/config_filter/tests/modules/config_filter_test/src/Plugin/ConfigFilter/PirateFilter.php create mode 100644 sites/all/modules/contrib/dev/config_filter/tests/phpunit.xml.dist create mode 100644 sites/all/modules/contrib/dev/config_filter/tests/src/Kernel/ConfigFilterStorageFactoryTest.php create mode 100644 sites/all/modules/contrib/dev/config_ignore/LICENSE.txt create mode 100644 sites/all/modules/contrib/dev/config_ignore/README.txt create mode 100644 sites/all/modules/contrib/dev/config_ignore/composer.json create mode 100644 sites/all/modules/contrib/dev/config_ignore/config/install/config_ignore.settings.yml create mode 100644 sites/all/modules/contrib/dev/config_ignore/config/schema/config_ignore.schema.yml create mode 100644 sites/all/modules/contrib/dev/config_ignore/config_ignore.api.php create mode 100644 sites/all/modules/contrib/dev/config_ignore/config_ignore.info.yml create mode 100644 sites/all/modules/contrib/dev/config_ignore/config_ignore.install create mode 100644 sites/all/modules/contrib/dev/config_ignore/config_ignore.links.task.yml create mode 100644 sites/all/modules/contrib/dev/config_ignore/config_ignore.module create mode 100644 sites/all/modules/contrib/dev/config_ignore/config_ignore.routing.yml create mode 100644 sites/all/modules/contrib/dev/config_ignore/src/Form/Settings.php create mode 100644 sites/all/modules/contrib/dev/config_ignore/src/Plugin/ConfigFilter/IgnoreFilter.php create mode 100644 sites/all/modules/contrib/dev/config_ignore/tests/config_ignore_hook_test/config_ignore_hook_test.info.yml create mode 100644 sites/all/modules/contrib/dev/config_ignore/tests/config_ignore_hook_test/config_ignore_hook_test.module create mode 100644 sites/all/modules/contrib/dev/config_ignore/tests/src/Functional/ConfigIgnoreBrowserTestBase.php create mode 100644 sites/all/modules/contrib/dev/config_ignore/tests/src/Functional/ConfigIgnoreHookTest.php create mode 100644 sites/all/modules/contrib/dev/config_ignore/tests/src/Functional/ConfigIgnoreTest.php create mode 100644 sites/default/config/sync/config_ignore.settings.yml diff --git a/sites/all/modules/contrib/dev/config_filter/.gitignore b/sites/all/modules/contrib/dev/config_filter/.gitignore new file mode 100644 index 000000000..7579f7431 --- /dev/null +++ b/sites/all/modules/contrib/dev/config_filter/.gitignore @@ -0,0 +1,2 @@ +vendor +composer.lock diff --git a/sites/all/modules/contrib/dev/config_filter/.travis.yml b/sites/all/modules/contrib/dev/config_filter/.travis.yml new file mode 100644 index 000000000..bc434ee30 --- /dev/null +++ b/sites/all/modules/contrib/dev/config_filter/.travis.yml @@ -0,0 +1,41 @@ +language: php + +php: + - 5.6 + - 7.0 + +env: + global: + - PATH=$PATH:/home/travis/.composer/vendor/bin + +install: + - composer self-update + +before_script: + # Set sendmail so drush doesn't throw an error during site install. + - echo "sendmail_path=`which true`" >> `php --ini | grep "Loaded Configuration" | awk '{print $4}'` + # Create database. + - mysql -e 'create database drupal' + # Install Drupal 8 target site. + - cd tests + - mkdir -p themes modules profiles + - composer install --prefer-dist + - ./vendor/bin/drush si standard -y --db-url=mysql://travis:@127.0.0.1/drupal + # Test latest commit on current branch. + - git clone --branch=$TRAVIS_BRANCH https://github.com/$TRAVIS_REPO_SLUG.git modules/config_filter + - ./vendor/bin/drush en config_filter -y + # Run Drush web server. + - ./vendor/bin/drush --debug runserver :8888 > ~/debug.txt 2>&1 & + - sleep 4s + - chmod -R ug+w sites + +script: + - cd $TRAVIS_BUILD_DIR + - cd tests + - ./vendor/bin/phpcs --config-set installed_paths ../../drupal/coder/coder_sniffer + - ./vendor/bin/phpcs --config-set show_progress 1 + - ./vendor/bin/phpcs --warning-severity=0 --standard=Drupal,DrupalPractice ../src + - ./vendor/bin/phpunit + +notifications: + email: false diff --git a/sites/all/modules/contrib/dev/config_filter/LICENSE.txt b/sites/all/modules/contrib/dev/config_filter/LICENSE.txt new file mode 100644 index 000000000..d159169d1 --- /dev/null +++ b/sites/all/modules/contrib/dev/config_filter/LICENSE.txt @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/sites/all/modules/contrib/dev/config_filter/README.md b/sites/all/modules/contrib/dev/config_filter/README.md new file mode 100644 index 000000000..253c90403 --- /dev/null +++ b/sites/all/modules/contrib/dev/config_filter/README.md @@ -0,0 +1,50 @@ +# Config Filter + +[![Build Status](https://travis-ci.org/nuvoleweb/config_filter.svg?branch=8.x-1.x)](https://travis-ci.org/nuvoleweb/config_filter) +[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/nuvoleweb/config_filter/badges/quality-score.png?b=8.x-1.x)](https://scrutinizer-ci.com/g/nuvoleweb/config_filter/?branch=8.x-1.x) + + +## Introduction + +Modules such as Config Split want to modify the configuration when it is +synchronized between the database and the exported yaml files. +This module provides the API to do so but does not influence a sites operation. + +## How it works + +Configuration Filter swaps the config.storage.sync service from Drupal 8 core. +The new service wraps the file storage and applies filters to it. +This allows other modules to change the configuration as it gets imported or +exported both in the Drupal UI and with drush. + +## What is a ConfigFilter + +A ConfigFilter is a plugin. This module provides the plugin definition, the +plugin manager and the storage factory. +A ConfigFilter can have the following annotation: + +```php +/** + * @ConfigFilter( + * id = "may_plugin_id", + * label = @Translation("An example configuration filter"), + * weight = 0, + * status = TRUE, + * storages = {"config.storage.sync"}, + * ) + */ +``` +See `\Drupal\config_filter\Annotation\ConfigFilter`. + +The weight allows the filters to be sorted. The status allows the filter to be +active or inactive, the `ConfigFilterManagerInterface::getFiltersForStorages` +will only take active filters into consideration. The weight, status and +storages are optional and the above values are the default. + +## Alternative Config Filter Managers + +Plugins are only available from enabled modules. If you want to provide a +config filter from a php library, all you have to do is implement the +`\Drupal\config_filter\ConfigFilterManagerInterface` and add it to the +service container with a `config.filter` tag. +Services with higher priority will have their filters added first. diff --git a/sites/all/modules/contrib/dev/config_filter/composer.json b/sites/all/modules/contrib/dev/config_filter/composer.json new file mode 100644 index 000000000..68bbb961a --- /dev/null +++ b/sites/all/modules/contrib/dev/config_filter/composer.json @@ -0,0 +1,31 @@ +{ + "name": "drupal/config_filter", + "type": "drupal-module", + "description": "Config Filter allows other modules to interact with a ConfigStorage through filter plugins.", + "keywords": ["Drupal", "configuration", "configuration management"], + "authors": [ + { + "name": "Fabian Bircher", + "email": "opensource@fabianbircher.com", + "homepage": "https://www.drupal.org/u/bircher", + "role": "Maintainer" + }, + { + "name": "Nuvole Web", + "email": "info@nuvole.org", + "homepage": "http://nuvole.org", + "role": "Maintainer" + } + ], + "homepage": "https://www.drupal.org/project/config_filter", + "support": { + "issues": "https://www.drupal.org/project/issues/config_filter", + "irc": "irc://irc.freenode.org/drupal-contribute", + "source": "http://cgit.drupalcode.org/config_filter" + }, + "license": "GPL-2.0+", + "require": {}, + "suggest": { + "drupal/config_split": "Split site configuration for different environments." + } +} diff --git a/sites/all/modules/contrib/dev/config_filter/config_filter.info.yml b/sites/all/modules/contrib/dev/config_filter/config_filter.info.yml new file mode 100644 index 000000000..fa43d41be --- /dev/null +++ b/sites/all/modules/contrib/dev/config_filter/config_filter.info.yml @@ -0,0 +1,11 @@ +name: Config Filter +type: module +description: Config Filter allows other modules to interact with a ConfigStorage through filter plugins. +# core: 8.x +package: Config + +# Information added by Drupal.org packaging script on 2017-11-27 +version: '8.x-1.1' +core: '8.x' +project: 'config_filter' +datestamp: 1511779987 diff --git a/sites/all/modules/contrib/dev/config_filter/config_filter.services.yml b/sites/all/modules/contrib/dev/config_filter/config_filter.services.yml new file mode 100644 index 000000000..5d77008db --- /dev/null +++ b/sites/all/modules/contrib/dev/config_filter/config_filter.services.yml @@ -0,0 +1,16 @@ +services: + plugin.manager.config_filter: + class: Drupal\config_filter\Plugin\ConfigFilterPluginManager + parent: default_plugin_manager + tags: + - { name: config.filter } + config_filter.storage.sync: + class: Drupal\config_filter\Config\FilteredStorage + factory: config_filter.storage_factory:getSync + decorates: config.storage.staging + public: false + config_filter.storage_factory: + class: Drupal\config_filter\ConfigFilterStorageFactory + arguments: ['@config_filter.storage.sync.inner'] + tags: + - { name: service_collector, tag: 'config.filter', call: addConfigFilterManager } diff --git a/sites/all/modules/contrib/dev/config_filter/src/Annotation/ConfigFilter.php b/sites/all/modules/contrib/dev/config_filter/src/Annotation/ConfigFilter.php new file mode 100644 index 000000000..5d768382a --- /dev/null +++ b/sites/all/modules/contrib/dev/config_filter/src/Annotation/ConfigFilter.php @@ -0,0 +1,62 @@ +storage = $storage; + $this->filters = $filters; + + // Set the storage to all the filters. + foreach ($this->filters as $filter) { + $filter->setSourceStorage(new ReadOnlyStorage($storage)); + $filter->setFilteredStorage($this); + } + } + + /** + * {@inheritdoc} + */ + public function exists($name) { + $exists = $this->storage->exists($name); + foreach ($this->filters as $filter) { + $exists = $filter->filterExists($name, $exists); + } + + return $exists; + } + + /** + * {@inheritdoc} + */ + public function read($name) { + $data = $this->storage->read($name); + foreach ($this->filters as $filter) { + $data = $filter->filterRead($name, $data); + } + + return $data; + } + + /** + * {@inheritdoc} + */ + public function readMultiple(array $names) { + $data = $this->storage->readMultiple($names); + foreach ($this->filters as $filter) { + $data = $filter->filterReadMultiple($names, $data); + } + ksort($data); + return $data; + } + + /** + * {@inheritdoc} + */ + public function write($name, array $data) { + foreach ($this->filters as $filter) { + if ($data) { + $data = $filter->filterWrite($name, $data); + } + else { + // The filterWrite has an array type hint in the interface. + $data = $filter->filterWrite($name, []); + } + } + + if ($data) { + return $this->storage->write($name, $data); + } + + // The data has been unset, check if it should be deleted. + if ($this->storage->exists($name)) { + foreach ($this->filters as $filter) { + if ($filter->filterWriteEmptyIsDelete($name)) { + return $this->storage->delete($name); + } + } + } + + // The data was not written, but it is not an error. + return TRUE; + } + + /** + * {@inheritdoc} + */ + public function delete($name) { + $success = TRUE; + foreach ($this->filters as $filter) { + $success = $filter->filterDelete($name, $success); + } + + if ($success) { + $success = $this->storage->delete($name); + } + + return $success; + } + + /** + * {@inheritdoc} + */ + public function rename($name, $new_name) { + $success = TRUE; + foreach ($this->filters as $filter) { + $success = $filter->filterRename($name, $new_name, $success); + } + + if ($success) { + $success = $this->storage->rename($name, $new_name); + } + + return $success; + } + + /** + * {@inheritdoc} + */ + public function encode($data) { + return $this->storage->encode($data); + } + + /** + * {@inheritdoc} + */ + public function decode($raw) { + return $this->storage->decode($raw); + } + + /** + * {@inheritdoc} + */ + public function listAll($prefix = '') { + $data = $this->storage->listAll($prefix); + foreach ($this->filters as $filter) { + $data = $filter->filterListAll($prefix, $data); + } + sort($data); + return $data; + } + + /** + * {@inheritdoc} + */ + public function deleteAll($prefix = '') { + $delete = TRUE; + foreach ($this->filters as $filter) { + $delete = $filter->filterDeleteAll($prefix, $delete); + } + + if ($delete) { + return $this->storage->deleteAll($prefix); + } + + // The filters returned FALSE for $delete, so we delete the names + // individually and allow filters to prevent deleting the config. + foreach ($this->storage->listAll($prefix) as $name) { + $this->delete($name); + } + + // The filters wanted to prevent deleting all and were called to delete the + // individual config name, is this a success? Let us say it is. + return TRUE; + } + + /** + * {@inheritdoc} + */ + public function createCollection($collection) { + $filters = []; + foreach ($this->filters as $key => $filter) { + $filter = $filter->filterCreateCollection($collection); + if ($filter) { + $filters[$key] = $filter; + } + } + + $storage = $this->storage->createCollection($collection); + $filtered = new static($storage, $filters); + + // Set the storage to all the filters. + foreach ($filters as $filter) { + $filter->setSourceStorage(new ReadOnlyStorage($storage)); + $filter->setFilteredStorage($filtered); + } + + return $filtered; + } + + /** + * {@inheritdoc} + */ + public function getAllCollectionNames() { + $collections = $this->storage->getAllCollectionNames(); + foreach ($this->filters as $filter) { + $collections = $filter->filterGetAllCollectionNames($collections); + } + sort($collections); + return $collections; + } + + /** + * {@inheritdoc} + */ + public function getCollectionName() { + $collection = $this->storage->getCollectionName(); + foreach ($this->filters as $filter) { + $collection = $filter->filterGetCollectionName($collection); + } + + return $collection; + } + +} diff --git a/sites/all/modules/contrib/dev/config_filter/src/Config/FilteredStorageInterface.php b/sites/all/modules/contrib/dev/config_filter/src/Config/FilteredStorageInterface.php new file mode 100644 index 000000000..0da0f131d --- /dev/null +++ b/sites/all/modules/contrib/dev/config_filter/src/Config/FilteredStorageInterface.php @@ -0,0 +1,12 @@ +storage = $storage; + } + + /** + * {@inheritdoc} + */ + public function exists($name) { + return $this->storage->exists($name); + } + + /** + * {@inheritdoc} + */ + public function read($name) { + return $this->storage->read($name); + } + + /** + * {@inheritdoc} + */ + public function readMultiple(array $names) { + return $this->storage->readMultiple($names); + } + + /** + * {@inheritdoc} + */ + public function write($name, array $data) { + throw new UnsupportedMethod(__METHOD__ . ' is not allowed on a ReadOnlyStorage'); + } + + /** + * {@inheritdoc} + */ + public function delete($name) { + throw new UnsupportedMethod(__METHOD__ . ' is not allowed on a ReadOnlyStorage'); + } + + /** + * {@inheritdoc} + */ + public function rename($name, $new_name) { + throw new UnsupportedMethod(__METHOD__ . ' is not allowed on a ReadOnlyStorage'); + } + + /** + * {@inheritdoc} + */ + public function encode($data) { + return $this->storage->encode($data); + } + + /** + * {@inheritdoc} + */ + public function decode($raw) { + return $this->storage->decode($raw); + } + + /** + * {@inheritdoc} + */ + public function listAll($prefix = '') { + return $this->storage->listAll($prefix); + } + + /** + * {@inheritdoc} + */ + public function deleteAll($prefix = '') { + throw new UnsupportedMethod(__METHOD__ . ' is not allowed on a ReadOnlyStorage'); + } + + /** + * {@inheritdoc} + */ + public function createCollection($collection) { + return new static($this->storage->createCollection($collection)); + } + + /** + * {@inheritdoc} + */ + public function getAllCollectionNames() { + return $this->storage->getAllCollectionNames(); + } + + /** + * {@inheritdoc} + */ + public function getCollectionName() { + return $this->storage->getCollectionName(); + } + +} diff --git a/sites/all/modules/contrib/dev/config_filter/src/Config/StorageFilterInterface.php b/sites/all/modules/contrib/dev/config_filter/src/Config/StorageFilterInterface.php new file mode 100644 index 000000000..ad2c38eb9 --- /dev/null +++ b/sites/all/modules/contrib/dev/config_filter/src/Config/StorageFilterInterface.php @@ -0,0 +1,223 @@ +sync = $sync; + } + + /** + * Add a config filter manager. + * + * @param \Drupal\config_filter\ConfigFilterManagerInterface $manager + * The ConfigFilter plugin manager. + */ + public function addConfigFilterManager(ConfigFilterManagerInterface $manager) { + $this->managers[] = $manager; + } + + /** + * Get the sync storage Drupal uses. + * + * @return \Drupal\config_filter\Config\FilteredStorageInterface + * The decorated sync config storage. + */ + public function getSync() { + return $this->getFilteredStorage($this->sync, ['config.storage.sync']); + } + + /** + * Get the sync storage Drupal uses and exclude some plugins. + * + * @param string[] $excluded + * The ids of filters to exclude. + * + * @return \Drupal\config_filter\Config\FilteredStorageInterface + * The decorated sync config storage. + */ + public function getSyncWithoutExcluded(array $excluded) { + return $this->getFilteredStorage($this->sync, ['config.storage.sync'], $excluded); + } + + /** + * Get a decorated storage with filters applied. + * + * @param \Drupal\Core\Config\StorageInterface $storage + * The storage to decorate. + * @param string[] $storage_names + * The names of the storage, so the correct filters can be applied. + * @param string[] $excluded + * The ids of filters to exclude. + * + * @return \Drupal\config_filter\Config\FilteredStorageInterface + * The decorated storage with the filters applied. + */ + public function getFilteredStorage(StorageInterface $storage, array $storage_names, array $excluded = []) { + $filters = []; + foreach ($this->managers as $manager) { + // Filters from managers that come first will not be overwritten by + // filters from lower priority managers. + $filters = $filters + $manager->getFiltersForStorages($storage_names, $excluded); + } + return new FilteredStorage($storage, $filters); + } + +} diff --git a/sites/all/modules/contrib/dev/config_filter/src/Exception/UnsupportedMethod.php b/sites/all/modules/contrib/dev/config_filter/src/Exception/UnsupportedMethod.php new file mode 100644 index 000000000..a6f5a17f8 --- /dev/null +++ b/sites/all/modules/contrib/dev/config_filter/src/Exception/UnsupportedMethod.php @@ -0,0 +1,9 @@ +source = $storage; + } + + /** + * {@inheritdoc} + */ + public function setFilteredStorage(StorageInterface $storage) { + $this->filtered = $storage; + } + + /** + * Get the read-only source Storage. + * + * @return \Drupal\Core\Config\StorageInterface + * The source storage. + */ + protected function getSourceStorage() { + return $this->source; + } + + /** + * Get the decorator storage which applies the filters. + * + * @return \Drupal\Core\Config\StorageInterface + * The filtered decorator storage. + */ + protected function getFilteredStorage() { + return $this->filtered; + } + + /** + * {@inheritdoc} + */ + public function filterRead($name, $data) { + return $data; + } + + /** + * {@inheritdoc} + */ + public function filterWrite($name, array $data) { + return $data; + } + + /** + * {@inheritdoc} + */ + public function filterWriteEmptyIsDelete($name) { + return NULL; + } + + /** + * {@inheritdoc} + */ + public function filterExists($name, $exists) { + return $exists; + } + + /** + * {@inheritdoc} + */ + public function filterDelete($name, $delete) { + return $delete; + } + + /** + * {@inheritdoc} + */ + public function filterReadMultiple(array $names, array $data) { + return $data; + } + + /** + * {@inheritdoc} + */ + public function filterRename($name, $new_name, $rename) { + return $rename; + } + + /** + * {@inheritdoc} + */ + public function filterListAll($prefix, array $data) { + return $data; + } + + /** + * {@inheritdoc} + */ + public function filterDeleteAll($prefix, $delete) { + return $delete; + } + + /** + * {@inheritdoc} + */ + public function filterCreateCollection($collection) { + return clone $this; + } + + /** + * {@inheritdoc} + */ + public function filterGetAllCollectionNames(array $collections) { + return $collections; + } + + /** + * {@inheritdoc} + */ + public function filterGetCollectionName($collection) { + return $collection; + } + +} diff --git a/sites/all/modules/contrib/dev/config_filter/src/Plugin/ConfigFilterInterface.php b/sites/all/modules/contrib/dev/config_filter/src/Plugin/ConfigFilterInterface.php new file mode 100644 index 000000000..66748734a --- /dev/null +++ b/sites/all/modules/contrib/dev/config_filter/src/Plugin/ConfigFilterInterface.php @@ -0,0 +1,13 @@ +alterInfo('config_filter_info'); + $this->setCacheBackend($cache_backend, 'config_filter_plugins'); + } + + /** + * {@inheritdoc} + */ + public function getFiltersForStorages(array $storage_names, array $excluded = []) { + $definitions = $this->getDefinitions(); + $filters = []; + foreach ($definitions as $id => $definition) { + if ($definition['status'] && array_intersect($storage_names, $definition['storages']) && !in_array($id, $excluded)) { + $filters[$id] = $this->createInstance($id, $definition); + } + } + + return $filters; + } + + /** + * {@inheritdoc} + */ + public function getFilterInstance($id) { + $definitions = $this->getDefinitions(); + if (array_key_exists($id, $definitions)) { + return $this->createInstance($id, $definitions[$id]); + } + + return NULL; + } + + /** + * {@inheritdoc} + */ + protected function findDefinitions() { + $definitions = array_map(function ($definition) { + if (empty($definition['storages'])) { + // The sync storage is the default. + $definition['storages'] = ['config.storage.sync']; + } + return $definition; + }, parent::findDefinitions()); + + // Sort the definitions by weight. + uasort($definitions, function ($a, $b) { + return strcmp($a['weight'], $b['weight']); + }); + + return $definitions; + } + +} diff --git a/sites/all/modules/contrib/dev/config_filter/src/Tests/FilteredStorageTest.php b/sites/all/modules/contrib/dev/config_filter/src/Tests/FilteredStorageTest.php new file mode 100644 index 000000000..083414a82 --- /dev/null +++ b/sites/all/modules/contrib/dev/config_filter/src/Tests/FilteredStorageTest.php @@ -0,0 +1,298 @@ +storage = new FilteredStorage($this->storage, [new TransparentFilter()]); + } + + /** + * Test that the storage is set on the filters. + */ + public function testSettingStorages() { + $filterReflection = new \ReflectionClass(FilteredStorage::class); + $filtersProperty = $filterReflection->getProperty('filters'); + $filtersProperty->setAccessible(TRUE); + + /** @var \Drupal\config_filter\Tests\TransparentFilter[] $filters */ + $filters = $filtersProperty->getValue($this->storage); + foreach ($filters as $filter) { + // Test that the source storage is a ReadonlyStorage and wraps the cached + // storage from the inherited test. + $readonly = $filter->getPrivateSourceStorage(); + $this->assertInstanceOf(ReadOnlyStorage::class, $readonly); + $readonlyReflection = new \ReflectionClass(ReadOnlyStorage::class); + $storageProperty = $readonlyReflection->getProperty('storage'); + $storageProperty->setAccessible(TRUE); + $source = $storageProperty->getValue($readonly); + $this->assertInstanceOf(CachedStorage::class, $source); + + // Assert that the filter gets the storage. + $this->assertEquals($this->storage, $filter->getPrivateFilteredStorage()); + } + } + + /** + * Test the read methods invokes the correct filter methods. + * + * @dataProvider readFilterProvider + */ + public function testReadFilter($name, $storageMethod, $filterMethod, $data, $expected) { + $source = $this->prophesize(StorageInterface::class); + $filterA = $this->prophesizeFilter(); + $filterB = $this->prophesizeFilter(); + + $source->$storageMethod($name)->willReturn($data); + $interim = $this->randomArray(); + $filterA->$filterMethod($name, $data)->willReturn($interim); + $filterB->$filterMethod($name, $interim)->willReturn($expected); + + $storage = new FilteredStorage($source->reveal(), [$filterA->reveal(), $filterB->reveal()]); + $this->assertEquals($expected, $storage->$storageMethod($name)); + } + + /** + * Data provider for testReadFilter. + */ + public function readFilterProvider() { + // @codingStandardsIgnoreStart + return [ + [$this->randomString(), 'exists', 'filterExists', TRUE, TRUE], + [$this->randomString(), 'exists', 'filterExists', TRUE, FALSE], + [$this->randomString(), 'exists', 'filterExists', FALSE, TRUE], + [$this->randomString(), 'exists', 'filterExists', FALSE, FALSE], + + [$this->randomString(), 'read', 'filterRead', $this->randomArray(), $this->randomArray()], + [$this->randomString(), 'read', 'filterRead', NULL, $this->randomArray()], + [$this->randomString(), 'read', 'filterRead', $this->randomArray(), NULL], + + [ + [$this->randomString(), $this->randomString()], + 'readMultiple', + 'filterReadMultiple', + [$this->randomArray(), $this->randomArray()], + [$this->randomArray(), $this->randomArray()], + ], + [ + [$this->randomString(), $this->randomString()], + 'readMultiple', + 'filterReadMultiple', + [$this->randomArray(), FALSE], + [$this->randomArray(), $this->randomArray()], + ], + + [ + $this->randomString(), + 'listAll', + 'filterListAll', + ['a' . $this->randomString(), 'b' . $this->randomString()], + ['a' . $this->randomString(), 'b' . $this->randomString()], + ], + ]; + // @codingStandardsIgnoreEnd + } + + /** + * Test the write method invokes the filterWrite in filters. + * + * @dataProvider writeFilterProvider + */ + public function testWriteFilter($interim, $expected, $exists = TRUE) { + $name = $this->randomString(); + $data = $this->randomArray(); + $source = $this->prophesize(StorageInterface::class); + $filterA = $this->prophesizeFilter(); + $filterB = $this->prophesizeFilter(); + + $filterA->filterWrite($name, $data)->willReturn($interim); + $interim = is_array($interim) ? $interim : []; + $filterB->filterWrite($name, $interim)->willReturn($expected); + + if ($expected) { + $source->write($name, $expected)->willReturn(TRUE); + } + else { + $source->write(Argument::any())->shouldNotBeCalled(); + $source->exists($name)->willReturn($exists); + if ($exists) { + $filterA->filterWriteEmptyIsDelete($name)->willReturn(TRUE); + $source->delete($name)->willReturn(TRUE); + } + } + + $storage = new FilteredStorage($source->reveal(), [$filterA->reveal(), $filterB->reveal()]); + $this->assertTrue($storage->write($name, $data)); + } + + /** + * Data provider for testWriteFilter. + */ + public function writeFilterProvider() { + return [ + [$this->randomArray(), $this->randomArray()], + [NULL, $this->randomArray()], + [[], $this->randomArray()], + [$this->randomArray(), NULL, FALSE], + [$this->randomArray(), [], FALSE], + [$this->randomArray(), NULL, TRUE], + ]; + } + + /** + * Test the delete method invokes the filterDelete in filters. + * + * @dataProvider deleteFilterProvider + */ + public function testDeleteFilter($interim, $expected) { + $name = $this->randomString(); + $source = $this->prophesize(StorageInterface::class); + $filterA = $this->prophesizeFilter(); + $filterB = $this->prophesizeFilter(); + + $filterA->filterDelete($name, TRUE)->willReturn($interim); + $filterB->filterDelete($name, $interim)->willReturn($expected); + + if ($expected) { + $source->delete($name)->willReturn(TRUE); + } + else { + $source->delete(Argument::any())->shouldNotBeCalled(); + } + + $storage = new FilteredStorage($source->reveal(), [$filterA->reveal(), $filterB->reveal()]); + $this->assertEquals($expected, $storage->delete($name)); + } + + /** + * Data provider for testDeleteFilter. + */ + public function deleteFilterProvider() { + return [ + [TRUE, TRUE], + [FALSE, TRUE], + [TRUE, FALSE], + [FALSE, FALSE], + ]; + } + + /** + * Test the rename method invokes the filterRename in filters. + * + * @dataProvider renameFilterProvider + */ + public function testRenameFilter($interim, $expected) { + $name = $this->randomString(); + $name2 = $this->randomString(); + $source = $this->prophesize(StorageInterface::class); + $filterA = $this->prophesizeFilter(); + $filterB = $this->prophesizeFilter(); + + $filterA->filterRename($name, $name2, TRUE)->willReturn($interim); + $filterB->filterRename($name, $name2, $interim)->willReturn($expected); + + if ($expected) { + $source->rename($name, $name2)->willReturn(TRUE); + } + else { + $source->rename(Argument::any())->shouldNotBeCalled(); + } + + $storage = new FilteredStorage($source->reveal(), [$filterA->reveal(), $filterB->reveal()]); + $this->assertEquals($expected, $storage->rename($name, $name2)); + } + + /** + * Data provider for testRenameFilter. + */ + public function renameFilterProvider() { + return [ + [TRUE, TRUE], + [FALSE, TRUE], + [TRUE, FALSE], + [FALSE, FALSE], + ]; + } + + /** + * Test the deleteAll method invokes the filterDeleteAll in filters. + * + * @dataProvider deleteAllFilterProvider + */ + public function testDeleteAllFilter($interim, $expected) { + $name = $this->randomString(); + $source = $this->prophesize(StorageInterface::class); + $filterA = $this->prophesizeFilter(); + $filterB = $this->prophesizeFilter(); + + $filterA->filterDeleteAll($name, TRUE)->willReturn($interim); + $filterB->filterDeleteAll($name, $interim)->willReturn($expected); + + if ($expected) { + $source->deleteAll($name)->willReturn(TRUE); + } + else { + $source->deleteAll(Argument::any())->shouldNotBeCalled(); + $all = [$this->randomString(), $this->randomString()]; + $source->listAll($name)->willReturn($all); + + foreach ($all as $item) { + $filterA->filterDelete($item, TRUE)->willReturn(TRUE); + $filterB->filterDelete($item, TRUE)->willReturn(FALSE); + } + } + + $storage = new FilteredStorage($source->reveal(), [$filterA->reveal(), $filterB->reveal()]); + $this->assertTrue($storage->deleteAll($name)); + } + + /** + * Data provider for testDeleteAllFilter. + */ + public function deleteAllFilterProvider() { + return [ + [TRUE, TRUE], + [FALSE, TRUE], + [TRUE, FALSE], + [FALSE, FALSE], + ]; + } + + /** + * Prophesize a StorageFilter. + */ + protected function prophesizeFilter() { + $filter = $this->prophesize(StorageFilterInterface::class); + $filter->setSourceStorage(Argument::type(ReadOnlyStorage::class))->shouldBeCalledTimes(1); + $filter->setFilteredStorage(Argument::type(FilteredStorage::class))->shouldBeCalledTimes(1); + return $filter; + } + + /** + * Create a random array. + */ + protected function randomArray($size = 4) { + return (array) $this->randomObject($size); + } + +} diff --git a/sites/all/modules/contrib/dev/config_filter/src/Tests/ReadonlyStorageTest.php b/sites/all/modules/contrib/dev/config_filter/src/Tests/ReadonlyStorageTest.php new file mode 100644 index 000000000..ee1917133 --- /dev/null +++ b/sites/all/modules/contrib/dev/config_filter/src/Tests/ReadonlyStorageTest.php @@ -0,0 +1,138 @@ +prophesize(StorageInterface::class); + $methodProhecy = new MethodProphecy($source, $method, $arguments); + $methodProhecy->shouldBeCalledTimes(1); + $methodProhecy->willReturn($returnValue); + $source->addMethodProphecy($methodProhecy); + + $storage = $this->getStorage($source->reveal()); + $actual = call_user_func_array([$storage, $method], $arguments); + $this->assertEquals($actual, $returnValue); + } + + /** + * Provide the methods that should continue to work. + * + * @return array + * The data. + */ + public function readMethodsProvider() { + return [ + ['exists', [$this->randomMachineName()], $this->randomMachineName()], + ['read', [$this->randomMachineName()], $this->randomArray()], + ['readMultiple', [$this->randomArray()], $this->randomArray()], + ['encode', [$this->randomArray()], $this->randomMachineName()], + ['decode', [$this->randomMachineName()], $this->randomArray()], + ['listAll', [$this->randomMachineName()], $this->randomArray()], + ['getAllCollectionNames', [], $this->randomArray()], + ['getCollectionName', [], $this->randomMachineName()], + ]; + } + + /** + * Test creating a collection. + * + * Creating collections returns a new instance, make sure it decorates the + * new instance of the source. + */ + public function testCreateCollection() { + $name = $this->randomMachineName(); + $source = $this->prophesize(StorageInterface::class); + $collectionSource = $this->prophesize(StorageInterface::class)->reveal(); + $source->createCollection($name)->willReturn($collectionSource); + + $storage = $this->getStorage($source->reveal()); + $collectionStorage = $storage->createCollection($name); + + $this->assertInstanceOf(ReadOnlyStorage::class, $collectionStorage); + + $readonlyReflection = new \ReflectionClass(ReadOnlyStorage::class); + $storageProperty = $readonlyReflection->getProperty('storage'); + $storageProperty->setAccessible(TRUE); + $actualSource = $storageProperty->getValue($collectionStorage); + $this->assertEquals($collectionSource, $actualSource); + } + + /** + * Test the operations that should throw an error. + * + * @dataProvider writeMethodsProvider + */ + public function testWriteOperations($method, $arguments) { + $source = $this->prophesize(StorageInterface::class); + $source->$method(Argument::any())->shouldNotBeCalled(); + + $storage = $this->getStorage($source->reveal()); + try { + call_user_func_array([$storage, $method], $arguments); + $this->fail(); + } + catch (UnsupportedMethod $exception) { + $this->assertEquals(ReadOnlyStorage::class . '::' . $method . ' is not allowed on a ReadOnlyStorage', $exception->getMessage()); + } + } + + /** + * Provide the methods that should throw an exception. + * + * @return array + * The data + */ + public function writeMethodsProvider() { + return [ + ['write', [$this->randomMachineName(), $this->randomArray()]], + ['delete', [$this->randomMachineName()]], + ['rename', [$this->randomMachineName(), $this->randomMachineName()]], + ['deleteAll', [$this->randomMachineName()]], + ]; + } + + /** + * Get a random array. + * + * @return array + * A random array used for data testing. + */ + protected function randomArray() { + return (array) $this->getRandomGenerator()->object(); + } + +} diff --git a/sites/all/modules/contrib/dev/config_filter/src/Tests/TransparentFilter.php b/sites/all/modules/contrib/dev/config_filter/src/Tests/TransparentFilter.php new file mode 100644 index 000000000..d96d6bb5c --- /dev/null +++ b/sites/all/modules/contrib/dev/config_filter/src/Tests/TransparentFilter.php @@ -0,0 +1,40 @@ +getSourceStorage(); + } + + /** + * Get the decorator storage which applies the filters. + * + * @return \Drupal\Core\Config\StorageInterface + * The filtered decorator storage. + */ + public function getPrivateFilteredStorage() { + return $this->getFilteredStorage(); + } + +} diff --git a/sites/all/modules/contrib/dev/config_filter/tests/composer.json b/sites/all/modules/contrib/dev/config_filter/tests/composer.json new file mode 100644 index 000000000..fe60edb17 --- /dev/null +++ b/sites/all/modules/contrib/dev/config_filter/tests/composer.json @@ -0,0 +1,24 @@ +{ + "name": "nuvoleweb/config-filter-test-site", + "description": "Config Filter test site.", + "type": "project", + "require": { + "composer/installers": "^1.2", + "drupal-composer/drupal-scaffold": "^2.2", + "drupal/core": "~8", + "drush/drush": "~8.0", + "drupal/coder": "^8.2", + "squizlabs/php_codesniffer": "^2.8", + "phpunit/phpunit": "5.5.*", + "bovigo/assert": "~1.7", + "mikey179/vfsStream": "*" + }, + "minimum-stability": "dev", + "prefer-stable": true, + "repositories": [ + {"type": "composer", "url": "https://packages.drupal.org/8"} + ], + "conflict": { + "drupal/drupal": "*" + } +} diff --git a/sites/all/modules/contrib/dev/config_filter/tests/modules/config_filter_split_test/README.md b/sites/all/modules/contrib/dev/config_filter/tests/modules/config_filter_split_test/README.md new file mode 100644 index 000000000..37b67f463 --- /dev/null +++ b/sites/all/modules/contrib/dev/config_filter/tests/modules/config_filter_split_test/README.md @@ -0,0 +1,40 @@ +# Config Filter Split test +This is a module for testing the proper functioning of config_filter. +But it also demonstrates how a filter can be used to read and write to a +different config storage. As such it is an instructive example. +But it also has a practical purpose: We can use it to read migrate config +directly from files. Of course it is in general a bad idea to directly +edit the active configuration since Drupal does many checks and database +alterations when synchronizing configuration. + +This is just here for the brave. You have been warned. + +## Developing with migrate configuration read from the files. + +Migrations are configurations, by default active configuration is stored in the +database. So when developing, the configuration has to be synced all the time. +To avoid this we can split out the migrate configuration to read directly +from the files. + +Enable the config_filter_split_test testing module from config_filter. + +To swap out the active storage, add the following to your services.local.yml: +```yaml +services: + config.storage: + class: Drupal\config_filter_split_test\Config\ActiveMigrateStorage + arguments: + - '@config.storage.active' + - '@cache.config' + - '../config/migrate_active' # The path to the folder. +``` + +Migrations are plugins, and plugin definitions are cached. The configuration +storage is also cached. +So either you have to clear the caches after you edit the migration or you add +the following to your settings.php (assuming you have the null cache set too): +```php +$settings['cache']['bins']['config'] = 'cache.backend.null'; +$settings['cache']['bins']['discovery'] = 'cache.backend.null'; +``` +This has an obvious performance implication. diff --git a/sites/all/modules/contrib/dev/config_filter/tests/modules/config_filter_split_test/config_filter_split_test.info.yml b/sites/all/modules/contrib/dev/config_filter/tests/modules/config_filter_split_test/config_filter_split_test.info.yml new file mode 100644 index 000000000..2924e12be --- /dev/null +++ b/sites/all/modules/contrib/dev/config_filter/tests/modules/config_filter_split_test/config_filter_split_test.info.yml @@ -0,0 +1,12 @@ +name: 'Simple split filter' +type: module +# core: 8.x +package: Testing +dependencies: + - drupal:config_filter + +# Information added by Drupal.org packaging script on 2017-11-27 +version: '8.x-1.1' +core: '8.x' +project: 'config_filter' +datestamp: 1511779987 diff --git a/sites/all/modules/contrib/dev/config_filter/tests/modules/config_filter_split_test/src/Config/ActiveMigrateStorage.php b/sites/all/modules/contrib/dev/config_filter/tests/modules/config_filter_split_test/src/Config/ActiveMigrateStorage.php new file mode 100644 index 000000000..068023497 --- /dev/null +++ b/sites/all/modules/contrib/dev/config_filter/tests/modules/config_filter_split_test/src/Config/ActiveMigrateStorage.php @@ -0,0 +1,34 @@ +storage = $storage; + $this->name = $name; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { + return new static(new DatabaseStorage($container->get('database'), 'config_filter_split_test'), 'core.'); + } + + /** + * Decide to split the config off or not. + * + * @param string $name + * The name of the configuration to check. + * + * @return bool + * Whether the configuration is supposed to be split. + */ + protected function isSplitConfig($name) { + return (strpos($name, $this->name) === 0); + } + + /** + * {@inheritdoc} + */ + public function filterRead($name, $data) { + if ($this->isSplitConfig($name)) { + if ($this->storage->exists($name)) { + $data = $this->storage->read($name); + } + } + + return $data; + } + + /** + * {@inheritdoc} + */ + public function filterExists($name, $exists) { + if ($this->isSplitConfig($name) && !$exists) { + $exists = $this->storage->exists($name); + } + + return $exists; + } + + /** + * {@inheritdoc} + */ + public function filterReadMultiple(array $names, array $data) { + return array_merge($data, $this->storage->readMultiple($names)); + } + + /** + * {@inheritdoc} + */ + public function filterListAll($prefix, array $data) { + return array_unique(array_merge($data, $this->storage->listAll($prefix))); + } + + /** + * {@inheritdoc} + */ + public function filterWrite($name, array $data) { + if ($this->isSplitConfig($name)) { + $this->storage->write($name, $data); + return NULL; + } + + return $data; + } + + /** + * {@inheritdoc} + */ + public function filterWriteEmptyIsDelete($name) { + return ($this->isSplitConfig($name) ? TRUE : NULL); + } + + /** + * {@inheritdoc} + */ + public function filterDelete($name, $delete) { + if ($delete && $this->storage->exists($name)) { + // Call delete on the secondary storage anyway. + $this->storage->delete($name); + } + + return $delete; + } + + /** + * {@inheritdoc} + */ + public function filterDeleteAll($prefix, $delete) { + if ($delete && $this->storage) { + try { + $this->storage->deleteAll($prefix); + } + catch (\UnexpectedValueException $exception) { + // The file storage tries to remove directories of collections. But this + // fails if the directory doesn't exist. So everything is actually fine. + } + } + + return $delete; + } + + /** + * {@inheritdoc} + */ + public function filterCreateCollection($collection) { + return new static($this->storage->createCollection($collection), $this->name); + } + +} diff --git a/sites/all/modules/contrib/dev/config_filter/tests/modules/config_filter_test/config_filter_test.info.yml b/sites/all/modules/contrib/dev/config_filter/tests/modules/config_filter_test/config_filter_test.info.yml new file mode 100644 index 000000000..0cdd63a2a --- /dev/null +++ b/sites/all/modules/contrib/dev/config_filter/tests/modules/config_filter_test/config_filter_test.info.yml @@ -0,0 +1,12 @@ +name: Config Filter Test +type: module +# core: 8.x +package: Testing +dependencies: + - drupal:config_filter + +# Information added by Drupal.org packaging script on 2017-11-27 +version: '8.x-1.1' +core: '8.x' +project: 'config_filter' +datestamp: 1511779987 diff --git a/sites/all/modules/contrib/dev/config_filter/tests/modules/config_filter_test/src/Plugin/ConfigFilter/PirateFilter.php b/sites/all/modules/contrib/dev/config_filter/tests/modules/config_filter_test/src/Plugin/ConfigFilter/PirateFilter.php new file mode 100644 index 000000000..96b022c9e --- /dev/null +++ b/sites/all/modules/contrib/dev/config_filter/tests/modules/config_filter_test/src/Plugin/ConfigFilter/PirateFilter.php @@ -0,0 +1,40 @@ +filterRead('system.site', $data['system.site']); + } + + return $data; + } + +} diff --git a/sites/all/modules/contrib/dev/config_filter/tests/phpunit.xml.dist b/sites/all/modules/contrib/dev/config_filter/tests/phpunit.xml.dist new file mode 100644 index 000000000..abb466ba1 --- /dev/null +++ b/sites/all/modules/contrib/dev/config_filter/tests/phpunit.xml.dist @@ -0,0 +1,13 @@ + + + + + + + + + + ./modules/config_filter/ + + + diff --git a/sites/all/modules/contrib/dev/config_filter/tests/src/Kernel/ConfigFilterStorageFactoryTest.php b/sites/all/modules/contrib/dev/config_filter/tests/src/Kernel/ConfigFilterStorageFactoryTest.php new file mode 100644 index 000000000..5b801dab2 --- /dev/null +++ b/sites/all/modules/contrib/dev/config_filter/tests/src/Kernel/ConfigFilterStorageFactoryTest.php @@ -0,0 +1,88 @@ +installConfig(['system']); + } + + /** + * Test that the config.storage.sync is decorated with the filtering version. + */ + public function testServiceProvider() { + // Export the configuration. + $this->copyConfig($this->container->get('config.storage'), $this->container->get('config.storage.sync')); + + // The pirate filter changes the system.site when importing. + $this->assertEquals(['system.site'], $this->configImporter()->getStorageComparer()->getChangelist('update')); + $this->assertEmpty($this->configImporter()->getStorageComparer()->getChangelist('create')); + $this->assertEmpty($this->configImporter()->getStorageComparer()->getChangelist('delete')); + $this->assertEmpty($this->configImporter()->getStorageComparer()->getChangelist('rename')); + + $config = $this->config('system.site')->getRawData(); + $config['name'] .= ' Arrr'; + + $this->assertEquals($config, $this->container->get('config.storage.sync')->read('system.site')); + } + + /** + * Test the storage factory decorating properly. + */ + public function testStorageFactory() { + /** @var \Drupal\Core\Database\Connection $database */ + $database = $this->container->get('database'); + $destination = new DatabaseStorage($database, 'config_filter_source_test'); + + // The $filtered storage will have the simple split applied to the + // destination storage, but is the unified storage. + $filtered = $this->container->get('config_filter.storage_factory')->getFilteredStorage($destination, ['test_storage']); + + /** @var \Drupal\Core\Config\StorageInterface $active */ + $active = $this->container->get('config.storage'); + + // Export the configuration to the filtered storage. + $this->copyConfig($active, $filtered); + + // Get the storage of the test split plugin. + $splitStorage = new DatabaseStorage($database, 'config_filter_split_test'); + + // Assert that the storage is properly split. + $this->assertTrue(count($destination->listAll()) > 0); + $this->assertTrue(count($splitStorage->listAll()) > 0); + $this->assertEquals(count($active->listAll()), count($destination->listAll()) + count($splitStorage->listAll())); + $this->assertEquals($active->listAll('core'), $splitStorage->listAll()); + $this->assertEquals($active->listAll('system'), $destination->listAll('system')); + + $this->assertEquals($active->readMultiple($active->listAll('core')), $splitStorage->readMultiple($splitStorage->listAll())); + $this->assertEquals($active->readMultiple($active->listAll('system')), $destination->readMultiple($destination->listAll('system'))); + + // Reading from the $filtered storage returns the merged config. + $this->assertEquals($active->listAll(), $filtered->listAll()); + $this->assertEquals($active->readMultiple($active->listAll()), $filtered->readMultiple($filtered->listAll())); + } + +} diff --git a/sites/all/modules/contrib/dev/config_ignore/LICENSE.txt b/sites/all/modules/contrib/dev/config_ignore/LICENSE.txt new file mode 100644 index 000000000..d159169d1 --- /dev/null +++ b/sites/all/modules/contrib/dev/config_ignore/LICENSE.txt @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/sites/all/modules/contrib/dev/config_ignore/README.txt b/sites/all/modules/contrib/dev/config_ignore/README.txt new file mode 100644 index 000000000..0a51fe965 --- /dev/null +++ b/sites/all/modules/contrib/dev/config_ignore/README.txt @@ -0,0 +1,41 @@ +Config Ignore +============= + +INTRODUCTION +------------ +Ever experienced that your sites configuration was overridden by the configuration on the filesystem, when doing a +`drush cim`? + +Not anymore! + +This modules is a tool to let you keep the configuration you want, in place. + +Lets say that you do would like the `system.site` configuration (which contains that sites name, slogan, email, etc) to +remain untouched, on your live site, no matter what the configuration, in the export folder says. + +Or maybe you are getting tired of having the `devel.settings` changed every time you import configuration? + +Then this module is what you are looking for. + +REQUIREMENTS +------------ +You will need the `config_filter` module to be enabled. + +INSTALLATION +------------ +Consult https://www.drupal.org/docs/8/extending-drupal-8/installing-contributed-modules-find-import-enable-configure-drupal-8 +to see how to install and manage modules in Drupal 8. + +CONFIGURATION +------------- +Go to `admin/config/development/configuration/ignore` to set what configuration you want to ignore upon import. + +Do not ignore the `core.extension` configuration as it will prevent you from enabling new modules with a config import. +Use the `config_split` module for environment specific modules. + +MAINTAINERS +----------- +Current maintainers: + + * Tommy Lynge Jørgensen (TLyngeJ) - https://www.drupal.org/u/tlyngej + * Fabian Bircher (bircher) - https://www.drupal.org/u/bircher diff --git a/sites/all/modules/contrib/dev/config_ignore/composer.json b/sites/all/modules/contrib/dev/config_ignore/composer.json new file mode 100644 index 000000000..9e8ee9b99 --- /dev/null +++ b/sites/all/modules/contrib/dev/config_ignore/composer.json @@ -0,0 +1,29 @@ +{ + "name": "drupal/config_ignore", + "description": "Ignore certain configuration during import.", + "type": "drupal-module", + "homepage": "http://drupal.org/project/config_ignore", + "authors": [ + { + "name": "Tommy Lynge Jørgensen", + "email": "tlyngej@gmail.com", + "homepage": "https://www.drupal.org/u/tlyngej", + "role": "Maintainer" + }, + { + "name": "Fabian Bircher", + "homepage": "https://www.drupal.org/u/bircher", + "role": "Maintainer" + } + ], + "support": { + "issues": "http://drupal.org/project/config_ignore", + "irc": "irc://irc.freenode.org/drupal-contribute", + "source": "http://cgit.drupalcode.org/config_ignore" + }, + "license": "GPL-2.0+", + "minimum-stability": "dev", + "require": { + "drupal/config_filter": "1.*" + } +} diff --git a/sites/all/modules/contrib/dev/config_ignore/config/install/config_ignore.settings.yml b/sites/all/modules/contrib/dev/config_ignore/config/install/config_ignore.settings.yml new file mode 100644 index 000000000..629b34249 --- /dev/null +++ b/sites/all/modules/contrib/dev/config_ignore/config/install/config_ignore.settings.yml @@ -0,0 +1 @@ +ignored_config_entities: { } diff --git a/sites/all/modules/contrib/dev/config_ignore/config/schema/config_ignore.schema.yml b/sites/all/modules/contrib/dev/config_ignore/config/schema/config_ignore.schema.yml new file mode 100644 index 000000000..9930f0d9d --- /dev/null +++ b/sites/all/modules/contrib/dev/config_ignore/config/schema/config_ignore.schema.yml @@ -0,0 +1,9 @@ +config_ignore.settings: + type: config_object + label: 'Config Ignore Settings' + mapping: + ignored_config_entities: + type: sequence + label: 'List of ignored configurations' + sequence: + type: string diff --git a/sites/all/modules/contrib/dev/config_ignore/config_ignore.api.php b/sites/all/modules/contrib/dev/config_ignore/config_ignore.api.php new file mode 100644 index 000000000..89e9f9189 --- /dev/null +++ b/sites/all/modules/contrib/dev/config_ignore/config_ignore.api.php @@ -0,0 +1,23 @@ +get('module_installer')->install(['config_filter']); +} diff --git a/sites/all/modules/contrib/dev/config_ignore/config_ignore.links.task.yml b/sites/all/modules/contrib/dev/config_ignore/config_ignore.links.task.yml new file mode 100644 index 000000000..b65a8dd60 --- /dev/null +++ b/sites/all/modules/contrib/dev/config_ignore/config_ignore.links.task.yml @@ -0,0 +1,5 @@ +config_ignore.settings: + route_name: 'config_ignore.settings' + title: 'Ignore' + base_route: config.sync + weight: 99 diff --git a/sites/all/modules/contrib/dev/config_ignore/config_ignore.module b/sites/all/modules/contrib/dev/config_ignore/config_ignore.module new file mode 100644 index 000000000..3ed573ad7 --- /dev/null +++ b/sites/all/modules/contrib/dev/config_ignore/config_ignore.module @@ -0,0 +1,70 @@ +getSyncWithoutExcluded(['config_ignore']); + $active_storage_sync = \Drupal::service('config.storage.sync'); + $storage = \Drupal::service('config.storage'); + $config_manager = \Drupal::service('config.manager'); + + // Create two StorageComparer objects, one with the filter enabled and one + // as without. We will compare them later to see what changes that has been + // ignored. + $unfiltered_storage_compare = new StorageComparer($stock_storage_sync, $storage, $config_manager); + $filtered_storage_compare = new StorageComparer($active_storage_sync, $storage, $config_manager); + $unfiltered_storage_compare->createChangelist(); + $filtered_storage_compare->createChangelist(); + + // Create an array of the changes with the filter on. + $config_changes = []; + foreach ($filtered_storage_compare->getChangelist() as $config_names) { + foreach ($config_names as $config_name) { + $config_changes[] = $config_name; + } + } + + foreach ($unfiltered_storage_compare->getAllCollectionNames() as $collection) { + foreach ($unfiltered_storage_compare->getChangelist(NULL, $collection) as $config_change_type => $config_names) { + foreach ($config_names as $config_name) { + // If the config name exists here, but not in the $config_changes array + // the it's because it's getting ignored. + if (!in_array($config_name, $config_changes)) { + $ignored_config_entities[] = [ + $config_name, + $config_change_type, + ]; + } + } + } + } + + // Build a table of changes that are not going to happen, due to the ignored + // config entities. + if (!empty($ignored_config_entities)) { + $form['ignored'] = [ + '#type' => 'table', + '#header' => ['Config name', 'Action'], + '#caption' => t('

The following configuration entities are ignored due to the Config Ignore Settings and therefore not displayed in the list above

', [ + '@url' => Url::fromRoute('config_ignore.settings') + ->toString() + ]), + '#rows' => $ignored_config_entities, + ]; + } + +} diff --git a/sites/all/modules/contrib/dev/config_ignore/config_ignore.routing.yml b/sites/all/modules/contrib/dev/config_ignore/config_ignore.routing.yml new file mode 100644 index 000000000..5a16abfa8 --- /dev/null +++ b/sites/all/modules/contrib/dev/config_ignore/config_ignore.routing.yml @@ -0,0 +1,7 @@ +config_ignore.settings: + path: '/admin/config/development/configuration/ignore' + defaults: + _form: '\Drupal\config_ignore\Form\Settings' + _title: 'Ignore' + requirements: + _permission: 'import configuration' diff --git a/sites/all/modules/contrib/dev/config_ignore/src/Form/Settings.php b/sites/all/modules/contrib/dev/config_ignore/src/Form/Settings.php new file mode 100644 index 000000000..8029db085 --- /dev/null +++ b/sites/all/modules/contrib/dev/config_ignore/src/Form/Settings.php @@ -0,0 +1,76 @@ +t('One configuration name per line.
+Examples:
    +
  • user.settings
  • +
  • views.settings
  • +
  • contact.settings
  • +
  • webform.webform.* (will ignore all config entities that starts with webform.webform)
  • +
  • *.contact_message.custom_contact_form.* (will ignore all config entities that starts with .contact_message.custom_contact_form. like fields attached to a custom contact form)
  • +
  • * (will ignore everything)
  • +
  • ~webform.webform.contact (will force import for this configuration, even if ignored by a wildcard)
  • +
  • user.mail:register_no_approval_required.body (will ignore the body of the no approval required email setting, but will not ignore other user.mail configuration.)
  • +
'); + + $config_ignore_settings = $this->config('config_ignore.settings'); + $form['ignored_config_entities'] = [ + '#type' => 'textarea', + '#rows' => 25, + '#title' => $this->t('Configuration entity names to ignore'), + '#description' => $description, + '#default_value' => implode(PHP_EOL, $config_ignore_settings->get('ignored_config_entities')), + '#size' => 60, + ]; + return parent::buildForm($form, $form_state); + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, FormStateInterface $form_state) { + $values = $form_state->getValues(); + $config_ignore_settings = $this->config('config_ignore.settings'); + $config_ignore_settings_array = preg_split("[\n|\r]", $values['ignored_config_entities']); + $config_ignore_settings_array = array_filter($config_ignore_settings_array); + $config_ignore_settings->set('ignored_config_entities', $config_ignore_settings_array); + $config_ignore_settings->save(); + parent::submitForm($form, $form_state); + + // Clear the config_filter plugin cache. + \Drupal::service('plugin.manager.config_filter')->clearCachedDefinitions(); + } + +} diff --git a/sites/all/modules/contrib/dev/config_ignore/src/Plugin/ConfigFilter/IgnoreFilter.php b/sites/all/modules/contrib/dev/config_ignore/src/Plugin/ConfigFilter/IgnoreFilter.php new file mode 100644 index 000000000..07fc90801 --- /dev/null +++ b/sites/all/modules/contrib/dev/config_ignore/src/Plugin/ConfigFilter/IgnoreFilter.php @@ -0,0 +1,236 @@ +active = $active; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { + // Get the list of ignored config. + $ignored = $container->get('config.factory')->get('config_ignore.settings')->get('ignored_config_entities'); + // Allow hooks to alter the list. + $container->get('module_handler')->invokeAll('config_ignore_settings_alter', [&$ignored]); + // Set the list in the plugin configuration. + $configuration['ignored'] = $ignored; + + return new static( + $configuration, + $plugin_id, + $plugin_definition, + $container->get('config.storage') + ); + } + + /** + * Match a config entity name against the list of ignored config entities. + * + * @param string $config_name + * The name of the config entity to match against all ignored entities. + * + * @return bool + * True, if the config entity is to be ignored, false otherwise. + */ + protected function matchConfigName($config_name) { + if (Settings::get('config_ignore_deactivate')) { + // Allow deactivating config_ignore in settings.php. Do not match any name + // in that case and allow a normal configuration import to happen. + return FALSE; + } + + // If the string is an excluded config, don't ignore it. + if (in_array(static::FORCE_EXCLUSION_PREFIX . $config_name, $this->configuration['ignored'], TRUE)) { + return FALSE; + } + + foreach ($this->configuration['ignored'] as $config_ignore_setting) { + // Split the ignore settings so that we can ignore individual keys. + $ignore = explode(':', $config_ignore_setting); + if (fnmatch($ignore[0], $config_name)) { + return TRUE; + } + } + + return FALSE; + } + + /** + * Read from the active configuration. + * + * This method will read the configuration from the active config store. + * But rather than just straight up returning the value it will check if + * a nested config key is set to be ignored and set only that value on the + * data to be filtered. + * + * @param string $name + * The name of the configuration to read. + * @param mixed $data + * The data to be filtered. + * + * @return mixed + * The data filtered or read from the active storage. + */ + protected function activeRead($name, $data) { + $keys = []; + foreach ($this->configuration['ignored'] as $ignored) { + // Split the ignore settings so that we can ignore individual keys. + $ignored = explode(':', $ignored); + if (fnmatch($ignored[0], $name)) { + if (count($ignored) == 1) { + // If one of the definitions does not have keys ignore the + // whole config. + return $this->active->read($name); + } + else { + // Add the sub parts to ignore to the keys. + $keys[] = $ignored[1]; + } + } + + } + + $active = $this->active->read($name); + foreach ($keys as $key) { + $parts = explode('.', $key); + + if (count($parts) == 1) { + if (isset($active[$key])) { + $data[$key] = $active[$key]; + } + } + else { + $value = NestedArray::getValue($active, $parts, $key_exists); + if ($key_exists) { + // Enforce the value if it existed in the active config. + NestedArray::setValue($data, $parts, $value, TRUE); + } + } + } + + return $data; + } + + /** + * Read multiple from the active storage. + * + * @param array $names + * The names of the configuration to read. + * @param array $data + * The data to filter. + * + * @return array + * The new data. + */ + protected function activeReadMultiple(array $names, array $data) { + $filtered_data = []; + foreach ($names as $name) { + $filtered_data[$name] = $this->activeRead($name, $data[$name]); + } + + return $filtered_data; + } + + /** + * {@inheritdoc} + */ + public function filterRead($name, $data) { + // Read from the active storage when the name is in the ignored list. + if ($this->matchConfigName($name)) { + return $this->activeRead($name, $data); + } + + return $data; + } + + /** + * {@inheritdoc} + */ + public function filterExists($name, $exists) { + // A name exists if it is ignored and exists in the active storage. + return $exists || ($this->matchConfigName($name) && $this->active->exists($name)); + } + + /** + * {@inheritdoc} + */ + public function filterReadMultiple(array $names, array $data) { + // Limit the names which are read from the active storage. + $names = array_filter($names, [$this, 'matchConfigName']); + $active_data = $this->activeReadMultiple($names, $data); + + // Return the data with merged in active data. + return array_merge($data, $active_data); + } + + /** + * {@inheritdoc} + */ + public function filterListAll($prefix, array $data) { + $active_names = $this->active->listAll($prefix); + // Filter out only ignored config names. + $active_names = array_filter($active_names, [$this, 'matchConfigName']); + + // Return the data with the active names which are ignored merged in. + return array_unique(array_merge($data, $active_names)); + } + + /** + * {@inheritdoc} + */ + public function filterCreateCollection($collection) { + return new static($this->configuration, $this->pluginId, $this->pluginDefinition, $this->active->createCollection($collection)); + } + + /** + * {@inheritdoc} + */ + public function filterGetAllCollectionNames(array $collections) { + // Add active collection names as there could be ignored config in them. + return array_merge($collections, $this->active->getAllCollectionNames()); + } + +} diff --git a/sites/all/modules/contrib/dev/config_ignore/tests/config_ignore_hook_test/config_ignore_hook_test.info.yml b/sites/all/modules/contrib/dev/config_ignore/tests/config_ignore_hook_test/config_ignore_hook_test.info.yml new file mode 100644 index 000000000..02e72b064 --- /dev/null +++ b/sites/all/modules/contrib/dev/config_ignore/tests/config_ignore_hook_test/config_ignore_hook_test.info.yml @@ -0,0 +1,13 @@ +name: Config Ignore Hook Test +type: module +description: Module that implements all the hook from Config Ignore for testing purposes +# core: 8.x +package: Configuration +dependencies: + - config_ignore + +# Information added by Drupal.org packaging script on 2017-10-11 +version: '8.x-2.1' +core: '8.x' +project: 'config_ignore' +datestamp: 1507706047 diff --git a/sites/all/modules/contrib/dev/config_ignore/tests/config_ignore_hook_test/config_ignore_hook_test.module b/sites/all/modules/contrib/dev/config_ignore/tests/config_ignore_hook_test/config_ignore_hook_test.module new file mode 100644 index 000000000..97ec446ca --- /dev/null +++ b/sites/all/modules/contrib/dev/config_ignore/tests/config_ignore_hook_test/config_ignore_hook_test.module @@ -0,0 +1,13 @@ +container->get('config.storage.sync'), + $this->container->get('config.storage'), + $this->container->get('config.manager') + ); + + $config_importer = new ConfigImporter( + $storage_comparer->createChangelist(), + $this->container->get('event_dispatcher'), + $this->container->get('config.manager'), + $this->container->get('lock'), + $this->container->get('config.typed'), + $this->container->get('module_handler'), + $this->container->get('module_installer'), + $this->container->get('theme_handler'), + $this->container->get('string_translation') + ); + + $config_importer->reset()->import(); + } + + /** + * Perform a config export to sync. folder. + */ + public function doExport() { + // Setup a config sync. dir with a, more or less, know set of config + // entities. This is a full blown export of yaml files, written to the disk. + $destination = CONFIG_SYNC_DIRECTORY; + $destination_dir = config_get_config_directory($destination); + /** @var \Drupal\Core\Config\CachedStorage $source_storage */ + $source_storage = \Drupal::service('config.storage'); + $destination_storage = new FileStorage($destination_dir); + foreach ($source_storage->listAll() as $name) { + $destination_storage->write($name, $source_storage->read($name)); + } + } + +} diff --git a/sites/all/modules/contrib/dev/config_ignore/tests/src/Functional/ConfigIgnoreHookTest.php b/sites/all/modules/contrib/dev/config_ignore/tests/src/Functional/ConfigIgnoreHookTest.php new file mode 100644 index 000000000..a17ac2886 --- /dev/null +++ b/sites/all/modules/contrib/dev/config_ignore/tests/src/Functional/ConfigIgnoreHookTest.php @@ -0,0 +1,47 @@ +config('system.site')->set('name', 'Test import')->save(); + + $this->doExport(); + + $this->config('system.site')->set('name', 'Changed title')->save(); + + $this->doImport(); + + // Test if the `config_ignore_hook_test` module got to ignore the site name + // config. + $this->assertEquals('Changed title', $this->config('system.site')->get('name')); + + } + +} diff --git a/sites/all/modules/contrib/dev/config_ignore/tests/src/Functional/ConfigIgnoreTest.php b/sites/all/modules/contrib/dev/config_ignore/tests/src/Functional/ConfigIgnoreTest.php new file mode 100644 index 000000000..f632f4923 --- /dev/null +++ b/sites/all/modules/contrib/dev/config_ignore/tests/src/Functional/ConfigIgnoreTest.php @@ -0,0 +1,196 @@ +config('system.site')->set('name', 'Test import')->save(); + $this->config('system.date')->set('first_day', '0')->save(); + $this->config('config_ignore.settings')->set('ignored_config_entities', ['system.site'])->save(); + + $this->doExport(); + + // Login with a user that has permission to sync. config. + $this->drupalLogin($this->drupalCreateUser(['synchronize configuration'])); + + // Change the site name, which is supposed to look as an ignored change + // in on the sync. page. + $this->config('system.site')->set('name', 'Test import with changed title')->save(); + $this->config('system.date')->set('first_day', '1')->save(); + + // Validate that the sync. table informs the user that the config will be + // ignored. + $this->drupalGet('admin/config/development/configuration'); + $this->assertSession()->linkExists('Config Ignore Settings'); + /** @var \Behat\Mink\Element\NodeElement[] $table_content */ + $table_content = $this->xpath('//table[@id="edit-ignored"]//td'); + + $table_values = []; + foreach ($table_content as $item) { + $table_values[] = $item->getHtml(); + } + + $this->assertTrue(in_array('system.site', $table_values)); + $this->assertFalse(in_array('system.date', $table_values)); + } + + /** + * Verify that the settings form works. + */ + public function testSettingsForm() { + // Login with a user that has permission to import config. + $this->drupalLogin($this->drupalCreateUser(['import configuration'])); + + $edit = [ + 'ignored_config_entities' => 'config.test', + ]; + + $this->drupalGet('admin/config/development/configuration/ignore'); + $this->submitForm($edit, t('Save configuration')); + + $settings = $this->config('config_ignore.settings')->get('ignored_config_entities'); + + $this->assertEqual($settings, ['config.test']); + } + + /** + * Verify that config can get ignored. + */ + public function testValidateIgnoring() { + + // Set the site name to a known value that we later will try and overwrite. + $this->config('system.site')->set('name', 'Test import')->save(); + + // Set the system.site:name to be ignored upon config import. + $this->config('config_ignore.settings')->set('ignored_config_entities', ['system.site'])->save(); + + $this->doExport(); + + // Change the site name, perform an import and see if the site name remains + // the same, as it should. + $this->config('system.site')->set('name', 'Changed title')->save(); + $this->doImport(); + $this->assertEquals('Changed title', $this->config('system.site')->get('name')); + + } + + /** + * Verify all wildcard asterisk is working. + */ + public function testValidateIgnoringWithWildcard() { + + // Set the site name to a known value that we later will try and overwrite. + $this->config('system.site')->set('name', 'Test import')->save(); + + // Set the system.site:name to be ignored upon config import. + $this->config('config_ignore.settings')->set('ignored_config_entities', ['system.' . IgnoreFilter::INCLUDE_SUFFIX])->save(); + + $this->doExport(); + + // Change the site name, perform an import and see if the site name remains + // the same, as it should. + $this->config('system.site')->set('name', 'Changed title')->save(); + $this->doImport(); + $this->assertEquals('Changed title', $this->config('system.site')->get('name')); + + } + + /** + * Verify Force Import syntax is working. + * + * This test makes sure we avoid regression issues. + */ + public function testValidateForceImporting() { + // Set the site name to a known value that we later will try and overwrite. + $this->config('system.site')->set('name', 'Test import')->save(); + + // Set the system.site:name to be (force-) imported upon config import. + $settings = [IgnoreFilter::FORCE_EXCLUSION_PREFIX . 'system.site']; + $this->config('config_ignore.settings')->set('ignored_config_entities', $settings)->save(); + + $this->doExport(); + + // Change the site name, perform an import and see if the site name remains + // the same, as it should. + $this->config('system.site')->set('name', 'Changed title')->save(); + $this->doImport(); + $this->assertEquals('Test import', $this->config('system.site')->get('name')); + } + + /** + * Verify excluded configuration works with wildcards. + * + * This test cover the scenario where a wildcard matches a specific + * configuration, but that's still imported due exclusion. + */ + public function testValidateForceImportingWithWildcard() { + + // Set the site name to a known value that we later will try and overwrite. + $this->config('system.site')->set('name', 'Test import')->save(); + + // Set the system.site:name to be (force-) imported upon config import. + $settings = ['system.' . IgnoreFilter::INCLUDE_SUFFIX, IgnoreFilter::FORCE_EXCLUSION_PREFIX . 'system.site']; + $this->config('config_ignore.settings')->set('ignored_config_entities', $settings)->save(); + + $this->doExport(); + + // Change the site name, perform an import and see if the site name remains + // the same, as it should. + $this->config('system.site')->set('name', 'Changed title')->save(); + $this->doImport(); + $this->assertEquals('Test import', $this->config('system.site')->get('name')); + + } + + /** + * Verify ignoring only some config keys. + * + * This test covers the scenario when not the whole config is to be ignored + * but only a certain subset of it. + */ + public function testValidateImportingWithIgnoredSubKeys() { + + // Set the site name to a known value that we later will try and overwrite. + $this->config('system.site') + ->set('name', 'Test name') + ->set('slogan', 'Test slogan') + ->set('page.front', '/ignore') + ->save(); + + // Set the system.site:name to be (force-) imported upon config import. + $settings = ['system.site:name', 'system.site:page.front']; + $this->config('config_ignore.settings')->set('ignored_config_entities', $settings)->save(); + + $this->doExport(); + + // Change the site name, perform an import and see if the site name remains + // the same, as it should. + $this->config('system.site') + ->set('name', 'Changed title') + ->set('slogan', 'Changed slogan') + ->set('page.front', '/new-ignore') + ->save(); + + $this->doImport(); + $this->assertEquals('Changed title', $this->config('system.site')->get('name')); + $this->assertEquals('Test slogan', $this->config('system.site')->get('slogan')); + $this->assertEquals('/new-ignore', $this->config('system.site')->get('page.front')); + } + +} diff --git a/sites/default/config/sync/config_ignore.settings.yml b/sites/default/config/sync/config_ignore.settings.yml new file mode 100644 index 000000000..78aae001e --- /dev/null +++ b/sites/default/config/sync/config_ignore.settings.yml @@ -0,0 +1,6 @@ +ignored_config_entities: + 0: system.performance + 2: devel.settings +_core: + default_config_hash: UVH1aJ4b44UM-VdPVN7hNNuuVqfReJxwfVeDQH1Hvsk +langcode: fr diff --git a/sites/default/config/sync/core.extension.yml b/sites/default/config/sync/core.extension.yml index 51f2d958a..40d3ce8bb 100644 --- a/sites/default/config/sync/core.extension.yml +++ b/sites/default/config/sync/core.extension.yml @@ -12,6 +12,8 @@ module: color_field: 0 config: 0 config_devel: 0 + config_filter: 0 + config_ignore: 0 config_update: 0 context: 0 context_ui: 0 diff --git a/sites/default/config/sync/system.performance.yml b/sites/default/config/sync/system.performance.yml index 7a276db56..76fb63587 100644 --- a/sites/default/config/sync/system.performance.yml +++ b/sites/default/config/sync/system.performance.yml @@ -1,8 +1,8 @@ cache: page: - max_age: 0 + max_age: 300 css: - preprocess: false + preprocess: true gzip: true fast_404: enabled: true @@ -10,7 +10,7 @@ fast_404: exclude_paths: '/\/(?:styles|imagecache)\//' html: '404 Not Found

Not Found

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

' js: - preprocess: false + preprocess: true gzip: true stale_file_threshold: 2592000 _core: