Update to Drupal 8.0.0 beta 14. For more information, see https://drupal.org/node/2544542
This commit is contained in:
parent
3b2511d96d
commit
81ccda77eb
2155 changed files with 54307 additions and 46870 deletions
409
core/lib/Drupal/Component/Assertion/Inspector.php
Normal file
409
core/lib/Drupal/Component/Assertion/Inspector.php
Normal file
|
@ -0,0 +1,409 @@
|
|||
<?php
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Component\Assertion\Inspector.
|
||||
*/
|
||||
|
||||
namespace Drupal\Component\Assertion;
|
||||
|
||||
use Traversable;
|
||||
|
||||
/**
|
||||
* Generic inspections for the assert() statement.
|
||||
*
|
||||
* This is a static function collection for inspecting variable contents. All
|
||||
* functions in this collection check a variable against an assertion about its
|
||||
* structure.
|
||||
*
|
||||
* Example call:
|
||||
* @code
|
||||
* assert('Drupal\\Component\\Assertion\\Inspector::assertAllStrings($array)');
|
||||
* @endcode
|
||||
*
|
||||
* @ingroup php_assert
|
||||
*/
|
||||
class Inspector {
|
||||
|
||||
/**
|
||||
* Asserts argument can be traversed with foreach.
|
||||
*
|
||||
* @param mixed $traversable
|
||||
* Variable to be examined.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if $traversable can be traversed with foreach.
|
||||
*/
|
||||
public static function assertTraversable($traversable) {
|
||||
return is_array($traversable) || $traversable instanceof Traversable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts callback returns TRUE for each member of a traversable.
|
||||
*
|
||||
* This is less memory intensive than using array_filter() to build a second
|
||||
* array and then comparing the arrays. Many of the other functions in this
|
||||
* collection alias this function passing a specific callback to make the
|
||||
* code more readable.
|
||||
*
|
||||
* @param callable $callable
|
||||
* Callback function.
|
||||
* @param mixed $traversable
|
||||
* Variable to be examined.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if $traversable can be traversed and $callable returns TRUE on
|
||||
* all members.
|
||||
*
|
||||
* @see http://php.net/manual/language.types.callable.php
|
||||
*/
|
||||
public static function assertAll(callable $callable, $traversable) {
|
||||
if (static::assertTraversable($traversable)) {
|
||||
foreach ($traversable as $member) {
|
||||
if (!$callable($member)) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that all members are strings.
|
||||
*
|
||||
* @param mixed $traversable
|
||||
* Variable to be examined.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if $traversable can be traversed and all members are strings.
|
||||
*/
|
||||
public static function assertAllStrings($traversable) {
|
||||
return static::assertAll('is_string', $traversable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts all members are strings or objects with magic __toString() method.
|
||||
*
|
||||
* @param mixed $traversable
|
||||
* Variable to be examined.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if $traversable can be traversed and all members are strings or
|
||||
* objects with __toString().
|
||||
*/
|
||||
public static function assertAllStringable($traversable) {
|
||||
if (static::assertTraversable($traversable)) {
|
||||
foreach ($traversable as $member) {
|
||||
if (!(is_string($member) || (is_object($member) && method_exists($member, '__toString')))) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that all members are arrays.
|
||||
*
|
||||
* @param mixed $traversable
|
||||
* Variable to be examined.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if $traversable can be traversed and all members are arrays.
|
||||
*/
|
||||
public static function assertAllArrays($traversable) {
|
||||
return static::assertAll('is_array', $traversable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the array is strict.
|
||||
*
|
||||
* What PHP calls arrays are more formally called maps in most other
|
||||
* programming languages. A map is a datatype that associates values to keys.
|
||||
* The term 'strict array' here refers to a 0-indexed array in the classic
|
||||
* sense found in programming languages other than PHP.
|
||||
*
|
||||
* @param mixed $array
|
||||
* Variable to be examined.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if $traversable is a 0-indexed array.
|
||||
*
|
||||
* @see http://php.net/manual/language.types.array.php
|
||||
*/
|
||||
public static function assertStrictArray($array) {
|
||||
if (!is_array($array)) {
|
||||
return FALSE;
|
||||
}
|
||||
$i = 0;
|
||||
|
||||
foreach (array_keys($array) as $key) {
|
||||
if ($i !== $key) {
|
||||
return FALSE;
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts all members are strict arrays.
|
||||
*
|
||||
* @param mixed $traversable
|
||||
* Variable to be examined.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if $traversable can be traversed and all members are strict arrays.
|
||||
*
|
||||
* @see ::assertStrictArray
|
||||
*/
|
||||
public static function assertAllStrictArrays($traversable) {
|
||||
return static::assertAll([__CLASS__, 'assertStrictArray'], $traversable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts all given keys exist in every member array.
|
||||
*
|
||||
* Drupal has several data structure arrays that require certain keys be set.
|
||||
* You can overload this function to specify a list of required keys. All
|
||||
* of the keys must be set for this method to return TRUE.
|
||||
*
|
||||
* As an example, this assertion tests for the keys of a theme registry.
|
||||
*
|
||||
* @code
|
||||
* assert('Drupal\\Component\\Assertion\\Inspector::assertAllHaveKey(
|
||||
* $arrayToTest, "type", "theme path", "function", "template", "variables", "render element", "preprocess functions")');
|
||||
* @endcode
|
||||
*
|
||||
* Note: If a method requires certain keys to be present it will usually be
|
||||
* specific about the data types for the values of those keys. Therefore it
|
||||
* will be best to write a specific test for it. Such tests are either bound
|
||||
* to the object that uses them, or are collected into one assertion set for
|
||||
* the package.
|
||||
*
|
||||
* @param mixed $traversable
|
||||
* Variable to be examined.
|
||||
* @param string ...
|
||||
* Keys to be searched for.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if $traversable can be traversed and all members have all keys.
|
||||
*/
|
||||
public static function assertAllHaveKey() {
|
||||
$args = func_get_args();
|
||||
$traversable = array_shift($args);
|
||||
|
||||
if (static::assertTraversable($traversable)) {
|
||||
foreach ($traversable as $member) {
|
||||
foreach ($args as $key) {
|
||||
if (!array_key_exists($key, $member)) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that all members are integer values.
|
||||
*
|
||||
* @param mixed $traversable
|
||||
* Variable to be examined.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if $traversable can be traversed and all members are integers.
|
||||
*/
|
||||
public static function assertAllIntegers($traversable) {
|
||||
return static::assertAll('is_int', $traversable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that all members are float values.
|
||||
*
|
||||
* @param mixed $traversable
|
||||
* Variable to be examined.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if $traversable can be traversed and all members are floating point
|
||||
* numbers.
|
||||
*/
|
||||
public static function assertAllFloat($traversable) {
|
||||
return static::assertAll('is_float', $traversable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that all members are callable.
|
||||
*
|
||||
* @param mixed $traversable
|
||||
* Variable to be examined.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if $traversable can be traversed and all members are callable.
|
||||
*/
|
||||
public static function assertAllCallable($traversable) {
|
||||
return static::assertAll('is_callable', $traversable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that all members are not empty.
|
||||
*
|
||||
* @param mixed $traversable
|
||||
* Variable to be examined.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if $traversable can be traversed and all members not empty.
|
||||
*/
|
||||
public static function assertAllNotEmpty($traversable) {
|
||||
if (static::assertTraversable($traversable)) {
|
||||
foreach ($traversable as $member) {
|
||||
if (empty($member)) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts all members are numeric data types or strings castable to such.
|
||||
*
|
||||
* @param mixed $traversable
|
||||
* Variable to be examined.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if $traversable can be traversed and all members are numeric.
|
||||
*/
|
||||
public static function assertAllNumeric($traversable) {
|
||||
return static::assertAll('is_numeric', $traversable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that all members are strings that contain the specified string.
|
||||
*
|
||||
* This runs faster than the regular expression equivalent.
|
||||
*
|
||||
* @param string $pattern
|
||||
* The needle to find.
|
||||
* @param mixed $traversable
|
||||
* Variable to examine.
|
||||
* @param bool $case_sensitive
|
||||
* TRUE to use strstr(), FALSE to use stristr() which is case insensitive.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if $traversable can be traversed and all members are strings
|
||||
* containing $pattern.
|
||||
*/
|
||||
public static function assertAllMatch($pattern, $traversable, $case_sensitive = FALSE) {
|
||||
if (static::assertTraversable($traversable)) {
|
||||
if ($case_sensitive) {
|
||||
foreach ($traversable as $member) {
|
||||
if (!(is_string($member) && strstr($member, $pattern))) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
foreach ($traversable as $member) {
|
||||
if (!(is_string($member) && stristr($member, $pattern))) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Asserts that all members are strings matching a regular expression.
|
||||
*
|
||||
* @param string $pattern
|
||||
* Regular expression string to find.
|
||||
* @param mixed $traversable
|
||||
* Variable to be examined.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if $traversable can be traversed and all members are strings
|
||||
* matching $pattern.
|
||||
*/
|
||||
public static function assertAllRegularExpressionMatch($pattern, $traversable) {
|
||||
if (static::assertTraversable($traversable)) {
|
||||
foreach ($traversable as $member) {
|
||||
if (!is_string($member)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!preg_match($pattern, $member)) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that all members are objects.
|
||||
*
|
||||
* When testing if a collection is composed of objects those objects should
|
||||
* be given a common interface to implement and the test should be written to
|
||||
* search for just that interface. While this method will allow tests for
|
||||
* just object status or for multiple classes and interfaces this was done to
|
||||
* allow tests to be written for existing code without altering it. Only use
|
||||
* this method in that manner when testing code from third party vendors.
|
||||
*
|
||||
* Here are some examples:
|
||||
* @code
|
||||
* // Just test all are objects, like a cache.
|
||||
* assert('Drupal\\Component\\Assertion\\Inspector::assertAllObjects(
|
||||
* $collection');
|
||||
*
|
||||
* // Test if traversable objects (arrays won't pass this)
|
||||
* assert('Drupal\\Component\\Assertion\\Inspector::assertAllObjects(
|
||||
* $collection', \'\\Traversable\');
|
||||
*
|
||||
* // Test for the Foo class or Bar\None interface
|
||||
* assert('Drupal\\Component\\Assertion\\Inspector::assertAllObjects(
|
||||
* $collection', \'\\Foo\', \'\\Bar\\None\'');
|
||||
* @endcode
|
||||
*
|
||||
* @param mixed $traversable
|
||||
* Variable to be examined.
|
||||
* @param string ...
|
||||
* Classes and interfaces to test objects against.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if $traversable can be traversed and all members are objects with
|
||||
* at least one of the listed classes or interfaces.
|
||||
*/
|
||||
public static function assertAllObjects() {
|
||||
$args = func_get_args();
|
||||
$traversable = array_shift($args);
|
||||
|
||||
if (static::assertTraversable($traversable)) {
|
||||
foreach ($traversable as $member) {
|
||||
if (count($args) > 0) {
|
||||
foreach ($args as $instance) {
|
||||
if ($member instanceof $instance) {
|
||||
// We're continuing to the next member on the outer loop.
|
||||
// @see http://php.net/continue
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
elseif (!is_object($member)) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
}
|
|
@ -508,7 +508,7 @@ class DateTimePlus {
|
|||
* @param array $array
|
||||
* An array of datetime values keyed by date part.
|
||||
*
|
||||
* @return boolean
|
||||
* @return bool
|
||||
* TRUE if the datetime parts contain valid values, otherwise FALSE.
|
||||
*/
|
||||
public static function checkArray($array) {
|
||||
|
|
339
core/lib/Drupal/Component/Gettext/LICENSE.txt
Normal file
339
core/lib/Drupal/Component/Gettext/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.
|
|
@ -147,7 +147,7 @@ class PoItem {
|
|||
/**
|
||||
* Get if the translation has plural values.
|
||||
*
|
||||
* @return boolean $plural
|
||||
* @return bool
|
||||
*/
|
||||
function isPlural() {
|
||||
return $this->_plural;
|
||||
|
|
12
core/lib/Drupal/Component/Gettext/README.txt
Normal file
12
core/lib/Drupal/Component/Gettext/README.txt
Normal file
|
@ -0,0 +1,12 @@
|
|||
The Drupal Gettext Component
|
||||
|
||||
Thanks for using this Drupal component.
|
||||
|
||||
You can participate in its development on Drupal.org, through our issue system:
|
||||
https://www.drupal.org/project/issues/drupal
|
||||
|
||||
You can get the full Drupal repo here:
|
||||
https://www.drupal.org/project/drupal/git-instructions
|
||||
|
||||
You can browse the full Drupal repo here:
|
||||
http://cgit.drupalcode.org/drupal
|
19
core/lib/Drupal/Component/Gettext/TESTING.txt
Normal file
19
core/lib/Drupal/Component/Gettext/TESTING.txt
Normal file
|
@ -0,0 +1,19 @@
|
|||
HOW-TO: Test this Drupal component
|
||||
|
||||
In order to test this component, you'll need to get the entire Drupal repo and
|
||||
run the tests there.
|
||||
|
||||
You'll find the tests under core/tests/Drupal/Tests/Component.
|
||||
|
||||
You can get the full Drupal repo here:
|
||||
https://www.drupal.org/project/drupal/git-instructions
|
||||
|
||||
You can find more information about running PHPUnit tests with Drupal here:
|
||||
https://www.drupal.org/node/2116263
|
||||
|
||||
Each component in the Drupal\Component namespace has its own annotated test
|
||||
group. You can use this group to run only the tests for this component. Like
|
||||
this:
|
||||
|
||||
$ cd ./core
|
||||
$ ./vendor/bin/phpunit --group Gettext
|
16
core/lib/Drupal/Component/Gettext/composer.json
Normal file
16
core/lib/Drupal/Component/Gettext/composer.json
Normal file
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"name": "drupal/core-gettext",
|
||||
"description": "PHP library for reading PO files.",
|
||||
"type": "library",
|
||||
"license": "GPL-2.0+",
|
||||
"support": {
|
||||
"issues": "https://www.drupal.org/project/issues/drupal",
|
||||
"irc": "irc://irc.freenode.net/drupal-contribute",
|
||||
"source": "https://www.drupal.org/project/drupal/git-instructions"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Drupal\\Component\\Gettext\\": ""
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Component\HttpFoundation\SecuredRedirectResponse.
|
||||
*/
|
||||
|
||||
namespace Drupal\Component\HttpFoundation;
|
||||
|
||||
use \Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
|
||||
/**
|
||||
* Provides a common base class for safe redirects.
|
||||
*
|
||||
* In case you want to redirect to external URLs use
|
||||
* TrustedRedirectResponse.
|
||||
*
|
||||
* For local URLs we use LocalRedirectResponse which opts
|
||||
* out of external redirects.
|
||||
*/
|
||||
abstract class SecuredRedirectResponse extends RedirectResponse {
|
||||
|
||||
/**
|
||||
* Copies an existing redirect response into a safe one.
|
||||
*
|
||||
* The safe one cannot accidentally redirect to an external URL, unless
|
||||
* actively wanted (see TrustedRedirectResponse).
|
||||
*
|
||||
* @param \Symfony\Component\HttpFoundation\RedirectResponse $response
|
||||
* The original redirect.
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public static function createFromRedirectResponse(RedirectResponse $response) {
|
||||
$safe_response = new static($response->getTargetUrl(), $response->getStatusCode(), $response->headers->allPreserveCase());
|
||||
$safe_response->setProtocolVersion($response->getProtocolVersion());
|
||||
$safe_response->setCharset($response->getCharset());
|
||||
return $safe_response;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setTargetUrl($url) {
|
||||
if (!$this->isSafe($url)) {
|
||||
throw new \InvalidArgumentException(sprintf('It is not safe to redirect to %s', $url));
|
||||
}
|
||||
return parent::setTargetUrl($url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the URL is considered as safe to redirect to.
|
||||
*
|
||||
* @param string $url
|
||||
* The URL checked for safety.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
abstract protected function isSafe($url);
|
||||
|
||||
}
|
|
@ -224,7 +224,7 @@ EOF;
|
|||
* @param string $path
|
||||
* A string containing either a file or directory path.
|
||||
*
|
||||
* @return boolean
|
||||
* @return bool
|
||||
* TRUE for success or if path does not exist, FALSE in the event of an
|
||||
* error.
|
||||
*/
|
||||
|
|
|
@ -58,7 +58,8 @@ class MTimeProtectedFileStorage extends MTimeProtectedFastFileStorage {
|
|||
*
|
||||
* @param string $name
|
||||
* The virtual file name. Can be a relative path.
|
||||
* return string
|
||||
*
|
||||
* @return string|false
|
||||
* The full path where the file is if it is valid, FALSE otherwise.
|
||||
*/
|
||||
protected function checkFile($name) {
|
||||
|
|
|
@ -67,6 +67,13 @@ class Context implements ContextInterface {
|
|||
return $this->contextValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function hasContextValue() {
|
||||
return (bool) $this->contextValue || (bool) $this->getContextDefinition()->getDefaultValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
|
@ -30,6 +30,14 @@ interface ContextInterface {
|
|||
*/
|
||||
public function getContextValue();
|
||||
|
||||
/**
|
||||
* Returns whether the context has a value.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the context has a value, FALSE otherwise.
|
||||
*/
|
||||
public function hasContextValue();
|
||||
|
||||
/**
|
||||
* Sets the definition that the context must conform to.
|
||||
*
|
||||
|
|
|
@ -22,7 +22,7 @@ abstract class ContextAwarePluginBase extends PluginBase implements ContextAware
|
|||
*
|
||||
* @var \Drupal\Component\Plugin\Context\ContextInterface[]
|
||||
*/
|
||||
protected $context;
|
||||
protected $context = [];
|
||||
|
||||
/**
|
||||
* Overrides \Drupal\Component\Plugin\PluginBase::__construct().
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
"homepage": "https://www.drupal.org/project/drupal",
|
||||
"license": "GPL-2.0+",
|
||||
"require": {
|
||||
"php": ">=5.4.2"
|
||||
"php": ">=5.5.9"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
|
|
|
@ -22,7 +22,30 @@ class ProxyBuilder {
|
|||
* The class name of the proxy.
|
||||
*/
|
||||
public static function buildProxyClassName($class_name) {
|
||||
return str_replace('\\', '_', $class_name) . '_Proxy';
|
||||
$match = [];
|
||||
preg_match('/([a-zA-Z0-9_]+\\\\[a-zA-Z0-9_]+)\\\\(.+)/', $class_name, $match);
|
||||
$root_namespace = $match[1];
|
||||
$rest_fqcn = $match[2];
|
||||
$proxy_class_name = $root_namespace . '\\ProxyClass\\' . $rest_fqcn;
|
||||
|
||||
return $proxy_class_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the used proxy namespace from a given class name.
|
||||
*
|
||||
* @param string $class_name
|
||||
* The class name of the actual service.
|
||||
*
|
||||
* @return string
|
||||
* The namespace name of the proxy.
|
||||
*/
|
||||
public static function buildProxyNamespace($class_name) {
|
||||
$proxy_classname = static::buildProxyClassName($class_name);
|
||||
|
||||
preg_match('/(.+)\\\\[a-zA-Z0-9]+/', $proxy_classname, $match);
|
||||
$proxy_namespace = $match[1];
|
||||
return $proxy_namespace;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -30,23 +53,38 @@ class ProxyBuilder {
|
|||
*
|
||||
* @param string $class_name
|
||||
* The class name of the actual service.
|
||||
* @param string $proxy_class_name
|
||||
* (optional) The class name of the proxy service.
|
||||
*
|
||||
* @return string
|
||||
* The full string with namespace class and methods.
|
||||
*/
|
||||
public function build($class_name) {
|
||||
public function build($class_name, $proxy_class_name = '') {
|
||||
$reflection = new \ReflectionClass($class_name);
|
||||
|
||||
if ($proxy_class_name) {
|
||||
$proxy_class_reflection = new \ReflectionClass($proxy_class_name);
|
||||
$proxy_namespace = $proxy_class_reflection->getNamespaceName();
|
||||
}
|
||||
else {
|
||||
$proxy_class_name = $this->buildProxyClassName($class_name);
|
||||
$proxy_namespace = $this->buildProxyNamespace($class_name);
|
||||
$proxy_class_shortname = str_replace($proxy_namespace . '\\', '', $proxy_class_name);
|
||||
}
|
||||
|
||||
$output = '';
|
||||
$class_documentation = <<<'EOS'
|
||||
/**
|
||||
* Provides a proxy class for \{{ class_name }}.
|
||||
*
|
||||
* @see \Drupal\Component\ProxyBuilder
|
||||
*/
|
||||
|
||||
namespace {{ namespace }}{
|
||||
|
||||
/**
|
||||
* Provides a proxy class for \{{ class_name }}.
|
||||
*
|
||||
* @see \Drupal\Component\ProxyBuilder
|
||||
*/
|
||||
|
||||
EOS;
|
||||
$class_start = 'class {{ proxy_class_name }}';
|
||||
$class_start = ' class {{ proxy_class_shortname }}';
|
||||
|
||||
// For cases in which the implemented interface is a child of another
|
||||
// interface, getInterfaceNames() also returns the parent. This causes a
|
||||
|
@ -77,11 +115,15 @@ EOS;
|
|||
// The actual class;
|
||||
$properties = <<<'EOS'
|
||||
/**
|
||||
* The id of the original proxied service.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $serviceId;
|
||||
protected $drupalProxyOriginalServiceId;
|
||||
|
||||
/**
|
||||
* The real proxied service, after it was lazy loaded.
|
||||
*
|
||||
* @var \{{ class_name }}
|
||||
*/
|
||||
protected $service;
|
||||
|
@ -123,13 +165,14 @@ EOS;
|
|||
if ($value === '') {
|
||||
return $value;
|
||||
}
|
||||
return " $value";
|
||||
return " $value";
|
||||
}, explode("\n", $output)));
|
||||
|
||||
$final_output = $class_documentation . $class_start . "\n{\n\n" . $output . "\n}\n";
|
||||
$final_output = $class_documentation . $class_start . "\n {\n\n" . $output . "\n }\n\n}\n";
|
||||
|
||||
$final_output = str_replace('{{ class_name }}', $class_name, $final_output);
|
||||
$final_output = str_replace('{{ proxy_class_name }}', $this->buildProxyClassName($class_name), $final_output);
|
||||
$final_output = str_replace('{{ namespace }}', $proxy_namespace ? $proxy_namespace . ' ' : '', $final_output);
|
||||
$final_output = str_replace('{{ proxy_class_shortname }}', $proxy_class_shortname, $final_output);
|
||||
|
||||
return $final_output;
|
||||
}
|
||||
|
@ -141,11 +184,16 @@ EOS;
|
|||
*/
|
||||
protected function buildLazyLoadItselfMethod() {
|
||||
$output = <<<'EOS'
|
||||
/**
|
||||
* Lazy loads the real service from the container.
|
||||
*
|
||||
* @return object
|
||||
* Returns the constructed real service.
|
||||
*/
|
||||
protected function lazyLoadItself()
|
||||
{
|
||||
if (!isset($this->service)) {
|
||||
$method_name = 'get' . Container::camelize($this->serviceId) . 'Service';
|
||||
$this->service = $this->container->$method_name(false);
|
||||
$this->service = $this->container->get($this->drupalProxyOriginalServiceId);
|
||||
}
|
||||
|
||||
return $this->service;
|
||||
|
@ -177,11 +225,19 @@ EOS;
|
|||
if ($reflection_method->returnsReference()) {
|
||||
$reference = '&';
|
||||
}
|
||||
|
||||
$signature_line = <<<'EOS'
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
||||
EOS;
|
||||
|
||||
if ($reflection_method->isStatic()) {
|
||||
$signature_line = 'public static function ' . $reference . $function_name . '(';
|
||||
$signature_line .= 'public static function ' . $reference . $function_name . '(';
|
||||
}
|
||||
else {
|
||||
$signature_line = 'public function ' . $reference . $function_name . '(';
|
||||
$signature_line .= 'public function ' . $reference . $function_name . '(';
|
||||
}
|
||||
|
||||
$signature_line .= implode(', ', $parameters);
|
||||
|
@ -269,10 +325,18 @@ EOS;
|
|||
*/
|
||||
protected function buildConstructorMethod() {
|
||||
$output = <<<'EOS'
|
||||
public function __construct(\Symfony\Component\DependencyInjection\ContainerInterface $container, $serviceId)
|
||||
/**
|
||||
* Constructs a ProxyClass Drupal proxy object.
|
||||
*
|
||||
* @param \Symfony\Component\DependencyInjection\ContainerInterface $container
|
||||
* The container.
|
||||
* @param string $drupal_proxy_original_service_id
|
||||
* The service ID of the original service.
|
||||
*/
|
||||
public function __construct(\Symfony\Component\DependencyInjection\ContainerInterface $container, $drupal_proxy_original_service_id)
|
||||
{
|
||||
$this->container = $container;
|
||||
$this->serviceId = $serviceId;
|
||||
$this->drupalProxyOriginalServiceId = $drupal_proxy_original_service_id;
|
||||
}
|
||||
|
||||
EOS;
|
||||
|
|
|
@ -1,78 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Component\ProxyBuilder\ProxyDumper.
|
||||
*/
|
||||
|
||||
namespace Drupal\Component\ProxyBuilder;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\DumperInterface;
|
||||
|
||||
/**
|
||||
* Dumps the proxy service into the dumped PHP container file.
|
||||
*/
|
||||
class ProxyDumper implements DumperInterface {
|
||||
|
||||
/**
|
||||
* Keeps track of already existing proxy classes.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $buildClasses = [];
|
||||
|
||||
/**
|
||||
* The proxy builder.
|
||||
*
|
||||
* @var \Drupal\Component\ProxyBuilder\ProxyBuilder
|
||||
*/
|
||||
protected $builder;
|
||||
|
||||
public function __construct(ProxyBuilder $builder) {
|
||||
$this->builder = $builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isProxyCandidate(Definition $definition) {
|
||||
return $definition->isLazy() && ($class = $definition->getClass()) && class_exists($class);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getProxyFactoryCode(Definition $definition, $id) {
|
||||
// Note: the specific get method is called initially with $lazyLoad=TRUE;
|
||||
// When you want to retrieve the actual service, the code generated in
|
||||
// ProxyBuilder calls the method with lazy loading disabled.
|
||||
$output = <<<'EOS'
|
||||
if ($lazyLoad) {
|
||||
return $this->services['{{ id }}'] = new {{ class_name }}($this, '{{ id }}');
|
||||
}
|
||||
|
||||
EOS;
|
||||
$output = str_replace('{{ id }}', $id, $output);
|
||||
$output = str_replace('{{ class_name }}', $this->builder->buildProxyClassName($definition->getClass()), $output);
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getProxyCode(Definition $definition) {
|
||||
// Maybe the same class is used in different services, which are both marked
|
||||
// as lazy (just think about 2 database connections).
|
||||
// In those cases we should not generate proxy code the second time.
|
||||
if (!isset($this->buildClasses[$definition->getClass()])) {
|
||||
$this->buildClasses[$definition->getClass()] = TRUE;
|
||||
return $this->builder->build($definition->getClass());
|
||||
}
|
||||
else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -5,7 +5,7 @@
|
|||
"homepage": "https://www.drupal.org/project/drupal",
|
||||
"license": "GPL-2.0+",
|
||||
"require": {
|
||||
"php": ">=5.4.2",
|
||||
"php": ">=5.5.9",
|
||||
"symfony/dependency-injection": "~2.6"
|
||||
},
|
||||
"autoload": {
|
||||
|
|
|
@ -106,7 +106,7 @@ class Crypt {
|
|||
|
||||
$hmac = base64_encode(hash_hmac('sha256', $data, $key, TRUE));
|
||||
// Modify the hmac so it's safe to use in URLs.
|
||||
return strtr($hmac, array('+' => '-', '/' => '_', '=' => ''));
|
||||
return str_replace(['+', '/', '='], ['-', '_', ''], $hmac);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -122,7 +122,7 @@ class Crypt {
|
|||
public static function hashBase64($data) {
|
||||
$hash = base64_encode(hash('sha256', $data, TRUE));
|
||||
// Modify the hash so it's safe to use in URLs.
|
||||
return strtr($hash, array('+' => '-', '/' => '_', '=' => ''));
|
||||
return str_replace(['+', '/', '='], ['-', '_', ''], $hash);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -137,7 +137,7 @@ class Crypt {
|
|||
* @see \Drupal\Component\Utility\Crypt::randomBytes()
|
||||
*/
|
||||
public static function randomBytesBase64($count = 32) {
|
||||
return strtr(base64_encode(static::randomBytes($count)), array('+' => '-', '/' => '_', '=' => ''));
|
||||
return str_replace(['+', '/', '='], ['-', '_', ''], base64_encode(static::randomBytes($count)));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -187,7 +187,7 @@ class Html {
|
|||
* @see self::getUniqueId()
|
||||
*/
|
||||
public static function getId($id) {
|
||||
$id = strtr(Unicode::strtolower($id), array(' ' => '-', '_' => '-', '[' => '-', ']' => ''));
|
||||
$id = str_replace([' ', '_', '[', ']'], ['-', '-', '-', ''], Unicode::strtolower($id));
|
||||
|
||||
// As defined in http://www.w3.org/TR/html4/types.html#type-name, HTML IDs can
|
||||
// only contain letters, digits ([0-9]), hyphens ("-"), underscores ("_"),
|
||||
|
|
|
@ -15,9 +15,9 @@ namespace Drupal\Component\Utility;
|
|||
* provides a store for known safe strings and methods to manage them
|
||||
* throughout the page request.
|
||||
*
|
||||
* Strings sanitized by self::checkPlain() or Xss::filter() are automatically
|
||||
* marked safe, as are markup strings created from render arrays via
|
||||
* drupal_render().
|
||||
* Strings sanitized by self::checkPlain() and self::escape() or
|
||||
* self::xssFilter() are automatically marked safe, as are markup strings
|
||||
* created from @link theme_render render arrays @endlink via drupal_render().
|
||||
*
|
||||
* This class should be limited to internal use only. Module developers should
|
||||
* instead use the appropriate
|
||||
|
@ -141,17 +141,79 @@ class SafeMarkup {
|
|||
/**
|
||||
* Applies a very permissive XSS/HTML filter for admin-only use.
|
||||
*
|
||||
* @param string $string
|
||||
* A string.
|
||||
* Note: This method only filters if $string is not marked safe already.
|
||||
*
|
||||
* @return string
|
||||
* The escaped string. If $string was already set as safe with
|
||||
* self::set(), it won't be escaped again.
|
||||
* @deprecated as of Drupal 8.0.x, will be removed before Drupal 8.0.0. If the
|
||||
* string used as part of a @link theme_render render array @endlink use
|
||||
* #markup to allow the render system to filter automatically. If the result
|
||||
* is not being used directly in the rendering system (for example, when its
|
||||
* result is being combined with other strings before rendering), use
|
||||
* Xss::filterAdmin(). Otherwise, use SafeMarkup::xssFilter() and the tag
|
||||
* list provided by Xss::getAdminTagList() instead. In the rare instance
|
||||
* that the caller does not want to filter strings that are marked safe
|
||||
* already, it needs to check SafeMarkup::isSafe() itself.
|
||||
*
|
||||
* @see \Drupal\Component\Utility\SafeMarkup::xssFilter()
|
||||
* @see \Drupal\Component\Utility\SafeMarkup::isSafe()
|
||||
* @see \Drupal\Component\Utility\Xss::filterAdmin()
|
||||
* @see \Drupal\Component\Utility\Xss::getAdminTagList()
|
||||
*/
|
||||
public static function checkAdminXss($string) {
|
||||
return static::isSafe($string) ? $string : Xss::filterAdmin($string);
|
||||
return static::isSafe($string) ? $string : static::xssFilter($string, Xss::getAdminTagList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters HTML for XSS vulnerabilities and marks the result as safe.
|
||||
*
|
||||
* Calling this method unnecessarily will result in bloating the safe string
|
||||
* list and increases the chance of unintended side effects.
|
||||
*
|
||||
* If Twig receives a value that is not marked as safe then it will
|
||||
* automatically encode special characters in a plain-text string for display
|
||||
* as HTML. Therefore, SafeMarkup::xssFilter() should only be used when the
|
||||
* string might contain HTML that needs to be rendered properly by the
|
||||
* browser.
|
||||
*
|
||||
* If you need to filter for admin use, like Xss::filterAdmin(), then:
|
||||
* - If the string is used as part of a @link theme_render render array @endlink,
|
||||
* use #markup to allow the render system to filter by the admin tag list
|
||||
* automatically.
|
||||
* - Otherwise, use the SafeMarkup::xssFilter() with tag list provided by
|
||||
* Xss::getAdminTagList() instead.
|
||||
*
|
||||
* This method should only be used instead of Xss::filter() when the result is
|
||||
* being added to a render array that is constructed before rendering begins.
|
||||
*
|
||||
* In the rare instance that the caller does not want to filter strings that
|
||||
* are marked safe already, it needs to check SafeMarkup::isSafe() itself.
|
||||
*
|
||||
* @param $string
|
||||
* The string with raw HTML in it. It will be stripped of everything that
|
||||
* can cause an XSS attack. The string provided will always be escaped
|
||||
* regardless of whether the string is already marked as safe.
|
||||
* @param array $html_tags
|
||||
* (optional) An array of HTML tags. If omitted, it uses the default tag
|
||||
* list defined by \Drupal\Component\Utility\Xss::filter().
|
||||
*
|
||||
* @return string
|
||||
* An XSS-safe version of $string, or an empty string if $string is not
|
||||
* valid UTF-8. The string is marked as safe.
|
||||
*
|
||||
* @ingroup sanitization
|
||||
*
|
||||
* @see \Drupal\Component\Utility\Xss::filter()
|
||||
* @see \Drupal\Component\Utility\Xss::filterAdmin()
|
||||
* @see \Drupal\Component\Utility\Xss::getAdminTagList()
|
||||
* @see \Drupal\Component\Utility\SafeMarkup::isSafe()
|
||||
*/
|
||||
public static function xssFilter($string, $html_tags = NULL) {
|
||||
if (is_null($html_tags)) {
|
||||
$string = Xss::filter($string);
|
||||
}
|
||||
else {
|
||||
$string = Xss::filter($string, $html_tags);
|
||||
}
|
||||
return static::set($string);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -244,7 +244,7 @@ class UrlHelper {
|
|||
$base_parts = parse_url($base_url);
|
||||
|
||||
if (empty($base_parts['host']) || empty($url_parts['host'])) {
|
||||
throw new \InvalidArgumentException(SafeMarkup::format('A path was passed when a fully qualified domain was expected.'));
|
||||
throw new \InvalidArgumentException('A path was passed when a fully qualified domain was expected.');
|
||||
}
|
||||
|
||||
if (!isset($url_parts['path']) || !isset($base_parts['path'])) {
|
||||
|
|
|
@ -29,14 +29,19 @@ class Xss {
|
|||
* Based on kses by Ulf Harnhammar, see http://sourceforge.net/projects/kses.
|
||||
* For examples of various XSS attacks, see: http://ha.ckers.org/xss.html.
|
||||
*
|
||||
* This code does five things:
|
||||
* This method is preferred to
|
||||
* \Drupal\Component\Utility\SafeMarkup::xssFilter() when the result is not
|
||||
* being used directly in the rendering system (for example, when its result
|
||||
* is being combined with other strings before rendering). This avoids
|
||||
* bloating the safe string list with partial strings if the whole result will
|
||||
* be marked safe.
|
||||
*
|
||||
* This code does four things:
|
||||
* - Removes characters and constructs that can trick browsers.
|
||||
* - Makes sure all HTML entities are well-formed.
|
||||
* - Makes sure all HTML tags and attributes are well-formed.
|
||||
* - Makes sure no HTML tags contain URLs with a disallowed protocol (e.g.
|
||||
* javascript:).
|
||||
* - Marks the sanitized, XSS-safe version of $string as safe markup for
|
||||
* rendering.
|
||||
*
|
||||
* @param $string
|
||||
* The string with raw HTML in it. It will be stripped of everything that
|
||||
|
@ -49,7 +54,7 @@ class Xss {
|
|||
* valid UTF-8.
|
||||
*
|
||||
* @see \Drupal\Component\Utility\Unicode::validateUtf8()
|
||||
* @see \Drupal\Component\Utility\SafeMarkup
|
||||
* @see \Drupal\Component\Utility\SafeMarkup::xssFilter()
|
||||
*
|
||||
* @ingroup sanitization
|
||||
*/
|
||||
|
@ -83,7 +88,7 @@ class Xss {
|
|||
// for output. All other known XSS vectors have been filtered out by this
|
||||
// point and any HTML tags remaining will have been deliberately allowed, so
|
||||
// it is acceptable to call SafeMarkup::set() on the resultant string.
|
||||
return SafeMarkup::set(preg_replace_callback('%
|
||||
return preg_replace_callback('%
|
||||
(
|
||||
<(?=[^a-zA-Z!/]) # a lone <
|
||||
| # or
|
||||
|
@ -92,7 +97,7 @@ class Xss {
|
|||
<[^>]*(>|$) # a string that starts with a <, up until the > or the end of the string
|
||||
| # or
|
||||
> # just a >
|
||||
)%x', $splitter, $string));
|
||||
)%x', $splitter, $string);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -103,6 +108,13 @@ class Xss {
|
|||
* is desired (so \Drupal\Component\Utility\SafeMarkup::checkPlain() is
|
||||
* not acceptable).
|
||||
*
|
||||
* This method is preferred to
|
||||
* \Drupal\Component\Utility\SafeMarkup::xssFilter() when the result is
|
||||
* not being used directly in the rendering system (for example, when its
|
||||
* result is being combined with other strings before rendering). This avoids
|
||||
* bloating the safe string list with partial strings if the whole result will
|
||||
* be marked safe.
|
||||
*
|
||||
* Allows all tags that can be used inside an HTML body, save
|
||||
* for scripts and styles.
|
||||
*
|
||||
|
@ -111,6 +123,12 @@ class Xss {
|
|||
*
|
||||
* @return string
|
||||
* The filtered string.
|
||||
*
|
||||
* @ingroup sanitization
|
||||
*
|
||||
* @see \Drupal\Component\Utility\SafeMarkup::xssFilter()
|
||||
* @see \Drupal\Component\Utility\Xss::getAdminTagList()
|
||||
*
|
||||
*/
|
||||
public static function filterAdmin($string) {
|
||||
return static::filter($string, static::$adminTags);
|
||||
|
@ -319,4 +337,14 @@ class Xss {
|
|||
return !isset($html_tags[strtolower($elem)]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the list of html tags allowed by Xss::filterAdmin().
|
||||
*
|
||||
* @return array
|
||||
* The list of html tags allowed by filterAdmin().
|
||||
*/
|
||||
public static function getAdminTagList() {
|
||||
return static::$adminTags;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
"homepage": "https://www.drupal.org/project/drupal",
|
||||
"license": "GPL-2.0+",
|
||||
"require": {
|
||||
"php": ">=5.3.10"
|
||||
"php": ">=5.5.9"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
|
|
|
@ -25,6 +25,9 @@ use Drupal\Core\Session\AccountInterface;
|
|||
*
|
||||
* When using ::orIf() and ::andIf(), cacheability metadata will be merged
|
||||
* accordingly as well.
|
||||
*
|
||||
* @todo Use RefinableCacheableDependencyInterface and the corresponding trait in
|
||||
* https://www.drupal.org/node/2526326.
|
||||
*/
|
||||
abstract class AccessResult implements AccessResultInterface, CacheableDependencyInterface {
|
||||
|
||||
|
@ -316,10 +319,12 @@ abstract class AccessResult implements AccessResultInterface, CacheableDependenc
|
|||
* The entity whose cache tag to set on the access result.
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @deprecated in Drupal 8.0.x-dev, will be removed before Drupal 9.0.0. Use
|
||||
* ::addCacheableDependency() instead.
|
||||
*/
|
||||
public function cacheUntilEntityChanges(EntityInterface $entity) {
|
||||
$this->addCacheTags($entity->getCacheTags());
|
||||
return $this;
|
||||
return $this->addCacheableDependency($entity);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -329,9 +334,33 @@ abstract class AccessResult implements AccessResultInterface, CacheableDependenc
|
|||
* The configuration object whose cache tag to set on the access result.
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @deprecated in Drupal 8.0.x-dev, will be removed before Drupal 9.0.0. Use
|
||||
* ::addCacheableDependency() instead.
|
||||
*/
|
||||
public function cacheUntilConfigurationChanges(ConfigBase $configuration) {
|
||||
$this->addCacheTags($configuration->getCacheTags());
|
||||
return $this->addCacheableDependency($configuration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a dependency on an object: merges its cacheability metadata.
|
||||
*
|
||||
* @param \Drupal\Core\Cache\CacheableDependencyInterface|object $other_object
|
||||
* The dependency. If the object implements CacheableDependencyInterface,
|
||||
* then its cacheability metadata will be used. Otherwise, the passed in
|
||||
* object must be assumed to be uncacheable, so max-age 0 is set.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function addCacheableDependency($other_object) {
|
||||
if ($other_object instanceof CacheableDependencyInterface) {
|
||||
$this->contexts = Cache::mergeContexts($this->contexts, $other_object->getCacheContexts());
|
||||
$this->tags = Cache::mergeTags($this->tags, $other_object->getCacheTags());
|
||||
$this->maxAge = Cache::mergeMaxAges($this->maxAge, $other_object->getCacheMaxAge());
|
||||
}
|
||||
else {
|
||||
$this->maxAge = 0;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
namespace Drupal\Core\Access;
|
||||
|
||||
use Drupal\Core\Cache\CacheableMetadata;
|
||||
use Drupal\Core\Render\BubbleableMetadata;
|
||||
use Drupal\Core\RouteProcessor\OutboundRouteProcessorInterface;
|
||||
use Symfony\Component\Routing\Route;
|
||||
|
||||
|
@ -36,7 +36,7 @@ class RouteProcessorCsrf implements OutboundRouteProcessorInterface {
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function processOutbound($route_name, Route $route, array &$parameters, CacheableMetadata $cacheable_metadata = NULL) {
|
||||
public function processOutbound($route_name, Route $route, array &$parameters, BubbleableMetadata $bubbleable_metadata = NULL) {
|
||||
if ($route->hasRequirement('_csrf_token')) {
|
||||
$path = ltrim($route->getPath(), '/');
|
||||
// Replace the path parameters with values from the parameters array.
|
||||
|
@ -45,13 +45,44 @@ class RouteProcessorCsrf implements OutboundRouteProcessorInterface {
|
|||
}
|
||||
// Adding this to the parameters means it will get merged into the query
|
||||
// string when the route is compiled.
|
||||
$parameters['token'] = $this->csrfToken->get($path);
|
||||
if ($cacheable_metadata) {
|
||||
// Tokens are per user and per session, so not cacheable.
|
||||
// @todo Improve in https://www.drupal.org/node/2351015.
|
||||
$cacheable_metadata->setCacheMaxAge(0);
|
||||
if (!$bubbleable_metadata) {
|
||||
$parameters['token'] = $this->csrfToken->get($path);
|
||||
}
|
||||
else {
|
||||
// Generate a placeholder and a render array to replace it.
|
||||
$placeholder = hash('sha1', $path);
|
||||
$placeholder_render_array = [
|
||||
'#lazy_builder' => ['route_processor_csrf:renderPlaceholderCsrfToken', [$path]],
|
||||
];
|
||||
|
||||
// Instead of setting an actual CSRF token as the query string, we set
|
||||
// the placeholder, which will be replaced at the very last moment. This
|
||||
// ensures links with CSRF tokens don't break cacheability.
|
||||
$parameters['token'] = $placeholder;
|
||||
$bubbleable_metadata->addAttachments(['placeholders' => [$placeholder => $placeholder_render_array]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* #lazy_builder callback; gets a CSRF token for the given path.
|
||||
*
|
||||
* @param string $path
|
||||
* The path to get a CSRF token for.
|
||||
*
|
||||
* @return array
|
||||
* A renderable array representing the CSRF token.
|
||||
*/
|
||||
public function renderPlaceholderCsrfToken($path) {
|
||||
return [
|
||||
'#markup' => $this->csrfToken->get($path),
|
||||
// Tokens are per session.
|
||||
'#cache' => [
|
||||
'contexts' => [
|
||||
'session',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -164,15 +164,15 @@ class AjaxResponseAttachmentsProcessor implements AttachmentsResponseProcessorIn
|
|||
$resource_commands = array();
|
||||
if ($css_assets) {
|
||||
$css_render_array = $this->cssCollectionRenderer->render($css_assets);
|
||||
$resource_commands[] = new AddCssCommand($this->renderer->renderPlain($css_render_array));
|
||||
$resource_commands[] = new AddCssCommand((string) $this->renderer->renderPlain($css_render_array));
|
||||
}
|
||||
if ($js_assets_header) {
|
||||
$js_header_render_array = $this->jsCollectionRenderer->render($js_assets_header);
|
||||
$resource_commands[] = new PrependCommand('head', $this->renderer->renderPlain($js_header_render_array));
|
||||
$resource_commands[] = new PrependCommand('head', (string) $this->renderer->renderPlain($js_header_render_array));
|
||||
}
|
||||
if ($js_assets_footer) {
|
||||
$js_footer_render_array = $this->jsCollectionRenderer->render($js_assets_footer);
|
||||
$resource_commands[] = new AppendCommand('body', $this->renderer->renderPlain($js_footer_render_array));
|
||||
$resource_commands[] = new AppendCommand('body', (string) $this->renderer->renderPlain($js_footer_render_array));
|
||||
}
|
||||
foreach (array_reverse($resource_commands) as $resource_command) {
|
||||
$response->addCommand($resource_command, TRUE);
|
||||
|
|
|
@ -37,10 +37,10 @@ trait CommandWithAttachedAssetsTrait {
|
|||
if (is_array($this->content)) {
|
||||
$html = \Drupal::service('renderer')->renderRoot($this->content);
|
||||
$this->attachedAssets = AttachedAssets::createFromRenderArray($this->content);
|
||||
return $html;
|
||||
return (string) $html;
|
||||
}
|
||||
else {
|
||||
return $this->content;
|
||||
return (string) $this->content;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Core\Authentication\AuthenticationCollector.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\Authentication;
|
||||
|
||||
/**
|
||||
* A collector class for authentication providers.
|
||||
*/
|
||||
class AuthenticationCollector implements AuthenticationCollectorInterface {
|
||||
|
||||
/**
|
||||
* Array of all registered authentication providers, keyed by ID.
|
||||
*
|
||||
* @var \Drupal\Core\Authentication\AuthenticationProviderInterface[]
|
||||
*/
|
||||
protected $providers;
|
||||
|
||||
/**
|
||||
* Array of all providers and their priority.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $providerOrders = [];
|
||||
|
||||
/**
|
||||
* Sorted list of registered providers.
|
||||
*
|
||||
* @var \Drupal\Core\Authentication\AuthenticationProviderInterface[]
|
||||
*/
|
||||
protected $sortedProviders;
|
||||
|
||||
/**
|
||||
* List of providers which are allowed on routes with no _auth option.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
protected $globalProviders;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function addProvider(AuthenticationProviderInterface $provider, $provider_id, $priority = 0, $global = FALSE) {
|
||||
$this->providers[$provider_id] = $provider;
|
||||
$this->providerOrders[$priority][$provider_id] = $provider;
|
||||
// Force the providers to be re-sorted.
|
||||
$this->sortedProviders = NULL;
|
||||
|
||||
if ($global) {
|
||||
$this->globalProviders[$provider_id] = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isGlobal($provider_id) {
|
||||
return isset($this->globalProviders[$provider_id]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getProvider($provider_id) {
|
||||
return isset($this->providers[$provider_id]) ? $this->providers[$provider_id] : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSortedProviders() {
|
||||
if (!isset($this->sortedProviders)) {
|
||||
// Sort the providers according to priority.
|
||||
krsort($this->providerOrders);
|
||||
|
||||
// Merge nested providers from $this->providers into $this->sortedProviders.
|
||||
$this->sortedProviders = [];
|
||||
foreach ($this->providerOrders as $providers) {
|
||||
$this->sortedProviders = array_merge($this->sortedProviders, $providers);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->sortedProviders;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Core\Authentication\AuthenticationCollectorInterface.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\Authentication;
|
||||
|
||||
/**
|
||||
* Interface for collectors of registered authentication providers.
|
||||
*/
|
||||
interface AuthenticationCollectorInterface {
|
||||
|
||||
/**
|
||||
* Adds a provider to the array of registered providers.
|
||||
*
|
||||
* @param \Drupal\Core\Authentication\AuthenticationProviderInterface $provider
|
||||
* The provider object.
|
||||
* @param string $provider_id
|
||||
* Identifier of the provider.
|
||||
* @param int $priority
|
||||
* (optional) The provider's priority.
|
||||
* @param bool $global
|
||||
* (optional) TRUE if the provider is to be applied globally on all routes.
|
||||
* Defaults to FALSE.
|
||||
*/
|
||||
public function addProvider(AuthenticationProviderInterface $provider, $provider_id, $priority = 0, $global = FALSE);
|
||||
|
||||
/**
|
||||
* Returns whether a provider is considered global.
|
||||
*
|
||||
* @param string $provider_id
|
||||
* The provider ID.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the provider is global, FALSE otherwise.
|
||||
*
|
||||
* @see \Drupal\Core\Authentication\AuthenticationCollectorInterface::addProvider
|
||||
*/
|
||||
public function isGlobal($provider_id);
|
||||
|
||||
/**
|
||||
* Returns an authentication provider.
|
||||
*
|
||||
* @param string $provider_id
|
||||
* The provider ID.
|
||||
*
|
||||
* @return \Drupal\Core\Authentication\AuthenticationProviderInterface|NULL
|
||||
* The authentication provider which matches the ID.
|
||||
*/
|
||||
public function getProvider($provider_id);
|
||||
|
||||
/**
|
||||
* Returns the sorted array of authentication providers.
|
||||
*
|
||||
* @return \Drupal\Core\Authentication\AuthenticationProviderInterface[]
|
||||
* An array of authentication provider objects.
|
||||
*/
|
||||
public function getSortedProviders();
|
||||
|
||||
}
|
|
@ -20,69 +20,23 @@ use Symfony\Component\HttpFoundation\Request;
|
|||
*
|
||||
* If no provider set an active user then the user is set to anonymous.
|
||||
*/
|
||||
class AuthenticationManager implements AuthenticationProviderInterface, AuthenticationProviderFilterInterface, AuthenticationProviderChallengeInterface, AuthenticationManagerInterface {
|
||||
class AuthenticationManager implements AuthenticationProviderInterface, AuthenticationProviderFilterInterface, AuthenticationProviderChallengeInterface {
|
||||
|
||||
/**
|
||||
* Array of all registered authentication providers, keyed by ID.
|
||||
* The authentication provider collector.
|
||||
*
|
||||
* @var \Drupal\Core\Authentication\AuthenticationProviderInterface[]
|
||||
* @var \Drupal\Core\Authentication\AuthenticationCollectorInterface
|
||||
*/
|
||||
protected $providers;
|
||||
protected $authCollector;
|
||||
|
||||
/**
|
||||
* Array of all providers and their priority.
|
||||
* Creates a new authentication manager instance.
|
||||
*
|
||||
* @var array
|
||||
* @param \Drupal\Core\Authentication\AuthenticationCollectorInterface $auth_collector
|
||||
* The authentication provider collector.
|
||||
*/
|
||||
protected $providerOrders = array();
|
||||
|
||||
/**
|
||||
* Sorted list of registered providers.
|
||||
*
|
||||
* @var \Drupal\Core\Authentication\AuthenticationProviderInterface[]
|
||||
*/
|
||||
protected $sortedProviders;
|
||||
|
||||
/**
|
||||
* List of providers which implement the filter interface.
|
||||
*
|
||||
* @var \Drupal\Core\Authentication\AuthenticationProviderFilterInterface[]
|
||||
*/
|
||||
protected $filters;
|
||||
|
||||
/**
|
||||
* List of providers which implement the challenge interface.
|
||||
*
|
||||
* @var \Drupal\Core\Authentication\AuthenticationProviderChallengeInterface[]
|
||||
*/
|
||||
protected $challengers;
|
||||
|
||||
/**
|
||||
* List of providers which are allowed on routes with no _auth option.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
protected $globalProviders;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function addProvider(AuthenticationProviderInterface $provider, $provider_id, $priority = 0, $global = FALSE) {
|
||||
$this->providers[$provider_id] = $provider;
|
||||
$this->providerOrders[$priority][$provider_id] = $provider;
|
||||
// Force the builders to be re-sorted.
|
||||
$this->sortedProviders = NULL;
|
||||
|
||||
if ($provider instanceof AuthenticationProviderFilterInterface) {
|
||||
$this->filters[$provider_id] = $provider;
|
||||
}
|
||||
if ($provider instanceof AuthenticationProviderChallengeInterface) {
|
||||
$this->challengers[$provider_id] = $provider;
|
||||
}
|
||||
|
||||
if ($global) {
|
||||
$this->globalProviders[$provider_id] = TRUE;
|
||||
}
|
||||
public function __construct(AuthenticationCollectorInterface $auth_collector) {
|
||||
$this->authCollector = $auth_collector;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -97,7 +51,13 @@ class AuthenticationManager implements AuthenticationProviderInterface, Authenti
|
|||
*/
|
||||
public function authenticate(Request $request) {
|
||||
$provider_id = $this->getProvider($request);
|
||||
return $this->providers[$provider_id]->authenticate($request);
|
||||
$provider = $this->authCollector->getProvider($provider_id);
|
||||
|
||||
if ($provider) {
|
||||
return $provider->authenticate($request);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -110,7 +70,7 @@ class AuthenticationManager implements AuthenticationProviderInterface, Authenti
|
|||
$result = $this->applyFilter($request, $authenticated, $this->getProvider($request));
|
||||
}
|
||||
else {
|
||||
foreach ($this->getSortedProviders() as $provider_id => $provider) {
|
||||
foreach ($this->authCollector->getSortedProviders() as $provider_id => $provider) {
|
||||
if ($this->applyFilter($request, $authenticated, $provider_id)) {
|
||||
$result = TRUE;
|
||||
break;
|
||||
|
@ -126,8 +86,10 @@ class AuthenticationManager implements AuthenticationProviderInterface, Authenti
|
|||
*/
|
||||
public function challengeException(Request $request, \Exception $previous) {
|
||||
$provider_id = $this->getChallenger($request);
|
||||
|
||||
if ($provider_id) {
|
||||
return $this->challengers[$provider_id]->challengeException($request, $previous);
|
||||
$provider = $this->authCollector->getProvider($provider_id);
|
||||
return $provider->challengeException($request, $previous);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -142,7 +104,7 @@ class AuthenticationManager implements AuthenticationProviderInterface, Authenti
|
|||
* If no application detects appropriate credentials, then NULL is returned.
|
||||
*/
|
||||
protected function getProvider(Request $request) {
|
||||
foreach ($this->getSortedProviders() as $provider_id => $provider) {
|
||||
foreach ($this->authCollector->getSortedProviders() as $provider_id => $provider) {
|
||||
if ($provider->applies($request)) {
|
||||
return $provider_id;
|
||||
}
|
||||
|
@ -150,21 +112,19 @@ class AuthenticationManager implements AuthenticationProviderInterface, Authenti
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the id of the challenge provider for a request.
|
||||
* Returns the ID of the challenge provider for a request.
|
||||
*
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
* The incoming request.
|
||||
*
|
||||
* @return string|NULL
|
||||
* The id of the first authentication provider which applies to the request.
|
||||
* The ID of the first authentication provider which applies to the request.
|
||||
* If no application detects appropriate credentials, then NULL is returned.
|
||||
*/
|
||||
protected function getChallenger(Request $request) {
|
||||
if (!empty($this->challengers)) {
|
||||
foreach ($this->getSortedProviders($request, FALSE) as $provider_id => $provider) {
|
||||
if (isset($this->challengers[$provider_id]) && !$provider->applies($request) && $this->applyFilter($request, FALSE, $provider_id)) {
|
||||
return $provider_id;
|
||||
}
|
||||
foreach ($this->authCollector->getSortedProviders() as $provider_id => $provider) {
|
||||
if (($provider instanceof AuthenticationProviderChallengeInterface) && !$provider->applies($request) && $this->applyFilter($request, FALSE, $provider_id)) {
|
||||
return $provider_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -186,8 +146,10 @@ class AuthenticationManager implements AuthenticationProviderInterface, Authenti
|
|||
* TRUE if provider is allowed, FALSE otherwise.
|
||||
*/
|
||||
protected function applyFilter(Request $request, $authenticated, $provider_id) {
|
||||
if (isset($this->filters[$provider_id])) {
|
||||
$result = $this->filters[$provider_id]->appliesToRoutedRequest($request, $authenticated);
|
||||
$provider = $this->authCollector->getProvider($provider_id);
|
||||
|
||||
if ($provider && ($provider instanceof AuthenticationProviderFilterInterface)) {
|
||||
$result = $provider->appliesToRoutedRequest($request, $authenticated);
|
||||
}
|
||||
else {
|
||||
$result = $this->defaultFilter($request, $provider_id);
|
||||
|
@ -222,27 +184,8 @@ class AuthenticationManager implements AuthenticationProviderInterface, Authenti
|
|||
return in_array($provider_id, $route->getOption('_auth'));
|
||||
}
|
||||
else {
|
||||
return isset($this->globalProviders[$provider_id]);
|
||||
return $this->authCollector->isGlobal($provider_id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the sorted array of authentication providers.
|
||||
*
|
||||
* @return \Drupal\Core\Authentication\AuthenticationProviderInterface[]
|
||||
* An array of authentication provider objects.
|
||||
*/
|
||||
protected function getSortedProviders() {
|
||||
if (!isset($this->sortedProviders)) {
|
||||
// Sort the builders according to priority.
|
||||
krsort($this->providerOrders);
|
||||
// Merge nested providers from $this->providers into $this->sortedProviders.
|
||||
$this->sortedProviders = array();
|
||||
foreach ($this->providerOrders as $providers) {
|
||||
$this->sortedProviders = array_merge($this->sortedProviders, $providers);
|
||||
}
|
||||
}
|
||||
return $this->sortedProviders;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Core\Authentication\AuthenticationManagerInterface.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\Authentication;
|
||||
|
||||
/**
|
||||
* Defines an interface for authentication managers.
|
||||
*/
|
||||
interface AuthenticationManagerInterface {
|
||||
|
||||
/**
|
||||
* Adds a provider to the array of registered providers.
|
||||
*
|
||||
* @param \Drupal\Core\Authentication\AuthenticationProviderInterface $provider
|
||||
* The provider object.
|
||||
* @param string $provider_id
|
||||
* Identifier of the provider.
|
||||
* @param int $priority
|
||||
* (optional) The provider's priority.
|
||||
* @param bool $global
|
||||
* (optional) TRUE if the provider is to be applied globally on all routes.
|
||||
* Defaults to FALSE.
|
||||
*/
|
||||
public function addProvider(AuthenticationProviderInterface $provider, $provider_id, $priority = 0, $global = FALSE);
|
||||
|
||||
}
|
|
@ -10,6 +10,7 @@ namespace Drupal\Core\Block;
|
|||
use Drupal\block\BlockInterface;
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
use Drupal\Core\Cache\CacheableDependencyInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Plugin\ContextAwarePluginBase;
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
|
@ -265,18 +266,23 @@ abstract class BlockBase extends ContextAwarePluginBase implements BlockPluginIn
|
|||
// \Drupal\system\MachineNameController::transliterate(), so it might make
|
||||
// sense to provide a common service for the two.
|
||||
$transliterated = $this->transliteration()->transliterate($admin_label, LanguageInterface::LANGCODE_DEFAULT, '_');
|
||||
|
||||
$replace_pattern = '[^a-z0-9_.]+';
|
||||
|
||||
$transliterated = Unicode::strtolower($transliterated);
|
||||
|
||||
if (isset($replace_pattern)) {
|
||||
$transliterated = preg_replace('@' . $replace_pattern . '@', '', $transliterated);
|
||||
}
|
||||
$transliterated = preg_replace('@[^a-z0-9_.]+@', '', $transliterated);
|
||||
|
||||
return $transliterated;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheMaxAge() {
|
||||
$max_age = parent::getCacheMaxAge();
|
||||
// @todo Configurability of this will be removed in
|
||||
// https://www.drupal.org/node/2458763.
|
||||
return Cache::mergeMaxAges($max_age, (int) $this->configuration['cache']['max_age']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the transliteration service.
|
||||
*
|
||||
|
@ -299,25 +305,4 @@ abstract class BlockBase extends ContextAwarePluginBase implements BlockPluginIn
|
|||
$this->transliteration = $transliteration;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheContexts() {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheTags() {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheMaxAge() {
|
||||
return (int)$this->configuration['cache']['max_age'];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
namespace Drupal\Core\Breadcrumb;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\Routing\RouteMatchInterface;
|
||||
|
||||
|
@ -95,7 +94,7 @@ class BreadcrumbManager implements ChainBreadcrumbBuilderInterface {
|
|||
break;
|
||||
}
|
||||
else {
|
||||
throw new \UnexpectedValueException(SafeMarkup::format('Invalid breadcrumb returned by !class::build().', array('!class' => get_class($builder))));
|
||||
throw new \UnexpectedValueException('Invalid breadcrumb returned by ' . get_class($builder) . '::build().');
|
||||
}
|
||||
}
|
||||
// Allow modules to alter the breadcrumb.
|
||||
|
|
|
@ -24,19 +24,16 @@ class Cache {
|
|||
/**
|
||||
* Merges arrays of cache contexts and removes duplicates.
|
||||
*
|
||||
* @param string[] …
|
||||
* Arrays of cache contexts to merge.
|
||||
* @param array $a
|
||||
* Cache contexts array to merge.
|
||||
* @param array $b
|
||||
* Cache contexts array to merge.
|
||||
*
|
||||
* @return string[]
|
||||
* The merged array of cache contexts.
|
||||
*/
|
||||
public static function mergeContexts() {
|
||||
$cache_context_arrays = func_get_args();
|
||||
$cache_contexts = [];
|
||||
foreach ($cache_context_arrays as $contexts) {
|
||||
$cache_contexts = array_merge($cache_contexts, $contexts);
|
||||
}
|
||||
$cache_contexts = array_unique($cache_contexts);
|
||||
public static function mergeContexts(array $a = [], array $b = []) {
|
||||
$cache_contexts = array_unique(array_merge($a, $b));
|
||||
\Drupal::service('cache_contexts_manager')->validateTokens($cache_contexts);
|
||||
sort($cache_contexts);
|
||||
return $cache_contexts;
|
||||
|
@ -53,19 +50,16 @@ class Cache {
|
|||
* allows items to be invalidated based on all tags attached to the content
|
||||
* they're constituted from.
|
||||
*
|
||||
* @param string[] …
|
||||
* Arrays of cache tags to merge.
|
||||
* @param array $a
|
||||
* Cache tags array to merge.
|
||||
* @param array $b
|
||||
* Cache tags array to merge.
|
||||
*
|
||||
* @return string[]
|
||||
* The merged array of cache tags.
|
||||
*/
|
||||
public static function mergeTags() {
|
||||
$cache_tag_arrays = func_get_args();
|
||||
$cache_tags = [];
|
||||
foreach ($cache_tag_arrays as $tags) {
|
||||
$cache_tags = array_merge($cache_tags, $tags);
|
||||
}
|
||||
$cache_tags = array_unique($cache_tags);
|
||||
public static function mergeTags(array $a = [], array $b = []) {
|
||||
$cache_tags = array_unique(array_merge($a, $b));
|
||||
static::validateTags($cache_tags);
|
||||
sort($cache_tags);
|
||||
return $cache_tags;
|
||||
|
@ -76,29 +70,25 @@ class Cache {
|
|||
*
|
||||
* Ensures infinite max-age (Cache::PERMANENT) is taken into account.
|
||||
*
|
||||
* @param int …
|
||||
* Max-age values.
|
||||
* @param int $a
|
||||
* Max age value to merge.
|
||||
* @param int $b
|
||||
* Max age value to merge.
|
||||
*
|
||||
* @return int
|
||||
* The minimum max-age value.
|
||||
*/
|
||||
public static function mergeMaxAges() {
|
||||
$max_ages = func_get_args();
|
||||
|
||||
// Filter out all max-age values set to cache permanently.
|
||||
if (in_array(Cache::PERMANENT, $max_ages)) {
|
||||
$max_ages = array_filter($max_ages, function ($max_age) {
|
||||
return $max_age !== Cache::PERMANENT;
|
||||
});
|
||||
|
||||
// If nothing is left, then all max-age values were set to cache
|
||||
// permanently, and then that is the result.
|
||||
if (empty($max_ages)) {
|
||||
return Cache::PERMANENT;
|
||||
}
|
||||
public static function mergeMaxAges($a = Cache::PERMANENT, $b = Cache::PERMANENT) {
|
||||
// If one of the values is Cache::PERMANENT, return the other value.
|
||||
if ($a === Cache::PERMANENT){
|
||||
return $b;
|
||||
}
|
||||
if ($b === Cache::PERMANENT){
|
||||
return $a;
|
||||
}
|
||||
|
||||
return min($max_ages);
|
||||
// If none or the values are Cache::PERMANENT, return the minimum value.
|
||||
return min($a, $b);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -10,6 +10,9 @@ namespace Drupal\Core\Cache;
|
|||
* Defines a generic class for passing cacheability metadata.
|
||||
*
|
||||
* @ingroup cache
|
||||
*
|
||||
* @todo Use RefinableCacheableDependencyInterface and the corresponding trait in
|
||||
* https://www.drupal.org/node/2526326.
|
||||
*/
|
||||
class CacheableMetadata implements CacheableDependencyInterface {
|
||||
|
||||
|
@ -129,6 +132,35 @@ class CacheableMetadata implements CacheableDependencyInterface {
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a dependency on an object: merges its cacheability metadata.
|
||||
*
|
||||
* @param \Drupal\Core\Cache\CacheableDependencyInterface|mixed $other_object
|
||||
* The dependency. If the object implements CacheableDependencyInterface,
|
||||
* then its cacheability metadata will be used. Otherwise, the passed in
|
||||
* object must be assumed to be uncacheable, so max-age 0 is set.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function addCacheableDependency($other_object) {
|
||||
if ($other_object instanceof CacheableDependencyInterface) {
|
||||
$this->addCacheTags($other_object->getCacheTags());
|
||||
$this->addCacheContexts($other_object->getCacheContexts());
|
||||
if ($this->maxAge === Cache::PERMANENT) {
|
||||
$this->maxAge = $other_object->getCacheMaxAge();
|
||||
}
|
||||
elseif (($max_age = $other_object->getCacheMaxAge()) && $max_age !== Cache::PERMANENT) {
|
||||
$this->maxAge = Cache::mergeMaxAges($this->maxAge, $max_age);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Not a cacheable dependency, this can not be cached.
|
||||
$this->maxAge = 0;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges the values of another CacheableMetadata object with this one.
|
||||
*
|
||||
|
@ -139,7 +171,7 @@ class CacheableMetadata implements CacheableDependencyInterface {
|
|||
* A new CacheableMetadata object, with the merged data.
|
||||
*/
|
||||
public function merge(CacheableMetadata $other) {
|
||||
$result = new static();
|
||||
$result = clone $this;
|
||||
|
||||
// This is called many times per request, so avoid merging unless absolutely
|
||||
// necessary.
|
||||
|
|
|
@ -7,18 +7,21 @@
|
|||
|
||||
namespace Drupal\Core\Cache\Context;
|
||||
|
||||
use Drupal\Core\Cache\CacheableMetadata;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\Core\Session\PermissionsHashGeneratorInterface;
|
||||
|
||||
/**
|
||||
* Defines the AccountPermissionsCacheContext service, for "per permission" caching.
|
||||
*
|
||||
* Cache context ID: 'user.permissions'.
|
||||
*/
|
||||
class AccountPermissionsCacheContext extends UserCacheContext {
|
||||
class AccountPermissionsCacheContext extends UserCacheContextBase implements CacheContextInterface {
|
||||
|
||||
/**
|
||||
* The permissions hash generator.
|
||||
*
|
||||
* @var \Drupal\user\PermissionsHashInterface
|
||||
* @var \Drupal\Core\Session\PermissionsHashGeneratorInterface
|
||||
*/
|
||||
protected $permissionsHashGenerator;
|
||||
|
||||
|
@ -27,7 +30,7 @@ class AccountPermissionsCacheContext extends UserCacheContext {
|
|||
*
|
||||
* @param \Drupal\Core\Session\AccountInterface $user
|
||||
* The current user.
|
||||
* @param \Drupal\user\PermissionsHashInterface $permissions_hash_generator
|
||||
* @param \Drupal\Core\Session\PermissionsHashGeneratorInterface $permissions_hash_generator
|
||||
* The permissions hash generator.
|
||||
*/
|
||||
public function __construct(AccountInterface $user, PermissionsHashGeneratorInterface $permissions_hash_generator) {
|
||||
|
@ -46,7 +49,24 @@ class AccountPermissionsCacheContext extends UserCacheContext {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function getContext() {
|
||||
return 'ph.' . $this->permissionsHashGenerator->generate($this->user);
|
||||
return $this->permissionsHashGenerator->generate($this->user);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheableMetadata() {
|
||||
$cacheable_metadata = new CacheableMetadata();
|
||||
|
||||
// The permissions hash changes when:
|
||||
// - a user is updated to have different roles;
|
||||
$tags = ['user:' . $this->user->id()];
|
||||
// - a role is updated to have different permissions.
|
||||
foreach ($this->user->getRoles() as $rid) {
|
||||
$tags[] = "config:user.role.$rid";
|
||||
}
|
||||
|
||||
return $cacheable_metadata->setCacheTags($tags);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -31,4 +31,21 @@ interface CacheContextInterface {
|
|||
*/
|
||||
public function getContext();
|
||||
|
||||
/**
|
||||
* Gets the cacheability metadata for the context.
|
||||
*
|
||||
* There are three valid cases for the returned CacheableMetadata object:
|
||||
* - An empty object means this can be optimized away safely.
|
||||
* - A max-age of 0 means that this context can never be optimized away. It
|
||||
* will never bubble up and cache tags will not be used.
|
||||
* - Any non-zero max-age and cache tags will bubble up into the cache item
|
||||
* if this is optimized away to allow for invalidation if the context
|
||||
* value changes.
|
||||
*
|
||||
*
|
||||
* @return \Drupal\Core\Cache\CacheableMetadata
|
||||
* A cacheable metadata object.
|
||||
*/
|
||||
public function getCacheableMetadata();
|
||||
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
namespace Drupal\Core\Cache\Context;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\Cache\CacheableMetadata;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
|
@ -99,23 +99,35 @@ class CacheContextsManager {
|
|||
* @param string[] $context_tokens
|
||||
* An array of cache context tokens.
|
||||
*
|
||||
* @return string[]
|
||||
* The array of corresponding cache keys.
|
||||
* @return \Drupal\Core\Cache\Context\ContextCacheKeys
|
||||
* The ContextCacheKeys object containing the converted cache keys and
|
||||
* cacheability metadata.
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
* @throws \LogicException
|
||||
* Thrown if any of the context tokens or parameters are not valid.
|
||||
*/
|
||||
public function convertTokensToKeys(array $context_tokens) {
|
||||
$context_tokens = $this->optimizeTokens($context_tokens);
|
||||
sort($context_tokens);
|
||||
$keys = [];
|
||||
foreach (static::parseTokens($context_tokens) as $context) {
|
||||
list($context_id, $parameter) = $context;
|
||||
if (!in_array($context_id, $this->contexts)) {
|
||||
throw new \InvalidArgumentException(SafeMarkup::format('"@context" is not a valid cache context ID.', ['@context' => $context_id]));
|
||||
}
|
||||
$keys[] = $this->getService($context_id)->getContext($parameter);
|
||||
$this->validateTokens($context_tokens);
|
||||
$cacheable_metadata = new CacheableMetadata();
|
||||
$optimized_tokens = $this->optimizeTokens($context_tokens);
|
||||
// Iterate over cache contexts that have been optimized away and get their
|
||||
// cacheability metadata.
|
||||
foreach (static::parseTokens(array_diff($context_tokens, $optimized_tokens)) as $context_token) {
|
||||
list($context_id, $parameter) = $context_token;
|
||||
$context = $this->getService($context_id);
|
||||
$cacheable_metadata = $cacheable_metadata->merge($context->getCacheableMetadata($parameter));
|
||||
}
|
||||
return $keys;
|
||||
|
||||
sort($optimized_tokens);
|
||||
$keys = [];
|
||||
foreach (array_combine($optimized_tokens, static::parseTokens($optimized_tokens)) as $context_token => $context) {
|
||||
list($context_id, $parameter) = $context;
|
||||
$keys[] = '[' . $context_token . ']=' . $this->getService($context_id)->getContext($parameter);
|
||||
}
|
||||
|
||||
// Create the returned object and merge in the cacheability metadata.
|
||||
$context_cache_keys = new ContextCacheKeys($keys);
|
||||
return $context_cache_keys->merge($cacheable_metadata);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -129,6 +141,9 @@ class CacheContextsManager {
|
|||
* possible of a set of cache context tokens, that still captures the entire
|
||||
* universe of variations.
|
||||
*
|
||||
* If a cache context is being optimized away, it is able to set cacheable
|
||||
* metadata for itself which will be bubbled up.
|
||||
*
|
||||
* E.g. when caching per user ('user'), also caching per role ('user.roles')
|
||||
* is meaningless because "per role" is implied by "per user".
|
||||
*
|
||||
|
@ -150,6 +165,14 @@ class CacheContextsManager {
|
|||
public function optimizeTokens(array $context_tokens) {
|
||||
$optimized_content_tokens = [];
|
||||
foreach ($context_tokens as $context_token) {
|
||||
|
||||
// Extract the parameter if available.
|
||||
$parameter = NULL;
|
||||
$context_id = $context_token;
|
||||
if (strpos($context_token, ':') !== FALSE) {
|
||||
list($context_id, $parameter) = explode(':', $context_token);
|
||||
}
|
||||
|
||||
// Context tokens without:
|
||||
// - a period means they don't have a parent
|
||||
// - a colon means they're not a specific value of a cache context
|
||||
|
@ -157,6 +180,11 @@ class CacheContextsManager {
|
|||
if (strpos($context_token, '.') === FALSE && strpos($context_token, ':') === FALSE) {
|
||||
$optimized_content_tokens[] = $context_token;
|
||||
}
|
||||
// Check cacheability. If the context defines a max-age of 0, then it
|
||||
// can not be optimized away. Pass the parameter along if we have one.
|
||||
elseif ($this->getService($context_id)->getCacheableMetadata($parameter)->getCacheMaxAge() === 0) {
|
||||
$optimized_content_tokens[] = $context_token;
|
||||
}
|
||||
// The context token has a period or a colon. Iterate over all ancestor
|
||||
// cache contexts. If one exists, omit the context token.
|
||||
else {
|
||||
|
|
|
@ -34,7 +34,32 @@ interface CalculatedCacheContextInterface {
|
|||
* @return string
|
||||
* The string representation of the cache context. When $parameter is NULL,
|
||||
* a value representing all possible parameters must be generated.
|
||||
*
|
||||
* @throws \LogicException
|
||||
* Thrown if the passed in parameter is invalid.
|
||||
*/
|
||||
public function getContext($parameter = NULL);
|
||||
|
||||
/**
|
||||
* Gets the cacheability metadata for the context based on the parameter value.
|
||||
*
|
||||
* There are three valid cases for the returned CacheableMetadata object:
|
||||
* - An empty object means this can be optimized away safely.
|
||||
* - A max-age of 0 means that this context can never be optimized away. It
|
||||
* will never bubble up and cache tags will not be used.
|
||||
* - Any non-zero max-age and cache tags will bubble up into the cache item
|
||||
* if this is optimized away to allow for invalidation if the context
|
||||
* value changes.
|
||||
*
|
||||
* @param string|null $parameter
|
||||
* The parameter, or NULL to indicate all possible parameter values.
|
||||
*
|
||||
* @return \Drupal\Core\Cache\CacheableMetadata
|
||||
* A cacheable metadata object.
|
||||
*
|
||||
* @throws \LogicException
|
||||
* Thrown if the passed in parameter is invalid.
|
||||
*/
|
||||
public function getCacheableMetadata($parameter = NULL);
|
||||
|
||||
}
|
||||
|
|
44
core/lib/Drupal/Core/Cache/Context/ContextCacheKeys.php
Normal file
44
core/lib/Drupal/Core/Cache/Context/ContextCacheKeys.php
Normal file
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Core\Cache\Context\ContextCacheKeys.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\Cache\Context;
|
||||
|
||||
use Drupal\Core\Cache\CacheableMetadata;
|
||||
|
||||
/**
|
||||
* A value object to store generated cache keys with its cacheability metadata.
|
||||
*/
|
||||
class ContextCacheKeys extends CacheableMetadata {
|
||||
|
||||
/**
|
||||
* The generated cache keys.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
protected $keys;
|
||||
|
||||
/**
|
||||
* Constructs a ContextCacheKeys object.
|
||||
*
|
||||
* @param string[] $keys
|
||||
* The cache context keys.
|
||||
*/
|
||||
public function __construct(array $keys) {
|
||||
$this->keys = $keys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the generated cache keys.
|
||||
*
|
||||
* @return string[]
|
||||
* The cache keys.
|
||||
*/
|
||||
public function getKeys() {
|
||||
return $this->keys;
|
||||
}
|
||||
|
||||
}
|
|
@ -7,8 +7,14 @@
|
|||
|
||||
namespace Drupal\Core\Cache\Context;
|
||||
|
||||
use Drupal\Core\Cache\CacheableMetadata;
|
||||
|
||||
/**
|
||||
* Defines the CookiesCacheContext service, for "per cookie" caching.
|
||||
*
|
||||
* Cache context ID: 'cookies' (to vary by all cookies).
|
||||
* Calculated cache context ID: 'cookies:%name', e.g. 'cookies:device_type' (to
|
||||
* vary by the 'device_type' cookie).
|
||||
*/
|
||||
class CookiesCacheContext extends RequestStackCacheContextBase implements CalculatedCacheContextInterface {
|
||||
|
||||
|
@ -31,4 +37,11 @@ class CookiesCacheContext extends RequestStackCacheContextBase implements Calcul
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheableMetadata($cookie = NULL) {
|
||||
return new CacheableMetadata();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,8 +7,14 @@
|
|||
|
||||
namespace Drupal\Core\Cache\Context;
|
||||
|
||||
use Drupal\Core\Cache\CacheableMetadata;
|
||||
|
||||
/**
|
||||
* Defines the HeadersCacheContext service, for "per header" caching.
|
||||
*
|
||||
* Cache context ID: 'headers' (to vary by all headers).
|
||||
* Calculated cache context ID: 'headers:%name', e.g. 'headers:X-Something' (to
|
||||
* vary by the 'X-Something' header).
|
||||
*/
|
||||
class HeadersCacheContext extends RequestStackCacheContextBase implements CalculatedCacheContextInterface {
|
||||
|
||||
|
@ -31,4 +37,11 @@ class HeadersCacheContext extends RequestStackCacheContextBase implements Calcul
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheableMetadata($header = NULL) {
|
||||
return new CacheableMetadata();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,10 +7,14 @@
|
|||
|
||||
namespace Drupal\Core\Cache\Context;
|
||||
|
||||
use Drupal\Core\Cache\CacheableMetadata;
|
||||
|
||||
/**
|
||||
* Defines the IpCacheContext service, for "per IP address" caching.
|
||||
*
|
||||
* Cache context ID: 'ip'.
|
||||
*/
|
||||
class IpCacheContext extends RequestStackCacheContextBase {
|
||||
class IpCacheContext extends RequestStackCacheContextBase implements CacheContextInterface {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
|
@ -26,4 +30,11 @@ class IpCacheContext extends RequestStackCacheContextBase {
|
|||
return $this->requestStack->getCurrentRequest()->getClientIp();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheableMetadata() {
|
||||
return new CacheableMetadata();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,10 +7,14 @@
|
|||
|
||||
namespace Drupal\Core\Cache\Context;
|
||||
|
||||
use Drupal\Core\Cache\CacheableMetadata;
|
||||
|
||||
/**
|
||||
* Defines the IsSuperUserCacheContext service, for "super user or not" caching.
|
||||
*
|
||||
* Cache context ID: 'user.is_super_user'.
|
||||
*/
|
||||
class IsSuperUserCacheContext extends UserCacheContext {
|
||||
class IsSuperUserCacheContext extends UserCacheContextBase implements CacheContextInterface {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
|
@ -26,4 +30,11 @@ class IsSuperUserCacheContext extends UserCacheContext {
|
|||
return ((int) $this->user->id()) === 1 ? '1' : '0';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheableMetadata() {
|
||||
return new CacheableMetadata();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
namespace Drupal\Core\Cache\Context;
|
||||
|
||||
use Drupal\Core\Cache\CacheableMetadata;
|
||||
use Drupal\Core\Language\LanguageManagerInterface;
|
||||
|
||||
/**
|
||||
|
@ -74,4 +75,11 @@ class LanguagesCacheContext implements CalculatedCacheContextInterface {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheableMetadata($type = NULL) {
|
||||
return new CacheableMetadata();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,12 +7,13 @@
|
|||
|
||||
namespace Drupal\Core\Cache\Context;
|
||||
|
||||
use Drupal\Core\Cache\CacheableMetadata;
|
||||
use Symfony\Component\DependencyInjection\ContainerAware;
|
||||
|
||||
/**
|
||||
* Defines the MenuActiveTrailsCacheContext service.
|
||||
*
|
||||
* This class is container-aware to avoid initializing the 'menu.active_trail'
|
||||
* This class is container-aware to avoid initializing the 'menu.active_trails'
|
||||
* service (and its dependencies) when it is not necessary.
|
||||
*/
|
||||
class MenuActiveTrailsCacheContext extends ContainerAware implements CalculatedCacheContextInterface {
|
||||
|
@ -28,9 +29,24 @@ class MenuActiveTrailsCacheContext extends ContainerAware implements CalculatedC
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function getContext($menu_name = NULL) {
|
||||
if (!$menu_name) {
|
||||
throw new \LogicException('No menu name provided for menu.active_trails cache context.');
|
||||
}
|
||||
|
||||
$active_trail = $this->container->get('menu.active_trail')
|
||||
->getActiveTrailIds($menu_name);
|
||||
return 'menu_trail.' . $menu_name . '|' . implode('|', $active_trail);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheableMetadata($menu_name = NULL) {
|
||||
if (!$menu_name) {
|
||||
throw new \LogicException('No menu name provided for menu.active_trails cache context.');
|
||||
}
|
||||
$cacheable_metadata = new CacheableMetadata();
|
||||
return $cacheable_metadata->setCacheTags(["config:system.menu.$menu_name"]);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,8 +7,14 @@
|
|||
|
||||
namespace Drupal\Core\Cache\Context;
|
||||
|
||||
use Drupal\Core\Cache\CacheableMetadata;
|
||||
|
||||
/**
|
||||
* Defines a cache context for "per page in a pager" caching.
|
||||
*
|
||||
* Cache context ID: 'url.query_args.pagers' (to vary by all pagers).
|
||||
* Calculated cache context ID: 'url.query_args.pagers:%pager_id', e.g.
|
||||
* 'url.query_args.pagers:1' (to vary by the pager with ID 1).
|
||||
*/
|
||||
class PagersCacheContext extends RequestStackCacheContextBase implements CalculatedCacheContextInterface {
|
||||
|
||||
|
@ -28,10 +34,17 @@ class PagersCacheContext extends RequestStackCacheContextBase implements Calcula
|
|||
// The value of the 'page' query argument contains the information that
|
||||
// controls *all* pagers.
|
||||
if ($pager_id === NULL) {
|
||||
return 'pager' . $this->requestStack->getCurrentRequest()->query->get('page', '');
|
||||
return $this->requestStack->getCurrentRequest()->query->get('page', '');
|
||||
}
|
||||
|
||||
return 'pager.' . $pager_id . '.' . pager_find_page($pager_id);
|
||||
return $pager_id . '.' . pager_find_page($pager_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheableMetadata($pager_id = NULL) {
|
||||
return new CacheableMetadata();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,12 +7,14 @@
|
|||
|
||||
namespace Drupal\Core\Cache\Context;
|
||||
|
||||
use Drupal\Core\Cache\CacheableMetadata;
|
||||
|
||||
/**
|
||||
* Defines the QueryArgsCacheContext service, for "per query args" caching.
|
||||
*
|
||||
* A "host" is defined as the combination of URI scheme, domain name and port.
|
||||
*
|
||||
* @see Symfony\Component\HttpFoundation::getSchemeAndHttpHost()
|
||||
* Cache context ID: 'url.query_args' (to vary by all query arguments).
|
||||
* Calculated cache context ID: 'url.query_args:%key', e.g.'url.query_args:foo'
|
||||
* (to vary by the 'foo' query argument).
|
||||
*/
|
||||
class QueryArgsCacheContext extends RequestStackCacheContextBase implements CalculatedCacheContextInterface {
|
||||
|
||||
|
@ -35,4 +37,11 @@ class QueryArgsCacheContext extends RequestStackCacheContextBase implements Calc
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheableMetadata($query_arg = NULL) {
|
||||
return new CacheableMetadata();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,8 +7,12 @@
|
|||
|
||||
namespace Drupal\Core\Cache\Context;
|
||||
|
||||
use Drupal\Core\Cache\CacheableMetadata;
|
||||
|
||||
/**
|
||||
* Defines the RequestFormatCacheContext service, for "per format" caching.
|
||||
*
|
||||
* Cache context ID: 'request_format'.
|
||||
*/
|
||||
class RequestFormatCacheContext extends RequestStackCacheContextBase {
|
||||
|
||||
|
@ -26,4 +30,11 @@ class RequestFormatCacheContext extends RequestStackCacheContextBase {
|
|||
return $this->requestStack->getCurrentRequest()->getRequestFormat();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheableMetadata() {
|
||||
return new CacheableMetadata();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -11,8 +11,12 @@ use Symfony\Component\HttpFoundation\RequestStack;
|
|||
|
||||
/**
|
||||
* Defines a base class for cache contexts depending only on the request stack.
|
||||
*
|
||||
* Subclasses need to implement either
|
||||
* \Drupal\Core\Cache\Context\CacheContextInterface or
|
||||
* \Drupal\Core\Cache\Context\CalculatedCacheContextInterface.
|
||||
*/
|
||||
abstract class RequestStackCacheContextBase implements CacheContextInterface {
|
||||
abstract class RequestStackCacheContextBase {
|
||||
|
||||
/**
|
||||
* The request stack.
|
||||
|
|
|
@ -7,10 +7,13 @@
|
|||
|
||||
namespace Drupal\Core\Cache\Context;
|
||||
|
||||
use Drupal\Core\Cache\CacheableMetadata;
|
||||
use Drupal\Core\Routing\RouteMatchInterface;
|
||||
|
||||
/**
|
||||
* Defines the RouteCacheContext service, for "per route" caching.
|
||||
*
|
||||
* Cache context ID: 'route'.
|
||||
*/
|
||||
class RouteCacheContext implements CacheContextInterface {
|
||||
|
||||
|
@ -45,4 +48,11 @@ class RouteCacheContext implements CacheContextInterface {
|
|||
return $this->routeMatch->getRouteName() . hash('sha256', serialize($this->routeMatch->getRawParameters()->all()));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheableMetadata() {
|
||||
return new CacheableMetadata();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -9,6 +9,8 @@ namespace Drupal\Core\Cache\Context;
|
|||
|
||||
/**
|
||||
* Defines the RouteCacheContext service, for "per route name" caching.
|
||||
*
|
||||
* Cache context ID: 'route.name'.
|
||||
*/
|
||||
class RouteNameCacheContext extends RouteCacheContext {
|
||||
|
||||
|
|
31
core/lib/Drupal/Core/Cache/Context/SessionCacheContext.php
Normal file
31
core/lib/Drupal/Core/Cache/Context/SessionCacheContext.php
Normal file
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Core\Cache\Context\SessionCacheContext.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\Cache\Context;
|
||||
|
||||
/**
|
||||
* Defines the SessionCacheContext service, for "per session" caching.
|
||||
*
|
||||
* Cache context ID: 'session'.
|
||||
*/
|
||||
class SessionCacheContext extends RequestStackCacheContextBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getLabel() {
|
||||
return t('Session');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getContext() {
|
||||
return $this->requestStack->getCurrentRequest()->getSession()->getId();
|
||||
}
|
||||
|
||||
}
|
|
@ -7,9 +7,13 @@
|
|||
|
||||
namespace Drupal\Core\Cache\Context;
|
||||
|
||||
use Drupal\Core\Cache\CacheableMetadata;
|
||||
|
||||
/**
|
||||
* Defines the SiteCacheContext service, for "per site" caching.
|
||||
*
|
||||
* Cache context ID: 'site'.
|
||||
*
|
||||
* A "site" is defined as the combination of URI scheme, domain name, port and
|
||||
* base path. It allows for varying between the *same* site being accessed via
|
||||
* different entry points. (Different sites in a multisite setup have separate
|
||||
|
@ -18,7 +22,7 @@ namespace Drupal\Core\Cache\Context;
|
|||
* @see \Symfony\Component\HttpFoundation\Request::getSchemeAndHttpHost()
|
||||
* @see \Symfony\Component\HttpFoundation\Request::getBaseUrl()
|
||||
*/
|
||||
class SiteCacheContext extends RequestStackCacheContextBase {
|
||||
class SiteCacheContext extends RequestStackCacheContextBase implements CacheContextInterface {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
|
@ -35,4 +39,11 @@ class SiteCacheContext extends RequestStackCacheContextBase {
|
|||
return $request->getSchemeAndHttpHost() . $request->getBaseUrl();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheableMetadata() {
|
||||
return new CacheableMetadata();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,11 +7,13 @@
|
|||
|
||||
namespace Drupal\Core\Cache\Context;
|
||||
|
||||
use Drupal\Core\Routing\RouteMatchInterface;
|
||||
use Drupal\Core\Cache\CacheableMetadata;
|
||||
use Drupal\Core\Theme\ThemeManagerInterface;
|
||||
|
||||
/**
|
||||
* Defines the ThemeCacheContext service, for "per theme" caching.
|
||||
*
|
||||
* Cache context ID: 'theme'.
|
||||
*/
|
||||
class ThemeCacheContext implements CacheContextInterface {
|
||||
|
||||
|
@ -46,4 +48,11 @@ class ThemeCacheContext implements CacheContextInterface {
|
|||
return $this->themeManager->getActiveTheme()->getName() ?: 'stark';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheableMetadata() {
|
||||
return new CacheableMetadata();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,9 +7,13 @@
|
|||
|
||||
namespace Drupal\Core\Cache\Context;
|
||||
|
||||
use Drupal\Core\Cache\CacheableMetadata;
|
||||
|
||||
/**
|
||||
* Defines the TimeZoneCacheContext service, for "per time zone" caching.
|
||||
*
|
||||
* Cache context ID: 'timezone'.
|
||||
*
|
||||
* @see \Drupal\Core\Session\AccountProxy::setAccount()
|
||||
*/
|
||||
class TimeZoneCacheContext implements CacheContextInterface {
|
||||
|
@ -30,4 +34,11 @@ class TimeZoneCacheContext implements CacheContextInterface {
|
|||
return date_default_timezone_get();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheableMetadata() {
|
||||
return new CacheableMetadata();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,10 +7,14 @@
|
|||
|
||||
namespace Drupal\Core\Cache\Context;
|
||||
|
||||
use Drupal\Core\Cache\CacheableMetadata;
|
||||
|
||||
/**
|
||||
* Defines the UrlCacheContext service, for "per page" caching.
|
||||
*
|
||||
* Cache context ID: 'url'.
|
||||
*/
|
||||
class UrlCacheContext extends RequestStackCacheContextBase {
|
||||
class UrlCacheContext extends RequestStackCacheContextBase implements CacheContextInterface {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
|
@ -26,4 +30,11 @@ class UrlCacheContext extends RequestStackCacheContextBase {
|
|||
return $this->requestStack->getCurrentRequest()->getUri();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheableMetadata() {
|
||||
return new CacheableMetadata();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,22 +7,14 @@
|
|||
|
||||
namespace Drupal\Core\Cache\Context;
|
||||
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\Core\Cache\CacheableMetadata;
|
||||
|
||||
/**
|
||||
* Defines the UserCacheContext service, for "per user" caching.
|
||||
*
|
||||
* Cache context ID: 'user'.
|
||||
*/
|
||||
class UserCacheContext implements CacheContextInterface {
|
||||
|
||||
/**
|
||||
* Constructs a new UserCacheContext service.
|
||||
*
|
||||
* @param \Drupal\Core\Session\AccountInterface $user
|
||||
* The current user.
|
||||
*/
|
||||
public function __construct(AccountInterface $user) {
|
||||
$this->user = $user;
|
||||
}
|
||||
class UserCacheContext extends UserCacheContextBase implements CacheContextInterface {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
|
@ -35,7 +27,14 @@ class UserCacheContext implements CacheContextInterface {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function getContext() {
|
||||
return "u." . $this->user->id();
|
||||
return $this->user->id();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheableMetadata() {
|
||||
return new CacheableMetadata();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
38
core/lib/Drupal/Core/Cache/Context/UserCacheContextBase.php
Normal file
38
core/lib/Drupal/Core/Cache/Context/UserCacheContextBase.php
Normal file
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Core\Cache\Context\UserCacheContextBase.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\Cache\Context;
|
||||
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
|
||||
/**
|
||||
* Base class for user-based cache contexts.
|
||||
*
|
||||
* Subclasses need to implement either
|
||||
* \Drupal\Core\Cache\Context\CacheContextInterface or
|
||||
* \Drupal\Core\Cache\Context\CalculatedCacheContextInterface.
|
||||
*/
|
||||
abstract class UserCacheContextBase {
|
||||
|
||||
/**
|
||||
* The account object.
|
||||
*
|
||||
* @var \Drupal\Core\Session\AccountInterface
|
||||
*/
|
||||
protected $user;
|
||||
|
||||
/**
|
||||
* Constructs a new UserCacheContextBase class.
|
||||
*
|
||||
* @param \Drupal\Core\Session\AccountInterface $user
|
||||
* The current user.
|
||||
*/
|
||||
public function __construct(AccountInterface $user) {
|
||||
$this->user = $user;
|
||||
}
|
||||
|
||||
}
|
|
@ -7,13 +7,19 @@
|
|||
|
||||
namespace Drupal\Core\Cache\Context;
|
||||
|
||||
use Drupal\Core\Cache\CacheableMetadata;
|
||||
|
||||
/**
|
||||
* Defines the UserRolesCacheContext service, for "per role" caching.
|
||||
*
|
||||
* Only use this cache context when checking explicitly for certain roles. Use
|
||||
* user.permissions for anything that checks permissions.
|
||||
*
|
||||
* Cache context ID: 'user.roles' (to vary by all roles of the current user).
|
||||
* Calculated cache context ID: 'user.roles:%role', e.g. 'user.roles:anonymous'
|
||||
* (to vary by the presence/absence of a specific role).
|
||||
*/
|
||||
class UserRolesCacheContext extends UserCacheContext implements CalculatedCacheContextInterface{
|
||||
class UserRolesCacheContext extends UserCacheContextBase implements CalculatedCacheContextInterface {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
|
@ -34,11 +40,18 @@ class UserRolesCacheContext extends UserCacheContext implements CalculatedCacheC
|
|||
return 'is-super-user';
|
||||
}
|
||||
if ($role === NULL) {
|
||||
return 'r.' . implode(',', $this->user->getRoles());
|
||||
return implode(',', $this->user->getRoles());
|
||||
}
|
||||
else {
|
||||
return 'r.' . $role . '.' . (in_array($role, $this->user->getRoles()) ? '0' : '1');
|
||||
return (in_array($role, $this->user->getRoles()) ? '0' : '1');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheableMetadata($role = NULL) {
|
||||
return (new CacheableMetadata())->setCacheTags(['user:' . $this->user->id()]);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Core\Cache\RefinableCacheableDependencyInterface.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\Cache;
|
||||
|
||||
/**
|
||||
* Allows to add cacheability metadata to an object for the current runtime.
|
||||
*
|
||||
* This must be used when changing an object in a way that affects its
|
||||
* cacheability. For example, when changing the active translation of an entity
|
||||
* based on the current content language then a cache context for that must be
|
||||
* added.
|
||||
*/
|
||||
interface RefinableCacheableDependencyInterface extends CacheableDependencyInterface {
|
||||
|
||||
/**
|
||||
* Adds cache contexts.
|
||||
*
|
||||
* @param string[] $cache_contexts
|
||||
* The cache contexts to be added.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function addCacheContexts(array $cache_contexts);
|
||||
|
||||
/**
|
||||
* Adds cache tags.
|
||||
*
|
||||
* @param string[] $cache_tags
|
||||
* The cache tags to be added.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function addCacheTags(array $cache_tags);
|
||||
|
||||
/**
|
||||
* Merges the maximum age (in seconds) with the existing maximum age.
|
||||
*
|
||||
* The max age will be set to the given value if it is lower than the existing
|
||||
* value.
|
||||
*
|
||||
* @param int $max_age
|
||||
* The max age to associate.
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
* Thrown if a non-integer value is supplied.
|
||||
*/
|
||||
public function mergeCacheMaxAge($max_age);
|
||||
|
||||
/**
|
||||
* Adds a dependency on an object: merges its cacheability metadata.
|
||||
*
|
||||
* @param \Drupal\Core\Cache\CacheableDependencyInterface|object $other_object
|
||||
* The dependency. If the object implements CacheableDependencyInterface,
|
||||
* then its cacheability metadata will be used. Otherwise, the passed in
|
||||
* object must be assumed to be uncacheable, so max-age 0 is set.
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @see \Drupal\Core\Cache\CacheableMetadata::createFromObject()
|
||||
*/
|
||||
public function addCacheableDependency($other_object);
|
||||
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Core\Cache\RefinableCacheableDependencyTrait.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\Cache;
|
||||
|
||||
/**
|
||||
* Trait for \Drupal\Core\Cache\RefinableCacheableDependencyInterface.
|
||||
*/
|
||||
trait RefinableCacheableDependencyTrait {
|
||||
|
||||
/**
|
||||
* Cache contexts.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
protected $cacheContexts = [];
|
||||
|
||||
/**
|
||||
* Cache tags.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
protected $cacheTags = [];
|
||||
|
||||
/**
|
||||
* Cache max-age.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $cacheMaxAge = Cache::PERMANENT;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function addCacheableDependency($other_object) {
|
||||
if ($other_object instanceof CacheableDependencyInterface) {
|
||||
$this->addCacheContexts($other_object->getCacheContexts());
|
||||
$this->addCacheTags($other_object->getCacheTags());
|
||||
$this->mergeCacheMaxAge($other_object->getCacheMaxAge());
|
||||
}
|
||||
else {
|
||||
// Not a cacheable dependency, this can not be cached.
|
||||
$this->maxAge = 0;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function addCacheContexts(array $cache_contexts) {
|
||||
$this->cacheContexts = Cache::mergeContexts($this->cacheContexts, $cache_contexts);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function addCacheTags(array $cache_tags) {
|
||||
$this->cacheTags = Cache::mergeTags($this->cacheTags, $cache_tags);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function mergeCacheMaxAge($max_age) {
|
||||
$this->cacheMaxAge = Cache::mergeMaxAges($this->cacheMaxAge, $max_age);
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
|
@ -220,6 +220,9 @@ class DbDumpCommand extends Command {
|
|||
// Set primary key, unique keys, and indexes.
|
||||
$this->getTableIndexes($table, $definition);
|
||||
|
||||
// Set table collation.
|
||||
$this->getTableCollation($table, $definition);
|
||||
|
||||
return $definition;
|
||||
}
|
||||
|
||||
|
@ -235,7 +238,6 @@ class DbDumpCommand extends Command {
|
|||
// Note, this query doesn't support ordering, so that is worked around
|
||||
// below by keying the array on Seq_in_index.
|
||||
$query = $this->connection->query("SHOW INDEX FROM {" . $table . "}");
|
||||
$indexes = [];
|
||||
while (($row = $query->fetchAssoc()) !== FALSE) {
|
||||
$index_name = $row['Key_name'];
|
||||
$column = $row['Column_name'];
|
||||
|
@ -259,6 +261,22 @@ class DbDumpCommand extends Command {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the table collation.
|
||||
*
|
||||
* @param string $table
|
||||
* The table to find indexes for.
|
||||
* @param array &$definition
|
||||
* The schema definition to modify.
|
||||
*/
|
||||
protected function getTableCollation($table, &$definition) {
|
||||
$query = $this->connection->query("SHOW TABLE STATUS LIKE '{" . $table . "}'");
|
||||
$data = $query->fetchAssoc();
|
||||
|
||||
// Set `mysql_character_set`. This will be ignored by other backends.
|
||||
$definition['mysql_character_set'] = str_replace('_general_ci', '', $data['Collation']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all data from a given table.
|
||||
*
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Core\Command\GenerateProxyClassApplication.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\Command;
|
||||
|
||||
use Drupal\Component\ProxyBuilder\ProxyBuilder;
|
||||
use Symfony\Component\Console\Application;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
|
||||
/**
|
||||
* Provides a console command to generate proxy classes.
|
||||
*/
|
||||
class GenerateProxyClassApplication extends Application {
|
||||
|
||||
/**
|
||||
* The proxy builder.
|
||||
*
|
||||
* @var \Drupal\Component\ProxyBuilder\ProxyBuilder
|
||||
*/
|
||||
protected $proxyBuilder;
|
||||
|
||||
/**
|
||||
* Constructs a new GenerateProxyClassApplication instance.
|
||||
*
|
||||
* @param \Drupal\Component\ProxyBuilder\ProxyBuilder $proxy_builder
|
||||
* The proxy builder.
|
||||
*/
|
||||
public function __construct(ProxyBuilder $proxy_builder) {
|
||||
$this->proxyBuilder = $proxy_builder;
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getCommandName(InputInterface $input) {
|
||||
return 'generate-proxy-class';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getDefaultCommands() {
|
||||
// Even though this is a single command, keep the HelpCommand (--help).
|
||||
$default_commands = parent::getDefaultCommands();
|
||||
$default_commands[] = new GenerateProxyClassCommand($this->proxyBuilder);
|
||||
return $default_commands;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* Overridden so the application doesn't expect the command name as the first
|
||||
* argument.
|
||||
*/
|
||||
public function getDefinition() {
|
||||
$definition = parent::getDefinition();
|
||||
// Clears the normal first argument (the command name).
|
||||
$definition->setArguments();
|
||||
return $definition;
|
||||
}
|
||||
|
||||
}
|
97
core/lib/Drupal/Core/Command/GenerateProxyClassCommand.php
Normal file
97
core/lib/Drupal/Core/Command/GenerateProxyClassCommand.php
Normal file
|
@ -0,0 +1,97 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Core\Command\GenerateProxyClassCommand.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\Command;
|
||||
|
||||
use Drupal\Component\ProxyBuilder\ProxyBuilder;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Provides a console command to generate proxy classes.
|
||||
*/
|
||||
class GenerateProxyClassCommand extends Command {
|
||||
|
||||
/**
|
||||
* The proxy builder.
|
||||
*
|
||||
* @var \Drupal\Component\ProxyBuilder\ProxyBuilder
|
||||
*/
|
||||
protected $proxyBuilder;
|
||||
|
||||
/**
|
||||
* Constructs a new GenerateProxyClassCommand instance.
|
||||
*
|
||||
* @param \Drupal\Component\ProxyBuilder\ProxyBuilder $proxy_builder
|
||||
* The proxy builder.
|
||||
*/
|
||||
public function __construct(ProxyBuilder $proxy_builder) {
|
||||
parent::__construct();
|
||||
|
||||
$this->proxyBuilder = $proxy_builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure() {
|
||||
$this->setName('generate-proxy-class')
|
||||
->setDefinition([
|
||||
new InputArgument('class_name', InputArgument::REQUIRED, 'The class to be proxied'),
|
||||
new InputArgument('namespace_root_path', InputArgument::REQUIRED, 'The filepath to the root of the namespace.'),
|
||||
])
|
||||
->setDescription('Dumps a generated proxy class into its appropriate namespace.')
|
||||
->addUsage('\'Drupal\Core\Batch\BatchStorage\' "core/lib/Drupal/Core"')
|
||||
->addUsage('\'Drupal\block\BlockRepository\' "core/modules/block/src"')
|
||||
->addUsage('\'Drupal\mymodule\MyClass\' "modules/contrib/mymodule/src"');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output) {
|
||||
$class_name = ltrim($input->getArgument('class_name'), '\\');
|
||||
$namespace_root = $input->getArgument('namespace_root_path');
|
||||
|
||||
$match = [];
|
||||
preg_match('/([a-zA-Z0-9_]+\\\\[a-zA-Z0-9_]+)\\\\(.+)/', $class_name, $match);
|
||||
|
||||
if ($match) {
|
||||
$root_namespace = $match[1];
|
||||
$rest_fqcn = $match[2];
|
||||
|
||||
$proxy_filename = $namespace_root . '/ProxyClass/' . str_replace('\\', '/', $rest_fqcn) . '.php';
|
||||
$proxy_class_name = $root_namespace . '\\ProxyClass\\' . $rest_fqcn;
|
||||
|
||||
$proxy_class_string = $this->proxyBuilder->build($class_name);
|
||||
|
||||
$file_string = <<<EOF
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \{{ proxy_class_name }}.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This file was generated via php core/scripts/generate-proxy-class.php '$class_name' "$namespace_root".
|
||||
*/
|
||||
{{ proxy_class_string }}
|
||||
EOF;
|
||||
$file_string = str_replace(['{{ proxy_class_name }}', '{{ proxy_class_string }}'], [$proxy_class_name, $proxy_class_string], $file_string);
|
||||
|
||||
mkdir(dirname($proxy_filename), 0775, TRUE);
|
||||
file_put_contents($proxy_filename, $file_string);
|
||||
|
||||
$output->writeln(sprintf('Proxy of class %s written to %s', $class_name, $proxy_filename));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -9,6 +9,7 @@ namespace Drupal\Core\Condition;
|
|||
|
||||
use Drupal\Component\Plugin\ConfigurablePluginInterface;
|
||||
use Drupal\Component\Plugin\PluginInspectionInterface;
|
||||
use Drupal\Core\Cache\CacheableDependencyInterface;
|
||||
use Drupal\Core\Executable\ExecutableInterface;
|
||||
use Drupal\Core\Executable\ExecutableManagerInterface;
|
||||
use Drupal\Core\Plugin\PluginFormInterface;
|
||||
|
@ -46,12 +47,12 @@ use Drupal\Core\Plugin\PluginFormInterface;
|
|||
*
|
||||
* @ingroup plugin_api
|
||||
*/
|
||||
interface ConditionInterface extends ExecutableInterface, PluginFormInterface, ConfigurablePluginInterface, PluginInspectionInterface {
|
||||
interface ConditionInterface extends ExecutableInterface, PluginFormInterface, ConfigurablePluginInterface, PluginInspectionInterface, CacheableDependencyInterface {
|
||||
|
||||
/**
|
||||
* Determines whether condition result will be negated.
|
||||
*
|
||||
* @return boolean
|
||||
* @return bool
|
||||
* Whether the condition result will be negated.
|
||||
*/
|
||||
public function isNegated();
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
namespace Drupal\Core\Condition;
|
||||
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\Cache\CacheableDependencyInterface;
|
||||
use Drupal\Core\Executable\ExecutableManagerInterface;
|
||||
use Drupal\Core\Executable\ExecutablePluginBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
|
|
|
@ -8,9 +8,9 @@
|
|||
namespace Drupal\Core\Config;
|
||||
|
||||
use Drupal\Component\Utility\NestedArray;
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\Cache\CacheableDependencyInterface;
|
||||
use Drupal\Core\Cache\RefinableCacheableDependencyInterface;
|
||||
use Drupal\Core\Cache\RefinableCacheableDependencyTrait;
|
||||
use \Drupal\Core\DependencyInjection\DependencySerializationTrait;
|
||||
|
||||
/**
|
||||
|
@ -28,8 +28,9 @@ use \Drupal\Core\DependencyInjection\DependencySerializationTrait;
|
|||
* @see \Drupal\Core\Config\Config
|
||||
* @see \Drupal\Core\Theme\ThemeSettings
|
||||
*/
|
||||
abstract class ConfigBase implements CacheableDependencyInterface {
|
||||
abstract class ConfigBase implements RefinableCacheableDependencyInterface {
|
||||
use DependencySerializationTrait;
|
||||
use RefinableCacheableDependencyTrait;
|
||||
|
||||
/**
|
||||
* The name of the configuration object.
|
||||
|
@ -97,24 +98,17 @@ abstract class ConfigBase implements CacheableDependencyInterface {
|
|||
public static function validateName($name) {
|
||||
// The name must be namespaced by owner.
|
||||
if (strpos($name, '.') === FALSE) {
|
||||
throw new ConfigNameException(SafeMarkup::format('Missing namespace in Config object name @name.', array(
|
||||
'@name' => $name,
|
||||
)));
|
||||
throw new ConfigNameException("Missing namespace in Config object name $name.");
|
||||
}
|
||||
// The name must be shorter than Config::MAX_NAME_LENGTH characters.
|
||||
if (strlen($name) > self::MAX_NAME_LENGTH) {
|
||||
throw new ConfigNameException(SafeMarkup::format('Config object name @name exceeds maximum allowed length of @length characters.', array(
|
||||
'@name' => $name,
|
||||
'@length' => self::MAX_NAME_LENGTH,
|
||||
)));
|
||||
throw new ConfigNameException("Config object name $name exceeds maximum allowed length of " . static::MAX_NAME_LENGTH . " characters.");
|
||||
}
|
||||
|
||||
// The name must not contain any of the following characters:
|
||||
// : ? * < > " ' / \
|
||||
if (preg_match('/[:?*<>"\'\/\\\\]/', $name)) {
|
||||
throw new ConfigNameException(SafeMarkup::format('Invalid character in Config object name @name.', array(
|
||||
'@name' => $name,
|
||||
)));
|
||||
throw new ConfigNameException("Invalid character in Config object name $name.");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -222,7 +216,7 @@ abstract class ConfigBase implements CacheableDependencyInterface {
|
|||
protected function validateKeys(array $data) {
|
||||
foreach ($data as $key => $value) {
|
||||
if (strpos($key, '.') !== FALSE) {
|
||||
throw new ConfigValueException(SafeMarkup::format('@key key contains a dot which is not supported.', array('@key' => $key)));
|
||||
throw new ConfigValueException("$key key contains a dot which is not supported.");
|
||||
}
|
||||
if (is_array($value)) {
|
||||
$this->validateKeys($value);
|
||||
|
@ -269,21 +263,21 @@ abstract class ConfigBase implements CacheableDependencyInterface {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheContexts() {
|
||||
return [];
|
||||
return $this->cacheContexts;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheTags() {
|
||||
return ['config:' . $this->name];
|
||||
return Cache::mergeTags(['config:' . $this->name], $this->cacheTags);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheMaxAge() {
|
||||
return Cache::PERMANENT;
|
||||
return $this->cacheMaxAge;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -21,11 +21,16 @@ final class ConfigEvents {
|
|||
* object is saved. The event listener method receives a
|
||||
* \Drupal\Core\Config\ConfigCrudEvent instance.
|
||||
*
|
||||
* See hook_update_N() documentation for safe configuration API usage and
|
||||
* restrictions as this event will be fired when configuration is saved by
|
||||
* hook_update_N().
|
||||
*
|
||||
* @Event
|
||||
*
|
||||
* @see \Drupal\Core\Config\ConfigCrudEvent
|
||||
* @see \Drupal\Core\Config\Config::save()
|
||||
* @see \Drupal\Core\Config\ConfigFactory::onConfigSave()
|
||||
* @see hook_update_N()
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
|
@ -38,11 +43,16 @@ final class ConfigEvents {
|
|||
* object is deleted. The event listener method receives a
|
||||
* \Drupal\Core\Config\ConfigCrudEvent instance.
|
||||
*
|
||||
* See hook_update_N() documentation for safe configuration API usage and
|
||||
* restrictions as this event will be fired when configuration is deleted by
|
||||
* hook_update_N().
|
||||
*
|
||||
* @Event
|
||||
*
|
||||
* @see \Drupal\Core\Config\ConfigCrudEvent
|
||||
* @see \Drupal\Core\Config\Config::delete()
|
||||
* @see \Drupal\Core\Config\ConfigFactory::onConfigDelete()
|
||||
* @see hook_update_N()
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
|
@ -55,10 +65,15 @@ final class ConfigEvents {
|
|||
* object's name is changed. The event listener method receives a
|
||||
* \Drupal\Core\Config\ConfigRenameEvent instance.
|
||||
*
|
||||
* See hook_update_N() documentation for safe configuration API usage and
|
||||
* restrictions as this event will be fired when configuration is renamed by
|
||||
* hook_update_N().
|
||||
*
|
||||
* @Event
|
||||
*
|
||||
* @see \Drupal\Core\Config\ConfigRenameEvent
|
||||
* @see \Drupal\Core\Config\ConfigFactoryInterface::rename().
|
||||
* @see \Drupal\Core\Config\ConfigFactoryInterface::rename()
|
||||
* @see hook_update_N()
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
|
|
|
@ -126,6 +126,9 @@ class ConfigFactory implements ConfigFactoryInterface, EventSubscriberInterface
|
|||
$this->cache[$cache_key]->setSettingsOverride($GLOBALS['config'][$name]);
|
||||
}
|
||||
}
|
||||
|
||||
$this->propagateConfigOverrideCacheability($cache_key, $name);
|
||||
|
||||
return $this->cache[$cache_key];
|
||||
}
|
||||
}
|
||||
|
@ -183,6 +186,9 @@ class ConfigFactory implements ConfigFactoryInterface, EventSubscriberInterface
|
|||
$this->cache[$cache_key]->setSettingsOverride($GLOBALS['config'][$name]);
|
||||
}
|
||||
}
|
||||
|
||||
$this->propagateConfigOverrideCacheability($cache_key, $name);
|
||||
|
||||
$list[$name] = $this->cache[$cache_key];
|
||||
}
|
||||
}
|
||||
|
@ -209,6 +215,20 @@ class ConfigFactory implements ConfigFactoryInterface, EventSubscriberInterface
|
|||
return $overrides;
|
||||
}
|
||||
|
||||
/**
|
||||
* Propagates cacheability of config overrides to cached config objects.
|
||||
*
|
||||
* @param string $cache_key
|
||||
* The key of the cached config object to update.
|
||||
* @param string $name
|
||||
* The name of the configuration object to construct.
|
||||
*/
|
||||
protected function propagateConfigOverrideCacheability($cache_key, $name) {
|
||||
foreach ($this->configFactoryOverrides as $override) {
|
||||
$this->cache[$cache_key]->addCacheableDependency($override->getCacheableMetadata($name));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
|
@ -74,7 +74,7 @@ abstract class ConfigFactoryOverrideBase implements EventSubscriberInterface {
|
|||
}
|
||||
elseif ($changed) {
|
||||
// Otherwise set the filtered override values back.
|
||||
$override->setData($override_data)->save();
|
||||
$override->setData($override_data)->save(TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -58,4 +58,15 @@ interface ConfigFactoryOverrideInterface {
|
|||
*/
|
||||
public function createConfigObject($name, $collection = StorageInterface::DEFAULT_COLLECTION);
|
||||
|
||||
/**
|
||||
* Gets the cacheability metadata associated with the config factory override.
|
||||
*
|
||||
* @param string $name
|
||||
* The name of the configuration override to get metadata for.
|
||||
*
|
||||
* @return \Drupal\Core\Cache\CacheableMetadata
|
||||
* A cacheable metadata object.
|
||||
*/
|
||||
public function getCacheableMetadata($name);
|
||||
|
||||
}
|
||||
|
|
|
@ -11,7 +11,6 @@ use Drupal\Core\Config\Importer\MissingContentEvent;
|
|||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\Extension\ModuleInstallerInterface;
|
||||
use Drupal\Core\Extension\ThemeHandlerInterface;
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\Config\Entity\ImportableEntityStorageInterface;
|
||||
use Drupal\Core\DependencyInjection\DependencySerializationTrait;
|
||||
use Drupal\Core\Entity\EntityStorageException;
|
||||
|
@ -763,7 +762,7 @@ class ConfigImporter {
|
|||
}
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
$this->logError($this->t('Unexpected error during import with operation @op for @name: @message', array('@op' => $op, '@name' => $name, '@message' => $e->getMessage())));
|
||||
$this->logError($this->t('Unexpected error during import with operation @op for @name: !message', array('@op' => $op, '@name' => $name, '!message' => $e->getMessage())));
|
||||
// Error for that operation was logged, mark it as processed so that
|
||||
// the import can continue.
|
||||
$this->setProcessedConfiguration($collection, $op, $name);
|
||||
|
@ -972,7 +971,7 @@ class ConfigImporter {
|
|||
// Call to the configuration entity's storage to handle the configuration
|
||||
// change.
|
||||
if (!($entity_storage instanceof ImportableEntityStorageInterface)) {
|
||||
throw new EntityStorageException(SafeMarkup::format('The entity storage "@storage" for the "@entity_type" entity type does not support imports', array('@storage' => get_class($entity_storage), '@entity_type' => $entity_type)));
|
||||
throw new EntityStorageException(sprintf('The entity storage "%s" for the "%s" entity type does not support imports', get_class($entity_storage), $entity_type));
|
||||
}
|
||||
$entity_storage->$method($name, $new_config, $old_config);
|
||||
$this->setProcessedConfiguration($collection, $op, $name);
|
||||
|
@ -1018,7 +1017,7 @@ class ConfigImporter {
|
|||
// Call to the configuration entity's storage to handle the configuration
|
||||
// change.
|
||||
if (!($entity_storage instanceof ImportableEntityStorageInterface)) {
|
||||
throw new EntityStorageException(SafeMarkup::format('The entity storage "@storage" for the "@entity_type" entity type does not support imports', array('@storage' => get_class($entity_storage), '@entity_type' => $entity_type_id)));
|
||||
throw new EntityStorageException(sprintf("The entity storage '%s' for the '%s' entity type does not support imports", get_class($entity_storage), $entity_type_id));
|
||||
}
|
||||
$entity_storage->importRename($names['old_name'], $new_config, $old_config);
|
||||
$this->setProcessedConfiguration($collection, 'rename', $rename_name);
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
namespace Drupal\Core\Config\Entity;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\Config\ConfigException;
|
||||
use Drupal\Core\Config\Schema\SchemaIncompleteException;
|
||||
|
@ -192,8 +191,6 @@ abstract class ConfigEntityBase extends Entity implements ConfigEntityInterface
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function disable() {
|
||||
// An entity was disabled, invalidate its own cache tag.
|
||||
Cache::invalidateTags($this->getCacheTags());
|
||||
return $this->setStatus(FALSE);
|
||||
}
|
||||
|
||||
|
@ -280,7 +277,7 @@ abstract class ConfigEntityBase extends Entity implements ConfigEntityInterface
|
|||
$config_name = $entity_type->getConfigPrefix() . '.' . $this->id();
|
||||
$definition = $this->getTypedConfig()->getDefinition($config_name);
|
||||
if (!isset($definition['mapping'])) {
|
||||
throw new SchemaIncompleteException(SafeMarkup::format('Incomplete or missing schema for @config_name', array('@config_name' => $config_name)));
|
||||
throw new SchemaIncompleteException("Incomplete or missing schema for $config_name");
|
||||
}
|
||||
$properties_to_export = array_combine(array_keys($definition['mapping']), array_keys($definition['mapping']));
|
||||
}
|
||||
|
@ -333,7 +330,7 @@ abstract class ConfigEntityBase extends Entity implements ConfigEntityInterface
|
|||
->execute();
|
||||
$matched_entity = reset($matching_entities);
|
||||
if (!empty($matched_entity) && ($matched_entity != $this->id()) && $matched_entity != $this->getOriginalId()) {
|
||||
throw new ConfigDuplicateUUIDException(SafeMarkup::format('Attempt to save a configuration entity %id with UUID %uuid when this UUID is already used for %matched', array('%id' => $this->id(), '%uuid' => $this->uuid(), '%matched' => $matched_entity)));
|
||||
throw new ConfigDuplicateUUIDException("Attempt to save a configuration entity '{$this->id()}' with UUID '{$this->uuid()}' when this UUID is already used for '$matched_entity'");
|
||||
}
|
||||
|
||||
// If this entity is not new, load the original entity for comparison.
|
||||
|
@ -341,7 +338,7 @@ abstract class ConfigEntityBase extends Entity implements ConfigEntityInterface
|
|||
$original = $storage->loadUnchanged($this->getOriginalId());
|
||||
// Ensure that the UUID cannot be changed for an existing entity.
|
||||
if ($original && ($original->uuid() != $this->uuid())) {
|
||||
throw new ConfigDuplicateUUIDException(SafeMarkup::format('Attempt to save a configuration entity %id with UUID %uuid when this entity already exists with UUID %original_uuid', array('%id' => $this->id(), '%uuid' => $this->uuid(), '%original_uuid' => $original->uuid())));
|
||||
throw new ConfigDuplicateUUIDException("Attempt to save a configuration entity '{$this->id()}' with UUID '{$this->uuid()}' when this entity already exists with UUID '{$original->uuid()}'");
|
||||
}
|
||||
}
|
||||
if (!$this->isSyncing() && !$this->trustedData) {
|
||||
|
@ -409,7 +406,7 @@ abstract class ConfigEntityBase extends Entity implements ConfigEntityInterface
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheTags() {
|
||||
public function getCacheTagsToInvalidate() {
|
||||
// Use cache tags that match the underlying config object's name.
|
||||
// @see \Drupal\Core\Config\ConfigBase::getCacheTags()
|
||||
return ['config:' . $this->getConfigDependencyName()];
|
||||
|
|
|
@ -7,14 +7,13 @@
|
|||
|
||||
namespace Drupal\Core\Config\Entity;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\Cache\CacheableMetadata;
|
||||
use Drupal\Core\Config\ConfigFactoryInterface;
|
||||
use Drupal\Core\Config\ConfigImporterException;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Entity\EntityMalformedException;
|
||||
use Drupal\Core\Entity\EntityStorageBase;
|
||||
use Drupal\Core\Config\Config;
|
||||
use Drupal\Core\Config\StorageInterface;
|
||||
use Drupal\Core\Config\Entity\Exception\ConfigEntityIdLengthException;
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Component\Uuid\UuidInterface;
|
||||
|
@ -184,11 +183,41 @@ class ConfigEntityStorage extends EntityStorageBase implements ConfigEntityStora
|
|||
}
|
||||
|
||||
// Load all of the configuration entities.
|
||||
$records = array();
|
||||
/** @var \Drupal\Core\Config\Config[] $configs */
|
||||
$configs = [];
|
||||
$records = [];
|
||||
foreach ($this->configFactory->loadMultiple($names) as $config) {
|
||||
$records[$config->get($this->idKey)] = $this->overrideFree ? $config->getOriginal(NULL, FALSE) : $config->get();
|
||||
$id = $config->get($this->idKey);
|
||||
$records[$id] = $this->overrideFree ? $config->getOriginal(NULL, FALSE) : $config->get();
|
||||
$configs[$id] = $config;
|
||||
}
|
||||
return $this->mapFromStorageRecords($records);
|
||||
$entities = $this->mapFromStorageRecords($records, $configs);
|
||||
|
||||
// Config entities wrap config objects, and therefore they need to inherit
|
||||
// the cacheability metadata of config objects (to ensure e.g. additional
|
||||
// cacheability metadata added by config overrides is not lost).
|
||||
foreach ($entities as $id => $entity) {
|
||||
// But rather than simply inheriting all cacheability metadata of config
|
||||
// objects, we need to make sure the self-referring cache tag that is
|
||||
// present on Config objects is not added to the Config entity. It must be
|
||||
// removed for 3 reasons:
|
||||
// 1. When renaming/duplicating a Config entity, the cache tag of the
|
||||
// original config object would remain present, which would be wrong.
|
||||
// 2. Some Config entities choose to not use the cache tag that the under-
|
||||
// lying Config object provides by default (For performance and
|
||||
// cacheability reasons it may not make sense to have a unique cache
|
||||
// tag for every Config entity. The DateFormat Config entity specifies
|
||||
// the 'rendered' cache tag for example, because A) date formats are
|
||||
// changed extremely rarely, so invalidating all render cache items is
|
||||
// fine, B) it means fewer cache tags per page.).
|
||||
// 3. Fewer cache tags is better for performance.
|
||||
$self_referring_cache_tag = ['config:' . $configs[$id]->getName()];
|
||||
$config_cacheability = CacheableMetadata::createFromObject($configs[$id]);
|
||||
$config_cacheability->setCacheTags(array_diff($config_cacheability->getCacheTags(), $self_referring_cache_tag));
|
||||
$entity->addCacheableDependency($config_cacheability);
|
||||
}
|
||||
|
||||
return $entities;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -229,10 +258,7 @@ class ConfigEntityStorage extends EntityStorageBase implements ConfigEntityStora
|
|||
// @todo Consider moving this to a protected method on the parent class, and
|
||||
// abstracting it for all entity types.
|
||||
if (strlen($entity->get($this->idKey)) > self::MAX_ID_LENGTH) {
|
||||
throw new ConfigEntityIdLengthException(SafeMarkup::format('Configuration entity ID @id exceeds maximum allowed length of @length characters.', array(
|
||||
'@id' => $entity->get($this->idKey),
|
||||
'@length' => self::MAX_ID_LENGTH,
|
||||
)));
|
||||
throw new ConfigEntityIdLengthException("Configuration entity ID {$entity->get($this->idKey)} exceeds maximum allowed length of " . self::MAX_ID_LENGTH . " characters.");
|
||||
}
|
||||
|
||||
return parent::save($entity);
|
||||
|
@ -374,7 +400,7 @@ class ConfigEntityStorage extends EntityStorageBase implements ConfigEntityStora
|
|||
$id = static::getIDFromConfigName($name, $this->entityType->getConfigPrefix());
|
||||
$entity = $this->load($id);
|
||||
if (!$entity) {
|
||||
throw new ConfigImporterException(SafeMarkup::format('Attempt to update non-existing entity "@id".', array('@id' => $id)));
|
||||
throw new ConfigImporterException("Attempt to update non-existing entity '$id'.");
|
||||
}
|
||||
$entity->setSyncing(TRUE);
|
||||
$entity = $this->updateFromStorageRecord($entity, $new_config->get());
|
||||
|
|
|
@ -10,7 +10,6 @@ namespace Drupal\Core\Config\Entity;
|
|||
use Drupal\Core\Config\Entity\Exception\ConfigEntityStorageClassException;
|
||||
use Drupal\Core\Entity\EntityType;
|
||||
use Drupal\Core\Config\ConfigPrefixLengthException;
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
|
||||
/**
|
||||
* Provides an implementation of a configuration entity type and its metadata.
|
||||
|
@ -93,10 +92,7 @@ class ConfigEntityType extends EntityType implements ConfigEntityTypeInterface {
|
|||
}
|
||||
|
||||
if (strlen($config_prefix) > static::PREFIX_LENGTH) {
|
||||
throw new ConfigPrefixLengthException(SafeMarkup::format('The configuration file name prefix @config_prefix exceeds the maximum character limit of @max_char.', array(
|
||||
'@config_prefix' => $config_prefix,
|
||||
'@max_char' => static::PREFIX_LENGTH,
|
||||
)));
|
||||
throw new ConfigPrefixLengthException("The configuration file name prefix $config_prefix exceeds the maximum character limit of " . static::PREFIX_LENGTH);
|
||||
}
|
||||
return $config_prefix;
|
||||
}
|
||||
|
@ -158,7 +154,7 @@ class ConfigEntityType extends EntityType implements ConfigEntityTypeInterface {
|
|||
*/
|
||||
protected function checkStorageClass($class) {
|
||||
if (!is_a($class, 'Drupal\Core\Config\Entity\ConfigEntityStorage', TRUE)) {
|
||||
throw new ConfigEntityStorageClassException(SafeMarkup::format('@class is not \Drupal\Core\Config\Entity\ConfigEntityStorage or it does not extend it', ['@class' => $class]));
|
||||
throw new ConfigEntityStorageClassException("$class is not \\Drupal\\Core\\Config\\Entity\\ConfigEntityStorage or it does not extend it");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@ namespace Drupal\Core\Config;
|
|||
|
||||
use Drupal\Component\Serialization\Yaml;
|
||||
use Drupal\Component\Serialization\Exception\InvalidDataTypeException;
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
|
||||
/**
|
||||
* Defines the file storage.
|
||||
|
@ -101,10 +100,7 @@ class FileStorage implements StorageInterface {
|
|||
$data = $this->decode($data);
|
||||
}
|
||||
catch (InvalidDataTypeException $e) {
|
||||
throw new UnsupportedDataTypeConfigException(SafeMarkup::format('Invalid data type in config @name: !message', array(
|
||||
'@name' => $name,
|
||||
'!message' => $e->getMessage(),
|
||||
)));
|
||||
throw new UnsupportedDataTypeConfigException("Invalid data type in config $name: {$e->getMessage()}");
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
@ -130,10 +126,7 @@ class FileStorage implements StorageInterface {
|
|||
$data = $this->encode($data);
|
||||
}
|
||||
catch (InvalidDataTypeException $e) {
|
||||
throw new StorageException(SafeMarkup::format('Invalid data type in config @name: !message', array(
|
||||
'@name' => $name,
|
||||
'!message' => $e->getMessage(),
|
||||
)));
|
||||
throw new StorageException("Invalid data type in config $name: {$e->getMessage()}");
|
||||
}
|
||||
|
||||
$target = $this->getFilePath($name);
|
||||
|
|
|
@ -7,8 +7,6 @@
|
|||
|
||||
namespace Drupal\Core\Config;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
|
||||
/**
|
||||
* Defines the immutable configuration object.
|
||||
*
|
||||
|
@ -31,21 +29,21 @@ class ImmutableConfig extends Config {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function set($key, $value) {
|
||||
throw new ImmutableConfigException(SafeMarkup::format('Can not set values on immutable configuration !name:!key. Use \Drupal\Core\Config\ConfigFactoryInterface::getEditable() to retrieve a mutable configuration object', ['!name' => $this->getName(), '!key' => $key]));
|
||||
throw new ImmutableConfigException("Can not set values on immutable configuration {$this->getName()}:$key. Use \\Drupal\\Core\\Config\\ConfigFactoryInterface::getEditable() to retrieve a mutable configuration object");
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function clear($key) {
|
||||
throw new ImmutableConfigException(SafeMarkup::format('Can not clear !key key in immutable configuration !name. Use \Drupal\Core\Config\ConfigFactoryInterface::getEditable() to retrieve a mutable configuration object', ['!name' => $this->getName(), '!key' => $key]));
|
||||
throw new ImmutableConfigException("Can not clear $key key in immutable configuration {$this->getName()}. Use \\Drupal\\Core\\Config\\ConfigFactoryInterface::getEditable() to retrieve a mutable configuration object");
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function save($has_trusted_data = FALSE) {
|
||||
throw new ImmutableConfigException(SafeMarkup::format('Can not save immutable configuration !name. Use \Drupal\Core\Config\ConfigFactoryInterface::getEditable() to retrieve a mutable configuration object', ['!name' => $this->getName()]));
|
||||
throw new ImmutableConfigException("Can not save immutable configuration {$this->getName()}. Use \\Drupal\\Core\\Config\\ConfigFactoryInterface::getEditable() to retrieve a mutable configuration object");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -55,7 +53,7 @@ class ImmutableConfig extends Config {
|
|||
* The configuration object.
|
||||
*/
|
||||
public function delete() {
|
||||
throw new ImmutableConfigException(SafeMarkup::format('Can not delete immutable configuration !name. Use \Drupal\Core\Config\ConfigFactoryInterface::getEditable() to retrieve a mutable configuration object', ['!name' => $this->getName()]));
|
||||
throw new ImmutableConfigException("Can not delete immutable configuration {$this->getName()}. Use \\Drupal\\Core\\Config\\ConfigFactoryInterface::getEditable() to retrieve a mutable configuration object");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -91,9 +91,7 @@ class InstallStorage extends FileStorage {
|
|||
}
|
||||
// If any code in the early installer requests a configuration object that
|
||||
// does not exist anywhere as default config, then that must be mistake.
|
||||
throw new StorageException(format_string('Missing configuration file: @name', array(
|
||||
'@name' => $name,
|
||||
)));
|
||||
throw new StorageException("Missing configuration file: $name");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
namespace Drupal\Core\Config\Schema;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\Config\TypedConfigManagerInterface;
|
||||
use Drupal\Core\TypedData\TypedData;
|
||||
|
||||
|
@ -94,7 +93,7 @@ abstract class ArrayElement extends TypedData implements \IteratorAggregate, Typ
|
|||
return $element;
|
||||
}
|
||||
else {
|
||||
throw new \InvalidArgumentException(SafeMarkup::format("The configuration property @key doesn't exist.", array('@key' => $name)));
|
||||
throw new \InvalidArgumentException("The configuration property $name doesn't exist.");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ interface TypedConfigInterface extends TraversableTypedDataInterface {
|
|||
/**
|
||||
* Determines whether the data structure is empty.
|
||||
*
|
||||
* @return boolean
|
||||
* @return bool
|
||||
* TRUE if the data structure is empty, FALSE otherwise.
|
||||
*/
|
||||
public function isEmpty();
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
namespace Drupal\Core\Config;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\Config\Schema\Ignore;
|
||||
use Drupal\Core\TypedData\PrimitiveInterface;
|
||||
use Drupal\Core\TypedData\Type\FloatInterface;
|
||||
|
@ -163,10 +162,7 @@ abstract class StorableConfigBase extends ConfigBase {
|
|||
}
|
||||
}
|
||||
elseif ($value !== NULL && !is_scalar($value)) {
|
||||
throw new UnsupportedDataTypeConfigException(SafeMarkup::format('Invalid data type for config element @name:@key', array(
|
||||
'@name' => $this->getName(),
|
||||
'@key' => $key,
|
||||
)));
|
||||
throw new UnsupportedDataTypeConfigException("Invalid data type for config element {$this->getName()}:$key");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -213,10 +209,7 @@ abstract class StorableConfigBase extends ConfigBase {
|
|||
else {
|
||||
// Throw exception on any non-scalar or non-array value.
|
||||
if (!is_array($value)) {
|
||||
throw new UnsupportedDataTypeConfigException(SafeMarkup::format('Invalid data type for config element @name:@key', array(
|
||||
'@name' => $this->getName(),
|
||||
'@key' => $key,
|
||||
)));
|
||||
throw new UnsupportedDataTypeConfigException("Invalid data type for config element {$this->getName()}:$key");
|
||||
}
|
||||
// Recurse into any nested keys.
|
||||
foreach ($value as $nested_value_key => $nested_value) {
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
namespace Drupal\Core\Config;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\Cache\MemoryBackend;
|
||||
use Drupal\Core\Config\Entity\ConfigDependencyManager;
|
||||
use Drupal\Core\DependencyInjection\DependencySerializationTrait;
|
||||
|
@ -196,7 +195,7 @@ class StorageComparer implements StorageComparerInterface {
|
|||
// ensure the array is keyed from 0.
|
||||
$this->changelist[$collection][$op] = array_values(array_intersect($sort_order, $this->changelist[$collection][$op]));
|
||||
if ($count != count($this->changelist[$collection][$op])) {
|
||||
throw new \InvalidArgumentException(SafeMarkup::format('Sorting the @op changelist should not change its length.', array('@op' => $op)));
|
||||
throw new \InvalidArgumentException("Sorting the $op changelist should not change its length.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -156,7 +156,7 @@ interface StorageInterface {
|
|||
* (optional) The prefix to search for. If omitted, all configuration
|
||||
* objects that exist will be deleted.
|
||||
*
|
||||
* @return boolean
|
||||
* @return bool
|
||||
* TRUE on success, FALSE otherwise.
|
||||
*/
|
||||
public function deleteAll($prefix = '');
|
||||
|
|
|
@ -88,14 +88,14 @@ class ConfigSchemaChecker implements EventSubscriberInterface {
|
|||
$this->checked[$name . ':' . $checksum] = TRUE;
|
||||
$errors = $this->checkConfigSchema($this->typedManager, $name, $data);
|
||||
if ($errors === FALSE) {
|
||||
throw new SchemaIncompleteException(SafeMarkup::format('No schema for @config_name', array('@config_name' => $name)));
|
||||
throw new SchemaIncompleteException("No schema for $name");
|
||||
}
|
||||
elseif (is_array($errors)) {
|
||||
$text_errors = [];
|
||||
foreach ($errors as $key => $error) {
|
||||
$text_errors[] = SafeMarkup::format('@key @error', array('@key' => $key, '@error' => $error));
|
||||
}
|
||||
throw new SchemaIncompleteException(SafeMarkup::format('Schema errors for @config_name with the following errors: @errors', array('@config_name' => $name, '@errors' => implode(', ', $text_errors))));
|
||||
throw new SchemaIncompleteException("Schema errors for $name with the following errors: " . implode(', ', $text_errors));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
namespace Drupal\Core\Config;
|
||||
|
||||
use Drupal\Component\Utility\NestedArray;
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\Cache\CacheBackendInterface;
|
||||
use Drupal\Core\Config\Schema\ArrayElement;
|
||||
use Drupal\Core\Config\Schema\ConfigSchemaAlterException;
|
||||
|
@ -17,7 +16,7 @@ use Drupal\Core\Extension\ModuleHandlerInterface;
|
|||
use Drupal\Core\TypedData\TypedDataManager;
|
||||
|
||||
/**
|
||||
* Manages config type plugins.
|
||||
* Manages config schema type plugins.
|
||||
*/
|
||||
class TypedConfigManager extends TypedDataManager implements TypedConfigManagerInterface {
|
||||
|
||||
|
@ -324,18 +323,18 @@ class TypedConfigManager extends TypedDataManager implements TypedConfigManagerI
|
|||
parent::alterDefinitions($definitions);
|
||||
$altered_schema = array_keys($definitions);
|
||||
if ($discovered_schema != $altered_schema) {
|
||||
$added_keys = array_diff($altered_schema, $discovered_schema);
|
||||
$removed_keys = array_diff($discovered_schema, $altered_schema);
|
||||
$added_keys = implode(',', array_diff($altered_schema, $discovered_schema));
|
||||
$removed_keys = implode(',', array_diff($discovered_schema, $altered_schema));
|
||||
if (!empty($added_keys) && !empty($removed_keys)) {
|
||||
$message = 'Invoking hook_config_schema_info_alter() has added (@added) and removed (@removed) schema definitions';
|
||||
$message = "Invoking hook_config_schema_info_alter() has added ($added_keys) and removed ($removed_keys) schema definitions";
|
||||
}
|
||||
elseif (!empty($added_keys)) {
|
||||
$message = 'Invoking hook_config_schema_info_alter() has added (@added) schema definitions';
|
||||
$message = "Invoking hook_config_schema_info_alter() has added ($added_keys) schema definitions";
|
||||
}
|
||||
else {
|
||||
$message = 'Invoking hook_config_schema_info_alter() has removed (@removed) schema definitions';
|
||||
$message = "Invoking hook_config_schema_info_alter() has removed ($removed_keys) schema definitions";
|
||||
}
|
||||
throw new ConfigSchemaAlterException(SafeMarkup::format($message, ['@added' => implode(',', $added_keys), '@removed' => implode(',', $removed_keys)]));
|
||||
throw new ConfigSchemaAlterException($message);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,9 +12,12 @@ use Drupal\Component\Plugin\PluginManagerInterface;
|
|||
use Drupal\Core\TypedData\DataDefinitionInterface;
|
||||
|
||||
/**
|
||||
* Defines an interface for typed configuration manager.
|
||||
* Defines an interface for managing config schema type plugins.
|
||||
*
|
||||
* @package Drupal\Core\Config
|
||||
* @see \Drupal\Core\Config\TypedConfigManager
|
||||
* @see \Drupal\Core\Config\Schema\ConfigSchemaDiscovery
|
||||
* @see hook_config_schema_info_alter()
|
||||
* @see https://www.drupal.org/node/1905070
|
||||
*/
|
||||
Interface TypedConfigManagerInterface extends PluginManagerInterface, CachedDiscoveryInterface {
|
||||
|
||||
|
|
|
@ -37,10 +37,6 @@ class ContentNegotiation {
|
|||
return $request->query->get('_format');
|
||||
}
|
||||
|
||||
if ($request->isXmlHttpRequest()) {
|
||||
return 'ajax';
|
||||
}
|
||||
|
||||
// Do HTML last so that it always wins.
|
||||
return 'html';
|
||||
}
|
||||
|
|
|
@ -10,6 +10,9 @@ namespace Drupal\Core;
|
|||
use Drupal\Core\Cache\Context\CacheContextsPass;
|
||||
use Drupal\Core\Cache\ListCacheBinsPass;
|
||||
use Drupal\Core\DependencyInjection\Compiler\BackendCompilerPass;
|
||||
use Drupal\Core\DependencyInjection\Compiler\GuzzleMiddlewarePass;
|
||||
use Drupal\Core\DependencyInjection\Compiler\ContextProvidersPass;
|
||||
use Drupal\Core\DependencyInjection\Compiler\ProxyServicesPass;
|
||||
use Drupal\Core\DependencyInjection\Compiler\RegisterLazyRouteEnhancers;
|
||||
use Drupal\Core\DependencyInjection\Compiler\RegisterLazyRouteFilters;
|
||||
use Drupal\Core\DependencyInjection\Compiler\DependencySerializationTraitPass;
|
||||
|
@ -60,6 +63,8 @@ class CoreServiceProvider implements ServiceProviderInterface {
|
|||
// list-building passes are operating on the post-alter services list.
|
||||
$container->addCompilerPass(new ModifyServiceDefinitionsPass());
|
||||
|
||||
$container->addCompilerPass(new ProxyServicesPass());
|
||||
|
||||
$container->addCompilerPass(new BackendCompilerPass());
|
||||
|
||||
$container->addCompilerPass(new StackedKernelPass());
|
||||
|
@ -71,6 +76,7 @@ class CoreServiceProvider implements ServiceProviderInterface {
|
|||
// Collect tagged handler services as method calls on consumer services.
|
||||
$container->addCompilerPass(new TaggedHandlersPass());
|
||||
$container->addCompilerPass(new RegisterStreamWrappersPass());
|
||||
$container->addCompilerPass(new GuzzleMiddlewarePass());
|
||||
|
||||
// Add a compiler pass for registering event subscribers.
|
||||
$container->addCompilerPass(new RegisterKernelListenersPass(), PassConfig::TYPE_AFTER_REMOVING);
|
||||
|
@ -85,6 +91,7 @@ class CoreServiceProvider implements ServiceProviderInterface {
|
|||
// Add the compiler pass that will process the tagged services.
|
||||
$container->addCompilerPass(new ListCacheBinsPass());
|
||||
$container->addCompilerPass(new CacheContextsPass());
|
||||
$container->addCompilerPass(new ContextProvidersPass());
|
||||
|
||||
// Register plugin managers.
|
||||
$container->addCompilerPass(new PluginManagerPass());
|
||||
|
@ -127,10 +134,10 @@ class CoreServiceProvider implements ServiceProviderInterface {
|
|||
if (!drupal_valid_test_ua()) {
|
||||
return;
|
||||
}
|
||||
// Add the HTTP request subscriber to Guzzle.
|
||||
// Add the HTTP request middleware to Guzzle.
|
||||
$container
|
||||
->register('test.http_client.request_subscriber', 'Drupal\Core\Test\EventSubscriber\HttpRequestSubscriber')
|
||||
->addTag('http_client_subscriber');
|
||||
->register('test.http_client.middleware', 'Drupal\Core\Test\HttpClientMiddleware\TestHttpClientMiddleware')
|
||||
->addTag('http_client_middleware');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -9,6 +9,8 @@ namespace Drupal\Core;
|
|||
|
||||
/**
|
||||
* An interface for running cron tasks.
|
||||
*
|
||||
* @see https://www.drupal.org/cron
|
||||
*/
|
||||
interface CronInterface {
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ abstract class Connection {
|
|||
*
|
||||
* We need this information for later auditing and logging.
|
||||
*
|
||||
* @var string
|
||||
* @var string|null
|
||||
*/
|
||||
protected $target = NULL;
|
||||
|
||||
|
@ -35,14 +35,14 @@ abstract class Connection {
|
|||
* connection can be a single server or a cluster of primary and replicas
|
||||
* (use target to pick between primary and replica).
|
||||
*
|
||||
* @var string
|
||||
* @var string|null
|
||||
*/
|
||||
protected $key = NULL;
|
||||
|
||||
/**
|
||||
* The current database logging object for this connection.
|
||||
*
|
||||
* @var Log
|
||||
* @var \Drupal\Core\Database\Log|null
|
||||
*/
|
||||
protected $logger = NULL;
|
||||
|
||||
|
@ -111,7 +111,9 @@ abstract class Connection {
|
|||
/**
|
||||
* The schema object for this connection.
|
||||
*
|
||||
* @var object
|
||||
* Set to NULL when the schema is destroyed.
|
||||
*
|
||||
* @var \Drupal\Core\Database\Schema|null
|
||||
*/
|
||||
protected $schema = NULL;
|
||||
|
||||
|
@ -138,6 +140,14 @@ abstract class Connection {
|
|||
|
||||
/**
|
||||
* Constructs a Connection object.
|
||||
*
|
||||
* @param \PDO $connection
|
||||
* An object of the PDO class representing a database connection.
|
||||
* @param array $connection_options
|
||||
* An array of options for the connection. May include the following:
|
||||
* - prefix
|
||||
* - namespace
|
||||
* - Other driver-specific options.
|
||||
*/
|
||||
public function __construct(\PDO $connection, array $connection_options) {
|
||||
// Initialize and prepare the connection prefix.
|
||||
|
@ -221,7 +231,7 @@ abstract class Connection {
|
|||
* that behavior and simply return NULL on failure, set this option to
|
||||
* FALSE.
|
||||
*
|
||||
* @return
|
||||
* @return array
|
||||
* An array of default query options.
|
||||
*/
|
||||
protected function defaultOptions() {
|
||||
|
@ -241,7 +251,7 @@ abstract class Connection {
|
|||
* is for requesting the connection information of this specific
|
||||
* open connection object.
|
||||
*
|
||||
* @return
|
||||
* @return array
|
||||
* An array of the connection information. The exact list of
|
||||
* properties is driver-dependent.
|
||||
*/
|
||||
|
@ -252,9 +262,9 @@ abstract class Connection {
|
|||
/**
|
||||
* Set the list of prefixes used by this database connection.
|
||||
*
|
||||
* @param $prefix
|
||||
* The prefixes, in any of the multiple forms documented in
|
||||
* default.settings.php.
|
||||
* @param array|string $prefix
|
||||
* Either a single prefix, or an array of prefixes, in any of the multiple
|
||||
* forms documented in default.settings.php.
|
||||
*/
|
||||
protected function setPrefix($prefix) {
|
||||
if (is_array($prefix)) {
|
||||
|
@ -289,10 +299,10 @@ abstract class Connection {
|
|||
* tables, allowing Drupal to coexist with other systems in the same database
|
||||
* and/or schema if necessary.
|
||||
*
|
||||
* @param $sql
|
||||
* @param string $sql
|
||||
* A string containing a partial or entire SQL query.
|
||||
*
|
||||
* @return
|
||||
* @return string
|
||||
* The properly-prefixed string.
|
||||
*/
|
||||
public function prefixTables($sql) {
|
||||
|
@ -304,6 +314,9 @@ abstract class Connection {
|
|||
*
|
||||
* This function is for when you want to know the prefix of a table. This
|
||||
* is not used in prefixTables due to performance reasons.
|
||||
*
|
||||
* @param string $table
|
||||
* (optional) The table to find the prefix for.
|
||||
*/
|
||||
public function tablePrefix($table = 'default') {
|
||||
if (isset($this->prefixes[$table])) {
|
||||
|
@ -355,9 +368,8 @@ abstract class Connection {
|
|||
* signature. We therefore also ensure that this function is only ever
|
||||
* called once.
|
||||
*
|
||||
* @param $target
|
||||
* The target this connection is for. Set to NULL (default) to disable
|
||||
* logging entirely.
|
||||
* @param string $target
|
||||
* (optional) The target this connection is for.
|
||||
*/
|
||||
public function setTarget($target = NULL) {
|
||||
if (!isset($this->target)) {
|
||||
|
@ -368,8 +380,8 @@ abstract class Connection {
|
|||
/**
|
||||
* Returns the target this connection is associated with.
|
||||
*
|
||||
* @return
|
||||
* The target string of this connection.
|
||||
* @return string|null
|
||||
* The target string of this connection, or NULL if no target is set.
|
||||
*/
|
||||
public function getTarget() {
|
||||
return $this->target;
|
||||
|
@ -378,7 +390,7 @@ abstract class Connection {
|
|||
/**
|
||||
* Tells this connection object what its key is.
|
||||
*
|
||||
* @param $target
|
||||
* @param string $key
|
||||
* The key this connection is for.
|
||||
*/
|
||||
public function setKey($key) {
|
||||
|
@ -390,8 +402,8 @@ abstract class Connection {
|
|||
/**
|
||||
* Returns the key this connection is associated with.
|
||||
*
|
||||
* @return
|
||||
* The key of this connection.
|
||||
* @return string|null
|
||||
* The key of this connection, or NULL if no key is set.
|
||||
*/
|
||||
public function getKey() {
|
||||
return $this->key;
|
||||
|
@ -400,7 +412,7 @@ abstract class Connection {
|
|||
/**
|
||||
* Associates a logging object with this connection.
|
||||
*
|
||||
* @param $logger
|
||||
* @param \Drupal\Core\Database\Log $logger
|
||||
* The logging object we want to use.
|
||||
*/
|
||||
public function setLogger(Log $logger) {
|
||||
|
@ -410,7 +422,7 @@ abstract class Connection {
|
|||
/**
|
||||
* Gets the current logging object for this connection.
|
||||
*
|
||||
* @return \Drupal\Core\Database\Log
|
||||
* @return \Drupal\Core\Database\Log|null
|
||||
* The current logging object for this connection. If there isn't one,
|
||||
* NULL is returned.
|
||||
*/
|
||||
|
@ -424,12 +436,12 @@ abstract class Connection {
|
|||
* This information is exposed to all database drivers, although it is only
|
||||
* useful on some of them. This method is table prefix-aware.
|
||||
*
|
||||
* @param $table
|
||||
* @param string $table
|
||||
* The table name to use for the sequence.
|
||||
* @param $field
|
||||
* @param string $field
|
||||
* The field name to use for the sequence.
|
||||
*
|
||||
* @return
|
||||
* @return string
|
||||
* A table prefix-parsed string for the sequence name.
|
||||
*/
|
||||
public function makeSequenceName($table, $field) {
|
||||
|
@ -441,10 +453,10 @@ abstract class Connection {
|
|||
*
|
||||
* The comment string will be sanitized to avoid SQL injection attacks.
|
||||
*
|
||||
* @param $comments
|
||||
* @param string[] $comments
|
||||
* An array of query comment strings.
|
||||
*
|
||||
* @return
|
||||
* @return string
|
||||
* A sanitized comment string.
|
||||
*/
|
||||
public function makeComment($comments) {
|
||||
|
@ -483,10 +495,10 @@ abstract class Connection {
|
|||
* Unless the comment is sanitised first, the SQL server would drop the
|
||||
* node table and ignore the rest of the SQL statement.
|
||||
*
|
||||
* @param $comment
|
||||
* @param string $comment
|
||||
* A query comment string.
|
||||
*
|
||||
* @return
|
||||
* @return string
|
||||
* A sanitized version of the query comment string.
|
||||
*/
|
||||
protected function filterComment($comment = '') {
|
||||
|
@ -500,7 +512,7 @@ abstract class Connection {
|
|||
* query. All queries executed by Drupal are executed as PDO prepared
|
||||
* statements.
|
||||
*
|
||||
* @param $query
|
||||
* @param string|\Drupal\Core\Database\StatementInterface $query
|
||||
* The query to execute. In most cases this will be a string containing
|
||||
* an SQL query with placeholders. An already-prepared instance of
|
||||
* StatementInterface may also be passed in order to allow calling
|
||||
|
@ -509,26 +521,36 @@ abstract class Connection {
|
|||
* It is extremely rare that module code will need to pass a statement
|
||||
* object to this method. It is used primarily for database drivers for
|
||||
* databases that require special LOB field handling.
|
||||
* @param $args
|
||||
* @param array $args
|
||||
* An array of arguments for the prepared statement. If the prepared
|
||||
* statement uses ? placeholders, this array must be an indexed array.
|
||||
* If it contains named placeholders, it must be an associative array.
|
||||
* @param $options
|
||||
* An associative array of options to control how the query is run. See
|
||||
* the documentation for DatabaseConnection::defaultOptions() for details.
|
||||
* @param array $options
|
||||
* An associative array of options to control how the query is run. The
|
||||
* given options will be merged with self::defaultOptions(). See the
|
||||
* documentation for self::defaultOptions() for details.
|
||||
* Typically, $options['return'] will be set by a default or by a query
|
||||
* builder, and should not be set by a user.
|
||||
*
|
||||
* @return \Drupal\Core\Database\StatementInterface|int|null
|
||||
* This method will return one of: the executed statement, the number of
|
||||
* rows affected by the query (not the number matched), or the generated
|
||||
* insert ID of the last query, depending on the value of
|
||||
* $options['return']. Typically that value will be set by default or a
|
||||
* query builder and should not be set by a user. If there is an error,
|
||||
* this method will return NULL and may throw an exception if
|
||||
* $options['throw_exception'] is TRUE.
|
||||
* This method will return one of the following:
|
||||
* - If either $options['return'] === self::RETURN_STATEMENT, or
|
||||
* $options['return'] is not set (due to self::defaultOptions()),
|
||||
* returns the executed statement.
|
||||
* - If $options['return'] === self::RETURN_AFFECTED,
|
||||
* returns the number of rows affected by the query
|
||||
* (not the number matched).
|
||||
* - If $options['return'] === self::RETURN_INSERT_ID,
|
||||
* returns the generated insert ID of the last query.
|
||||
* - If either $options['return'] === self::RETURN_NULL, or
|
||||
* an exception occurs and $options['throw_exception'] evaluates to FALSE,
|
||||
* returns NULL.
|
||||
*
|
||||
* @throws \Drupal\Core\Database\DatabaseExceptionWrapper
|
||||
* @throws \Drupal\Core\Database\IntegrityConstraintViolationException
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @see \Drupal\Core\Database\Connection::defaultOptions()
|
||||
*/
|
||||
public function query($query, array $args = array(), $options = array()) {
|
||||
// Use default values if not already set.
|
||||
|
@ -628,6 +650,13 @@ abstract class Connection {
|
|||
*
|
||||
* @return bool
|
||||
* TRUE if the query was modified, FALSE otherwise.
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
* This exception is thrown when:
|
||||
* - A placeholder that ends in [] is supplied, and the supplied value is
|
||||
* not an array.
|
||||
* - A placeholder that does not end in [] is supplied, and the supplied
|
||||
* value is an array.
|
||||
*/
|
||||
protected function expandArguments(&$query, &$args) {
|
||||
$modified = FALSE;
|
||||
|
@ -700,12 +729,12 @@ abstract class Connection {
|
|||
/**
|
||||
* Prepares and returns a SELECT query object.
|
||||
*
|
||||
* @param $table
|
||||
* @param string $table
|
||||
* The base table for this query, that is, the first table in the FROM
|
||||
* clause. This table will also be used as the "base" table for query_alter
|
||||
* hook implementations.
|
||||
* @param $alias
|
||||
* The alias of the base table of this query.
|
||||
* @param string $alias
|
||||
* (optional) The alias of the base table of this query.
|
||||
* @param $options
|
||||
* An array of options on the query.
|
||||
*
|
||||
|
@ -724,8 +753,10 @@ abstract class Connection {
|
|||
/**
|
||||
* Prepares and returns an INSERT query object.
|
||||
*
|
||||
* @param $options
|
||||
* An array of options on the query.
|
||||
* @param string $table
|
||||
* The table to use for the insert statement.
|
||||
* @param array $options
|
||||
* (optional) An array of options on the query.
|
||||
*
|
||||
* @return \Drupal\Core\Database\Query\Insert
|
||||
* A new Insert query object.
|
||||
|
@ -740,8 +771,10 @@ abstract class Connection {
|
|||
/**
|
||||
* Prepares and returns a MERGE query object.
|
||||
*
|
||||
* @param $options
|
||||
* An array of options on the query.
|
||||
* @param string $table
|
||||
* The table to use for the merge statement.
|
||||
* @param array $options
|
||||
* (optional) An array of options on the query.
|
||||
*
|
||||
* @return \Drupal\Core\Database\Query\Merge
|
||||
* A new Merge query object.
|
||||
|
@ -757,8 +790,10 @@ abstract class Connection {
|
|||
/**
|
||||
* Prepares and returns an UPDATE query object.
|
||||
*
|
||||
* @param $options
|
||||
* An array of options on the query.
|
||||
* @param string $table
|
||||
* The table to use for the update statement.
|
||||
* @param array $options
|
||||
* (optional) An array of options on the query.
|
||||
*
|
||||
* @return \Drupal\Core\Database\Query\Update
|
||||
* A new Update query object.
|
||||
|
@ -773,8 +808,10 @@ abstract class Connection {
|
|||
/**
|
||||
* Prepares and returns a DELETE query object.
|
||||
*
|
||||
* @param $options
|
||||
* An array of options on the query.
|
||||
* @param string $table
|
||||
* The table to use for the delete statement.
|
||||
* @param array $options
|
||||
* (optional) An array of options on the query.
|
||||
*
|
||||
* @return \Drupal\Core\Database\Query\Delete
|
||||
* A new Delete query object.
|
||||
|
@ -789,8 +826,10 @@ abstract class Connection {
|
|||
/**
|
||||
* Prepares and returns a TRUNCATE query object.
|
||||
*
|
||||
* @param $options
|
||||
* An array of options on the query.
|
||||
* @param string $table
|
||||
* The table to use for the truncate statement.
|
||||
* @param array $options
|
||||
* (optional) An array of options on the query.
|
||||
*
|
||||
* @return \Drupal\Core\Database\Query\Truncate
|
||||
* A new Truncate query object.
|
||||
|
@ -825,8 +864,11 @@ abstract class Connection {
|
|||
* For some database drivers, it may also wrap the database name in
|
||||
* database-specific escape characters.
|
||||
*
|
||||
* @param string $database
|
||||
* An unsanitized database name.
|
||||
*
|
||||
* @return string
|
||||
* The sanitized database name string.
|
||||
* The sanitized database name.
|
||||
*/
|
||||
public function escapeDatabase($database) {
|
||||
return preg_replace('/[^A-Za-z0-9_.]+/', '', $database);
|
||||
|
@ -839,8 +881,11 @@ abstract class Connection {
|
|||
* For some database drivers, it may also wrap the table name in
|
||||
* database-specific escape characters.
|
||||
*
|
||||
* @return
|
||||
* The sanitized table name string.
|
||||
* @param string $table
|
||||
* An unsanitized table name.
|
||||
*
|
||||
* @return string
|
||||
* The sanitized table name.
|
||||
*/
|
||||
public function escapeTable($table) {
|
||||
return preg_replace('/[^A-Za-z0-9_.]+/', '', $table);
|
||||
|
@ -853,8 +898,11 @@ abstract class Connection {
|
|||
* For some database drivers, it may also wrap the field name in
|
||||
* database-specific escape characters.
|
||||
*
|
||||
* @return
|
||||
* The sanitized field name string.
|
||||
* @param string $field
|
||||
* An unsanitized field name.
|
||||
*
|
||||
* @return string
|
||||
* The sanitized field name.
|
||||
*/
|
||||
public function escapeField($field) {
|
||||
return preg_replace('/[^A-Za-z0-9_.]+/', '', $field);
|
||||
|
@ -868,8 +916,11 @@ abstract class Connection {
|
|||
* DatabaseConnection::escapeTable(), this doesn't allow the period (".")
|
||||
* because that is not allowed in aliases.
|
||||
*
|
||||
* @return
|
||||
* The sanitized field name string.
|
||||
* @param string $field
|
||||
* An unsanitized alias name.
|
||||
*
|
||||
* @return string
|
||||
* The sanitized alias name.
|
||||
*/
|
||||
public function escapeAlias($field) {
|
||||
return preg_replace('/[^A-Za-z0-9_]+/', '', $field);
|
||||
|
@ -894,10 +945,10 @@ abstract class Connection {
|
|||
* Backslash is defined as escape character for LIKE patterns in
|
||||
* Drupal\Core\Database\Query\Condition::mapConditionOperator().
|
||||
*
|
||||
* @param $string
|
||||
* @param string $string
|
||||
* The string to escape.
|
||||
*
|
||||
* @return
|
||||
* @return string
|
||||
* The escaped string.
|
||||
*/
|
||||
public function escapeLike($string) {
|
||||
|
@ -907,7 +958,7 @@ abstract class Connection {
|
|||
/**
|
||||
* Determines if there is an active transaction open.
|
||||
*
|
||||
* @return
|
||||
* @return bool
|
||||
* TRUE if we're currently in a transaction, FALSE otherwise.
|
||||
*/
|
||||
public function inTransaction() {
|
||||
|
@ -915,7 +966,10 @@ abstract class Connection {
|
|||
}
|
||||
|
||||
/**
|
||||
* Determines current transaction depth.
|
||||
* Determines the current transaction depth.
|
||||
*
|
||||
* @return int
|
||||
* The current transaction depth.
|
||||
*/
|
||||
public function transactionDepth() {
|
||||
return count($this->transactionLayers);
|
||||
|
@ -924,8 +978,8 @@ abstract class Connection {
|
|||
/**
|
||||
* Returns a new DatabaseTransaction object on this connection.
|
||||
*
|
||||
* @param $name
|
||||
* Optional name of the savepoint.
|
||||
* @param string $name
|
||||
* (optional) The name of the savepoint.
|
||||
*
|
||||
* @return \Drupal\Core\Database\Transaction
|
||||
* A Transaction object.
|
||||
|
@ -942,10 +996,11 @@ abstract class Connection {
|
|||
*
|
||||
* This method throws an exception if no transaction is active.
|
||||
*
|
||||
* @param $savepoint_name
|
||||
* The name of the savepoint. The default, 'drupal_transaction', will roll
|
||||
* the entire transaction back.
|
||||
* @param string $savepoint_name
|
||||
* (optional) The name of the savepoint. The default, 'drupal_transaction',
|
||||
* will roll the entire transaction back.
|
||||
*
|
||||
* @throws \Drupal\Core\Database\TransactionOutOfOrderException
|
||||
* @throws \Drupal\Core\Database\TransactionNoActiveException
|
||||
*
|
||||
* @see \Drupal\Core\Database\Transaction::rollback()
|
||||
|
@ -997,6 +1052,9 @@ abstract class Connection {
|
|||
*
|
||||
* If no transaction is already active, we begin a new transaction.
|
||||
*
|
||||
* @param string $name
|
||||
* The name of the transaction.
|
||||
*
|
||||
* @throws \Drupal\Core\Database\TransactionNameNonUniqueException
|
||||
*
|
||||
* @see \Drupal\Core\Database\Transaction
|
||||
|
@ -1026,8 +1084,8 @@ abstract class Connection {
|
|||
* back the transaction as necessary. If no transaction is active, we return
|
||||
* because the transaction may have manually been rolled back.
|
||||
*
|
||||
* @param $name
|
||||
* The name of the savepoint
|
||||
* @param string $name
|
||||
* The name of the savepoint.
|
||||
*
|
||||
* @throws \Drupal\Core\Database\TransactionNoActiveException
|
||||
* @throws \Drupal\Core\Database\TransactionCommitFailedException
|
||||
|
@ -1083,16 +1141,17 @@ abstract class Connection {
|
|||
* separate parameters so that they can be properly escaped to avoid SQL
|
||||
* injection attacks.
|
||||
*
|
||||
* @param $query
|
||||
* @param string $query
|
||||
* A string containing an SQL query.
|
||||
* @param $args
|
||||
* An array of values to substitute into the query at placeholder markers.
|
||||
* @param $from
|
||||
* @param int $from
|
||||
* The first result row to return.
|
||||
* @param $count
|
||||
* @param int $count
|
||||
* The maximum number of result rows to return.
|
||||
* @param $options
|
||||
* An array of options on the query.
|
||||
* @param array $args
|
||||
* (optional) An array of values to substitute into the query at placeholder
|
||||
* markers.
|
||||
* @param array $options
|
||||
* (optional) An array of options on the query.
|
||||
*
|
||||
* @return \Drupal\Core\Database\StatementInterface
|
||||
* A database query result resource, or NULL if the query was not executed
|
||||
|
@ -1103,7 +1162,7 @@ abstract class Connection {
|
|||
/**
|
||||
* Generates a temporary table name.
|
||||
*
|
||||
* @return
|
||||
* @return string
|
||||
* A table name.
|
||||
*/
|
||||
protected function generateTemporaryTableName() {
|
||||
|
@ -1122,15 +1181,17 @@ abstract class Connection {
|
|||
* Note that if you need to know how many results were returned, you should do
|
||||
* a SELECT COUNT(*) on the temporary table afterwards.
|
||||
*
|
||||
* @param $query
|
||||
* @param string $query
|
||||
* A string containing a normal SELECT SQL query.
|
||||
* @param $args
|
||||
* An array of values to substitute into the query at placeholder markers.
|
||||
* @param $options
|
||||
* An associative array of options to control how the query is run. See
|
||||
* the documentation for DatabaseConnection::defaultOptions() for details.
|
||||
* @param array $args
|
||||
* (optional) An array of values to substitute into the query at placeholder
|
||||
* markers.
|
||||
* @param array $options
|
||||
* (optional) An associative array of options to control how the query is
|
||||
* run. See the documentation for DatabaseConnection::defaultOptions() for
|
||||
* details.
|
||||
*
|
||||
* @return
|
||||
* @return string
|
||||
* The name of the temporary table.
|
||||
*/
|
||||
abstract function queryTemporary($query, array $args = array(), array $options = array());
|
||||
|
@ -1142,6 +1203,9 @@ abstract class Connection {
|
|||
* instance, there could be two MySQL drivers, mysql and mysql_mock. This
|
||||
* function would return different values for each, but both would return
|
||||
* "mysql" for databaseType().
|
||||
*
|
||||
* @return string
|
||||
* The type of database driver.
|
||||
*/
|
||||
abstract public function driver();
|
||||
|
||||
|
@ -1155,7 +1219,7 @@ abstract class Connection {
|
|||
/**
|
||||
* Determines if this driver supports transactions.
|
||||
*
|
||||
* @return
|
||||
* @return bool
|
||||
* TRUE if this connection supports transactions, FALSE otherwise.
|
||||
*/
|
||||
public function supportsTransactions() {
|
||||
|
@ -1167,7 +1231,7 @@ abstract class Connection {
|
|||
*
|
||||
* DDL queries are those that change the schema, such as ALTER queries.
|
||||
*
|
||||
* @return
|
||||
* @return bool
|
||||
* TRUE if this connection supports transactions for DDL queries, FALSE
|
||||
* otherwise.
|
||||
*/
|
||||
|
@ -1199,7 +1263,7 @@ abstract class Connection {
|
|||
* overridable lookup function. Database connections should define only
|
||||
* those operators they wish to be handled differently than the default.
|
||||
*
|
||||
* @param $operator
|
||||
* @param string $operator
|
||||
* The condition operator, such as "IN", "BETWEEN", etc. Case-sensitive.
|
||||
*
|
||||
* @return
|
||||
|
@ -1226,7 +1290,7 @@ abstract class Connection {
|
|||
}
|
||||
|
||||
/**
|
||||
* Retrieves an unique id from a given sequence.
|
||||
* Retrieves an unique ID from a given sequence.
|
||||
*
|
||||
* Use this function if for some reason you can't use a serial field. For
|
||||
* example, MySQL has no ways of reading of the current value of a sequence
|
||||
|
@ -1234,9 +1298,9 @@ abstract class Connection {
|
|||
* value. Or sometimes you just need a unique integer.
|
||||
*
|
||||
* @param $existing_id
|
||||
* After a database import, it might be that the sequences table is behind,
|
||||
* so by passing in the maximum existing id, it can be assured that we
|
||||
* never issue the same id.
|
||||
* (optional) After a database import, it might be that the sequences table
|
||||
* is behind, so by passing in the maximum existing ID, it can be assured
|
||||
* that we never issue the same ID.
|
||||
*
|
||||
* @return
|
||||
* An integer number larger than any number returned by earlier calls and
|
||||
|
|
|
@ -14,6 +14,7 @@ use Drupal\Core\Database\DatabaseNotFoundException;
|
|||
use Drupal\Core\Database\TransactionCommitFailedException;
|
||||
use Drupal\Core\Database\DatabaseException;
|
||||
use Drupal\Core\Database\Connection as DatabaseConnection;
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
|
||||
/**
|
||||
* @addtogroup database
|
||||
|
@ -34,6 +35,16 @@ class Connection extends DatabaseConnection {
|
|||
*/
|
||||
protected $needsCleanup = FALSE;
|
||||
|
||||
/**
|
||||
* The minimal possible value for the max_allowed_packet setting of MySQL.
|
||||
*
|
||||
* @link https://mariadb.com/kb/en/mariadb/server-system-variables/#max_allowed_packet
|
||||
* @link https://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_max_allowed_packet
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
const MIN_MAX_ALLOWED_PACKET = 1024;
|
||||
|
||||
/**
|
||||
* Constructs a Connection object.
|
||||
*/
|
||||
|
@ -49,6 +60,24 @@ class Connection extends DatabaseConnection {
|
|||
$this->connectionOptions = $connection_options;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function query($query, array $args = array(), $options = array()) {
|
||||
try {
|
||||
return parent::query($query, $args, $options);
|
||||
} catch (DatabaseException $e) {
|
||||
if ($e->getPrevious()->errorInfo[1] == 1153) {
|
||||
// If a max_allowed_packet error occurs the message length is truncated.
|
||||
// This should prevent the error from recurring if the exception is
|
||||
// logged to the database using dblog or the like.
|
||||
$message = Unicode::truncateBytes($e->getMessage(), self::MIN_MAX_ALLOWED_PACKET);
|
||||
$e = new DatabaseExceptionWrapper($message, $e->getCode(), $e->getPrevious());
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -278,6 +307,7 @@ class Connection extends DatabaseConnection {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -31,6 +31,27 @@ class Connection extends DatabaseConnection {
|
|||
*/
|
||||
const DATABASE_NOT_FOUND = 7;
|
||||
|
||||
/**
|
||||
* The list of PostgreSQL reserved key words.
|
||||
*
|
||||
* @see http://www.postgresql.org/docs/9.4/static/sql-keywords-appendix.html
|
||||
*/
|
||||
protected $postgresqlReservedKeyWords = ['all', 'analyse', 'analyze', 'and',
|
||||
'any', 'array', 'as', 'asc', 'asymmetric', 'authorization', 'binary', 'both',
|
||||
'case', 'cast', 'check', 'collate', 'collation', 'column', 'concurrently',
|
||||
'constraint', 'create', 'cross', 'current_catalog', 'current_date',
|
||||
'current_role', 'current_schema', 'current_time', 'current_timestamp',
|
||||
'current_user', 'default', 'deferrable', 'desc', 'distinct', 'do', 'else',
|
||||
'end', 'except', 'false', 'fetch', 'for', 'foreign', 'freeze', 'from', 'full',
|
||||
'grant', 'group', 'having', 'ilike', 'in', 'initially', 'inner', 'intersect',
|
||||
'into', 'is', 'isnull', 'join', 'lateral', 'leading', 'left', 'like', 'limit',
|
||||
'localtime', 'localtimestamp', 'natural', 'not', 'notnull', 'null', 'offset',
|
||||
'on', 'only', 'or', 'order', 'outer', 'over', 'overlaps', 'placing',
|
||||
'primary', 'references', 'returning', 'right', 'select', 'session_user',
|
||||
'similar', 'some', 'symmetric', 'table', 'then', 'to', 'trailing', 'true',
|
||||
'union', 'unique', 'user', 'using', 'variadic', 'verbose', 'when', 'where',
|
||||
'window', 'with'];
|
||||
|
||||
/**
|
||||
* Constructs a connection object.
|
||||
*/
|
||||
|
@ -167,6 +188,10 @@ class Connection extends DatabaseConnection {
|
|||
// Quote the field name for case-sensitivity.
|
||||
$escaped = '"' . $escaped . '"';
|
||||
}
|
||||
elseif (in_array(strtolower($escaped), $this->postgresqlReservedKeyWords)) {
|
||||
// Quote the field name for PostgreSQL reserved key words.
|
||||
$escaped = '"' . $escaped . '"';
|
||||
}
|
||||
|
||||
return $escaped;
|
||||
}
|
||||
|
@ -181,6 +206,10 @@ class Connection extends DatabaseConnection {
|
|||
if (preg_match('/[A-Z]/', $escaped)) {
|
||||
$escaped = '"' . $escaped . '"';
|
||||
}
|
||||
elseif (in_array(strtolower($escaped), $this->postgresqlReservedKeyWords)) {
|
||||
// Quote the alias name for PostgreSQL reserved key words.
|
||||
$escaped = '"' . $escaped . '"';
|
||||
}
|
||||
|
||||
return $escaped;
|
||||
}
|
||||
|
@ -195,6 +224,10 @@ class Connection extends DatabaseConnection {
|
|||
if (preg_match('/[A-Z]/', $escaped)) {
|
||||
$escaped = '"' . $escaped . '"';
|
||||
}
|
||||
elseif (in_array(strtolower($escaped), $this->postgresqlReservedKeyWords)) {
|
||||
// Quote the table name for PostgreSQL reserved key words.
|
||||
$escaped = '"' . $escaped . '"';
|
||||
}
|
||||
|
||||
return $escaped;
|
||||
}
|
||||
|
|
|
@ -117,6 +117,8 @@ class Insert extends QueryInsert {
|
|||
// Default fields are always placed first for consistency.
|
||||
$insert_fields = array_merge($this->defaultFields, $this->insertFields);
|
||||
|
||||
$insert_fields = array_map(function($f) { return $this->connection->escapeField($f); }, $insert_fields);
|
||||
|
||||
// If we're selecting from a SelectQuery, finish building the query and
|
||||
// pass it back, as any remaining options are irrelevant.
|
||||
if (!empty($this->fromQuery)) {
|
||||
|
@ -154,4 +156,5 @@ class Insert extends QueryInsert {
|
|||
|
||||
return $query;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ class Tasks extends InstallTasks {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function minimumVersion() {
|
||||
return '8.3';
|
||||
return '9.1.2';
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -329,7 +329,7 @@ class Schema extends DatabaseSchema {
|
|||
}
|
||||
|
||||
if (!empty($field['unsigned'])) {
|
||||
// Unsigned datatypes are not supported in PostgreSQL 8.3. In MySQL,
|
||||
// Unsigned datatypes are not supported in PostgreSQL 9.1. In MySQL,
|
||||
// they are used to ensure a positive number is inserted and it also
|
||||
// doubles the maximum integer size that can be stored in a field.
|
||||
// The PostgreSQL schema in Drupal creates a check constraint
|
||||
|
@ -569,7 +569,7 @@ class Schema extends DatabaseSchema {
|
|||
}
|
||||
|
||||
public function indexExists($table, $name) {
|
||||
// Details http://www.postgresql.org/docs/8.3/interactive/view-pg-indexes.html
|
||||
// Details http://www.postgresql.org/docs/9.1/interactive/view-pg-indexes.html
|
||||
$index_name = $this->ensureIdentifiersLength($table, $name, 'idx');
|
||||
// Remove leading and trailing quotes because the index name is in a WHERE
|
||||
// clause and not used as an identifier.
|
||||
|
|
|
@ -22,7 +22,7 @@ use Drupal\Core\Database\StatementInterface;
|
|||
class Statement extends StatementPrefetch implements StatementInterface {
|
||||
|
||||
/**
|
||||
* SQLite specific implementation of getStatement().
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* The PDO SQLite layer doesn't replace numeric placeholders in queries
|
||||
* correctly, and this makes numeric expressions (such as COUNT(*) >= :count)
|
||||
|
@ -87,6 +87,9 @@ class Statement extends StatementPrefetch implements StatementInterface {
|
|||
return $this->pdoConnection->prepare($query);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function execute($args = array(), $options = array()) {
|
||||
try {
|
||||
$return = parent::execute($args, $options);
|
||||
|
|
|
@ -17,6 +17,8 @@ use Drupal\Core\Database\Connection;
|
|||
*/
|
||||
class Delete extends Query implements ConditionInterface {
|
||||
|
||||
use QueryConditionTrait;
|
||||
|
||||
/**
|
||||
* The table from which to delete.
|
||||
*
|
||||
|
@ -24,15 +26,6 @@ class Delete extends Query implements ConditionInterface {
|
|||
*/
|
||||
protected $table;
|
||||
|
||||
/**
|
||||
* The condition object for this query.
|
||||
*
|
||||
* Condition handling is handled via composition.
|
||||
*
|
||||
* @var Condition
|
||||
*/
|
||||
protected $condition;
|
||||
|
||||
/**
|
||||
* Constructs a Delete object.
|
||||
*
|
||||
|
@ -51,82 +44,6 @@ class Delete extends Query implements ConditionInterface {
|
|||
$this->condition = new Condition('AND');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements Drupal\Core\Database\Query\ConditionInterface::condition().
|
||||
*/
|
||||
public function condition($field, $value = NULL, $operator = '=') {
|
||||
$this->condition->condition($field, $value, $operator);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements Drupal\Core\Database\Query\ConditionInterface::isNull().
|
||||
*/
|
||||
public function isNull($field) {
|
||||
$this->condition->isNull($field);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements Drupal\Core\Database\Query\ConditionInterface::isNotNull().
|
||||
*/
|
||||
public function isNotNull($field) {
|
||||
$this->condition->isNotNull($field);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements Drupal\Core\Database\Query\ConditionInterface::exists().
|
||||
*/
|
||||
public function exists(SelectInterface $select) {
|
||||
$this->condition->exists($select);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements Drupal\Core\Database\Query\ConditionInterface::notExists().
|
||||
*/
|
||||
public function notExists(SelectInterface $select) {
|
||||
$this->condition->notExists($select);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements Drupal\Core\Database\Query\ConditionInterface::conditions().
|
||||
*/
|
||||
public function &conditions() {
|
||||
return $this->condition->conditions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements Drupal\Core\Database\Query\ConditionInterface::arguments().
|
||||
*/
|
||||
public function arguments() {
|
||||
return $this->condition->arguments();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements Drupal\Core\Database\Query\ConditionInterface::where().
|
||||
*/
|
||||
public function where($snippet, $args = array()) {
|
||||
$this->condition->where($snippet, $args);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements Drupal\Core\Database\Query\ConditionInterface::compile().
|
||||
*/
|
||||
public function compile(Connection $connection, PlaceholderInterface $queryPlaceholder) {
|
||||
return $this->condition->compile($connection, $queryPlaceholder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements Drupal\Core\Database\Query\ConditionInterface::compiled().
|
||||
*/
|
||||
public function compiled() {
|
||||
return $this->condition->compiled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the DELETE query.
|
||||
*
|
||||
|
|
|
@ -49,6 +49,9 @@ use Drupal\Core\Database\IntegrityConstraintViolationException;
|
|||
* fields() and updateFields().
|
||||
*/
|
||||
class Merge extends Query implements ConditionInterface {
|
||||
|
||||
use QueryConditionTrait;
|
||||
|
||||
/**
|
||||
* Returned by execute() if an INSERT query has been executed.
|
||||
*/
|
||||
|
@ -339,82 +342,6 @@ class Merge extends Query implements ConditionInterface {
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements Drupal\Core\Database\Query\ConditionInterface::condition().
|
||||
*/
|
||||
public function condition($field, $value = NULL, $operator = '=') {
|
||||
$this->condition->condition($field, $value, $operator);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements Drupal\Core\Database\Query\ConditionInterface::isNull().
|
||||
*/
|
||||
public function isNull($field) {
|
||||
$this->condition->isNull($field);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements Drupal\Core\Database\Query\ConditionInterface::isNotNull().
|
||||
*/
|
||||
public function isNotNull($field) {
|
||||
$this->condition->isNotNull($field);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements Drupal\Core\Database\Query\ConditionInterface::exists().
|
||||
*/
|
||||
public function exists(SelectInterface $select) {
|
||||
$this->condition->exists($select);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements Drupal\Core\Database\Query\ConditionInterface::notExists().
|
||||
*/
|
||||
public function notExists(SelectInterface $select) {
|
||||
$this->condition->notExists($select);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements Drupal\Core\Database\Query\ConditionInterface::conditions().
|
||||
*/
|
||||
public function &conditions() {
|
||||
return $this->condition->conditions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements Drupal\Core\Database\Query\ConditionInterface::arguments().
|
||||
*/
|
||||
public function arguments() {
|
||||
return $this->condition->arguments();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements Drupal\Core\Database\Query\ConditionInterface::where().
|
||||
*/
|
||||
public function where($snippet, $args = array()) {
|
||||
$this->condition->where($snippet, $args);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements Drupal\Core\Database\Query\ConditionInterface::compile().
|
||||
*/
|
||||
public function compile(Connection $connection, PlaceholderInterface $queryPlaceholder) {
|
||||
return $this->condition->compile($connection, $queryPlaceholder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements Drupal\Core\Database\Query\ConditionInterface::compiled().
|
||||
*/
|
||||
public function compiled() {
|
||||
return $this->condition->compiled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements PHP magic __toString method to convert the query to a string.
|
||||
*
|
||||
|
|
|
@ -180,25 +180,4 @@ abstract class Query implements PlaceholderInterface {
|
|||
return $this->comments;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function conditionGroupFactory($conjunction = 'AND') {
|
||||
return new Condition($conjunction);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function andConditionGroup() {
|
||||
return $this->conditionGroupFactory('AND');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function orConditionGroup() {
|
||||
return $this->conditionGroupFactory('OR');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Reference in a new issue