Pathauto and dependencies
This commit is contained in:
parent
4b1a293d57
commit
24ffcb956b
339
web/modules/contrib/ctools/LICENSE.txt
Normal file
339
web/modules/contrib/ctools/LICENSE.txt
Normal file
|
@ -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.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
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.
|
||||
|
||||
<signature of Ty Coon>, 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.
|
40
web/modules/contrib/ctools/composer.json
Normal file
40
web/modules/contrib/ctools/composer.json
Normal file
|
@ -0,0 +1,40 @@
|
|||
{
|
||||
"name": "drupal/ctools",
|
||||
"description": "Provides a number of utility and helper APIs for Drupal developers and site builders.",
|
||||
"type": "drupal-module",
|
||||
"license": "GPL-2.0+",
|
||||
"minimum-stability": "dev",
|
||||
"homepage": "https://www.drupal.org/project/ctools",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Kris Vanderwater (EclipseGc)",
|
||||
"homepage": "https://www.drupal.org/u/eclipsegc",
|
||||
"role": "Maintainer"
|
||||
},
|
||||
{
|
||||
"name": "Jakob Perry (japerry)",
|
||||
"homepage": "https://www.drupal.org/u/japerry",
|
||||
"role": "Maintainer"
|
||||
},
|
||||
{
|
||||
"name": "Tim Plunkett (tim.plunkett)",
|
||||
"homepage": "https://www.drupal.org/u/timplunkett",
|
||||
"role": "Maintainer"
|
||||
},
|
||||
{
|
||||
"name": "James Gilliland (neclimdul)",
|
||||
"homepage": "https://www.drupal.org/u/neclimdul",
|
||||
"role": "Maintainer"
|
||||
},
|
||||
{
|
||||
"name": "Daniel Wehner (dawehner)",
|
||||
"homepage": "https://www.drupal.org/u/dawehner",
|
||||
"role": "Maintainer"
|
||||
}
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://www.drupal.org/project/issues/ctools",
|
||||
"source": "http://cgit.drupalcode.org/ctools"
|
||||
},
|
||||
"require": {}
|
||||
}
|
63
web/modules/contrib/ctools/config/schema/ctools.schema.yml
Normal file
63
web/modules/contrib/ctools/config/schema/ctools.schema.yml
Normal file
|
@ -0,0 +1,63 @@
|
|||
ctools.context:
|
||||
type: mapping
|
||||
label: Context
|
||||
mapping:
|
||||
label:
|
||||
type: label
|
||||
label: 'Label of the context'
|
||||
type:
|
||||
type: string
|
||||
label: 'Context type'
|
||||
description:
|
||||
type: string
|
||||
label: 'Description of the context'
|
||||
value:
|
||||
type: string
|
||||
label: 'Context value'
|
||||
|
||||
ctools.relationship:
|
||||
type: mapping
|
||||
label: 'Relationship'
|
||||
mapping:
|
||||
id:
|
||||
type: string
|
||||
label: 'ID'
|
||||
label:
|
||||
type: label
|
||||
label: 'Label'
|
||||
|
||||
condition.plugin.entity_bundle:*:
|
||||
type: condition.plugin
|
||||
mapping:
|
||||
bundles:
|
||||
type: sequence
|
||||
sequence:
|
||||
type: string
|
||||
|
||||
ctools.block_plugin.*:
|
||||
type: block.settings.[id]
|
||||
mapping:
|
||||
region:
|
||||
type: string
|
||||
label: 'Region'
|
||||
weight:
|
||||
type: integer
|
||||
label: 'Weight'
|
||||
uuid:
|
||||
type: string
|
||||
label: 'UUID'
|
||||
context_mapping:
|
||||
type: sequence
|
||||
label: 'Context assignments'
|
||||
sequence:
|
||||
- type: string
|
||||
|
||||
ctools.block_display_variant:
|
||||
type: display_variant.plugin
|
||||
label: 'Block display variant'
|
||||
mapping:
|
||||
blocks:
|
||||
type: sequence
|
||||
label: 'Blocks'
|
||||
sequence:
|
||||
- type: ctools.block_plugin.[id]
|
11
web/modules/contrib/ctools/ctools.info.yml
Normal file
11
web/modules/contrib/ctools/ctools.info.yml
Normal file
|
@ -0,0 +1,11 @@
|
|||
name: Chaos tools
|
||||
type: module
|
||||
description: 'Provides a number of utility and helper APIs for Drupal developers and site builders.'
|
||||
package: Chaos tool suite
|
||||
# core: 8.x
|
||||
|
||||
# Information added by Drupal.org packaging script on 2017-04-28
|
||||
version: '8.x-3.0'
|
||||
core: '8.x'
|
||||
project: 'ctools'
|
||||
datestamp: 1493401747
|
64
web/modules/contrib/ctools/ctools.module
Normal file
64
web/modules/contrib/ctools/ctools.module
Normal file
|
@ -0,0 +1,64 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Implements hook_theme().
|
||||
*/
|
||||
function ctools_theme($existing, $type, $theme, $path) {
|
||||
return [
|
||||
'ctools_wizard_trail' => [
|
||||
'variables' => [
|
||||
'wizard' => NULL,
|
||||
'cached_values' => [],
|
||||
'trail' => [],
|
||||
'divider' => ' » ',
|
||||
'step' => NULL,
|
||||
],
|
||||
],
|
||||
'ctools_wizard_trail_links' => [
|
||||
'variables' => [
|
||||
'wizard' => NULL,
|
||||
'cached_values' => [],
|
||||
'trail' => [],
|
||||
'divider' => ' » ',
|
||||
'step' => NULL,
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
function template_preprocess_ctools_wizard_trail(&$variables) {
|
||||
/** @var $wizard \Drupal\ctools\Wizard\FormWizardInterface|\Drupal\ctools\Wizard\EntityFormWizardInterface */
|
||||
$wizard = $variables['wizard'];
|
||||
$cached_values = $variables['cached_values'];
|
||||
$trail = $variables['trail'];
|
||||
$variables['step'] = $wizard->getStep($cached_values);
|
||||
foreach ($wizard->getOperations($cached_values) as $step => $operation) {
|
||||
$trail[$step] = !empty($operation['title']) ? $operation['title'] : '';
|
||||
}
|
||||
$variables['trail'] = $trail;
|
||||
}
|
||||
|
||||
function template_preprocess_ctools_wizard_trail_links(&$variables) {
|
||||
/** @var $wizard \Drupal\ctools\Wizard\FormWizardInterface|\Drupal\ctools\Wizard\EntityFormWizardInterface */
|
||||
$wizard = $variables['wizard'];
|
||||
$cached_values = $variables['cached_values'];
|
||||
$trail = $variables['trail'];
|
||||
$variables['step'] = $wizard->getStep($cached_values);
|
||||
foreach ($wizard->getOperations($cached_values) as $step => $operation) {
|
||||
$parameters = $wizard->getNextParameters($cached_values);
|
||||
// Override step to be the step we want.
|
||||
$parameters['step'] = $step;
|
||||
$trail[$step] = [
|
||||
'title' => !empty($operation['title']) ? $operation['title'] : '',
|
||||
'url' => new \Drupal\Core\Url($wizard->getRouteName(), $parameters),
|
||||
];
|
||||
}
|
||||
$variables['trail'] = $trail;
|
||||
}
|
||||
|
||||
function ctools_condition_info_alter(&$definitions) {
|
||||
// If the node_type's class is unaltered, use a custom ctools implementation.
|
||||
if (isset($definitions['node_type']) && $definitions['node_type']['class'] == 'Drupal\node\Plugin\Condition\NodeType') {
|
||||
$definitions['node_type']['class'] = 'Drupal\ctools\Plugin\Condition\NodeType';
|
||||
}
|
||||
}
|
38
web/modules/contrib/ctools/ctools.services.yml
Normal file
38
web/modules/contrib/ctools/ctools.services.yml
Normal file
|
@ -0,0 +1,38 @@
|
|||
services:
|
||||
ctools.wizard.form:
|
||||
class: Drupal\ctools\Controller\WizardFormController
|
||||
arguments: ['@controller_resolver', '@form_builder', '@ctools.wizard.factory']
|
||||
ctools.wizard.entity.form:
|
||||
class: Drupal\ctools\Controller\WizardEntityFormController
|
||||
arguments: ['@controller_resolver', '@form_builder', '@ctools.wizard.factory', '@entity.manager']
|
||||
ctools.wizard_enhancer:
|
||||
class: Drupal\ctools\Routing\Enhancer\WizardEnhancer
|
||||
tags:
|
||||
- { name: route_enhancer }
|
||||
ctools.wizard.factory:
|
||||
class: Drupal\ctools\Wizard\WizardFactory
|
||||
arguments: ['@form_builder', '@event_dispatcher']
|
||||
ctools.paramconverter.tempstore:
|
||||
class: Drupal\ctools\ParamConverter\TempstoreConverter
|
||||
arguments: ['@user.shared_tempstore', '@entity_type.manager']
|
||||
tags:
|
||||
- { name: paramconverter }
|
||||
ctools.typed_data.resolver:
|
||||
class: Drupal\ctools\TypedDataResolver
|
||||
arguments: ['@typed_data_manager', '@string_translation']
|
||||
ctools.access:
|
||||
class: Drupal\ctools\Access\TempstoreAccess
|
||||
arguments: ['@user.shared_tempstore']
|
||||
tags:
|
||||
- { name: access_check, applies_to: _ctools_access }
|
||||
plugin.manager.ctools.relationship:
|
||||
class: Drupal\ctools\Plugin\RelationshipManager
|
||||
parent: default_plugin_manager
|
||||
ctools.context_mapper:
|
||||
class: Drupal\ctools\ContextMapper
|
||||
arguments: ['@entity.repository']
|
||||
ctools.serializable.tempstore.factory:
|
||||
class: Drupal\ctools\SerializableTempstoreFactory
|
||||
arguments: ['@keyvalue.expirable', '@lock', '@request_stack', '%user.tempstore.expire%']
|
||||
tags:
|
||||
- { name: backend_overridable }
|
|
@ -0,0 +1,28 @@
|
|||
block.settings.entity_field:*:*:
|
||||
type: block_settings
|
||||
label: 'Entity field block'
|
||||
mapping:
|
||||
formatter:
|
||||
type: mapping
|
||||
label: 'Field formatter'
|
||||
mapping:
|
||||
type:
|
||||
type: string
|
||||
label: 'Format type machine name'
|
||||
weight:
|
||||
type: integer
|
||||
label: 'Weight'
|
||||
region:
|
||||
type: string
|
||||
label: 'Region'
|
||||
label:
|
||||
type: string
|
||||
label: 'Label setting machine name'
|
||||
settings:
|
||||
type: field.formatter.settings.[%parent.type]
|
||||
label: 'Settings'
|
||||
third_party_settings:
|
||||
type: sequence
|
||||
label: 'Third party settings'
|
||||
sequence:
|
||||
type: field.formatter.third_party.[%key]
|
|
@ -0,0 +1,14 @@
|
|||
name: Chaos tools blocks
|
||||
type: module
|
||||
description: 'Provides improvements to blocks that will one day be added to Drupal core.'
|
||||
package: Chaos tool suite (Experimental)
|
||||
# version: 3.x
|
||||
# core: 8.x
|
||||
dependencies:
|
||||
- ctools
|
||||
|
||||
# Information added by Drupal.org packaging script on 2017-04-28
|
||||
version: '8.x-3.0'
|
||||
core: '8.x'
|
||||
project: 'ctools'
|
||||
datestamp: 1493401747
|
|
@ -0,0 +1,376 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools_block\Plugin\Block;
|
||||
|
||||
use Drupal\Component\Utility\NestedArray;
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
use Drupal\Core\Block\BlockBase;
|
||||
use Drupal\Core\Cache\CacheableMetadata;
|
||||
use Drupal\Core\Entity\EntityFieldManagerInterface;
|
||||
use Drupal\Core\Entity\EntityTypeManagerInterface;
|
||||
use Drupal\Core\Entity\FieldableEntityInterface;
|
||||
use Drupal\Core\Field\FieldTypePluginManagerInterface;
|
||||
use Drupal\Core\Field\FormatterPluginManager;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\Core\Plugin\ContextAwarePluginInterface;
|
||||
use Drupal\Core\Render\Element;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides a block to a field on an entity.
|
||||
*
|
||||
* @Block(
|
||||
* id = "entity_field",
|
||||
* deriver = "Drupal\ctools_block\Plugin\Deriver\EntityFieldDeriver",
|
||||
* )
|
||||
*/
|
||||
class EntityField extends BlockBase implements ContextAwarePluginInterface, ContainerFactoryPluginInterface {
|
||||
|
||||
/**
|
||||
* The entity type manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
|
||||
*/
|
||||
protected $entityTypeManager;
|
||||
|
||||
/**
|
||||
* The entity field manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityFieldManagerInterface
|
||||
*/
|
||||
protected $entityFieldManager;
|
||||
|
||||
/**
|
||||
* The field type manager.
|
||||
*
|
||||
* @var \Drupal\Core\Field\FieldTypePluginManagerInterface
|
||||
*/
|
||||
protected $fieldTypeManager;
|
||||
|
||||
/**
|
||||
* The formatter manager.
|
||||
*
|
||||
* @var \Drupal\Core\Field\FormatterPluginManager
|
||||
*/
|
||||
protected $formatterManager;
|
||||
|
||||
/**
|
||||
* The entity type id.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $entityTypeId;
|
||||
|
||||
/**
|
||||
* The field name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $fieldName;
|
||||
|
||||
/**
|
||||
* The field definition.
|
||||
*
|
||||
* @var \Drupal\Core\Field\FieldDefinitionInterface
|
||||
*/
|
||||
protected $fieldDefinition;
|
||||
|
||||
/**
|
||||
* The field storage definition.
|
||||
*
|
||||
* @var \Drupal\Core\Field\FieldStorageDefinitionInterface
|
||||
*/
|
||||
protected $fieldStorageDefinition;
|
||||
|
||||
/**
|
||||
* Constructs a new EntityField.
|
||||
*
|
||||
* @param array $configuration
|
||||
* A configuration array containing information about the plugin instance.
|
||||
* @param string $plugin_id
|
||||
* The plugin ID for the plugin instance.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
|
||||
* The entity type manager.
|
||||
* @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager
|
||||
* The entity field manager.
|
||||
* @param \Drupal\Core\Field\FormatterPluginManager $formatter_manager
|
||||
* The formatter manager.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager, FieldTypePluginManagerInterface $field_type_manager, FormatterPluginManager $formatter_manager) {
|
||||
$this->entityTypeManager = $entity_type_manager;
|
||||
$this->entityFieldManager = $entity_field_manager;
|
||||
$this->fieldTypeManager = $field_type_manager;
|
||||
$this->formatterManager = $formatter_manager;
|
||||
|
||||
// Get the entity type and field name from the plugin id.
|
||||
list (, $entity_type_id, $field_name) = explode(':', $plugin_id);
|
||||
$this->entityTypeId = $entity_type_id;
|
||||
$this->fieldName = $field_name;
|
||||
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||
return new static(
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$container->get('entity_type.manager'),
|
||||
$container->get('entity_field.manager'),
|
||||
$container->get('plugin.manager.field.field_type'),
|
||||
$container->get('plugin.manager.field.formatter')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function build() {
|
||||
/** @var \Drupal\Core\Entity\FieldableEntityInterface $entity */
|
||||
$entity = $this->getContextValue('entity');
|
||||
$build = [];
|
||||
/** @var \Drupal\Core\Field\FieldItemListInterface $field */
|
||||
$field = $entity->{$this->fieldName};
|
||||
$display_settings = $this->getConfiguration()['formatter'];
|
||||
$build['field'] = $field->view($display_settings);
|
||||
|
||||
// Set the cache data appropriately.
|
||||
$build['#cache']['contexts'] = $this->getCacheContexts();
|
||||
$build['#cache']['tags'] = $this->getCacheTags();
|
||||
$build['#cache']['max-age'] = $this->getCacheMaxAge();
|
||||
|
||||
return $build;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function blockAccess(AccountInterface $account) {
|
||||
/** @var \Drupal\Core\Entity\EntityInterface $entity */
|
||||
$entity = $this->getContextValue('entity');
|
||||
// Make sure we have access to the entity.
|
||||
$access = $entity->access('view', $account, TRUE);
|
||||
if ($access->isAllowed()) {
|
||||
// Check that the entity in question has this field.
|
||||
if ($entity instanceof FieldableEntityInterface && $entity->hasField($this->fieldName)) {
|
||||
// Check field access.
|
||||
$field_access = $this->entityTypeManager
|
||||
->getAccessControlHandler($this->entityTypeId)
|
||||
->fieldAccess('view', $this->getFieldDefinition(), $account);
|
||||
|
||||
if ($field_access) {
|
||||
// Build a renderable array for the field.
|
||||
$build = $entity->get($this->fieldName)->view($this->configuration['formatter']);
|
||||
// If there are actual renderable children, grant access.
|
||||
if (Element::children($build)) {
|
||||
return AccessResult::allowed();
|
||||
}
|
||||
}
|
||||
}
|
||||
// Entity doesn't have this field, so access is denied.
|
||||
return AccessResult::forbidden();
|
||||
}
|
||||
// If we don't have access to the entity, return the forbidden result.
|
||||
return $access;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function defaultConfiguration() {
|
||||
$field_type_definition = $this->getFieldTypeDefinition();
|
||||
return [
|
||||
'formatter' => [
|
||||
'label' => 'above',
|
||||
'type' => $field_type_definition['default_formatter'] ?: '',
|
||||
'settings' => [],
|
||||
'third_party_settings' => [],
|
||||
'weight' => 0,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function blockForm($form, FormStateInterface $form_state) {
|
||||
$config = $this->getConfiguration();
|
||||
|
||||
$form['formatter_label'] = [
|
||||
'#type' => 'select',
|
||||
'#title' => $this->t('Label'),
|
||||
'#options' => [
|
||||
'above' => $this->t('Above'),
|
||||
'inline' => $this->t('Inline'),
|
||||
'hidden' => '- ' . $this->t('Hidden') . ' -',
|
||||
'visually_hidden' => '- ' . $this->t('Visually Hidden') . ' -',
|
||||
],
|
||||
'#default_value' => $config['formatter']['label'],
|
||||
];
|
||||
|
||||
$form['formatter_type'] = [
|
||||
'#type' => 'select',
|
||||
'#title' => $this->t('Formatter'),
|
||||
'#options' => $this->getFormatterOptions(),
|
||||
'#default_value' => $config['formatter']['type'],
|
||||
'#ajax' => [
|
||||
'callback' => [static::class, 'formatterSettingsAjaxCallback'],
|
||||
'wrapper' => 'formatter-settings-wrapper',
|
||||
'effect' => 'fade',
|
||||
],
|
||||
];
|
||||
|
||||
// Add the formatter settings to the form via AJAX.
|
||||
$form['#process'][] = [$this, 'formatterSettingsProcessCallback'];
|
||||
$form['formatter_settings_wrapper'] = [
|
||||
'#prefix' => '<div id="formatter-settings-wrapper">',
|
||||
'#suffix' => '</div>',
|
||||
];
|
||||
$form['formatter_settings_wrapper']['formatter_settings'] = [
|
||||
'#tree' => TRUE,
|
||||
// The settings from the formatter plugin will be added in the
|
||||
// ::formatterSettingsProcessCallback method.
|
||||
];
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render API callback: builds the formatter settings elements.
|
||||
*/
|
||||
public function formatterSettingsProcessCallback(array &$element, FormStateInterface $form_state, array &$complete_form) {
|
||||
$config = $this->getConfiguration();
|
||||
$parents_base = $element['#parents'];
|
||||
$formatter_parent = array_merge($parents_base, ['formatter_type']);
|
||||
$formatter_settings_parent = array_merge($parents_base, ['formatter_settings']);
|
||||
|
||||
$settings_element = &$element['formatter_settings_wrapper']['formatter_settings'];
|
||||
|
||||
// Set the #parents on the formatter_settings so they end up as a peer to
|
||||
// formatter_type.
|
||||
$settings_element['#parents'] = $formatter_settings_parent;
|
||||
|
||||
// Get the formatter name in a way that works regardless of whether we're
|
||||
// getting the value via AJAX or not.
|
||||
$formatter_name = NestedArray::getValue($form_state->getUserInput(), $formatter_parent) ?: $element['formatter_type']['#default_value'];
|
||||
|
||||
// Place the formatter settings on the form if a formatter is selected.
|
||||
$formatter = $this->getFormatter($formatter_name, $form_state->getValue('formatter_label'), $form_state->getValue($formatter_settings_parent, $config['formatter']['settings']), $config['formatter']['third_party_settings']);
|
||||
$settings_element = array_merge($formatter->settingsForm($settings_element, $form_state), $settings_element);
|
||||
|
||||
// Store the array parents for our element so that we can use it to pull out
|
||||
// the formatter settings in our AJAX callback.
|
||||
$complete_form['#formatter_array_parents'] = $element['#array_parents'];
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render API callback: gets the layout settings elements.
|
||||
*/
|
||||
public static function formatterSettingsAjaxCallback(array $form, FormStateInterface $form_state) {
|
||||
$formatter_array_parents = $form['#formatter_array_parents'];
|
||||
return NestedArray::getValue($form, array_merge($formatter_array_parents, ['formatter_settings_wrapper']));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function blockSubmit($form, FormStateInterface $form_state) {
|
||||
$this->configuration['formatter']['label'] = $form_state->getValue('formatter_label');
|
||||
$this->configuration['formatter']['type'] = $form_state->getValue('formatter_type');
|
||||
// @todo Remove this manual cast after https://www.drupal.org/node/2635236
|
||||
// is resolved.
|
||||
$this->configuration['formatter']['settings'] = (array) $form_state->getValue('formatter_settings');
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the field definition.
|
||||
*
|
||||
* @return \Drupal\Core\Field\FieldDefinitionInterface
|
||||
*/
|
||||
protected function getFieldDefinition() {
|
||||
if (empty($this->fieldDefinition)) {
|
||||
$field_map = $this->entityFieldManager->getFieldMap();
|
||||
$bundle = reset($field_map[$this->entityTypeId][$this->fieldName]['bundles']);
|
||||
$field_definitions = $this->entityFieldManager->getFieldDefinitions($this->entityTypeId, $bundle);
|
||||
$this->fieldDefinition = $field_definitions[$this->fieldName];
|
||||
}
|
||||
return $this->fieldDefinition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the field storage definition.
|
||||
*
|
||||
* @return \Drupal\Core\Field\FieldStorageDefinitionInterface
|
||||
*/
|
||||
protected function getFieldStorageDefinition() {
|
||||
if (empty($this->fieldStorageDefinition)) {
|
||||
$field_definitions = $this->entityFieldManager->getFieldStorageDefinitions($this->entityTypeId);
|
||||
$this->fieldStorageDefinition = $field_definitions[$this->fieldName];
|
||||
}
|
||||
return $this->fieldStorageDefinition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets field type definition.
|
||||
*
|
||||
* @return array
|
||||
* The field type definition.
|
||||
*/
|
||||
protected function getFieldTypeDefinition() {
|
||||
return $this->fieldTypeManager->getDefinition($this->getFieldStorageDefinition()->getType());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the formatter options for this field type.
|
||||
*
|
||||
* @return array
|
||||
* The formatter options.
|
||||
*/
|
||||
protected function getFormatterOptions() {
|
||||
return $this->formatterManager->getOptions($this->getFieldStorageDefinition()->getType());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the formatter object.
|
||||
*
|
||||
* @param string $type
|
||||
* The formatter name.
|
||||
* @param string $label
|
||||
* The label option for the formatter.
|
||||
* @param array $settings
|
||||
* The formatter settings.
|
||||
* @param array $third_party_settings
|
||||
* The formatter third party settings.
|
||||
*
|
||||
* @return \Drupal\Core\Field\FormatterInterface
|
||||
* The formatter object.
|
||||
*/
|
||||
protected function getFormatter($type, $label, array $settings, array $third_party_settings) {
|
||||
return $this->formatterManager->createInstance($type, [
|
||||
'field_definition' => $this->getFieldDefinition(),
|
||||
'view_mode' => 'default',
|
||||
'prepare' => TRUE,
|
||||
'label' => $label,
|
||||
'settings' => $settings,
|
||||
'third_party_settings' => $third_party_settings,
|
||||
]);
|
||||
}
|
||||
|
||||
public function __wakeup() {
|
||||
parent::__wakeup();
|
||||
// @todo figure out why this happens.
|
||||
// prevent $fieldStorageDefinition being erroneously set to $this.
|
||||
$this->fieldStorageDefinition = NULL;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools_block\Plugin\Deriver;
|
||||
|
||||
use Drupal\Core\Plugin\Context\ContextDefinition;
|
||||
use Drupal\ctools\Plugin\Deriver\EntityDeriverBase;
|
||||
|
||||
/**
|
||||
* Provides entity field block definitions for every field.
|
||||
*/
|
||||
class EntityFieldDeriver extends EntityDeriverBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDerivativeDefinitions($base_plugin_definition) {
|
||||
$entity_type_labels = $this->entityManager->getEntityTypeLabels();
|
||||
foreach ($this->entityManager->getFieldMap() as $entity_type_id => $entity_field_map) {
|
||||
foreach ($this->entityManager->getFieldStorageDefinitions($entity_type_id) as $field_storage_definition) {
|
||||
$field_name = $field_storage_definition->getName();
|
||||
|
||||
// The blocks are based on fields. However, we are looping through field
|
||||
// storages for which no fields may exist. If that is the case, skip
|
||||
// this field storage.
|
||||
if (!isset($entity_field_map[$field_name])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$field_info = $entity_field_map[$field_name];
|
||||
$derivative_id = $entity_type_id . ":" . $field_name;
|
||||
|
||||
// Get the admin label for both base and configurable fields.
|
||||
if ($field_storage_definition->isBaseField()) {
|
||||
$admin_label = $field_storage_definition->getLabel();
|
||||
}
|
||||
else {
|
||||
// We take the field label used on the first bundle.
|
||||
$first_bundle = reset($field_info['bundles']);
|
||||
$bundle_field_definitions = $this->entityManager->getFieldDefinitions($entity_type_id, $first_bundle);
|
||||
|
||||
// The field storage config may exist, but it's possible that no
|
||||
// fields are actually using it. If that's the case, skip to the next
|
||||
// field.
|
||||
if (empty($bundle_field_definitions[$field_name])) {
|
||||
continue;
|
||||
}
|
||||
$admin_label = $bundle_field_definitions[$field_name]->getLabel();
|
||||
}
|
||||
|
||||
// Set plugin definition for derivative.
|
||||
$derivative = $base_plugin_definition;
|
||||
$derivative['category'] = $this->t('@entity', ['@entity' => $entity_type_labels[$entity_type_id]]);
|
||||
$derivative['admin_label'] = $admin_label;
|
||||
$derivative['context'] = [
|
||||
'entity' => new ContextDefinition('entity:' . $entity_type_id, $entity_type_labels[$entity_type_id], TRUE),
|
||||
];
|
||||
|
||||
$this->derivatives[$derivative_id] = $derivative;
|
||||
|
||||
}
|
||||
}
|
||||
return $this->derivatives;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- node.type.ctools_block_field_test
|
||||
_core:
|
||||
default_config_hash: hoRuk0InNhhRVGnhQ9hzifTXVz432i9hvPe-tVstUbc
|
||||
id: node.ctools_block_field_test.promote
|
||||
field_name: promote
|
||||
entity_type: node
|
||||
bundle: ctools_block_field_test
|
||||
label: 'Promoted to front page'
|
||||
description: ''
|
||||
required: false
|
||||
translatable: true
|
||||
default_value:
|
||||
-
|
||||
value: 0
|
||||
default_value_callback: ''
|
||||
settings:
|
||||
on_label: 'On'
|
||||
off_label: 'Off'
|
||||
field_type: boolean
|
|
@ -0,0 +1,62 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- field.field.node.ctools_block_field_test.body
|
||||
- node.type.ctools_block_field_test
|
||||
module:
|
||||
- path
|
||||
- text
|
||||
_core:
|
||||
default_config_hash: xpDeWNLzjX4dDB9YyBlO9y9FR4vHwMv0GKsuqDYy0Bc
|
||||
id: node.ctools_block_field_test.default
|
||||
targetEntityType: node
|
||||
bundle: ctools_block_field_test
|
||||
mode: default
|
||||
content:
|
||||
body:
|
||||
type: text_textarea_with_summary
|
||||
weight: 31
|
||||
settings:
|
||||
rows: 9
|
||||
summary_rows: 3
|
||||
placeholder: ''
|
||||
third_party_settings: { }
|
||||
created:
|
||||
type: datetime_timestamp
|
||||
weight: 10
|
||||
settings: { }
|
||||
third_party_settings: { }
|
||||
path:
|
||||
type: path
|
||||
weight: 30
|
||||
settings: { }
|
||||
third_party_settings: { }
|
||||
promote:
|
||||
type: boolean_checkbox
|
||||
settings:
|
||||
display_label: true
|
||||
weight: 15
|
||||
third_party_settings: { }
|
||||
sticky:
|
||||
type: boolean_checkbox
|
||||
settings:
|
||||
display_label: true
|
||||
weight: 16
|
||||
third_party_settings: { }
|
||||
title:
|
||||
type: string_textfield
|
||||
weight: -5
|
||||
settings:
|
||||
size: 60
|
||||
placeholder: ''
|
||||
third_party_settings: { }
|
||||
uid:
|
||||
type: entity_reference_autocomplete
|
||||
weight: 5
|
||||
settings:
|
||||
match_operator: CONTAINS
|
||||
size: 60
|
||||
placeholder: ''
|
||||
third_party_settings: { }
|
||||
hidden: { }
|
|
@ -0,0 +1,18 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- field.field.node.ctools_block_field_test.body
|
||||
- node.type.ctools_block_field_test
|
||||
module:
|
||||
- user
|
||||
_core:
|
||||
default_config_hash: clNnyw6fhh5SwIme5I_3zjbLv-PMfpY-JXofVAC3CV8
|
||||
id: node.ctools_block_field_test.default
|
||||
targetEntityType: node
|
||||
bundle: ctools_block_field_test
|
||||
mode: default
|
||||
content: { }
|
||||
hidden:
|
||||
body: true
|
||||
links: true
|
|
@ -0,0 +1,27 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- core.entity_view_mode.node.teaser
|
||||
- field.field.node.ctools_block_field_test.body
|
||||
- node.type.ctools_block_field_test
|
||||
module:
|
||||
- text
|
||||
- user
|
||||
_core:
|
||||
default_config_hash: gQV5baI7pCIOBUtLkbJ1c2WJwM8CdlKiKOtLLIWnfy0
|
||||
id: node.ctools_block_field_test.teaser
|
||||
targetEntityType: node
|
||||
bundle: ctools_block_field_test
|
||||
mode: teaser
|
||||
content:
|
||||
body:
|
||||
label: hidden
|
||||
type: text_summary_or_trimmed
|
||||
weight: 101
|
||||
settings:
|
||||
trim_length: 600
|
||||
third_party_settings: { }
|
||||
links:
|
||||
weight: 100
|
||||
hidden: { }
|
|
@ -0,0 +1,23 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- field.storage.node.body
|
||||
- node.type.ctools_block_field_test
|
||||
module:
|
||||
- text
|
||||
_core:
|
||||
default_config_hash: fzUnwtwftRsgKExjpF6XdMqbUzP16ytkjQniBZl1Hqg
|
||||
id: node.ctools_block_field_test.body
|
||||
field_name: body
|
||||
entity_type: node
|
||||
bundle: ctools_block_field_test
|
||||
label: Body
|
||||
description: ''
|
||||
required: false
|
||||
translatable: true
|
||||
default_value: { }
|
||||
default_value_callback: ''
|
||||
settings:
|
||||
display_summary: true
|
||||
field_type: text_with_summary
|
|
@ -0,0 +1,37 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- field.storage.node.field_image
|
||||
- node.type.ctools_block_field_test
|
||||
module:
|
||||
- image
|
||||
id: node.ctools_block_field_test.field_image
|
||||
field_name: field_image
|
||||
entity_type: node
|
||||
bundle: ctools_block_field_test
|
||||
label: Image
|
||||
description: ''
|
||||
required: false
|
||||
translatable: true
|
||||
default_value: { }
|
||||
default_value_callback: ''
|
||||
settings:
|
||||
file_directory: '[date:custom:Y]-[date:custom:m]'
|
||||
file_extensions: 'png gif jpg jpeg'
|
||||
max_filesize: ''
|
||||
max_resolution: ''
|
||||
min_resolution: ''
|
||||
alt_field: true
|
||||
title_field: false
|
||||
alt_field_required: true
|
||||
title_field_required: false
|
||||
default_image:
|
||||
uuid: null
|
||||
alt: ''
|
||||
title: ''
|
||||
width: null
|
||||
height: null
|
||||
handler: 'default:file'
|
||||
handler_settings: { }
|
||||
field_type: image
|
|
@ -0,0 +1,31 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- file
|
||||
- image
|
||||
- node
|
||||
id: node.field_image
|
||||
field_name: field_image
|
||||
entity_type: node
|
||||
type: image
|
||||
settings:
|
||||
uri_scheme: public
|
||||
default_image:
|
||||
uuid: null
|
||||
alt: ''
|
||||
title: ''
|
||||
width: null
|
||||
height: null
|
||||
target_type: file
|
||||
display_field: false
|
||||
display_default: false
|
||||
module: image
|
||||
locked: false
|
||||
cardinality: 1
|
||||
translatable: true
|
||||
indexes:
|
||||
target_id:
|
||||
- target_id
|
||||
persist_with_no_fields: false
|
||||
custom_storage: false
|
|
@ -0,0 +1,18 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- menu_ui
|
||||
third_party_settings:
|
||||
menu_ui:
|
||||
available_menus: { }
|
||||
parent: ''
|
||||
_core:
|
||||
default_config_hash: hjC271ZF6B5XYgF6-F5Ak73sJiZWJRmSLsgk8S7Vo-8
|
||||
name: 'CTools block field test'
|
||||
type: ctools_block_field_test
|
||||
description: 'A content type used for the ctools_block field tests.'
|
||||
help: ''
|
||||
new_revision: false
|
||||
preview_mode: 0
|
||||
display_submitted: false
|
|
@ -0,0 +1,20 @@
|
|||
name: 'Chaos tools blocks test'
|
||||
type: module
|
||||
description: 'Support module for Chaos tools blocks tests.'
|
||||
# core: 8.x
|
||||
package: Testing
|
||||
# version: 8.0.1
|
||||
dependencies:
|
||||
- image
|
||||
- menu_ui
|
||||
- node
|
||||
- path
|
||||
- text
|
||||
- user
|
||||
features: true
|
||||
|
||||
# Information added by Drupal.org packaging script on 2017-04-28
|
||||
version: '8.x-3.0'
|
||||
core: '8.x'
|
||||
project: 'ctools'
|
||||
datestamp: 1493401747
|
|
@ -0,0 +1,132 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\ctools_block\Functional;
|
||||
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Tests the entity field block.
|
||||
*
|
||||
* @group ctools_block
|
||||
*/
|
||||
class EntityFieldBlockTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['block', 'ctools_block', 'ctools_block_field_test'];
|
||||
|
||||
/**
|
||||
* Tests using the node body field in a block.
|
||||
*/
|
||||
public function testBodyField() {
|
||||
$block = $this->drupalPlaceBlock('entity_field:node:body', [
|
||||
'formatter' => [
|
||||
'type' => 'text_default',
|
||||
],
|
||||
'context_mapping' => [
|
||||
'entity' => '@node.node_route_context:node',
|
||||
],
|
||||
]);
|
||||
$node = $this->drupalCreateNode(['type' => 'ctools_block_field_test']);
|
||||
$this->drupalGet('node/' . $node->id());
|
||||
$assert = $this->assertSession();
|
||||
$assert->pageTextContains($block->label());
|
||||
$assert->pageTextContains($node->body->value);
|
||||
|
||||
$node->set('body', NULL)->save();
|
||||
$this->getSession()->reload();
|
||||
// The block should not appear if there is no value in the field.
|
||||
$assert->pageTextNotContains($block->label());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that empty image fields will still render their default value.
|
||||
*/
|
||||
public function testEmptyImageField() {
|
||||
$source = \Drupal::moduleHandler()->getModule('image')->getPath() . '/sample.png';
|
||||
file_unmanaged_copy($source, 'public://sample.png');
|
||||
|
||||
/** @var \Drupal\file\FileInterface $file */
|
||||
$file = \Drupal::entityTypeManager()
|
||||
->getStorage('file')
|
||||
->create([
|
||||
'uri' => 'public://sample.png',
|
||||
]);
|
||||
$file->save();
|
||||
|
||||
/** @var \Drupal\field\FieldConfigInterface $field */
|
||||
$field = \Drupal::entityTypeManager()
|
||||
->getStorage('field_config')
|
||||
->load('node.ctools_block_field_test.field_image');
|
||||
$settings = $field->getSettings();
|
||||
$settings['default_image']['uuid'] = $file->uuid();
|
||||
$field->set('settings', $settings)->save();
|
||||
|
||||
$this->drupalPlaceBlock('entity_field:node:field_image', [
|
||||
'formatter' => [
|
||||
'type' => 'image_image',
|
||||
],
|
||||
'context_mapping' => [
|
||||
'entity' => '@node.node_route_context:node',
|
||||
],
|
||||
]);
|
||||
|
||||
$node = $this->drupalCreateNode(['type' => 'ctools_block_field_test']);
|
||||
$this->drupalGet('node/' . $node->id());
|
||||
|
||||
$url = $file->getFileUri();
|
||||
$url = file_create_url($url);
|
||||
$url = file_url_transform_relative($url);
|
||||
$this->assertSession()->responseContains('src="' . $url . '"');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests using the node uid base field in a block.
|
||||
*/
|
||||
public function testNodeBaseFields() {
|
||||
$block = $this->drupalPlaceBlock('entity_field:node:title', [
|
||||
'formatter' => [
|
||||
'type' => 'string',
|
||||
],
|
||||
'context_mapping' => [
|
||||
'entity' => '@node.node_route_context:node',
|
||||
],
|
||||
]);
|
||||
$node = $this->drupalCreateNode(['type' => 'ctools_block_field_test', 'uid' => 1]);
|
||||
$this->drupalGet('node/' . $node->id());
|
||||
$assert = $this->assertSession();
|
||||
$assert->pageTextContains($block->label());
|
||||
$assert->pageTextContains($node->getTitle());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that we are setting the render cache metadata correctly.
|
||||
*/
|
||||
public function testRenderCache() {
|
||||
$this->drupalPlaceBlock('entity_field:node:body', [
|
||||
'formatter' => [
|
||||
'type' => 'text_default',
|
||||
],
|
||||
'context_mapping' => [
|
||||
'entity' => '@node.node_route_context:node',
|
||||
],
|
||||
]);
|
||||
$a = $this->drupalCreateNode(['type' => 'ctools_block_field_test']);
|
||||
$b = $this->drupalCreateNode(['type' => 'ctools_block_field_test']);
|
||||
|
||||
$assert = $this->assertSession();
|
||||
$this->drupalGet('node/' . $a->id());
|
||||
$assert->pageTextContains($a->body->value);
|
||||
$this->drupalGet('node/' . $b->id());
|
||||
$assert->pageTextNotContains($a->body->value);
|
||||
$assert->pageTextContains($b->body->value);
|
||||
|
||||
$text = 'This is my text. Are you not entertained?';
|
||||
$a->body->value = $text;
|
||||
$a->save();
|
||||
$this->drupalGet('node/' . $a->id());
|
||||
$assert->pageTextContains($text);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
name: Chaos tools Views
|
||||
type: module
|
||||
description: 'A set of improvements to the core Views code that allows for greater control over Blocks.'
|
||||
package: Chaos tool suite (Experimental)
|
||||
# version: 3.x
|
||||
# core: 8.x
|
||||
dependencies:
|
||||
- block
|
||||
- views
|
||||
|
||||
# Information added by Drupal.org packaging script on 2017-04-28
|
||||
version: '8.x-3.0'
|
||||
core: '8.x'
|
||||
project: 'ctools'
|
||||
datestamp: 1493401747
|
|
@ -0,0 +1,104 @@
|
|||
<?php
|
||||
|
||||
use Drupal\views\Plugin\views\display\Block as CoreBlock;
|
||||
use Drupal\ctools_views\Plugin\Display\Block;
|
||||
|
||||
/**
|
||||
* Implements hook_views_plugins_display_alter().
|
||||
*/
|
||||
function ctools_views_views_plugins_display_alter(&$displays) {
|
||||
if (!empty($displays['block']['class']) && $displays['block']['class'] == CoreBlock::class) {
|
||||
$displays['block']['class'] = Block::class;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_config_schema_info_alter().
|
||||
*/
|
||||
function ctools_views_config_schema_info_alter(&$definitions) {
|
||||
// Add to the views block plugin schema.
|
||||
$definitions['views_block']['mapping']['pager'] = [
|
||||
'type' => 'string',
|
||||
'label' => 'Pager type'
|
||||
];
|
||||
$definitions['views_block']['mapping']['fields'] = [
|
||||
'type' => 'sequence',
|
||||
'label' => 'Fields settings',
|
||||
'sequence' => [
|
||||
[
|
||||
'type' => 'mapping',
|
||||
'label' => 'Field settings',
|
||||
'mapping' => [
|
||||
'hide' => [
|
||||
'type' => 'boolean',
|
||||
'label' => 'Hide field',
|
||||
],
|
||||
'weight' => [
|
||||
'type' => 'integer',
|
||||
'label' => 'Field weight',
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
$definitions['views_block']['mapping']['filter'] = [
|
||||
'type' => 'sequence',
|
||||
'label' => 'Filters settings',
|
||||
'sequence' => [
|
||||
[
|
||||
'type' => 'mapping',
|
||||
'label' => 'Filter settings',
|
||||
'mapping' => [
|
||||
'type' => [
|
||||
'type' => 'string',
|
||||
'label' => 'Plugin id',
|
||||
],
|
||||
'disable' => [
|
||||
'type' => 'boolean',
|
||||
'label' => 'Disable filter',
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
$definitions['views_block']['mapping']['sort'] = [
|
||||
'type' => 'sequence',
|
||||
'label' => 'Sort settings',
|
||||
'sequence' => [
|
||||
[
|
||||
'type' => 'string',
|
||||
'label' => 'Sort order value',
|
||||
],
|
||||
],
|
||||
];
|
||||
$definitions['views_block']['mapping']['pager_offset'] = [
|
||||
'type' => 'integer',
|
||||
'label' => 'Pager offset'
|
||||
];
|
||||
|
||||
// Add to the views block display plugin schema.
|
||||
$definitions['views.display.block']['mapping']['allow']['mapping']['offset'] = [
|
||||
'type' => 'string',
|
||||
'label' => 'Pager offset',
|
||||
];
|
||||
$definitions['views.display.block']['mapping']['allow']['mapping']['pager'] = [
|
||||
'type' => 'string',
|
||||
'label' => 'Pager type',
|
||||
];
|
||||
$definitions['views.display.block']['mapping']['allow']['mapping']['hide_fields'] = [
|
||||
'type' => 'string',
|
||||
'label' => 'Hide fields',
|
||||
];
|
||||
$definitions['views.display.block']['mapping']['allow']['mapping']['sort_fields'] = [
|
||||
'type' => 'string',
|
||||
'label' => 'Sort fields',
|
||||
];
|
||||
$definitions['views.display.block']['mapping']['allow']['mapping']['disable_filters'] = [
|
||||
'type' => 'string',
|
||||
'label' => 'Disable filters',
|
||||
];
|
||||
$definitions['views.display.block']['mapping']['allow']['mapping']['configure_sorts'] = [
|
||||
'type' => 'string',
|
||||
'label' => 'Configure sorts',
|
||||
];
|
||||
}
|
|
@ -0,0 +1,438 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools_views\Plugin\Display;
|
||||
|
||||
use Drupal\Core\Form\FormState;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\views\Plugin\Block\ViewsBlock;
|
||||
use Drupal\views\Plugin\views\display\Block as CoreBlock;
|
||||
use Drupal\views\Plugin\views\filter\InOperator;
|
||||
|
||||
/**
|
||||
* Provides a Block display plugin that allows for greater control over Views
|
||||
* block settings.
|
||||
*/
|
||||
class Block extends CoreBlock {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function optionsSummary(&$categories, &$options) {
|
||||
parent::optionsSummary($categories, $options);
|
||||
$filtered_allow = array_filter($this->getOption('allow'));
|
||||
$filter_options = [
|
||||
'items_per_page' => $this->t('Items per page'),
|
||||
'offset' => $this->t('Pager offset'),
|
||||
'pager' => $this->t('Pager type'),
|
||||
'hide_fields' => $this->t('Hide fields'),
|
||||
'sort_fields' => $this->t('Reorder fields'),
|
||||
'disable_filters' => $this->t('Disable filters'),
|
||||
'configure_sorts' => $this->t('Configure sorts')
|
||||
];
|
||||
$filter_intersect = array_intersect_key($filter_options, $filtered_allow);
|
||||
|
||||
$options['allow'] = array(
|
||||
'category' => 'block',
|
||||
'title' => $this->t('Allow settings'),
|
||||
'value' => empty($filtered_allow) ? $this->t('None') : implode(', ', $filter_intersect),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildOptionsForm(&$form, FormStateInterface $form_state) {
|
||||
parent::buildOptionsForm($form, $form_state);
|
||||
$options = $form['allow']['#options'];
|
||||
$options['offset'] = $this->t('Pager offset');
|
||||
$options['pager'] = $this->t('Pager type');
|
||||
$options['hide_fields'] = $this->t('Hide fields');
|
||||
$options['sort_fields'] = $this->t('Reorder fields');
|
||||
$options['disable_filters'] = $this->t('Disable filters');
|
||||
$options['configure_sorts'] = $this->t('Configure sorts');
|
||||
$form['allow']['#options'] = $options;
|
||||
// Update the items_per_page if set.
|
||||
$defaults = array_filter($form['allow']['#default_value']);
|
||||
if (isset($defaults['items_per_page'])) {
|
||||
$defaults['items_per_page'] = 'items_per_page';
|
||||
}
|
||||
$form['allow']['#default_value'] = $defaults;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function blockForm(ViewsBlock $block, array &$form, FormStateInterface $form_state) {
|
||||
$form = parent::blockForm($block, $form, $form_state);
|
||||
|
||||
$allow_settings = array_filter($this->getOption('allow'));
|
||||
$block_configuration = $block->getConfiguration();
|
||||
|
||||
// Modify "Items per page" block settings form.
|
||||
if (!empty($allow_settings['items_per_page'])) {
|
||||
// Items per page
|
||||
$form['override']['items_per_page']['#type'] = 'number';
|
||||
unset($form['override']['items_per_page']['#options']);
|
||||
}
|
||||
|
||||
// Provide "Pager offset" block settings form.
|
||||
if (!empty($allow_settings['offset'])) {
|
||||
$form['override']['pager_offset'] = [
|
||||
'#type' => 'number',
|
||||
'#title' => $this->t('Pager offset'),
|
||||
'#default_value' => isset($block_configuration['pager_offset']) ? $block_configuration['pager_offset'] : 0,
|
||||
'#description' => $this->t('For example, set this to 3 and the first 3 items will not be displayed.'),
|
||||
];
|
||||
}
|
||||
|
||||
// Provide "Pager type" block settings form.
|
||||
if (!empty($allow_settings['pager'])) {
|
||||
$pager_options = [
|
||||
'view' => $this->t('Inherit from view'),
|
||||
'some' => $this->t('Display a specified number of items'),
|
||||
'none' => $this->t('Display all items')
|
||||
];
|
||||
$form['override']['pager'] = [
|
||||
'#type' => 'radios',
|
||||
'#title' => $this->t('Pager'),
|
||||
'#options' => $pager_options,
|
||||
'#default_value' => isset($block_configuration['pager']) ? $block_configuration['pager'] : 'view'
|
||||
];
|
||||
}
|
||||
|
||||
// Provide "Hide fields" / "Reorder fields" block settings form.
|
||||
if (!empty($allow_settings['hide_fields']) || !empty($allow_settings['sort_fields'])) {
|
||||
// Set up the configuration table for hiding / sorting fields.
|
||||
$fields = $this->getHandlers('field');
|
||||
$header = [];
|
||||
if (!empty($allow_settings['hide_fields'])) {
|
||||
$header['hide'] = $this->t('Hide');
|
||||
}
|
||||
$header['label'] = $this->t('Label');
|
||||
if (!empty($allow_settings['sort_fields'])) {
|
||||
$header['weight'] = $this->t('Weight');
|
||||
}
|
||||
$form['override']['order_fields'] = [
|
||||
'#type' => 'table',
|
||||
'#header' => $header,
|
||||
'#rows' => array(),
|
||||
];
|
||||
if (!empty($allow_settings['sort_fields'])) {
|
||||
$form['override']['order_fields']['#tabledrag'] = [
|
||||
[
|
||||
'action' => 'order',
|
||||
'relationship' => 'sibling',
|
||||
'group' => 'field-weight',
|
||||
]
|
||||
];
|
||||
$form['override']['order_fields']['#attributes'] = ['id' => 'order-fields'];
|
||||
}
|
||||
|
||||
// Sort available field plugins by their currently configured weight.
|
||||
$sorted_fields = [];
|
||||
if (!empty($allow_settings['sort_fields']) && isset($block_configuration['fields'])) {
|
||||
uasort($block_configuration['fields'], '\Drupal\ctools_views\Plugin\Display\Block::sortFieldsByWeight');
|
||||
foreach (array_keys($block_configuration['fields']) as $field_name) {
|
||||
if (!empty($fields[$field_name])) {
|
||||
$sorted_fields[$field_name] = $fields[$field_name];
|
||||
unset($fields[$field_name]);
|
||||
}
|
||||
}
|
||||
if (!empty($fields)) {
|
||||
foreach ($fields as $field_name => $field_info) {
|
||||
$sorted_fields[$field_name] = $field_info;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
$sorted_fields = $fields;
|
||||
}
|
||||
|
||||
// Add each field to the configuration table.
|
||||
foreach ($sorted_fields as $field_name => $plugin) {
|
||||
$field_label = $plugin->adminLabel();
|
||||
if (!empty($plugin->options['label'])) {
|
||||
$field_label .= ' (' . $plugin->options['label'] . ')';
|
||||
}
|
||||
if (!empty($allow_settings['sort_fields'])) {
|
||||
$form['override']['order_fields'][$field_name]['#attributes']['class'][] = 'draggable';
|
||||
}
|
||||
$form['override']['order_fields'][$field_name]['#weight'] = !empty($block_configuration['fields'][$field_name]['weight']) ? $block_configuration['fields'][$field_name]['weight'] : '';
|
||||
if (!empty($allow_settings['hide_fields'])) {
|
||||
$form['override']['order_fields'][$field_name]['hide'] = [
|
||||
'#type' => 'checkbox',
|
||||
'#default_value' => !empty($block_configuration['fields'][$field_name]['hide']) ? $block_configuration['fields'][$field_name]['hide'] : 0,
|
||||
];
|
||||
}
|
||||
$form['override']['order_fields'][$field_name]['label'] = [
|
||||
'#markup' => $field_label,
|
||||
];
|
||||
if (!empty($allow_settings['sort_fields'])) {
|
||||
$form['override']['order_fields'][$field_name]['weight'] = [
|
||||
'#type' => 'weight',
|
||||
'#title' => $this->t('Weight for @title', ['@title' => $field_label]),
|
||||
'#title_display' => 'invisible',
|
||||
'#delta' => 50,
|
||||
'#default_value' => !empty($block_configuration['fields'][$field_name]['weight']) ? $block_configuration['fields'][$field_name]['weight'] : 0,
|
||||
'#attributes' => ['class' => ['field-weight']],
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Provide "Configure filters" / "Disable filters" block settings form.
|
||||
if (!empty($allow_settings['disable_filters'])) {
|
||||
$items = [];
|
||||
foreach ((array) $this->getOption('filters') as $filter_name => $item) {
|
||||
$item['value'] = isset($block_configuration["filter"][$filter_name]['value']) ? $block_configuration["filter"][$filter_name]['value'] : '';
|
||||
$items[$filter_name] = $item;
|
||||
}
|
||||
$this->setOption('filters', $items);
|
||||
$filters = $this->getHandlers('filter');
|
||||
|
||||
// Add a settings form for each exposed filter to configure or hide it.
|
||||
foreach ($filters as $filter_name => $plugin) {
|
||||
if ($plugin->isExposed() && $exposed_info = $plugin->exposedInfo()) {
|
||||
$form['override']['filters'][$filter_name] = [
|
||||
'#type' => 'details',
|
||||
'#title' => $exposed_info['label'],
|
||||
];
|
||||
$form['override']['filters'][$filter_name]['plugin'] = [
|
||||
'#type' => 'value',
|
||||
'#value' => $plugin,
|
||||
];
|
||||
// Render "Disable filters" settings form.
|
||||
if (!empty($allow_settings['disable_filters'])) {
|
||||
$form['override']['filters'][$filter_name]['disable'] = [
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Disable'),
|
||||
'#default_value' => !empty($block_configuration['filter'][$filter_name]['disable']) ? $block_configuration['filter'][$filter_name]['disable'] : 0,
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Provide "Configure sorts" block settings form.
|
||||
if (!empty($allow_settings['configure_sorts'])) {
|
||||
$sorts = $this->getHandlers('sort');
|
||||
$options = array(
|
||||
'ASC' => $this->t('Sort ascending'),
|
||||
'DESC' => $this->t('Sort descending'),
|
||||
);
|
||||
foreach ($sorts as $sort_name => $plugin) {
|
||||
$form['override']['sort'][$sort_name] = [
|
||||
'#type' => 'details',
|
||||
'#title' => $plugin->adminLabel(),
|
||||
];
|
||||
$form['override']['sort'][$sort_name]['plugin'] = [
|
||||
'#type' => 'value',
|
||||
'#value' => $plugin,
|
||||
];
|
||||
$form['override']['sort'][$sort_name]['order'] = array(
|
||||
'#title' => $this->t('Order'),
|
||||
'#type' => 'radios',
|
||||
'#options' => $options,
|
||||
'#default_value' => $plugin->options['order']
|
||||
);
|
||||
|
||||
// Set default values for sorts for this block.
|
||||
if (!empty($block_configuration["sort"][$sort_name])) {
|
||||
$form['override']['sort'][$sort_name]['order']['#default_value'] = $block_configuration["sort"][$sort_name];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function blockSubmit(ViewsBlock $block, $form, FormStateInterface $form_state) {
|
||||
// Set default value for items_per_page if left blank.
|
||||
if (empty($form_state->getValue(array('override', 'items_per_page')))) {
|
||||
$form_state->setValue(array('override', 'items_per_page'), "none");
|
||||
}
|
||||
|
||||
parent::blockSubmit($block, $form, $form_state);
|
||||
$configuration = $block->getConfiguration();
|
||||
$allow_settings = array_filter($this->getOption('allow'));
|
||||
|
||||
// Save "Pager type" settings to block configuration.
|
||||
if (!empty($allow_settings['pager'])) {
|
||||
if ($pager = $form_state->getValue(['override', 'pager'])) {
|
||||
$configuration['pager'] = $pager;
|
||||
}
|
||||
}
|
||||
|
||||
// Save "Pager offset" settings to block configuration.
|
||||
if (!empty($allow_settings['offset'])) {
|
||||
$configuration['pager_offset'] = $form_state->getValue(['override', 'pager_offset']);
|
||||
}
|
||||
|
||||
// Save "Hide fields" / "Reorder fields" settings to block configuration.
|
||||
if (!empty($allow_settings['hide_fields']) || !empty($allow_settings['sort_fields'])) {
|
||||
if ($fields = array_filter($form_state->getValue(['override', 'order_fields']))) {
|
||||
uasort($fields, '\Drupal\ctools_views\Plugin\Display\Block::sortFieldsByWeight');
|
||||
$configuration['fields'] = $fields;
|
||||
}
|
||||
}
|
||||
|
||||
// Save "Configure filters" / "Disable filters" settings to block
|
||||
// configuration.
|
||||
unset($configuration['filter']);
|
||||
if (!empty($allow_settings['disable_filters'])) {
|
||||
if ($filters = $form_state->getValue(['override', 'filters'])) {
|
||||
foreach ($filters as $filter_name => $filter) {
|
||||
/** @var \Drupal\views\Plugin\views\filter\FilterPluginBase $plugin */
|
||||
$plugin = $form_state->getValue(['override', 'filters', $filter_name, 'plugin']);
|
||||
$configuration["filter"][$filter_name]['type'] = $plugin->getPluginId();
|
||||
|
||||
// Check if we want to disable this filter.
|
||||
if (!empty($allow_settings['disable_filters'])) {
|
||||
$disable = $form_state->getValue(['override', 'filters', $filter_name, 'disable']);
|
||||
// If marked disabled, we don't really care about other stuff.
|
||||
if ($disable) {
|
||||
$configuration["filter"][$filter_name]['disable'] = $disable;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Save "Configure sorts" settings to block configuration.
|
||||
if (!empty($allow_settings['configure_sorts'])) {
|
||||
$sorts = $form_state->getValue(['override', 'sort']);
|
||||
foreach ($sorts as $sort_name => $sort) {
|
||||
$plugin = $sort['plugin'];
|
||||
// Check if we want to override the default sort order
|
||||
if ($plugin->options['order'] != $sort['order']) {
|
||||
$configuration['sort'][$sort_name] = $sort['order'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$block->setConfiguration($configuration);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function preBlockBuild(ViewsBlock $block) {
|
||||
parent::preBlockBuild($block);
|
||||
|
||||
$allow_settings = array_filter($this->getOption('allow'));
|
||||
$config = $block->getConfiguration();
|
||||
list(, $display_id) = explode('-', $block->getDerivativeId(), 2);
|
||||
|
||||
// Change pager offset settings based on block configuration.
|
||||
if (!empty($allow_settings['offset'])) {
|
||||
$this->view->setOffset($config['pager_offset']);
|
||||
}
|
||||
|
||||
// Change pager style settings based on block configuration.
|
||||
if (!empty($allow_settings['pager'])) {
|
||||
$pager = $this->view->display_handler->getOption('pager');
|
||||
if (!empty($config['pager']) && $config['pager'] != 'view') {
|
||||
$pager['type'] = $config['pager'];
|
||||
}
|
||||
$this->view->display_handler->setOption('pager', $pager);
|
||||
}
|
||||
|
||||
// Change fields output based on block configuration.
|
||||
if (!empty($allow_settings['hide_fields']) || !empty($allow_settings['sort_fields'])) {
|
||||
if (!empty($config['fields']) && $this->view->getStyle()->usesFields()) {
|
||||
$fields = $this->view->getHandlers('field');
|
||||
uasort($config['fields'], '\Drupal\ctools_views\Plugin\Display\Block::sortFieldsByWeight');
|
||||
$iterate_fields = !empty($allow_settings['sort_fields']) ? $config['fields'] : $fields;
|
||||
foreach (array_keys($iterate_fields) as $field_name) {
|
||||
// Remove each field in sequence and re-add them to sort
|
||||
// appropriately or hide if disabled.
|
||||
$this->view->removeHandler($display_id, 'field', $field_name);
|
||||
if (empty($allow_settings['hide_fields']) || (!empty($allow_settings['hide_fields']) && empty($config['fields'][$field_name]['hide']))) {
|
||||
$this->view->addHandler($display_id, 'field', $fields[$field_name]['table'], $fields[$field_name]['field'], $fields[$field_name], $field_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Change filters output based on block configuration.
|
||||
if (!empty($allow_settings['disable_filters'])) {
|
||||
$filters = $this->view->getHandlers('filter', $display_id);
|
||||
foreach ($filters as $filter_name => $filter) {
|
||||
// If we allow disabled filters and this filter is disabled, disable it
|
||||
// and continue.
|
||||
if (!empty($allow_settings['disable_filters']) && !empty($config["filter"][$filter_name]['disable'])) {
|
||||
$this->view->removeHandler($display_id, 'filter', $filter_name);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Change sorts based on block configuration.
|
||||
if (!empty($allow_settings['configure_sorts'])) {
|
||||
$sorts = $this->view->getHandlers('sort', $display_id);
|
||||
foreach ($sorts as $sort_name => $sort) {
|
||||
if (!empty($config["sort"][$sort_name])) {
|
||||
$sort['order'] = $config["sort"][$sort_name];
|
||||
$this->view->setHandler($display_id, 'sort', $sort_name, $sort);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function getFilterOptionsValue(array $filter, array $config) {
|
||||
$plugin_definition = \Drupal::service('plugin.manager.views.filter')->getDefinition($config['type']);
|
||||
if (is_subclass_of($plugin_definition['class'], '\Drupal\views\Plugin\views\filter\InOperator')) {
|
||||
return array_values($config['value']);
|
||||
}
|
||||
return $config['value'][$filter['expose']['identifier']];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function usesExposed() {
|
||||
$filters = $this->getHandlers('filter');
|
||||
foreach ($filters as $filter_name => $filter) {
|
||||
if ($filter->isExposed() && !empty($filter->exposedInfo())) {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Exposed widgets typically only work with ajax in Drupal core, however
|
||||
* #2605218 totally breaks the rest of the functionality in this display and
|
||||
* in Core's Block display as well, so we allow non-ajax block views to use
|
||||
* exposed filters and manually set the #action to the current request uri.
|
||||
*/
|
||||
public function elementPreRender(array $element) {
|
||||
/** @var \Drupal\views\ViewExecutable $view */
|
||||
$view = $element['#view'];
|
||||
if (!empty($view->exposed_widgets['#action']) && !$view->ajaxEnabled()) {
|
||||
$view->exposed_widgets['#action'] = \Drupal::request()->getRequestUri();
|
||||
}
|
||||
return parent::elementPreRender($element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort field config array by weight.
|
||||
*
|
||||
* @param $a
|
||||
* @param $b
|
||||
* @return int
|
||||
*/
|
||||
public static function sortFieldsByWeight($a, $b) {
|
||||
$a_weight = isset($a['weight']) ? $a['weight'] : 0;
|
||||
$b_weight = isset($b['weight']) ? $b['weight'] : 0;
|
||||
if ($a_weight == $b_weight) {
|
||||
return 0;
|
||||
}
|
||||
return ($a_weight < $b_weight) ? -1 : 1;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,350 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools_views\Tests;
|
||||
|
||||
use Drupal\views_ui\Tests\UITestBase;
|
||||
use Drupal\views\Tests\ViewTestData;
|
||||
use Drupal\Core\StringTranslation\StringTranslationTrait;
|
||||
|
||||
/**
|
||||
* Tests the ctools_views block display plugin
|
||||
* overriding settings from a basic View.
|
||||
*
|
||||
* @group ctools_views
|
||||
* @see \Drupal\ctools_views\Plugin\Display\Block
|
||||
*/
|
||||
class CToolsViewsBasicViewBlockTest extends UITestBase {
|
||||
|
||||
use StringTranslationTrait;
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('ctools_views', 'ctools_views_test_views');
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = array('ctools_views_test_view');
|
||||
|
||||
/**
|
||||
* The block storage.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityStorageInterface
|
||||
*/
|
||||
protected $storage;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
ViewTestData::createTestViews(get_class($this), array('ctools_views_test_views'));
|
||||
$this->storage = $this->container->get('entity.manager')->getStorage('block');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test ctools_views "items_per_page" configuration.
|
||||
*/
|
||||
public function testItemsPerPage() {
|
||||
$default_theme = $this->config('system.theme')->get('default');
|
||||
|
||||
// Get the "Configure block" form for our Views block.
|
||||
$this->drupalGet('admin/structure/block/add/views_block:ctools_views_test_view-block_pager/' . $default_theme);
|
||||
$this->assertFieldByXPath('//input[@type="number" and @name="settings[override][items_per_page]"]', NULL, 'items_per_page setting is a number field');
|
||||
// Add block to sidebar_first region with default settings.
|
||||
$edit = array();
|
||||
$edit['region'] = 'sidebar_first';
|
||||
$edit['settings[override][items_per_page]'] = 0;
|
||||
$this->drupalPostForm('admin/structure/block/add/views_block:ctools_views_test_view-block_pager/' . $default_theme, $edit, $this->t('Save block'));
|
||||
|
||||
// Assert items per page default settings.
|
||||
$this->drupalGet('<front>');
|
||||
$result = $this->xpath('//div[contains(@class, "region-sidebar-first")]/div[contains(@class, "block-views")]/h2');
|
||||
$this->assertEqual((string) $result[0], 'CTools Views Pager Block');
|
||||
$this->assertRaw('Showing 3 records on page 1');
|
||||
$this->assertEqual(3, count($this->xpath('//div[contains(@class, "view-display-id-block_pager")]//table/tbody/tr')));
|
||||
|
||||
// Override items per page settings.
|
||||
$edit = array();
|
||||
$edit['region'] = 'sidebar_first';
|
||||
$edit['settings[override][items_per_page]'] = 2;
|
||||
$this->drupalPostForm('admin/structure/block/manage/views_block__ctools_views_test_view_block_pager', $edit, $this->t('Save block'));
|
||||
|
||||
$block = $this->storage->load('views_block__ctools_views_test_view_block_pager');
|
||||
$config = $block->getPlugin()->getConfiguration();
|
||||
$this->assertEqual(2, $config['items_per_page'], "'Items per page' is properly saved.");
|
||||
|
||||
// Assert items per page overridden settings.
|
||||
$this->drupalGet('<front>');
|
||||
$result = $this->xpath('//div[contains(@class, "region-sidebar-first")]/div[contains(@class, "block-views")]/h2');
|
||||
$this->assertEqual((string) $result[0], 'CTools Views Pager Block');
|
||||
$this->assertRaw('Showing 2 records on page 1');
|
||||
$this->assertEqual(2, count($this->xpath('//div[contains(@class, "view-display-id-block_pager")]//table/tbody/tr')));
|
||||
$this->assertEqual([1, 2], $this->xpath('//div[contains(@class, "view-display-id-block_pager")]//table//tr//td[contains(@class, "views-field-id")]'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test ctools_views "offset" configuration.
|
||||
*/
|
||||
public function testOffset() {
|
||||
$default_theme = $this->config('system.theme')->get('default');
|
||||
|
||||
// Get the "Configure block" form for our Views block.
|
||||
$this->drupalGet('admin/structure/block/add/views_block:ctools_views_test_view-block_pager/' . $default_theme);
|
||||
$this->assertFieldByXPath('//input[@type="number" and @name="settings[override][pager_offset]"]', NULL, 'items_per_page setting is a number field');
|
||||
// Add block to sidebar_first region with default settings.
|
||||
$edit = array();
|
||||
$edit['region'] = 'sidebar_first';
|
||||
$edit['settings[override][items_per_page]'] = 0;
|
||||
$this->drupalPostForm('admin/structure/block/add/views_block:ctools_views_test_view-block_pager/' . $default_theme, $edit, $this->t('Save block'));
|
||||
|
||||
// Assert pager offset default settings.
|
||||
$this->drupalGet('<front>');
|
||||
$this->assertEqual([1, 2, 3], $this->xpath('//div[contains(@class, "view-display-id-block_pager")]//table//tr//td[contains(@class, "views-field-id")]'));
|
||||
|
||||
// Override pager offset settings.
|
||||
$edit = array();
|
||||
$edit['region'] = 'sidebar_first';
|
||||
$edit['settings[override][items_per_page]'] = 0;
|
||||
$edit['settings[override][pager_offset]'] = 1;
|
||||
$this->drupalPostForm('admin/structure/block/manage/views_block__ctools_views_test_view_block_pager', $edit, $this->t('Save block'));
|
||||
|
||||
$block = $this->storage->load('views_block__ctools_views_test_view_block_pager');
|
||||
$config = $block->getPlugin()->getConfiguration();
|
||||
$this->assertEqual(1, $config['pager_offset'], "'Pager offset' is properly saved.");
|
||||
|
||||
// Assert pager offset overridden settings.
|
||||
$this->drupalGet('<front>');
|
||||
$this->assertEqual([2, 3, 4], $this->xpath('//div[contains(@class, "view-display-id-block_pager")]//table//tr//td[contains(@class, "views-field-id")]'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test ctools_views "pager" configuration.
|
||||
*/
|
||||
public function testPager() {
|
||||
$default_theme = $this->config('system.theme')->get('default');
|
||||
|
||||
// Get the "Configure block" form for our Views block.
|
||||
$this->drupalGet('admin/structure/block/add/views_block:ctools_views_test_view-block_pager/' . $default_theme);
|
||||
$this->assertFieldById('edit-settings-override-pager-view', 'view');
|
||||
$this->assertFieldById('edit-settings-override-pager-some');
|
||||
$this->assertFieldById('edit-settings-override-pager-none');
|
||||
|
||||
// Add block to sidebar_first region with default settings.
|
||||
$edit = array();
|
||||
$edit['region'] = 'sidebar_first';
|
||||
$edit['settings[override][items_per_page]'] = 0;
|
||||
$this->drupalPostForm('admin/structure/block/add/views_block:ctools_views_test_view-block_pager/' . $default_theme, $edit, $this->t('Save block'));
|
||||
|
||||
// Assert pager default settings.
|
||||
$this->drupalGet('<front>');
|
||||
$this->assertText('Page 1');
|
||||
$this->assertText('Next ›');
|
||||
|
||||
// Override pager settings to 'some'.
|
||||
$edit = array();
|
||||
$edit['region'] = 'sidebar_first';
|
||||
$edit['settings[override][items_per_page]'] = 0;
|
||||
$edit['settings[override][pager]'] = 'some';
|
||||
$this->drupalPostForm('admin/structure/block/manage/views_block__ctools_views_test_view_block_pager', $edit, $this->t('Save block'));
|
||||
|
||||
$block = $this->storage->load('views_block__ctools_views_test_view_block_pager');
|
||||
$config = $block->getPlugin()->getConfiguration();
|
||||
$this->assertEqual('some', $config['pager'], "'Pager' setting is properly saved.");
|
||||
|
||||
// Assert pager overridden settings to 'some', showing no pager.
|
||||
$this->drupalGet('<front>');
|
||||
$this->assertEqual(3, count($this->xpath('//div[contains(@class, "view-display-id-block_pager")]//table/tbody/tr')));
|
||||
$this->assertNoText('Page 1');
|
||||
$this->assertNoText('Next ›');
|
||||
|
||||
// Override pager settings to 'none'.
|
||||
$edit = array();
|
||||
$edit['region'] = 'sidebar_first';
|
||||
$edit['settings[override][items_per_page]'] = 0;
|
||||
$edit['settings[override][pager]'] = 'none';
|
||||
$this->drupalPostForm('admin/structure/block/manage/views_block__ctools_views_test_view_block_pager', $edit, $this->t('Save block'));
|
||||
|
||||
$block = $this->storage->load('views_block__ctools_views_test_view_block_pager');
|
||||
$config = $block->getPlugin()->getConfiguration();
|
||||
$this->assertEqual('none', $config['pager'], "'Pager' setting is properly saved.");
|
||||
|
||||
// Assert pager overridden settings to 'some', showing no pager.
|
||||
$this->drupalGet('<front>');
|
||||
$this->assertEqual(5, count($this->xpath('//div[contains(@class, "view-display-id-block_pager")]//table/tbody/tr')));
|
||||
$this->assertNoText('Page 1');
|
||||
$this->assertNoText('Next ›');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test ctools_views 'hide_fields' configuration.
|
||||
*/
|
||||
public function testHideFields() {
|
||||
$default_theme = $this->config('system.theme')->get('default');
|
||||
|
||||
// Get the "Configure block" form for our Views block.
|
||||
$this->drupalGet('admin/structure/block/add/views_block:ctools_views_test_view-block_fields/' . $default_theme);
|
||||
$this->assertFieldById('edit-settings-override-order-fields-id-hide');
|
||||
|
||||
// Add block to sidebar_first region with default settings.
|
||||
$edit = array();
|
||||
$edit['region'] = 'sidebar_first';
|
||||
$this->drupalPostForm('admin/structure/block/add/views_block:ctools_views_test_view-block_fields/' . $default_theme, $edit, $this->t('Save block'));
|
||||
|
||||
// Assert hide_fields default settings.
|
||||
$this->drupalGet('<front>');
|
||||
$this->assertEqual(5, count($this->xpath('//div[contains(@class, "view-display-id-block_fields")]//table//td[contains(@class, "views-field-id")]')));
|
||||
|
||||
// Override hide_fields settings.
|
||||
$edit = array();
|
||||
$edit['region'] = 'sidebar_first';
|
||||
$edit['settings[override][order_fields][id][hide]'] = 1;
|
||||
$this->drupalPostForm('admin/structure/block/manage/views_block__ctools_views_test_view_block_fields', $edit, $this->t('Save block'));
|
||||
|
||||
$block = $this->storage->load('views_block__ctools_views_test_view_block_fields');
|
||||
$config = $block->getPlugin()->getConfiguration();
|
||||
$this->assertEqual(1, $config['fields']['id']['hide'], "'hide_fields' setting is properly saved.");
|
||||
$this->assertEqual(0, $config['fields']['name']['hide'], "'hide_fields' setting is properly saved.");
|
||||
|
||||
// Assert hide_fields overridden settings.
|
||||
$this->drupalGet('<front>');
|
||||
$this->assertEqual(0, count($this->xpath('//div[contains(@class, "view-display-id-block_fields")]//table//td[contains(@class, "views-field-id")]')));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test ctools_views 'sort_fields' configuration.
|
||||
*/
|
||||
public function testOrderFields() {
|
||||
$default_theme = $this->config('system.theme')->get('default');
|
||||
|
||||
// Get the "Configure block" form for our Views block.
|
||||
$this->drupalGet('admin/structure/block/add/views_block:ctools_views_test_view-block_fields/' . $default_theme);
|
||||
$this->assertFieldById('edit-settings-override-order-fields-id-weight', 0);
|
||||
|
||||
// Add block to sidebar_first region with default settings.
|
||||
$edit = array();
|
||||
$edit['region'] = 'sidebar_first';
|
||||
$this->drupalPostForm('admin/structure/block/add/views_block:ctools_views_test_view-block_fields/' . $default_theme, $edit, $this->t('Save block'));
|
||||
|
||||
// Assert sort_fields default settings.
|
||||
$this->drupalGet('<front>');
|
||||
// Check that the td with class "views-field-id" is the first td in the first tr element.
|
||||
$this->assertEqual(0, count($this->xpath('count(//div[contains(@class, "view-display-id-block_fields")]//table//tr[1]//td[contains(@class, "views-field-id")]/preceding-sibling::td)')));
|
||||
|
||||
// Override sort_fields settings.
|
||||
$edit = array();
|
||||
$edit['region'] = 'sidebar_first';
|
||||
$edit['settings[override][order_fields][name][weight]'] = -50;
|
||||
$edit['settings[override][order_fields][age][weight]'] = -49;
|
||||
$edit['settings[override][order_fields][job][weight]'] = -48;
|
||||
$edit['settings[override][order_fields][created][weight]'] = -47;
|
||||
$edit['settings[override][order_fields][id][weight]'] = -46;
|
||||
$edit['settings[override][order_fields][name_1][weight]'] = -45;
|
||||
$this->drupalPostForm('admin/structure/block/manage/views_block__ctools_views_test_view_block_fields', $edit, $this->t('Save block'));
|
||||
|
||||
$block = $this->storage->load('views_block__ctools_views_test_view_block_fields');
|
||||
$config = $block->getPlugin()->getConfiguration();
|
||||
$this->assertEqual(-46, $config['fields']['id']['weight'], "'sort_fields' setting is properly saved.");
|
||||
$this->assertEqual(-50, $config['fields']['name']['weight'], "'sort_fields' setting is properly saved.");
|
||||
|
||||
// Assert sort_fields overridden settings.
|
||||
$this->drupalGet('<front>');
|
||||
|
||||
// Check that the td with class "views-field-id" is the 5th td in the first tr element.
|
||||
$this->assertEqual(4, count($this->xpath('//div[contains(@class, "view-display-id-block_fields")]//table//tr[1]//td[contains(@class, "views-field-id")]/preceding-sibling::td')));
|
||||
|
||||
// Check that duplicate fields in the View produce expected outpu
|
||||
$name1_element = $this->xpath('//div[contains(@class, "view-display-id-block_fields")]//table//tr[1]/td[contains(@class, "views-field-name")]/text()');
|
||||
$name1 = (string) $name1_element[0];
|
||||
$this->assertEqual("John", trim($name1));
|
||||
$name2_element = $this->xpath('//div[contains(@class, "view-display-id-block_fields")]//table//tr[1]/td[contains(@class, "views-field-name-1")]/text()');
|
||||
$name2 = (string) $name2_element[0];
|
||||
$this->assertEqual("John", trim($name2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test ctools_views 'disable_filters' configuration.
|
||||
*/
|
||||
public function testDisableFilters() {
|
||||
$default_theme = $this->config('system.theme')->get('default');
|
||||
|
||||
// Get the "Configure block" form for our Views block.
|
||||
$this->drupalGet('admin/structure/block/add/views_block:ctools_views_test_view-block_filter/' . $default_theme);
|
||||
$this->assertFieldById('edit-settings-override-filters-status-disable');
|
||||
$this->assertFieldById('edit-settings-override-filters-job-disable');
|
||||
|
||||
// Add block to sidebar_first region with default settings.
|
||||
$edit = array();
|
||||
$edit['region'] = 'sidebar_first';
|
||||
$this->drupalPostForm('admin/structure/block/add/views_block:ctools_views_test_view-block_filter/' . $default_theme, $edit, $this->t('Save block'));
|
||||
|
||||
// Assert disable_filters default settings.
|
||||
$this->drupalGet('<front>');
|
||||
// Check that the default settings show both filters
|
||||
$this->assertFieldByXPath('//select[@name="status"]');
|
||||
$this->assertFieldByXPath('//input[@name="job"]');
|
||||
|
||||
// Override disable_filters settings.
|
||||
$edit = array();
|
||||
$edit['region'] = 'sidebar_first';
|
||||
$edit['settings[override][filters][status][disable]'] = 1;
|
||||
$edit['settings[override][filters][job][disable]'] = 1;
|
||||
$this->drupalPostForm('admin/structure/block/manage/views_block__ctools_views_test_view_block_filter', $edit, $this->t('Save block'));
|
||||
|
||||
$block = $this->storage->load('views_block__ctools_views_test_view_block_filter');
|
||||
$config = $block->getPlugin()->getConfiguration();
|
||||
$this->assertEqual(1, $config['filter']['status']['disable'], "'disable_filters' setting is properly saved.");
|
||||
$this->assertEqual(1, $config['filter']['job']['disable'], "'disable_filters' setting is properly saved.");
|
||||
|
||||
// Assert disable_filters overridden settings.
|
||||
$this->drupalGet('<front>');
|
||||
$this->assertNoFieldByXPath('//select[@name="status"]');
|
||||
$this->assertNoFieldByXPath('//input[@name="job"]');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test ctools_views 'configure_sorts' configuration.
|
||||
*/
|
||||
public function testConfigureSorts() {
|
||||
$default_theme = $this->config('system.theme')->get('default');
|
||||
|
||||
// Get the "Configure block" form for our Views block.
|
||||
$this->drupalGet('admin/structure/block/add/views_block:ctools_views_test_view-block_sort/' . $default_theme);
|
||||
$this->assertFieldByXPath('//input[@name="settings[override][sort][id][order]"]');
|
||||
|
||||
// Add block to sidebar_first region with default settings.
|
||||
$edit = array();
|
||||
$edit['region'] = 'sidebar_first';
|
||||
$this->drupalPostForm('admin/structure/block/add/views_block:ctools_views_test_view-block_sort/' . $default_theme, $edit, $this->t('Save block'));
|
||||
|
||||
// Assert configure_sorts default settings.
|
||||
$this->drupalGet('<front>');
|
||||
// Check that the results are sorted ASC
|
||||
$element = $this->xpath('//div[contains(@class, "view-display-id-block_sort")]//table//tr[1]/td[1]/text()');
|
||||
$value = (string) $element[0];
|
||||
$this->assertEqual("1", trim($value));
|
||||
|
||||
// Override configure_sorts settings.
|
||||
$edit = array();
|
||||
$edit['region'] = 'sidebar_first';
|
||||
$edit['settings[override][sort][id][order]'] = "DESC";
|
||||
$this->drupalPostForm('admin/structure/block/manage/views_block__ctools_views_test_view_block_sort', $edit, $this->t('Save block'));
|
||||
|
||||
$block = $this->storage->load('views_block__ctools_views_test_view_block_sort');
|
||||
$config = $block->getPlugin()->getConfiguration();
|
||||
$this->assertEqual("DESC", $config['sort']['id'], "'configure_sorts' setting is properly saved.");
|
||||
|
||||
// Assert configure_sorts overridden settings.
|
||||
// Check that the results are sorted DESC
|
||||
$this->drupalGet('<front>');
|
||||
$element = $this->xpath('//div[contains(@class, "view-display-id-block_sort")]//table//tr[1]/td[1]/text()');
|
||||
$value = (string) $element[0];
|
||||
$this->assertEqual("5", trim($value));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
name: 'CTools Views test views'
|
||||
type: module
|
||||
description: 'Provides default views for CTools Views tests.'
|
||||
package: Testing
|
||||
# core: 8.x
|
||||
dependencies:
|
||||
- views
|
||||
- block
|
||||
- entity_test
|
||||
- ctools_views
|
||||
- text
|
||||
- user
|
||||
- node
|
||||
- taxonomy
|
||||
|
||||
# Information added by Drupal.org packaging script on 2017-04-28
|
||||
version: '8.x-3.0'
|
||||
core: '8.x'
|
||||
project: 'ctools'
|
||||
datestamp: 1493401747
|
|
@ -0,0 +1,543 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- node.type.ctools_views
|
||||
- taxonomy.vocabulary.tags
|
||||
module:
|
||||
- datetime
|
||||
- node
|
||||
- options
|
||||
- taxonomy
|
||||
- user
|
||||
id: ctools_views_entity_test
|
||||
label: 'CTools Views Entity Test View'
|
||||
module: views
|
||||
description: ''
|
||||
tag: ''
|
||||
base_table: node_field_data
|
||||
base_field: nid
|
||||
core: 8.x
|
||||
display:
|
||||
default:
|
||||
display_plugin: default
|
||||
id: default
|
||||
display_title: Master
|
||||
position: 0
|
||||
display_options:
|
||||
access:
|
||||
type: perm
|
||||
options:
|
||||
perm: 'access content'
|
||||
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: false
|
||||
reset_button_label: Reset
|
||||
exposed_sorts_label: 'Sort by'
|
||||
expose_sort_order: true
|
||||
sort_asc_label: Asc
|
||||
sort_desc_label: Desc
|
||||
pager:
|
||||
type: none
|
||||
options:
|
||||
offset: 0
|
||||
style:
|
||||
type: table
|
||||
row:
|
||||
type: fields
|
||||
fields:
|
||||
title:
|
||||
id: title
|
||||
table: node_field_data
|
||||
field: title
|
||||
entity_type: node
|
||||
entity_field: title
|
||||
alter:
|
||||
alter_text: false
|
||||
make_link: false
|
||||
absolute: false
|
||||
trim: false
|
||||
word_boundary: false
|
||||
ellipsis: false
|
||||
strip_tags: false
|
||||
html: false
|
||||
hide_empty: false
|
||||
empty_zero: false
|
||||
settings:
|
||||
link_to_entity: true
|
||||
plugin_id: field
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
label: Title
|
||||
exclude: 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_alter_empty: true
|
||||
click_sort_column: value
|
||||
type: string
|
||||
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
|
||||
filters:
|
||||
status:
|
||||
value: true
|
||||
table: node_field_data
|
||||
field: status
|
||||
plugin_id: boolean
|
||||
entity_type: node
|
||||
entity_field: status
|
||||
id: status
|
||||
expose:
|
||||
operator: ''
|
||||
group: 1
|
||||
type:
|
||||
id: type
|
||||
table: node_field_data
|
||||
field: type
|
||||
value:
|
||||
ctools_views: ctools_views
|
||||
entity_type: node
|
||||
entity_field: type
|
||||
plugin_id: bundle
|
||||
sorts:
|
||||
created:
|
||||
id: created
|
||||
table: node_field_data
|
||||
field: created
|
||||
order: DESC
|
||||
entity_type: node
|
||||
entity_field: created
|
||||
plugin_id: date
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
exposed: false
|
||||
expose:
|
||||
label: ''
|
||||
granularity: second
|
||||
title: 'CTools Views Entity Test View'
|
||||
header: { }
|
||||
footer: { }
|
||||
empty: { }
|
||||
relationships: { }
|
||||
arguments: { }
|
||||
display_extenders: { }
|
||||
cache_metadata:
|
||||
max-age: 0
|
||||
contexts:
|
||||
- 'languages:language_content'
|
||||
- 'languages:language_interface'
|
||||
- 'user.node_grants:view'
|
||||
- user.permissions
|
||||
tags: { }
|
||||
block_filter_date:
|
||||
display_plugin: block
|
||||
id: block_filter_date
|
||||
display_title: 'Date filter'
|
||||
position: 4
|
||||
display_options:
|
||||
display_extenders: { }
|
||||
display_description: ''
|
||||
title: 'Date filter'
|
||||
defaults:
|
||||
title: false
|
||||
filters: false
|
||||
filter_groups: false
|
||||
filters:
|
||||
status:
|
||||
value: true
|
||||
table: node_field_data
|
||||
field: status
|
||||
plugin_id: boolean
|
||||
entity_type: node
|
||||
entity_field: status
|
||||
id: status
|
||||
expose:
|
||||
operator: ''
|
||||
group: 1
|
||||
type:
|
||||
id: type
|
||||
table: node_field_data
|
||||
field: type
|
||||
value:
|
||||
ctools_views: ctools_views
|
||||
entity_type: node
|
||||
entity_field: type
|
||||
plugin_id: bundle
|
||||
group: 1
|
||||
field_ctools_views_date_value:
|
||||
id: field_ctools_views_date_value
|
||||
table: node__field_ctools_views_date
|
||||
field: field_ctools_views_date_value
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
operator: between
|
||||
group: 1
|
||||
exposed: true
|
||||
expose:
|
||||
operator_id: field_ctools_views_date_value_op
|
||||
label: 'CTools Views Date (field_ctools_views_date)'
|
||||
description: ''
|
||||
use_operator: false
|
||||
operator: field_ctools_views_date_value_op
|
||||
identifier: field_ctools_views_date_value
|
||||
required: false
|
||||
remember: false
|
||||
multiple: false
|
||||
remember_roles:
|
||||
authenticated: authenticated
|
||||
anonymous: '0'
|
||||
administrator1: '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: { }
|
||||
plugin_id: datetime
|
||||
filter_groups:
|
||||
operator: AND
|
||||
groups:
|
||||
1: AND
|
||||
allow:
|
||||
items_per_page: false
|
||||
offset: '0'
|
||||
pager: '0'
|
||||
hide_fields: '0'
|
||||
sort_fields: '0'
|
||||
disable_filters: '0'
|
||||
cache_metadata:
|
||||
max-age: 0
|
||||
contexts:
|
||||
- 'languages:language_content'
|
||||
- 'languages:language_interface'
|
||||
- url
|
||||
- 'user.node_grants:view'
|
||||
- user.permissions
|
||||
tags: { }
|
||||
block_filter_list:
|
||||
display_plugin: block
|
||||
id: block_filter_list
|
||||
display_title: 'List filter'
|
||||
position: 3
|
||||
display_options:
|
||||
display_extenders: { }
|
||||
display_description: ''
|
||||
title: 'List filter'
|
||||
defaults:
|
||||
title: false
|
||||
filters: false
|
||||
filter_groups: false
|
||||
filters:
|
||||
status:
|
||||
value: true
|
||||
table: node_field_data
|
||||
field: status
|
||||
plugin_id: boolean
|
||||
entity_type: node
|
||||
entity_field: status
|
||||
id: status
|
||||
expose:
|
||||
operator: ''
|
||||
group: 1
|
||||
type:
|
||||
id: type
|
||||
table: node_field_data
|
||||
field: type
|
||||
value:
|
||||
ctools_views: ctools_views
|
||||
entity_type: node
|
||||
entity_field: type
|
||||
plugin_id: bundle
|
||||
field_ctools_views_list_value:
|
||||
id: field_ctools_views_list_value
|
||||
table: node__field_ctools_views_list
|
||||
field: field_ctools_views_list_value
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
operator: or
|
||||
value: { }
|
||||
group: 1
|
||||
exposed: true
|
||||
expose:
|
||||
operator_id: field_ctools_views_list_value_op
|
||||
label: 'Ctools Views List (field_ctools_views_list)'
|
||||
description: ''
|
||||
use_operator: false
|
||||
operator: field_ctools_views_list_value_op
|
||||
identifier: field_ctools_views_list_value
|
||||
required: false
|
||||
remember: false
|
||||
multiple: false
|
||||
remember_roles:
|
||||
authenticated: authenticated
|
||||
anonymous: '0'
|
||||
administrator1: '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: { }
|
||||
reduce_duplicates: false
|
||||
plugin_id: list_field
|
||||
filter_groups:
|
||||
operator: AND
|
||||
groups:
|
||||
1: AND
|
||||
allow:
|
||||
items_per_page: false
|
||||
offset: '0'
|
||||
pager: '0'
|
||||
hide_fields: '0'
|
||||
sort_fields: '0'
|
||||
disable_filters: '0'
|
||||
cache_metadata:
|
||||
max-age: 0
|
||||
contexts:
|
||||
- 'languages:language_content'
|
||||
- 'languages:language_interface'
|
||||
- url
|
||||
- 'user.node_grants:view'
|
||||
- user.permissions
|
||||
tags: { }
|
||||
block_filter_tax:
|
||||
display_plugin: block
|
||||
id: block_filter_tax
|
||||
display_title: 'Taxonomy filter'
|
||||
position: 2
|
||||
display_options:
|
||||
display_extenders: { }
|
||||
display_description: ''
|
||||
title: 'Taxonomy filter'
|
||||
defaults:
|
||||
title: false
|
||||
filters: false
|
||||
filter_groups: false
|
||||
filters:
|
||||
status:
|
||||
value: true
|
||||
table: node_field_data
|
||||
field: status
|
||||
plugin_id: boolean
|
||||
entity_type: node
|
||||
entity_field: status
|
||||
id: status
|
||||
expose:
|
||||
operator: ''
|
||||
group: 1
|
||||
type:
|
||||
id: type
|
||||
table: node_field_data
|
||||
field: type
|
||||
value:
|
||||
ctools_views: ctools_views
|
||||
entity_type: node
|
||||
entity_field: type
|
||||
plugin_id: bundle
|
||||
group: 1
|
||||
field_ctools_views_tags_target_id:
|
||||
id: field_ctools_views_tags_target_id
|
||||
table: node__field_ctools_views_tags
|
||||
field: field_ctools_views_tags_target_id
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
operator: or
|
||||
value: { }
|
||||
group: 1
|
||||
exposed: true
|
||||
expose:
|
||||
operator_id: field_ctools_views_tags_target_id_op
|
||||
label: 'Tags (field_ctools_views_tags)'
|
||||
description: ''
|
||||
use_operator: false
|
||||
operator: field_ctools_views_tags_target_id_op
|
||||
identifier: field_ctools_views_tags_target_id
|
||||
required: false
|
||||
remember: false
|
||||
multiple: false
|
||||
remember_roles:
|
||||
authenticated: authenticated
|
||||
anonymous: '0'
|
||||
administrator1: '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: { }
|
||||
reduce_duplicates: false
|
||||
type: select
|
||||
limit: true
|
||||
vid: tags
|
||||
hierarchy: false
|
||||
error_message: true
|
||||
plugin_id: taxonomy_index_tid
|
||||
filter_groups:
|
||||
operator: AND
|
||||
groups:
|
||||
1: AND
|
||||
allow:
|
||||
items_per_page: false
|
||||
offset: '0'
|
||||
pager: '0'
|
||||
hide_fields: '0'
|
||||
sort_fields: '0'
|
||||
disable_filters: '0'
|
||||
cache_metadata:
|
||||
max-age: 0
|
||||
contexts:
|
||||
- 'languages:language_content'
|
||||
- 'languages:language_interface'
|
||||
- url
|
||||
- user
|
||||
- 'user.node_grants:view'
|
||||
- user.permissions
|
||||
tags: { }
|
||||
block_filter_text:
|
||||
display_plugin: block
|
||||
id: block_filter_text
|
||||
display_title: 'Textfield filter'
|
||||
position: 1
|
||||
display_options:
|
||||
display_extenders: { }
|
||||
display_description: ''
|
||||
title: 'Textfield filter'
|
||||
defaults:
|
||||
title: false
|
||||
filters: false
|
||||
filter_groups: false
|
||||
filters:
|
||||
status:
|
||||
value: true
|
||||
table: node_field_data
|
||||
field: status
|
||||
plugin_id: boolean
|
||||
entity_type: node
|
||||
entity_field: status
|
||||
id: status
|
||||
expose:
|
||||
operator: ''
|
||||
group: 1
|
||||
type:
|
||||
id: type
|
||||
table: node_field_data
|
||||
field: type
|
||||
value:
|
||||
ctools_views: ctools_views
|
||||
entity_type: node
|
||||
entity_field: type
|
||||
plugin_id: bundle
|
||||
field_ctools_views_text_value:
|
||||
id: field_ctools_views_text_value
|
||||
table: node__field_ctools_views_text
|
||||
field: field_ctools_views_text_value
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
operator: '='
|
||||
value: ''
|
||||
group: 1
|
||||
exposed: true
|
||||
expose:
|
||||
operator_id: field_ctools_views_text_value_op
|
||||
label: 'Text (field_ctools_views_text)'
|
||||
description: ''
|
||||
use_operator: false
|
||||
operator: field_ctools_views_text_value_op
|
||||
identifier: field_ctools_views_text_value
|
||||
required: false
|
||||
remember: false
|
||||
multiple: false
|
||||
remember_roles:
|
||||
authenticated: authenticated
|
||||
anonymous: '0'
|
||||
administrator1: '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: { }
|
||||
plugin_id: string
|
||||
filter_groups:
|
||||
operator: AND
|
||||
groups:
|
||||
1: AND
|
||||
allow:
|
||||
items_per_page: false
|
||||
offset: '0'
|
||||
pager: '0'
|
||||
hide_fields: '0'
|
||||
sort_fields: '0'
|
||||
disable_filters: '0'
|
||||
cache_metadata:
|
||||
max-age: 0
|
||||
contexts:
|
||||
- 'languages:language_content'
|
||||
- 'languages:language_interface'
|
||||
- url
|
||||
- 'user.node_grants:view'
|
||||
- user.permissions
|
||||
tags: { }
|
|
@ -0,0 +1,949 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies: { }
|
||||
id: ctools_views_test_view
|
||||
label: 'CTools Views Test View'
|
||||
module: views
|
||||
description: ''
|
||||
tag: ''
|
||||
base_table: views_test_data
|
||||
base_field: id
|
||||
core: 8.x
|
||||
display:
|
||||
default:
|
||||
display_plugin: default
|
||||
id: default
|
||||
display_title: Master
|
||||
position: 0
|
||||
display_options:
|
||||
access:
|
||||
type: none
|
||||
options: { }
|
||||
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: false
|
||||
reset_button_label: Reset
|
||||
exposed_sorts_label: 'Sort by'
|
||||
expose_sort_order: true
|
||||
sort_asc_label: Asc
|
||||
sort_desc_label: Desc
|
||||
pager:
|
||||
type: none
|
||||
options:
|
||||
offset: 0
|
||||
style:
|
||||
type: table
|
||||
options:
|
||||
grouping: { }
|
||||
row_class: ''
|
||||
default_row_class: true
|
||||
override: true
|
||||
sticky: false
|
||||
caption: ''
|
||||
summary: ''
|
||||
description: ''
|
||||
columns:
|
||||
id: id
|
||||
age: age
|
||||
created: created
|
||||
id_1: id_1
|
||||
job: job
|
||||
name: name
|
||||
info:
|
||||
id:
|
||||
sortable: false
|
||||
default_sort_order: asc
|
||||
align: ''
|
||||
separator: ''
|
||||
empty_column: false
|
||||
responsive: ''
|
||||
age:
|
||||
sortable: false
|
||||
default_sort_order: asc
|
||||
align: ''
|
||||
separator: ''
|
||||
empty_column: false
|
||||
responsive: ''
|
||||
created:
|
||||
sortable: false
|
||||
default_sort_order: asc
|
||||
align: ''
|
||||
separator: ''
|
||||
empty_column: false
|
||||
responsive: ''
|
||||
id_1:
|
||||
sortable: false
|
||||
default_sort_order: asc
|
||||
align: ''
|
||||
separator: ''
|
||||
empty_column: false
|
||||
responsive: ''
|
||||
job:
|
||||
sortable: false
|
||||
default_sort_order: asc
|
||||
align: ''
|
||||
separator: ''
|
||||
empty_column: false
|
||||
responsive: ''
|
||||
name:
|
||||
sortable: false
|
||||
default_sort_order: asc
|
||||
align: ''
|
||||
separator: ''
|
||||
empty_column: false
|
||||
responsive: ''
|
||||
default: '-1'
|
||||
empty_table: false
|
||||
row:
|
||||
type: fields
|
||||
fields:
|
||||
id:
|
||||
id: id
|
||||
table: views_test_data
|
||||
field: id
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
label: ID
|
||||
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
|
||||
set_precision: false
|
||||
precision: 0
|
||||
decimal: .
|
||||
separator: ''
|
||||
format_plural: false
|
||||
format_plural_string: "1\x03@count"
|
||||
prefix: ''
|
||||
suffix: ''
|
||||
entity_type: null
|
||||
entity_field: null
|
||||
plugin_id: numeric
|
||||
name:
|
||||
id: name
|
||||
table: views_test_data
|
||||
field: name
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
label: Name
|
||||
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
|
||||
plugin_id: standard
|
||||
age:
|
||||
id: age
|
||||
table: views_test_data
|
||||
field: age
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
label: Age
|
||||
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
|
||||
set_precision: false
|
||||
precision: 0
|
||||
decimal: .
|
||||
separator: ''
|
||||
format_plural: false
|
||||
format_plural_string: "1\x03@count"
|
||||
prefix: ''
|
||||
suffix: ''
|
||||
plugin_id: numeric
|
||||
job:
|
||||
id: job
|
||||
table: views_test_data
|
||||
field: job
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
label: Job
|
||||
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
|
||||
plugin_id: standard
|
||||
created:
|
||||
id: created
|
||||
table: views_test_data
|
||||
field: created
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
label: Created
|
||||
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
|
||||
date_format: fallback
|
||||
custom_date_format: ''
|
||||
timezone: ''
|
||||
plugin_id: date
|
||||
filters: { }
|
||||
sorts:
|
||||
id:
|
||||
id: id
|
||||
table: views_test_data
|
||||
field: id
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
order: ASC
|
||||
exposed: false
|
||||
expose:
|
||||
label: ''
|
||||
plugin_id: standard
|
||||
title: 'CTools Views Test View'
|
||||
header: { }
|
||||
footer: { }
|
||||
empty: { }
|
||||
relationships: { }
|
||||
arguments: { }
|
||||
display_extenders: { }
|
||||
use_ajax: false
|
||||
filter_groups:
|
||||
operator: AND
|
||||
groups: { }
|
||||
cache_metadata:
|
||||
max-age: 0
|
||||
contexts:
|
||||
- 'languages:language_interface'
|
||||
tags: { }
|
||||
block_fields:
|
||||
display_plugin: block
|
||||
id: block_fields
|
||||
display_title: 'CTools Views Fields Block'
|
||||
position: 2
|
||||
display_options:
|
||||
display_extenders: { }
|
||||
block_category: 'CTools Views'
|
||||
allow:
|
||||
hide_fields: hide_fields
|
||||
sort_fields: sort_fields
|
||||
items_per_page: false
|
||||
offset: '0'
|
||||
pager: '0'
|
||||
disable_filters: '0'
|
||||
block_description: 'CTools Views Fields Block'
|
||||
display_description: ''
|
||||
pager:
|
||||
type: none
|
||||
options:
|
||||
offset: 0
|
||||
defaults:
|
||||
pager: false
|
||||
title: false
|
||||
fields: false
|
||||
title: 'CTools Views Fields Block'
|
||||
fields:
|
||||
id:
|
||||
id: id
|
||||
table: views_test_data
|
||||
field: id
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
label: ID
|
||||
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
|
||||
set_precision: false
|
||||
precision: 0
|
||||
decimal: .
|
||||
separator: ''
|
||||
format_plural: false
|
||||
format_plural_string: "1\x03@count"
|
||||
prefix: ''
|
||||
suffix: ''
|
||||
entity_type: null
|
||||
entity_field: null
|
||||
plugin_id: numeric
|
||||
name:
|
||||
id: name
|
||||
table: views_test_data
|
||||
field: name
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
label: Name
|
||||
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
|
||||
plugin_id: standard
|
||||
age:
|
||||
id: age
|
||||
table: views_test_data
|
||||
field: age
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
label: Age
|
||||
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
|
||||
set_precision: false
|
||||
precision: 0
|
||||
decimal: .
|
||||
separator: ''
|
||||
format_plural: false
|
||||
format_plural_string: "1\x03@count"
|
||||
prefix: ''
|
||||
suffix: ''
|
||||
plugin_id: numeric
|
||||
job:
|
||||
id: job
|
||||
table: views_test_data
|
||||
field: job
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
label: Job
|
||||
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
|
||||
plugin_id: standard
|
||||
created:
|
||||
id: created
|
||||
table: views_test_data
|
||||
field: created
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
label: Created
|
||||
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
|
||||
date_format: fallback
|
||||
custom_date_format: ''
|
||||
timezone: ''
|
||||
plugin_id: date
|
||||
name_1:
|
||||
id: name_1
|
||||
table: views_test_data
|
||||
field: name
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
label: '2nd name field'
|
||||
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
|
||||
plugin_id: standard
|
||||
cache_metadata:
|
||||
max-age: 0
|
||||
contexts:
|
||||
- 'languages:language_interface'
|
||||
tags: { }
|
||||
block_filter:
|
||||
display_plugin: block
|
||||
id: block_filter
|
||||
display_title: 'CTools Views Filter Block'
|
||||
position: 3
|
||||
display_options:
|
||||
display_extenders: { }
|
||||
display_description: ''
|
||||
block_category: 'CTools Views'
|
||||
block_description: 'CTools Views Filter Block'
|
||||
allow:
|
||||
disable_filters: disable_filters
|
||||
items_per_page: false
|
||||
offset: '0'
|
||||
pager: '0'
|
||||
hide_fields: '0'
|
||||
sort_fields: '0'
|
||||
filters:
|
||||
status:
|
||||
id: status
|
||||
table: views_test_data
|
||||
field: status
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
operator: '='
|
||||
value: true
|
||||
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'
|
||||
administrator1: '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: { }
|
||||
plugin_id: boolean
|
||||
job:
|
||||
id: job
|
||||
table: views_test_data
|
||||
field: job
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
operator: '='
|
||||
value: ''
|
||||
group: 1
|
||||
exposed: true
|
||||
expose:
|
||||
operator_id: job_op
|
||||
label: Job
|
||||
description: ''
|
||||
use_operator: false
|
||||
operator: job_op
|
||||
identifier: job
|
||||
required: false
|
||||
remember: false
|
||||
multiple: false
|
||||
remember_roles:
|
||||
authenticated: authenticated
|
||||
anonymous: '0'
|
||||
administrator1: '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: { }
|
||||
plugin_id: string
|
||||
defaults:
|
||||
filters: false
|
||||
filter_groups: false
|
||||
title: false
|
||||
filter_groups:
|
||||
operator: AND
|
||||
groups:
|
||||
1: AND
|
||||
title: 'CTools Views Filter Block'
|
||||
cache_metadata:
|
||||
max-age: 0
|
||||
contexts:
|
||||
- 'languages:language_interface'
|
||||
- url
|
||||
tags: { }
|
||||
block_pager:
|
||||
display_plugin: block
|
||||
id: block_pager
|
||||
display_title: 'CTools Views Pager Block'
|
||||
position: 1
|
||||
display_options:
|
||||
display_extenders: { }
|
||||
block_description: 'CTools Views Pager Block'
|
||||
block_category: 'CTools Views'
|
||||
allow:
|
||||
items_per_page: true
|
||||
offset: offset
|
||||
pager: pager
|
||||
hide_fields: '0'
|
||||
sort_fields: '0'
|
||||
disable_filters: '0'
|
||||
display_description: ''
|
||||
header:
|
||||
result:
|
||||
id: result
|
||||
table: views
|
||||
field: result
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
empty: false
|
||||
content: "Displaying @start - @end of @total\nShowing @current_record_count records on page @current_page"
|
||||
plugin_id: result
|
||||
defaults:
|
||||
header: false
|
||||
pager: false
|
||||
title: false
|
||||
pager:
|
||||
type: mini
|
||||
options:
|
||||
items_per_page: 3
|
||||
offset: 0
|
||||
id: 0
|
||||
total_pages: null
|
||||
tags:
|
||||
previous: '‹ Previous'
|
||||
next: 'Next ›'
|
||||
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
|
||||
title: 'CTools Views Pager Block'
|
||||
cache_metadata:
|
||||
max-age: 0
|
||||
contexts:
|
||||
- 'languages:language_interface'
|
||||
- url.query_args
|
||||
tags: { }
|
||||
block_sort:
|
||||
display_plugin: block
|
||||
id: block_sort
|
||||
display_title: 'CTools Views Sort Block'
|
||||
position: 4
|
||||
display_options:
|
||||
display_extenders: { }
|
||||
display_description: ''
|
||||
title: 'CTools Views Sort Block'
|
||||
defaults:
|
||||
title: false
|
||||
block_description: 'CTools Views Sort Block'
|
||||
block_category: 'CTools Views'
|
||||
allow:
|
||||
configure_sorts: configure_sorts
|
||||
items_per_page: false
|
||||
offset: '0'
|
||||
pager: '0'
|
||||
hide_fields: '0'
|
||||
sort_fields: '0'
|
||||
disable_filters: '0'
|
||||
cache_metadata:
|
||||
max-age: 0
|
||||
contexts:
|
||||
- 'languages:language_interface'
|
||||
tags: { }
|
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools\Access;
|
||||
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
|
||||
interface AccessInterface {
|
||||
public function access(AccountInterface $account);
|
||||
}
|
51
web/modules/contrib/ctools/src/Access/TempstoreAccess.php
Normal file
51
web/modules/contrib/ctools/src/Access/TempstoreAccess.php
Normal file
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools\Access;
|
||||
|
||||
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
use Drupal\Core\Routing\Access\AccessInterface as CoreAccessInterface;
|
||||
use Drupal\Core\Routing\RouteMatch;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\ctools\Access\AccessInterface as CToolsAccessInterface;
|
||||
use Drupal\user\SharedTempStoreFactory;
|
||||
use Symfony\Component\Routing\Route;
|
||||
|
||||
class TempstoreAccess implements CoreAccessInterface {
|
||||
|
||||
/**
|
||||
* The shared tempstore factory.
|
||||
*
|
||||
* @var \Drupal\user\SharedTempStoreFactory
|
||||
*/
|
||||
protected $tempstore;
|
||||
|
||||
public function __construct(SharedTempStoreFactory $tempstore) {
|
||||
$this->tempstore = $tempstore;
|
||||
}
|
||||
|
||||
protected function getTempstore() {
|
||||
return $this->tempstore;
|
||||
}
|
||||
|
||||
public function access(Route $route, RouteMatch $match, AccountInterface $account) {
|
||||
$tempstore_id = $match->getParameter('tempstore_id') ? $match->getParameter('tempstore_id') : $route->getDefault('tempstore_id');
|
||||
$id = $match->getParameter($route->getRequirement('_ctools_access'));
|
||||
if ($tempstore_id && $id) {
|
||||
$cached_values = $this->getTempstore()->get($tempstore_id)->get($id);
|
||||
if (!empty($cached_values['access']) && ($cached_values['access'] instanceof CToolsAccessInterface)) {
|
||||
$access = $cached_values['access']->access($account);
|
||||
}
|
||||
else {
|
||||
$access = AccessResult::allowed();
|
||||
}
|
||||
}
|
||||
else {
|
||||
$access = AccessResult::forbidden();
|
||||
}
|
||||
// The different wizards will have different tempstore ids and adding this
|
||||
// cache context allows us to nuance the access per wizard.
|
||||
$access->addCacheContexts(['url.query_args:tempstore_id']);
|
||||
return $access;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools\Ajax;
|
||||
|
||||
use Drupal\Core\Ajax\OpenModalDialogCommand;
|
||||
|
||||
class OpenModalWizardCommand extends OpenModalDialogCommand {
|
||||
|
||||
public function __construct($object, $tempstore_id, array $parameters = array(), array $dialog_options = array(), $settings = NULL) {
|
||||
// Instantiate the wizard class properly.
|
||||
$parameters += [
|
||||
'tempstore_id' => $tempstore_id,
|
||||
'machine_name' => NULL,
|
||||
'step' => NULL,
|
||||
];
|
||||
$form = \Drupal::service('ctools.wizard.factory')->getWizardForm($object, $parameters, TRUE);
|
||||
$title = isset($form['#title']) ? $form['#title'] : '';
|
||||
$content = $form;
|
||||
|
||||
parent::__construct($title, $content, $dialog_options, $settings);
|
||||
}
|
||||
|
||||
}
|
54
web/modules/contrib/ctools/src/Annotation/Relationship.php
Normal file
54
web/modules/contrib/ctools/src/Annotation/Relationship.php
Normal file
|
@ -0,0 +1,54 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools\Annotation;
|
||||
|
||||
use Drupal\Component\Annotation\Plugin;
|
||||
|
||||
/**
|
||||
* Defines a Relationship item annotation object.
|
||||
*
|
||||
* @see \Drupal\ctools\Plugin\RelationshipManager
|
||||
* @see plugin_api
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class Relationship extends Plugin {
|
||||
|
||||
/**
|
||||
* The plugin ID.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* The label of the plugin.
|
||||
*
|
||||
* @var \Drupal\Core\Annotation\Translation
|
||||
*
|
||||
* @ingroup plugin_translatable
|
||||
*/
|
||||
public $label;
|
||||
|
||||
/**
|
||||
* The returned data type of this relationship
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $data_type;
|
||||
|
||||
/**
|
||||
* The name of the property from which this relationship is derived.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $property_name;
|
||||
|
||||
/**
|
||||
* The array of contexts requires or optional for this plugin.
|
||||
*
|
||||
* @var \Drupal\Core\Plugin\Context\ContextInterface[]
|
||||
*/
|
||||
public $context;
|
||||
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools;
|
||||
|
||||
|
||||
interface ConstraintConditionInterface {
|
||||
|
||||
/**
|
||||
* Applies relevant constraints for this condition to the injected contexts.
|
||||
*
|
||||
* @param \Drupal\Core\Plugin\Context\ContextInterface[] $contexts
|
||||
*
|
||||
* @return NULL
|
||||
*/
|
||||
public function applyConstraints(array $contexts = array());
|
||||
|
||||
/**
|
||||
* Removes constraints for this condition from the injected contexts.
|
||||
*
|
||||
* @param \Drupal\Core\Plugin\Context\ContextInterface[] $contexts
|
||||
*
|
||||
* @return NULL
|
||||
*/
|
||||
public function removeConstraints(array $contexts = array());
|
||||
|
||||
}
|
25
web/modules/contrib/ctools/src/Context/AutomaticContext.php
Normal file
25
web/modules/contrib/ctools/src/Context/AutomaticContext.php
Normal file
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools\Context;
|
||||
|
||||
use Drupal\Core\Plugin\Context\Context;
|
||||
|
||||
/**
|
||||
* Provides a class to indicate that this context is always present.
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @todo Move into core.
|
||||
*/
|
||||
class AutomaticContext extends Context {
|
||||
|
||||
/**
|
||||
* Returns TRUE if this context is automatic and always available.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isAutomatic() {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools\Context;
|
||||
|
||||
use Drupal\Core\Entity\EntityRepositoryInterface;
|
||||
use Drupal\Core\Plugin\Context\Context;
|
||||
use Drupal\Core\Plugin\Context\ContextDefinitionInterface;
|
||||
|
||||
/**
|
||||
* @todo.
|
||||
*/
|
||||
class EntityLazyLoadContext extends Context {
|
||||
|
||||
/**
|
||||
* The entity UUID.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $uuid;
|
||||
|
||||
/**
|
||||
* The entity repository.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityRepositoryInterface
|
||||
*/
|
||||
protected $entityRepository;
|
||||
|
||||
/**
|
||||
* Construct an EntityLazyLoadContext object.
|
||||
*
|
||||
* @param \Drupal\Core\Plugin\Context\ContextDefinitionInterface $context_definition
|
||||
* The context definition.
|
||||
* @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository
|
||||
* The entity repository.
|
||||
* @param string $uuid
|
||||
* The UUID of the entity.
|
||||
*/
|
||||
public function __construct(ContextDefinitionInterface $context_definition, EntityRepositoryInterface $entity_repository, $uuid) {
|
||||
parent::__construct($context_definition);
|
||||
$this->entityRepository = $entity_repository;
|
||||
$this->uuid = $uuid;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getContextValue() {
|
||||
if (!$this->contextData) {
|
||||
$entity_type_id = substr($this->contextDefinition->getDataType(), 7);
|
||||
$this->setContextValue($this->entityRepository->loadEntityByUuid($entity_type_id, $this->uuid));
|
||||
}
|
||||
return parent::getContextValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function hasContextValue() {
|
||||
// Ensure that the entity is loaded before checking if it exists.
|
||||
if (!$this->contextData) {
|
||||
$this->getContextValue();
|
||||
}
|
||||
return parent::hasContextValue();
|
||||
}
|
||||
|
||||
}
|
50
web/modules/contrib/ctools/src/ContextMapper.php
Normal file
50
web/modules/contrib/ctools/src/ContextMapper.php
Normal file
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools;
|
||||
|
||||
use Drupal\Core\Entity\EntityRepositoryInterface;
|
||||
use Drupal\Core\Plugin\Context\Context;
|
||||
use Drupal\Core\Plugin\Context\ContextDefinition;
|
||||
use Drupal\ctools\Context\EntityLazyLoadContext;
|
||||
|
||||
/**
|
||||
* Maps context configurations to context objects.
|
||||
*/
|
||||
class ContextMapper implements ContextMapperInterface {
|
||||
|
||||
/**
|
||||
* The entity repository.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityRepositoryInterface
|
||||
*/
|
||||
protected $entityRepository;
|
||||
|
||||
/**
|
||||
* Constructs a new ContextMapper.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository
|
||||
* The entity repository.
|
||||
*/
|
||||
public function __construct(EntityRepositoryInterface $entity_repository) {
|
||||
$this->entityRepository = $entity_repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getContextValues(array $context_configurations) {
|
||||
$contexts = [];
|
||||
foreach ($context_configurations as $name => $context_configuration) {
|
||||
$context_definition = new ContextDefinition($context_configuration['type'], $context_configuration['label'], TRUE, FALSE, $context_configuration['description']);
|
||||
if (strpos($context_configuration['type'], 'entity:') === 0) {
|
||||
$context = new EntityLazyLoadContext($context_definition, $this->entityRepository, $context_configuration['value']);
|
||||
}
|
||||
else {
|
||||
$context = new Context($context_definition, $context_configuration['value']);
|
||||
}
|
||||
$contexts[$name] = $context;
|
||||
}
|
||||
return $contexts;
|
||||
}
|
||||
|
||||
}
|
21
web/modules/contrib/ctools/src/ContextMapperInterface.php
Normal file
21
web/modules/contrib/ctools/src/ContextMapperInterface.php
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools;
|
||||
|
||||
/**
|
||||
* Provides an interface for mapping context configurations to context objects.
|
||||
*/
|
||||
interface ContextMapperInterface {
|
||||
|
||||
/**
|
||||
* Gathers the static context values.
|
||||
*
|
||||
* @param array[] $static_context_configurations
|
||||
* An array of static context configurations.
|
||||
*
|
||||
* @return \Drupal\Component\Plugin\Context\ContextInterface[]
|
||||
* An array of set context values, keyed by context name.
|
||||
*/
|
||||
public function getContextValues(array $static_context_configurations);
|
||||
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools;
|
||||
|
||||
|
||||
class ContextNotFoundException extends \Exception {}
|
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools\Controller;
|
||||
|
||||
use Drupal\Core\Controller\ControllerResolverInterface;
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Form\FormBuilderInterface;
|
||||
use Drupal\Core\Routing\RouteMatchInterface;
|
||||
use Drupal\ctools\Wizard\WizardFactoryInterface;
|
||||
|
||||
/**
|
||||
* Wrapping controller for wizard forms that serve as the main page body.
|
||||
*/
|
||||
class WizardEntityFormController extends WizardFormController {
|
||||
|
||||
/**
|
||||
* The entity manager service.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityManagerInterface
|
||||
*/
|
||||
protected $entityManager;
|
||||
|
||||
/**
|
||||
* @param \Drupal\Core\Controller\ControllerResolverInterface $controller_resolver
|
||||
* The controller resolver.
|
||||
* @param \Drupal\Core\Form\FormBuilderInterface $form_builder
|
||||
* The form builder.
|
||||
* @param \Drupal\ctools\Wizard\WizardFactoryInterface $wizard_factory
|
||||
* The wizard factory.
|
||||
* @param \Drupal\Core\Entity\EntityManagerInterface $manager
|
||||
* The entity manager.
|
||||
*/
|
||||
public function __construct(ControllerResolverInterface $controller_resolver, FormBuilderInterface $form_builder, WizardFactoryInterface $wizard_factory, EntityManagerInterface $manager) {
|
||||
parent::__construct($controller_resolver, $form_builder, $wizard_factory);
|
||||
$this->entityManager = $manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getFormArgument(RouteMatchInterface $route_match) {
|
||||
$form_arg = $route_match->getRouteObject()->getDefault('_entity_wizard');
|
||||
list($entity_type_id, $operation) = explode('.', $form_arg);
|
||||
$definition = $this->entityManager->getDefinition($entity_type_id);
|
||||
$handlers = $definition->getHandlerClasses();
|
||||
if (empty($handlers['wizard'][$operation])) {
|
||||
throw new \Exception(sprintf('Unsupported wizard operation %s', $operation));
|
||||
}
|
||||
return $handlers['wizard'][$operation];
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools\Controller;
|
||||
|
||||
use Drupal\Core\Controller\ControllerResolverInterface;
|
||||
use Drupal\Core\Controller\FormController;
|
||||
use Drupal\Core\Form\FormBuilderInterface;
|
||||
use Drupal\Core\Routing\RouteMatchInterface;
|
||||
use Drupal\ctools\Wizard\FormWizardInterface;
|
||||
use Drupal\ctools\Wizard\WizardFactoryInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* Wrapping controller for wizard forms that serve as the main page body.
|
||||
*/
|
||||
class WizardFormController extends FormController {
|
||||
|
||||
/**
|
||||
* The class resolver.
|
||||
*
|
||||
* @var \Drupal\Core\DependencyInjection\ClassResolverInterface;
|
||||
*/
|
||||
protected $classResolver;
|
||||
|
||||
/**
|
||||
* Tempstore Factory for keeping track of values in each step of the wizard.
|
||||
*
|
||||
* @var \Drupal\user\SharedTempStoreFactory
|
||||
*/
|
||||
protected $tempstore;
|
||||
|
||||
/**
|
||||
* The event dispatcher.
|
||||
*
|
||||
* @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
|
||||
*/
|
||||
protected $dispatcher;
|
||||
|
||||
/**
|
||||
* @param \Drupal\Core\Controller\ControllerResolverInterface $controller_resolver
|
||||
* The controller resolver.
|
||||
* @param \Drupal\Core\Form\FormBuilderInterface $form_builder
|
||||
* The form builder.
|
||||
* @param \Drupal\ctools\Wizard\WizardFactoryInterface $wizard_factory
|
||||
* The wizard factory.
|
||||
*/
|
||||
public function __construct(ControllerResolverInterface $controller_resolver, FormBuilderInterface $form_builder, WizardFactoryInterface $wizard_factory) {
|
||||
parent::__construct($controller_resolver, $form_builder);
|
||||
$this->wizardFactory = $wizard_factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getFormArgument(RouteMatchInterface $route_match) {
|
||||
return $route_match->getRouteObject()->getDefault('_wizard');
|
||||
}
|
||||
|
||||
/**
|
||||
* Wizards are not instantiated as simply as forms, so this method is unused.
|
||||
*/
|
||||
protected function getFormObject(RouteMatchInterface $route_match, $form_arg) {
|
||||
if (!is_subclass_of($form_arg, '\Drupal\ctools\Wizard\FormWizardInterface')) {
|
||||
throw new \Exception("The _wizard default must reference a class instance of \\Drupal\\ctools\\Wizard\\FormWizardInterface.");
|
||||
}
|
||||
$parameters = $route_match->getParameters()->all();
|
||||
$parameters += $form_arg::getParameters();
|
||||
$parameters['route_match'] = $route_match;
|
||||
return $this->wizardFactory->createWizard($form_arg, $parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getContentResult(Request $request, RouteMatchInterface $route_match) {
|
||||
$wizard = $this->getFormObject($route_match, $this->getFormArgument($route_match));
|
||||
$ajax = $request->attributes->get('js') == 'ajax' ? TRUE : FALSE;
|
||||
|
||||
return $this->wizardFactory->getWizardForm($wizard, $request->attributes->all(), $ajax);
|
||||
}
|
||||
|
||||
}
|
41
web/modules/contrib/ctools/src/Event/WizardEvent.php
Normal file
41
web/modules/contrib/ctools/src/Event/WizardEvent.php
Normal file
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools\Event;
|
||||
|
||||
use Drupal\ctools\Wizard\FormWizardInterface;
|
||||
use Symfony\Component\EventDispatcher\Event;
|
||||
|
||||
/**
|
||||
* An event for altering form wizard values.
|
||||
*/
|
||||
class WizardEvent extends Event {
|
||||
|
||||
/**
|
||||
* @var \Drupal\ctools\Wizard\FormWizardInterface
|
||||
*/
|
||||
protected $wizard;
|
||||
|
||||
/**
|
||||
* @var mixed
|
||||
*/
|
||||
protected $values;
|
||||
|
||||
function __construct(FormWizardInterface $wizard, $values) {
|
||||
$this->wizard = $wizard;
|
||||
$this->values = $values;
|
||||
}
|
||||
|
||||
public function getWizard() {
|
||||
return $this->wizard;
|
||||
}
|
||||
|
||||
public function getValues() {
|
||||
return $this->values;
|
||||
}
|
||||
|
||||
public function setValues($values) {
|
||||
$this->values = $values;
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
43
web/modules/contrib/ctools/src/Form/AjaxFormTrait.php
Normal file
43
web/modules/contrib/ctools/src/Form/AjaxFormTrait.php
Normal file
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools\Form;
|
||||
|
||||
use Drupal\Component\Serialization\Json;
|
||||
use Drupal\Component\Utility\NestedArray;
|
||||
|
||||
/**
|
||||
* Provides helper methods for using an AJAX modal.
|
||||
*/
|
||||
trait AjaxFormTrait {
|
||||
|
||||
/**
|
||||
* Gets attributes for use with an AJAX modal.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getAjaxAttributes() {
|
||||
return [
|
||||
'class' => ['use-ajax'],
|
||||
'data-dialog-type' => 'modal',
|
||||
'data-dialog-options' => Json::encode([
|
||||
'width' => 'auto',
|
||||
]),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets attributes for use with an add button AJAX modal.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getAjaxButtonAttributes() {
|
||||
return NestedArray::mergeDeep(AjaxFormTrait::getAjaxAttributes(), [
|
||||
'class' => [
|
||||
'button',
|
||||
'button--small',
|
||||
'button-action',
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
182
web/modules/contrib/ctools/src/Form/ConditionConfigure.php
Normal file
182
web/modules/contrib/ctools/src/Form/ConditionConfigure.php
Normal file
|
@ -0,0 +1,182 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools\Form;
|
||||
|
||||
|
||||
use Drupal\Component\Plugin\PluginManagerInterface;
|
||||
use Drupal\Component\Uuid\Uuid;
|
||||
use Drupal\Core\Ajax\AjaxResponse;
|
||||
use Drupal\Core\Ajax\CloseModalDialogCommand;
|
||||
use Drupal\Core\Ajax\RedirectCommand;
|
||||
use Drupal\Core\Form\FormBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Plugin\ContextAwarePluginInterface;
|
||||
use Drupal\ctools\ConstraintConditionInterface;
|
||||
use Drupal\user\SharedTempStoreFactory;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Base class for condition configur operations.
|
||||
*/
|
||||
abstract class ConditionConfigure extends FormBase {
|
||||
|
||||
/**
|
||||
* @var \Drupal\user\SharedTempStoreFactory
|
||||
*/
|
||||
protected $tempstore;
|
||||
|
||||
/**
|
||||
* @var \Drupal\Core\Condition\ConditionManager
|
||||
*/
|
||||
protected $manager;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $tempstore_id;
|
||||
|
||||
/**
|
||||
* @var string;
|
||||
*/
|
||||
protected $machine_name;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static($container->get('user.shared_tempstore'), $container->get('plugin.manager.condition'));
|
||||
}
|
||||
|
||||
function __construct(SharedTempStoreFactory $tempstore, PluginManagerInterface $manager) {
|
||||
$this->tempstore = $tempstore;
|
||||
$this->manager = $manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'ctools_condition_configure';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state, $condition = NULL, $tempstore_id = NULL, $machine_name = NULL) {
|
||||
$this->tempstore_id = $tempstore_id;
|
||||
$this->machine_name = $machine_name;
|
||||
$cached_values = $this->tempstore->get($this->tempstore_id)->get($this->machine_name);
|
||||
if (is_numeric($condition) || Uuid::isValid($condition)) {
|
||||
$id = $condition;
|
||||
$condition = $this->getConditions($cached_values)[$id];
|
||||
$instance = $this->manager->createInstance($condition['id'], $condition);
|
||||
}
|
||||
else {
|
||||
$instance = $this->manager->createInstance($condition, []);
|
||||
}
|
||||
$form_state->setTemporaryValue('gathered_contexts', $this->getContexts($cached_values));
|
||||
/** @var $instance \Drupal\Core\Condition\ConditionInterface */
|
||||
$form = $instance->buildConfigurationForm($form, $form_state);
|
||||
if (isset($id)) {
|
||||
// Conditionally set this form element so that we can update or add.
|
||||
$form['id'] = [
|
||||
'#type' => 'value',
|
||||
'#value' => $id
|
||||
];
|
||||
}
|
||||
$form['instance'] = [
|
||||
'#type' => 'value',
|
||||
'#value' => $instance
|
||||
];
|
||||
$form['submit'] = [
|
||||
'#type' => 'submit',
|
||||
'#value' => $this->t('Save'),
|
||||
'#ajax' => [
|
||||
'callback' => [$this, 'ajaxSave'],
|
||||
]
|
||||
];
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
$cached_values = $this->tempstore->get($this->tempstore_id)->get($this->machine_name);
|
||||
/** @var $instance \Drupal\Core\Condition\ConditionInterface */
|
||||
$instance = $form_state->getValue('instance');
|
||||
$instance->submitConfigurationForm($form, $form_state);
|
||||
$conditions = $this->getConditions($cached_values);
|
||||
if ($instance instanceof ContextAwarePluginInterface) {
|
||||
/** @var $instance \Drupal\Core\Plugin\ContextAwarePluginInterface */
|
||||
$context_mapping = $form_state->hasValue('context_mapping')? $form_state->getValue('context_mapping') : [];
|
||||
$instance->setContextMapping($context_mapping);
|
||||
}
|
||||
if ($instance instanceof ConstraintConditionInterface) {
|
||||
/** @var $instance \Drupal\ctools\ConstraintConditionInterface */
|
||||
$instance->applyConstraints($this->getContexts($cached_values));
|
||||
}
|
||||
if ($form_state->hasValue('id')) {
|
||||
$conditions[$form_state->getValue('id')] = $instance->getConfiguration();
|
||||
}
|
||||
else {
|
||||
$conditions[] = $instance->getConfiguration();
|
||||
}
|
||||
$cached_values = $this->setConditions($cached_values, $conditions);
|
||||
$this->tempstore->get($this->tempstore_id)->set($this->machine_name, $cached_values);
|
||||
list($route_name, $route_parameters) = $this->getParentRouteInfo($cached_values);
|
||||
$form_state->setRedirect($route_name, $route_parameters);
|
||||
}
|
||||
|
||||
public function ajaxSave(array &$form, FormStateInterface $form_state) {
|
||||
$response = new AjaxResponse();
|
||||
$cached_values = $this->tempstore->get($this->tempstore_id)->get($this->machine_name);
|
||||
list($route_name, $route_parameters) = $this->getParentRouteInfo($cached_values);
|
||||
$response->addCommand(new RedirectCommand($this->url($route_name, $route_parameters)));
|
||||
$response->addCommand(new CloseModalDialogCommand());
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Document the route name and parameters for redirect after submission.
|
||||
*
|
||||
* @param $cached_values
|
||||
*
|
||||
* @return array
|
||||
* In the format of
|
||||
* return ['route.name', ['machine_name' => $this->machine_name, 'step' => 'step_name']];
|
||||
*/
|
||||
abstract protected function getParentRouteInfo($cached_values);
|
||||
|
||||
/**
|
||||
* Custom logic for retrieving the conditions array from cached_values.
|
||||
*
|
||||
* @param $cached_values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
abstract protected function getConditions($cached_values);
|
||||
|
||||
/**
|
||||
* Custom logic for setting the conditions array in cached_values.
|
||||
*
|
||||
* @param $cached_values
|
||||
*
|
||||
* @param $conditions
|
||||
* The conditions to set within the cached values.
|
||||
*
|
||||
* @return mixed
|
||||
* Return the $cached_values
|
||||
*/
|
||||
abstract protected function setConditions($cached_values, $conditions);
|
||||
|
||||
/**
|
||||
* Custom logic for retrieving the contexts array from cached_values.
|
||||
*
|
||||
* @param $cached_values
|
||||
*
|
||||
* @return \Drupal\Core\Plugin\Context\ContextInterface[]
|
||||
*/
|
||||
abstract protected function getContexts($cached_values);
|
||||
|
||||
}
|
210
web/modules/contrib/ctools/src/Form/ConditionDelete.php
Normal file
210
web/modules/contrib/ctools/src/Form/ConditionDelete.php
Normal file
|
@ -0,0 +1,210 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools\Form;
|
||||
|
||||
use Drupal\Component\Plugin\PluginManagerInterface;
|
||||
use Drupal\Core\Form\ConfirmFormBase;
|
||||
use Drupal\Core\Form\ConfirmFormHelper;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\ctools\ConstraintConditionInterface;
|
||||
use Drupal\user\SharedTempStoreFactory;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
abstract class ConditionDelete extends ConfirmFormBase {
|
||||
|
||||
/**
|
||||
* @var \Drupal\user\SharedTempStoreFactory
|
||||
*/
|
||||
protected $tempstore;
|
||||
|
||||
/**
|
||||
* @var \Drupal\Core\Condition\ConditionManager
|
||||
*/
|
||||
protected $manager;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $tempstore_id;
|
||||
|
||||
/**
|
||||
* @var string;
|
||||
*/
|
||||
protected $machine_name;
|
||||
|
||||
/**
|
||||
* @var int;
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static($container->get('user.shared_tempstore'), $container->get('plugin.manager.condition'));
|
||||
}
|
||||
|
||||
function __construct(SharedTempStoreFactory $tempstore, PluginManagerInterface $manager) {
|
||||
$this->tempstore = $tempstore;
|
||||
$this->manager = $manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'ctools_condition_delete';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state, $id = NULL, $tempstore_id = NULL, $machine_name = NULL) {
|
||||
$this->tempstore_id = $tempstore_id;
|
||||
$this->machine_name = $machine_name;
|
||||
$this->id = $id;
|
||||
|
||||
$cached_values = $this->tempstore->get($this->tempstore_id)->get($this->machine_name);
|
||||
$form ['#title'] = $this->getQuestion($id, $cached_values);
|
||||
|
||||
$form ['#attributes']['class'][] = 'confirmation';
|
||||
$form ['description'] = array('#markup' => $this->getDescription());
|
||||
$form [$this->getFormName()] = array('#type' => 'hidden', '#value' => 1);
|
||||
|
||||
// By default, render the form using theme_confirm_form().
|
||||
if (!isset($form ['#theme'])) {
|
||||
$form ['#theme'] = 'confirm_form';
|
||||
}
|
||||
$form['actions'] = array('#type' => 'actions');
|
||||
$form['actions'] += $this->actions($form, $form_state);
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
$cached_values = $this->tempstore->get($this->tempstore_id)->get($this->machine_name);
|
||||
$conditions = $this->getConditions($cached_values);
|
||||
/** @var $instance \Drupal\ctools\ConstraintConditionInterface */
|
||||
$instance = $this->manager->createInstance($conditions[$this->id]['id'], $conditions[$this->id]);
|
||||
if ($instance instanceof ConstraintConditionInterface) {
|
||||
$instance->removeConstraints($this->getContexts($cached_values));
|
||||
}
|
||||
unset($conditions[$this->id]);
|
||||
$cached_values = $this->setConditions($cached_values, $conditions);
|
||||
$this->tempstore->get($this->tempstore_id)->set($this->machine_name, $cached_values);
|
||||
list($route_name, $route_parameters) = $this->getParentRouteInfo($cached_values);
|
||||
$form_state->setRedirect($route_name, $route_parameters);
|
||||
}
|
||||
|
||||
public function getQuestion($id = NULL, $cached_values = NULL) {
|
||||
$condition = $this->getConditions($cached_values)[$id];
|
||||
return $this->t('Are you sure you want to delete the @label condition?', array(
|
||||
'@label' => $condition['id'],
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDescription() {
|
||||
return $this->t('This action cannot be undone.');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormName() {
|
||||
return 'confirm';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function actions(array $form, FormStateInterface $form_state) {
|
||||
return array(
|
||||
'submit' => array(
|
||||
'#type' => 'submit',
|
||||
'#value' => $this->getConfirmText(),
|
||||
'#validate' => array(
|
||||
array($this, 'validateForm'),
|
||||
),
|
||||
'#submit' => array(
|
||||
array($this, 'submitForm'),
|
||||
),
|
||||
),
|
||||
'cancel' => ConfirmFormHelper::buildCancelLink($this, $this->getRequest()),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the route to go to if the user cancels the action.
|
||||
*
|
||||
* @return \Drupal\Core\Url
|
||||
* A URL object.
|
||||
*/
|
||||
public function getCancelUrl() {
|
||||
$cached_values = $this->tempstore->get($this->tempstore_id)->get($this->machine_name);
|
||||
list($route_name, $route_parameters) = $this->getParentRouteInfo($cached_values);
|
||||
return new Url($route_name, $route_parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getConfirmText() {
|
||||
return $this->t('Delete');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCancelText() {
|
||||
return $this->t('Cancel');
|
||||
}
|
||||
|
||||
/**
|
||||
* Document the route name and parameters for redirect after submission.
|
||||
*
|
||||
* @param $cached_values
|
||||
*
|
||||
* @return array
|
||||
* In the format of
|
||||
* return ['route.name', ['machine_name' => $this->machine_name, 'step' => 'step_name]];
|
||||
*/
|
||||
abstract protected function getParentRouteInfo($cached_values);
|
||||
|
||||
/**
|
||||
* Custom logic for retrieving the conditions array from cached_values.
|
||||
*
|
||||
* @param $cached_values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
abstract protected function getConditions($cached_values);
|
||||
|
||||
/**
|
||||
* Custom logic for setting the conditions array in cached_values.
|
||||
*
|
||||
* @param $cached_values
|
||||
*
|
||||
* @param $conditions
|
||||
* The conditions to set within the cached values.
|
||||
*
|
||||
* @return mixed
|
||||
* Return the $cached_values
|
||||
*/
|
||||
abstract protected function setConditions($cached_values, $conditions);
|
||||
|
||||
/**
|
||||
* Custom logic for retrieving the contexts array from cached_values.
|
||||
*
|
||||
* @param $cached_values
|
||||
*
|
||||
* @return \Drupal\Core\Plugin\Context\ContextInterface[]
|
||||
*/
|
||||
abstract protected function getContexts($cached_values);
|
||||
|
||||
}
|
254
web/modules/contrib/ctools/src/Form/ContextConfigure.php
Normal file
254
web/modules/contrib/ctools/src/Form/ContextConfigure.php
Normal file
|
@ -0,0 +1,254 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools\Form;
|
||||
|
||||
|
||||
use Drupal\Core\Ajax\AjaxResponse;
|
||||
use Drupal\Core\Ajax\CloseModalDialogCommand;
|
||||
use Drupal\Core\Ajax\RedirectCommand;
|
||||
use Drupal\Core\Entity\Entity;
|
||||
use Drupal\Core\Entity\Plugin\DataType\EntityAdapter;
|
||||
use Drupal\Core\Form\FormBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Plugin\Context\Context;
|
||||
use Drupal\Core\Plugin\Context\ContextDefinition;
|
||||
use Drupal\Core\Plugin\Context\ContextInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\user\SharedTempStoreFactory;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
abstract class ContextConfigure extends FormBase {
|
||||
|
||||
/**
|
||||
* @var \Drupal\user\SharedTempStoreFactory
|
||||
*/
|
||||
protected $tempstore;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $tempstore_id;
|
||||
|
||||
/**
|
||||
* @var string;
|
||||
*/
|
||||
protected $machine_name;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static($container->get('user.shared_tempstore'));
|
||||
}
|
||||
|
||||
function __construct(SharedTempStoreFactory $tempstore) {
|
||||
$this->tempstore = $tempstore;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'ctools_context_configure';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state, $context_id = NULL, $tempstore_id = NULL, $machine_name = NULL) {
|
||||
$this->tempstore_id = $tempstore_id;
|
||||
$this->machine_name = $machine_name;
|
||||
$cached_values = $this->tempstore->get($this->tempstore_id)->get($this->machine_name);
|
||||
$contexts = $this->getContexts($cached_values);
|
||||
$edit = FALSE;
|
||||
if (!empty($contexts[$context_id])) {
|
||||
$context = $contexts[$context_id];
|
||||
$machine_name = $context_id;
|
||||
$edit = TRUE;
|
||||
}
|
||||
else {
|
||||
$context_definition = new ContextDefinition($context_id);
|
||||
$context = new Context($context_definition);
|
||||
$machine_name = '';
|
||||
}
|
||||
$label = $context->getContextDefinition()->getLabel();
|
||||
$description = $context->getContextDefinition()->getDescription();
|
||||
$data_type = $context->getContextDefinition()->getDataType();
|
||||
$form['#attached']['library'][] = 'core/drupal.dialog.ajax';
|
||||
$form['context_id'] = [
|
||||
'#type' => 'value',
|
||||
'#value' => $context_id
|
||||
];
|
||||
$form['label'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Label'),
|
||||
'#default_value' => $label,
|
||||
'#required' => TRUE,
|
||||
];
|
||||
$form['machine_name'] = [
|
||||
'#type' => 'machine_name',
|
||||
'#title' => $this->t('Machine Name'),
|
||||
'#default_value' => $machine_name,
|
||||
'#required' => TRUE,
|
||||
'#maxlength' => 128,
|
||||
'#machine_name' => [
|
||||
'source' => ['label'],
|
||||
'exists' => [$this, 'contextExists'],
|
||||
],
|
||||
'#disabled' => $this->disableMachineName($cached_values, $machine_name),
|
||||
];
|
||||
$form['description'] = [
|
||||
'#type' => 'textarea',
|
||||
'#title' => $this->t('Description'),
|
||||
'#default_value' => $description,
|
||||
];
|
||||
if (strpos($data_type, 'entity:') === 0) {
|
||||
list(, $entity_type) = explode(':', $data_type);
|
||||
/** @var EntityAdapter $entity */
|
||||
$entity = $edit ? $context->getContextValue() : NULL;
|
||||
$form['context_value'] = [
|
||||
'#type' => 'entity_autocomplete',
|
||||
'#required' => TRUE,
|
||||
'#target_type' => $entity_type,
|
||||
'#default_value' => $entity,
|
||||
'#title' => $this->t('Select entity'),
|
||||
];
|
||||
}
|
||||
else {
|
||||
$value = $context->getContextData()->getValue();
|
||||
$form['context_value'] = [
|
||||
'#title' => $this->t('Set a context value'),
|
||||
'#type' => 'textfield',
|
||||
'#required' => TRUE,
|
||||
'#default_value' => $value,
|
||||
];
|
||||
}
|
||||
$form['submit'] = [
|
||||
'#type' => 'submit',
|
||||
'#value' => $this->t('Save'),
|
||||
'#ajax' => [
|
||||
'callback' => [$this, 'ajaxSave'],
|
||||
]
|
||||
];
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateForm(array &$form, FormStateInterface $form_state) {
|
||||
// If these are not equal, then we're adding a new context and should not override an existing context.
|
||||
if ($form_state->getValue('machine_name') != $form_state->getValue('context_id')) {
|
||||
$machine_name = $form_state->getValue('machine_name');
|
||||
$cached_values = $this->tempstore->get($this->tempstore_id)->get($this->machine_name);
|
||||
if (!empty($this->getContexts($cached_values)[$machine_name])) {
|
||||
$form_state->setError($form['machine_name'], $this->t('That machine name is in use by another context definition.'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
$cached_values = $this->tempstore->get($this->tempstore_id)->get($this->machine_name);
|
||||
$contexts = $this->getContexts($cached_values);
|
||||
if ($form_state->getValue('machine_name') != $form_state->getValue('context_id')) {
|
||||
$data_type = $form_state->getValue('context_id');
|
||||
$context_definition = new ContextDefinition($data_type, $form_state->getValue('label'), TRUE, FALSE, $form_state->getValue('description'));
|
||||
}
|
||||
else {
|
||||
$context = $contexts[$form_state->getValue('machine_name')];
|
||||
$context_definition = $context->getContextDefinition();
|
||||
$context_definition->setLabel($form_state->getValue('label'));
|
||||
$context_definition->setDescription($form_state->getValue('description'));
|
||||
}
|
||||
// We're dealing with an entity and should make sure it's loaded.
|
||||
if (strpos($context_definition->getDataType(), 'entity:') === 0) {
|
||||
list(, $entity_type) = explode(':', $context_definition->getDataType());
|
||||
if (is_numeric($form_state->getValue('context_value'))) {
|
||||
$value = \Drupal::entityTypeManager()->getStorage($entity_type)->load($form_state->getValue('context_value'));
|
||||
}
|
||||
}
|
||||
// No loading required for non-entity values.
|
||||
else {
|
||||
$value = $form_state->getValue('context_value');
|
||||
}
|
||||
$context = new Context($context_definition, $value);
|
||||
|
||||
$cached_values = $this->addContext($cached_values, $form_state->getValue('machine_name'), $context);
|
||||
$this->tempstore->get($this->tempstore_id)->set($this->machine_name, $cached_values);
|
||||
list($route_name, $route_parameters) = $this->getParentRouteInfo($cached_values);
|
||||
$form_state->setRedirect($route_name, $route_parameters);
|
||||
}
|
||||
|
||||
public function ajaxSave(array &$form, FormStateInterface $form_state) {
|
||||
$response = new AjaxResponse();
|
||||
$cached_values = $this->tempstore->get($this->tempstore_id)->get($this->machine_name);
|
||||
list($route_name, $route_parameters) = $this->getParentRouteInfo($cached_values);
|
||||
$url = new Url($route_name, $route_parameters);
|
||||
$response->addCommand(new RedirectCommand($url->toString()));
|
||||
$response->addCommand(new CloseModalDialogCommand());
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Document the route name and parameters for redirect after submission.
|
||||
*
|
||||
* @param $cached_values
|
||||
*
|
||||
* @return array
|
||||
* In the format of
|
||||
* return ['route.name', ['machine_name' => $this->machine_name, 'step' => 'step_name]];
|
||||
*/
|
||||
abstract protected function getParentRouteInfo($cached_values);
|
||||
|
||||
/**
|
||||
* Custom logic for retrieving the contexts array from cached_values.
|
||||
*
|
||||
* @param $cached_values
|
||||
*
|
||||
* @return \Drupal\Core\Plugin\Context\ContextInterface[]
|
||||
*/
|
||||
abstract protected function getContexts($cached_values);
|
||||
|
||||
/**
|
||||
* Custom logic for adding a context to the cached_values contexts array.
|
||||
*
|
||||
* @param array $cached_values
|
||||
* The cached_values currently in use.
|
||||
* @param string $context_id
|
||||
* The context identifier.
|
||||
* @param \Drupal\Core\Plugin\Context\ContextInterface $context
|
||||
* The context to add or update within the cached values.
|
||||
*
|
||||
* @return mixed
|
||||
* Return the $cached_values
|
||||
*/
|
||||
abstract protected function addContext($cached_values, $context_id, ContextInterface $context);
|
||||
|
||||
/**
|
||||
* Custom "exists" logic for the context to be created.
|
||||
*
|
||||
* @param string $value
|
||||
* The name of the context.
|
||||
* @param $element
|
||||
* The machine_name element
|
||||
* @param \Drupal\Core\Form\FormStateInterface $form_state
|
||||
* The form state.
|
||||
*
|
||||
* @return bool
|
||||
* Return true if a context of this name exists.
|
||||
*/
|
||||
abstract public function contextExists($value, $element, $form_state);
|
||||
|
||||
/**
|
||||
* Determines if the machine_name should be disabled.
|
||||
*
|
||||
* @param $cached_values
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
abstract protected function disableMachineName($cached_values, $machine_name);
|
||||
|
||||
}
|
85
web/modules/contrib/ctools/src/Form/ContextDelete.php
Normal file
85
web/modules/contrib/ctools/src/Form/ContextDelete.php
Normal file
|
@ -0,0 +1,85 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools\Form;
|
||||
|
||||
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Form\ConfirmFormBase;
|
||||
use Drupal\user\SharedTempStoreFactory;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides a form for deleting an contexts and relationships.
|
||||
*/
|
||||
abstract class ContextDelete extends ConfirmFormBase {
|
||||
|
||||
/**
|
||||
* @var \Drupal\user\SharedTempStoreFactory
|
||||
*/
|
||||
protected $tempstore;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $tempstore_id;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $machine_name;
|
||||
|
||||
/**
|
||||
* The static context's machine name.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $context_id;
|
||||
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static($container->get('user.shared_tempstore'));
|
||||
}
|
||||
|
||||
public function __construct(SharedTempStoreFactory $tempstore) {
|
||||
$this->tempstore = $tempstore;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'ctools_context_delete_form';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getConfirmText() {
|
||||
return $this->t('Delete');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state, $tempstore_id = NULL, $machine_name = NULL, $context_id = NULL) {
|
||||
$this->tempstore_id = $tempstore_id;
|
||||
$this->machine_name = $machine_name;
|
||||
$this->context_id = $context_id;
|
||||
return parent::buildForm($form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
$form_state->setRedirectUrl($this->getCancelUrl());
|
||||
}
|
||||
|
||||
protected function getTempstore() {
|
||||
return $this->tempstore->get($this->tempstore_id)->get($this->machine_name);
|
||||
}
|
||||
|
||||
protected function setTempstore($cached_values) {
|
||||
$this->tempstore->get($this->tempstore_id)->set($this->machine_name, $cached_values);
|
||||
}
|
||||
|
||||
}
|
224
web/modules/contrib/ctools/src/Form/ManageConditions.php
Normal file
224
web/modules/contrib/ctools/src/Form/ManageConditions.php
Normal file
|
@ -0,0 +1,224 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools\Form;
|
||||
|
||||
|
||||
use Drupal\Component\Plugin\PluginManagerInterface;
|
||||
use Drupal\Component\Serialization\Json;
|
||||
use Drupal\Core\Ajax\AjaxResponse;
|
||||
use Drupal\Core\Ajax\OpenModalDialogCommand;
|
||||
use Drupal\Core\Form\FormBase;
|
||||
use Drupal\Core\Form\FormBuilderInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
abstract class ManageConditions extends FormBase {
|
||||
|
||||
/**
|
||||
* @var \Drupal\Core\Condition\ConditionManager
|
||||
*/
|
||||
protected $manager;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $machine_name;
|
||||
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static($container->get('plugin.manager.condition'));
|
||||
}
|
||||
|
||||
function __construct(PluginManagerInterface $manager) {
|
||||
$this->manager = $manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'ctools_manage_conditions_form';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state) {
|
||||
$cached_values = $form_state->getTemporaryValue('wizard');
|
||||
$this->machine_name = $cached_values['id'];
|
||||
$form['#attached']['library'][] = 'core/drupal.dialog.ajax';
|
||||
$options = [];
|
||||
$contexts = $this->getContexts($cached_values);
|
||||
foreach ($this->manager->getDefinitionsForContexts($contexts) as $plugin_id => $definition) {
|
||||
$options[$plugin_id] = (string) $definition['label'];
|
||||
}
|
||||
$form['items'] = array(
|
||||
'#type' => 'markup',
|
||||
'#prefix' => '<div id="configured-conditions">',
|
||||
'#suffix' => '</div>',
|
||||
'#theme' => 'table',
|
||||
'#header' => array($this->t('Plugin Id'), $this->t('Summary'), $this->t('Operations')),
|
||||
'#rows' => $this->renderRows($cached_values),
|
||||
'#empty' => $this->t('No required conditions have been configured.')
|
||||
);
|
||||
$form['conditions'] = [
|
||||
'#type' => 'select',
|
||||
'#options' => $options,
|
||||
];
|
||||
$form['add'] = [
|
||||
'#type' => 'submit',
|
||||
'#name' => 'add',
|
||||
'#value' => $this->t('Add Condition'),
|
||||
'#ajax' => [
|
||||
'callback' => [$this, 'add'],
|
||||
'event' => 'click',
|
||||
],
|
||||
'#submit' => [
|
||||
'callback' => [$this, 'submitForm'],
|
||||
]
|
||||
];
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
$cached_values = $form_state->getTemporaryValue('wizard');
|
||||
list(, $route_parameters) = $this->getOperationsRouteInfo($cached_values, $this->machine_name, $form_state->getValue('conditions'));
|
||||
$form_state->setRedirect($this->getAddRoute($cached_values), $route_parameters);
|
||||
}
|
||||
|
||||
public function add(array &$form, FormStateInterface $form_state) {
|
||||
$condition = $form_state->getValue('conditions');
|
||||
$content = \Drupal::formBuilder()->getForm($this->getConditionClass(), $condition, $this->getTempstoreId(), $this->machine_name);
|
||||
$content['#attached']['library'][] = 'core/drupal.dialog.ajax';
|
||||
$cached_values = $form_state->getTemporaryValue('wizard');
|
||||
list(, $route_parameters) = $this->getOperationsRouteInfo($cached_values, $this->machine_name, $form_state->getValue('conditions'));
|
||||
$content['submit']['#attached']['drupalSettings']['ajax'][$content['submit']['#id']]['url'] = $this->url($this->getAddRoute($cached_values), $route_parameters, ['query' => [FormBuilderInterface::AJAX_FORM_REQUEST => TRUE]]);
|
||||
$response = new AjaxResponse();
|
||||
$response->addCommand(new OpenModalDialogCommand($this->t('Configure Required Context'), $content, array('width' => '700')));
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $cached_values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function renderRows($cached_values) {
|
||||
$configured_conditions = array();
|
||||
foreach ($this->getConditions($cached_values) as $row => $condition) {
|
||||
/** @var $instance \Drupal\Core\Condition\ConditionInterface */
|
||||
$instance = $this->manager->createInstance($condition['id'], $condition);
|
||||
list($route_name, $route_parameters) = $this->getOperationsRouteInfo($cached_values, $cached_values['id'], $row);
|
||||
$build = array(
|
||||
'#type' => 'operations',
|
||||
'#links' => $this->getOperations($route_name, $route_parameters),
|
||||
);
|
||||
$configured_conditions[] = array(
|
||||
$instance->getPluginId(),
|
||||
$instance->summary(),
|
||||
'operations' => [
|
||||
'data' => $build,
|
||||
],
|
||||
);
|
||||
}
|
||||
return $configured_conditions;
|
||||
}
|
||||
|
||||
protected function getOperations($route_name_base, array $route_parameters = array()) {
|
||||
$operations['edit'] = array(
|
||||
'title' => $this->t('Edit'),
|
||||
'url' => new Url($route_name_base . '.edit', $route_parameters),
|
||||
'weight' => 10,
|
||||
'attributes' => array(
|
||||
'class' => ['use-ajax'],
|
||||
'data-dialog-type' => 'modal',
|
||||
'data-dialog-options' => Json::encode([
|
||||
'width' => 700,
|
||||
]),
|
||||
),
|
||||
);
|
||||
$route_parameters['id'] = $route_parameters['condition'];
|
||||
$operations['delete'] = array(
|
||||
'title' => $this->t('Delete'),
|
||||
'url' => new Url($route_name_base . '.delete', $route_parameters),
|
||||
'weight' => 100,
|
||||
'attributes' => array(
|
||||
'class' => array('use-ajax'),
|
||||
'data-dialog-type' => 'modal',
|
||||
'data-dialog-options' => Json::encode([
|
||||
'width' => 700,
|
||||
]),
|
||||
),
|
||||
);
|
||||
return $operations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a subclass of '\Drupal\ctools\Form\ConditionConfigure'.
|
||||
*
|
||||
* The ConditionConfigure class is designed to be subclassed with custom
|
||||
* route information to control the modal/redirect needs of your use case.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function getConditionClass();
|
||||
|
||||
/**
|
||||
* The route to which condition 'add' actions should submit.
|
||||
*
|
||||
* @param mixed $cached_values
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function getAddRoute($cached_values);
|
||||
|
||||
/**
|
||||
* Provide the tempstore id for your specified use case.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function getTempstoreId();
|
||||
|
||||
/**
|
||||
* Document the route name and parameters for edit/delete context operations.
|
||||
*
|
||||
* The route name returned from this method is used as a "base" to which
|
||||
* ".edit" and ".delete" are appeneded in the getOperations() method.
|
||||
* Subclassing '\Drupal\ctools\Form\ConditionConfigure' and
|
||||
* '\Drupal\ctools\Form\ConditionDelete' should set you up for using this
|
||||
* approach quite seamlessly.
|
||||
*
|
||||
* @param mixed $cached_values
|
||||
*
|
||||
* @param string $machine_name
|
||||
*
|
||||
* @param string $row
|
||||
*
|
||||
* @return array
|
||||
* In the format of
|
||||
* return ['route.base.name', ['machine_name' => $machine_name, 'context' => $row]];
|
||||
*/
|
||||
abstract protected function getOperationsRouteInfo($cached_values, $machine_name, $row);
|
||||
|
||||
/**
|
||||
* Custom logic for retrieving the conditions array from cached_values.
|
||||
*
|
||||
* @param $cached_values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
abstract protected function getConditions($cached_values);
|
||||
|
||||
/**
|
||||
* Custom logic for retrieving the contexts array from cached_values.
|
||||
*
|
||||
* @param $cached_values
|
||||
*
|
||||
* @return \Drupal\Core\Plugin\Context\ContextInterface[]
|
||||
*/
|
||||
abstract protected function getContexts($cached_values);
|
||||
|
||||
}
|
327
web/modules/contrib/ctools/src/Form/ManageContext.php
Normal file
327
web/modules/contrib/ctools/src/Form/ManageContext.php
Normal file
|
@ -0,0 +1,327 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools\Form;
|
||||
|
||||
use Drupal\Component\Serialization\Json;
|
||||
use Drupal\Core\Ajax\AjaxResponse;
|
||||
use Drupal\Core\Ajax\OpenModalDialogCommand;
|
||||
use Drupal\Core\Form\FormBase;
|
||||
use Drupal\Core\Form\FormBuilderInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\TypedData\TypedDataManagerInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
abstract class ManageContext extends FormBase {
|
||||
|
||||
/**
|
||||
* The machine name of the wizard we're working with.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $machine_name;
|
||||
|
||||
/**
|
||||
* The typed data manager.
|
||||
*
|
||||
* @var \Drupal\Core\TypedData\TypedDataManagerInterface
|
||||
*/
|
||||
protected $typedDataManager;
|
||||
|
||||
/**
|
||||
* The form builder.
|
||||
*
|
||||
* @var \Drupal\Core\Form\FormBuilderInterface
|
||||
*/
|
||||
protected $formBuilder;
|
||||
|
||||
/**
|
||||
* An array of property types that are eligible as relationships.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $property_types = [];
|
||||
|
||||
/**
|
||||
* A property for controlling usage of relationships in an implementation.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $relationships = TRUE;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static($container->get('typed_data_manager'), $container->get('form_builder'));
|
||||
}
|
||||
|
||||
/**
|
||||
* ManageContext constructor.
|
||||
*
|
||||
* @param \Drupal\Core\TypedData\TypedDataManagerInterface $typed_data_manager
|
||||
* The typed data manager.
|
||||
* @param \Drupal\Core\Form\FormBuilderInterface $form_builder
|
||||
* The form builder.
|
||||
*/
|
||||
public function __construct(TypedDataManagerInterface $typed_data_manager, FormBuilderInterface $form_builder) {
|
||||
$this->typedDataManager = $typed_data_manager;
|
||||
$this->formBuilder = $form_builder;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'ctools_manage_context_form';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state) {
|
||||
$cached_values = $form_state->getTemporaryValue('wizard');
|
||||
$this->machine_name = $cached_values['id'];
|
||||
$form['items'] = array(
|
||||
'#type' => 'markup',
|
||||
'#prefix' => '<div id="configured-contexts">',
|
||||
'#suffix' => '</div>',
|
||||
'#theme' => 'table',
|
||||
'#header' => array($this->t('Context ID'), $this->t('Label'), $this->t('Data Type'), $this->t('Options')),
|
||||
'#rows' => $this->renderRows($cached_values),
|
||||
'#empty' => $this->t('No contexts or relationships have been added.')
|
||||
);
|
||||
foreach ($this->typedDataManager->getDefinitions() as $type => $definition) {
|
||||
$types[$type] = $definition['label'];
|
||||
}
|
||||
if (isset($types['entity'])) {
|
||||
unset($types['entity']);
|
||||
}
|
||||
asort($types);
|
||||
$form['context'] = [
|
||||
'#type' => 'select',
|
||||
'#options' => $types,
|
||||
];
|
||||
$form['add'] = [
|
||||
'#type' => 'submit',
|
||||
'#name' => 'add',
|
||||
'#value' => $this->t('Add new context'),
|
||||
'#ajax' => [
|
||||
'callback' => [$this, 'addContext'],
|
||||
'event' => 'click',
|
||||
],
|
||||
'#submit' => [
|
||||
'callback' => [$this, 'submitForm'],
|
||||
]
|
||||
];
|
||||
|
||||
$form['relationships'] = [
|
||||
'#type' => 'select',
|
||||
'#title' => $this->t('Add a relationship'),
|
||||
'#options' => $this->getAvailableRelationships($cached_values),
|
||||
'#access' => $this->relationships,
|
||||
];
|
||||
$form['add_relationship'] = [
|
||||
'#type' => 'submit',
|
||||
'#name' => 'add_relationship',
|
||||
'#value' => $this->t('Add Relationship'),
|
||||
'#ajax' => [
|
||||
'callback' => [$this, 'addRelationship'],
|
||||
'event' => 'click',
|
||||
],
|
||||
'#submit' => [
|
||||
'callback' => [$this, 'submitForm'],
|
||||
],
|
||||
'#access' => $this->relationships,
|
||||
];
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
if ($form_state->getTriggeringElement()['#name'] == 'add') {
|
||||
$cached_values = $form_state->getTemporaryValue('wizard');
|
||||
list(, $route_parameters) = $this->getContextOperationsRouteInfo($cached_values, $this->machine_name, $form_state->getValue('context'));
|
||||
$form_state->setRedirect($this->getContextAddRoute($cached_values), $route_parameters);
|
||||
}
|
||||
if ($form_state->getTriggeringElement()['#name'] == 'add_relationship') {
|
||||
$cached_values = $form_state->getTemporaryValue('wizard');
|
||||
list(, $route_parameters) = $this->getRelationshipOperationsRouteInfo($cached_values, $this->machine_name, $form_state->getValue('relationships'));
|
||||
$form_state->setRedirect($this->getRelationshipAddRoute($cached_values), $route_parameters);
|
||||
}
|
||||
}
|
||||
|
||||
public function addContext(array &$form, FormStateInterface $form_state) {
|
||||
$context = $form_state->getValue('context');
|
||||
$content = $this->formBuilder->getForm($this->getContextClass(), $context, $this->getTempstoreId(), $this->machine_name);
|
||||
$content['#attached']['library'][] = 'core/drupal.dialog.ajax';
|
||||
$cached_values = $form_state->getTemporaryValue('wizard');
|
||||
list(, $route_parameters) = $this->getContextOperationsRouteInfo($cached_values, $this->machine_name, $context);
|
||||
$content['submit']['#attached']['drupalSettings']['ajax'][$content['submit']['#id']]['url'] = $this->url($this->getContextAddRoute($cached_values), $route_parameters, ['query' => [FormBuilderInterface::AJAX_FORM_REQUEST => TRUE]]);
|
||||
$response = new AjaxResponse();
|
||||
$response->addCommand(new OpenModalDialogCommand($this->t('Add new context'), $content, array('width' => '700')));
|
||||
return $response;
|
||||
}
|
||||
|
||||
public function addRelationship(array &$form, FormStateInterface $form_state) {
|
||||
$relationship = $form_state->getValue('relationships');
|
||||
$content = $this->formBuilder->getForm($this->getRelationshipClass(), $relationship, $this->getTempstoreId(), $this->machine_name);
|
||||
$content['#attached']['library'][] = 'core/drupal.dialog.ajax';
|
||||
$cached_values = $form_state->getTemporaryValue('wizard');
|
||||
list(, $route_parameters) = $this->getRelationshipOperationsRouteInfo($cached_values, $this->machine_name, $relationship);
|
||||
$content['submit']['#attached']['drupalSettings']['ajax'][$content['submit']['#id']]['url'] = $this->url($this->getRelationshipAddRoute($cached_values), $route_parameters, ['query' => [FormBuilderInterface::AJAX_FORM_REQUEST => TRUE]]);
|
||||
$response = new AjaxResponse();
|
||||
$response->addCommand(new OpenModalDialogCommand($this->t('Configure Relationship'), $content, array('width' => '700')));
|
||||
return $response;
|
||||
}
|
||||
|
||||
protected function getAvailableRelationships($cached_values) {
|
||||
/** @var \Drupal\ctools\TypedDataResolver $resolver */
|
||||
$resolver = \Drupal::service('ctools.typed_data.resolver');
|
||||
return $resolver->getTokensForContexts($this->getContexts($cached_values));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $cached_values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function renderRows($cached_values) {
|
||||
$contexts = array();
|
||||
foreach ($this->getContexts($cached_values) as $row => $context) {
|
||||
list($route_name, $route_parameters) = $this->getContextOperationsRouteInfo($cached_values, $this->machine_name, $row);
|
||||
$build = array(
|
||||
'#type' => 'operations',
|
||||
'#links' => $this->getOperations($cached_values, $row, $route_name, $route_parameters),
|
||||
);
|
||||
$contexts[$row] = array(
|
||||
$row,
|
||||
$context->getContextDefinition()->getLabel(),
|
||||
$context->getContextDefinition()->getDataType(),
|
||||
'operations' => [
|
||||
'data' => $build,
|
||||
],
|
||||
);
|
||||
}
|
||||
return $contexts;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $cached_values
|
||||
* @param string $row
|
||||
* @param string $route_name_base
|
||||
* @param array $route_parameters
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function getOperations($cached_values, $row, $route_name_base, array $route_parameters = array()) {
|
||||
$operations = [];
|
||||
if ($this->isEditableContext($cached_values, $row)) {
|
||||
$operations['edit'] = array(
|
||||
'title' => $this->t('Edit'),
|
||||
'url' => new Url($route_name_base . '.edit', $route_parameters),
|
||||
'weight' => 10,
|
||||
'attributes' => array(
|
||||
'class' => ['use-ajax'],
|
||||
'data-dialog-type' => 'modal',
|
||||
'data-dialog-options' => Json::encode([
|
||||
'width' => 700,
|
||||
]),
|
||||
),
|
||||
);
|
||||
$operations['delete'] = array(
|
||||
'title' => $this->t('Delete'),
|
||||
'url' => new Url($route_name_base . '.delete', $route_parameters),
|
||||
'weight' => 100,
|
||||
'attributes' => array(
|
||||
'class' => array('use-ajax'),
|
||||
'data-dialog-type' => 'modal',
|
||||
'data-dialog-options' => Json::encode([
|
||||
'width' => 700,
|
||||
]),
|
||||
),
|
||||
);
|
||||
}
|
||||
return $operations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a subclass of '\Drupal\ctools\Form\ContextConfigure'.
|
||||
*
|
||||
* The ContextConfigure class is designed to be subclassed with custom
|
||||
* route information to control the modal/redirect needs of your use case.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function getContextClass($cached_values);
|
||||
|
||||
/**
|
||||
* Return a subclass of '\Drupal\ctools\Form\RelationshipConfigure'.
|
||||
*
|
||||
* The RelationshipConfigure class is designed to be subclassed with custom
|
||||
* route information to control the modal/redirect needs of your use case.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function getRelationshipClass($cached_values);
|
||||
|
||||
/**
|
||||
* The route to which context 'add' actions should submit.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function getContextAddRoute($cached_values);
|
||||
|
||||
/**
|
||||
* The route to which relationship 'add' actions should submit.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function getRelationshipAddRoute($cached_values);
|
||||
|
||||
/**
|
||||
* Provide the tempstore id for your specified use case.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function getTempstoreId();
|
||||
|
||||
/**
|
||||
* Returns the contexts already available in the wizard.
|
||||
*
|
||||
* @param mixed $cached_values
|
||||
*
|
||||
* @return \Drupal\Core\Plugin\Context\ContextInterface[]
|
||||
*/
|
||||
abstract protected function getContexts($cached_values);
|
||||
|
||||
/**
|
||||
* @param mixed $cached_values
|
||||
* @param string $machine_name
|
||||
* @param string $row
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
abstract protected function getContextOperationsRouteInfo($cached_values, $machine_name, $row);
|
||||
|
||||
/**
|
||||
* @param mixed $cached_values
|
||||
* @param string $machine_name
|
||||
* @param string $row
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
abstract protected function getRelationshipOperationsRouteInfo($cached_values, $machine_name, $row);
|
||||
|
||||
/**
|
||||
* @param mixed $cached_values
|
||||
* @param string $row
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
abstract protected function isEditableContext($cached_values, $row);
|
||||
|
||||
}
|
|
@ -0,0 +1,205 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools\Form;
|
||||
|
||||
use Drupal\Component\Serialization\Json;
|
||||
use Drupal\Core\Ajax\AjaxResponse;
|
||||
use Drupal\Core\Ajax\OpenModalDialogCommand;
|
||||
use Drupal\Core\Form\FormBase;
|
||||
use Drupal\Core\Form\FormBuilderInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Url;
|
||||
|
||||
abstract class ManageResolverRelationships extends FormBase {
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $machine_name;
|
||||
|
||||
/**
|
||||
* An array of property types that are eligible as relationships.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $property_types = [];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'ctools_manage_resolver_relationships_form';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state) {
|
||||
$cached_values = $form_state->getTemporaryValue('wizard');
|
||||
$this->machine_name = $cached_values['id'];
|
||||
$form['items'] = array(
|
||||
'#type' => 'markup',
|
||||
'#prefix' => '<div id="configured-relationships">',
|
||||
'#suffix' => '</div>',
|
||||
'#theme' => 'table',
|
||||
'#header' => array($this->t('Context ID'), $this->t('Label'), $this->t('Data Type'), $this->t('Options')),
|
||||
'#rows' => $this->renderRows($cached_values),
|
||||
'#empty' => $this->t('No relationships have been added.')
|
||||
);
|
||||
|
||||
$form['relationships'] = [
|
||||
'#type' => 'select',
|
||||
'#title' => $this->t('Add a relationship'),
|
||||
'#options' => $this->getAvailableRelationships($cached_values),
|
||||
];
|
||||
$form['add_relationship'] = [
|
||||
'#type' => 'submit',
|
||||
'#name' => 'add',
|
||||
'#value' => $this->t('Add Relationship'),
|
||||
'#ajax' => [
|
||||
'callback' => [$this, 'addRelationship'],
|
||||
'event' => 'click',
|
||||
],
|
||||
'#submit' => [
|
||||
'callback' => [$this, 'submitForm'],
|
||||
]
|
||||
];
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
if ($form_state->getTriggeringElement()['#name'] == 'add') {
|
||||
$cached_values = $form_state->getTemporaryValue('wizard');
|
||||
list(, $route_parameters) = $this->getRelationshipOperationsRouteInfo($cached_values, $this->machine_name, $form_state->getValue('relationships'));
|
||||
$form_state->setRedirect($this->getAddRoute($cached_values), $route_parameters);
|
||||
}
|
||||
}
|
||||
|
||||
public function addRelationship(array &$form, FormStateInterface $form_state) {
|
||||
$relationship = $form_state->getValue('relationships');
|
||||
$content = \Drupal::formBuilder()->getForm($this->getContextClass(), $relationship, $this->getTempstoreId(), $this->machine_name);
|
||||
$content['#attached']['library'][] = 'core/drupal.dialog.ajax';
|
||||
$cached_values = $form_state->getTemporaryValue('wizard');
|
||||
list(, $route_parameters) = $this->getRelationshipOperationsRouteInfo($cached_values, $this->machine_name, $relationship);
|
||||
$content['submit']['#attached']['drupalSettings']['ajax'][$content['submit']['#id']]['url'] = $this->url($this->getAddRoute($cached_values), $route_parameters, ['query' => [FormBuilderInterface::AJAX_FORM_REQUEST => TRUE]]);
|
||||
$response = new AjaxResponse();
|
||||
$response->addCommand(new OpenModalDialogCommand($this->t('Configure Relationship'), $content, array('width' => '700')));
|
||||
return $response;
|
||||
}
|
||||
|
||||
protected function getAvailableRelationships($cached_values) {
|
||||
/** @var \Drupal\ctools\TypedDataResolver $resolver */
|
||||
$resolver = \Drupal::service('ctools.typed_data.resolver');
|
||||
return $resolver->getTokensForContexts($this->getContexts($cached_values));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $cached_values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function renderRows($cached_values) {
|
||||
$contexts = array();
|
||||
foreach ($this->getContexts($cached_values) as $row => $context) {
|
||||
list($route_name, $route_parameters) = $this->getRelationshipOperationsRouteInfo($cached_values, $this->machine_name, $row);
|
||||
$build = array(
|
||||
'#type' => 'operations',
|
||||
'#links' => $this->getOperations($cached_values, $row, $route_name, $route_parameters),
|
||||
);
|
||||
$contexts[$row] = array(
|
||||
$row,
|
||||
$context->getContextDefinition()->getLabel(),
|
||||
$context->getContextDefinition()->getDataType(),
|
||||
'operations' => [
|
||||
'data' => $build,
|
||||
],
|
||||
);
|
||||
}
|
||||
return $contexts;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $cached_values
|
||||
* @param string $row
|
||||
* @param string $route_name_base
|
||||
* @param array $route_parameters
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function getOperations($cached_values, $row, $route_name_base, array $route_parameters = array()) {
|
||||
// Base contexts will not be a : separated and generated relationships should have 3 parts.
|
||||
if (count(explode(':', $row)) < 2) {
|
||||
return [];
|
||||
}
|
||||
$operations['edit'] = array(
|
||||
'title' => $this->t('Edit'),
|
||||
'url' => new Url($route_name_base . '.edit', $route_parameters),
|
||||
'weight' => 10,
|
||||
'attributes' => array(
|
||||
'class' => ['use-ajax'],
|
||||
'data-dialog-type' => 'modal',
|
||||
'data-dialog-options' => Json::encode([
|
||||
'width' => 700,
|
||||
]),
|
||||
),
|
||||
);
|
||||
$route_parameters['id'] = $route_parameters['context'];
|
||||
$operations['delete'] = array(
|
||||
'title' => $this->t('Delete'),
|
||||
'url' => new Url($route_name_base . '.delete', $route_parameters),
|
||||
'weight' => 100,
|
||||
'attributes' => array(
|
||||
'class' => array('use-ajax'),
|
||||
'data-dialog-type' => 'modal',
|
||||
'data-dialog-options' => Json::encode([
|
||||
'width' => 700,
|
||||
]),
|
||||
),
|
||||
);
|
||||
return $operations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a subclass of '\Drupal\ctools\Form\ResolverRelationshipConfigure'.
|
||||
*
|
||||
* The ConditionConfigure class is designed to be subclassed with custom
|
||||
* route information to control the modal/redirect needs of your use case.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function getContextClass($cached_values);
|
||||
|
||||
/**
|
||||
* The route to which relationship 'add' actions should submit.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function getAddRoute($cached_values);
|
||||
|
||||
/**
|
||||
* Provide the tempstore id for your specified use case.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function getTempstoreId();
|
||||
|
||||
/**
|
||||
* @param $cached_values
|
||||
*
|
||||
* @return \Drupal\Core\Plugin\Context\ContextInterface[]
|
||||
*/
|
||||
abstract protected function getContexts($cached_values);
|
||||
|
||||
/**
|
||||
* @param string $cached_values
|
||||
* @param string $machine_name
|
||||
* @param string $row
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
abstract protected function getRelationshipOperationsRouteInfo($cached_values, $machine_name, $row);
|
||||
|
||||
}
|
152
web/modules/contrib/ctools/src/Form/RelationshipConfigure.php
Normal file
152
web/modules/contrib/ctools/src/Form/RelationshipConfigure.php
Normal file
|
@ -0,0 +1,152 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools\Form;
|
||||
|
||||
use Drupal\Core\Ajax\AjaxResponse;
|
||||
use Drupal\Core\Ajax\CloseModalDialogCommand;
|
||||
use Drupal\Core\Ajax\RedirectCommand;
|
||||
use Drupal\Core\Form\FormBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\ctools\TypedDataResolver;
|
||||
use Drupal\user\SharedTempStoreFactory;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
abstract class RelationshipConfigure extends FormBase {
|
||||
|
||||
/**
|
||||
* @var \Drupal\user\SharedTempStoreFactory
|
||||
*/
|
||||
protected $tempstore;
|
||||
|
||||
/**
|
||||
* @var \Drupal\ctools\TypedDataResolver
|
||||
*/
|
||||
protected $resolver;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $tempstore_id;
|
||||
|
||||
/**
|
||||
* @var string;
|
||||
*/
|
||||
protected $machine_name;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static($container->get('user.shared_tempstore'), $container->get('ctools.typed_data.resolver'));
|
||||
}
|
||||
|
||||
public function __construct(SharedTempStoreFactory $tempstore, TypedDataResolver $resolver) {
|
||||
$this->tempstore = $tempstore;
|
||||
$this->resolver = $resolver;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'ctools_relationship_configure';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state, $context_id = NULL, $tempstore_id = NULL, $machine_name = NULL) {
|
||||
$this->tempstore_id = $tempstore_id;
|
||||
$this->machine_name = $machine_name;
|
||||
$cached_values = $this->tempstore->get($this->tempstore_id)->get($this->machine_name);
|
||||
|
||||
/** @var \Drupal\Core\Plugin\Context\ContextInterface[] $contexts */
|
||||
$contexts = $this->getContexts($cached_values);
|
||||
$context_object = $this->resolver->convertTokenToContext($context_id, $contexts);
|
||||
$form['id'] = [
|
||||
'#type' => 'value',
|
||||
'#value' => $context_id
|
||||
];
|
||||
$form['context_object'] = [
|
||||
'#type' => 'value',
|
||||
'#value' => $context_object,
|
||||
];
|
||||
$form['label'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Context label'),
|
||||
'#default_value' => !empty($contexts[$context_id]) ? $contexts[$context_id]->getContextDefinition()->getLabel() : $this->resolver->getLabelByToken($context_id, $contexts),
|
||||
'#required' => TRUE,
|
||||
];
|
||||
$form['context_data'] = [
|
||||
'#type' => 'item',
|
||||
'#title' => $this->t('Data type'),
|
||||
'#markup' => $context_object->getContextDefinition()->getDataType(),
|
||||
];
|
||||
$form['submit'] = [
|
||||
'#type' => 'submit',
|
||||
'#value' => $this->t('Save'),
|
||||
'#ajax' => [
|
||||
'callback' => [$this, 'ajaxSave'],
|
||||
]
|
||||
];
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
$cached_values = $this->tempstore->get($this->tempstore_id)->get($this->machine_name);
|
||||
list($route_name, $route_options) = $this->getParentRouteInfo($cached_values);
|
||||
$form_state->setRedirect($route_name, $route_options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $form
|
||||
* @param \Drupal\Core\Form\FormStateInterface $form_state
|
||||
*
|
||||
* @return \Drupal\Core\Ajax\AjaxResponse
|
||||
*/
|
||||
public function ajaxSave(array &$form, FormStateInterface $form_state) {
|
||||
$cached_values = $this->tempstore->get($this->tempstore_id)->get($this->machine_name);
|
||||
list($route_name, $route_parameters) = $this->getParentRouteInfo($cached_values);
|
||||
$response = new AjaxResponse();
|
||||
$response->addCommand(new RedirectCommand($this->url($route_name, $route_parameters)));
|
||||
$response->addCommand(new CloseModalDialogCommand());
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Document the route name and parameters for redirect after submission.
|
||||
*
|
||||
* @param array $cached_values
|
||||
*
|
||||
* @return array In the format of
|
||||
* In the format of
|
||||
* return ['route.name', ['machine_name' => $this->machine_name, 'step' => 'step_name']];
|
||||
*/
|
||||
abstract protected function getParentRouteInfo($cached_values);
|
||||
|
||||
/**
|
||||
* Custom logic for setting the conditions array in cached_values.
|
||||
*
|
||||
* @param $cached_values
|
||||
*
|
||||
* @param $contexts
|
||||
* The conditions to set within the cached values.
|
||||
*
|
||||
* @return mixed
|
||||
* Return the $cached_values
|
||||
*/
|
||||
abstract protected function setContexts($cached_values, $contexts);
|
||||
|
||||
/**
|
||||
* Custom logic for retrieving the contexts array from cached_values.
|
||||
*
|
||||
* @param $cached_values
|
||||
*
|
||||
* @return \Drupal\Core\Plugin\Context\ContextInterface[]
|
||||
*/
|
||||
abstract protected function getContexts($cached_values);
|
||||
|
||||
}
|
212
web/modules/contrib/ctools/src/Form/RequiredContext.php
Normal file
212
web/modules/contrib/ctools/src/Form/RequiredContext.php
Normal file
|
@ -0,0 +1,212 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools\Form;
|
||||
|
||||
use Drupal\Component\Plugin\PluginManagerInterface;
|
||||
use Drupal\Core\Ajax\AjaxResponse;
|
||||
use Drupal\Core\Ajax\OpenModalDialogCommand;
|
||||
use Drupal\Core\Form\FormBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
abstract class RequiredContext extends FormBase {
|
||||
|
||||
/**
|
||||
* @var \Drupal\Core\TypedData\TypedDataManager
|
||||
*/
|
||||
protected $typedDataManager;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $machine_name;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static($container->get('typed_data_manager'));
|
||||
}
|
||||
|
||||
public function __construct(PluginManagerInterface $typed_data_manager) {
|
||||
$this->typedDataManager = $typed_data_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'ctools_required_context_form';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state) {
|
||||
$cached_values = $form_state->getTemporaryValue('wizard');
|
||||
$this->machine_name = $cached_values['id'];
|
||||
$form['#attached']['library'][] = 'core/drupal.dialog.ajax';
|
||||
$options = [];
|
||||
foreach ($this->typedDataManager->getDefinitions() as $plugin_id => $definition) {
|
||||
$options[$plugin_id] = (string) $definition['label'];
|
||||
}
|
||||
$form['items'] = array(
|
||||
'#type' => 'markup',
|
||||
'#prefix' => '<div id="configured-contexts">',
|
||||
'#suffix' => '</div>',
|
||||
'#theme' => 'table',
|
||||
'#header' => array($this->t('Information'), $this->t('Description'), $this->t('Operations')),
|
||||
'#rows' => $this->renderContexts($cached_values),
|
||||
'#empty' => $this->t('No required contexts have been configured.')
|
||||
);
|
||||
$form['contexts'] = [
|
||||
'#type' => 'select',
|
||||
'#options' => $options,
|
||||
];
|
||||
$form['add'] = [
|
||||
'#type' => 'submit',
|
||||
'#name' => 'add',
|
||||
'#value' => $this->t('Add required context'),
|
||||
'#ajax' => [
|
||||
'callback' => [$this, 'add'],
|
||||
'event' => 'click',
|
||||
],
|
||||
'#submit' => [
|
||||
'callback' => [$this, 'submitform'],
|
||||
]
|
||||
];
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
$cached_values = $form_state->getTemporaryValue('wizard');
|
||||
list($route_name, $route_parameters) = $this->getOperationsRouteInfo($cached_values, $this->machine_name, $form_state->getValue('contexts'));
|
||||
$form_state->setRedirect($route_name . '.edit', $route_parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom ajax form submission handler.
|
||||
*
|
||||
* @param array $form
|
||||
* @param \Drupal\Core\Form\FormStateInterface $form_state
|
||||
*
|
||||
* @return \Drupal\Core\Ajax\AjaxResponse
|
||||
*/
|
||||
public function add(array &$form, FormStateInterface $form_state) {
|
||||
$context = $form_state->getValue('contexts');
|
||||
$content = \Drupal::formBuilder()->getForm($this->getContextClass(), $context, $this->getTempstoreId(), $this->machine_name);
|
||||
$content['#attached']['library'][] = 'core/drupal.dialog.ajax';
|
||||
$response = new AjaxResponse();
|
||||
$response->addCommand(new OpenModalDialogCommand($this->t('Configure Required Context'), $content, array('width' => '700')));
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $cached_values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function renderContexts($cached_values) {
|
||||
$configured_contexts = array();
|
||||
foreach ($this->getContexts($cached_values) as $row => $context) {
|
||||
list($plugin_id, $label, $machine_name, $description) = array_values($context);
|
||||
list($route_name, $route_parameters) = $this->getOperationsRouteInfo($cached_values, $cached_values['id'], $row);
|
||||
$build = array(
|
||||
'#type' => 'operations',
|
||||
'#links' => $this->getOperations($route_name, $route_parameters),
|
||||
);
|
||||
$configured_contexts[] = array(
|
||||
$this->t('<strong>Label:</strong> @label<br /> <strong>Type:</strong> @type', ['@label' => $label, '@type' => $plugin_id]),
|
||||
$this->t('@description', ['@description' => $description]),
|
||||
'operations' => [
|
||||
'data' => $build,
|
||||
],
|
||||
);
|
||||
}
|
||||
return $configured_contexts;
|
||||
}
|
||||
|
||||
protected function getOperations($route_name_base, array $route_parameters = array()) {
|
||||
$operations['edit'] = array(
|
||||
'title' => $this->t('Edit'),
|
||||
'url' => new Url($route_name_base . '.edit', $route_parameters),
|
||||
'weight' => 10,
|
||||
'attributes' => array(
|
||||
'class' => array('use-ajax'),
|
||||
'data-accepts' => 'application/vnd.drupal-modal',
|
||||
'data-dialog-options' => json_encode(array(
|
||||
'width' => 700,
|
||||
)),
|
||||
),
|
||||
'ajax' => [
|
||||
''
|
||||
],
|
||||
);
|
||||
$route_parameters['id'] = $route_parameters['context'];
|
||||
$operations['delete'] = array(
|
||||
'title' => $this->t('Delete'),
|
||||
'url' => new Url($route_name_base . '.delete', $route_parameters),
|
||||
'weight' => 100,
|
||||
'attributes' => array(
|
||||
'class' => array('use-ajax'),
|
||||
'data-accepts' => 'application/vnd.drupal-modal',
|
||||
'data-dialog-options' => json_encode(array(
|
||||
'width' => 700,
|
||||
)),
|
||||
),
|
||||
);
|
||||
return $operations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a subclass of '\Drupal\ctools\Form\ContextConfigure'.
|
||||
*
|
||||
* The ContextConfigure class is designed to be subclassed with custom route
|
||||
* information to control the modal/redirect needs of your use case.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function getContextClass();
|
||||
|
||||
/**
|
||||
* Provide the tempstore id for your specified use case.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function getTempstoreId();
|
||||
|
||||
/**
|
||||
* Document the route name and parameters for edit/delete context operations.
|
||||
*
|
||||
* The route name returned from this method is used as a "base" to which
|
||||
* ".edit" and ".delete" are appeneded in the getOperations() method.
|
||||
* Subclassing '\Drupal\ctools\Form\ContextConfigure' and
|
||||
* '\Drupal\ctools\Form\RequiredContextDelete' should set you up for using
|
||||
* this approach quite seamlessly.
|
||||
*
|
||||
* @param mixed $cached_values
|
||||
*
|
||||
* @param string $machine_name
|
||||
*
|
||||
* @param string $row
|
||||
*
|
||||
* @return array
|
||||
* In the format of
|
||||
* return ['route.base.name', ['machine_name' => $machine_name, 'context' => $row]];
|
||||
*/
|
||||
abstract protected function getOperationsRouteInfo($cached_values, $machine_name, $row);
|
||||
|
||||
/**
|
||||
* Custom logic for retrieving the contexts array from cached_values.
|
||||
*
|
||||
* @param $cached_values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
abstract protected function getContexts($cached_values);
|
||||
|
||||
}
|
194
web/modules/contrib/ctools/src/Form/RequiredContextDelete.php
Normal file
194
web/modules/contrib/ctools/src/Form/RequiredContextDelete.php
Normal file
|
@ -0,0 +1,194 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools\Form;
|
||||
|
||||
use Drupal\Core\Form\ConfirmFormBase;
|
||||
use Drupal\Core\Form\ConfirmFormHelper;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\user\SharedTempStoreFactory;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Base class for adding a required contexts step to your wizard.
|
||||
*/
|
||||
abstract class RequiredContextDelete extends ConfirmFormBase {
|
||||
|
||||
/**
|
||||
* @var \Drupal\user\SharedTempStoreFactory
|
||||
*/
|
||||
protected $tempstore;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $tempstore_id;
|
||||
|
||||
/**
|
||||
* @var string;
|
||||
*/
|
||||
protected $machine_name;
|
||||
|
||||
/**
|
||||
* @var int;
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static($container->get('user.shared_tempstore'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Drupal\user\SharedTempStoreFactory $tempstore
|
||||
*/
|
||||
function __construct(SharedTempStoreFactory $tempstore) {
|
||||
$this->tempstore = $tempstore;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'ctools_required_context_delete';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state, $id = NULL, $tempstore_id = NULL, $machine_name = NULL) {
|
||||
$this->tempstore_id = $tempstore_id;
|
||||
$this->machine_name = $machine_name;
|
||||
$this->id = $id;
|
||||
|
||||
$cached_values = $this->tempstore->get($this->tempstore_id)->get($this->machine_name);
|
||||
$form ['#title'] = $this->getQuestion($id, $cached_values);
|
||||
|
||||
$form ['#attributes']['class'][] = 'confirmation';
|
||||
$form ['description'] = array('#markup' => $this->getDescription());
|
||||
$form [$this->getFormName()] = array('#type' => 'hidden', '#value' => 1);
|
||||
|
||||
// By default, render the form using theme_confirm_form().
|
||||
if (!isset($form ['#theme'])) {
|
||||
$form ['#theme'] = 'confirm_form';
|
||||
}
|
||||
$form['actions'] = array('#type' => 'actions');
|
||||
$form['actions'] += $this->actions($form, $form_state);
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
$cached_values = $this->tempstore->get($this->tempstore_id)->get($this->machine_name);
|
||||
$contexts = $this->getContexts($cached_values);
|
||||
unset($contexts[$this->id]);
|
||||
$cached_values = $this->setContexts($cached_values, $contexts);
|
||||
$this->tempstore->get($this->tempstore_id)->set($this->machine_name, $cached_values);
|
||||
list($route_name, $route_parameters) = $this->getParentRouteInfo($cached_values);
|
||||
$form_state->setRedirect($route_name, $route_parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getQuestion($id = NULL, $cached_values = NULL) {
|
||||
$context = $this->getContexts($cached_values)[$id];
|
||||
return $this->t('Are you sure you want to delete the @label context?', array(
|
||||
'@label' => $context['label'],
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDescription() {
|
||||
return $this->t('This action cannot be undone.');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormName() {
|
||||
return 'confirm';
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the action buttons for submitting this form.
|
||||
*/
|
||||
protected function actions(array $form, FormStateInterface $form_state) {
|
||||
return array(
|
||||
'submit' => array(
|
||||
'#type' => 'submit',
|
||||
'#value' => $this->getConfirmText(),
|
||||
'#validate' => array(
|
||||
array($this, 'validate'),
|
||||
),
|
||||
'#submit' => array(
|
||||
array($this, 'submitForm'),
|
||||
),
|
||||
),
|
||||
'cancel' => ConfirmFormHelper::buildCancelLink($this, $this->getRequest()),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCancelUrl() {
|
||||
$cached_values = $this->tempstore->get($this->tempstore_id)->get($this->machine_name);
|
||||
list($route_name, $route_parameters) = $this->getParentRouteInfo($cached_values);
|
||||
return new Url($route_name, $route_parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getConfirmText() {
|
||||
return $this->t('Delete');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCancelText() {
|
||||
return $this->t('Cancel');
|
||||
}
|
||||
|
||||
/**
|
||||
* Document the route name and parameters for redirect after submission.
|
||||
*
|
||||
* @param $cached_values
|
||||
*
|
||||
* @return array
|
||||
* In the format of
|
||||
* return ['route.name', ['machine_name' => $this->machine_name, 'step' => 'step_name]];
|
||||
*/
|
||||
abstract protected function getParentRouteInfo($cached_values);
|
||||
|
||||
/**
|
||||
* Custom logic for retrieving the contexts array from cached_values.
|
||||
*
|
||||
* @param $cached_values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
abstract protected function getContexts($cached_values);
|
||||
|
||||
/**
|
||||
* Custom logic for setting the contexts array in cached_values.
|
||||
*
|
||||
* @param $cached_values
|
||||
*
|
||||
* @param $contexts
|
||||
* The contexts to set within the cached values.
|
||||
*
|
||||
* @return mixed
|
||||
* Return the $cached_values
|
||||
*/
|
||||
abstract protected function setContexts($cached_values, $contexts);
|
||||
|
||||
}
|
|
@ -0,0 +1,182 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools\Form;
|
||||
|
||||
|
||||
use Drupal\Core\Ajax\AjaxResponse;
|
||||
use Drupal\Core\Ajax\CloseModalDialogCommand;
|
||||
use Drupal\Core\Ajax\RedirectCommand;
|
||||
use Drupal\Core\Form\FormBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\user\SharedTempStoreFactory;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
abstract class ResolverRelationshipConfigure extends FormBase {
|
||||
|
||||
/**
|
||||
* @var \Drupal\user\SharedTempStoreFactory
|
||||
*/
|
||||
protected $tempstore;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $tempstore_id;
|
||||
|
||||
/**
|
||||
* @var string;
|
||||
*/
|
||||
protected $machine_name;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static($container->get('user.shared_tempstore'));
|
||||
}
|
||||
|
||||
function __construct(SharedTempStoreFactory $tempstore) {
|
||||
$this->tempstore = $tempstore;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'ctools_context_configure';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state, $context = NULL, $tempstore_id = NULL, $machine_name = NULL) {
|
||||
$this->tempstore_id = $tempstore_id;
|
||||
$this->machine_name = $machine_name;
|
||||
$cached_values = $this->tempstore->get($this->tempstore_id)->get($this->machine_name);
|
||||
if (is_numeric($context)) {
|
||||
$id = $context;
|
||||
$contexts = $this->getContexts($cached_values);
|
||||
$context = $contexts[$id]['context'];
|
||||
$label = $contexts[$id]['label'];
|
||||
$machine_name = $contexts[$id]['machine_name'];
|
||||
$description = $contexts[$id]['description'];
|
||||
// Conditionally set this form element so that we can update or add.
|
||||
$form['id'] = [
|
||||
'#type' => 'value',
|
||||
'#value' => $id
|
||||
];
|
||||
}
|
||||
else {
|
||||
$label = '';
|
||||
$machine_name = '';
|
||||
$description = '';
|
||||
}
|
||||
$form['#attached']['library'][] = 'core/drupal.dialog.ajax';
|
||||
$form['context'] = [
|
||||
'#type' => 'value',
|
||||
'#value' => $context
|
||||
];
|
||||
$form['label'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Label'),
|
||||
'#default_value' => $label,
|
||||
'#required' => TRUE,
|
||||
];
|
||||
$form['machine_name'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Machine Name'),
|
||||
'#default_value' => $machine_name,
|
||||
'#required' => TRUE,
|
||||
];
|
||||
$form['description'] = [
|
||||
'#type' => 'textarea',
|
||||
'#title' => $this->t('Description'),
|
||||
'#default_value' => $description,
|
||||
];
|
||||
$form['submit'] = [
|
||||
'#type' => 'submit',
|
||||
'#value' => $this->t('Save'),
|
||||
'#ajax' => [
|
||||
'callback' => [$this, 'ajaxSave'],
|
||||
]
|
||||
];
|
||||
return $form;
|
||||
}
|
||||
|
||||
public function validateForm(array &$form, FormStateInterface $form_state) {
|
||||
$machine_name = $form_state->getValue('machine_name');
|
||||
$cached_values = $this->tempstore->get($this->tempstore_id)->get($this->machine_name);
|
||||
foreach ($this->getContexts($cached_values) as $id => $context) {
|
||||
if ($context['machine_name'] == $machine_name) {
|
||||
$form_state->setError($form['machine_name'], $this->t('That machine name is in use by another context definition.'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
$cached_values = $this->tempstore->get($this->tempstore_id)->get($this->machine_name);
|
||||
$contexts = $this->getContexts($cached_values);
|
||||
$context = [
|
||||
'context' => $form_state->getValue('context'),
|
||||
'label' => $form_state->getValue('label'),
|
||||
'machine_name' => $form_state->getValue('machine_name'),
|
||||
'description' => $form_state->getValue('description'),
|
||||
];
|
||||
if ($form_state->hasValue('id')) {
|
||||
$contexts[$form_state->getValue('id')] = $context;
|
||||
}
|
||||
else {
|
||||
$contexts[] = $context;
|
||||
}
|
||||
$cached_values = $this->setContexts($cached_values, $contexts);
|
||||
$this->tempstore->get($this->tempstore_id)->set($this->machine_name, $cached_values);
|
||||
list($route_name, $route_parameters) = $this->getParentRouteInfo($cached_values);
|
||||
$form_state->setRedirect($route_name, $route_parameters);
|
||||
}
|
||||
|
||||
public function ajaxSave(array &$form, FormStateInterface $form_state) {
|
||||
$response = new AjaxResponse();
|
||||
$cached_values = $this->tempstore->get($this->tempstore_id)->get($this->machine_name);
|
||||
list($route_name, $route_parameters) = $this->getParentRouteInfo($cached_values);
|
||||
$response->addCommand(new RedirectCommand($this->url($route_name, $route_parameters)));
|
||||
$response->addCommand(new CloseModalDialogCommand());
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Document the route name and parameters for redirect after submission.
|
||||
*
|
||||
* @param $cached_values
|
||||
*
|
||||
* @return array
|
||||
* In the format of
|
||||
* return ['route.name', ['machine_name' => $this->machine_name, 'step' => 'step_name]];
|
||||
*/
|
||||
abstract protected function getParentRouteInfo($cached_values);
|
||||
|
||||
/**
|
||||
* Custom logic for retrieving the contexts array from cached_values.
|
||||
*
|
||||
* @param $cached_values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
abstract protected function getContexts($cached_values);
|
||||
|
||||
/**
|
||||
* Custom logic for setting the contexts array in cached_values.
|
||||
*
|
||||
* @param $cached_values
|
||||
*
|
||||
* @param $contexts
|
||||
* The contexts to set within the cached values.
|
||||
*
|
||||
* @return mixed
|
||||
* Return the $cached_values
|
||||
*/
|
||||
abstract protected function setContexts($cached_values, $contexts);
|
||||
|
||||
}
|
|
@ -0,0 +1,150 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools\Form;
|
||||
|
||||
|
||||
use Drupal\Core\Form\ConfirmFormBase;
|
||||
use Drupal\Core\Form\ConfirmFormHelper;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\ctools\TypedDataResolver;
|
||||
use Drupal\user\SharedTempStoreFactory;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
abstract class ResolverRelationshipDelete extends ConfirmFormBase {
|
||||
|
||||
/**
|
||||
* @var \Drupal\user\SharedTempStoreFactory
|
||||
*/
|
||||
protected $tempstore;
|
||||
|
||||
/**
|
||||
* @var \Drupal\ctools\TypedDataResolver
|
||||
*/
|
||||
protected $resolver;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $tempstore_id;
|
||||
|
||||
/**
|
||||
* @var string;
|
||||
*/
|
||||
protected $machine_name;
|
||||
|
||||
/**
|
||||
* @var string;
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static($container->get('user.shared_tempstore'), $container->get('ctools.typed_data.resolver'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Drupal\user\SharedTempStoreFactory $tempstore
|
||||
* The shared tempstore.
|
||||
* @param \Drupal\ctools\TypedDataResolver $resolver
|
||||
* The the typed data resolver.
|
||||
*/
|
||||
public function __construct(SharedTempStoreFactory $tempstore, TypedDataResolver $resolver) {
|
||||
$this->tempstore = $tempstore;
|
||||
$this->resolver = $resolver;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'ctools_resolver_relationship_delete';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getQuestion($id = NULL, $cached_values = []) {
|
||||
$context = $this->getContexts($cached_values)[$id];
|
||||
return $this->t('Are you sure you want to delete the @label relationship?', [
|
||||
'@label' => $context->getContextDefinition()->getLabel(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
abstract public function getCancelUrl($cached_values = []);
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state, $id = NULL, $tempstore_id = NULL, $machine_name = NULL) {
|
||||
$this->tempstore_id = $tempstore_id;
|
||||
$this->machine_name = $machine_name;
|
||||
$this->id = $id;
|
||||
|
||||
$cached_values = $this->tempstore->get($this->tempstore_id)->get($this->machine_name);
|
||||
$form ['#title'] = $this->getQuestion($id, $cached_values);
|
||||
|
||||
$form ['#attributes']['class'][] = 'confirmation';
|
||||
$form ['description'] = array('#markup' => $this->getDescription());
|
||||
$form [$this->getFormName()] = array('#type' => 'hidden', '#value' => 1);
|
||||
|
||||
// By default, render the form using theme_confirm_form().
|
||||
if (!isset($form ['#theme'])) {
|
||||
$form ['#theme'] = 'confirm_form';
|
||||
}
|
||||
$form['actions'] = array('#type' => 'actions');
|
||||
$form['actions'] += $this->actions($form, $form_state, $cached_values);
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
$cached_values = $this->tempstore->get($this->tempstore_id)->get($this->machine_name);
|
||||
$form_state->setRedirectUrl($this->getCancelUrl($cached_values));
|
||||
}
|
||||
|
||||
/**
|
||||
* A custom form actions method.
|
||||
*
|
||||
* @param array $form
|
||||
* The form array.
|
||||
* @param \Drupal\Core\Form\FormStateInterface $form_state
|
||||
* The current form state.
|
||||
* @param $cached_values
|
||||
* The current wizard cached values.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function actions(array $form, FormStateInterface $form_state, $cached_values) {
|
||||
return array(
|
||||
'submit' => array(
|
||||
'#type' => 'submit',
|
||||
'#value' => $this->getConfirmText(),
|
||||
'#validate' => array(
|
||||
array($this, 'validate'),
|
||||
),
|
||||
'#submit' => array(
|
||||
array($this, 'submitForm'),
|
||||
),
|
||||
),
|
||||
'cancel' => ConfirmFormHelper::buildCancelLink($this, $this->getRequest()),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract contexts from the cached values.
|
||||
*
|
||||
* @param array $cached_values
|
||||
* The cached values.
|
||||
*
|
||||
* @return \Drupal\Core\Plugin\Context\ContextInterface[]
|
||||
*/
|
||||
abstract public function getContexts($cached_values);
|
||||
|
||||
}
|
|
@ -0,0 +1,169 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools\ParamConverter;
|
||||
|
||||
use Drupal\Component\Utility\NestedArray;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Entity\EntityTypeManagerInterface;
|
||||
use Drupal\Core\ParamConverter\ParamConverterInterface;
|
||||
use Drupal\user\SharedTempStoreFactory;
|
||||
use Symfony\Component\Routing\Route;
|
||||
|
||||
/**
|
||||
* Parameter converter for pulling entities out of the tempstore.
|
||||
*
|
||||
* This is particularly useful when building non-wizard forms (like dialogs)
|
||||
* that operate on data in the wizard and getting the route access correct.
|
||||
*
|
||||
* There are four different ways to use this!
|
||||
*
|
||||
* In the most basic way, you specify the 'tempstore_id' in the defaults (so
|
||||
* that the form/controller has access to it as well) and in the parameter type
|
||||
* we simply give 'tempstore'. This assumes the entity is the full value
|
||||
* returned from the tempstore.
|
||||
*
|
||||
* @code
|
||||
* example.route:
|
||||
* path: foo/{example}
|
||||
* defaults:
|
||||
* tempstore_id: example.foo
|
||||
* options:
|
||||
* parameters:
|
||||
* example:
|
||||
* type: tempstore
|
||||
* @endcode
|
||||
*
|
||||
* If the value returned from the tempstore is an array, and the entity is
|
||||
* one of the keys, then we specify that after 'tempstore:', for example:
|
||||
*
|
||||
* @code
|
||||
* example.route:
|
||||
* path: foo/{example}
|
||||
* defaults:
|
||||
* tempstore_id: example.foo
|
||||
* options:
|
||||
* parameters:
|
||||
* example:
|
||||
* # Get the 'foo' key from the array returned by the tempstore.
|
||||
* type: tempstore:foo
|
||||
* @endcode
|
||||
*
|
||||
* You can also specify the 'tempstore_id' under the parameter rather than in
|
||||
* the defaults, for example:
|
||||
*
|
||||
* @code
|
||||
* example.route:
|
||||
* path: foo/{example}
|
||||
* options:
|
||||
* parameters:
|
||||
* example:
|
||||
* type: tempstore:foo
|
||||
* tempstore_id: example.foo
|
||||
* @endcode
|
||||
*
|
||||
* Or, if you have two parameters which are represented by two keys on the same
|
||||
* array from the tempstore, put the slug which represents the id for the
|
||||
* tempstore in the 2nd key. For example:
|
||||
*
|
||||
* @code
|
||||
* example.route:
|
||||
* path: foo/{example}/{other}
|
||||
* defaults:
|
||||
* tempstore_id: example.foo
|
||||
* options:
|
||||
* parameters:
|
||||
* example:
|
||||
* type: tempstore:foo
|
||||
* other:
|
||||
* type: tempstore:{example}:other
|
||||
* @endcode
|
||||
*/
|
||||
class TempstoreConverter implements ParamConverterInterface {
|
||||
|
||||
/**
|
||||
* The tempstore factory.
|
||||
*
|
||||
* @var \Drupal\user\SharedTempStoreFactory
|
||||
*/
|
||||
protected $tempstore;
|
||||
|
||||
/**
|
||||
* The entity type manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
|
||||
*/
|
||||
protected $entityTypeManager;
|
||||
|
||||
/**
|
||||
* Constructs a TempstoreConverter.
|
||||
*
|
||||
* @param \Drupal\user\SharedTempStoreFactory $tempstore
|
||||
*/
|
||||
public function __construct(SharedTempStoreFactory $tempstore, EntityTypeManagerInterface $entity_type_manager) {
|
||||
$this->tempstore = $tempstore;
|
||||
$this->entityTypeManager = $entity_type_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function convert($value, $definition, $name, array $defaults) {
|
||||
$tempstore_id = !empty($definition['tempstore_id']) ? $definition['tempstore_id'] : $defaults['tempstore_id'];
|
||||
$machine_name = $this->convertVariable($value, $defaults);
|
||||
|
||||
list(, $parts) = explode(':', $definition['type'], 2);
|
||||
$parts = explode(':', $parts);
|
||||
foreach ($parts as $key => $part) {
|
||||
$parts[$key] = $this->convertVariable($part, $defaults);
|
||||
}
|
||||
$cached_values = $this->tempstore->get($tempstore_id)->get($machine_name);
|
||||
// Entity type upcasting is most common, so we just assume that here.
|
||||
// @todo see if there's a better way to do this.
|
||||
if (!$cached_values && $this->entityTypeManager->hasDefinition($name)) {
|
||||
$value = $this->entityTypeManager->getStorage($name)->load($machine_name);
|
||||
return $value;
|
||||
}
|
||||
elseif (!$cached_values) {
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
$value = NestedArray::getValue($cached_values, $parts, $key_exists);
|
||||
return $key_exists ? $value : NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper function for converting string variable names from the defaults.
|
||||
*
|
||||
* @param mixed $name
|
||||
* If name is a string in the format of {var} it will parse the defaults
|
||||
* for a 'var' default. If $name isn't a string or isn't a slug, it will
|
||||
* return the raw $name value. If no default is found, it will return NULL
|
||||
* @param array $defaults
|
||||
* The route defaults array.
|
||||
*
|
||||
* @return mixed
|
||||
* The value of a variable in defaults.
|
||||
*/
|
||||
protected function convertVariable($name, $defaults) {
|
||||
if (is_string($name) && strpos($name, '{') === 0) {
|
||||
$length = strlen($name);
|
||||
$name = substr($name, 1, $length -2);
|
||||
return isset($defaults[$name]) ? $defaults[$name] : NULL;
|
||||
}
|
||||
return $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function applies($definition, $name, Route $route) {
|
||||
if (!empty($definition['type']) && ($definition['type'] == 'tempstore' || strpos($definition['type'], 'tempstore:') === 0)) {
|
||||
if (!empty($definition['tempstore_id']) || $route->hasDefault('tempstore_id')) {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
}
|
105
web/modules/contrib/ctools/src/Plugin/Block/EntityView.php
Normal file
105
web/modules/contrib/ctools/src/Plugin/Block/EntityView.php
Normal file
|
@ -0,0 +1,105 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools\Plugin\Block;
|
||||
|
||||
use Drupal\Core\Block\BlockBase;
|
||||
use Drupal\Core\Cache\CacheableMetadata;
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\Core\Plugin\ContextAwarePluginInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides a block to view a specific entity.
|
||||
*
|
||||
* @Block(
|
||||
* id = "entity_view",
|
||||
* deriver = "Drupal\ctools\Plugin\Deriver\EntityViewDeriver",
|
||||
* )
|
||||
*/
|
||||
class EntityView extends BlockBase implements ContextAwarePluginInterface, ContainerFactoryPluginInterface {
|
||||
|
||||
/**
|
||||
* The entity manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityManagerInterface
|
||||
*/
|
||||
protected $entityManager;
|
||||
|
||||
/**
|
||||
* Constructs a new EntityView.
|
||||
*
|
||||
* @param array $configuration
|
||||
* A configuration array containing information about the plugin instance.
|
||||
* @param string $plugin_id
|
||||
* The plugin ID for the plugin instance.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
|
||||
* The entity manager.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityManagerInterface $entity_manager) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
|
||||
$this->entityManager = $entity_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||
return new static(
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$container->get('entity.manager')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function defaultConfiguration() {
|
||||
return [
|
||||
'view_mode' => 'default',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function blockForm($form, FormStateInterface $form_state) {
|
||||
$form['view_mode'] = [
|
||||
'#type' => 'select',
|
||||
'#options' => $this->entityManager->getViewModeOptions($this->getDerivativeId()),
|
||||
'#title' => $this->t('View mode'),
|
||||
'#default_value' => $this->configuration['view_mode'],
|
||||
];
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function blockSubmit($form, FormStateInterface $form_state) {
|
||||
$this->configuration['view_mode'] = $form_state->getValue('view_mode');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function build() {
|
||||
/** @var $entity \Drupal\Core\Entity\EntityInterface */
|
||||
$entity = $this->getContextValue('entity');
|
||||
|
||||
$view_builder = $this->entityManager->getViewBuilder($entity->getEntityTypeId());
|
||||
$build = $view_builder->view($entity, $this->configuration['view_mode']);
|
||||
|
||||
CacheableMetadata::createFromObject($this->getContext('entity'))
|
||||
->applyTo($build);
|
||||
|
||||
return $build;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools\Plugin;
|
||||
|
||||
use Drupal\Core\Block\BlockPluginInterface;
|
||||
use Drupal\Core\Plugin\DefaultLazyPluginCollection;
|
||||
|
||||
/**
|
||||
* Provides a collection of block plugins.
|
||||
*/
|
||||
class BlockPluginCollection extends DefaultLazyPluginCollection {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return \Drupal\Core\Block\BlockPluginInterface
|
||||
*/
|
||||
public function &get($instance_id) {
|
||||
return parent::get($instance_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all blocks keyed by their region.
|
||||
*
|
||||
* @return array
|
||||
* An associative array keyed by region, containing an associative array of
|
||||
* block plugins.
|
||||
*/
|
||||
public function getAllByRegion() {
|
||||
$region_assignments = [];
|
||||
foreach ($this as $block_id => $block) {
|
||||
$configuration = $block->getConfiguration();
|
||||
$region = isset($configuration['region']) ? $configuration['region'] : NULL;
|
||||
$region_assignments[$region][$block_id] = $block;
|
||||
}
|
||||
foreach ($region_assignments as $region => $region_assignment) {
|
||||
// @todo Determine the reason this needs error suppression.
|
||||
@uasort($region_assignment, function (BlockPluginInterface $a, BlockPluginInterface $b) {
|
||||
$a_config = $a->getConfiguration();
|
||||
$a_weight = isset($a_config['weight']) ? $a_config['weight'] : 0;
|
||||
$b_config = $b->getConfiguration();
|
||||
$b_weight = isset($b_config['weight']) ? $b_config['weight'] : 0;
|
||||
if ($a_weight == $b_weight) {
|
||||
return strcmp($a->label(), $b->label());
|
||||
}
|
||||
return $a_weight > $b_weight ? 1 : -1;
|
||||
});
|
||||
$region_assignments[$region] = $region_assignment;
|
||||
}
|
||||
return $region_assignments;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools\Plugin;
|
||||
|
||||
use Drupal\Core\Display\VariantInterface;
|
||||
|
||||
/**
|
||||
* Provides an interface for variant plugins that use block plugins.
|
||||
*/
|
||||
interface BlockVariantInterface extends VariantInterface {
|
||||
|
||||
/**
|
||||
* Returns the human-readable list of regions keyed by machine name.
|
||||
*
|
||||
* @return array
|
||||
* An array of human-readable region names keyed by machine name.
|
||||
*/
|
||||
public function getRegionNames();
|
||||
|
||||
/**
|
||||
* Returns the human-readable name of a specific region.
|
||||
*
|
||||
* @param string $region
|
||||
* The machine name of a region.
|
||||
*
|
||||
* @return string
|
||||
* The human-readable name of a region.
|
||||
*/
|
||||
public function getRegionName($region);
|
||||
|
||||
/**
|
||||
* Adds a block to this display variant.
|
||||
*
|
||||
* @param array $configuration
|
||||
* An array of block configuration.
|
||||
*
|
||||
* @return string
|
||||
* The block ID.
|
||||
*/
|
||||
public function addBlock(array $configuration);
|
||||
|
||||
/**
|
||||
* Returns the region a specific block is assigned to.
|
||||
*
|
||||
* @param string $block_id
|
||||
* The block ID.
|
||||
*
|
||||
* @return string
|
||||
* The machine name of the region this block is assigned to.
|
||||
*/
|
||||
public function getRegionAssignment($block_id);
|
||||
|
||||
/**
|
||||
* Returns an array of regions and their block plugins.
|
||||
*
|
||||
* @return array
|
||||
* The array is first keyed by region machine name, with the values
|
||||
* containing an array keyed by block ID, with block plugin instances as the
|
||||
* values.
|
||||
*/
|
||||
public function getRegionAssignments();
|
||||
|
||||
/**
|
||||
* Returns a specific block plugin.
|
||||
*
|
||||
* @param string $block_id
|
||||
* The block ID.
|
||||
*
|
||||
* @return \Drupal\Core\Block\BlockPluginInterface
|
||||
* The block plugin.
|
||||
*/
|
||||
public function getBlock($block_id);
|
||||
|
||||
/**
|
||||
* Updates the configuration of a specific block plugin.
|
||||
*
|
||||
* @param string $block_id
|
||||
* The block ID.
|
||||
* @param array $configuration
|
||||
* The array of configuration to set.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function updateBlock($block_id, array $configuration);
|
||||
|
||||
/**
|
||||
* Removes a specific block from this display variant.
|
||||
*
|
||||
* @param string $block_id
|
||||
* The block ID.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function removeBlock($block_id);
|
||||
|
||||
}
|
130
web/modules/contrib/ctools/src/Plugin/BlockVariantTrait.php
Normal file
130
web/modules/contrib/ctools/src/Plugin/BlockVariantTrait.php
Normal file
|
@ -0,0 +1,130 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools\Plugin;
|
||||
|
||||
/**
|
||||
* Provides methods for \Drupal\ctools\Plugin\BlockVariantInterface.
|
||||
*/
|
||||
trait BlockVariantTrait {
|
||||
|
||||
/**
|
||||
* The block manager.
|
||||
*
|
||||
* @var \Drupal\Core\Block\BlockManager
|
||||
*/
|
||||
protected $blockManager;
|
||||
|
||||
/**
|
||||
* The plugin collection that holds the block plugins.
|
||||
*
|
||||
* @var \Drupal\ctools\Plugin\BlockPluginCollection
|
||||
*/
|
||||
protected $blockPluginCollection;
|
||||
|
||||
/**
|
||||
* @see \Drupal\ctools\Plugin\BlockVariantInterface::getRegionNames()
|
||||
*/
|
||||
abstract public function getRegionNames();
|
||||
|
||||
/**
|
||||
* @see \Drupal\ctools\Plugin\BlockVariantInterface::getBlock()
|
||||
*/
|
||||
public function getBlock($block_id) {
|
||||
return $this->getBlockCollection()->get($block_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \Drupal\ctools\Plugin\BlockVariantInterface::addBlock()
|
||||
*/
|
||||
public function addBlock(array $configuration) {
|
||||
$configuration['uuid'] = $this->uuidGenerator()->generate();
|
||||
$this->getBlockCollection()->addInstanceId($configuration['uuid'], $configuration);
|
||||
return $configuration['uuid'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \Drupal\ctools\Plugin\BlockVariantInterface::removeBlock()
|
||||
*/
|
||||
public function removeBlock($block_id) {
|
||||
$this->getBlockCollection()->removeInstanceId($block_id);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \Drupal\ctools\Plugin\BlockVariantInterface::updateBlock()
|
||||
*/
|
||||
public function updateBlock($block_id, array $configuration) {
|
||||
$existing_configuration = $this->getBlock($block_id)->getConfiguration();
|
||||
$this->getBlockCollection()->setInstanceConfiguration($block_id, $configuration + $existing_configuration);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \Drupal\ctools\Plugin\BlockVariantInterface::getRegionAssignment()
|
||||
*/
|
||||
public function getRegionAssignment($block_id) {
|
||||
$configuration = $this->getBlock($block_id)->getConfiguration();
|
||||
return isset($configuration['region']) ? $configuration['region'] : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \Drupal\ctools\Plugin\BlockVariantInterface::getRegionAssignments()
|
||||
*/
|
||||
public function getRegionAssignments() {
|
||||
// Build an array of the region names in the right order.
|
||||
$empty = array_fill_keys(array_keys($this->getRegionNames()), []);
|
||||
$full = $this->getBlockCollection()->getAllByRegion();
|
||||
// Merge it with the actual values to maintain the ordering.
|
||||
return array_intersect_key(array_merge($empty, $full), $empty);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \Drupal\ctools\Plugin\BlockVariantInterface::getRegionName()
|
||||
*/
|
||||
public function getRegionName($region) {
|
||||
$regions = $this->getRegionNames();
|
||||
return isset($regions[$region]) ? $regions[$region] : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the block plugin manager.
|
||||
*
|
||||
* @return \Drupal\Core\Block\BlockManager
|
||||
* The block plugin manager.
|
||||
*/
|
||||
protected function getBlockManager() {
|
||||
if (!$this->blockManager) {
|
||||
$this->blockManager = \Drupal::service('plugin.manager.block');
|
||||
}
|
||||
return $this->blockManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the block plugins used for this display variant.
|
||||
*
|
||||
* @return \Drupal\Core\Block\BlockPluginInterface[]|\Drupal\ctools\Plugin\BlockPluginCollection
|
||||
* An array or collection of configured block plugins.
|
||||
*/
|
||||
protected function getBlockCollection() {
|
||||
if (!$this->blockPluginCollection) {
|
||||
$this->blockPluginCollection = new BlockPluginCollection($this->getBlockManager(), $this->getBlockConfig());
|
||||
}
|
||||
return $this->blockPluginCollection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the UUID generator.
|
||||
*
|
||||
* @return \Drupal\Component\Uuid\UuidInterface
|
||||
*/
|
||||
abstract protected function uuidGenerator();
|
||||
|
||||
/**
|
||||
* Returns the configuration for stored blocks.
|
||||
*
|
||||
* @return array
|
||||
* An array of block configuration, keyed by the unique block ID.
|
||||
*/
|
||||
abstract protected function getBlockConfig();
|
||||
|
||||
}
|
160
web/modules/contrib/ctools/src/Plugin/Condition/EntityBundle.php
Normal file
160
web/modules/contrib/ctools/src/Plugin/Condition/EntityBundle.php
Normal file
|
@ -0,0 +1,160 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools\Plugin\Condition;
|
||||
|
||||
use Drupal\Core\Condition\ConditionPluginBase;
|
||||
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
|
||||
use Drupal\Core\Entity\EntityTypeManagerInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\ctools\ConstraintConditionInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides a 'Entity Bundle' condition.
|
||||
*
|
||||
* @Condition(
|
||||
* id = "entity_bundle",
|
||||
* deriver = "\Drupal\ctools\Plugin\Deriver\EntityBundle"
|
||||
* )
|
||||
*
|
||||
*/
|
||||
class EntityBundle extends ConditionPluginBase implements ConstraintConditionInterface, ContainerFactoryPluginInterface {
|
||||
|
||||
/**
|
||||
* The entity type bundle info service.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
|
||||
*/
|
||||
protected $entityTypeBundleInfo;
|
||||
|
||||
/**
|
||||
* @var \Drupal\Core\Entity\EntityTypeInterface|null
|
||||
*/
|
||||
protected $bundleOf;
|
||||
|
||||
/**
|
||||
* Creates a new EntityBundle instance.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
|
||||
* The entity type manager.
|
||||
* @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entity_type_bundle_info
|
||||
* The entity type bundle info service.
|
||||
* @param array $configuration
|
||||
* The plugin configuration, i.e. an array with configuration values keyed
|
||||
* by configuration option name. The special key 'context' may be used to
|
||||
* initialize the defined contexts by setting it to an array of context
|
||||
* values keyed by context names.
|
||||
* @param string $plugin_id
|
||||
* The plugin_id for the plugin instance.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
*/
|
||||
public function __construct(EntityTypeManagerInterface $entity_type_manager, EntityTypeBundleInfoInterface $entity_type_bundle_info, array $configuration, $plugin_id, $plugin_definition) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
$this->entityTypeBundleInfo = $entity_type_bundle_info;
|
||||
$this->bundleOf = $entity_type_manager->getDefinition($this->getDerivativeId());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||
return new static(
|
||||
$container->get('entity_type.manager'),
|
||||
$container->get('entity_type.bundle.info'),
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
|
||||
$options = array();
|
||||
$bundles = $this->entityTypeBundleInfo->getBundleInfo($this->bundleOf->id());
|
||||
foreach ($bundles as $id => $info) {
|
||||
$options[$id] = $info['label'];
|
||||
}
|
||||
$form['bundles'] = array(
|
||||
'#title' => $this->pluginDefinition['label'],
|
||||
'#type' => 'checkboxes',
|
||||
'#options' => $options,
|
||||
'#default_value' => $this->configuration['bundles'],
|
||||
);
|
||||
return parent::buildConfigurationForm($form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
|
||||
$this->configuration['bundles'] = array_filter($form_state->getValue('bundles'));
|
||||
parent::submitConfigurationForm($form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function evaluate() {
|
||||
if (empty($this->configuration['bundles']) && !$this->isNegated()) {
|
||||
return TRUE;
|
||||
}
|
||||
/** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
|
||||
$entity = $this->getContextValue($this->bundleOf->id());
|
||||
return !empty($this->configuration['bundles'][$entity->bundle()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function summary() {
|
||||
if (count($this->configuration['bundles']) > 1) {
|
||||
$bundles = $this->configuration['bundles'];
|
||||
$last = array_pop($bundles);
|
||||
$bundles = implode(', ', $bundles);
|
||||
return $this->t('@bundle_type is @bundles or @last', array('@bundle_type' => $this->bundleOf->getBundleLabel(), '@bundles' => $bundles, '@last' => $last));
|
||||
}
|
||||
$bundle = reset($this->configuration['bundles']);
|
||||
return $this->t('@bundle_type is @bundle', array('@bundle_type' => $this->bundleOf->getBundleLabel(), '@bundle' => $bundle));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function defaultConfiguration() {
|
||||
return array('bundles' => array()) + parent::defaultConfiguration();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @param \Drupal\Core\Plugin\Context\ContextInterface[] $contexts
|
||||
*/
|
||||
public function applyConstraints(array $contexts = array()) {
|
||||
// Nullify any bundle constraints on contexts we care about.
|
||||
$this->removeConstraints($contexts);
|
||||
$bundle = array_values($this->configuration['bundles']);
|
||||
// There's only one expected context for this plugint type.
|
||||
foreach ($this->getContextMapping() as $definition_id => $context_id) {
|
||||
$contexts[$context_id]->getContextDefinition()->addConstraint('Bundle', ['value' => $bundle]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @param \Drupal\Core\Plugin\Context\ContextInterface[] $contexts
|
||||
*/
|
||||
public function removeConstraints(array $contexts = array()) {
|
||||
// Reset the bundle constraint for any context we've mapped.
|
||||
foreach ($this->getContextMapping() as $definition_id => $context_id) {
|
||||
$constraints = $contexts[$context_id]->getContextDefinition()->getConstraints();
|
||||
unset($constraints['Bundle']);
|
||||
$contexts[$context_id]->getContextDefinition()->setConstraints($constraints);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
41
web/modules/contrib/ctools/src/Plugin/Condition/NodeType.php
Normal file
41
web/modules/contrib/ctools/src/Plugin/Condition/NodeType.php
Normal file
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools\Plugin\Condition;
|
||||
|
||||
use Drupal\node\Plugin\Condition\NodeType as CoreNodeType;
|
||||
use Drupal\ctools\ConstraintConditionInterface;
|
||||
|
||||
class NodeType extends CoreNodeType implements ConstraintConditionInterface {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @param \Drupal\Core\Plugin\Context\ContextInterface[] $contexts
|
||||
*/
|
||||
public function applyConstraints(array $contexts = array()) {
|
||||
// Nullify any bundle constraints on contexts we care about.
|
||||
$this->removeConstraints($contexts);
|
||||
// If a single bundle is configured, we can set a proper constraint.
|
||||
if (count($this->configuration['bundles']) == 1) {
|
||||
$bundle = array_values($this->configuration['bundles']);
|
||||
foreach ($this->getContextMapping() as $definition_id => $context_id) {
|
||||
$contexts[$context_id]->getContextDefinition()->addConstraint('Bundle', ['value' => $bundle[0]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @param \Drupal\Core\Plugin\Context\ContextInterface[] $contexts
|
||||
*/
|
||||
public function removeConstraints(array $contexts = array()) {
|
||||
// Reset the bundle constraint for any context we've mapped.
|
||||
foreach ($this->getContextMapping() as $definition_id => $context_id) {
|
||||
$constraints = $contexts[$context_id]->getContextDefinition()->getConstraints();
|
||||
unset($constraints['Bundle']);
|
||||
$contexts[$context_id]->getContextDefinition()->setConstraints($constraints);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools\Plugin\Deriver;
|
||||
|
||||
use Drupal\Core\Plugin\Context\ContextDefinition;
|
||||
|
||||
/**
|
||||
* Deriver that creates a condition for each entity type with bundles.
|
||||
*/
|
||||
class EntityBundle extends EntityDeriverBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDerivativeDefinitions($base_plugin_definition) {
|
||||
foreach ($this->entityManager->getDefinitions() as $entity_type_id => $entity_type) {
|
||||
if ($entity_type->hasKey('bundle')) {
|
||||
$this->derivatives[$entity_type_id] = $base_plugin_definition;
|
||||
$this->derivatives[$entity_type_id]['label'] = $this->getEntityBundleLabel($entity_type);
|
||||
$this->derivatives[$entity_type_id]['context'] = [
|
||||
"$entity_type_id" => new ContextDefinition('entity:' . $entity_type_id),
|
||||
];
|
||||
}
|
||||
}
|
||||
return $this->derivatives;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the bundle label with a fallback when not defined.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
|
||||
* The entity type we are looking the bundle label for.
|
||||
*
|
||||
* @return \Drupal\Core\StringTranslation\TranslatableMarkup
|
||||
* The entity bundle label or a fallback label.
|
||||
*/
|
||||
protected function getEntityBundleLabel($entity_type) {
|
||||
|
||||
if ($label = $entity_type->getBundleLabel()) {
|
||||
return $this->t('@label', ['@label' => $label]);
|
||||
}
|
||||
|
||||
$fallback = $entity_type->getLabel();
|
||||
if ($bundle_entity_type = $entity_type->getBundleEntityType()) {
|
||||
// This is a better fallback.
|
||||
$fallback = $this->entityManager->getDefinition($bundle_entity_type)->getLabel();
|
||||
}
|
||||
|
||||
return $this->t('@label bundle', ['@label' => $fallback]);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools\Plugin\Deriver;
|
||||
|
||||
|
||||
use Drupal\Component\Plugin\Derivative\DeriverBase;
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
|
||||
use Drupal\Core\StringTranslation\StringTranslationTrait;
|
||||
use Drupal\Core\StringTranslation\TranslationInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* An abstract base class that sets up the needs of entity specific derivers.
|
||||
*/
|
||||
abstract class EntityDeriverBase extends DeriverBase implements ContainerDeriverInterface {
|
||||
|
||||
use StringTranslationTrait;
|
||||
|
||||
/**
|
||||
* The entity manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityManagerInterface
|
||||
*/
|
||||
protected $entityManager;
|
||||
|
||||
/**
|
||||
* Constructs new EntityViewDeriver.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
|
||||
* The entity manager.
|
||||
* @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation
|
||||
* The string translation service.
|
||||
*/
|
||||
public function __construct(EntityManagerInterface $entity_manager, TranslationInterface $string_translation) {
|
||||
$this->entityManager = $entity_manager;
|
||||
$this->stringTranslation = $string_translation;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, $base_plugin_id) {
|
||||
return new static(
|
||||
$container->get('entity.manager'),
|
||||
$container->get('string_translation')
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools\Plugin\Deriver;
|
||||
|
||||
use Drupal\Core\Plugin\Context\ContextDefinition;
|
||||
|
||||
/**
|
||||
* Provides entity view block definitions for each entity type.
|
||||
*/
|
||||
class EntityViewDeriver extends EntityDeriverBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDerivativeDefinitions($base_plugin_definition) {
|
||||
foreach ($this->entityManager->getDefinitions() as $entity_type_id => $entity_type) {
|
||||
if ($entity_type->hasViewBuilderClass()) {
|
||||
$this->derivatives[$entity_type_id] = $base_plugin_definition;
|
||||
$this->derivatives[$entity_type_id]['admin_label'] = $this->t('Entity view (@label)', ['@label' => $entity_type->getLabel()]);
|
||||
$this->derivatives[$entity_type_id]['context'] = [
|
||||
'entity' => new ContextDefinition('entity:' . $entity_type_id),
|
||||
];
|
||||
}
|
||||
}
|
||||
return $this->derivatives;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools\Plugin\Deriver;
|
||||
|
||||
|
||||
use Drupal\Core\TypedData\DataDefinitionInterface;
|
||||
|
||||
class TypedDataEntityRelationshipDeriver extends TypedDataRelationshipDeriver {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $label = '@property Entity from @base';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function generateDerivativeDefinition($base_plugin_definition, $data_type_id, $data_type_definition, DataDefinitionInterface $base_definition, $property_name, DataDefinitionInterface $property_definition) {
|
||||
if (method_exists($property_definition, 'getType') && $property_definition->getType() == 'entity_reference') {
|
||||
parent::generateDerivativeDefinition($base_plugin_definition, $data_type_id, $data_type_definition, $base_definition, $property_name, $property_definition);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools\Plugin\Deriver;
|
||||
|
||||
|
||||
use Drupal\Core\TypedData\DataDefinitionInterface;
|
||||
|
||||
class TypedDataLanguageRelationshipDeriver extends TypedDataRelationshipDeriver {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @todo this results in awful labels like "Language Language from Content"
|
||||
* Fix it.
|
||||
*/
|
||||
protected $label = '@property Language from @base';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function generateDerivativeDefinition($base_plugin_definition, $data_type_id, $data_type_definition, DataDefinitionInterface $base_definition, $property_name, DataDefinitionInterface $property_definition) {
|
||||
if (method_exists($property_definition, 'getType') && $property_definition->getType() == 'language') {
|
||||
parent::generateDerivativeDefinition($base_plugin_definition, $data_type_id, $data_type_definition, $base_definition, $property_name, $property_definition);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDerivativeDefinitions($base_plugin_definition) {
|
||||
parent::getDerivativeDefinitions($base_plugin_definition);
|
||||
// The data types will all be set to string since language extends string
|
||||
// and the parent class finds the related primitive.
|
||||
foreach ($this->derivatives as $plugin_id => $derivative) {
|
||||
$this->derivatives[$plugin_id]['data_type'] = 'language';
|
||||
}
|
||||
return $this->derivatives;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools\Plugin\Deriver;
|
||||
|
||||
|
||||
use Drupal\Component\Plugin\Derivative\DeriverBase;
|
||||
use Drupal\Core\Field\BaseFieldDefinition;
|
||||
use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
|
||||
use Drupal\Core\StringTranslation\StringTranslationTrait;
|
||||
use Drupal\Core\StringTranslation\TranslationInterface;
|
||||
use Drupal\Core\TypedData\ComplexDataInterface;
|
||||
use Drupal\Core\TypedData\DataDefinitionInterface;
|
||||
use Drupal\Core\TypedData\DataReferenceDefinitionInterface;
|
||||
use Drupal\Core\TypedData\ListDataDefinitionInterface;
|
||||
use Drupal\Core\TypedData\TypedDataManagerInterface;
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
abstract class TypedDataPropertyDeriverBase extends DeriverBase implements ContainerDeriverInterface {
|
||||
|
||||
use StringTranslationTrait;
|
||||
|
||||
/**
|
||||
* @var \Drupal\Core\TypedData\TypedDataManagerInterface
|
||||
*/
|
||||
protected $typedDataManager;
|
||||
|
||||
/**
|
||||
* The label string for use with derivative labels.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $label = '@property from @base';
|
||||
|
||||
/**
|
||||
* TypedDataPropertyDeriverBase constructor.
|
||||
*
|
||||
* @param \Drupal\Core\TypedData\TypedDataManagerInterface $typed_data_manager
|
||||
* The typed data manager.
|
||||
* @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation
|
||||
* The string translation service.
|
||||
*/
|
||||
public function __construct(TypedDataManagerInterface $typed_data_manager, TranslationInterface $string_translation) {
|
||||
$this->typedDataManager = $typed_data_manager;
|
||||
$this->stringTranslation = $string_translation;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, $base_plugin_id) {
|
||||
return new static(
|
||||
$container->get('typed_data_manager'),
|
||||
$container->get('string_translation')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDerivativeDefinitions($base_plugin_definition) {
|
||||
foreach ($this->typedDataManager->getDefinitions() as $data_type_id => $data_type_definition) {
|
||||
if (is_subclass_of($data_type_definition['class'], ComplexDataInterface::class, TRUE)) {
|
||||
/** @var \Drupal\Core\TypedData\ComplexDataDefinitionInterface $base_definition */
|
||||
$base_definition = $this->typedDataManager->createDataDefinition($data_type_id);
|
||||
foreach ($base_definition->getPropertyDefinitions() as $property_name => $property_definition) {
|
||||
if ($property_definition instanceof BaseFieldDefinition || $property_definition instanceof FieldConfig) {
|
||||
$this->generateDerivativeDefinition($base_plugin_definition, $data_type_id, $data_type_definition, $base_definition, $property_name, $property_definition);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $this->derivatives;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $property_definition
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function getDataType($property_definition) {
|
||||
if ($property_definition instanceof DataReferenceDefinitionInterface) {
|
||||
return $property_definition->getTargetDefinition()->getDataType();
|
||||
}
|
||||
if ($property_definition instanceof ListDataDefinitionInterface) {
|
||||
return $property_definition->getItemDefinition()->getDataType();
|
||||
}
|
||||
return $property_definition->getDataType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates and maintains a derivative definition.
|
||||
*
|
||||
* This method should directly manipulate $this->derivatives and not return
|
||||
* values. This allows implementations control over the derivative names.
|
||||
*
|
||||
* @param $base_plugin_definition
|
||||
* The base plugin definition.
|
||||
* @param string $data_type_id
|
||||
* The plugin id of the data type.
|
||||
* @param mixed $data_type_definition
|
||||
* The plugin definition of the data type.
|
||||
* @param \Drupal\Core\TypedData\DataDefinitionInterface $base_definition
|
||||
* The data type definition of a complex data object.
|
||||
* @param string $property_name
|
||||
* The name of the property
|
||||
* @param \Drupal\Core\TypedData\DataDefinitionInterface $property_definition
|
||||
* The property definition.
|
||||
*
|
||||
*/
|
||||
abstract protected function generateDerivativeDefinition($base_plugin_definition, $data_type_id, $data_type_definition, DataDefinitionInterface $base_definition, $property_name, DataDefinitionInterface $property_definition);
|
||||
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools\Plugin\Deriver;
|
||||
|
||||
|
||||
use Drupal\Core\Plugin\Context\ContextDefinition;
|
||||
use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
|
||||
use Drupal\Core\TypedData\DataDefinitionInterface;
|
||||
use Drupal\field\FieldConfigInterface;
|
||||
|
||||
class TypedDataRelationshipDeriver extends TypedDataPropertyDeriverBase implements ContainerDeriverInterface {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function generateDerivativeDefinition($base_plugin_definition, $data_type_id, $data_type_definition, DataDefinitionInterface $base_definition, $property_name, DataDefinitionInterface $property_definition) {
|
||||
$bundle_info = $base_definition->getConstraint('Bundle');
|
||||
// Identify base definitions that appear on bundle-able entities.
|
||||
if ($bundle_info && array_filter($bundle_info) && $base_definition->getConstraint('EntityType')) {
|
||||
$base_data_type = 'entity:' . $base_definition->getConstraint('EntityType');
|
||||
}
|
||||
// Otherwise, just use the raw data type identifier.
|
||||
else {
|
||||
$base_data_type = $data_type_id;
|
||||
}
|
||||
// If we've not processed this thing before.
|
||||
if (!isset($this->derivatives[$base_data_type . ':' . $property_name])) {
|
||||
$derivative = $base_plugin_definition;
|
||||
|
||||
$derivative['label'] = $this->t($this->label, [
|
||||
'@property' => $property_definition->getLabel(),
|
||||
'@base' => $data_type_definition['label'],
|
||||
]);
|
||||
$derivative['data_type'] = $property_definition->getFieldStorageDefinition()->getPropertyDefinition($property_definition->getFieldStorageDefinition()->getMainPropertyName())->getDataType();
|
||||
$derivative['property_name'] = $property_name;
|
||||
$context_definition = new ContextDefinition($base_data_type, $this->typedDataManager->createDataDefinition($base_data_type));
|
||||
// Add the constraints of the base definition to the context definition.
|
||||
if ($base_definition->getConstraint('Bundle')) {
|
||||
$context_definition->addConstraint('Bundle', $base_definition->getConstraint('Bundle'));
|
||||
}
|
||||
$derivative['context'] = [
|
||||
'base' => $context_definition,
|
||||
];
|
||||
$derivative['property_name'] = $property_name;
|
||||
|
||||
$this->derivatives[$base_data_type . ':' . $property_name] = $derivative;
|
||||
}
|
||||
// Individual fields can be on multiple bundles.
|
||||
elseif ($property_definition instanceof FieldConfigInterface) {
|
||||
// We should only end up in here on entity bundles.
|
||||
$derivative = $this->derivatives[$base_data_type . ':' . $property_name];
|
||||
// Update label
|
||||
/** @var \Drupal\Core\StringTranslation\TranslatableMarkup $label */
|
||||
$label = $derivative['label'];
|
||||
list(,, $argument_name) = explode(':', $data_type_id);
|
||||
$arguments = $label->getArguments();
|
||||
$arguments['@'. $argument_name] = $data_type_definition['label'];
|
||||
$string_args = $arguments;
|
||||
array_shift($string_args);
|
||||
$last = array_slice($string_args, -1);
|
||||
// The slice doesn't remove, so do that now.
|
||||
array_pop($string_args);
|
||||
$string = count($string_args) >= 2 ? '@property from '. implode(', ', array_keys($string_args)) .' and '. array_keys($last)[0] : '@property from @base and '. array_keys($last)[0];
|
||||
$this->derivatives[$base_data_type . ':' . $property_name]['label'] = $this->t($string, $arguments);
|
||||
if ($base_definition->getConstraint('Bundle')) {
|
||||
// Add bundle constraints
|
||||
$context_definition = $derivative['context']['base'];
|
||||
$bundles = $context_definition->getConstraint('Bundle') ?: [];
|
||||
$bundles = array_merge($bundles, $base_definition->getConstraint('Bundle'));
|
||||
$context_definition->addConstraint('Bundle', $bundles);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,226 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools\Plugin\DisplayVariant;
|
||||
|
||||
use Drupal\Component\Uuid\UuidInterface;
|
||||
use Drupal\Core\Block\BlockManager;
|
||||
use Drupal\Core\Cache\RefinableCacheableDependencyInterface;
|
||||
use Drupal\Core\Condition\ConditionManager;
|
||||
use Drupal\Core\Display\VariantBase;
|
||||
use Drupal\Core\Display\ContextAwareVariantInterface;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\Core\Plugin\Context\ContextHandlerInterface;
|
||||
use Drupal\Core\Render\Element;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\Core\Utility\Token;
|
||||
use Drupal\ctools\Form\AjaxFormTrait;
|
||||
use Drupal\ctools\Plugin\BlockVariantInterface;
|
||||
use Drupal\ctools\Plugin\BlockVariantTrait;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides a base class for a display variant that simply contains blocks.
|
||||
*/
|
||||
abstract class BlockDisplayVariant extends VariantBase implements ContextAwareVariantInterface, ContainerFactoryPluginInterface, BlockVariantInterface, RefinableCacheableDependencyInterface {
|
||||
|
||||
use AjaxFormTrait;
|
||||
use BlockVariantTrait;
|
||||
|
||||
/**
|
||||
* The context handler.
|
||||
*
|
||||
* @var \Drupal\Core\Plugin\Context\ContextHandlerInterface
|
||||
*/
|
||||
protected $contextHandler;
|
||||
|
||||
/**
|
||||
* The UUID generator.
|
||||
*
|
||||
* @var \Drupal\Component\Uuid\UuidInterface
|
||||
*/
|
||||
protected $uuidGenerator;
|
||||
|
||||
/**
|
||||
* The current user.
|
||||
*
|
||||
* @var \Drupal\Core\Session\AccountInterface
|
||||
*/
|
||||
protected $account;
|
||||
|
||||
/**
|
||||
* The token service.
|
||||
*
|
||||
* @var \Drupal\Core\Utility\Token
|
||||
*/
|
||||
protected $token;
|
||||
|
||||
/**
|
||||
* An array of collected contexts.
|
||||
*
|
||||
* This is only used on runtime, and is not stored.
|
||||
*
|
||||
* @var \Drupal\Component\Plugin\Context\ContextInterface[]
|
||||
*/
|
||||
protected $contexts = [];
|
||||
|
||||
/**
|
||||
* Constructs a new BlockDisplayVariant.
|
||||
*
|
||||
* @param array $configuration
|
||||
* A configuration array containing information about the plugin instance.
|
||||
* @param string $plugin_id
|
||||
* The plugin ID for the plugin instance.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
* @param \Drupal\Core\Plugin\Context\ContextHandlerInterface $context_handler
|
||||
* The context handler.
|
||||
* @param \Drupal\Core\Session\AccountInterface $account
|
||||
* The current user.
|
||||
* @param \Drupal\Component\Uuid\UuidInterface $uuid_generator
|
||||
* The UUID generator.
|
||||
* @param \Drupal\Core\Utility\Token $token
|
||||
* The token service.
|
||||
* @param \Drupal\Core\Block\BlockManager $block_manager
|
||||
* The block manager.
|
||||
* @param \Drupal\Core\Condition\ConditionManager $condition_manager
|
||||
* The condition manager.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, ContextHandlerInterface $context_handler, AccountInterface $account, UuidInterface $uuid_generator, Token $token, BlockManager $block_manager, ConditionManager $condition_manager) {
|
||||
// Inject dependencies as early as possible, so they can be used in
|
||||
// configuration.
|
||||
$this->contextHandler = $context_handler;
|
||||
$this->account = $account;
|
||||
$this->uuidGenerator = $uuid_generator;
|
||||
$this->token = $token;
|
||||
$this->blockManager = $block_manager;
|
||||
$this->conditionManager = $condition_manager;
|
||||
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||
return new static(
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$container->get('context.handler'),
|
||||
$container->get('current_user'),
|
||||
$container->get('uuid'),
|
||||
$container->get('token'),
|
||||
$container->get('plugin.manager.block'),
|
||||
$container->get('plugin.manager.condition')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function defaultConfiguration() {
|
||||
return parent::defaultConfiguration() + [
|
||||
'blocks' => []
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function calculateDependencies() {
|
||||
foreach ($this->getBlockCollection() as $instance) {
|
||||
$this->calculatePluginDependencies($instance);
|
||||
}
|
||||
return $this->dependencies;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getConfiguration() {
|
||||
return [
|
||||
'blocks' => $this->getBlockCollection()->getConfiguration(),
|
||||
] + parent::getConfiguration();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setConfiguration(array $configuration) {
|
||||
// preserve the uuid.
|
||||
if ($this->configuration && !empty($this->configuration['uuid'])) {
|
||||
$configuration['uuid'] = $this->configuration['uuid'];
|
||||
}
|
||||
parent::setConfiguration($configuration);
|
||||
$this->getBlockCollection()->setConfiguration($this->configuration['blocks']);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the contexts.
|
||||
*
|
||||
* @return \Drupal\Component\Plugin\Context\ContextInterface[]
|
||||
* An array of set contexts, keyed by context name.
|
||||
*/
|
||||
public function getContexts() {
|
||||
return $this->contexts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the contexts.
|
||||
*
|
||||
* @param \Drupal\Component\Plugin\Context\ContextInterface[] $contexts
|
||||
* An array of contexts, keyed by context name.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setContexts(array $contexts) {
|
||||
$this->contexts = $contexts;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function contextHandler() {
|
||||
return $this->contextHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getBlockConfig() {
|
||||
return $this->configuration['blocks'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function uuidGenerator() {
|
||||
return $this->uuidGenerator;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __sleep() {
|
||||
$vars = parent::__sleep();
|
||||
|
||||
// Gathered contexts objects should not be serialized.
|
||||
if (($key = array_search('contexts', $vars)) !== FALSE) {
|
||||
unset($vars[$key]);
|
||||
}
|
||||
|
||||
// The block plugin collection should also not be serialized, ensure that
|
||||
// configuration is synced back.
|
||||
if (($key = array_search('blockPluginCollection', $vars)) !== FALSE) {
|
||||
if ($this->blockPluginCollection) {
|
||||
$this->configuration['blocks'] = $this->blockPluginCollection->getConfiguration();
|
||||
}
|
||||
unset($vars[$key]);
|
||||
}
|
||||
|
||||
return $vars;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools\Plugin;
|
||||
|
||||
/**
|
||||
* Provides an interface for configuring a plugin via wizard steps.
|
||||
*/
|
||||
interface PluginWizardInterface {
|
||||
|
||||
/**
|
||||
* Retrieve a list of FormInterface classes by their step key in the wizard.
|
||||
*
|
||||
* @param mixed $cached_values
|
||||
* The cached values used in the wizard. The plugin we're editing will
|
||||
* always be assigned to the 'plugin' key.
|
||||
*
|
||||
* @return array
|
||||
* An associative array keyed on the step name with an array value with the
|
||||
* following keys:
|
||||
* - title (string): Human-readable title of the step.
|
||||
* - form (string): Fully-qualified class name of the form for this step.
|
||||
*/
|
||||
public function getWizardOperations($cached_values);
|
||||
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools\Plugin\Relationship;
|
||||
use Drupal\Core\Plugin\Context\Context;
|
||||
use Drupal\Core\Plugin\Context\ContextDefinition;
|
||||
|
||||
/**
|
||||
* @Relationship(
|
||||
* id = "typed_data_entity_relationship",
|
||||
* deriver = "\Drupal\ctools\Plugin\Deriver\TypedDataEntityRelationshipDeriver"
|
||||
* )
|
||||
*/
|
||||
class TypedDataEntityRelationship extends TypedDataRelationship {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getRelationship() {
|
||||
$plugin_definition = $this->getPluginDefinition();
|
||||
|
||||
$entity_type = $this->getData($this->getContext('base'))->getDataDefinition()->getSetting('target_type');
|
||||
$context_definition = new ContextDefinition("entity:$entity_type", $plugin_definition['label']);
|
||||
$context_value = NULL;
|
||||
|
||||
// If the 'base' context has a value, then get the property value to put on
|
||||
// the context (otherwise, mapping hasn't occurred yet and we just want to
|
||||
// return the context with the right definition and no value).
|
||||
if ($this->getContext('base')->hasContextValue()) {
|
||||
$context_value = $this->getData($this->getContext('base'))->entity;
|
||||
}
|
||||
|
||||
$context_definition->setDefaultValue($context_value);
|
||||
return new Context($context_definition, $context_value);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools\Plugin\Relationship;
|
||||
use Drupal\Core\Plugin\Context\Context;
|
||||
use Drupal\Core\Plugin\Context\ContextDefinition;
|
||||
|
||||
/**
|
||||
* @Relationship(
|
||||
* id = "typed_data_language_relationship",
|
||||
* deriver = "\Drupal\ctools\Plugin\Deriver\TypedDataLanguageRelationshipDeriver"
|
||||
* )
|
||||
*/
|
||||
class TypedDataLanguageRelationship extends TypedDataRelationship {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getRelationship() {
|
||||
$plugin_definition = $this->getPluginDefinition();
|
||||
|
||||
$context_definition = new ContextDefinition("language", $plugin_definition['label']);
|
||||
$context_value = NULL;
|
||||
|
||||
// If the 'base' context has a value, then get the property value to put on
|
||||
// the context (otherwise, mapping hasn't occurred yet and we just want to
|
||||
// return the context with the right definition and no value).
|
||||
if ($this->getContext('base')->hasContextValue()) {
|
||||
$context_value = $this->getData($this->getContext('base'))->language;
|
||||
}
|
||||
|
||||
$context_definition->setDefaultValue($context_value);
|
||||
return new Context($context_definition, $context_value);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools\Plugin\Relationship;
|
||||
|
||||
|
||||
use Drupal\Core\Field\FieldItemInterface;
|
||||
use Drupal\Core\Field\TypedData\FieldItemDataDefinition;
|
||||
use Drupal\Core\Plugin\Context\Context;
|
||||
use Drupal\Core\Plugin\Context\ContextDefinition;
|
||||
use Drupal\Core\Plugin\Context\ContextInterface;
|
||||
use Drupal\Core\TypedData\DataReferenceInterface;
|
||||
use Drupal\Core\TypedData\ListInterface;
|
||||
use Drupal\ctools\Annotation\Relationship;
|
||||
use Drupal\ctools\Plugin\RelationshipBase;
|
||||
|
||||
/**
|
||||
* @Relationship(
|
||||
* id = "typed_data_relationship",
|
||||
* deriver = "\Drupal\ctools\Plugin\Deriver\TypedDataRelationshipDeriver"
|
||||
* )
|
||||
*/
|
||||
class TypedDataRelationship extends RelationshipBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getRelationship() {
|
||||
$plugin_definition = $this->getPluginDefinition();
|
||||
|
||||
$data_type = $plugin_definition['data_type'];
|
||||
$context_definition = new ContextDefinition($data_type, $plugin_definition['label']);
|
||||
$context_value = NULL;
|
||||
|
||||
// If the 'base' context has a value, then get the property value to put on
|
||||
// the context (otherwise, mapping hasn't occurred yet and we just want to
|
||||
// return the context with the right definition and no value).
|
||||
if ($this->getContext('base')->hasContextValue()) {
|
||||
$data = $this->getData($this->getContext('base'));
|
||||
$property = $this->getMainPropertyName($data);
|
||||
$context_value = $data->get($property)->getValue();
|
||||
}
|
||||
|
||||
$context_definition->setDefaultValue($context_value);
|
||||
return new Context($context_definition, $context_value);
|
||||
}
|
||||
|
||||
public function getName() {
|
||||
return $this->getPluginDefinition()['property_name'];
|
||||
}
|
||||
|
||||
protected function getData(ContextInterface $context) {
|
||||
/** @var \Drupal\Core\TypedData\ComplexDataInterface $base */
|
||||
$base = $context->getContextValue();
|
||||
$name = $this->getPluginDefinition()['property_name'];
|
||||
$data = $base->get($name);
|
||||
// @todo add configuration to get N instead of first.
|
||||
if ($data instanceof ListInterface) {
|
||||
$data = $data->first();
|
||||
}
|
||||
if ($data instanceof DataReferenceInterface) {
|
||||
$data = $data->getTarget();
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
protected function getMainPropertyName(FieldItemInterface $data) {
|
||||
return $data->getFieldDefinition()->getFieldStorageDefinition()->getMainPropertyName();
|
||||
}
|
||||
|
||||
public function getRelationshipValue() {
|
||||
$property = $this->getMainPropertyName();
|
||||
/** @var \Drupal\Core\TypedData\ComplexDataInterface $data */
|
||||
$data = $this->getRelationship()->getContextData();
|
||||
$data->get($property)->getValue();
|
||||
}
|
||||
|
||||
}
|
10
web/modules/contrib/ctools/src/Plugin/RelationshipBase.php
Normal file
10
web/modules/contrib/ctools/src/Plugin/RelationshipBase.php
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools\Plugin;
|
||||
|
||||
use Drupal\Core\Plugin\ContextAwarePluginBase;
|
||||
|
||||
/**
|
||||
* Base class for Relationship plugins.
|
||||
*/
|
||||
abstract class RelationshipBase extends ContextAwarePluginBase implements RelationshipInterface {}
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools\Plugin;
|
||||
|
||||
use Drupal\Component\Plugin\DerivativeInspectionInterface;
|
||||
use Drupal\Core\Plugin\ContextAwarePluginInterface;
|
||||
|
||||
/**
|
||||
* Defines an interface for Relationship plugins.
|
||||
*/
|
||||
interface RelationshipInterface extends ContextAwarePluginInterface, DerivativeInspectionInterface {
|
||||
|
||||
/**
|
||||
* Generates a context based on this plugin's configuration.
|
||||
*
|
||||
* @return \Drupal\Core\Plugin\Context\ContextInterface
|
||||
*/
|
||||
public function getRelationship();
|
||||
|
||||
/**
|
||||
* The name of the property used to get this relationship.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName();
|
||||
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools\Plugin;
|
||||
|
||||
use Drupal\Core\Plugin\Context\ContextAwarePluginManagerTrait;
|
||||
use Drupal\Core\Plugin\DefaultPluginManager;
|
||||
use Drupal\Core\Cache\CacheBackendInterface;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
|
||||
/**
|
||||
* Provides the Relationship plugin manager.
|
||||
*/
|
||||
class RelationshipManager extends DefaultPluginManager implements RelationshipManagerInterface {
|
||||
|
||||
use ContextAwarePluginManagerTrait;
|
||||
|
||||
/**
|
||||
* Constructor for RelationshipManager objects.
|
||||
*
|
||||
* @param \Traversable $namespaces
|
||||
* An object that implements \Traversable which contains the root paths
|
||||
* keyed by the corresponding namespace to look for plugin implementations.
|
||||
* @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
|
||||
* Cache backend instance to use.
|
||||
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
|
||||
* The module handler to invoke the alter hook with.
|
||||
*/
|
||||
public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
|
||||
parent::__construct('Plugin/Relationship', $namespaces, $module_handler, 'Drupal\ctools\Plugin\RelationshipInterface', 'Drupal\ctools\Annotation\Relationship');
|
||||
|
||||
$this->alterInfo('ctools_relationship_info');
|
||||
$this->setCacheBackend($cache_backend, 'ctools_relationship_plugins');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools\Plugin;
|
||||
use Drupal\Component\Plugin\Discovery\CachedDiscoveryInterface;
|
||||
use Drupal\Core\Plugin\Context\ContextAwarePluginManagerInterface;
|
||||
|
||||
/**
|
||||
* Provides the Relationship plugin manager.
|
||||
*/
|
||||
interface RelationshipManagerInterface extends ContextAwarePluginManagerInterface, CachedDiscoveryInterface {}
|
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools\Plugin;
|
||||
|
||||
/**
|
||||
* Provides an interface for objects that have variants e.g. Pages.
|
||||
*/
|
||||
interface VariantCollectionInterface {
|
||||
|
||||
/**
|
||||
* Adds a new variant to the entity.
|
||||
*
|
||||
* @param array $configuration
|
||||
* An array of configuration for the new variant.
|
||||
*
|
||||
* @return string
|
||||
* The variant ID.
|
||||
*/
|
||||
public function addVariant(array $configuration);
|
||||
|
||||
/**
|
||||
* Retrieves a specific variant.
|
||||
*
|
||||
* @param string $variant_id
|
||||
* The variant ID.
|
||||
*
|
||||
* @return \Drupal\Core\Display\VariantInterface
|
||||
* The variant object.
|
||||
*/
|
||||
public function getVariant($variant_id);
|
||||
|
||||
/**
|
||||
* Removes a specific variant.
|
||||
*
|
||||
* @param string $variant_id
|
||||
* The variant ID.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function removeVariant($variant_id);
|
||||
|
||||
/**
|
||||
* Returns the variants available for the entity.
|
||||
*
|
||||
* @return \Drupal\Core\Display\VariantInterface[]
|
||||
* An array of the variants.
|
||||
*/
|
||||
public function getVariants();
|
||||
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools\Plugin;
|
||||
|
||||
/**
|
||||
* Provides methods for VariantCollectionInterface.
|
||||
*/
|
||||
trait VariantCollectionTrait {
|
||||
|
||||
/**
|
||||
* The plugin collection that holds the variants.
|
||||
*
|
||||
* @var \Drupal\ctools\Plugin\VariantPluginCollection
|
||||
*/
|
||||
protected $variantCollection;
|
||||
|
||||
/**
|
||||
* @see \Drupal\ctools\Plugin\VariantCollectionInterface::addVariant()
|
||||
*/
|
||||
public function addVariant(array $configuration) {
|
||||
$configuration['uuid'] = $this->uuidGenerator()->generate();
|
||||
$this->getVariants()->addInstanceId($configuration['uuid'], $configuration);
|
||||
return $configuration['uuid'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \Drupal\ctools\Plugin\VariantCollectionInterface::getVariant()
|
||||
*/
|
||||
public function getVariant($variant_id) {
|
||||
return $this->getVariants()->get($variant_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \Drupal\ctools\Plugin\VariantCollectionInterface::removeVariant()
|
||||
*/
|
||||
public function removeVariant($variant_id) {
|
||||
$this->getVariants()->removeInstanceId($variant_id);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \Drupal\ctools\Plugin\VariantCollectionInterface::getVariants()
|
||||
*/
|
||||
public function getVariants() {
|
||||
if (!$this->variantCollection) {
|
||||
$this->variantCollection = new VariantPluginCollection(\Drupal::service('plugin.manager.display_variant'), $this->getVariantConfig());
|
||||
$this->variantCollection->sort();
|
||||
}
|
||||
return $this->variantCollection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the configuration for stored variants.
|
||||
*
|
||||
* @return array
|
||||
* An array of variant configuration, keyed by the unique variant ID.
|
||||
*/
|
||||
abstract protected function getVariantConfig();
|
||||
|
||||
/**
|
||||
* Returns the UUID generator.
|
||||
*
|
||||
* @return \Drupal\Component\Uuid\UuidInterface
|
||||
*/
|
||||
abstract protected function uuidGenerator();
|
||||
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools\Plugin;
|
||||
|
||||
use Drupal\Core\Plugin\DefaultLazyPluginCollection;
|
||||
|
||||
/**
|
||||
* Provides a collection of variants plugins.
|
||||
*/
|
||||
class VariantPluginCollection extends DefaultLazyPluginCollection {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return \Drupal\Core\Display\VariantInterface
|
||||
*/
|
||||
public function &get($instance_id) {
|
||||
return parent::get($instance_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function sort() {
|
||||
// @todo Determine the reason this needs error suppression.
|
||||
@uasort($this->instanceIDs, [$this, 'sortHelper']);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function sortHelper($aID, $bID) {
|
||||
$a_weight = $this->get($aID)->getWeight();
|
||||
$b_weight = $this->get($bID)->getWeight();
|
||||
if ($a_weight == $b_weight) {
|
||||
return strcmp($aID, $bID);
|
||||
}
|
||||
|
||||
return ($a_weight < $b_weight) ? -1 : 1;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools\Routing\Enhancer;
|
||||
|
||||
use Drupal\Core\Routing\Enhancer\RouteEnhancerInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Routing\Route;
|
||||
|
||||
/**
|
||||
* Sets the request format onto the request object.
|
||||
*/
|
||||
class WizardEnhancer implements RouteEnhancerInterface {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function applies(Route $route) {
|
||||
return !$route->hasDefault('_controller') && ($route->hasDefault('_wizard') || $route->hasDefault('_entity_wizard'));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function enhance(array $defaults, Request $request) {
|
||||
if (!empty($defaults['_wizard'])) {
|
||||
$defaults['_controller'] = 'ctools.wizard.form:getContentResult';
|
||||
}
|
||||
if (!empty($defaults['_entity_wizard'])) {
|
||||
$defaults['_controller'] = 'ctools.wizard.entity.form:getContentResult';
|
||||
}
|
||||
return $defaults;
|
||||
}
|
||||
|
||||
}
|
13
web/modules/contrib/ctools/src/SerializableTempstore.php
Normal file
13
web/modules/contrib/ctools/src/SerializableTempstore.php
Normal file
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools;
|
||||
|
||||
use Drupal\Core\DependencyInjection\DependencySerializationTrait;
|
||||
use Drupal\user\SharedTempStore;
|
||||
|
||||
/**
|
||||
* An extension of the SharedTempStore system for serialized data.
|
||||
*/
|
||||
class SerializableTempstore extends SharedTempStore {
|
||||
use DependencySerializationTrait;
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools;
|
||||
|
||||
use Drupal\user\SharedTempStoreFactory;
|
||||
|
||||
/**
|
||||
* A factory for creating SerializableTempStore objects.
|
||||
*/
|
||||
class SerializableTempstoreFactory extends SharedTempStoreFactory {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function get($collection, $owner = NULL) {
|
||||
// Use the currently authenticated user ID or the active user ID unless the
|
||||
// owner is overridden.
|
||||
if (!isset($owner)) {
|
||||
$owner = \Drupal::currentUser()->id() ?: session_id();
|
||||
}
|
||||
|
||||
// Store the data for this collection in the database.
|
||||
$storage = $this->storageFactory->get("user.shared_tempstore.$collection");
|
||||
return new SerializableTempstore($storage, $this->lockBackend, $owner, $this->requestStack, $this->expire);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools\Testing;
|
||||
|
||||
|
||||
use Drupal\Component\Render\FormattableMarkup;
|
||||
|
||||
trait EntityCreationTrait {
|
||||
|
||||
/**
|
||||
* The entity type manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
|
||||
*/
|
||||
protected $entityTypeManager;
|
||||
|
||||
/**
|
||||
* Creates a custom content type based on default settings.
|
||||
*
|
||||
* @param string $entity_type
|
||||
* The type of entity to create.
|
||||
* @param array $values
|
||||
* An array of settings to change from the defaults.
|
||||
* Example: 'type' => 'foo'.
|
||||
*
|
||||
* @return \Drupal\Core\Entity\EntityInterface
|
||||
* Created entity.
|
||||
*/
|
||||
protected function createEntity($entity_type, array $values = array()) {
|
||||
$storage = $this->getEntityTypeManager()->getStorage($entity_type);
|
||||
$entity = $storage->create($values);
|
||||
$status = $entity->save();
|
||||
\Drupal::service('router.builder')->rebuild();
|
||||
|
||||
if ($this instanceof \PHPUnit_Framework_TestCase) {
|
||||
$this->assertSame($status, SAVED_NEW, (new FormattableMarkup('Created entity %id of type %type.', ['%id' => $entity->id(), '%type' => $entity_type]))->__toString());
|
||||
}
|
||||
else {
|
||||
$this->assertEqual($status, SAVED_NEW, (new FormattableMarkup('Created entity %id of type %type.', ['%id' => $entity->id(), '%type' => $entity_type]))->__toString());
|
||||
}
|
||||
|
||||
return $entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Drupal\Core\Entity\EntityTypeManagerInterface
|
||||
*/
|
||||
protected function getEntityTypeManager() {
|
||||
if (!isset($this->entityTypeManager)) {
|
||||
$this->entityTypeManager = $this->container->get('entity_type.manager');
|
||||
}
|
||||
return $this->entityTypeManager;
|
||||
}
|
||||
|
||||
}
|
136
web/modules/contrib/ctools/src/Tests/Wizard/CToolsWizardTest.php
Normal file
136
web/modules/contrib/ctools/src/Tests/Wizard/CToolsWizardTest.php
Normal file
|
@ -0,0 +1,136 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools\Tests\Wizard;
|
||||
|
||||
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
use Drupal\Core\StringTranslation\StringTranslationTrait;
|
||||
|
||||
|
||||
/**
|
||||
* Tests basic wizard functionality.
|
||||
*
|
||||
* @group ctools
|
||||
*/
|
||||
class CToolsWizardTest extends WebTestBase {
|
||||
|
||||
use StringTranslationTrait;
|
||||
public static $modules = array('ctools', 'ctools_wizard_test');
|
||||
|
||||
function testWizardSteps() {
|
||||
$this->drupalGet('ctools/wizard');
|
||||
$this->assertText('Form One');
|
||||
$this->dumpHeaders = TRUE;
|
||||
// Check that $operations['one']['values'] worked.
|
||||
$this->assertText('Xylophone');
|
||||
// Submit first step in the wizard.
|
||||
$edit = [
|
||||
'one' => 'test',
|
||||
];
|
||||
$this->drupalPostForm('ctools/wizard', $edit, $this->t('Next'));
|
||||
// Redirected to the second step.
|
||||
$this->assertText('Form Two');
|
||||
$this->assertText('Dynamic value submitted: Xylophone');
|
||||
// Check that $operations['two']['values'] worked.
|
||||
$this->assertText('Zebra');
|
||||
// Hit previous to make sure our form value are preserved.
|
||||
$this->drupalPostForm(NULL, [], $this->t('Previous'));
|
||||
// Check the known form values.
|
||||
$this->assertFieldByName('one', 'test');
|
||||
$this->assertText('Xylophone');
|
||||
// Goto next step again and finish this wizard.
|
||||
$this->drupalPostForm(NULL, [], $this->t('Next'));
|
||||
$edit = [
|
||||
'two' => 'Second test',
|
||||
];
|
||||
$this->drupalPostForm(NULL, $edit, $this->t('Finish'));
|
||||
// Check that the wizard finished properly.
|
||||
$this->assertText('Value One: test');
|
||||
$this->assertText('Value Two: Second test');
|
||||
}
|
||||
|
||||
function testStepValidateAndSubmit() {
|
||||
$this->drupalGet('ctools/wizard');
|
||||
$this->assertText('Form One');
|
||||
// Submit first step in the wizard.
|
||||
$edit = [
|
||||
'one' => 'wrong',
|
||||
];
|
||||
$this->drupalPostForm('ctools/wizard', $edit, $this->t('Next'));
|
||||
// We're still on the first form and the error is present.
|
||||
$this->assertText('Form One');
|
||||
$this->assertText('Cannot set the value to "wrong".');
|
||||
// Try again with the magic value.
|
||||
$edit = [
|
||||
'one' => 'magic',
|
||||
];
|
||||
$this->drupalPostForm('ctools/wizard', $edit, $this->t('Next'));
|
||||
// Redirected to the second step.
|
||||
$this->assertText('Form Two');
|
||||
$edit = [
|
||||
'two' => 'Second test',
|
||||
];
|
||||
$this->drupalPostForm(NULL, $edit, $this->t('Finish'));
|
||||
// Check that the magic value triggered our submit callback.
|
||||
$this->assertText('Value One: Abraham');
|
||||
$this->assertText('Value Two: Second test');
|
||||
}
|
||||
|
||||
function testEntityWizard() {
|
||||
$this->drupalLogin($this->drupalCreateUser(['administer site configuration']));
|
||||
|
||||
// Start adding a new config entity.
|
||||
$this->drupalGet('admin/structure/ctools_wizard_test_config_entity/add');
|
||||
$this->assertText('Example entity');
|
||||
$this->assertNoText('Existing entity');
|
||||
|
||||
// Submit the general step.
|
||||
$edit = [
|
||||
'id' => 'test123',
|
||||
'label' => 'Test Config Entity 123',
|
||||
];
|
||||
$this->drupalPostForm(NULL, $edit, $this->t('Next'));
|
||||
|
||||
// Submit the first step.
|
||||
$edit = [
|
||||
'one' => 'The first bit',
|
||||
];
|
||||
$this->drupalPostForm(NULL, $edit, $this->t('Next'));
|
||||
|
||||
// Submit the second step.
|
||||
$edit = [
|
||||
'two' => 'The second bit',
|
||||
];
|
||||
$this->drupalPostForm(NULL, $edit, $this->t('Finish'));
|
||||
|
||||
// Now we should be looking at the list of entities.
|
||||
$this->assertUrl('admin/structure/ctools_wizard_test_config_entity');
|
||||
$this->assertText('Test Config Entity 123');
|
||||
|
||||
// Edit the entity again and make sure the values are what we expect.
|
||||
$this->clickLink(t('Edit'));
|
||||
$this->assertText('Existing entity');
|
||||
$this->assertFieldByName('label', 'Test Config Entity 123');
|
||||
$this->clickLink(t('Form One'));
|
||||
$this->assertFieldByName('one', 'The first bit');
|
||||
$previous = $this->getUrl();
|
||||
$this->clickLink(t('Show on dialog'));
|
||||
$this->assertRaw('Value from one: The first bit');
|
||||
$this->drupalGet($previous);
|
||||
// Change the value for 'one'.
|
||||
$this->drupalPostForm(NULL, ['one' => 'New value'], $this->t('Next'));
|
||||
$this->assertFieldByName('two', 'The second bit');
|
||||
$this->drupalPostForm(NULL, [], $this->t('Next'));
|
||||
// Make sure we get the additional step because the entity exists.
|
||||
$this->assertText('This step only shows if the entity is already existing!');
|
||||
$this->drupalPostForm(NULL, [], $this->t('Finish'));
|
||||
|
||||
// Edit the entity again and make sure the change stuck.
|
||||
$this->assertUrl('admin/structure/ctools_wizard_test_config_entity');
|
||||
$this->clickLink(t('Edit'));
|
||||
$this->drupalPostForm(NULL, [], $this->t('Next'));
|
||||
$this->assertFieldByName('one', 'New value');
|
||||
}
|
||||
|
||||
}
|
||||
|
253
web/modules/contrib/ctools/src/TypedDataResolver.php
Normal file
253
web/modules/contrib/ctools/src/TypedDataResolver.php
Normal file
|
@ -0,0 +1,253 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools;
|
||||
|
||||
|
||||
use Drupal\Core\Field\BaseFieldDefinition;
|
||||
use Drupal\Core\Plugin\Context\Context;
|
||||
use Drupal\Core\Plugin\Context\ContextDefinition;
|
||||
use Drupal\Core\Plugin\Context\ContextDefinitionInterface;
|
||||
use Drupal\Core\Plugin\Context\ContextInterface;
|
||||
use Drupal\Core\StringTranslation\TranslationInterface;
|
||||
use Drupal\Core\TypedData\ComplexDataDefinitionInterface;
|
||||
use Drupal\Core\TypedData\DataReferenceDefinitionInterface;
|
||||
use Drupal\Core\TypedData\DataReferenceInterface;
|
||||
use Drupal\Core\TypedData\ListDataDefinitionInterface;
|
||||
use Drupal\Core\TypedData\ListInterface;
|
||||
use Drupal\Core\TypedData\TypedDataManagerInterface;
|
||||
|
||||
class TypedDataResolver {
|
||||
|
||||
/**
|
||||
* The typed data manager.
|
||||
*
|
||||
* @var \Drupal\Core\TypedData\TypedDataManagerInterface
|
||||
*/
|
||||
protected $manager;
|
||||
|
||||
/**
|
||||
* The string translation service.
|
||||
*
|
||||
* @var \Drupal\Core\StringTranslation\TranslationInterface
|
||||
*/
|
||||
protected $translation;
|
||||
|
||||
/**
|
||||
* @param \Drupal\Core\TypedData\TypedDataManagerInterface $manager
|
||||
* The typed data manager.
|
||||
* @param \Drupal\Core\StringTranslation\TranslationInterface $translation
|
||||
* The string translation service.
|
||||
*/
|
||||
public function __construct(TypedDataManagerInterface $manager, TranslationInterface $translation) {
|
||||
$this->manager = $manager;
|
||||
$this->translation = $translation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a property to a context.
|
||||
*
|
||||
* This method will respect the value of contexts as well, so if a context
|
||||
* object is pass that contains a value, the appropriate value will be
|
||||
* extracted and injected into the resulting context object if available.
|
||||
*
|
||||
* @param string $property_path
|
||||
* The name of the property.
|
||||
* @param \Drupal\Core\Plugin\Context\ContextInterface $context
|
||||
* The context from which we will extract values if available.
|
||||
*
|
||||
* @return \Drupal\Core\Plugin\Context\Context
|
||||
* A context object that represents the definition & value of the property.
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function getContextFromProperty($property_path, ContextInterface $context) {
|
||||
$value = NULL;
|
||||
$data_definition = NULL;
|
||||
if ($context->hasContextValue()) {
|
||||
/** @var \Drupal\Core\TypedData\ComplexDataInterface $data */
|
||||
$data = $context->getContextData();
|
||||
foreach (explode(':', $property_path) as $name) {
|
||||
|
||||
if ($data instanceof ListInterface) {
|
||||
if (!is_numeric($name)) {
|
||||
// Implicitly default to delta 0 for lists when not specified.
|
||||
$data = $data->first();
|
||||
}
|
||||
else {
|
||||
// If we have a delta, fetch it and continue with the next part.
|
||||
$data = $data->get($name);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Forward to the target value if this is a data reference.
|
||||
if ($data instanceof DataReferenceInterface) {
|
||||
$data = $data->getTarget();
|
||||
}
|
||||
|
||||
if (!$data->getDataDefinition()->getPropertyDefinition($name)) {
|
||||
throw new \Exception("Unknown property $name in property path $property_path");
|
||||
}
|
||||
$data = $data->get($name);
|
||||
}
|
||||
|
||||
$value = $data->getValue();
|
||||
$data_definition = $data instanceof DataReferenceInterface ? $data->getDataDefinition()->getTargetDefinition() : $data->getDataDefinition();
|
||||
}
|
||||
else {
|
||||
/** @var \Drupal\Core\TypedData\ComplexDataDefinitionInterface $data_definition */
|
||||
$data_definition = $context->getContextDefinition()->getDataDefinition();
|
||||
foreach (explode(':', $property_path) as $name) {
|
||||
|
||||
if ($data_definition instanceof ListDataDefinitionInterface) {
|
||||
$data_definition = $data_definition->getItemDefinition();
|
||||
|
||||
// If the delta was specified explicitly, continue with the next part.
|
||||
if (is_numeric($name)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Forward to the target definition if this is a data reference
|
||||
// definition.
|
||||
if ($data_definition instanceof DataReferenceDefinitionInterface) {
|
||||
$data_definition = $data_definition->getTargetDefinition();
|
||||
}
|
||||
|
||||
if (!$data_definition->getPropertyDefinition($name)) {
|
||||
throw new \Exception("Unknown property $name in property path $property_path");
|
||||
}
|
||||
$data_definition = $data_definition->getPropertyDefinition($name);
|
||||
}
|
||||
|
||||
// Forward to the target definition if this is a data reference
|
||||
// definition.
|
||||
if ($data_definition instanceof DataReferenceDefinitionInterface) {
|
||||
$data_definition = $data_definition->getTargetDefinition();
|
||||
}
|
||||
}
|
||||
$context_definition = new ContextDefinition($data_definition->getDataType(), $data_definition->getLabel(), $data_definition->isRequired(), FALSE, $data_definition->getDescription());
|
||||
return new Context($context_definition, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts a context from an array of contexts by a tokenized pattern.
|
||||
*
|
||||
* This is more than simple isset/empty checks on the contexts array. The
|
||||
* pattern could be node:uid:name which will iterate over all provided
|
||||
* contexts in the array for one named 'node', it will then load the data
|
||||
* definition of 'node' and check for a property named 'uid'. This will then
|
||||
* set a new (temporary) context on the array and recursively call itself to
|
||||
* navigate through related properties all the way down until the request
|
||||
* property is located. At that point the property is passed to a
|
||||
* TypedDataResolver which will convert it to an appropriate ContextInterface
|
||||
* object.
|
||||
*
|
||||
* @param $token
|
||||
* A ":" delimited set of tokens representing
|
||||
* @param \Drupal\Core\Plugin\Context\ContextInterface[] $contexts
|
||||
* The array of available contexts.
|
||||
*
|
||||
* @return \Drupal\Core\Plugin\Context\ContextInterface
|
||||
* The requested token as a full Context object.
|
||||
*
|
||||
* @throws \Drupal\ctools\ContextNotFoundException
|
||||
*/
|
||||
public function convertTokenToContext($token, $contexts) {
|
||||
// If the requested token is already a context, just return it.
|
||||
if (isset($contexts[$token])) {
|
||||
return $contexts[$token];
|
||||
}
|
||||
else {
|
||||
list($base, $property_path) = explode(':', $token, 2);
|
||||
// A base must always be set. This method recursively calls itself
|
||||
// setting bases for this reason.
|
||||
if (!empty($contexts[$base])) {
|
||||
return $this->getContextFromProperty($property_path, $contexts[$base]);
|
||||
}
|
||||
// @todo improve this exception message.
|
||||
throw new ContextNotFoundException("The requested context was not found in the supplied array of contexts.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides an administrative label for a tokenized relationship.
|
||||
*
|
||||
* @param string $token
|
||||
* The token related to a context in the contexts array.
|
||||
* @param \Drupal\Core\Plugin\Context\ContextInterface[] $contexts
|
||||
* An array of contexts from which to extract our token's label.
|
||||
*
|
||||
* @return \Drupal\Core\StringTranslation\TranslatableMarkup
|
||||
* The administrative label of $token.
|
||||
*/
|
||||
public function getLabelByToken($token, $contexts) {
|
||||
// @todo Optimize this by allowing to limit the desired token?
|
||||
$tokens = $this->getTokensForContexts($contexts);
|
||||
if (isset($tokens[$token])) {
|
||||
return $tokens[$token];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts an array of tokens and labels.
|
||||
*
|
||||
* @param \Drupal\Core\Plugin\Context\ContextInterface[] $contexts
|
||||
* The array of contexts with which we are currently dealing.
|
||||
*
|
||||
* @return array
|
||||
* An array of token keys and corresponding labels.
|
||||
*/
|
||||
public function getTokensForContexts($contexts) {
|
||||
$tokens = [];
|
||||
foreach ($contexts as $context_id => $context) {
|
||||
$data_definition = $context->getContextDefinition()->getDataDefinition();
|
||||
if ($data_definition instanceof ComplexDataDefinitionInterface) {
|
||||
foreach ($this->getTokensFromComplexData($data_definition) as $token => $label) {
|
||||
$tokens["$context_id:$token"] = $data_definition->getLabel() . ': ' . $label;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns tokens for a complex data definition.
|
||||
*
|
||||
* @param \Drupal\Core\TypedData\ComplexDataDefinitionInterface $complex_data_definition
|
||||
*
|
||||
* @return array
|
||||
* An array of token keys and corresponding labels.
|
||||
*/
|
||||
protected function getTokensFromComplexData(ComplexDataDefinitionInterface $complex_data_definition) {
|
||||
$tokens = [];
|
||||
// Loop over all properties.
|
||||
foreach ($complex_data_definition->getPropertyDefinitions() as $property_name => $property_definition) {
|
||||
|
||||
// Item definitions do not always have a label. Use the list definition
|
||||
// label if the item does not have one.
|
||||
$property_label = $property_definition->getLabel();
|
||||
if ($property_definition instanceof ListDataDefinitionInterface) {
|
||||
$property_definition = $property_definition->getItemDefinition();
|
||||
$property_label = $property_definition->getLabel() ?: $property_label;
|
||||
}
|
||||
|
||||
// If the property is complex too, recurse to find child properties.
|
||||
if ($property_definition instanceof ComplexDataDefinitionInterface) {
|
||||
$property_tokens = $this->getTokensFromComplexData($property_definition);
|
||||
foreach ($property_tokens as $token => $label) {
|
||||
$tokens[$property_name . ':' . $token] = count($property_tokens) > 1 ? ($property_label . ': ' . $label) : $property_label;
|
||||
}
|
||||
}
|
||||
|
||||
// Only expose references as tokens.
|
||||
// @todo Consider to expose primitive and non-reference typed data
|
||||
// definitions too, like strings, integers and dates. The current UI
|
||||
// will not scale to that.
|
||||
if ($property_definition instanceof DataReferenceDefinitionInterface) {
|
||||
$tokens[$property_name] = $property_definition->getLabel();
|
||||
}
|
||||
}
|
||||
return $tokens;
|
||||
}
|
||||
|
||||
}
|
180
web/modules/contrib/ctools/src/Wizard/EntityFormWizardBase.php
Normal file
180
web/modules/contrib/ctools/src/Wizard/EntityFormWizardBase.php
Normal file
|
@ -0,0 +1,180 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools\Wizard;
|
||||
|
||||
|
||||
use Drupal\Core\DependencyInjection\ClassResolverInterface;
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Form\FormBuilderInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Routing\RouteMatchInterface;
|
||||
use Drupal\ctools\Event\WizardEvent;
|
||||
use Drupal\user\SharedTempStoreFactory;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
|
||||
/**
|
||||
* The base class for all entity form wizards.
|
||||
*/
|
||||
abstract class EntityFormWizardBase extends FormWizardBase implements EntityFormWizardInterface {
|
||||
|
||||
/**
|
||||
* The entity manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityManagerInterface
|
||||
*/
|
||||
protected $entityManager;
|
||||
|
||||
/**
|
||||
* @param \Drupal\user\SharedTempStoreFactory $tempstore
|
||||
* Tempstore Factory for keeping track of values in each step of the
|
||||
* wizard.
|
||||
* @param \Drupal\Core\Form\FormBuilderInterface $builder
|
||||
* The Form Builder.
|
||||
* @param \Drupal\Core\DependencyInjection\ClassResolverInterface $class_resolver
|
||||
* The class resolver.
|
||||
* @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
|
||||
* The event dispatcher.
|
||||
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
|
||||
* The entity manager.
|
||||
* @param $tempstore_id
|
||||
* The shared temp store factory collection name.
|
||||
* @param null $machine_name
|
||||
* The SharedTempStore key for our current wizard values.
|
||||
* @param null $step
|
||||
* The current active step of the wizard.
|
||||
*/
|
||||
public function __construct(SharedTempStoreFactory $tempstore, FormBuilderInterface $builder, ClassResolverInterface $class_resolver, EventDispatcherInterface $event_dispatcher, EntityManagerInterface $entity_manager, RouteMatchInterface $route_match, $tempstore_id, $machine_name = NULL, $step = NULL) {
|
||||
$this->entityManager = $entity_manager;
|
||||
parent::__construct($tempstore, $builder, $class_resolver, $event_dispatcher, $route_match, $tempstore_id, $machine_name, $step);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getParameters() {
|
||||
return [
|
||||
'tempstore' => \Drupal::service('user.shared_tempstore'),
|
||||
'builder' => \Drupal::service('form_builder'),
|
||||
'class_resolver' => \Drupal::service('class_resolver'),
|
||||
'event_dispatcher' => \Drupal::service('event_dispatcher'),
|
||||
'entity_manager' => \Drupal::service('entity.manager'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function initValues() {
|
||||
$storage = $this->entityManager->getStorage($this->getEntityType());
|
||||
if ($this->getMachineName()) {
|
||||
$values = $this->getTempstore()->get($this->getMachineName());
|
||||
if (!$values) {
|
||||
$entity = $storage->load($this->getMachineName());
|
||||
$values[$this->getEntityType()] = $entity;
|
||||
$values['id'] = $entity->id();
|
||||
$values['label'] = $entity->label();
|
||||
}
|
||||
}
|
||||
else {
|
||||
$entity = $storage->create([]);
|
||||
$values[$this->getEntityType()] = $entity;
|
||||
}
|
||||
$event = new WizardEvent($this, $values);
|
||||
$this->dispatcher->dispatch(FormWizardInterface::LOAD_VALUES, $event);
|
||||
return $event->getValues();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function finish(array &$form, FormStateInterface $form_state) {
|
||||
$cached_values = $form_state->getTemporaryValue('wizard');
|
||||
/** @var $entity \Drupal\Core\Entity\EntityInterface */
|
||||
$entity = $cached_values[$this->getEntityType()];
|
||||
$entity->set('id', $cached_values['id']);
|
||||
$entity->set('label', $cached_values['label']);
|
||||
$status = $entity->save();
|
||||
$definition = $this->entityManager->getDefinition($this->getEntityType());
|
||||
if ($status) {
|
||||
drupal_set_message($this->t('Saved the %label @entity_type.', array(
|
||||
'%label' => $entity->label(),
|
||||
'@entity_type' => $definition->getLabel(),
|
||||
)));
|
||||
}
|
||||
else {
|
||||
drupal_set_message($this->t('The %label @entity_type was not saved.', array(
|
||||
'%label' => $entity->label(),
|
||||
'@entity_type' => $definition->getLabel(),
|
||||
)));
|
||||
}
|
||||
$form_state->setRedirectUrl($entity->toUrl('collection'));
|
||||
parent::finish($form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for generating label and id form elements.
|
||||
*
|
||||
* @param array $form
|
||||
* @param \Drupal\Core\Form\FormStateInterface $form_state
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function customizeForm(array $form, FormStateInterface $form_state) {
|
||||
$form = parent::customizeForm($form, $form_state);
|
||||
if ($this->machine_name) {
|
||||
$entity = $this->entityManager->getStorage($this->getEntityType())
|
||||
->load($this->machine_name);
|
||||
}
|
||||
else {
|
||||
$entity = NULL;
|
||||
}
|
||||
$cached_values = $form_state->getTemporaryValue('wizard');
|
||||
// If the entity already exists, allow for non-linear step interaction.
|
||||
if ($entity) {
|
||||
// Setup the step rendering theme element.
|
||||
$prefix = [
|
||||
'#theme' => ['ctools_wizard_trail_links'],
|
||||
'#wizard' => $this,
|
||||
'#cached_values' => $cached_values,
|
||||
];
|
||||
$form['#prefix'] = \Drupal::service('renderer')->render($prefix);
|
||||
}
|
||||
// Get the current form operation.
|
||||
$operation = $this->getOperation($cached_values);
|
||||
$operations = $this->getOperations($cached_values);
|
||||
$default_operation = reset($operations);
|
||||
if ($operation['form'] == $default_operation['form']) {
|
||||
// Get the plugin definition of this entity.
|
||||
$definition = $this->entityManager->getDefinition($this->getEntityType());
|
||||
// Create id and label form elements.
|
||||
$form['name'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#attributes' => array('class' => array('fieldset-no-legend')),
|
||||
'#title' => $this->getWizardLabel(),
|
||||
);
|
||||
$form['name']['label'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->getMachineLabel(),
|
||||
'#required' => TRUE,
|
||||
'#size' => 32,
|
||||
'#default_value' => !empty($cached_values['label']) ? $cached_values['label'] : '',
|
||||
'#maxlength' => 255,
|
||||
'#disabled' => !empty($cached_values['label']),
|
||||
);
|
||||
$form['name']['id'] = array(
|
||||
'#type' => 'machine_name',
|
||||
'#maxlength' => 128,
|
||||
'#machine_name' => array(
|
||||
'source' => array('name', 'label'),
|
||||
'exists' => $this->exists(),
|
||||
),
|
||||
'#description' => $this->t('A unique machine-readable name for this @entity_type. It must only contain lowercase letters, numbers, and underscores.', ['@entity_type' => $definition->getLabel()]),
|
||||
'#default_value' => !empty($cached_values['id']) ? $cached_values['id'] : '',
|
||||
'#disabled' => !empty($cached_values['id']),
|
||||
);
|
||||
}
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools\Wizard;
|
||||
|
||||
/**
|
||||
* Form wizard interface for use with entities.
|
||||
*/
|
||||
interface EntityFormWizardInterface extends FormWizardInterface {
|
||||
|
||||
/**
|
||||
* The fieldset #title for your label & machine name elements.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getWizardLabel();
|
||||
|
||||
/**
|
||||
* The form element #title for your unique identifier label.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getMachineLabel();
|
||||
|
||||
/**
|
||||
* The machine name of the entity type.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getEntityType();
|
||||
|
||||
/**
|
||||
* A method for determining if this entity already exists.
|
||||
*
|
||||
* @return callable
|
||||
* The callable to pass the id to via typical machine_name form element.
|
||||
*/
|
||||
public function exists();
|
||||
|
||||
}
|
465
web/modules/contrib/ctools/src/Wizard/FormWizardBase.php
Normal file
465
web/modules/contrib/ctools/src/Wizard/FormWizardBase.php
Normal file
|
@ -0,0 +1,465 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools\Wizard;
|
||||
|
||||
use Drupal\Core\Ajax\AjaxResponse;
|
||||
use Drupal\Core\Ajax\CloseModalDialogCommand;
|
||||
use Drupal\Core\DependencyInjection\ClassResolverInterface;
|
||||
use Drupal\Core\Form\FormBase;
|
||||
use Drupal\Core\Form\FormBuilderInterface;
|
||||
use Drupal\Core\Form\FormInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Routing\RouteMatchInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\ctools\Ajax\OpenModalWizardCommand;
|
||||
use Drupal\ctools\Event\WizardEvent;
|
||||
use Drupal\user\SharedTempStoreFactory;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
|
||||
/**
|
||||
* The base class for all form wizard.
|
||||
*/
|
||||
abstract class FormWizardBase extends FormBase implements FormWizardInterface {
|
||||
|
||||
/**
|
||||
* Tempstore Factory for keeping track of values in each step of the wizard.
|
||||
*
|
||||
* @var \Drupal\user\SharedTempStoreFactory
|
||||
*/
|
||||
protected $tempstore;
|
||||
|
||||
/**
|
||||
* The Form Builder.
|
||||
*
|
||||
* @var \Drupal\Core\Form\FormBuilderInterface
|
||||
*/
|
||||
protected $builder;
|
||||
|
||||
/**
|
||||
* The class resolver.
|
||||
*
|
||||
* @var \Drupal\Core\DependencyInjection\ClassResolverInterface;
|
||||
*/
|
||||
protected $classResolver;
|
||||
|
||||
/**
|
||||
* The event dispatcher.
|
||||
*
|
||||
* @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
|
||||
*/
|
||||
protected $dispatcher;
|
||||
|
||||
/**
|
||||
* The shared temp store factory collection name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $tempstore_id;
|
||||
|
||||
/**
|
||||
* The SharedTempStore key for our current wizard values.
|
||||
*
|
||||
* @var string|NULL
|
||||
*/
|
||||
protected $machine_name;
|
||||
|
||||
/**
|
||||
* The current active step of the wizard.
|
||||
*
|
||||
* @var string|NULL
|
||||
*/
|
||||
protected $step;
|
||||
|
||||
/**
|
||||
* @param \Drupal\user\SharedTempStoreFactory $tempstore
|
||||
* Tempstore Factory for keeping track of values in each step of the
|
||||
* wizard.
|
||||
* @param \Drupal\Core\Form\FormBuilderInterface $builder
|
||||
* The Form Builder.
|
||||
* @param \Drupal\Core\DependencyInjection\ClassResolverInterface $class_resolver
|
||||
* The class resolver.
|
||||
* @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
|
||||
* The event dispatcher.
|
||||
* @param $tempstore_id
|
||||
* The shared temp store factory collection name.
|
||||
* @param null $machine_name
|
||||
* The SharedTempStore key for our current wizard values.
|
||||
* @param null $step
|
||||
* The current active step of the wizard.
|
||||
*/
|
||||
public function __construct(SharedTempStoreFactory $tempstore, FormBuilderInterface $builder, ClassResolverInterface $class_resolver, EventDispatcherInterface $event_dispatcher, RouteMatchInterface $route_match, $tempstore_id, $machine_name = NULL, $step = NULL) {
|
||||
$this->tempstore = $tempstore;
|
||||
$this->builder = $builder;
|
||||
$this->classResolver = $class_resolver;
|
||||
$this->dispatcher = $event_dispatcher;
|
||||
$this->routeMatch = $route_match;
|
||||
$this->tempstore_id = $tempstore_id;
|
||||
$this->machine_name = $machine_name;
|
||||
$this->step = $step;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getParameters() {
|
||||
return [
|
||||
'tempstore' => \Drupal::service('user.shared_tempstore'),
|
||||
'builder' => \Drupal::service('form_builder'),
|
||||
'class_resolver' => \Drupal::service('class_resolver'),
|
||||
'event_dispatcher' => \Drupal::service('event_dispatcher'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function initValues() {
|
||||
$values = [];
|
||||
$event = new WizardEvent($this, $values);
|
||||
$this->dispatcher->dispatch(FormWizardInterface::LOAD_VALUES, $event);
|
||||
return $event->getValues();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getTempstoreId() {
|
||||
return $this->tempstore_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getTempstore() {
|
||||
return $this->tempstore->get($this->getTempstoreId());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getMachineName() {
|
||||
return $this->machine_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getStep($cached_values) {
|
||||
if (!$this->step) {
|
||||
$operations = $this->getOperations($cached_values);
|
||||
$steps = array_keys($operations);
|
||||
$this->step = reset($steps);
|
||||
}
|
||||
return $this->step;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getOperation($cached_values) {
|
||||
$operations = $this->getOperations($cached_values);
|
||||
$step = $this->getStep($cached_values);
|
||||
if (!empty($operations[$step])) {
|
||||
return $operations[$step];
|
||||
}
|
||||
$operation = reset($operations);
|
||||
return $operation;
|
||||
}
|
||||
|
||||
/**
|
||||
* The translated text of the "Next" button's text.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getNextOp() {
|
||||
return $this->t('Next');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getNextParameters($cached_values) {
|
||||
// Get the steps by key.
|
||||
$operations = $this->getOperations($cached_values);
|
||||
$steps = array_keys($operations);
|
||||
// Get the steps after the current step.
|
||||
$after = array_slice($operations, array_search($this->getStep($cached_values), $steps) + 1);
|
||||
// Get the steps after the current step by key.
|
||||
$after_keys = array_keys($after);
|
||||
$step = reset($after_keys);
|
||||
if (!$step) {
|
||||
$keys = array_keys($operations);
|
||||
$step = end($keys);
|
||||
}
|
||||
return [
|
||||
'machine_name' => $this->getMachineName(),
|
||||
'step' => $step,
|
||||
'js' => 'nojs',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getPreviousParameters($cached_values) {
|
||||
$operations = $this->getOperations($cached_values);
|
||||
$step = $this->getStep($cached_values);
|
||||
|
||||
// Get the steps by key.
|
||||
$steps = array_keys($operations);
|
||||
// Get the steps before the current step.
|
||||
$before = array_slice($operations, 0, array_search($step, $steps));
|
||||
// Get the steps before the current step by key.
|
||||
$before = array_keys($before);
|
||||
// Reverse the steps for easy access to the next step.
|
||||
$before_steps = array_reverse($before);
|
||||
$step = reset($before_steps);
|
||||
return [
|
||||
'machine_name' => $this->getMachineName(),
|
||||
'step' => $step,
|
||||
'js' => 'nojs',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
if (!$this->getMachineName() || !$this->getTempstore()->get($this->getMachineName())) {
|
||||
$cached_values = $this->initValues();
|
||||
}
|
||||
else {
|
||||
$cached_values = $this->getTempstore()->get($this->getMachineName());
|
||||
}
|
||||
$operation = $this->getOperation($cached_values);
|
||||
/* @var $operation \Drupal\Core\Form\FormInterface */
|
||||
$operation = $this->classResolver->getInstanceFromDefinition($operation['form']);
|
||||
return $operation->getFormId();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state) {
|
||||
$cached_values = $form_state->getTemporaryValue('wizard');
|
||||
// Get the current form operation.
|
||||
$operation = $this->getOperation($cached_values);
|
||||
$form = $this->customizeForm($form, $form_state);
|
||||
/* @var $formClass \Drupal\Core\Form\FormInterface */
|
||||
$formClass = $this->classResolver->getInstanceFromDefinition($operation['form']);
|
||||
// Pass include any custom values for this operation.
|
||||
if (!empty($operation['values'])) {
|
||||
$cached_values = array_merge($cached_values, $operation['values']);
|
||||
$form_state->setTemporaryValue('wizard', $cached_values);
|
||||
}
|
||||
// Build the form.
|
||||
$form = $formClass->buildForm($form, $form_state);
|
||||
if (isset($operation['title'])) {
|
||||
$form['#title'] = $operation['title'];
|
||||
}
|
||||
$form['actions'] = $this->actions($formClass, $form_state);
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateForm(array &$form, FormStateInterface $form_state) {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
// Only perform this logic if we're moving to the next page. This prevents
|
||||
// the loss of cached values on ajax submissions.
|
||||
if ((string)$form_state->getValue('op') == (string)$this->getNextOp()) {
|
||||
$cached_values = $form_state->getTemporaryValue('wizard');
|
||||
if ($form_state->hasValue('label')) {
|
||||
$cached_values['label'] = $form_state->getValue('label');
|
||||
}
|
||||
if ($form_state->hasValue('id')) {
|
||||
$cached_values['id'] = $form_state->getValue('id');
|
||||
}
|
||||
if (is_null($this->machine_name) && !empty($cached_values['id'])) {
|
||||
$this->machine_name = $cached_values['id'];
|
||||
}
|
||||
$this->getTempstore()->set($this->getMachineName(), $cached_values);
|
||||
if (!$form_state->get('ajax')) {
|
||||
$form_state->setRedirect($this->getRouteName(), $this->getNextParameters($cached_values));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function populateCachedValues(array &$form, FormStateInterface $form_state) {
|
||||
$cached_values = $this->getTempstore()->get($this->getMachineName());
|
||||
if (!$cached_values) {
|
||||
$cached_values = $form_state->getTemporaryValue('wizard');
|
||||
if (!$cached_values) {
|
||||
$cached_values = $this->initValues();
|
||||
$form_state->setTemporaryValue('wizard', $cached_values);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function previous(array &$form, FormStateInterface $form_state) {
|
||||
$cached_values = $form_state->getTemporaryValue('wizard');
|
||||
$form_state->setRedirect($this->getRouteName(), $this->getPreviousParameters($cached_values));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function finish(array &$form, FormStateInterface $form_state) {
|
||||
$this->getTempstore()->delete($this->getMachineName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for generating default form elements.
|
||||
*
|
||||
* @param array $form
|
||||
* @param \Drupal\Core\Form\FormStateInterface $form_state
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function customizeForm(array $form, FormStateInterface $form_state) {
|
||||
// Setup the step rendering theme element.
|
||||
$prefix = [
|
||||
'#theme' => ['ctools_wizard_trail'],
|
||||
'#wizard' => $this,
|
||||
'#cached_values' => $form_state->getTemporaryValue('wizard'),
|
||||
];
|
||||
// @todo properly inject the renderer.
|
||||
$form['#prefix'] = \Drupal::service('renderer')->render($prefix);
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates action elements for navigating between the operation steps.
|
||||
*
|
||||
* @param \Drupal\Core\Form\FormInterface $form_object
|
||||
* The current operation form.
|
||||
* @param \Drupal\Core\Form\FormStateInterface $form_state
|
||||
* The current form state.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function actions(FormInterface $form_object, FormStateInterface $form_state) {
|
||||
$cached_values = $form_state->getTemporaryValue('wizard');
|
||||
$operations = $this->getOperations($cached_values);
|
||||
$step = $this->getStep($cached_values);
|
||||
$operation = $operations[$step];
|
||||
|
||||
$steps = array_keys($operations);
|
||||
// Slice to find the operations that occur before the current operation.
|
||||
$before = array_slice($operations, 0, array_search($step, $steps));
|
||||
// Slice to find the operations that occur after the current operation.
|
||||
$after = array_slice($operations, array_search($step, $steps) + 1);
|
||||
|
||||
$actions = [
|
||||
'submit' => [
|
||||
'#type' => 'submit',
|
||||
'#value' => $this->t('Next'),
|
||||
'#button_type' => 'primary',
|
||||
'#validate' => [
|
||||
'::populateCachedValues',
|
||||
[$form_object, 'validateForm'],
|
||||
],
|
||||
'#submit' => [
|
||||
[$form_object, 'submitForm'],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
// Add any submit or validate functions for the step and the global ones.
|
||||
if (isset($operation['validate'])) {
|
||||
$actions['submit']['#validate'] = array_merge($actions['submit']['#validate'], $operation['validate']);
|
||||
}
|
||||
$actions['submit']['#validate'][] = '::validateForm';
|
||||
if (isset($operation['submit'])) {
|
||||
$actions['submit']['#submit'] = array_merge($actions['submit']['#submit'], $operation['submit']);
|
||||
}
|
||||
$actions['submit']['#submit'][] = '::submitForm';
|
||||
|
||||
if ($form_state->get('ajax')) {
|
||||
// Ajax submissions need to submit to the current step, not "next".
|
||||
$parameters = $this->getNextParameters($cached_values);
|
||||
$parameters['step'] = $this->getStep($cached_values);
|
||||
$actions['submit']['#ajax'] = [
|
||||
'callback' => '::ajaxSubmit',
|
||||
'url' => Url::fromRoute($this->getRouteName(), $parameters),
|
||||
'options' => ['query' => \Drupal::request()->query->all() + [FormBuilderInterface::AJAX_FORM_REQUEST => TRUE]],
|
||||
];
|
||||
}
|
||||
|
||||
// If there are steps before this one, label the button "previous"
|
||||
// otherwise do not display a button.
|
||||
if ($before) {
|
||||
$actions['previous'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => $this->t('Previous'),
|
||||
'#validate' => array(
|
||||
array($this, 'populateCachedValues'),
|
||||
),
|
||||
'#submit' => array(
|
||||
array($this, 'previous'),
|
||||
),
|
||||
'#limit_validation_errors' => array(),
|
||||
'#weight' => -10,
|
||||
);
|
||||
if ($form_state->get('ajax')) {
|
||||
// Ajax submissions need to submit to the current step, not "previous".
|
||||
$parameters = $this->getPreviousParameters($cached_values);
|
||||
$parameters['step'] = $this->getStep($cached_values);
|
||||
$actions['previous']['#ajax'] = [
|
||||
'callback' => '::ajaxPrevious',
|
||||
'url' => Url::fromRoute($this->getRouteName(), $parameters),
|
||||
'options' => ['query' => \Drupal::request()->query->all() + [FormBuilderInterface::AJAX_FORM_REQUEST => TRUE]],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// If there are not steps after this one, label the button "Finish".
|
||||
if (!$after) {
|
||||
$actions['submit']['#value'] = $this->t('Finish');
|
||||
$actions['submit']['#submit'][] = array($this, 'finish');
|
||||
if ($form_state->get('ajax')) {
|
||||
$actions['submit']['#ajax']['callback'] = [$this, 'ajaxFinish'];
|
||||
}
|
||||
}
|
||||
|
||||
return $actions;
|
||||
}
|
||||
|
||||
public function ajaxSubmit(array $form, FormStateInterface $form_state) {
|
||||
$cached_values = $form_state->getTemporaryValue('wizard');
|
||||
$response = new AjaxResponse();
|
||||
$parameters = $this->getNextParameters($cached_values);
|
||||
$response->addCommand(new OpenModalWizardCommand($this, $this->getTempstoreId(), $parameters));
|
||||
return $response;
|
||||
}
|
||||
|
||||
public function ajaxPrevious(array $form, FormStateInterface $form_state) {
|
||||
$cached_values = $form_state->getTemporaryValue('wizard');
|
||||
$response = new AjaxResponse();
|
||||
$parameters = $this->getPreviousParameters($cached_values);
|
||||
$response->addCommand(new OpenModalWizardCommand($this, $this->getTempstoreId(), $parameters));
|
||||
return $response;
|
||||
}
|
||||
|
||||
public function ajaxFinish(array $form, FormStateInterface $form_state) {
|
||||
$response = new AjaxResponse();
|
||||
$response->addCommand(new CloseModalDialogCommand());
|
||||
return $response;
|
||||
}
|
||||
|
||||
public function getRouteName() {
|
||||
return $this->routeMatch->getRouteName();
|
||||
}
|
||||
|
||||
}
|
182
web/modules/contrib/ctools/src/Wizard/FormWizardInterface.php
Normal file
182
web/modules/contrib/ctools/src/Wizard/FormWizardInterface.php
Normal file
|
@ -0,0 +1,182 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools\Wizard;
|
||||
|
||||
use Drupal\Core\Form\FormInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
|
||||
/**
|
||||
* Form wizard interface.
|
||||
*/
|
||||
interface FormWizardInterface extends FormInterface {
|
||||
|
||||
/**
|
||||
* Constant value for wizard load event.
|
||||
*/
|
||||
const LOAD_VALUES = 'wizard.load';
|
||||
|
||||
/**
|
||||
* Return an array of parameters required to construct this wizard.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getParameters();
|
||||
|
||||
/**
|
||||
* Initialize wizard values.
|
||||
*
|
||||
* return mixed.
|
||||
*/
|
||||
public function initValues();
|
||||
|
||||
/**
|
||||
* The shared temp store factory collection name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getTempstoreId();
|
||||
|
||||
/**
|
||||
* The active SharedTempStore for this wizard.
|
||||
*
|
||||
* @return \Drupal\user\SharedTempStore
|
||||
*/
|
||||
public function getTempstore();
|
||||
|
||||
/**
|
||||
* The SharedTempStore key for our current wizard values.
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
public function getMachineName();
|
||||
|
||||
/**
|
||||
* Retrieve the current active step of the wizard.
|
||||
*
|
||||
* This will return the first step of the wizard if no step has been set.
|
||||
*
|
||||
* @param mixed $cached_values
|
||||
* The values returned by $this->getTempstore()->get($this->getMachineName());
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getStep($cached_values);
|
||||
|
||||
/**
|
||||
* Retrieve a list of FormInterface classes by their step key in the wizard.
|
||||
*
|
||||
* @param mixed $cached_values
|
||||
* The values returned by $this->getTempstore()->get($this->getMachineName()); *
|
||||
*
|
||||
* @return array
|
||||
* An associative array keyed on the step name with an array value with the
|
||||
* following keys:
|
||||
* - title (string): Human-readable title of the step.
|
||||
* - form (string): Fully-qualified class name of the form for this step.
|
||||
* - values (array): Optional array of cached values to override when on
|
||||
* this step.
|
||||
* - validate (array): Optional array of callables to be called when this
|
||||
* step is validated.
|
||||
* - submit (array): Optional array of callables to be called when this
|
||||
* step is submitted.
|
||||
*/
|
||||
public function getOperations($cached_values);
|
||||
|
||||
/**
|
||||
* Retrieve the current Operation.
|
||||
*
|
||||
* @param mixed $cached_values
|
||||
* The values returned by $this->getTempstore()->get($this->getMachineName());
|
||||
*
|
||||
* @return string
|
||||
* The class name to instantiate.
|
||||
*/
|
||||
public function getOperation($cached_values);
|
||||
|
||||
/**
|
||||
* The name of the route to which forward or backwards steps redirect.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getRouteName();
|
||||
|
||||
/**
|
||||
* The Route parameters for a 'next' step.
|
||||
*
|
||||
* If your route requires more than machine_name and step keys, override and
|
||||
* extend this method as needed.
|
||||
*
|
||||
* @param mixed $cached_values
|
||||
* The values returned by $this->getTempstore()->get($this->getMachineName());
|
||||
*
|
||||
* @return array
|
||||
* An array keyed by:
|
||||
* machine_name
|
||||
* step
|
||||
*/
|
||||
public function getNextParameters($cached_values);
|
||||
|
||||
/**
|
||||
* The Route parameters for a 'previous' step.
|
||||
*
|
||||
* If your route requires more than machine_name and step keys, override and
|
||||
* extend this method as needed.
|
||||
*
|
||||
* @param mixed $cached_values
|
||||
* The values returned by $this->getTempstore()->get($this->getMachineName());
|
||||
*
|
||||
* @return array
|
||||
* An array keyed by:
|
||||
* machine_name
|
||||
* step
|
||||
*/
|
||||
public function getPreviousParameters($cached_values);
|
||||
|
||||
/**
|
||||
* Form validation handler that populates the cached values from tempstore.
|
||||
*
|
||||
* Temporary values are only available for a single page load so form
|
||||
* submission will lose all the values. This was we reload and provide them
|
||||
* to the validate and submit process.
|
||||
*
|
||||
* @param array $form
|
||||
* Drupal form array
|
||||
* @param \Drupal\Core\Form\FormStateInterface $form_state
|
||||
* The initial form state before validation or submission of the steps.
|
||||
*/
|
||||
public function populateCachedValues(array &$form, FormStateInterface $form_state);
|
||||
|
||||
/**
|
||||
* Form submit handler to step backwards in the wizard.
|
||||
*
|
||||
* "Next" steps are handled by \Drupal\Core\Form\FormInterface::submitForm().
|
||||
*
|
||||
* @param array $form
|
||||
* Drupal form array
|
||||
* @param \Drupal\Core\Form\FormStateInterface $form_state
|
||||
* The current form state of the wizard. This will not contain values from
|
||||
* the current step since the previous button does not actually submit
|
||||
* those values.
|
||||
*/
|
||||
public function previous(array &$form, FormStateInterface $form_state);
|
||||
|
||||
/**
|
||||
* Form submit handler for finalizing the wizard values.
|
||||
*
|
||||
* If you need to generate an entity or save config or raw table data
|
||||
* subsequent to your form wizard, this is the responsible method.
|
||||
*
|
||||
* @param array $form
|
||||
* Drupal form array
|
||||
* @param \Drupal\Core\Form\FormStateInterface $form_state
|
||||
* The final form state of the wizard.
|
||||
*/
|
||||
public function finish(array &$form, FormStateInterface $form_state);
|
||||
|
||||
public function ajaxSubmit(array $form, FormStateInterface $form_state);
|
||||
|
||||
public function ajaxPrevious(array $form, FormStateInterface $form_state);
|
||||
|
||||
public function ajaxFinish(array $form, FormStateInterface $form_state);
|
||||
|
||||
}
|
129
web/modules/contrib/ctools/src/Wizard/WizardFactory.php
Normal file
129
web/modules/contrib/ctools/src/Wizard/WizardFactory.php
Normal file
|
@ -0,0 +1,129 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools\Wizard;
|
||||
|
||||
use Drupal\Core\Form\FormBuilderInterface;
|
||||
use Drupal\Core\Form\FormState;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
|
||||
class WizardFactory implements WizardFactoryInterface {
|
||||
|
||||
/**
|
||||
* The Form Builder.
|
||||
*
|
||||
* @var \Drupal\Core\Form\FormBuilderInterface
|
||||
*/
|
||||
protected $builder;
|
||||
|
||||
/**
|
||||
* The event dispatcher.
|
||||
*
|
||||
* @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
|
||||
*/
|
||||
protected $dispatcher;
|
||||
|
||||
/**
|
||||
* @param \Drupal\Core\Form\FormBuilderInterface $form_builder
|
||||
* The form builder.
|
||||
* @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
|
||||
* The event dispatcher.
|
||||
*/
|
||||
public function __construct(FormBuilderInterface $form_builder, EventDispatcherInterface $event_dispatcher) {
|
||||
$this->builder = $form_builder;
|
||||
$this->dispatcher = $event_dispatcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getWizardForm(FormWizardInterface $wizard, array $parameters = [], $ajax = FALSE) {
|
||||
$form_state = $this->getFormState($wizard, $parameters, $ajax);
|
||||
$form = $this->builder->buildForm($wizard, $form_state);
|
||||
|
||||
if ($ajax) {
|
||||
$form['#attached']['library'][] = 'core/drupal.dialog.ajax';
|
||||
$status_messages = array('#type' => 'status_messages');
|
||||
// @todo properly inject the renderer. Core should really be doing this work.
|
||||
if ($messages = \Drupal::service('renderer')->renderRoot($status_messages)) {
|
||||
if (!empty($form['#prefix'])) {
|
||||
// Form prefix is expected to be a string. Prepend the messages to
|
||||
// that string.
|
||||
$form['#prefix'] = '<div class="wizard-messages">' . $messages . '</div>' . $form['#prefix'];
|
||||
}
|
||||
}
|
||||
}
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $class
|
||||
* A class name implementing FormWizardInterface.
|
||||
* @param array $parameters
|
||||
* The array of parameters specific to this wizard.
|
||||
*
|
||||
* @return \Drupal\ctools\Wizard\FormWizardInterface
|
||||
*/
|
||||
public function createWizard($class, array $parameters) {
|
||||
$arguments = [];
|
||||
$reflection = new \ReflectionClass($class);
|
||||
$constructor = $reflection->getMethod('__construct');
|
||||
foreach ($constructor->getParameters() as $parameter) {
|
||||
if (array_key_exists($parameter->name, $parameters)) {
|
||||
$arguments[] = $parameters[$parameter->name];
|
||||
}
|
||||
elseif ($parameter->isDefaultValueAvailable()) {
|
||||
$arguments[] = $parameter->getDefaultValue();
|
||||
}
|
||||
}
|
||||
/** @var $wizard \Drupal\ctools\Wizard\FormWizardInterface */
|
||||
$wizard = $reflection->newInstanceArgs($arguments);
|
||||
return $wizard;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the wizard form state.
|
||||
*
|
||||
* @param \Drupal\ctools\Wizard\FormWizardInterface $wizard
|
||||
* The form wizard.
|
||||
* @param array $parameters
|
||||
* The array of parameters specific to this wizard.
|
||||
* @param bool $ajax
|
||||
*
|
||||
* @return \Drupal\Core\Form\FormState
|
||||
*/
|
||||
public function getFormState(FormWizardInterface $wizard, array $parameters, $ajax = FALSE) {
|
||||
$form_state = new FormState();
|
||||
// If a wizard has no values, initialize them.
|
||||
if (!$wizard->getMachineName() || !$wizard->getTempstore()->get($wizard->getMachineName())) {
|
||||
$cached_values = $wizard->initValues();
|
||||
// Save the cached values that were initialized.
|
||||
if ($wizard->getMachineName()) {
|
||||
$wizard->getTempstore()->set($wizard->getMachineName(), $cached_values);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$cached_values = $wizard->getTempstore()->get($wizard->getMachineName());
|
||||
}
|
||||
$form_state->setTemporaryValue('wizard', $cached_values);
|
||||
$form_state->set('ajax', $ajax);
|
||||
|
||||
$parameters['form'] = [];
|
||||
$parameters['form_state'] = $form_state;
|
||||
$method = new \ReflectionMethod($wizard, 'buildForm');
|
||||
$arguments = [];
|
||||
foreach ($method->getParameters() as $parameter) {
|
||||
if (array_key_exists($parameter->name, $parameters)) {
|
||||
$arguments[] = $parameters[$parameter->name];
|
||||
}
|
||||
elseif ($parameter->isDefaultValueAvailable()) {
|
||||
$arguments[] = $parameter->getDefaultValue();
|
||||
}
|
||||
}
|
||||
unset($parameters['form'], $parameters['form_state']);
|
||||
// Remove $form and $form_state from the arguments, and re-index them.
|
||||
unset($arguments[0], $arguments[1]);
|
||||
$form_state->addBuildInfo('args', array_values($arguments));
|
||||
return $form_state;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
namespace Drupal\ctools\Wizard;
|
||||
|
||||
interface WizardFactoryInterface {
|
||||
/**
|
||||
* Get the wizard form.
|
||||
*
|
||||
* @param FormWizardInterface $wizard
|
||||
* The form wizard
|
||||
* @param array $parameters
|
||||
* The array of default parameters specific to this wizard.
|
||||
* @param bool $ajax
|
||||
* Whether or not this wizard is displayed via ajax modals.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getWizardForm(FormWizardInterface $wizard, array $parameters = [], $ajax = FALSE);
|
||||
|
||||
/**
|
||||
* @param string $class
|
||||
* A class name implementing FormWizardInterface.
|
||||
* @param array $parameters
|
||||
* The array of parameters specific to this wizard.
|
||||
*
|
||||
* @return \Drupal\ctools\Wizard\FormWizardInterface
|
||||
*/
|
||||
public function createWizard($class, array $parameters);
|
||||
|
||||
/**
|
||||
* Get the wizard form state.
|
||||
*
|
||||
* @param \Drupal\ctools\Wizard\FormWizardInterface $wizard
|
||||
* The form wizard.
|
||||
* @param array $parameters
|
||||
* The array of parameters specific to this wizard.
|
||||
* @param bool $ajax
|
||||
*
|
||||
* @return \Drupal\Core\Form\FormState
|
||||
*/
|
||||
public function getFormState(FormWizardInterface $wizard, array $parameters, $ajax = FALSE);
|
||||
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
{% if trail %}
|
||||
<div class="wizard-trail">
|
||||
{% for key, value in trail %}
|
||||
{% if key is same as(step) %}
|
||||
<strong>{{ link(value.title, value.url) }}</strong>
|
||||
{% else %}
|
||||
{{ link(value.title, value.url) }}
|
||||
{% endif %}
|
||||
{% if value is not same as(trail|last) %}
|
||||
{{ divider }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
|
@ -0,0 +1,14 @@
|
|||
{% if trail %}
|
||||
<div class="wizard-trail">
|
||||
{% for key, value in trail %}
|
||||
{% if key is same as(step) %}
|
||||
<strong>{{ value }}</strong>
|
||||
{% else %}
|
||||
{{ value }}
|
||||
{% endif %}
|
||||
{% if value is not same as(trail|last) %}
|
||||
{{ divider }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
|
@ -0,0 +1,18 @@
|
|||
ctools_wizard_test.ctools_wizard_test_config_entity.*:
|
||||
type: config_entity
|
||||
label: 'Example config entity'
|
||||
mapping:
|
||||
id:
|
||||
type: string
|
||||
label: 'ID'
|
||||
label:
|
||||
type: label
|
||||
label: 'Label'
|
||||
uuid:
|
||||
type: string
|
||||
one:
|
||||
type: string
|
||||
label: 'The first piece of information'
|
||||
two:
|
||||
type: string
|
||||
label: 'The second piece of information'
|
|
@ -0,0 +1,12 @@
|
|||
name: Chaos Wizard Test
|
||||
type: module
|
||||
description: 'Provides testing for ctools wizard'
|
||||
package: Testing
|
||||
# version: 3.x
|
||||
# core: 8.x
|
||||
|
||||
# Information added by Drupal.org packaging script on 2017-04-28
|
||||
version: '8.x-3.0'
|
||||
core: '8.x'
|
||||
project: 'ctools'
|
||||
datestamp: 1493401747
|
|
@ -0,0 +1,6 @@
|
|||
entity.ctools_wizard_test_config_entity.add_form:
|
||||
route_name: 'entity.ctools_wizard_test_config_entity.add_form'
|
||||
title: 'Add Example config entity'
|
||||
appears_on:
|
||||
- entity.ctools_wizard_test_config_entity.collection
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
# Example config entity menu items definition
|
||||
entity.ctools_wizard_test_config_entity.collection:
|
||||
title: 'Example config entity'
|
||||
route_name: entity.ctools_wizard_test_config_entity.collection
|
||||
description: 'List Example config entity'
|
||||
parent: system.admin_structure
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
ctools.wizard.test:
|
||||
path: '/ctools/wizard'
|
||||
defaults:
|
||||
_wizard: '\Drupal\ctools_wizard_test\Wizard\WizardTest'
|
||||
_title: 'Wizard Test'
|
||||
tempstore_id: 'ctools.wizard.test'
|
||||
machine_name: 'WizardTest'
|
||||
requirements:
|
||||
_access: 'TRUE'
|
||||
ctools.wizard.test.step:
|
||||
path: '/ctools/wizard/{step}'
|
||||
defaults:
|
||||
_wizard: '\Drupal\ctools_wizard_test\Wizard\WizardTest'
|
||||
_title: 'Wizard Test'
|
||||
tempstore_id: 'ctools.wizard.test'
|
||||
machine_name: 'WizardTest'
|
||||
requirements:
|
||||
_access: 'TRUE'
|
||||
|
||||
# ExampleConfigEntity routing definition
|
||||
entity.ctools_wizard_test_config_entity.collection:
|
||||
path: '/admin/structure/ctools_wizard_test_config_entity'
|
||||
defaults:
|
||||
_entity_list: 'ctools_wizard_test_config_entity'
|
||||
_title: 'Example config entity'
|
||||
requirements:
|
||||
_permission: 'administer site configuration'
|
||||
options:
|
||||
_admin_route: TRUE
|
||||
|
||||
entity.ctools_wizard_test_config_entity.add_form:
|
||||
path: '/admin/structure/ctools_wizard_test_config_entity/add'
|
||||
defaults:
|
||||
_entity_wizard: 'ctools_wizard_test_config_entity.add'
|
||||
_title: 'Add Example config entity'
|
||||
tempstore_id: 'ctools_wizard_test.config_entity'
|
||||
requirements:
|
||||
_permission: 'administer site configuration'
|
||||
options:
|
||||
_admin_route: TRUE
|
||||
|
||||
entity.ctools_wizard_test_config_entity.add_step_form:
|
||||
path: '/admin/structure/ctools_wizard_test_config_entity/add/{machine_name}/{step}'
|
||||
defaults:
|
||||
_entity_wizard: 'ctools_wizard_test_config_entity.add'
|
||||
_title: 'Add Example config entity'
|
||||
tempstore_id: 'ctools_wizard_test.config_entity'
|
||||
requirements:
|
||||
_permission: 'administer site configuration'
|
||||
options:
|
||||
_admin_route: TRUE
|
||||
|
||||
entity.ctools_wizard_test_config_entity.edit_form:
|
||||
path: '/admin/structure/ctools_wizard_test_config_entity/{machine_name}/{step}'
|
||||
defaults:
|
||||
_entity_wizard: 'ctools_wizard_test_config_entity.edit'
|
||||
_title: 'Edit Example config entity'
|
||||
tempstore_id: 'ctools_wizard_test.config_entity'
|
||||
requirements:
|
||||
_permission: 'administer site configuration'
|
||||
options:
|
||||
_admin_route: TRUE
|
||||
|
||||
entity.ctools_wizard_test_config_entity.external_form:
|
||||
path: '/admin/structure/ctools_wizard_test_config_entity/{machine_name}/external'
|
||||
defaults:
|
||||
_title: 'Edit Example config entity'
|
||||
_form: '\Drupal\ctools_wizard_test\Form\ExampleConfigEntityExternalForm'
|
||||
requirements:
|
||||
_permission: 'administer site configuration'
|
||||
options:
|
||||
_admin_route: TRUE
|
||||
|
||||
entity.ctools_wizard_test_config_entity.delete_form:
|
||||
path: '/admin/structure/ctools_wizard_test_config_entity/{ctools_wizard_test_config_entity}/delete'
|
||||
defaults:
|
||||
_entity_form: 'ctools_wizard_test_config_entity.delete'
|
||||
_title: 'Delete Example config entity'
|
||||
requirements:
|
||||
_permission: 'administer site configuration'
|
||||
options:
|
||||
_admin_route: TRUE
|
|
@ -0,0 +1,83 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools_wizard_test\Entity;
|
||||
|
||||
use Drupal\Core\Config\Entity\ConfigEntityBase;
|
||||
use Drupal\ctools_wizard_test\ExampleConfigEntityInterface;
|
||||
|
||||
/**
|
||||
* Defines the Example config entity entity.
|
||||
*
|
||||
* @ConfigEntityType(
|
||||
* id = "ctools_wizard_test_config_entity",
|
||||
* label = @Translation("Example config entity"),
|
||||
* handlers = {
|
||||
* "list_builder" = "Drupal\ctools_wizard_test\ExampleConfigEntityListBuilder",
|
||||
* "form" = {
|
||||
* "delete" = "Drupal\ctools_wizard_test\Form\ExampleConfigEntityDeleteForm"
|
||||
* },
|
||||
* "wizard" = {
|
||||
* "add" = "Drupal\ctools_wizard_test\Wizard\EntityAddWizardTest",
|
||||
* "edit" = "Drupal\ctools_wizard_test\Wizard\EntityEditWizardTest"
|
||||
* }
|
||||
* },
|
||||
* config_prefix = "ctools_wizard_test_config_entity",
|
||||
* admin_permission = "administer site configuration",
|
||||
* entity_keys = {
|
||||
* "id" = "id",
|
||||
* "label" = "label",
|
||||
* "uuid" = "uuid"
|
||||
* },
|
||||
* links = {
|
||||
* "canonical" = "/admin/structure/ctools_wizard_test_config_entity/{ctools_wizard_test_config_entity}",
|
||||
* "edit-form" = "/admin/structure/ctools_wizard_test_config_entity/{machine_name}/{step}",
|
||||
* "delete-form" = "/admin/structure/ctools_wizard_test_config_entity/{ctools_wizard_test_config_entity}/delete",
|
||||
* "collection" = "/admin/structure/ctools_wizard_test_config_entity"
|
||||
* }
|
||||
* )
|
||||
*/
|
||||
class ExampleConfigEntity extends ConfigEntityBase implements ExampleConfigEntityInterface {
|
||||
|
||||
/**
|
||||
* The Example config entity ID.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* The Example config entity label.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $label;
|
||||
|
||||
/**
|
||||
* The first piece of information.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $one;
|
||||
|
||||
/**
|
||||
* The second piece of information.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $two;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getOne() {
|
||||
return $this->one;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getTwo() {
|
||||
return $this->two;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\ctools_wizard_test;
|
||||
|
||||
use Drupal\Core\Config\Entity\ConfigEntityInterface;
|
||||
|
||||
/**
|
||||
* Provides an interface for defining Example config entity entities.
|
||||
*/
|
||||
interface ExampleConfigEntityInterface extends ConfigEntityInterface {
|
||||
|
||||
/**
|
||||
* Get first piece of information.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getOne();
|
||||
|
||||
/**
|
||||
* Get second piece of information;
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getTwo();
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Reference in a new issue