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