From: Jeff Veit Date: Mon, 19 Nov 2018 22:05:11 +0000 (+0000) Subject: Added the Search API Synonym module to deal specifically with licence and license... X-Git-Url: http://www.aleph1.co.uk/gitweb/?p=yaffs-website;a=commitdiff_plain;h=4e1bfbf98b844da83b18aca92ef00f11a4735806 Added the Search API Synonym module to deal specifically with licence and license, which stemming doesn't deal with. --- diff --git a/web/modules/contrib/search_api_synonym/LICENSE.txt b/web/modules/contrib/search_api_synonym/LICENSE.txt new file mode 100644 index 000000000..d159169d1 --- /dev/null +++ b/web/modules/contrib/search_api_synonym/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/web/modules/contrib/search_api_synonym/README.txt b/web/modules/contrib/search_api_synonym/README.txt new file mode 100644 index 000000000..ff7c7f4b2 --- /dev/null +++ b/web/modules/contrib/search_api_synonym/README.txt @@ -0,0 +1,89 @@ +CONTENTS OF THIS FILE +--------------------- + * Introduction + * Requirements + * Installation + * Manage synonyms + * Export synonyms + * Developers + * Troubleshooting + * Sponsors + * Maintainers + +INTRODUCTION +------------ +This module let editors or administrators manage synonyms for Search API +directly in Drupal. + +Synonyms can be export using the build in Drupal Console command. +Drush command and automatic export using Drupal cron job is in development. + +The module support the synonyms.txt format used in Apache Solr. +Other formats can be added using the Export plugin annotation. + +REQUIREMENTS +------------ +* No requirements. + +INSTALLATION +------------ + * Install as you would normally install a contributed drupal module. See: + https://www.drupal.org/documentation/install/modules-themes/modules-8 + for further information. + +MANAGE SYNONYMS +--------------- +After installation can you start managing your synonyms and spelling errors +at admin/config/search/search-api-synonyms. + +EXPORT SYNONYMS +--------------- + +Drupal Console +-------------- + +Export the added synonyms using the Drupal Console command: + +- drupal searchapi:synonym:export + +Execute the command with --help to see the different options. + +Drush +----- + +Export synonyms using the Drush command: + +- drush search-api-synonym-export + +- drush sapi-syn-ex + +Execute the command with --help to see the different options. + +Cron +---- + +Export using Drupal cron is supported. See the settings in /admin/config/search/search-api-synonyms/settings. + +DEVELOPERS +---------- + +The Search API Synonym module provides the following ways for developers to +extend the functionality: + +- Plugins + Export plugin - see the annotation and the Solr plugin: + - Drupal\search_api_synonym\Annotation\SearchApiSynonymExport + - Drupal\search_api_synonym\Plugin\search_api_synonym\export\Solr + +TROUBLESHOOTING +--------------- +- + +SPONSORS +-------- + * FFW - https://ffwagency.com + +MAINTAINERS +----------- +Current maintainers: + * Jens Beltofte (beltofte) - https://drupal.org/u/beltofte diff --git a/web/modules/contrib/search_api_synonym/composer.json b/web/modules/contrib/search_api_synonym/composer.json new file mode 100644 index 000000000..af1c05ba5 --- /dev/null +++ b/web/modules/contrib/search_api_synonym/composer.json @@ -0,0 +1,14 @@ +{ + "name": "drupal/search_api_synonym", + "type": "drupal-module", + "description": "Managing of search synonyms in Drupal.", + "keywords": ["Drupal"], + "license": "GPL-2.0+", + "homepage": "https://www.drupal.org/project/search_api_synonym", + "minimum-stability": "dev", + "support": { + "issues": "http://drupal.org/project/issues/search_api_synonym", + "source": "http://cgit.drupalcode.org/search_api_synonym" + }, + "require": { } +} diff --git a/web/modules/contrib/search_api_synonym/config/install/search_api_synonym.settings.yml b/web/modules/contrib/search_api_synonym/config/install/search_api_synonym.settings.yml new file mode 100644 index 000000000..a704d6ea7 --- /dev/null +++ b/web/modules/contrib/search_api_synonym/config/install/search_api_synonym.settings.yml @@ -0,0 +1,7 @@ +cron: + plugin: solr + interval: 86400 + type: all + filter: none + separate_files: 1 + export_if_changed: 1 diff --git a/web/modules/contrib/search_api_synonym/config/install/views.view.search_api_synonym.yml b/web/modules/contrib/search_api_synonym/config/install/views.view.search_api_synonym.yml new file mode 100644 index 000000000..a4b4de745 --- /dev/null +++ b/web/modules/contrib/search_api_synonym/config/install/views.view.search_api_synonym.yml @@ -0,0 +1,917 @@ +langcode: en +status: true +dependencies: + module: + - options + - search_api_synonym + - user +id: search_api_synonym +label: 'Search API Synonym' +module: views +description: 'Editorial views used by Search API Synonym.' +tag: '' +base_table: search_api_synonym +base_field: sid +core: 8.x +display: + default: + display_plugin: default + id: default + display_title: Master + position: 0 + display_options: + access: + type: perm + options: + perm: 'administer search api synonyms' + cache: + type: tag + options: { } + query: + type: views_query + options: + disable_sql_rewrite: false + distinct: false + replica: false + query_comment: '' + query_tags: { } + exposed_form: + type: basic + options: + submit_button: Apply + reset_button: true + reset_button_label: Reset + exposed_sorts_label: 'Sort by' + expose_sort_order: true + sort_asc_label: Asc + sort_desc_label: Desc + pager: + type: mini + options: + items_per_page: 50 + offset: 0 + id: 0 + total_pages: null + expose: + items_per_page: false + items_per_page_label: 'Items per page' + items_per_page_options: '5, 10, 25, 50' + items_per_page_options_all: false + items_per_page_options_all_label: '- All -' + offset: false + offset_label: Offset + tags: + previous: ‹‹ + next: ›› + style: + type: table + options: + grouping: { } + row_class: '' + default_row_class: true + override: true + sticky: false + caption: '' + summary: '' + description: '' + columns: + word: word + synonyms: synonyms + type: type + langcode: langcode + name: name + status: status + changed: changed + operations: operations + info: + word: + sortable: true + default_sort_order: asc + align: '' + separator: '' + empty_column: false + responsive: '' + synonyms: + sortable: true + default_sort_order: asc + align: '' + separator: '' + empty_column: false + responsive: priority-medium + type: + sortable: true + default_sort_order: asc + align: '' + separator: '' + empty_column: false + responsive: priority-medium + langcode: + sortable: true + default_sort_order: asc + align: '' + separator: '' + empty_column: false + responsive: priority-low + name: + sortable: true + default_sort_order: asc + align: '' + separator: '' + empty_column: false + responsive: priority-low + status: + sortable: true + default_sort_order: asc + align: '' + separator: '' + empty_column: false + responsive: priority-low + changed: + sortable: true + default_sort_order: asc + align: '' + separator: '' + empty_column: false + responsive: priority-low + operations: + sortable: false + default_sort_order: asc + align: '' + separator: '' + empty_column: false + responsive: priority-medium + default: word + empty_table: false + row: + type: fields + fields: + word: + id: word + table: search_api_synonym + field: word + relationship: none + group_type: group + admin_label: '' + label: Word + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: string + settings: + link_to_entity: true + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + entity_type: null + entity_field: word + plugin_id: field + synonyms: + id: synonyms + table: search_api_synonym + field: synonyms + relationship: none + group_type: group + admin_label: '' + label: Synonyms + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 125 + word_boundary: false + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: true + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: false + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: string + settings: + link_to_entity: true + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + entity_type: search_api_synonym + entity_field: synonyms + plugin_id: field + type: + id: type + table: search_api_synonym + field: type + relationship: none + group_type: group + admin_label: '' + label: Type + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: false + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: list_default + settings: { } + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + entity_type: search_api_synonym + entity_field: type + plugin_id: field + langcode: + id: langcode + table: search_api_synonym + field: langcode + relationship: none + group_type: group + admin_label: '' + label: Language + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: false + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: language + settings: + link_to_entity: false + native_language: false + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + entity_type: search_api_synonym + entity_field: langcode + plugin_id: field + name: + id: name + table: users_field_data + field: name + relationship: uid + group_type: group + admin_label: '' + label: Author + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: user_name + settings: + link_to_entity: true + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + entity_type: user + entity_field: name + plugin_id: field + status: + id: status + table: search_api_synonym + field: status + relationship: none + group_type: group + admin_label: '' + label: Status + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: false + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: boolean + settings: + format: custom + format_custom_true: active + format_custom_false: inactive + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + entity_type: search_api_synonym + entity_field: status + plugin_id: field + changed: + id: changed + table: search_api_synonym + field: changed + relationship: none + group_type: group + admin_label: '' + label: Updated + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: timestamp + settings: + date_format: custom + custom_date_format: 'd/m/Y H:i' + timezone: '' + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + entity_type: search_api_synonym + entity_field: changed + plugin_id: field + operations: + id: operations + table: search_api_synonym + field: operations + relationship: none + group_type: group + admin_label: '' + label: Operations + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + destination: true + entity_type: search_api_synonym + plugin_id: entity_operations + filters: + word: + id: word + table: search_api_synonym + field: word + relationship: none + group_type: group + admin_label: '' + operator: contains + value: '' + group: 1 + exposed: true + expose: + operator_id: word_op + label: Word + description: '' + use_operator: false + operator: word_op + identifier: word + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + administrator: '0' + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + entity_type: search_api_synonym + entity_field: word + plugin_id: string + synonyms: + id: synonyms + table: search_api_synonym + field: synonyms + relationship: none + group_type: group + admin_label: '' + operator: contains + value: '' + group: 1 + exposed: true + expose: + operator_id: synonyms_op + label: Synonyms + description: '' + use_operator: false + operator: synonyms_op + identifier: synonyms + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + administrator: '0' + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + entity_type: search_api_synonym + entity_field: synonyms + plugin_id: string + type: + id: type + table: search_api_synonym + field: type + relationship: none + group_type: group + admin_label: '' + operator: '=' + value: '' + group: 1 + exposed: true + expose: + operator_id: type_op + label: Type + description: '' + use_operator: false + operator: type_op + identifier: type + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + administrator: '0' + is_grouped: true + group_info: + label: Type + description: '' + identifier: type + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: + 1: + title: Synonym + operator: '=' + value: synonym + 2: + title: 'Spelling error' + operator: '=' + value: spelling_error + entity_type: search_api_synonym + entity_field: type + plugin_id: string + status: + id: status + table: search_api_synonym + field: status + relationship: none + group_type: group + admin_label: '' + operator: '=' + value: All + group: 1 + exposed: true + expose: + operator_id: '' + label: Status + description: '' + use_operator: false + operator: status_op + identifier: status + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + administrator: '0' + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + entity_type: search_api_synonym + entity_field: status + plugin_id: boolean + langcode: + id: langcode + table: search_api_synonym + field: langcode + relationship: none + group_type: group + admin_label: '' + operator: in + value: { } + group: 1 + exposed: true + expose: + operator_id: langcode_op + label: Language + description: '' + use_operator: false + operator: langcode_op + identifier: langcode + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + administrator: '0' + reduce: false + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + entity_type: search_api_synonym + entity_field: langcode + plugin_id: language + sorts: { } + title: 'Search API Synonym' + header: { } + footer: { } + empty: { } + relationships: + uid: + id: uid + table: search_api_synonym + field: uid + relationship: none + group_type: group + admin_label: User + required: true + entity_type: search_api_synonym + entity_field: uid + plugin_id: standard + arguments: { } + display_extenders: { } + filter_groups: + operator: AND + groups: + 1: AND + use_ajax: true + cache_metadata: + max-age: 0 + contexts: + - 'languages:language_content' + - 'languages:language_interface' + - url + - url.query_args + - user.permissions + tags: { } + list: + display_plugin: page + id: list + display_title: Page + position: 1 + display_options: + display_extenders: { } + path: admin/config/search/search-api-synonyms + cache_metadata: + max-age: 0 + contexts: + - 'languages:language_content' + - 'languages:language_interface' + - url + - url.query_args + - user.permissions + tags: { } diff --git a/web/modules/contrib/search_api_synonym/config/schema/search_api_synonym.schema.yml b/web/modules/contrib/search_api_synonym/config/schema/search_api_synonym.schema.yml new file mode 100644 index 000000000..8ccb1266d --- /dev/null +++ b/web/modules/contrib/search_api_synonym/config/schema/search_api_synonym.schema.yml @@ -0,0 +1,28 @@ +# Schema for the configuration files of the Search API Synonym module. + +search_api_synonym.settings: + type: config_object + label: 'Search API Synonym settings' + mapping: + cron: + type: mapping + label: 'Cron' + mapping: + plugin: + type: string + label: 'Plugin' + interval: + type: integer + label: 'Interval' + type: + type: string + label: 'Type' + filter: + type: string + label: 'Filter' + separate_files: + type: bool + label: 'Separate files' + export_if_changed: + type: bool + label: 'Export if new added or changed since last export.' diff --git a/web/modules/contrib/search_api_synonym/console/translations/en/searchapi.synonym.export.yml b/web/modules/contrib/search_api_synonym/console/translations/en/searchapi.synonym.export.yml new file mode 100644 index 000000000..ad1369d59 --- /dev/null +++ b/web/modules/contrib/search_api_synonym/console/translations/en/searchapi.synonym.export.yml @@ -0,0 +1,23 @@ +description: 'Export search synonyms to a specific format.' +options: + plugin: + description: 'Machine name of the export plugin. E.g. solr.' + langcode: + description: 'Language being exported. Use the language code. E.g. en or da.' + type: + description: 'Synonym type. Allowed values: synonym = Synomyms, spelling_error = Spelling errors, all = All types (synonyms and spelling errors). If option not defined will all types be exported.' + filter: + description: 'Export filter. Allowed values: nospace = Skip all words containing a space, onlyspace = Skip all words without a space.' + incremental: + description: 'Incremental export - use Unix timestamp. Only export synonyms changed after the provided timestamp.' + file: + description: 'File name used when saving the exported file. Include extension and not folder name!' +arguments: {} +messages: + start: 'Starting synonym export....' + success: 'Synonyms export and saved in the following file:' + invalidplugin: '--plugin is not valid. Please, use an existing plugin machine name.' + invalidlangcode: '--langcode is not valid. Please, use an existing language code.' + invalidtype: '--type option is not valid. The only allowed values are "synonym", "spelling_error", "all".' + invalidfilter: '--filter option is not valid. The only allowed values are "nospace", "onlyspace", "all".' + diff --git a/web/modules/contrib/search_api_synonym/examples/example.csv b/web/modules/contrib/search_api_synonym/examples/example.csv new file mode 100644 index 000000000..891bd29ff --- /dev/null +++ b/web/modules/contrib/search_api_synonym/examples/example.csv @@ -0,0 +1,4 @@ +"word";"synonym";"type" +"cms";"content management system";"synonym" +"dropal";"drupal";"spelling_error" +"cq5,sitecore,sharepoint";"drupal";"spelling_error" diff --git a/web/modules/contrib/search_api_synonym/examples/example.json b/web/modules/contrib/search_api_synonym/examples/example.json new file mode 100644 index 000000000..9b1cae0d8 --- /dev/null +++ b/web/modules/contrib/search_api_synonym/examples/example.json @@ -0,0 +1,17 @@ +[ + { + "word": "cms", + "synonym": "content management system", + "type": "synonym" + }, + { + "word": "dropal", + "synonym": "drupal", + "type": "spelling_error" + }, + { + "word": "cq5,sitecore,sharepoint", + "synonym": "drupal", + "type": "spelling_error" + } +] \ No newline at end of file diff --git a/web/modules/contrib/search_api_synonym/examples/solr_synonyms.txt b/web/modules/contrib/search_api_synonym/examples/solr_synonyms.txt new file mode 100644 index 000000000..cede97b3d --- /dev/null +++ b/web/modules/contrib/search_api_synonym/examples/solr_synonyms.txt @@ -0,0 +1,10 @@ +# +# Apache Solr - Synonyms.txt example file. +# + +# Synonym +cms, content management system + +# Spelling errors +dropal => drupal +cq5, sitecore, sharepoint => drupal diff --git a/web/modules/contrib/search_api_synonym/search_api_synonym.drush.inc b/web/modules/contrib/search_api_synonym/search_api_synonym.drush.inc new file mode 100644 index 000000000..2fb3e8fc0 --- /dev/null +++ b/web/modules/contrib/search_api_synonym/search_api_synonym.drush.inc @@ -0,0 +1,122 @@ + 'Export search synonyms to a specific format.', + 'examples' => [ + 'drush search-api-synonym-export --plugin=solr langcode=da type=spelling_error filter=all' => dt('Export all Danish spelling errors in the Solr format.'), + 'drush sapi-syn-ex --plugin=solr langcode=da type=spelling_error filter=all' => dt('Export all Danish spelling errors in the Solr format.'), + ], + 'options' => [ + 'plugin' => dt('Machine name of the export plugin. E.g. solr.'), + 'langcode' => dt('Language being exported. Use the language code. E.g. en or da.'), + 'type' => dt('Synonym type. Allowed values: synonym = Synomyms, spelling_error = Spelling errors, all = All types (synonyms and spelling errors). Defaults to "alL".'), + 'filter' => dt('Export filter. Allowed values: nospace = Skip all words containing a space, onlyspace = Skip all words without a space. Defaults to "all".'), + 'incremental' => dt('Incremental export - use Unix timestamp. Only export synonyms changed after the provided timestamp.'), + 'file' => dt('File name used when saving the exported file. Include extension but not folder name!.'), + ], + 'aliases' => ['sapi-syn-ex'], + ]; + + return $items; +} + +/** + * Export synonyms to a flat file. + */ +function drush_search_api_synonym_export() { + // Plugin manager + $pluginManager = \Drupal::service('plugin.manager.search_api_synonym.export'); + + // Options + $plugin = drush_get_option('plugin'); + $langcode = drush_get_option('langcode'); + $type = drush_get_option('type', 'all'); + $filter = drush_get_option('filter', 'all'); + $file = drush_get_option('file'); + $incremental = drush_get_option('incremental'); + + // Validate option: plugin + if (!$pluginManager->validatePlugin($plugin)) { + $error = TRUE; + drush_set_error(dt('--plugin is not valid. Please, use an existing plugin machine name.')); + } + + // Validate option: langcode + if (empty($langcode)) { + $error = TRUE; + drush_set_error(dt('--langcode is not valid. Please, use an existing language code.')); + } + + // Validate option: type + if (!empty($type) && !search_api_synonym_drush_validate_option_type($type)) { + $error = TRUE; + drush_set_error(dt('--type option is not valid. The only allowed values are "synonym", "spelling_error", "all".')); + } + + // Validate option: filter + if (!empty($filter) && !search_api_synonym_drush_validate_option_filter($filter)) { + $error = TRUE; + drush_set_error(dt('--filter option is not valid. The only allowed values are "nospace", "onlyspace", "all".')); + } + + // Prepare export + if (!isset($error)) { + drush_log(dt('Starting synonym export....'), 'ok'); + + $options = [ + 'langcode' => $langcode, + 'type' => $type, + 'filter' => $filter, + 'file' => $file, + 'incremental' => (int) $incremental, + ]; + $pluginManager->setPluginId($plugin); + $pluginManager->setExportOptions($options); + + // Execute export + if ($result = $pluginManager->executeExport()) { + + // Output result + drush_log(dt('Synonyms export and saved in the file @file', ['@file' => $result]), 'ok'); + } + } +} + +/** + * Validate that the type option is valid. + * + * @param string $type + * Type value from --type command option. + * + * @return boolean + * TRUE if valid, FALSE if invalid. + */ +function search_api_synonym_drush_validate_option_type($type) { + $types = ['synonym', 'spelling_error', 'all']; + return in_array($type, $types); +} + +/** + * Validate that the filter option is valid. + * + * @param string $filter + * Type value from --filter command option. + * + * @return boolean + * TRUE if valid, FALSE if invalid. + */ +function search_api_synonym_drush_validate_option_filter($filter) { + $filters = ['nospace', 'onlyspace', 'all']; + return in_array($filter, $filters); +} diff --git a/web/modules/contrib/search_api_synonym/search_api_synonym.info.yml b/web/modules/contrib/search_api_synonym/search_api_synonym.info.yml new file mode 100644 index 000000000..a9afd88d1 --- /dev/null +++ b/web/modules/contrib/search_api_synonym/search_api_synonym.info.yml @@ -0,0 +1,14 @@ +name: Search API Synonym +type: module +description: Managing of search synonyms in Drupal. +# core: 8.x +package: Search +configure: entity.search_api_synonym.collection +dependencies: + - system (>=8.2.0) + +# Information added by Drupal.org packaging script on 2017-07-24 +version: '8.x-1.2' +core: '8.x' +project: 'search_api_synonym' +datestamp: 1500888244 diff --git a/web/modules/contrib/search_api_synonym/search_api_synonym.install b/web/modules/contrib/search_api_synonym/search_api_synonym.install new file mode 100644 index 000000000..695b500ed --- /dev/null +++ b/web/modules/contrib/search_api_synonym/search_api_synonym.install @@ -0,0 +1,40 @@ + 'varchar', + 'length' => 128, + 'not null' => FALSE, + ]; + $schema = Database::getConnection()->schema(); + $schema->changeField('search_api_synonym', 'word', 'word', $spec); +} + +/** + * Remove extra white spaces from synonyms. + */ +function search_api_synonym_update_8002() { + $sids = \Drupal::entityQuery('search_api_synonym') + ->condition('synonyms', '% %', 'LIKE') + ->execute(); + + foreach ($sids as $sid) { + $synonym = Synonym::load($sid); + $synonyms = explode(',', $synonym->getSynonyms()); + array_walk($synonyms, 'trim'); + $synonyms = implode(',', $synonyms); + $synonym->setSynonyms($synonyms); + $synonym->save(); + } +} diff --git a/web/modules/contrib/search_api_synonym/search_api_synonym.links.action.yml b/web/modules/contrib/search_api_synonym/search_api_synonym.links.action.yml new file mode 100644 index 000000000..c92bcb0cb --- /dev/null +++ b/web/modules/contrib/search_api_synonym/search_api_synonym.links.action.yml @@ -0,0 +1,6 @@ +entity.search_api_synonym.add_form: + route_name: 'entity.search_api_synonym.add_form' + title: 'Add synonym' + appears_on: + - entity.search_api_synonym.collection + diff --git a/web/modules/contrib/search_api_synonym/search_api_synonym.links.menu.yml b/web/modules/contrib/search_api_synonym/search_api_synonym.links.menu.yml new file mode 100644 index 000000000..7f2b91f6a --- /dev/null +++ b/web/modules/contrib/search_api_synonym/search_api_synonym.links.menu.yml @@ -0,0 +1,5 @@ +entity.search_api_synonym.collection: + title: 'Search API Synonyms' + route_name: entity.search_api_synonym.collection + description: 'Create and configure synonyms.' + parent: system.admin_config_search diff --git a/web/modules/contrib/search_api_synonym/search_api_synonym.links.task.yml b/web/modules/contrib/search_api_synonym/search_api_synonym.links.task.yml new file mode 100644 index 000000000..b1a8a6f64 --- /dev/null +++ b/web/modules/contrib/search_api_synonym/search_api_synonym.links.task.yml @@ -0,0 +1,14 @@ +entity.search_api_synonym.collection: + title: List + route_name: entity.search_api_synonym.collection + base_route: entity.search_api_synonym.collection + +entity.search_api_synonym.settings_form: + title: Settings + route_name: entity.search_api_synonym.settings + base_route: entity.search_api_synonym.collection + +entity.search_api_synonym.import: + title: Import + route_name: entity.search_api_synonym.import + base_route: entity.search_api_synonym.collection diff --git a/web/modules/contrib/search_api_synonym/search_api_synonym.module b/web/modules/contrib/search_api_synonym/search_api_synonym.module new file mode 100644 index 000000000..e8ab74385 --- /dev/null +++ b/web/modules/contrib/search_api_synonym/search_api_synonym.module @@ -0,0 +1,122 @@ +' . t('About') . ''; + $output .= '

' . t('Managing of search synonyms in Drupal.') . '

'; + return $output; + + default: + return ''; + } +} + +/** + * Implements hook_cron(). + */ +function search_api_synonym_cron() { + $request_time = \Drupal::time()->getRequestTime(); + + // Export synonyms to files. + $conf = \Drupal::configFactory()->getEditable('search_api_synonym.settings')->get('cron'); + $interval = !empty($conf['interval']) ? $conf['interval'] : 86400; + $next_execution = \Drupal::state()->get('search_api_synonym.export.next_execution', 0); + + if ($request_time >= $next_execution) { + $logger = \Drupal::logger('search_api_synonym'); + // Execute export + $logger->notice('Executing export'); + + // Plugin manager + $pluginManager = \Drupal::service('plugin.manager.search_api_synonym.export'); + + // Validate option: plugin + $plugin = $conf['plugin']; + if (!$pluginManager->validatePlugin($plugin)) { + $logger->warning('Export plugin not found'); + return; + } + + // Setting non language specific export options + $options = [ + 'type' => $conf['type'], + 'filter' => $conf['filter'], + 'file' => '', + 'incremental' => $conf['export_if_changed'] ? $next_execution : 0 + ]; + + // Get all languages in the system + $languages = \Drupal::languageManager()->getLanguages(); + + foreach ($languages as $language) { + $options['langcode'] = $language->getId(); + + // Export synonyms with and without spaces into separate files + if ($conf['separate_files'] && ($conf['filter'] == 'none' || !$conf['filter'])) { + // Without spaces + $options['filter'] = 'nospace'; + search_api_synonym_execute_single_import($plugin, $options); + + // With spaces + $options['filter'] = 'onlyspace'; + search_api_synonym_execute_single_import($plugin, $options); + + } + else { + search_api_synonym_execute_single_import($plugin, $options); + } + } + + $logger->info('Export done'); + + \Drupal::state()->set('search_api_synonym.export.next_execution', $request_time + $interval); + } + +} + +/** + * Execute single export. + * + * @param string $plugin + * Plugin name + * + * @param array $options + * Array of export options + */ +function search_api_synonym_execute_single_import($plugin, $options) { + // Plugin manager + $pluginManager = \Drupal::service('plugin.manager.search_api_synonym.export'); + + // Logger + $logger = \Drupal::logger('search_api_synonym'); + + $pluginManager->setPluginId($plugin); + $pluginManager->setExportOptions($options); + if ($result = $pluginManager->executeExport()) { + $logger->info('Synonyms export to {filename}', ['filename' => $result]); + } + +} diff --git a/web/modules/contrib/search_api_synonym/search_api_synonym.permissions.yml b/web/modules/contrib/search_api_synonym/search_api_synonym.permissions.yml new file mode 100644 index 000000000..b786d91f5 --- /dev/null +++ b/web/modules/contrib/search_api_synonym/search_api_synonym.permissions.yml @@ -0,0 +1,9 @@ +administer search api synonyms: + title: 'Administer Search API Synonym synonyms' + description: 'Allow to access the administration of search API synonyms entities.' +administer search api synonym configuration: + title: 'Administer Search API Synonym configuration' + description: 'Allow to access the configuration of Search API Synonym.' +import search api synonyms: + title: 'Import synonyms to Search API Synonym' + description: 'Allow to access to import synonyms into Search API Synonym.' diff --git a/web/modules/contrib/search_api_synonym/search_api_synonym.routing.yml b/web/modules/contrib/search_api_synonym/search_api_synonym.routing.yml new file mode 100644 index 000000000..99b918377 --- /dev/null +++ b/web/modules/contrib/search_api_synonym/search_api_synonym.routing.yml @@ -0,0 +1,55 @@ +entity.search_api_synonym.collection: + path: '/admin/config/search/search-api-synonyms' + defaults: + _entity_list: 'search_api_synonym' + _title: 'Search API Synonyms' + requirements: + _permission: 'administer search api synonyms' + +entity.search_api_synonym.add_form: + path: '/admin/config/search/search-api-synonyms/add' + defaults: + _entity_form: 'search_api_synonym.add' + _title: 'Add synonym' + requirements: + _permission: 'administer search api synonyms' + +entity.search_api_synonym.canonical: + path: '/admin/config/search/search-api-synonyms/{search_api_synonym}' + defaults: + _entity_form: 'search_api_synonym.edit' + _title: 'Edit synonym' + requirements: + _permission: 'administer search api synonyms' + +entity.search_api_synonym.edit_form: + path: '/admin/config/search/search-api-synonyms/{search_api_synonym}/edit' + defaults: + _entity_form: 'search_api_synonym.edit' + _title: 'Edit synonym' + requirements: + _permission: 'administer search api synonyms' + +entity.search_api_synonym.delete_form: + path: '/admin/config/search/search-api-synonyms/{search_api_synonym}/delete' + defaults: + _entity_form: 'search_api_synonym.delete' + _title: 'Delete synonym' + requirements: + _permission: 'administer search api synonyms' + +entity.search_api_synonym.settings: + path: '/admin/config/search/search-api-synonyms/settings' + defaults: + _form: 'Drupal\search_api_synonym\Form\SynonymSettingsForm' + _title: 'Settings' + requirements: + _permission: 'administer search api synonym configuration' + +entity.search_api_synonym.import: + path: '/admin/config/search/search-api-synonyms/import' + defaults: + _form: 'Drupal\search_api_synonym\Form\SynonymImportForm' + _title: 'Import' + requirements: + _permission: 'import search api synonyms' diff --git a/web/modules/contrib/search_api_synonym/search_api_synonym.services.yml b/web/modules/contrib/search_api_synonym/search_api_synonym.services.yml new file mode 100644 index 000000000..5d80d8075 --- /dev/null +++ b/web/modules/contrib/search_api_synonym/search_api_synonym.services.yml @@ -0,0 +1,12 @@ +services: + plugin.manager.search_api_synonym.import: + class: Drupal\search_api_synonym\Import\ImportPluginManager + parent: default_plugin_manager + plugin.manager.search_api_synonym.export: + class: Drupal\search_api_synonym\Export\ExportPluginManager + parent: default_plugin_manager + search_api_synonym.command.export: + class: Drupal\search_api_synonym\Command\ExportCommand + arguments: [] + tags: + - { name: drupal.command } diff --git a/web/modules/contrib/search_api_synonym/src/Annotation/SearchApiSynonymExport.php b/web/modules/contrib/search_api_synonym/src/Annotation/SearchApiSynonymExport.php new file mode 100644 index 000000000..b157980b8 --- /dev/null +++ b/web/modules/contrib/search_api_synonym/src/Annotation/SearchApiSynonymExport.php @@ -0,0 +1,37 @@ +setName('searchapi:synonym:export') + ->setDescription($this->trans('commands.searchapi.synonym.export.description')) + ->addOption( + 'plugin', + null, + InputOption::VALUE_REQUIRED, + $this->trans('commands.searchapi.synonym.export.options.plugin.description') + ) + ->addOption( + 'langcode', + null, + InputOption::VALUE_REQUIRED, + $this->trans('commands.searchapi.synonym.export.options.langcode.description') + ) + ->addOption( + 'type', + null, + InputOption::VALUE_OPTIONAL, + $this->trans('commands.searchapi.synonym.export.options.type.description'), + 'all' + ) + ->addOption( + 'filter', + null, + InputOption::VALUE_OPTIONAL, + $this->trans('commands.searchapi.synonym.export.options.filter.description'), + 'all' + ) + ->addOption( + 'incremental', + null, + InputOption::VALUE_OPTIONAL, + $this->trans('commands.searchapi.synonym.export.options.incremental.description') + ) + ->addOption( + 'file', + null, + InputOption::VALUE_OPTIONAL, + $this->trans('commands.searchapi.synonym.export.options.file.description') + ); + } + + /** + * {@inheritdoc} + */ + protected function execute(InputInterface $input, OutputInterface $output) { + // Plugin manager + $pluginManager = \Drupal::service('plugin.manager.search_api_synonym.export'); + + // Options + $plugin = $input->getOption('plugin'); + $langcode = $input->getOption('langcode'); + $type = $input->getOption('type'); + $filter = $input->getOption('filter'); + $file = $input->getOption('file'); + $incremental = $input->getOption('incremental'); + + // Command output + $io = new DrupalStyle($input, $output); + + // Validate option: plugin + if (!$pluginManager->validatePlugin($plugin)) { + $error = TRUE; + $io->info($this->trans('commands.searchapi.synonym.export.messages.invalidplugin')); + } + + // Validate option: langcode + if (empty($langcode)) { + $error = TRUE; + $io->info($this->trans('commands.searchapi.synonym.export.messages.invalidlangcode')); + } + + // Validate option: type + if (!empty($type) && !$this->validateOptionType($type)) { + $error = TRUE; + $io->info($this->trans('commands.searchapi.synonym.export.messages.invalidtype')); + } + + // Validate option: filter + if (!empty($filter) && !$this->validateOptionFilter($filter)) { + $error = TRUE; + $io->info($this->trans('commands.searchapi.synonym.export.messages.invalidfilter')); + } + + // Prepare export + if (!isset($error)) { + $io->info($this->trans('commands.searchapi.synonym.export.messages.start')); + + $options = [ + 'langcode' => $langcode, + 'type' => $type, + 'filter' => $filter, + 'file' => $file, + 'incremental' => (int) $incremental, + ]; + $pluginManager->setPluginId($plugin); + $pluginManager->setExportOptions($options); + + // Execute export + if ($result = $pluginManager->executeExport()) { + + // Output result + $io->info($this->trans('commands.searchapi.synonym.export.messages.success')); + $io->info($result); + } + } + } + + /** + * Validate that the type option is valid. + * + * @param string $type + * Type value from --type command option. + * + * @return boolean + * TRUE if valid, FALSE if invalid. + */ + private function validateOptionType($type) { + $types = ['synonym', 'spelling_error', 'all']; + return in_array($type, $types); + } + + /** + * Validate that the filter option is valid. + * + * @param string $filter + * Type value from --filter command option. + * + * @return boolean + * TRUE if valid, FALSE if invalid. + */ + private function validateOptionFilter($filter) { + $filters = ['nospace', 'onlyspace', 'all']; + return in_array($filter, $filters); + } + +} diff --git a/web/modules/contrib/search_api_synonym/src/Entity/Synonym.php b/web/modules/contrib/search_api_synonym/src/Entity/Synonym.php new file mode 100644 index 000000000..df9e2ce72 --- /dev/null +++ b/web/modules/contrib/search_api_synonym/src/Entity/Synonym.php @@ -0,0 +1,320 @@ + \Drupal::currentUser()->id(), + ]; + } + + /** + * {@inheritdoc} + */ + public function getType() { + return $this->get('type')->value; + } + + /** + * {@inheritdoc} + */ + public function setType($type) { + $this->set('type', $type); + return $this; + } + + /** + * {@inheritdoc} + */ + public function getWord() { + return $this->get('word')->value; + } + + /** + * {@inheritdoc} + */ + public function setWord($word) { + $this->set('word', $word); + return $this; + } + + /** + * {@inheritdoc} + */ + public function getSynonyms() { + return $this->get('synonyms')->value; + } + + /** + * {@inheritdoc} + */ + public function getSynonymsFormatted() { + $synonyms = $this->get('synonyms')->value; + $synonyms = str_replace(',', ', ', $synonyms); + return trim($synonyms); + } + + /** + * {@inheritdoc} + */ + public function setSynonyms($synonyms) { + $this->set('synonyms', $synonyms); + return $this; + } + + /** + * {@inheritdoc} + */ + public function getCreatedTime() { + return $this->get('created')->value; + } + + /** + * {@inheritdoc} + */ + public function setCreatedTime($timestamp) { + $this->set('created', $timestamp); + return $this; + } + + /** + * {@inheritdoc} + */ + public function getOwner() { + return $this->get('uid')->entity; + } + + /** + * {@inheritdoc} + */ + public function getOwnerId() { + return $this->get('uid')->target_id; + } + + /** + * {@inheritdoc} + */ + public function setOwnerId($uid) { + $this->set('uid', $uid); + return $this; + } + + /** + * {@inheritdoc} + */ + public function setOwner(UserInterface $account) { + $this->set('uid', $account->id()); + return $this; + } + + /** + * {@inheritdoc} + */ + public function isActive() { + return (bool) $this->get('status'); + } + + /** + * {@inheritdoc} + */ + public function setActive($active) { + $this->set('status', $active ? SYNONYM_ACTIVE : SYNONYM_NOT_ACTIVE); + return $this; + } + + /** + * {@inheritdoc} + */ + public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { + /** @var \Drupal\Core\Field\BaseFieldDefinition[] $fields */ + /** @var \Drupal\Core\Field\BaseFieldDefinition[] $fields */ + $fields = parent::baseFieldDefinitions($entity_type); + + $fields['sid'] = BaseFieldDefinition::create('integer') + ->setLabel(t('ID')) + ->setDescription(t('The ID of the Synonym entity.')) + ->setReadOnly(TRUE); + + $fields['uuid'] = BaseFieldDefinition::create('uuid') + ->setLabel(t('UUID')) + ->setDescription(t('The UUID of the Synonym entity.')) + ->setReadOnly(TRUE); + + $fields['uid'] = BaseFieldDefinition::create('entity_reference') + ->setLabel(t('Authored by')) + ->setDescription(t('The user ID of author of the Synonym entity.')) + ->setSettings([ + 'target_type' => 'user', + 'handler' => 'default', + 'required' => TRUE, + ]) + ->setDefaultValueCallback('Drupal\node\Entity\Node::getCurrentUserId') + ->setDisplayOptions('view', [ + 'label' => 'hidden', + 'type' => 'author', + 'weight' => 0, + ]) + ->setDisplayOptions('form', [ + 'type' => 'entity_reference_autocomplete', + 'weight' => 5, + 'settings' => [ + 'match_operator' => 'CONTAINS', + 'size' => '60', + 'autocomplete_type' => 'tags', + 'placeholder' => '', + ], + ]) + ->setDisplayConfigurable('form', TRUE) + ->setDisplayConfigurable('view', TRUE); + + $fields['type'] = BaseFieldDefinition::create('list_string') + ->setLabel(t('Type')) + ->setDescription(t('The type of synonym.')) + ->setSettings([ + 'max_length' => 50, + 'allowed_values' => array('synonym' => 'Synonym', 'spelling_error' => 'Spelling error'), + ]) + ->setRequired(TRUE) + ->setDefaultValue('') + ->setDisplayOptions('view', [ + 'label' => 'above', + 'type' => 'string', + 'weight' => -3, + ]) + ->setDisplayOptions('form', [ + 'type' => 'options_buttons', + 'weight' => -3, + ]) + ->setDisplayConfigurable('form', TRUE) + ->setDisplayConfigurable('view', TRUE); + + $fields['word'] = BaseFieldDefinition::create('string') + ->setLabel(t('Word')) + ->setDescription(t('The word we are defining synonyms for.')) + ->setSettings([ + 'max_length' => 128, + 'text_processing' => 0, + ]) + ->setRequired(TRUE) + ->setDefaultValue('') + ->setDisplayOptions('view', [ + 'label' => 'above', + 'type' => 'string', + 'weight' => -4, + ]) + ->setDisplayOptions('form', [ + 'type' => 'string_textfield', + 'weight' => -4, + ]) + ->setDisplayConfigurable('form', TRUE) + ->setDisplayConfigurable('view', TRUE); + + $fields['synonyms'] = BaseFieldDefinition::create('string') + ->setLabel(t('Synonyms')) + ->setDescription(t('The synonyms to the word. Separate multiple by comma.')) + ->setSettings([ + 'max_length' => 1024, + 'text_processing' => 0, + ]) + ->setRequired(TRUE) + ->setDefaultValue('') + ->setDisplayOptions('view', [ + 'label' => 'above', + 'type' => 'string', + 'weight' => -3, + ]) + ->setDisplayOptions('form', [ + 'type' => 'string_textfield', + 'weight' => -3, + ]) + ->setDisplayConfigurable('form', TRUE) + ->setDisplayConfigurable('view', TRUE); + + $fields['status'] = BaseFieldDefinition::create('boolean') + ->setLabel(t('Activate synonym')) + ->setDescription(t('Only active synonyms will be used.')) + ->setDefaultValue(TRUE) + ->setDisplayOptions('view', [ + 'label' => 'above', + 'type' => 'boolean', + 'weight' => -2, + ]) + ->setDisplayOptions('form', [ + 'type' => 'boolean_checkbox', + 'weight' => -2, + ]) + ->setDisplayConfigurable('form', TRUE) + ->setDisplayConfigurable('view', TRUE); + + $fields['langcode'] = BaseFieldDefinition::create('language') + ->setLabel(t('Language')) + ->setDescription(t('The language for the Synonym entity.')) + ->setDisplayOptions('form', [ + 'type' => 'language_select', + 'weight' => 10, + ]) + ->setDisplayConfigurable('form', TRUE); + + $fields['created'] = BaseFieldDefinition::create('created') + ->setLabel(t('Created')) + ->setDescription(t('The time that the entity was created.')); + + $fields['changed'] = BaseFieldDefinition::create('changed') + ->setLabel(t('Changed')) + ->setDescription(t('The time that the entity was last edited.')); + + return $fields; + } + +} diff --git a/web/modules/contrib/search_api_synonym/src/Export/ExportPluginBase.php b/web/modules/contrib/search_api_synonym/src/Export/ExportPluginBase.php new file mode 100644 index 000000000..69746fedd --- /dev/null +++ b/web/modules/contrib/search_api_synonym/src/Export/ExportPluginBase.php @@ -0,0 +1,91 @@ +configFactory = $config_factory; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { + return new static( + $configuration, $plugin_id, $plugin_definition, $container->get('config.factory') + ); + } + + /** + * {@inheritdoc} + */ + public function getConfiguration() { + return $this->configuration; + } + + /** + * {@inheritdoc} + */ + public function setConfiguration(array $configuration) { + $this->configuration += $configuration; + } + + /** + * {@inheritdoc} + */ + public function defaultConfiguration() { + return []; + } + + /** + * {@inheritdoc} + */ + public function buildConfigurationForm(array $form, FormStateInterface $form_state) { + return $form; + } + + /** + * {@inheritdoc} + */ + public function validateConfigurationForm(array &$form, FormStateInterface $form_state) { + $values = $form_state->getValues(); + } + + /** + * {@inheritdoc} + */ + public function submitConfigurationForm(array &$form, FormStateInterface $form_state) { + parent::submitConfigurationForm($form, $form_state); + } + + /** + * {@inheritdoc} + */ + public function calculateDependencies() { + return []; + } + +} diff --git a/web/modules/contrib/search_api_synonym/src/Export/ExportPluginInterface.php b/web/modules/contrib/search_api_synonym/src/Export/ExportPluginInterface.php new file mode 100644 index 000000000..8e685eb8c --- /dev/null +++ b/web/modules/contrib/search_api_synonym/src/Export/ExportPluginInterface.php @@ -0,0 +1,26 @@ +alterInfo('search_api_synonym_export_info'); + $this->setCacheBackend($cache_backend, 'search_api_synonym_export_info_plugins'); + } + + /** + * Set active plugin. + * + * @param string $plugin_id + * The active plugin. + */ + public function setPluginId($plugin_id) { + $this->pluginId = $plugin_id; + } + + /** + * Get active plugin. + * + * @return string + * The active plugin. + */ + public function getPluginId() { + return $this->pluginId; + } + + /** + * Set export options. + * + * @param array $export_options + * Array with export options + */ + public function setExportOptions(array $export_options) { + $this->exportOptions = $export_options; + } + + /** + * Get export options. + * + * @return array + * Array with export options + */ + public function getExportOptions() { + return $this->exportOptions; + } + + /** + * Get single export option. + * + * @param string $key + * Option key + * + * @return string + * Option value + */ + public function getExportOption($key) { + return isset($this->exportOptions[$key]) ? $this->exportOptions[$key] : ''; + } + + /** + * Gets a list of available export plugins. + * + * @return array + * An array with the plugin names as keys and the descriptions as values. + */ + public function getAvailableExportPlugins() { + // Use plugin system to get list of available export plugins. + $plugins = $this->getDefinitions(); + + $output = []; + foreach ($plugins as $id => $definition) { + $output[$id] = $definition; + } + + return $output; + } + + /** + * Validate that a specific export plugin exists. + * + * @param string $plugin + * The plugin machine name. + * + * @return boolean + * TRUE if the plugin exists. + */ + public function validatePlugin($plugin) { + if ($this->getDefinition($plugin, FALSE)) { + return TRUE; + } + else { + return FALSE; + } + } + + /** + * Execute the synonym export. + * + * @return mixed + * Export result + */ + public function executeExport() { + // Export plugin instance + $instance = $this->createInstance($this->getPluginId(), []); + + // Get synonyms data matching the options. + $synonyms = $this->getSynonymsData(); + + // We only export if full export or if their is new synonyms. + if (!($this->getExportOption('incremental') && empty($synonyms))) { + // Get data in the plugin instance format + $data = $instance->getFormattedSynonyms($synonyms); + + return $this->saveSynonymsFile($data); + } + else { + return FALSE; + } + } + + /** + * Get synonyms matching the export options. + * + * @return array + * Array with synonyms + */ + private function getSynonymsData() { + // Create the db query. + $query = \Drupal::database()->select('search_api_synonym', 's'); + $query->fields('s', ['sid', 'type', 'word', 'synonyms']); + $query->condition('s.status', 1); + $query->condition('s.langcode', $this->getExportOption('langcode')); + $query->orderBy('s.word'); + + // Add type condition if it is set and different from all. + $type = $this->getExportOption('type'); + if ($type && $type != 'all') { + $query->condition('s.type', $type); + } + + // Add filter condition if it is set and different from all. + $filter = $this->getExportOption('filter'); + if ($filter && $filter != 'all') { + switch ($filter) { + case 'nospace': + $query->condition('s.word', '% %', 'NOT LIKE'); + $query->condition('s.synonyms', '% %', 'NOT LIKE'); + break; + case 'onlyspace': + $group = $query->orConditionGroup() + ->condition('s.word', '% %', 'LIKE') + ->condition('s.synonyms', '% %', 'LIKE'); + $query = $query->condition($group); + break; + } + } + + // Add changed condition if incremental option is set. + if ($incremental = $this->getExportOption('incremental')) { + $query->condition('s.changed', $incremental, '>='); + } + + // Fetch the result. + return $query->execute()->fetchAllAssoc('sid'); + } + + /** + * Save synonyms data to a file. + * + * @param string $data + * String with the synonyms data being written to a file. + * + * @return string + * Return path to the saved synonyms file. + */ + private function saveSynonymsFile($data) { + if ($file = $this->getExportOption('file')) { + $filename = $file; + } + else { + $filename = $this->generateFileName(); + } + + // Create folder if it does not exist. + $folder = 'public://synonyms'; + file_prepare_directory($folder, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS); + + // Save file and return result. + $path = $folder . '/'. $filename; + return file_unmanaged_save_data($data, $path, FILE_EXISTS_REPLACE); + } + + /** + * Generate an export file name based on export options. + * + * @return string + * The generated file name. + */ + private function generateFileName() { + $options = $this->getExportOptions(); + + // Add benning of file name + $name[] = 'synonyms'; + + // Add language code as the first part of the file name. + $name[] = "lang_{$options['langcode']}"; + + // Add type option to file name + if (!empty($options['type'])) { + $name[] = "type_{$options['type']}"; + } + + // Add filter option to file name + if (!empty($options['filter'])) { + $name[] = "filter_{$options['filter']}"; + } + + // Implode the name parts. + return implode('__', $name) . '.txt'; + } + +} diff --git a/web/modules/contrib/search_api_synonym/src/Form/SynonymDeleteForm.php b/web/modules/contrib/search_api_synonym/src/Form/SynonymDeleteForm.php new file mode 100644 index 000000000..1d3b46a03 --- /dev/null +++ b/web/modules/contrib/search_api_synonym/src/Form/SynonymDeleteForm.php @@ -0,0 +1,14 @@ +entity; + $synonyms = $entity->getSynonymsFormatted(); + if (!empty($synonyms)) { + $entity->setSynonyms($synonyms); + } + + return parent::buildForm($form, $form_state); + } + + /** + * {@inheritdoc} + */ + public function save(array $form, FormStateInterface $form_state) { + // Trim whitespaces from synonyms and save back into the form state. + /* @var \Drupal\search_api_synonym\SynonymInterface $entity */ + $entity = $this->entity; + $trimmed = array_map('trim', explode(',', $entity->getSynonyms())); + $entity->setSynonyms(implode(',', $trimmed)); + + // Save synonym. + $status = parent::save($form, $form_state); + + switch ($status) { + case SAVED_NEW: + drupal_set_message($this->t('Created the %label Synonym.', [ + '%label' => $entity->label(), + ])); + break; + + default: + drupal_set_message($this->t('Saved the %label Synonym.', [ + '%label' => $entity->label(), + ])); + } + + $form_state->setRedirect($entity->toUrl('collection')->getRouteName()); + } + +} diff --git a/web/modules/contrib/search_api_synonym/src/Form/SynonymImportForm.php b/web/modules/contrib/search_api_synonym/src/Form/SynonymImportForm.php new file mode 100644 index 000000000..eefbffb9b --- /dev/null +++ b/web/modules/contrib/search_api_synonym/src/Form/SynonymImportForm.php @@ -0,0 +1,254 @@ +pluginManager = $manager; + + foreach ($manager->getAvailableImportPlugins() as $id => $definition) { + $this->availablePlugins[$id] = $manager->createInstance($id); + } + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('plugin.manager.search_api_synonym.import') + ); + } + + /** + * {@inheritdoc} + */ + public function getFormId() { + return 'search_api_synonym_import'; + } + + /** + * {@inheritdoc} + */ + public function buildForm(array $form, FormStateInterface $form_state) { + // File. + $form['file_upload'] = [ + '#type' => 'file', + '#title' => $this->t('File'), + '#description' => $this->t('Select the import file.'), + '#required' => FALSE, + ]; + + // Update + $form['update_existing'] = [ + '#type' => 'radios', + '#title' => $this->t('Update existing'), + '#description' => $this->t('What should happen with existing synonyms?'), + '#options' => [ + 'merge' => $this->t('Merge'), + 'overwrite' => $this->t('Overwrite') + ], + '#default_value' => 'merge', + '#required' => TRUE, + ]; + + // Synonym type. + $form['synonym_type'] = [ + '#type' => 'radios', + '#title' => $this->t('Type '), + '#description' => $this->t('Which synonym type should the imported data be saved as?'), + '#options' => [ + 'synonym' => $this->t('Synonym'), + 'spelling_error' => $this->t('Spelling error'), + 'mixed' => $this->t('Mixed - Controlled by information in the source file') + ], + '#default_value' => 'synonym', + '#required' => TRUE, + ]; + + $message = $this->t('Notice: the source file must contain information per synonym about the synonym type. All synonyms without type information will be skipped during import!'); + $message = Markup::create('
' . $message . '
'); + $form['synonym_type_notice'] = [ + '#type' => 'item', + '#markup' => $message, + '#states' => [ + 'visible' => [ + ':radio[name="synonym_type"]' => ['value' => 'mixed'], + ], + ], + ]; + + // Activate. + $form['status'] = [ + '#type' => 'checkbox', + '#title' => $this->t('Activate synonyms'), + '#description' => $this->t('Mark import synonyms as active. Only active synonyms will be exported to the configured search backend.'), + '#default_value' => TRUE, + '#required' => TRUE, + ]; + + // Language code. + $form['langcode'] = [ + '#type' => 'language_select', + '#title' => $this->t('Language'), + '#description' => $this->t('Which language should the imported data be saved as?'), + '#default_value' => \Drupal::languageManager()->getCurrentLanguage()->getId(), + ]; + + // Import plugin configuration. + $form['plugin'] = [ + '#type' => 'radios', + '#title' => $this->t('Import format'), + '#description' => $this->t('Choose the import format to use.'), + '#options' => [], + '#default_value' => key($this->availablePlugins), + '#required' => TRUE, + ]; + + $form['plugin_settings'] = [ + '#tree' => TRUE, + ]; + + foreach ($this->availablePlugins as $id => $instance) { + $definition = $instance->getPluginDefinition(); + $form['plugin']['#options'][$id] = $definition['label']; + $form['plugin_settings'][$id] = [ + '#type' => 'details', + '#title' => $this->t('@plugin plugin', ['@plugin' => $definition['label']]), + '#open' => TRUE, + '#tree' => TRUE, + '#states' => [ + 'visible' => [ + ':radio[name="plugin"]' => ['value' => $id], + ], + ], + ]; + $form['plugin_settings'][$id] += $instance->buildConfigurationForm([], $form_state); + } + + // Actions. + $form['actions']['submit'] = [ + '#type' => 'submit', + '#value' => $this->t('Import file'), + '#button_type' => 'primary', + ]; + + return $form; + } + + /** + * {@inheritdoc} + */ + public function validateForm(array &$form, FormStateInterface $form_state) { + parent::validateForm($form, $form_state); + + $values = $form_state->getValues(); + // Get plugin instance for active plugin. + $instance_active = $this->getPluginInstance($values['plugin']); + + // Validate the uploaded file. + $extensions = $instance_active->allowedExtensions(); + $validators = ['file_validate_extensions' => $extensions]; + + $file = file_save_upload('file_upload', $validators, FALSE, 0, FILE_EXISTS_RENAME); + if (isset($file)) { + if ($file) { + $form_state->setValue('file_upload', $file); + } + else { + $form_state->setErrorByName('file_upload', $this->t('The import file could not be uploaded.')); + } + } + + // Call the form validation handler for each of the plugins. + foreach ($this->availablePlugins as $instance) { + $instance->validateConfigurationForm($form, $form_state); + } + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, FormStateInterface $form_state) { + try { + // All values from the form. + $values = $form_state->getValues(); + + // Instance of active import plugin. + $plugin_id = $values['plugin']; + $instance = $this->getPluginInstance($plugin_id); + + // Parse file. + $data = $instance->parseFile($values['file_upload'], (array) $values['plugin_settings'][$plugin_id]); + + // Import data. + $importer = new Importer(); + $results = $importer->execute($data, $values); + + if (!empty($results['errors'])) { + $count = count($results['errors']); + $message = \Drupal::translation()->formatPlural($count, + '@count synonym failed import.', + '@count synonyms failed import.', + ['@count' => $count] + ); + drupal_set_message($message); + } + } + catch (ImportException $e) { + $this->logger('search_api_synonym')->error($this->t('Failed to import file due to "%error".', ['%error' => $e->getMessage()])); + drupal_set_message($this->t('Failed to import file due to "%error".', ['%error' => $e->getMessage()])); + } + } + + /** + * Returns an import plugin instance for a given plugin id. + * + * @param string $plugin_id + * The plugin_id for the plugin instance. + * + * @return \Drupal\search_api_synonym\Import\ImportPluginInterface + * An import plugin instance. + */ + public function getPluginInstance($plugin_id) { + return $this->pluginManager->createInstance($plugin_id, []); + } + +} diff --git a/web/modules/contrib/search_api_synonym/src/Form/SynonymSettingsForm.php b/web/modules/contrib/search_api_synonym/src/Form/SynonymSettingsForm.php new file mode 100644 index 000000000..54a2e6e66 --- /dev/null +++ b/web/modules/contrib/search_api_synonym/src/Form/SynonymSettingsForm.php @@ -0,0 +1,168 @@ +getAvailableExportPlugins() as $id => $definition) { + $this->availablePlugins[$id] = $manager->createInstance($id); + } + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('config.factory'), + $container->get('plugin.manager.search_api_synonym.export') + ); + } + + /** + * {@inheritdoc} + */ + public function getFormId() { + return 'search_api_synonym_settings'; + } + + /** + * {@inheritdoc} + */ + protected function getEditableConfigNames() { + return ['search_api_synonym.settings']; + } + + /** + * {@inheritdoc} + */ + public function buildForm(array $form, FormStateInterface $form_state) { + $config = $this->config($this->getEditableConfigNames()[0]); + + // Add cron settings + $cron = $config->get('cron'); + $form['cron'] = [ + '#title' => $this->t('Cron settings'), + '#type' => 'details', + '#open' => TRUE, + '#tree' => TRUE, + ]; + + $options = []; + foreach ($this->availablePlugins as $id => $source) { + $definition = $source->getPluginDefinition(); + $options[$id] = $definition['label']; + } + $form['cron']['plugin'] = [ + '#type' => 'select', + '#title' => $this->t('Synonym export plugin'), + '#description' => $this->t('Select the export plugin being used by cron.'), + '#default_value' => $cron['plugin'] ? $cron['plugin'] : '', + '#options' => $options, + ]; + + $options = [900, 1800, 3600, 10800, 21600, 43200, 86400, 604800]; + $form['cron']['interval'] = [ + '#type' => 'select', + '#title' => $this->t('Export synonyms every'), + '#description' => $this->t('How often should Drupal export synonyms?'), + '#default_value' => $cron['interval'] ? $cron['interval'] : 86400, + '#options' => array_map([\Drupal::service('date.formatter'), 'formatInterval'], array_combine($options, $options)), + ]; + + $form['cron']['type'] = [ + '#type' => 'radios', + '#title' => $this->t('Type'), + '#description' => $this->t('Which synonym type should be exported by cron?'), + '#default_value' => $cron['type'] ? $cron['type'] : 'all', + '#options' => [ + 'all' => $this->t('All'), + 'synonym' => $this->t('Synonyms'), + 'spelling_error' => $this->t('Spelling errors') + ], + ]; + + $form['cron']['filter'] = [ + '#type' => 'radios', + '#title' => $this->t('Filter'), + '#description' => $this->t('Which filters should be used when selecting synonyms.'), + '#default_value' => $cron['filter'] ? $cron['filter'] : 'none', + '#options' => [ + 'none' => $this->t('No filter'), + 'nospace' => $this->t('Synonyms without spaces in the word'), + 'onlyspace' => $this->t('Synonyms with spaces in the word') + ], + ]; + + $form['cron']['separate_files'] = [ + '#type' => 'checkbox', + '#title' => $this->t('Separate files'), + '#description' => $this->t('Export synonyms with and without spaces into separate files.'), + '#default_value' => $cron['separate_files'] ? $cron['separate_files'] : '', + '#states' => [ + 'visible' => [ + ':radio[name="cron[filter]"]' => ['value' => 'none'], + ], + ], + ]; + + $form['cron']['export_if_changed'] = [ + '#type' => 'checkbox', + '#title' => $this->t('Only export if changes'), + '#description' => $this->t('Only export synonyms if their is either new or changed synonyms since last export.'), + '#default_value' => $cron['export_if_changed'] ? $cron['export_if_changed'] : FALSE, + ]; + + return parent::buildForm($form, $form_state); + } + + /** + * {@inheritdoc} + */ + public function validateForm(array &$form, FormStateInterface $form_state) { + parent::validateForm($form, $form_state); + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, FormStateInterface $form_state) { + $this->config($this->getEditableConfigNames()[0]) + ->set('cron', $form_state->getValue('cron')) + ->save(); + + parent::submitForm($form, $form_state); + } + +} diff --git a/web/modules/contrib/search_api_synonym/src/Import/ImportException.php b/web/modules/contrib/search_api_synonym/src/Import/ImportException.php new file mode 100644 index 000000000..98da1923a --- /dev/null +++ b/web/modules/contrib/search_api_synonym/src/Import/ImportException.php @@ -0,0 +1,12 @@ +configFactory = $config_factory; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { + return new static( + $configuration, $plugin_id, $plugin_definition, $container->get('config.factory') + ); + } + + /** + * {@inheritdoc} + */ + public function parseFile(File $file, array $settings = []) { + return []; + } + + /** + * {@inheritdoc} + */ + public function allowedExtensions() { + return []; + } + + /** + * {@inheritdoc} + */ + public function getConfiguration() { + return $this->configuration; + } + + /** + * {@inheritdoc} + */ + public function setConfiguration(array $configuration) { + $this->configuration += $configuration; + } + + /** + * {@inheritdoc} + */ + public function defaultConfiguration() { + return []; + } + + /** + * {@inheritdoc} + */ + public function buildConfigurationForm(array $form, FormStateInterface $form_state) { + return $form; + } + + /** + * {@inheritdoc} + */ + public function validateConfigurationForm(array &$form, FormStateInterface $form_state) { + $values = $form_state->getValues(); + } + + /** + * {@inheritdoc} + */ + public function submitConfigurationForm(array &$form, FormStateInterface $form_state) { + parent::submitConfigurationForm($form, $form_state); + } + + /** + * {@inheritdoc} + */ + public function calculateDependencies() { + return []; + } + +} diff --git a/web/modules/contrib/search_api_synonym/src/Import/ImportPluginInterface.php b/web/modules/contrib/search_api_synonym/src/Import/ImportPluginInterface.php new file mode 100644 index 000000000..4f7522d16 --- /dev/null +++ b/web/modules/contrib/search_api_synonym/src/Import/ImportPluginInterface.php @@ -0,0 +1,61 @@ +alterInfo('search_api_synonym_import_info'); + $this->setCacheBackend($cache_backend, 'search_api_synonym_import_info_plugins'); + } + + /** + * Set active plugin + * + * @param string $plugin_id + * The active plugin. + */ + public function setPluginId($plugin_id) { + $this->pluginId = $plugin_id; + } + + /** + * Get active plugin + * + * @return string + * The active plugin. + */ + public function getPluginId() { + return $this->pluginId; + } + + /** + * Gets a list of available import plugins. + * + * @return array + * An array with the plugin names as keys and the descriptions as values. + */ + public function getAvailableImportPlugins() { + // Use plugin system to get list of available import plugins. + $plugins = $this->getDefinitions(); + + $output = []; + foreach ($plugins as $id => $definition) { + $output[$id] = $definition; + } + + return $output; + } + + /** + * Validate that a specific import plugin exists. + * + * @param string $plugin + * The plugin machine name. + * + * @return boolean + * TRUE if the plugin exists. + */ + public function validatePlugin($plugin) { + if ($this->getDefinition($plugin, FALSE)) { + return TRUE; + } + else { + return FALSE; + } + } + +} diff --git a/web/modules/contrib/search_api_synonym/src/Import/Importer.php b/web/modules/contrib/search_api_synonym/src/Import/Importer.php new file mode 100644 index 000000000..5defcc2ce --- /dev/null +++ b/web/modules/contrib/search_api_synonym/src/Import/Importer.php @@ -0,0 +1,275 @@ +entityManager = \Drupal::service('entity.manager'); + $this->entityRepository = \Drupal::service('entity.repository'); + $this->moduleHandler = \Drupal::service('module_handler'); + $this->connection = \Drupal::service('database'); + } + + /** + * Execute the import of an array with synonyms. + * + * @param array $items + * Raw synonyms data. + * @param array $settings + * Import settings. + * + * @return array + * Array with info about the result. + */ + public function execute(array $items, array $settings) { + // Prepare items. + $items = $this->prepare($items, $settings); + + // Create synonyms. + $results = $this->createSynonyms($items, $settings); + + return $results; + } + + /** + * Prepare and validate the data. + * + * @param array $items + * Raw synonyms data. + * @param array $settings + * Import settings. + * + * @return array + * Array with prepared data. + */ + private function prepare(array $items, array $settings) { + $prepared = []; + + foreach ($items as $item) { + // Decide which synonym type to use. + if ($settings['synonym_type'] != 'mixed') { + $type = $settings['synonym_type']; + } + else { + $type = !empty($item['type']) ? $item['type'] : 'empty'; + } + + $prepared[$type][$item['word']][] = $item['synonym']; + } + + return $prepared; + } + + /** + * Create synonyms. + * + * @param array $items + * Raw synonyms data. + * @param array $settings + * Import settings. + * + * @return array + * Array with info about the result. + */ + public function createSynonyms(array $items, array $settings) { + $context = []; + + // Import with batch. + $operations = []; + + foreach ($items as $type => $item) { + // Continue with next item if type is not valid. + if ($type == 'empty') { + $context['results']['errors'][] = [ + 'word' => key($item), + 'synonyms' => current($item) + ]; + continue; + } + + // Add each item to the batch. + foreach ($item as $word => $synonyms) { + $operations[] = [ + '\Drupal\search_api_synonym\Import\Importer::createSynonym', + [$word, $synonyms, $type, $settings] + ]; + } + } + + $batch = [ + 'title' => t('Import synonyms...'), + 'operations' => $operations, + 'finished' => '\Drupal\search_api_synonym\Import\Importer::createSynonymBatchFinishedCallback', + ]; + batch_set($batch); + + return isset($context['results']) ? $context['results'] : NULL; + } + + /** + * Create / update a synonym. + * + * @param string $word + * The source word we add the synonym for. + * @param array $synonyms + * Simple array with synonyms. + * @param string $type + * The synonym type. + * @param array $settings + * Import settings. + * @param array $context + * Batch context - also used for storing results in non batch operations. + */ + public static function createSynonym($word, array $synonyms, $type, array $settings, array &$context) { + $request_time = \Drupal::time()->getRequestTime(); + + // Check if we have an existing synonym entity we should update. + $sid = Importer::lookUpSynonym($word, $type, $settings['langcode']); + + // Trim spaces from synonyms. + $synonyms = array_map('trim', $synonyms); + + // Load and update existing synonym entity. + if ($sid) { + $entity = Synonym::load($sid); + + // Update method = Merge. + if ($settings['update_existing'] == 'merge') { + $existing = $entity->getSynonyms(); + $existing = array_map('trim', explode(',', $existing)); + $synonyms = array_unique(array_merge($existing, $synonyms)); + } + + $synonyms_str = implode(',', $synonyms); + $entity->setSynonyms($synonyms_str); + } + // Create new entity. + else { + $entity = Synonym::create([ + 'langcode' => $settings['langcode'], + ]); + $uid = \Drupal::currentUser()->id(); + $entity->setOwnerId($uid); + $entity->setCreatedTime($request_time); + $entity->setType($type); + $entity->setWord($word); + $synonyms_str = implode(',', $synonyms); + $entity->setSynonyms($synonyms_str); + } + + $entity->setChangedTime($request_time); + $entity->setActive($settings['status']); + + $entity->save(); + + if ($sid = $entity->id()) { + $context['results']['success'][] = $sid; + } + else { + $context['results']['errors'][] = [ + 'word' => $word, + 'synonyms' => $synonyms + ]; + } + } + + /** + * Batch finished callback. + * + * @param bool $success + * Was the batch successful or not? + * @param array $result + * Array with the result of the import. + * @param array $operations + * Batch operations. + * @param string $elapsed + * Formatted string with the time batch operation was running. + */ + public static function createSynonymBatchFinishedCallback($success, $result, $operations, $elapsed) { + if ($success) { + // Set message before returning to form. + if (!empty($result['success'])) { + $count = count($result['success']); + $message = \Drupal::translation()->formatPlural($count, + '@count synonym was successfully imported.', + '@count synonyms was successfully imported.', + ['@count' => $count] + ); + drupal_set_message($message); + } + } + } + + /** + * Look up synonym. + * + * @param string $word + * The source word we add the synonym for. + * @param string $type + * Synonym type. + * @param string $langcode + * Language code. + * + * @return int + * Entity id for the found synonym. + */ + public static function lookUpSynonym($word, $type, $langcode) { + $query = \Drupal::database()->select('search_api_synonym', 's'); + $query->fields('s', ['sid']); + $query->condition('s.type', $type); + $query->condition('s.word', $word, 'LIKE'); + $query->condition('s.langcode', $langcode); + $query->range(0, 1); + return (int) $query->execute()->fetchField(0); + } + +} diff --git a/web/modules/contrib/search_api_synonym/src/Plugin/search_api_synonym/export/Solr.php b/web/modules/contrib/search_api_synonym/src/Plugin/search_api_synonym/export/Solr.php new file mode 100644 index 000000000..bf9ff4ed0 --- /dev/null +++ b/web/modules/contrib/search_api_synonym/src/Plugin/search_api_synonym/export/Solr.php @@ -0,0 +1,69 @@ +generateLine($synonym->word, $synonym->synonyms, $synonym->type); + } + + return implode("\n", $lines); + } + + /** + * Generate a single synonyms line for the export file. + * + * @param string $word + * The main word. + * + * @param string $synonyms + * The comma separated string with synonyms. + * + * @param string $type + * Synonym (synonym) og Spelling error (spelling_error) + * + * @return string + * Return the single line with synonyms and the corresponding word. + */ + private function generateLine($word, $synonyms, $type) { + $line = ''; + + switch ($type) { + case 'synonym': + // We force using of equivalent mappings for type = synonym. + $line = "{$word}, {$synonyms}"; + break; + case 'spelling_error': + $line = "{$word} => {$synonyms}"; + break; + } + return $line; + } + +} diff --git a/web/modules/contrib/search_api_synonym/src/Plugin/search_api_synonym/import/CSV.php b/web/modules/contrib/search_api_synonym/src/Plugin/search_api_synonym/import/CSV.php new file mode 100644 index 000000000..31da97b2e --- /dev/null +++ b/web/modules/contrib/search_api_synonym/src/Plugin/search_api_synonym/import/CSV.php @@ -0,0 +1,110 @@ +getFileUri(), 'r')) !== FALSE) { + while (($row = fgetcsv($handle, 1000, $delimiter, $enclosure)) !== FALSE) { + if ($header_row && $i++ == 1) { + continue; + } + + if (!empty($row[0]) && !empty($row[1])) { + $data[] = [ + 'word' => $row[0], + 'synonym' => $row['1'], + 'type' => !empty($row['2']) ? $row['2'] : '' + ]; + } + } + fclose($handle); + } + + return $data; + } + + /** + * {@inheritdoc} + */ + public function buildConfigurationForm(array $form, FormStateInterface $form_state) { + $example_url = 'internal:' . base_path() . drupal_get_path('module', 'search_api_synonym') . '/examples/example.csv'; + $form['template'] = [ + '#type' => 'item', + '#title' => $this->t('Example'), + '#markup' => Link::fromTextAndUrl(t('Download example file'), Url::fromUri($example_url))->toString() + ]; + $form['delimiter'] = [ + '#type' => 'select', + '#title' => t('Delimiter'), + '#description' => t('Field delimiter character used in the import file.'), + '#options' => [ + ';' => $this->t('Semicolon'), + ',' => $this->t('Comma'), + '\t' => $this->t('Tab'), + '|' => $this->t('Pipe'), + ], + '#default_value' => ';', + '#required' => TRUE + ]; + $form['enclosure'] = [ + '#type' => 'select', + '#title' => t('Text qualifier'), + '#description' => t('Field enclosure character used in import file.'), + '#options' => [ + '"' => '"', + "'" => "'", + '' => $this->t('None'), + ], + '#default_value' => '"' + ]; + $form['header_row'] = [ + '#type' => 'checkbox', + '#title' => $this->t('Header row'), + '#description' => $this->t('Does the file contain a header row that should be skipped in the import?'), + '#default_value' => FALSE, + ]; + return $form; + } + + /** + * {@inheritdoc} + */ + public function validateConfigurationForm(array &$form, FormStateInterface $form_state) { + $values = $form_state->getValues(); + } + + /** + * {@inheritdoc} + */ + public function allowedExtensions() { + return ['csv txt']; + } + +} diff --git a/web/modules/contrib/search_api_synonym/src/Plugin/search_api_synonym/import/JSON.php b/web/modules/contrib/search_api_synonym/src/Plugin/search_api_synonym/import/JSON.php new file mode 100644 index 000000000..58901d0ee --- /dev/null +++ b/web/modules/contrib/search_api_synonym/src/Plugin/search_api_synonym/import/JSON.php @@ -0,0 +1,72 @@ +getFileUri()); + + if ($items = SerializationJSON::decode($json)) { + foreach ($items as $item) { + if (!empty($item['word']) && !empty($item['synonym'])) { + $data[] = [ + 'word' => $item['word'], + 'synonym' => $item['synonym'], + 'type' => !empty($item['type']) ? $item['type'] : '' + ]; + } + } + } + + return $data; + } + + /** + * {@inheritdoc} + */ + public function buildConfigurationForm(array $form, FormStateInterface $form_state) { + $example_url = 'internal:' . base_path() . drupal_get_path('module', 'search_api_synonym') . '/examples/example.json'; + $form['template'] = [ + '#type' => 'item', + '#title' => $this->t('Example'), + '#markup' => Link::fromTextAndUrl(t('Download example file'), Url::fromUri($example_url))->toString() + ]; + return $form; + } + + /** + * {@inheritdoc} + */ + public function validateConfigurationForm(array &$form, FormStateInterface $form_state) { + } + + /** + * {@inheritdoc} + */ + public function allowedExtensions() { + return ['json']; + } + +} diff --git a/web/modules/contrib/search_api_synonym/src/Plugin/search_api_synonym/import/Solr.php b/web/modules/contrib/search_api_synonym/src/Plugin/search_api_synonym/import/Solr.php new file mode 100644 index 000000000..13a98524d --- /dev/null +++ b/web/modules/contrib/search_api_synonym/src/Plugin/search_api_synonym/import/Solr.php @@ -0,0 +1,91 @@ +getFileUri()); + + if (is_array($rows)) { + foreach ($rows as $row) { + $row = trim($row); + + // Skip comment lines + if (empty($row) || substr($row, 0, 1) == '#') { + continue; + } + + $parts = explode('=>', $row); + + // Spelling error. + if (count($parts) == 2) { + $data[] = [ + 'word' => trim($parts[0]), + 'synonym' => trim($parts['1']), + 'type' => 'spelling_error' + ]; + } + // Synonym. + else { + $data[] = [ + 'word' => trim(substr($row, 0, strpos($row, ','))), + 'synonym' => trim(substr($row, strpos($row, ',') + 1)), + 'type' => 'synonym' + ]; + } + } + } + + return $data; + } + + /** + * {@inheritdoc} + */ + public function buildConfigurationForm(array $form, FormStateInterface $form_state) { + $example_url = 'internal:' . base_path() . drupal_get_path('module', 'search_api_synonym') . '/examples/solr_synonyms.txt'; + $form['template'] = [ + '#type' => 'item', + '#title' => $this->t('Example'), + '#markup' => Link::fromTextAndUrl(t('Download example file'), Url::fromUri($example_url))->toString() + ]; + return $form; + } + + /** + * {@inheritdoc} + */ + public function validateConfigurationForm(array &$form, FormStateInterface $form_state) { + } + + /** + * {@inheritdoc} + */ + public function allowedExtensions() { + return ['txt']; + } + +} diff --git a/web/modules/contrib/search_api_synonym/src/SynonymInterface.php b/web/modules/contrib/search_api_synonym/src/SynonymInterface.php new file mode 100644 index 000000000..d673344c2 --- /dev/null +++ b/web/modules/contrib/search_api_synonym/src/SynonymInterface.php @@ -0,0 +1,125 @@ +dateFormatter = $date_formatter; + } + + /** + * {@inheritdoc} + */ + public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) { + return new static( + $entity_type, + $container->get('entity.manager')->getStorage($entity_type->id()), + $container->get('date.formatter') + ); + } + + /** + * {@inheritdoc} + */ + public function buildHeader() { + $header = [ + 'word' => $this->t('Word'), + 'synonyms' => $this->t('Synonyms'), + 'author' => [ + 'data' => $this->t('Author'), + 'class' => [RESPONSIVE_PRIORITY_LOW], + ], + 'status' => [ + 'data' => $this->t('Status'), + 'class' => [RESPONSIVE_PRIORITY_LOW], + ], + 'changed' => [ + 'data' => $this->t('Updated'), + 'class' => [RESPONSIVE_PRIORITY_LOW], + ], + ]; + if (\Drupal::languageManager()->isMultilingual()) { + $header['language_name'] = [ + 'data' => $this->t('Language'), + 'class' => [RESPONSIVE_PRIORITY_LOW], + ]; + } + + return $header + parent::buildHeader(); + } + + /** + * {@inheritdoc} + */ + public function buildRow(EntityInterface $entity) { + $langcode = $entity->language()->getId(); + + /* @var $entity \Drupal\search_api_synonym\Entity\Synonym */ + $row['word'] = $this->buildEditLink($entity->label(), $entity); + $row['synonyms'] = $this->buildEditLink($entity->getSynonyms(), $entity); + $row['author']['data'] = [ + '#theme' => 'username', + '#account' => $entity->getOwner(), + ]; + $row['status'] = $entity->isActive() ? $this->t('active') : $this->t('inactive'); + $row['changed'] = $this->dateFormatter->format($entity->getChangedTime(), 'short'); + $language_manager = \Drupal::languageManager(); + if ($language_manager->isMultilingual()) { + $row['language_name'] = $language_manager->getLanguageName($langcode); + } + + return $row + parent::buildRow($entity); + } + + /** + * Build the edit link object. + * + * @param string $label + * The label used in the link + * + * @param \Drupal\search_api_synonym\Entity\Synonym $entity + * The synonym entity object. + * + * @return \Drupal\Core\Link + * The build link object. + */ + private function buildEditLink($label, $entity) { + return new Link( + $label, + new Url( + 'entity.search_api_synonym.edit_form', [ + 'search_api_synonym' => $entity->id(), + ] + ) + ); + } + +} diff --git a/web/modules/contrib/search_api_synonym/src/SynonymViewsData.php b/web/modules/contrib/search_api_synonym/src/SynonymViewsData.php new file mode 100644 index 000000000..f33fc2705 --- /dev/null +++ b/web/modules/contrib/search_api_synonym/src/SynonymViewsData.php @@ -0,0 +1,162 @@ +t('Synonyms managed by Search API Synonyms module.'); + $data['search_api_synonym_field_data']['table']['base']['defaults']['field'] = 'word'; + $data['search_api_synonym_field_data']['table']['wizard_id'] = 'synonym'; + + $data['search_api_synonym_field_data']['sid']['title'] = $this->t('Synonym ID'); + $data['search_api_synonym_field_data']['sid']['help'] = $this->t('The unique id of the synonym entity.'); + + $data['search_api_synonym_field_data']['word']['title'] = $this->t('Word'); + $data['search_api_synonym_field_data']['word']['help'] = $this->t('The word we are defining synonyms for.'); + + $data['search_api_synonym_field_data']['synonyms']['title'] = $this->t('Synonyms'); + $data['search_api_synonym_field_data']['synonyms']['help'] = $this->t('The synonyms to the word.'); + + $data['search_api_synonym_field_data']['type']['title'] = $this->t('Type'); + $data['search_api_synonym_field_data']['type']['help'] = $this->t('The type of synonym. Either synonym or spelling error.'); + + $data['search_api_synonym_field_data']['created']['title'] = $this->t('Create date'); + $data['search_api_synonym_field_data']['created']['help'] = $this->t('Date and time of when the synonym was created.'); + + $data['search_api_synonym_field_data']['created_fulldata'] = [ + 'title' => $this->t('Created date'), + 'help' => $this->t('Date in the form of CCYYMMDD.'), + 'argument' => [ + 'field' => 'created', + 'id' => 'date_fulldate', + ], + ]; + + $data['search_api_synonym_field_data']['created_year_month'] = [ + 'title' => $this->t('Created year + month'), + 'help' => $this->t('Date in the form of YYYYMM.'), + 'argument' => [ + 'field' => 'created', + 'id' => 'date_year_month', + ], + ]; + + $data['search_api_synonym_field_data']['created_year'] = [ + 'title' => $this->t('Created year'), + 'help' => $this->t('Date in the form of YYYY.'), + 'argument' => [ + 'field' => 'created', + 'id' => 'date_year', + ], + ]; + + $data['search_api_synonym_field_data']['created_month'] = [ + 'title' => $this->t('Created month'), + 'help' => $this->t('Date in the form of MM (01 - 12).'), + 'argument' => [ + 'field' => 'created', + 'id' => 'date_month', + ], + ]; + + $data['search_api_synonym_field_data']['created_day'] = [ + 'title' => $this->t('Created day'), + 'help' => $this->t('Date in the form of DD (01 - 31).'), + 'argument' => [ + 'field' => 'created', + 'id' => 'date_day', + ], + ]; + + $data['search_api_synonym_field_data']['created_week'] = [ + 'title' => $this->t('Created week'), + 'help' => $this->t('Date in the form of WW (01 - 53).'), + 'argument' => [ + 'field' => 'created', + 'id' => 'date_week', + ], + ]; + + $data['search_api_synonym_field_data']['changed']['title'] = $this->t('Updated date'); + $data['search_api_synonym_field_data']['changed']['help'] = $this->t('Date and time of when the synonym was last updated.'); + + $data['search_api_synonym_field_data']['changed_fulldata'] = [ + 'title' => $this->t('Changed date'), + 'help' => $this->t('Date in the form of CCYYMMDD.'), + 'argument' => [ + 'field' => 'changed', + 'id' => 'date_fulldate', + ], + ]; + + $data['search_api_synonym_field_data']['changed_year_month'] = [ + 'title' => $this->t('Changed year + month'), + 'help' => $this->t('Date in the form of YYYYMM.'), + 'argument' => [ + 'field' => 'changed', + 'id' => 'date_year_month', + ], + ]; + + $data['search_api_synonym_field_data']['changed_year'] = [ + 'title' => $this->t('Changed year'), + 'help' => $this->t('Date in the form of YYYY.'), + 'argument' => [ + 'field' => 'changed', + 'id' => 'date_year', + ], + ]; + + $data['search_api_synonym_field_data']['changed_month'] = [ + 'title' => $this->t('Changed month'), + 'help' => $this->t('Date in the form of MM (01 - 12).'), + 'argument' => [ + 'field' => 'changed', + 'id' => 'date_month', + ], + ]; + + $data['search_api_synonym_field_data']['changed_day'] = [ + 'title' => $this->t('Changed day'), + 'help' => $this->t('Date in the form of DD (01 - 31).'), + 'argument' => [ + 'field' => 'changed', + 'id' => 'date_day', + ], + ]; + + $data['search_api_synonym_field_data']['changed_week'] = [ + 'title' => $this->t('Changed week'), + 'help' => $this->t('Date in the form of WW (01 - 53).'), + 'argument' => [ + 'field' => 'changed', + 'id' => 'date_week', + ], + ]; + + $data['search_api_synonym_field_data']['status']['title'] = $this->t('Active status'); + $data['search_api_synonym_field_data']['status']['help'] = $this->t('Whether the synonym is active and used by search engines or is it no active.'); + $data['search_api_synonym_field_data']['status']['filter']['label'] = $this->t('Active synonym status'); + $data['search_api_synonym_field_data']['status']['filter']['type'] = 'yes-no'; + + $data['search_api_synonym_field_data']['uid']['title'] = $this->t('Author uid'); + $data['search_api_synonym_field_data']['uid']['help'] = $this->t('If you need more fields than the uid add the synonym: author relationship'); + $data['search_api_synonym_field_data']['uid']['relationship']['title'] = $this->t('Author'); + $data['search_api_synonym_field_data']['uid']['relationship']['help'] = $this->t('The User ID of the synonym\'s author.'); + $data['search_api_synonym_field_data']['uid']['relationship']['label'] = $this->t('author'); + + return $data; + } + +}