Update to Drupal 8.2.0. For more information, see https://www.drupal.org/project/drupal/releases/8.2.0

This commit is contained in:
Pantheon Automation 2016-10-06 15:16:20 -07:00 committed by Greg Anderson
parent 2f563ab520
commit f1c8716f57
1732 changed files with 52334 additions and 11780 deletions

View file

@ -3,6 +3,7 @@
namespace Drupal\Component\Annotation\Plugin\Discovery;
use Drupal\Component\Annotation\AnnotationInterface;
use Drupal\Component\FileCache\FileCacheFactory;
use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
use Drupal\Component\Annotation\Reflection\MockFileFinder;
use Doctrine\Common\Annotations\SimpleAnnotationReader;
@ -48,6 +49,13 @@ class AnnotatedClassDiscovery implements DiscoveryInterface {
*/
protected $annotationNamespaces = [];
/**
* The file cache object.
*
* @var \Drupal\Component\FileCache\FileCacheInterface
*/
protected $fileCache;
/**
* Constructs a new instance.
*
@ -64,6 +72,10 @@ class AnnotatedClassDiscovery implements DiscoveryInterface {
$this->pluginNamespaces = $plugin_namespaces;
$this->pluginDefinitionAnnotationName = $plugin_definition_annotation_name;
$this->annotationNamespaces = $annotation_namespaces;
$file_cache_suffix = str_replace('\\', '_', $plugin_definition_annotation_name);
$file_cache_suffix .= ':' . hash('crc32b', serialize($annotation_namespaces));
$this->fileCache = FileCacheFactory::get('annotation_discovery:' . $file_cache_suffix);
}
/**
@ -110,6 +122,14 @@ class AnnotatedClassDiscovery implements DiscoveryInterface {
);
foreach ($iterator as $fileinfo) {
if ($fileinfo->getExtension() == 'php') {
if ($cached = $this->fileCache->get($fileinfo->getPathName())) {
if (isset($cached['id'])) {
// Explicitly unserialize this to create a new object instance.
$definitions[$cached['id']] = unserialize($cached['content']);
}
continue;
}
$sub_path = $iterator->getSubIterator()->getSubPath();
$sub_path = $sub_path ? str_replace(DIRECTORY_SEPARATOR, '\\', $sub_path) . '\\' : '';
$class = $namespace . '\\' . $sub_path . $fileinfo->getBasename('.php');
@ -123,7 +143,16 @@ class AnnotatedClassDiscovery implements DiscoveryInterface {
/** @var $annotation \Drupal\Component\Annotation\AnnotationInterface */
if ($annotation = $reader->getClassAnnotation($parser->getReflectionClass(), $this->pluginDefinitionAnnotationName)) {
$this->prepareAnnotationDefinition($annotation, $class);
$definitions[$annotation->getId()] = $annotation->get();
$id = $annotation->getId();
$content = $annotation->get();
$definitions[$id] = $content;
// Explicitly serialize this to create a new object instance.
$this->fileCache->set($fileinfo->getPathName(), ['id' => $id, 'content' => serialize($content)]);
}
else {
// Store a NULL object, so the file is not reparsed again.
$this->fileCache->set($fileinfo->getPathName(), [NULL]);
}
}
}

View file

@ -8,8 +8,9 @@
"php": ">=5.5.9",
"doctrine/common": "2.5.*",
"doctrine/annotations": "1.2.*",
"drupal/core-plugin": "~8.1",
"drupal/core-utility": "~8.1"
"drupal/core-fileCache": "~8.2",
"drupal/core-plugin": "~8.2",
"drupal/core-utility": "~8.2"
},
"autoload": {
"psr-4": {

View file

@ -1,41 +1,6 @@
<?php
/**
* @file
* Contains \Drupal\Component\Assertion\Handle.
*
* For PHP 5 this contains \AssertionError as well.
*/
namespace {
if (!class_exists('AssertionError', FALSE)) {
/**
* Emulates PHP 7 AssertionError as closely as possible.
*
* We force this class to exist at the root namespace for PHP 5.
* This class exists natively in PHP 7. Note that in PHP 7 it extends from
* Error, not Exception, but that isn't possible for PHP 5 - all exceptions
* must extend from exception.
*/
class AssertionError extends Exception {
/**
* {@inheritdoc}
*/
public function __construct($message = '', $code = 0, Exception $previous = NULL, $file = '', $line = 0) {
parent::__construct($message, $code, $previous);
// Preserve the filename and line number of the assertion failure.
$this->file = $file;
$this->line = $line;
}
}
}
}
namespace Drupal\Component\Assertion {
namespace Drupal\Component\Assertion;
/**
* Handler for runtime assertion failures.
@ -56,6 +21,9 @@ class Handle {
assert_options(ASSERT_WARNING, FALSE);
if (version_compare(PHP_VERSION, '7.0.0-dev') < 0) {
if (!class_exists('AssertionError', FALSE)) {
require __DIR__ . '/global_namespace_php5.php';
}
// PHP 5 - create a handler to throw the exception directly.
assert_options(ASSERT_CALLBACK, function($file = '', $line = 0, $code = '', $message = '') {
if (empty($message)) {
@ -71,5 +39,3 @@ class Handle {
}
}
}

View file

@ -108,7 +108,7 @@ class Inspector {
* Use this instead of is_string() alone unless the argument being an object
* in any way will cause a problem.
*
* @param mixed string
* @param mixed $string
* Variable to be examined
*
* @return bool

View file

@ -0,0 +1,28 @@
<?php
/**
* @file
* Contains PHP5 version of the \AssertionError class.
*/
/**
* Emulates PHP 7 AssertionError as closely as possible.
*
* This class is declared in the global namespace. It will only be included by
* \Drupal\Component\Assertion\Handle for PHP5 since this class exists natively
* in PHP 7. Note that in PHP 7 it extends from Error, not Exception, but that
* isn't possible for PHP 5 - all exceptions must extend from exception.
*/
class AssertionError extends Exception {
/**
* {@inheritdoc}
*/
public function __construct($message = '', $code = 0, Exception $previous = NULL, $file = '', $line = 0) {
parent::__construct($message, $code, $previous);
// Preserve the filename and line number of the assertion failure.
$this->file = $file;
$this->line = $line;
}
}

View file

@ -0,0 +1,32 @@
<?php
namespace Drupal\Component\ClassFinder;
use Doctrine\Common\Reflection\ClassFinderInterface;
/**
* A Utility class that uses active autoloaders to find a file for a class.
*/
class ClassFinder implements ClassFinderInterface {
/**
* {@inheritdoc}
*/
public function findFile($class) {
$loaders = spl_autoload_functions();
foreach ($loaders as $loader) {
if (is_array($loader) && isset($loader[0]) && is_object($loader[0]) && method_exists($loader[0], 'findFile')) {
$file = call_user_func_array([$loader[0], 'findFile'], [$class]);
// Different implementations return different empty values. For example,
// \Composer\Autoload\ClassLoader::findFile() returns FALSE whilst
// \Doctrine\Common\Reflection\ClassFinderInterface::findFile()
// documents that a NULL should be returned.
if (!empty($file)) {
return $file;
}
}
}
return NULL;
}
}

View 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.

View file

@ -0,0 +1,12 @@
The Drupal ClassFinder 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

View file

@ -0,0 +1,18 @@
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:
$ ./vendor/bin/phpunit -c core --group ClassFinder

View file

@ -0,0 +1,16 @@
{
"name": "drupal/core-class-finder",
"description": "This class provides a class finding utility.",
"keywords": ["drupal"],
"homepage": "https://www.drupal.org/project/drupal",
"license": "GPL-2.0+",
"require": {
"php": ">=5.5.9",
"doctrine/common": "2.5.*"
},
"autoload": {
"psr-4": {
"Drupal\\Component\\ClassFinder\\": ""
}
}
}

View file

@ -6,7 +6,7 @@
"license": "GPL-2.0+",
"require": {
"php": ">=5.5.9",
"drupal/core-utility": "~8.1"
"drupal/core-utility": "~8.2"
},
"autoload": {
"psr-4": {

View file

@ -440,7 +440,7 @@ class OptimizedPhpArrayDumper extends Dumper {
*
* @param string $id
* The ID of the service to get a reference for.
* @param \Symfony\Component\DependencyInjection\Reference|NULL $reference
* @param \Symfony\Component\DependencyInjection\Reference|null $reference
* (optional) The reference object to process; needed to get the invalid
* behavior value.
*

View file

@ -6,7 +6,7 @@
"license": "GPL-2.0+",
"require": {
"php": ">=5.5.9",
"drupal/utility": "~8.1"
"drupal/utility": "~8.2"
},
"autoload": {
"psr-4": {

View file

@ -61,7 +61,7 @@ class YamlDiscovery implements DiscoverableInterface {
foreach ($provider_by_files as $file => $provider) {
// If a file is empty or its contents are commented out, return an empty
// array instead of NULL for type consistency.
$all[$provider] = Yaml::decode(file_get_contents($file)) ?: [];
$all[$provider] = $this->decode($file);
$file_cache->set($file, $all[$provider]);
}
}
@ -69,6 +69,17 @@ class YamlDiscovery implements DiscoverableInterface {
return $all;
}
/**
* Decode a YAML file.
*
* @param string $file
* Yaml file path.
* @return array
*/
protected function decode($file) {
return Yaml::decode(file_get_contents($file)) ?: [];
}
/**
* Returns an array of file paths, keyed by provider.
*

View file

@ -6,8 +6,8 @@
"license": "GPL-2.0+",
"require": {
"php": ">=5.5.9",
"drupal/core-filecache": "~8.1",
"drupal/core-serialization": "~8.1"
"drupal/core-filecache": "~8.2",
"drupal/core-serialization": "~8.2"
},
"autoload": {
"psr-4": {

View file

@ -156,6 +156,35 @@ class ContainerAwareEventDispatcher implements EventDispatcherInterface {
return $result;
}
/**
* {@inheritdoc}
*/
public function getListenerPriority($eventName, $listener) {
// Parts copied from \Symfony\Component\EventDispatcher, that's why you see
// a yoda condition here.
if (!isset($this->listeners[$eventName])) {
return;
}
foreach ($this->listeners[$eventName] as $priority => $listeners) {
if (FALSE !== ($key = array_search(['callable' => $listener], $listeners, TRUE))) {
return $priority;
}
}
// Resolve service definitions if the listener has not been found so far.
foreach ($this->listeners[$eventName] as $priority => &$definitions) {
foreach ($definitions as $key => &$definition) {
if (!isset($definition['callable'])) {
// Once the callable is retrieved we keep it for subsequent method
// invocations on this class.
$definition['callable'] = [$this->container->get($definition['service'][0]), $definition['service'][1]];
if ($definition['callable'] === $listener) {
return $priority;
}
}
}
}
}
/**
* {@inheritdoc}
*/

View file

@ -7,6 +7,11 @@ namespace Drupal\Component\FileCache;
*/
class FileCacheFactory {
/**
* The configuration key to disable FileCache completely.
*/
const DISABLE_CACHE = 'file_cache_disable';
/**
* The configuration used to create FileCache objects.
*
@ -34,23 +39,35 @@ class FileCacheFactory {
* The initialized FileCache object.
*/
public static function get($collection, $default_configuration = []) {
$default_configuration += [
// If there is a special key in the configuration, disable FileCache completely.
if (!empty(static::$configuration[static::DISABLE_CACHE])) {
return new NullFileCache('', '');
}
$configuration = [];
// Check for a collection specific setting first.
if (isset(static::$configuration[$collection])) {
$configuration += static::$configuration[$collection];
}
// Then check if a default configuration has been provided.
if (!empty($default_configuration)) {
$configuration += $default_configuration;
}
// Last check if a default setting has been provided.
if (isset(static::$configuration['default'])) {
$configuration += static::$configuration['default'];
}
// Ensure that all properties are set.
$fallback_configuration = [
'class' => '\Drupal\Component\FileCache\FileCache',
'collection' => $collection,
'cache_backend_class' => NULL,
'cache_backend_configuration' => [],
];
$configuration = [];
if (isset(static::$configuration[$collection])) {
$configuration = static::$configuration[$collection];
}
elseif (isset(static::$configuration['default'])) {
$configuration = static::$configuration['default'];
}
// Add defaults to the configuration.
$configuration = $configuration + $default_configuration;
$configuration = $configuration + $fallback_configuration;
$class = $configuration['class'];
return new $class(static::getPrefix(), $configuration['collection'], $configuration['cache_backend_class'], $configuration['cache_backend_configuration']);

View file

@ -0,0 +1,46 @@
<?php
namespace Drupal\Component\FileSystem;
/**
* Provides file system functions.
*/
class FileSystem {
/**
* Discovers a writable system-appropriate temporary directory.
*
* @return string|false
* A string containing the path to the temporary directory, or FALSE if no
* suitable temporary directory can be found.
*/
public static function getOsTemporaryDirectory() {
$directories = array();
// Has PHP been set with an upload_tmp_dir?
if (ini_get('upload_tmp_dir')) {
$directories[] = ini_get('upload_tmp_dir');
}
// Operating system specific dirs.
if (substr(PHP_OS, 0, 3) == 'WIN') {
$directories[] = 'c:\\windows\\temp';
$directories[] = 'c:\\winnt\\temp';
}
else {
$directories[] = '/tmp';
}
// PHP may be able to find an alternative tmp directory.
$directories[] = sys_get_temp_dir();
foreach ($directories as $directory) {
if (is_dir($directory) && is_writable($directory)) {
// Both sys_get_temp_dir() and ini_get('upload_tmp_dir') can return paths
// with a trailing directory separator.
return rtrim($directory, DIRECTORY_SEPARATOR);
}
}
return FALSE;
}
}

View file

@ -169,7 +169,7 @@ class PoItem {
/**
* Create the PoItem from a structured array.
*
* @param array values
* @param array $values
*/
public function setFromArray(array $values = array()) {
if (isset($values['context'])) {

View file

@ -10,7 +10,7 @@
},
"require": {
"php": ">=5.5.9",
"drupal/core-utility": "~8.1"
"drupal/core-utility": "~8.2"
},
"autoload": {
"psr-4": {

View file

@ -80,7 +80,7 @@ interface PhpStorageInterface {
* @param string $name
* The virtual file name. Can be a relative path.
*
* @return string|FALSE
* @return string|false
* The full file path for the provided name. Return FALSE if the
* implementation needs to prevent access to the file.
*/

View file

@ -0,0 +1,18 @@
<?php
namespace Drupal\Component\Plugin;
/**
* Provides an interface for objects that depend on a plugin.
*/
interface PluginAwareInterface {
/**
* Sets the plugin for this object.
*
* @param \Drupal\Component\Plugin\PluginInspectionInterface $plugin
* The plugin.
*/
public function setPlugin(PluginInspectionInterface $plugin);
}

View file

@ -227,11 +227,18 @@ class FormattableMarkup implements MarkupInterface, \Countable {
default:
// We do not trigger an error for placeholder that start with an
// alphabetic character.
// @todo https://www.drupal.org/node/2807743 Change to an exception
// and always throw regardless of the first character.
if (!ctype_alpha($key[0])) {
// We trigger an error as we may want to introduce new placeholders
// in the future without breaking backward compatibility.
trigger_error('Invalid placeholder (' . $key . ') in string: ' . $string, E_USER_ERROR);
}
elseif (strpos($string, $key) !== FALSE) {
trigger_error('Invalid placeholder (' . $key . ') in string: ' . $string, E_USER_DEPRECATED);
}
// No replacement possible therefore we can discard the argument.
unset($args[$key]);
break;
}
}

View file

@ -6,7 +6,7 @@
"license": "GPL-2.0+",
"require": {
"php": ">=5.5.9",
"drupal/core-utility": "~8.1"
"drupal/core-utility": "~8.2"
},
"autoload": {
"psr-4": {

View file

@ -2,42 +2,37 @@
namespace Drupal\Component\Serialization;
use Drupal\Component\Serialization\Exception\InvalidDataTypeException;
use Symfony\Component\Yaml\Parser;
use Symfony\Component\Yaml\Dumper;
/**
* Default serialization for YAML using the Symfony component.
* Provides a YAML serialization implementation.
*
* Proxy implementation that will choose the best library based on availability.
*/
class Yaml implements SerializationInterface {
/**
* The YAML implementation to use.
*
* @var \Drupal\Component\Serialization\SerializationInterface
*/
protected static $serializer;
/**
* {@inheritdoc}
*/
public static function encode($data) {
try {
$yaml = new Dumper();
$yaml->setIndentation(2);
return $yaml->dump($data, PHP_INT_MAX, 0, TRUE, FALSE);
}
catch (\Exception $e) {
throw new InvalidDataTypeException($e->getMessage(), $e->getCode(), $e);
}
// Instead of using \Drupal\Component\Serialization\Yaml::getSerializer(),
// always using Symfony for writing the data, to reduce the risk of having
// differences if different environments (like production and development)
// do not match in terms of what YAML implementation is available.
return YamlSymfony::encode($data);
}
/**
* {@inheritdoc}
*/
public static function decode($raw) {
try {
$yaml = new Parser();
// Make sure we have a single trailing newline. A very simple config like
// 'foo: bar' with no newline will fail to parse otherwise.
return $yaml->parse($raw, TRUE, FALSE);
}
catch (\Exception $e) {
throw new InvalidDataTypeException($e->getMessage(), $e->getCode(), $e);
}
$serializer = static::getSerializer();
return $serializer::decode($raw);
}
/**
@ -47,4 +42,23 @@ class Yaml implements SerializationInterface {
return 'yml';
}
/**
* Determines which implementation to use for parsing YAML.
*/
protected static function getSerializer() {
if (!isset(static::$serializer)) {
// Use the PECL YAML extension if it is available. It has better
// performance for file reads and is YAML compliant.
if (extension_loaded('yaml')) {
static::$serializer = YamlPecl::class;
}
else {
// Otherwise, fallback to the Symfony implementation.
static::$serializer = YamlSymfony::class;
}
}
return static::$serializer;
}
}

View file

@ -0,0 +1,101 @@
<?php
namespace Drupal\Component\Serialization;
use Drupal\Component\Serialization\Exception\InvalidDataTypeException;
/**
* Provides default serialization for YAML using the PECL extension.
*/
class YamlPecl implements SerializationInterface {
/**
* {@inheritdoc}
*/
public static function encode($data) {
static $init;
if (!isset($init)) {
ini_set('yaml.output_indent', 2);
// Do not break lines at 80 characters.
ini_set('yaml.output_width', -1);
$init = TRUE;
}
return yaml_emit($data, YAML_UTF8_ENCODING, YAML_LN_BREAK);
}
/**
* {@inheritdoc}
*/
public static function decode($raw) {
// yaml_parse() will error with an empty value.
if (!trim($raw)) {
return NULL;
}
// @todo Use ErrorExceptions when https://drupal.org/node/1247666 is in.
// yaml_parse() will throw errors instead of raising an exception. Until
// such time as Drupal supports native PHP ErrorExceptions as the error
// handler, we need to temporarily set the error handler as ::errorHandler()
// and then restore it after decoding has occurred. This allows us to turn
// parsing errors into a throwable exception.
// @see Drupal\Component\Serialization\Exception\InvalidDataTypeException
// @see http://php.net/manual/en/class.errorexception.php
set_error_handler([__CLASS__, 'errorHandler']);
$ndocs = 0;
$data = yaml_parse($raw, 0, $ndocs, [
YAML_BOOL_TAG => '\Drupal\Component\Serialization\YamlPecl::applyBooleanCallbacks',
]);
restore_error_handler();
return $data;
}
/**
* Handles errors for \Drupal\Component\Serialization\YamlPecl::decode().
*
* @param int $severity
* The severity level of the error.
* @param string $message
* The error message to display.
*
* @see \Drupal\Component\Serialization\YamlPecl::decode()
*/
public static function errorHandler($severity, $message) {
restore_error_handler();
throw new InvalidDataTypeException($message, $severity);
}
/**
* {@inheritdoc}
*/
public static function getFileExtension() {
return 'yml';
}
/**
* Applies callbacks after parsing to ignore 1.1 style booleans.
*
* @param mixed $value
* Value from YAML file.
* @param string $tag
* Tag that triggered the callback.
* @param int $flags
* Scalar entity style flags.
*
* @return string|bool
* FALSE, false, TRUE and true are returned as booleans, everything else is
* returned as a string.
*/
public static function applyBooleanCallbacks($value, $tag, $flags) {
// YAML 1.1 spec dictates that 'Y', 'N', 'y' and 'n' are booleans. But, we
// want the 1.2 behavior, so we only consider 'false', 'FALSE', 'true' and
// 'TRUE' as booleans.
if (!in_array(strtolower($value), ['false', 'true'], TRUE)) {
return $value;
}
$map = [
'false' => FALSE,
'true' => TRUE,
];
return $map[strtolower($value)];
}
}

View file

@ -0,0 +1,50 @@
<?php
namespace Drupal\Component\Serialization;
use Drupal\Component\Serialization\Exception\InvalidDataTypeException;
use Symfony\Component\Yaml\Parser;
use Symfony\Component\Yaml\Dumper;
/**
* Default serialization for YAML using the Symfony component.
*/
class YamlSymfony implements SerializationInterface {
/**
* {@inheritdoc}
*/
public static function encode($data) {
try {
$yaml = new Dumper();
$yaml->setIndentation(2);
return $yaml->dump($data, PHP_INT_MAX, 0, TRUE, FALSE);
}
catch (\Exception $e) {
throw new InvalidDataTypeException($e->getMessage(), $e->getCode(), $e);
}
}
/**
* {@inheritdoc}
*/
public static function decode($raw) {
try {
$yaml = new Parser();
// Make sure we have a single trailing newline. A very simple config like
// 'foo: bar' with no newline will fail to parse otherwise.
return $yaml->parse($raw, TRUE, FALSE);
}
catch (\Exception $e) {
throw new InvalidDataTypeException($e->getMessage(), $e->getCode(), $e);
}
}
/**
* {@inheritdoc}
*/
public static function getFileExtension() {
return 'yml';
}
}

View file

@ -349,7 +349,7 @@ class NestedArray {
*
* @param array $array
* The filtered nested array.
* @param callable|NULL $callable
* @param callable|null $callable
* The callable to apply for filtering.
*
* @return array

View file

@ -9,6 +9,16 @@ namespace Drupal\Component\Utility;
*/
class OpCodeCache {
/**
* Checks if OpCodeCache is enabled.
*
* @return bool
* TRUE if opcache is enabled, FALSE otherwise.
*/
public static function isEnabled() {
return extension_loaded('Zend OPcache') && ini_get('opcache.enable');
}
/**
* Invalidates a PHP file from a possibly active opcode cache.
*

View file

@ -81,9 +81,9 @@ class SortArray {
* @return int
* The comparison result for uasort().
*/
public static function sortByTitleProperty($a, $b) {
return static::sortByKeyString($a, $b, '#title');
}
public static function sortByTitleProperty($a, $b) {
return static::sortByKeyString($a, $b, '#title');
}
/**
* Sorts a string array item by an arbitrary key.

View file

@ -224,6 +224,8 @@ class Xss {
$skip_protocol_filtering = substr($attribute_name, 0, 5) === 'data-' || in_array($attribute_name, array(
'title',
'alt',
'rel',
'property',
));
$working = $mode = 1;

View file

@ -7,7 +7,7 @@
"require": {
"php": ">=5.5.9",
"paragonie/random_compat": "~1.0",
"drupal/core-render": "~8.1"
"drupal/core-render": "~8.2"
},
"autoload": {
"psr-4": {

View file

@ -10,7 +10,7 @@
},
"require": {
"php": ">=5.5.9",
"drupal/core-utility": "~8.1"
"drupal/core-utility": "~8.2"
},
"autoload": {
"psr-4": {

View file

@ -51,11 +51,16 @@ abstract class AccessResult implements AccessResultInterface, RefinableCacheable
/**
* Creates an AccessResultInterface object with isForbidden() === TRUE.
*
* @param string|null $reason
* (optional) The reason why access is forbidden. Intended for developers,
* hence not translatable.
*
* @return \Drupal\Core\Access\AccessResult
* isForbidden() will be TRUE.
*/
public static function forbidden() {
return new AccessResultForbidden();
public static function forbidden($reason = NULL) {
assert('is_string($reason) || is_null($reason)');
return new AccessResultForbidden($reason);
}
/**
@ -334,8 +339,16 @@ abstract class AccessResult implements AccessResultInterface, RefinableCacheable
if ($this->isForbidden() || $other->isForbidden()) {
$result = static::forbidden();
if (!$this->isForbidden()) {
if ($other instanceof AccessResultReasonInterface) {
$result->setReason($other->getReason());
}
$merge_other = TRUE;
}
else {
if ($this instanceof AccessResultReasonInterface) {
$result->setReason($this->getReason());
}
}
}
elseif ($this->isAllowed() && $other->isAllowed()) {
$result = static::allowed();

View file

@ -5,7 +5,25 @@ namespace Drupal\Core\Access;
/**
* Value object indicating a forbidden access result, with cacheability metadata.
*/
class AccessResultForbidden extends AccessResult {
class AccessResultForbidden extends AccessResult implements AccessResultReasonInterface {
/**
* The reason why access is forbidden. For use in error messages.
*
* @var string|null
*/
protected $reason;
/**
* Constructs a new AccessResultForbidden instance.
*
* @param null|string $reason
* (optional) a message to provide details about this access result
*/
public function __construct($reason = NULL) {
$this->reason = $reason;
}
/**
* {@inheritdoc}
@ -14,4 +32,19 @@ class AccessResultForbidden extends AccessResult {
return TRUE;
}
/**
* {@inheritdoc}
*/
public function getReason() {
return $this->reason;
}
/**
* {@inheritdoc}
*/
public function setReason($reason) {
$this->reason = $reason;
return $this;
}
}

View file

@ -0,0 +1,36 @@
<?php
namespace Drupal\Core\Access;
/**
* Interface for access result value objects with stored reason for developers.
*
* For example, a developer can specify the reason for forbidden access:
* @code
* new AccessResultForbidden('You are not authorized to hack core');
* @endcode
*
* @see \Drupal\Core\Access\AccessResultInterface
*/
interface AccessResultReasonInterface extends AccessResultInterface {
/**
* Gets the reason for this access result.
*
* @return string|null
* The reason of this access result or NULL if no reason is provided.
*/
public function getReason();
/**
* Sets the reason for this access result.
*
* @param $reason string|null
* The reason of this access result or NULL if no reason is provided.
*
* @return \Drupal\Core\Access\AccessResultInterface
* The access result instance.
*/
public function setReason($reason);
}

View file

@ -3,14 +3,17 @@
namespace Drupal\Core\Access;
use Drupal\Core\Routing\Access\AccessInterface;
use Symfony\Component\DependencyInjection\ContainerAware;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerAwareTrait;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;
/**
* Loads access checkers from the container.
*/
class CheckProvider extends ContainerAware implements CheckProviderInterface {
class CheckProvider implements CheckProviderInterface, ContainerAwareInterface {
use ContainerAwareTrait;
/**
* Array of registered access check service ids.

View file

@ -0,0 +1,112 @@
<?php
namespace Drupal\Core\Access;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Session\SessionConfigurationInterface;
use Symfony\Component\Routing\Route;
use Symfony\Component\HttpFoundation\Request;
/**
* Access protection against CSRF attacks.
*/
class CsrfRequestHeaderAccessCheck implements AccessCheckInterface {
/**
* A string key that will used to designate the token used by this class.
*/
const TOKEN_KEY = 'X-CSRF-Token request header';
/**
* The session configuration.
*
* @var \Drupal\Core\Session\SessionConfigurationInterface
*/
protected $sessionConfiguration;
/**
* The token generator.
*
* @var \Drupal\Core\Access\CsrfTokenGenerator
*/
protected $csrfToken;
/**
* Constructs a new rest CSRF access check.
*
* @param \Drupal\Core\Session\SessionConfigurationInterface $session_configuration
* The session configuration.
* @param \Drupal\Core\Access\CsrfTokenGenerator $csrf_token
* The token generator.
*/
public function __construct(SessionConfigurationInterface $session_configuration, CsrfTokenGenerator $csrf_token) {
$this->sessionConfiguration = $session_configuration;
$this->csrfToken = $csrf_token;
}
/**
* {@inheritdoc}
*/
public function applies(Route $route) {
$requirements = $route->getRequirements();
// Check for current requirement _csrf_request_header_token and deprecated
// REST requirement.
$applicable_requirements = [
'_csrf_request_header_token',
// @todo Remove _access_rest_csrf in Drupal 9.0.0.
'_access_rest_csrf',
];
$requirement_keys = array_keys($requirements);
if (array_intersect($applicable_requirements, $requirement_keys)) {
if (isset($requirements['_method'])) {
// There could be more than one method requirement separated with '|'.
$methods = explode('|', $requirements['_method']);
// CSRF protection only applies to write operations, so we can filter
// out any routes that require reading methods only.
$write_methods = array_diff($methods, array('GET', 'HEAD', 'OPTIONS', 'TRACE'));
if (empty($write_methods)) {
return FALSE;
}
}
// No method requirement given, so we run this access check to be on the
// safe side.
return TRUE;
}
}
/**
* Checks access.
*
* @param \Symfony\Component\HttpFoundation\Request $request
* The request object.
* @param \Drupal\Core\Session\AccountInterface $account
* The currently logged in account.
*
* @return \Drupal\Core\Access\AccessResultInterface
* The access result.
*/
public function access(Request $request, AccountInterface $account) {
$method = $request->getMethod();
// This check only applies if
// 1. this is a write operation
// 2. the user was successfully authenticated and
// 3. the request comes with a session cookie.
if (!in_array($method, array('GET', 'HEAD', 'OPTIONS', 'TRACE'))
&& $account->isAuthenticated()
&& $this->sessionConfiguration->hasSession($request)
) {
$csrf_token = $request->headers->get('X-CSRF-Token');
// @todo Remove validate call using 'rest' in 8.3.
// Kept here for sessions active during update.
if (!$this->csrfToken->validate($csrf_token, self::TOKEN_KEY)
&& !$this->csrfToken->validate($csrf_token, 'rest')) {
return AccessResult::forbidden()->setReason('X-CSRF-Token request header is missing')->setCacheMaxAge(0);
}
}
// Let other access checkers decide if the request is legit.
return AccessResult::allowed()->setCacheMaxAge(0);
}
}

View file

@ -40,13 +40,13 @@ class CssCollectionOptimizer implements AssetCollectionOptimizerInterface {
/**
* Constructs a CssCollectionOptimizer.
*
* @param \Drupal\Core\Asset\AssetCollectionGrouperInterface
* @param \Drupal\Core\Asset\AssetCollectionGrouperInterface $grouper
* The grouper for CSS assets.
* @param \Drupal\Core\Asset\AssetOptimizerInterface
* @param \Drupal\Core\Asset\AssetOptimizerInterface $optimizer
* The optimizer for a single CSS asset.
* @param \Drupal\Core\Asset\AssetDumperInterface
* @param \Drupal\Core\Asset\AssetDumperInterface $dumper
* The dumper for optimized CSS assets.
* @param \Drupal\Core\State\StateInterface
* @param \Drupal\Core\State\StateInterface $state
* The state key/value store.
*/
public function __construct(AssetCollectionGrouperInterface $grouper, AssetOptimizerInterface $optimizer, AssetDumperInterface $dumper, StateInterface $state) {

View file

@ -63,7 +63,7 @@ class CssCollectionRenderer implements AssetCollectionRendererInterface {
/**
* Constructs a CssCollectionRenderer.
*
* @param \Drupal\Core\State\StateInterface
* @param \Drupal\Core\State\StateInterface $state
* The state key/value store.
*/
public function __construct(StateInterface $state) {

View file

@ -41,13 +41,13 @@ class JsCollectionOptimizer implements AssetCollectionOptimizerInterface {
/**
* Constructs a JsCollectionOptimizer.
*
* @param \Drupal\Core\Asset\AssetCollectionGrouperInterface
* @param \Drupal\Core\Asset\AssetCollectionGrouperInterface $grouper
* The grouper for JS assets.
* @param \Drupal\Core\Asset\AssetOptimizerInterface
* @param \Drupal\Core\Asset\AssetOptimizerInterface $optimizer
* The optimizer for a single JS asset.
* @param \Drupal\Core\Asset\AssetDumperInterface
* @param \Drupal\Core\Asset\AssetDumperInterface $dumper
* The dumper for optimized JS assets.
* @param \Drupal\Core\State\StateInterface
* @param \Drupal\Core\State\StateInterface $state
* The state key/value store.
*/
public function __construct(AssetCollectionGrouperInterface $grouper, AssetOptimizerInterface $optimizer, AssetDumperInterface $dumper, StateInterface $state) {

View file

@ -20,7 +20,7 @@ class JsCollectionRenderer implements AssetCollectionRendererInterface {
/**
* Constructs a JsCollectionRenderer.
*
* @param \Drupal\Core\State\StateInterface
* @param \Drupal\Core\State\StateInterface $state
* The state key/value store.
*/
public function __construct(StateInterface $state) {

View file

@ -39,7 +39,7 @@ interface LibraryDiscoveryInterface {
* @param string $name
* The name of a registered library to retrieve.
*
* @return array|FALSE
* @return array|false
* The definition of the requested library, if $name was passed and it
* exists, otherwise FALSE.
*/

View file

@ -7,9 +7,9 @@ use Drupal\Core\Asset\Exception\InvalidLibrariesOverrideSpecificationException;
use Drupal\Core\Asset\Exception\InvalidLibraryFileException;
use Drupal\Core\Asset\Exception\LibraryDefinitionMissingLicenseException;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Serialization\Yaml;
use Drupal\Core\Theme\ThemeManagerInterface;
use Drupal\Component\Serialization\Exception\InvalidDataTypeException;
use Drupal\Component\Serialization\Yaml;
use Drupal\Component\Utility\NestedArray;
/**

View file

@ -41,7 +41,7 @@ interface AuthenticationCollectorInterface {
* @param string $provider_id
* The provider ID.
*
* @return \Drupal\Core\Authentication\AuthenticationProviderInterface|NULL
* @return \Drupal\Core\Authentication\AuthenticationProviderInterface|null
* The authentication provider which matches the ID.
*/
public function getProvider($provider_id);

View file

@ -94,7 +94,7 @@ class AuthenticationManager implements AuthenticationProviderInterface, Authenti
* @param \Symfony\Component\HttpFoundation\Request $request
* The incoming request.
*
* @return string|NULL
* @return string|null
* The id of the first authentication provider which applies to the request.
* If no application detects appropriate credentials, then NULL is returned.
*/
@ -112,7 +112,7 @@ class AuthenticationManager implements AuthenticationProviderInterface, Authenti
* @param \Symfony\Component\HttpFoundation\Request $request
* The incoming request.
*
* @return string|NULL
* @return string|null
* The ID of the first authentication provider which applies to the request.
* If no application detects appropriate credentials, then NULL is returned.
*/

View file

@ -21,7 +21,7 @@ interface AuthenticationProviderChallengeInterface {
* @param \Exception $previous
* The previous exception.
*
* @return \Symfony\Component\HttpKernel\Exception\HttpExceptionInterface|NULL
* @return \Symfony\Component\HttpKernel\Exception\HttpExceptionInterface|null
* An exception to be used in order to generate an authentication challenge.
*/
public function challengeException(Request $request, \Exception $previous);

View file

@ -24,10 +24,10 @@ interface AuthenticationProviderInterface {
/**
* Authenticates the user.
*
* @param \Symfony\Component\HttpFoundation\Request|NULL $request
* @param \Symfony\Component\HttpFoundation\Request|null $request
* The request object.
*
* @return \Drupal\Core\Session\AccountInterface|NULL
* @return \Drupal\Core\Session\AccountInterface|null
* AccountInterface - in case of a successful authentication.
* NULL - in case where authentication failed.
*/

View file

@ -10,6 +10,8 @@ use Drupal\Core\Plugin\ContextAwarePluginBase;
use Drupal\Component\Utility\Unicode;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Plugin\PluginWithFormsInterface;
use Drupal\Core\Plugin\PluginWithFormsTrait;
use Drupal\Core\Session\AccountInterface;
use Drupal\Component\Transliteration\TransliterationInterface;
@ -22,9 +24,10 @@ use Drupal\Component\Transliteration\TransliterationInterface;
*
* @ingroup block_api
*/
abstract class BlockBase extends ContextAwarePluginBase implements BlockPluginInterface {
abstract class BlockBase extends ContextAwarePluginBase implements BlockPluginInterface, PluginWithFormsInterface {
use ContextAwarePluginAssignmentTrait;
use PluginWithFormsTrait;
/**
* The transliteration service.

View file

@ -148,7 +148,7 @@ class Cache {
/**
* Gets all cache bin services.
*
* @return array
* @return \Drupal\Core\Cache\CacheBackendInterface[]
* An array of cache backend objects keyed by cache bins.
*/
public static function getBins() {

View file

@ -64,16 +64,20 @@ class CacheFactory implements CacheFactoryInterface, ContainerAwareInterface {
*/
public function get($bin) {
$cache_settings = $this->settings->get('cache');
// First, look for a cache bin specific setting.
if (isset($cache_settings['bins'][$bin])) {
$service_name = $cache_settings['bins'][$bin];
}
elseif (isset($cache_settings['default'])) {
$service_name = $cache_settings['default'];
}
// Second, use the default backend specified by the cache bin.
elseif (isset($this->defaultBinBackends[$bin])) {
$service_name = $this->defaultBinBackends[$bin];
}
// Third, use configured default backend.
elseif (isset($cache_settings['default'])) {
$service_name = $cache_settings['default'];
}
else {
// Fall back to the database backend if nothing else is configured.
$service_name = 'cache.backend.database';
}
return $this->container->get($service_name)->get($bin);

View file

@ -87,16 +87,8 @@ class ChainedFastBackend implements CacheBackendInterface, CacheTagsInvalidatorI
* The fast cache backend.
* @param string $bin
* The cache bin for which the object is created.
*
* @throws \Exception
* When the consistent cache backend and the fast cache backend are the same
* service.
*/
public function __construct(CacheBackendInterface $consistent_backend, CacheBackendInterface $fast_backend, $bin) {
if ($consistent_backend == $fast_backend) {
// @todo: should throw a proper exception. See https://www.drupal.org/node/2751847.
trigger_error('Consistent cache backend and fast cache backend cannot use the same service.', E_USER_ERROR);
}
$this->consistentBackend = $consistent_backend;
$this->fastBackend = $fast_backend;
$this->bin = 'cache_' . $bin;

View file

@ -28,14 +28,14 @@ class ChainedFastBackendFactory implements CacheFactoryInterface {
/**
* Constructs ChainedFastBackendFactory object.
*
* @param \Drupal\Core\Site\Settings|NULL $settings
* @param \Drupal\Core\Site\Settings|null $settings
* (optional) The settings object.
* @param string|NULL $consistent_service_name
* @param string|null $consistent_service_name
* (optional) The service name of the consistent backend factory. Defaults
* to:
* - $settings->get('cache')['default'] (if specified)
* - 'cache.backend.database' (if the above isn't specified)
* @param string|NULL $fast_service_name
* @param string|null $fast_service_name
* (optional) The service name of the fast backend factory. Defaults to:
* - 'cache.backend.apcu' (if the PHP process has APCu enabled)
* - NULL (if the PHP process doesn't have APCu enabled)

View file

@ -3,7 +3,8 @@
namespace Drupal\Core\Cache\Context;
use Drupal\Core\Cache\CacheableMetadata;
use Symfony\Component\DependencyInjection\ContainerAware;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerAwareTrait;
/**
* Defines the MenuActiveTrailsCacheContext service.
@ -11,7 +12,9 @@ use Symfony\Component\DependencyInjection\ContainerAware;
* 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 {
class MenuActiveTrailsCacheContext implements CalculatedCacheContextInterface, ContainerAwareInterface {
use ContainerAwareTrait;
/**
* {@inheritdoc}

View file

@ -0,0 +1,35 @@
<?php
namespace Drupal\Core\Cache;
/**
* Trait to implement CacheableDependencyInterface for uncacheable objects.
*
* Use this for objects that are never cacheable.
*
* @see \Drupal\Core\Cache\CacheableDependencyInterface
*/
trait UncacheableDependencyTrait {
/**
* {@inheritdoc}
*/
public function getCacheContexts() {
return [];
}
/**
* {@inheritdoc}
*/
public function getCacheTags() {
return [];
}
/**
* {@inheritdoc}
*/
public function getCacheMaxAge() {
return 0;
}
}

View file

@ -33,7 +33,7 @@ class DbDumpCommand extends DbCommandBase {
*
* @var array
*/
protected $excludeTables = ['simpletest.+'];
protected $excludeTables = ['test[0-9]+'];
/**
* {@inheritdoc}

View file

@ -196,7 +196,7 @@ EOT;
* @param string $package_name
* The package name from composer. This is always already lower case.
*
* @return NULL|string
* @return string|null
* The string key, or NULL if none was found.
*/
protected static function findPackageKey($package_name) {

View file

@ -26,8 +26,9 @@ trait ConditionAccessResolverTrait {
$pass = $condition->execute();
}
catch (ContextException $e) {
// If a condition is missing context, consider that a fail.
$pass = FALSE;
// If a condition is missing context and is not negated, consider that a
// fail.
$pass = $condition->isNegated();
}
// If a condition fails and all conditions were needed, deny access.

View file

@ -5,6 +5,7 @@ namespace Drupal\Core\Condition;
use Drupal\Core\Executable\ExecutableManagerInterface;
use Drupal\Core\Executable\ExecutablePluginBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Form\SubformStateInterface;
use Drupal\Core\Plugin\ContextAwarePluginAssignmentTrait;
/**
@ -47,6 +48,9 @@ abstract class ConditionPluginBase extends ExecutablePluginBase implements Condi
* {@inheritdoc}
*/
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
if ($form_state instanceof SubformStateInterface) {
$form_state = $form_state->getCompleteFormState();
}
$contexts = $form_state->getTemporaryValue('gathered_contexts') ?: [];
$form['context_mapping'] = $this->addContextAssignmentElement($this, $contexts);
$form['negate'] = array(
@ -68,6 +72,9 @@ abstract class ConditionPluginBase extends ExecutablePluginBase implements Condi
*/
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
$this->configuration['negate'] = $form_state->getValue('negate');
if ($form_state->hasValue('context_mapping')) {
$this->setContextMapping($form_state->getValue('context_mapping'));
}
}
/**

View file

@ -24,7 +24,7 @@ class ConfigCollectionInfo extends Event {
*
* @param string $collection
* Collection name to add.
* @param \Drupal\Core\Config\ConfigFactoryOverrideInterface
* @param \Drupal\Core\Config\ConfigFactoryOverrideInterface $override_service
* (optional) The configuration factory override service responsible for the
* collection.
*
@ -63,7 +63,7 @@ class ConfigCollectionInfo extends Event {
* @param string $collection
* The configuration collection.
*
* @return \Drupal\Core\Config\ConfigFactoryOverrideInterface|NULL
* @return \Drupal\Core\Config\ConfigFactoryOverrideInterface|null
* The override service responsible for the collection if one exists. NULL
* if not.
*/

View file

@ -19,7 +19,7 @@ class ConfigCrudEvent extends Event {
/**
* Constructs a configuration event object.
*
* @param \Drupal\Core\Config\Config
* @param \Drupal\Core\Config\Config $config
* Configuration object.
*/
public function __construct(Config $config) {

View file

@ -511,6 +511,7 @@ class ConfigInstaller implements ConfigInstallerInterface {
* TRUE if the dependencies are met, FALSE if not.
*/
protected function validateDependencies($config_name, array $data, array $enabled_extensions, array $all_config) {
list($provider) = explode('.', $config_name, 2);
if (isset($data['dependencies'])) {
$all_dependencies = $data['dependencies'];
@ -521,7 +522,6 @@ class ConfigInstaller implements ConfigInstallerInterface {
}
// Ensure the configuration entity type provider is in the list of
// dependencies.
list($provider) = explode('.', $config_name, 2);
if (!isset($all_dependencies['module'])) {
$all_dependencies['module'][] = $provider;
}
@ -548,6 +548,10 @@ class ConfigInstaller implements ConfigInstallerInterface {
}
}
}
else {
// Simple config or a config entity without dependencies.
return in_array($provider, $enabled_extensions, TRUE);
}
return TRUE;
}

View file

@ -40,7 +40,7 @@ interface ConfigInstallerInterface {
* - it's a configuration entity.
* - its dependencies can be met.
*
* @param \Drupal\Core\Config\StorageInterface
* @param \Drupal\Core\Config\StorageInterface $storage
* (optional) The configuration storage to search for optional
* configuration. If not provided, all enabled extension's optional
* configuration directories will be searched.

View file

@ -3,12 +3,12 @@
namespace Drupal\Core\Config;
use Drupal\Component\Diff\Diff;
use Drupal\Component\Serialization\Yaml;
use Drupal\Core\Config\Entity\ConfigDependencyManager;
use Drupal\Core\Config\Entity\ConfigEntityInterface;
use Drupal\Core\Config\Entity\ConfigEntityTypeInterface;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Serialization\Yaml;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\StringTranslation\TranslationInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;

View file

@ -37,7 +37,7 @@ class ConfigModuleOverridesEvent extends Event {
*
* @param array $names
* A list of configuration names.
* @param \Drupal\Core\Language\LanguageInterface
* @param \Drupal\Core\Language\LanguageInterface $language
* (optional) The language for this configuration.
*/
public function __construct(array $names, LanguageInterface $language = NULL) {

View file

@ -174,10 +174,34 @@ class ConfigDependencyManager {
// always after field storages. This is because field storages need to be
// created before a field.
$graph = $this->getGraph();
uasort($graph, array($this, 'sortGraph'));
$sorts = $this->prepareMultisort($graph, ['weight', 'name']);
array_multisort($sorts['weight'], SORT_DESC, SORT_NUMERIC, $sorts['name'], SORT_ASC, SORT_NATURAL | SORT_FLAG_CASE, $graph);
return array_replace(array_intersect_key($graph, $dependencies), $dependencies);
}
/**
* Extracts data from the graph for use in array_multisort().
*
* @param array $graph
* The graph to extract data from.
* @param array $keys
* The keys whose values to extract.
*
* @return
* An array keyed by the $keys passed in. The values are arrays keyed by the
* row from the graph and the value is the corresponding value for the key
* from the graph.
*/
protected function prepareMultisort($graph, $keys) {
$return = array_fill_keys($keys, []);
foreach ($graph as $graph_key => $graph_row) {
foreach ($keys as $key) {
$return[$key][$graph_key] = $graph_row[$key];
}
}
return $return;
}
/**
* Sorts the dependencies in order of most dependent last.
*
@ -189,7 +213,8 @@ class ConfigDependencyManager {
$graph = $this->getGraph();
// Sort by weight and alphabetically. The most dependent entities
// are last and entities with the same weight are alphabetically ordered.
uasort($graph, array($this, 'sortGraphByWeight'));
$sorts = $this->prepareMultisort($graph, ['weight', 'name']);
array_multisort($sorts['weight'], SORT_ASC, SORT_NUMERIC, $sorts['name'], SORT_ASC, SORT_NATURAL | SORT_FLAG_CASE, $graph);
// Use array_intersect_key() to exclude modules and themes from the list.
return array_keys(array_intersect_key($graph, $this->data));
}
@ -197,6 +222,10 @@ class ConfigDependencyManager {
/**
* Sorts the dependency graph by weight and alphabetically.
*
* @deprecated in Drupal 8.2.0, will be removed before Drupal 9.0.0. Use
* \Drupal\Core\Config\Entity\ConfigDependencyManager::prepareMultisort() and
* array_multisort() instead.
*
* @param array $a
* First item for comparison. The compared items should be associative
* arrays that include a 'weight' and a 'name' key.
@ -218,6 +247,10 @@ class ConfigDependencyManager {
/**
* Sorts the dependency graph by reverse weight and alphabetically.
*
* @deprecated in Drupal 8.2.0, will be removed before Drupal 9.0.0. Use
* \Drupal\Core\Config\Entity\ConfigDependencyManager::prepareMultisort() and
* array_multisort() instead.
*
* @param array $a
* First item for comparison. The compared items should be associative
* arrays that include a 'weight' and a 'name' key.

View file

@ -65,7 +65,7 @@ interface ConfigEntityTypeInterface extends EntityTypeInterface {
/**
* Gets the config entity properties to export if declared on the annotation.
*
* @return array|NULL
* @return array|null
* The properties to export or NULL if they can not be determine from the
* config entity type annotation.
*/

View file

@ -135,7 +135,7 @@ abstract class DraggableListBuilder extends ConfigEntityListBuilder implements F
$form['actions']['#type'] = 'actions';
$form['actions']['submit'] = array(
'#type' => 'submit',
'#value' => t('Save order'),
'#value' => t('Save'),
'#button_type' => 'primary',
);

View file

@ -66,8 +66,8 @@ class QueryFactory implements QueryFactoryInterface, EventSubscriberInterface {
/**
* {@inheritdoc}
*/
public function getAggregate(EntityTypeInterface $entity_type, $conjunction) {
throw new QueryException('Aggregation over configuration entities is not supported');
public function getAggregate(EntityTypeInterface $entity_type, $conjunction) {
throw new QueryException('Aggregation over configuration entities is not supported');
}
/**
@ -189,7 +189,7 @@ class QueryFactory implements QueryFactoryInterface, EventSubscriberInterface {
* @param int $start
* Which position of $parts we are processing. Defaults to 0.
*
* @return array|NULL
* @return array|null
* The array of configuration values the match the provided key. NULL if
* the configuration object does not have a value that corresponds to the
* key.

View file

@ -44,9 +44,8 @@ class ExtensionInstallStorage extends InstallStorage {
* search and to get overrides from.
*/
public function __construct(StorageInterface $config_storage, $directory = self::CONFIG_INSTALL_DIRECTORY, $collection = StorageInterface::DEFAULT_COLLECTION, $include_profile = TRUE) {
parent::__construct($directory, $collection);
$this->configStorage = $config_storage;
$this->directory = $directory;
$this->collection = $collection;
$this->includeProfile = $include_profile;
}

View file

@ -2,8 +2,9 @@
namespace Drupal\Core\Config;
use Drupal\Component\Serialization\Yaml;
use Drupal\Component\FileCache\FileCacheFactory;
use Drupal\Component\Serialization\Exception\InvalidDataTypeException;
use Drupal\Core\Serialization\Yaml;
/**
* Defines the file storage.
@ -24,6 +25,13 @@ class FileStorage implements StorageInterface {
*/
protected $directory = '';
/**
* The file cache object.
*
* @var \Drupal\Component\FileCache\FileCacheInterface
*/
protected $fileCache;
/**
* Constructs a new FileStorage.
*
@ -36,6 +44,11 @@ class FileStorage implements StorageInterface {
public function __construct($directory, $collection = StorageInterface::DEFAULT_COLLECTION) {
$this->directory = $directory;
$this->collection = $collection;
// Use a NULL File Cache backend by default. This will ensure only the
// internal statc caching of FileCache is used and thus avoids blowing up
// the APCu cache.
$this->fileCache = FileCacheFactory::get('config', ['cache_backend_class' => NULL]);
}
/**
@ -90,7 +103,12 @@ class FileStorage implements StorageInterface {
if (!$this->exists($name)) {
return FALSE;
}
$filepath = $this->getFilePath($name);
if ($data = $this->fileCache->get($filepath)) {
return $data;
}
$data = file_get_contents($filepath);
try {
$data = $this->decode($data);
@ -98,6 +116,8 @@ class FileStorage implements StorageInterface {
catch (InvalidDataTypeException $e) {
throw new UnsupportedDataTypeConfigException('Invalid data type in config ' . $name . ', found in file' . $filepath . ' : ' . $e->getMessage());
}
$this->fileCache->set($filepath, $data);
return $data;
}
@ -119,18 +139,18 @@ class FileStorage implements StorageInterface {
*/
public function write($name, array $data) {
try {
$data = $this->encode($data);
$encoded_data = $this->encode($data);
}
catch (InvalidDataTypeException $e) {
throw new StorageException("Invalid data type in config $name: {$e->getMessage()}");
}
$target = $this->getFilePath($name);
$status = @file_put_contents($target, $data);
$status = @file_put_contents($target, $encoded_data);
if ($status === FALSE) {
// Try to make sure the directory exists and try writing again.
$this->ensureStorage();
$status = @file_put_contents($target, $data);
$status = @file_put_contents($target, $encoded_data);
}
if ($status === FALSE) {
throw new StorageException('Failed to write configuration file: ' . $this->getFilePath($name));
@ -138,6 +158,9 @@ class FileStorage implements StorageInterface {
else {
drupal_chmod($target);
}
$this->fileCache->set($target, $data);
return TRUE;
}
@ -152,6 +175,7 @@ class FileStorage implements StorageInterface {
}
return FALSE;
}
$this->fileCache->delete($this->getFilePath($name));
return drupal_unlink($this->getFilePath($name));
}
@ -163,6 +187,8 @@ class FileStorage implements StorageInterface {
if ($status === FALSE) {
throw new StorageException('Failed to rename configuration file from: ' . $this->getFilePath($name) . ' to: ' . $this->getFilePath($new_name));
}
$this->fileCache->delete($this->getFilePath($name));
$this->fileCache->delete($this->getFilePath($new_name));
return TRUE;
}

View file

@ -58,8 +58,7 @@ class InstallStorage extends FileStorage {
* default collection.
*/
public function __construct($directory = self::CONFIG_INSTALL_DIRECTORY, $collection = StorageInterface::DEFAULT_COLLECTION) {
$this->directory = $directory;
$this->collection = $collection;
parent::__construct($directory, $collection);
}
/**

View file

@ -3,6 +3,7 @@
namespace Drupal\Core\Controller;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Logger\LoggerChannelTrait;
use Drupal\Core\Routing\LinkGeneratorTrait;
use Drupal\Core\Routing\RedirectDestinationTrait;
use Drupal\Core\Routing\UrlGeneratorTrait;
@ -33,6 +34,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
abstract class ControllerBase implements ContainerInjectionInterface {
use LinkGeneratorTrait;
use LoggerChannelTrait;
use RedirectDestinationTrait;
use StringTranslationTrait;
use UrlGeneratorTrait;
@ -107,13 +109,6 @@ abstract class ControllerBase implements ContainerInjectionInterface {
*/
protected $formBuilder;
/**
* The logger factory.
*
* @var \Psr\Log\LoggerInterface
*/
protected $loggerFactory;
/**
* {@inheritdoc}
*/
@ -284,23 +279,6 @@ abstract class ControllerBase implements ContainerInjectionInterface {
return $this->languageManager;
}
/**
* Returns a channel logger object.
*
* @param string $channel
* The name of the channel. Can be any string, but the general practice is
* to use the name of the subsystem calling this.
*
* @return \Psr\Log\LoggerInterface
* The logger for this channel.
*/
protected function getLogger($channel) {
if (!$this->loggerFactory) {
$this->loggerFactory = $this->container()->get('logger.factory');
}
return $this->loggerFactory->get($channel);
}
/**
* Returns the service container.
*

View file

@ -4,7 +4,9 @@ namespace Drupal\Core;
use Drupal\Core\Cache\Context\CacheContextsPass;
use Drupal\Core\Cache\ListCacheBinsPass;
use Drupal\Core\DependencyInjection\Compiler\AuthenticationProviderPass;
use Drupal\Core\DependencyInjection\Compiler\BackendCompilerPass;
use Drupal\Core\DependencyInjection\Compiler\CorsCompilerPass;
use Drupal\Core\DependencyInjection\Compiler\GuzzleMiddlewarePass;
use Drupal\Core\DependencyInjection\Compiler\ContextProvidersPass;
use Drupal\Core\DependencyInjection\Compiler\ProxyServicesPass;
@ -15,6 +17,7 @@ use Drupal\Core\DependencyInjection\Compiler\StackedKernelPass;
use Drupal\Core\DependencyInjection\Compiler\StackedSessionHandlerPass;
use Drupal\Core\DependencyInjection\Compiler\RegisterStreamWrappersPass;
use Drupal\Core\DependencyInjection\Compiler\TwigExtensionPass;
use Drupal\Core\DependencyInjection\ServiceModifierInterface;
use Drupal\Core\DependencyInjection\ServiceProviderInterface;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\DependencyInjection\Compiler\ModifyServiceDefinitionsPass;
@ -39,12 +42,12 @@ use Symfony\Component\DependencyInjection\Compiler\PassConfig;
*
* @ingroup container
*/
class CoreServiceProvider implements ServiceProviderInterface {
class CoreServiceProvider implements ServiceProviderInterface, ServiceModifierInterface {
/**
* {@inheritdoc}
*/
public function register(ContainerBuilder $container) {
$this->registerUuid($container);
$this->registerTest($container);
// Only register the private file stream wrapper if a file path has been set.
@ -62,6 +65,8 @@ class CoreServiceProvider implements ServiceProviderInterface {
$container->addCompilerPass(new BackendCompilerPass());
$container->addCompilerPass(new CorsCompilerPass());
$container->addCompilerPass(new StackedKernelPass());
$container->addCompilerPass(new StackedSessionHandlerPass());
@ -89,6 +94,7 @@ class CoreServiceProvider implements ServiceProviderInterface {
$container->addCompilerPass(new ListCacheBinsPass());
$container->addCompilerPass(new CacheContextsPass());
$container->addCompilerPass(new ContextProvidersPass());
$container->addCompilerPass(new AuthenticationProviderPass());
// Register plugin managers.
$container->addCompilerPass(new PluginManagerPass());
@ -97,30 +103,23 @@ class CoreServiceProvider implements ServiceProviderInterface {
}
/**
* Determines and registers the UUID service.
* Alters the UUID service to use the most efficient method available.
*
* @param \Drupal\Core\DependencyInjection\ContainerBuilder $container
* The container builder.
*
* @return string
* Class name for the UUID service.
*/
public static function registerUuid(ContainerBuilder $container) {
$uuid_class = 'Drupal\Component\Uuid\Php';
public function alter(ContainerBuilder $container) {
$uuid_service = $container->getDefinition('uuid');
// Debian/Ubuntu uses the (broken) OSSP extension as their UUID
// implementation. The OSSP implementation is not compatible with the
// PECL functions.
if (function_exists('uuid_create') && !function_exists('uuid_make')) {
$uuid_class = 'Drupal\Component\Uuid\Pecl';
$uuid_service->setClass('Drupal\Component\Uuid\Pecl');
}
// Try to use the COM implementation for Windows users.
elseif (function_exists('com_create_guid')) {
$uuid_class = 'Drupal\Component\Uuid\Com';
$uuid_service->setClass('Drupal\Component\Uuid\Com');
}
$container->register('uuid', $uuid_class);
return $uuid_class;
}
/**

View file

@ -2,6 +2,7 @@
namespace Drupal\Core;
use Drupal\Component\Utility\Timer;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Queue\QueueWorkerManagerInterface;
use Drupal\Core\Queue\RequeueException;
@ -82,7 +83,7 @@ class Cron implements CronInterface {
* The account switching service.
* @param \Psr\Log\LoggerInterface $logger
* A logger instance.
* @param \Drupal\Core\Queue\QueueWorkerManagerInterface
* @param \Drupal\Core\Queue\QueueWorkerManagerInterface $queue_manager
* The queue plugin manager.
*/
public function __construct(ModuleHandlerInterface $module_handler, LockBackendInterface $lock, QueueFactory $queue_factory, StateInterface $state, AccountSwitcherInterface $account_switcher, LoggerInterface $logger, QueueWorkerManagerInterface $queue_manager) {
@ -193,8 +194,25 @@ class Cron implements CronInterface {
* Invokes any cron handlers implementing hook_cron.
*/
protected function invokeCronHandlers() {
$module_previous = '';
// Iterate through the modules calling their cron handlers (if any):
foreach ($this->moduleHandler->getImplementations('cron') as $module) {
if (!$module_previous) {
$this->logger->notice('Starting execution of @module_cron().', [
'@module' => $module,
]);
}
else {
$this->logger->notice('Starting execution of @module_cron(), execution of @module_previous_cron() took @time.', [
'@module' => $module,
'@module_previous' => $module_previous,
'@time' => Timer::read('cron_' . $module_previous) . 'ms',
]);
}
Timer::start('cron_' . $module);
// Do not let an exception thrown by one module disturb another.
try {
$this->moduleHandler->invoke($module, 'cron');
@ -202,6 +220,15 @@ class Cron implements CronInterface {
catch (\Exception $e) {
watchdog_exception('cron', $e);
}
Timer::stop('cron_' . $module);
$module_previous = $module;
}
if ($module_previous) {
$this->logger->notice('Execution of @module_previous_cron() took @time.', [
'@module_previous' => $module_previous,
'@time' => Timer::read('cron_' . $module_previous) . 'ms',
]);
}
}

View file

@ -129,7 +129,7 @@ abstract class Database {
*/
final public static function getLog($logging_key, $key = 'default') {
if (empty(self::$logs[$key])) {
return NULL;
return [];
}
$queries = self::$logs[$key]->get($logging_key);
self::$logs[$key]->end($logging_key);

View file

@ -411,6 +411,11 @@ class Schema extends DatabaseSchema {
->fields(array($field => $spec['initial']))
->execute();
}
if (isset($spec['initial_from_field'])) {
$this->connection->update($table)
->expression($field, $spec['initial_from_field'])
->execute();
}
if ($fixnull) {
$spec['not null'] = TRUE;
$this->changeField($table, $field, $field, $spec);

View file

@ -210,13 +210,8 @@ class Connection extends DatabaseConnection {
// need to be escaped.
$escaped = $this->escapeTable($table) . '.' . $this->escapeAlias($column);
}
elseif (preg_match('/[A-Z]/', $escaped)) {
// 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 . '"';
else {
$escaped = $this->doEscape($escaped);
}
return $escaped;
@ -227,16 +222,7 @@ class Connection extends DatabaseConnection {
*/
public function escapeAlias($field) {
$escaped = preg_replace('/[^A-Za-z0-9_]+/', '', $field);
// Escape the alias in quotes for case-sensitivity.
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 . '"';
}
$escaped = $this->doEscape($escaped);
return $escaped;
}
@ -246,18 +232,35 @@ class Connection extends DatabaseConnection {
public function escapeTable($table) {
$escaped = parent::escapeTable($table);
// Quote identifier to make it case-sensitive.
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 . '"';
}
// Ensure that each part (database, schema and table) of the table name is
// properly and independently escaped.
$parts = explode('.', $escaped);
$parts = array_map([$this, 'doEscape'], $parts);
$escaped = implode('.', $parts);
return $escaped;
}
/**
* Escape a string if needed.
*
* @param $string
* The string to escape.
* @return string
* The escaped string.
*/
protected function doEscape($string) {
// Quote identifier to make it case-sensitive.
if (preg_match('/[A-Z]/', $string)) {
$string = '"' . $string . '"';
}
elseif (in_array(strtolower($string), $this->postgresqlReservedKeyWords)) {
// Quote the string for PostgreSQL reserved key words.
$string = '"' . $string . '"';
}
return $string;
}
public function driver() {
return 'pgsql';
}

View file

@ -65,7 +65,7 @@ class Tasks extends InstallTasks {
$this->pass('Drupal can CONNECT to the database ok.');
}
catch (\Exception $e) {
// Attempt to create the database if it is not found.
// Attempt to create the database if it is not found.
if ($e->getCode() == Connection::DATABASE_NOT_FOUND) {
// Remove the database string from connection info.
$connection_info = Database::getConnectionInfo();

View file

@ -531,6 +531,11 @@ class Schema extends DatabaseSchema {
->fields(array($field => $spec['initial']))
->execute();
}
if (isset($spec['initial_from_field'])) {
$this->connection->update($table)
->expression($field, $spec['initial_from_field'])
->execute();
}
if ($fixnull) {
$this->connection->query("ALTER TABLE {" . $table . "} ALTER $field SET NOT NULL");
}

View file

@ -124,6 +124,16 @@ class Connection extends DatabaseConnection {
// Create a user-space case-insensitive collation with UTF-8 support.
$pdo->sqliteCreateCollation('NOCASE_UTF8', array('Drupal\Component\Utility\Unicode', 'strcasecmp'));
// Set SQLite init_commands if not already defined. Enable the Write-Ahead
// Logging (WAL) for SQLite. See https://www.drupal.org/node/2348137 and
// https://www.sqlite.org/wal.html.
$connection_options += array(
'init_commands' => array(),
);
$connection_options['init_commands'] += array(
'wal' => "PRAGMA journal_mode=WAL",
);
// Execute sqlite init_commands.
if (isset($connection_options['init_commands'])) {
$pdo->exec(implode('; ', $connection_options['init_commands']));

View file

@ -316,6 +316,11 @@ class Schema extends DatabaseSchema {
->fields(array($field => $specification['initial']))
->execute();
}
if (isset($specification['initial_from_field'])) {
$this->connection->update($table)
->expression($field, $specification['initial_from_field'])
->execute();
}
}
else {
// We cannot add the field directly. Use the slower table alteration
@ -335,6 +340,13 @@ class Schema extends DatabaseSchema {
'arguments' => array(':newfieldinitial' => $specification['initial']),
);
}
elseif (isset($specification['initial_from_field'])) {
// If we have a initial value, copy it over.
$mapping[$field] = array(
'expression' => $specification['initial_from_field'],
'arguments' => [],
);
}
else {
// Else use the default of the field.
$mapping[$field] = NULL;

View file

@ -300,6 +300,7 @@ class Condition implements ConditionInterface, \Countable {
// $specials does not use drupal_static as its value never changes.
static $specials = array(
'BETWEEN' => array('delimiter' => ' AND '),
'NOT BETWEEN' => array('delimiter' => ' AND '),
'IN' => array('delimiter' => ', ', 'prefix' => ' (', 'postfix' => ')'),
'NOT IN' => array('delimiter' => ', ', 'prefix' => ' (', 'postfix' => ')'),
'EXISTS' => array('prefix' => ' (', 'postfix' => ')'),

View file

@ -340,6 +340,12 @@ interface SelectInterface extends ConditionInterface, AlterableInterface, Extend
* An array of arguments to replace into the $condition of this join.
* @return
* The unique alias that was assigned for this table.
*
* @deprecated as of Drupal 8.1.x, will be removed in Drupal 9.0.0. Instead,
* change the query to use leftJoin(). For instance:
* db_query('A')->rightJoin('B') is identical to
* db_query('B')->leftJoin('A'). This functionality has been deprecated
* because SQLite does not support it.
*/
public function rightJoin($table, $alias = NULL, $condition = NULL, $arguments = array());

View file

@ -305,6 +305,8 @@ abstract class Schema implements PlaceholderInterface {
* created field will be set to the value of the key in all rows.
* This is most useful for creating NOT NULL columns with no default
* value in existing tables.
* Alternatively, the 'initial_form_field' key may be used, which will
* auto-populate the new field with values from the specified field.
* @param $keys_new
* (optional) Keys and indexes specification to be created on the
* table along with adding the field. The format is the same as a

View file

@ -90,7 +90,7 @@ interface StatementInterface extends \Traversable {
* If $mode is PDO::FETCH_CLASS, the optional arguments to pass to the
* constructor.
*/
public function setFetchMode($mode, $a1 = NULL, $a2 = array());
public function setFetchMode($mode, $a1 = NULL, $a2 = array());
/**
* Fetches the next row from a result set.
@ -109,7 +109,7 @@ interface StatementInterface extends \Traversable {
* @return
* A result, formatted according to $mode.
*/
public function fetch($mode = NULL, $cursor_orientation = NULL, $cursor_offset = NULL);
public function fetch($mode = NULL, $cursor_orientation = NULL, $cursor_offset = NULL);
/**
* Returns a single field from the next record of a result set.
@ -128,7 +128,7 @@ interface StatementInterface extends \Traversable {
* The object will be of the class specified by StatementInterface::setFetchMode()
* or stdClass if not specified.
*/
public function fetchObject();
public function fetchObject();
/**
* Fetches the next row and returns it as an associative array.
@ -155,7 +155,7 @@ interface StatementInterface extends \Traversable {
* @return
* An array of results.
*/
function fetchAll($mode = NULL, $column_index = NULL, $constructor_arguments = NULL);
function fetchAll($mode = NULL, $column_index = NULL, $constructor_arguments = NULL);
/**
* Returns an entire single column of a result set as an indexed array.

View file

@ -150,7 +150,7 @@ class Datetime extends DateElementBase {
* list of the possible formats and HTML5 standards for the HTML5
* requirements. Defaults to the right HTML5 format for the chosen element
* if a HTML5 element is used, otherwise defaults to
* entity_load('date_format', 'html_date')->getPattern().
* DateFormat::load('html_date')->getPattern().
* - #date_date_element: The date element. Options are:
* - datetime: Use the HTML5 datetime element type.
* - datetime-local: Use the HTML5 datetime-local element type.
@ -170,7 +170,7 @@ class Datetime extends DateElementBase {
* a list of the possible formats and HTML5 standards for the HTML5
* requirements. Defaults to the right HTML5 format for the chosen element
* if a HTML5 element is used, otherwise defaults to
* entity_load('date_format', 'html_time')->getPattern().
* DateFormat::load('html_time')->getPattern().
* - #date_time_callbacks: An array of optional callbacks for the time
* element. Can be used to add a jQuery timepicker or an 'All day' checkbox.
* - #date_year_range: A description of the range of years to allow, like

View file

@ -0,0 +1,27 @@
<?php
namespace Drupal\Core\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
/**
* Registers the authentication_providers container parameter.
*/
class AuthenticationProviderPass implements CompilerPassInterface {
/**
* {@inheritdoc}
*/
public function process(ContainerBuilder $container) {
$authentication_providers = [];
foreach ($container->findTaggedServiceIds('authentication_provider') as $service_id => $attributes) {
$authentication_provider = $attributes[0]['provider_id'];
if ($provider_tag = $container->getDefinition($service_id)->getTag('_provider')) {
$authentication_providers[$authentication_provider] = $provider_tag[0]['provider'];
}
}
$container->setParameter('authentication_providers', $authentication_providers);
}
}

View file

@ -0,0 +1,31 @@
<?php
namespace Drupal\Core\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
/**
* Provides a compiler pass which disables the CORS middleware in case disabled.
*
* @see core.services.yml
*/
class CorsCompilerPass implements CompilerPassInterface {
/**
* {@inheritdoc}
*/
public function process(ContainerBuilder $container) {
$enabled = FALSE;
if ($cors_config = $container->getParameter('cors.config')) {
$enabled = !empty($cors_config['enabled']);
}
// Remove the CORS middleware completly in case it was not enabled.
if (!$enabled) {
$container->removeDefinition('http_middleware.cors');
}
}
}

View file

@ -14,7 +14,7 @@ class Container extends DrupalContainer {
* {@inheritdoc}
*/
public function set($id, $service, $scope = ContainerInterface::SCOPE_CONTAINER) {
parent::set($id, $service, $scope);
parent::set($id, $service, $scope);
// Ensure that the _serviceId property is set on synthetic services as well.
if (isset($this->services[$id]) && is_object($this->services[$id]) && !isset($this->services[$id]->_serviceId)) {

View file

@ -7,11 +7,7 @@ use Symfony\Component\DependencyInjection\ContainerBuilder as SymfonyContainerBu
use Symfony\Component\DependencyInjection\Container as SymfonyContainer;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\LazyProxy\Instantiator\RealServiceInstantiator;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Exception\InactiveScopeException;
/**
* Drupal's dependency injection container builder.
@ -35,129 +31,6 @@ class ContainerBuilder extends SymfonyContainerBuilder {
parent::__construct($parameterBag);
}
/**
* Creates a service for a service definition.
*
* Overrides the parent implementation, but just changes one line about
* deprecations, see below.
*
* @param \Symfony\Component\DependencyInjection\Definition $definition
* @param string $id
* @param bool|true $tryProxy
*
* @return mixed|object
*/
public function createService(Definition $definition, $id, $tryProxy = true)
{
if ($definition->isSynthetic()) {
throw new RuntimeException(sprintf('You have requested a synthetic service ("%s"). The DIC does not know how to construct this service.', $id));
}
if ($definition->isDeprecated()) {
// Suppress deprecation warnings when a service is marked as
// 'deprecated: %service_id%-no-warning'
if ($definition->getDeprecationMessage($id) != ($id . '-no-warning')) {
@trigger_error($definition->getDeprecationMessage($id), E_USER_DEPRECATED);
}
}
if ($tryProxy && $definition->isLazy()) {
$container = $this;
$proxy = $this
->getProxyInstantiator()
->instantiateProxy(
$container,
$definition,
$id, function () use ($definition, $id, $container) {
return $container->createService($definition, $id, false);
}
);
$this->shareService($definition, $proxy, $id);
return $proxy;
}
$parameterBag = $this->getParameterBag();
if (null !== $definition->getFile()) {
require_once $parameterBag->resolveValue($definition->getFile());
}
$arguments = $this->resolveServices($parameterBag->unescapeValue($parameterBag->resolveValue($definition->getArguments())));
if (null !== $factory = $definition->getFactory()) {
if (is_array($factory)) {
$factory = array($this->resolveServices($parameterBag->resolveValue($factory[0])), $factory[1]);
} elseif (!is_string($factory)) {
throw new RuntimeException(sprintf('Cannot create service "%s" because of invalid factory', $id));
}
$service = call_user_func_array($factory, $arguments);
if (!$definition->isDeprecated() && is_array($factory) && is_string($factory[0])) {
$r = new \ReflectionClass($factory[0]);
if (0 < strpos($r->getDocComment(), "\n * @deprecated ")) {
@trigger_error(sprintf('The "%s" service relies on the deprecated "%s" factory class. It should either be deprecated or its factory upgraded.', $id, $r->name), E_USER_DEPRECATED);
}
}
} elseif (null !== $definition->getFactoryMethod(false)) {
if (null !== $definition->getFactoryClass(false)) {
$factory = $parameterBag->resolveValue($definition->getFactoryClass(false));
} elseif (null !== $definition->getFactoryService(false)) {
$factory = $this->get($parameterBag->resolveValue($definition->getFactoryService(false)));
} else {
throw new RuntimeException(sprintf('Cannot create service "%s" from factory method without a factory service or factory class.', $id));
}
$service = call_user_func_array(array($factory, $definition->getFactoryMethod(false)), $arguments);
} else {
$r = new \ReflectionClass($parameterBag->resolveValue($definition->getClass()));
$service = null === $r->getConstructor() ? $r->newInstance() : $r->newInstanceArgs($arguments);
if (!$definition->isDeprecated() && 0 < strpos($r->getDocComment(), "\n * @deprecated ")) {
// Skip deprecation notices for deprecations which opt out.
@trigger_error(sprintf('The "%s" service relies on the deprecated "%s" class. It should either be deprecated or its implementation upgraded.', $id, $r->name), E_USER_DEPRECATED);
}
}
if ($tryProxy || !$definition->isLazy()) {
// share only if proxying failed, or if not a proxy
$this->shareService($definition, $service, $id);
}
foreach ($definition->getMethodCalls() as $call) {
$this->callMethod($service, $call);
}
$properties = $this->resolveServices($parameterBag->unescapeValue($parameterBag->resolveValue($definition->getProperties())));
foreach ($properties as $name => $value) {
$service->$name = $value;
}
if ($callable = $definition->getConfigurator()) {
if (is_array($callable)) {
$callable[0] = $parameterBag->resolveValue($callable[0]);
if ($callable[0] instanceof Reference) {
$callable[0] = $this->get((string) $callable[0], $callable[0]->getInvalidBehavior());
} elseif ($callable[0] instanceof Definition) {
$callable[0] = $this->createService($callable[0], null);
}
}
if (!is_callable($callable)) {
throw new InvalidArgumentException(sprintf('The configure callable for class "%s" is not a callable.', get_class($service)));
}
call_user_func($callable, $service);
}
return $service;
}
/**
* Retrieves the currently set proxy instantiator or instantiates one.
*

View file

@ -4,7 +4,7 @@
namespace Drupal\Core\DependencyInjection;
use Drupal\Component\FileCache\FileCacheFactory;
use Drupal\Component\Serialization\Yaml;
use Drupal\Core\Serialization\Yaml;
use Symfony\Component\DependencyInjection\Alias;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Definition;
@ -111,7 +111,16 @@ class YamlFileLoader
throw new InvalidArgumentException(sprintf('The "services" key should contain an array in %s. Check your YAML syntax.', $file));
}
// Some extensions split up their dependencies into multiple files.
if (isset($content['_provider'])) {
$provider = $content['_provider'];
}
else {
$basename = basename($file);
list($provider, ) = explode('.', $basename, 2);
}
foreach ($content['services'] as $id => $service) {
$service['tags'][] = ['name' => '_provider', 'provider' => $provider];
$this->parseDefinition($id, $service, $file);
}
}

View file

@ -0,0 +1,22 @@
<?php
namespace Drupal\Core\Discovery;
use Drupal\Component\Discovery\YamlDiscovery as ComponentYamlDiscovery;
use Drupal\Core\Serialization\Yaml;
/**
* Provides discovery for YAML files within a given set of directories.
*
* This overrides the Component file decoding with the Core YAML implementation.
*/
class YamlDiscovery extends ComponentYamlDiscovery {
/**
* {@inheritdoc}
*/
protected function decode($file) {
return Yaml::decode(file_get_contents($file)) ?: [];
}
}

View file

@ -2,6 +2,7 @@
namespace Drupal\Core;
use Composer\Autoload\ClassLoader;
use Drupal\Component\Assertion\Handle;
use Drupal\Component\FileCache\FileCacheFactory;
use Drupal\Component\Utility\Unicode;
@ -18,6 +19,7 @@ use Drupal\Core\File\MimeType\MimeTypeGuesser;
use Drupal\Core\Http\TrustedHostsRequestFactory;
use Drupal\Core\Language\Language;
use Drupal\Core\Site\Settings;
use Drupal\Core\Test\TestDatabase;
use Symfony\Cmf\Component\Routing\RouteObjectInterface;
use Symfony\Component\ClassLoader\ApcClassLoader;
use Symfony\Component\DependencyInjection\ContainerInterface;
@ -248,15 +250,18 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface {
* @param bool $allow_dumping
* (optional) FALSE to stop the container from being written to or read
* from disk. Defaults to TRUE.
* @param string $app_root
* (optional) The path to the application root as a string. If not supplied,
* the application root will be computed.
*
* @return static
*
* @throws \Symfony\Component\HttpKernel\Exception\BadRequestHttpException
* In case the host name in the request is not trusted.
*/
public static function createFromRequest(Request $request, $class_loader, $environment, $allow_dumping = TRUE) {
$kernel = new static($environment, $class_loader, $allow_dumping);
static::bootEnvironment();
public static function createFromRequest(Request $request, $class_loader, $environment, $allow_dumping = TRUE, $app_root = NULL) {
$kernel = new static($environment, $class_loader, $allow_dumping, $app_root);
static::bootEnvironment($app_root);
$kernel->initializeSettings($request);
return $kernel;
}
@ -273,12 +278,28 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface {
* @param bool $allow_dumping
* (optional) FALSE to stop the container from being written to or read
* from disk. Defaults to TRUE.
* @param string $app_root
* (optional) The path to the application root as a string. If not supplied,
* the application root will be computed.
*/
public function __construct($environment, $class_loader, $allow_dumping = TRUE) {
public function __construct($environment, $class_loader, $allow_dumping = TRUE, $app_root = NULL) {
$this->environment = $environment;
$this->classLoader = $class_loader;
$this->allowDumping = $allow_dumping;
$this->root = dirname(dirname(substr(__DIR__, 0, -strlen(__NAMESPACE__))));
if ($app_root === NULL) {
$app_root = static::guessApplicationRoot();
}
$this->root = $app_root;
}
/**
* Determine the application root directory based on assumptions.
*
* @return string
* The application root.
*/
protected static function guessApplicationRoot() {
return dirname(dirname(substr(__DIR__, 0, -strlen(__NAMESPACE__))));
}
/**
@ -320,6 +341,9 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface {
* Defaults to TRUE. During initial installation, this is set to FALSE so
* that Drupal can detect a matching directory, then create a new
* settings.php file in it.
* @param string $app_root
* (optional) The path to the application root as a string. If not supplied,
* the application root will be computed.
*
* @return string
* The path of the matching directory.
@ -332,18 +356,23 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface {
* @see default.settings.php
* @see example.sites.php
*/
public static function findSitePath(Request $request, $require_settings = TRUE) {
public static function findSitePath(Request $request, $require_settings = TRUE, $app_root = NULL) {
if (static::validateHostname($request) === FALSE) {
throw new BadRequestHttpException();
}
if ($app_root === NULL) {
$app_root = static::guessApplicationRoot();
}
// Check for a simpletest override.
if ($test_prefix = drupal_valid_test_ua()) {
return 'sites/simpletest/' . substr($test_prefix, 10);
$test_db = new TestDatabase($test_prefix);
return $test_db->getTestSitePath();
}
// Determine whether multi-site functionality is enabled.
if (!file_exists(DRUPAL_ROOT . '/sites/sites.php')) {
if (!file_exists($app_root . '/sites/sites.php')) {
return 'sites/default';
}
@ -355,17 +384,17 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface {
$http_host = $request->getHttpHost();
$sites = array();
include DRUPAL_ROOT . '/sites/sites.php';
include $app_root . '/sites/sites.php';
$uri = explode('/', $script_name);
$server = explode('.', implode('.', array_reverse(explode(':', rtrim($http_host, '.')))));
for ($i = count($uri) - 1; $i > 0; $i--) {
for ($j = count($server); $j > 0; $j--) {
$dir = implode('.', array_slice($server, -$j)) . implode('.', array_slice($uri, 0, $i));
if (isset($sites[$dir]) && file_exists(DRUPAL_ROOT . '/sites/' . $sites[$dir])) {
if (isset($sites[$dir]) && file_exists($app_root . '/sites/' . $sites[$dir])) {
$dir = $sites[$dir];
}
if (file_exists(DRUPAL_ROOT . '/sites/' . $dir . '/settings.php') || (!$require_settings && file_exists(DRUPAL_ROOT . '/sites/' . $dir))) {
if (file_exists($app_root . '/sites/' . $dir . '/settings.php') || (!$require_settings && file_exists($app_root . '/sites/' . $dir))) {
return "sites/$dir";
}
}
@ -417,11 +446,6 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface {
// Provide a default configuration, if not set.
if (!isset($configuration['default'])) {
$configuration['default'] = [
'class' => '\Drupal\Component\FileCache\FileCache',
'cache_backend_class' => NULL,
'cache_backend_configuration' => [],
];
// @todo Use extension_loaded('apcu') for non-testbot
// https://www.drupal.org/node/2447753.
if (function_exists('apcu_fetch')) {
@ -733,6 +757,10 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface {
* needed.
*/
public function updateModules(array $module_list, array $module_filenames = array()) {
$pre_existing_module_namespaces = [];
if ($this->booted && is_array($this->moduleList)) {
$pre_existing_module_namespaces = $this->getModuleNamespacesPsr4($this->getModuleFileNames());
}
$this->moduleList = $module_list;
foreach ($module_filenames as $name => $extension) {
$this->moduleData[$name] = $extension;
@ -745,6 +773,20 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface {
// container in order to refresh the serviceProvider list and container.
$this->containerNeedsRebuild = TRUE;
if ($this->booted) {
// We need to register any new namespaces to a new class loader because
// the current class loader might have stored a negative result for a
// class that is now available.
// @see \Composer\Autoload\ClassLoader::findFile()
$new_namespaces = array_diff_key(
$this->getModuleNamespacesPsr4($this->getModuleFileNames()),
$pre_existing_module_namespaces
);
if (!empty($new_namespaces)) {
$additional_class_loader = new ClassLoader();
$this->classLoaderAddMultiplePsr4($new_namespaces, $additional_class_loader);
$additional_class_loader->register();
}
$this->initializeContainer();
}
}
@ -877,15 +919,23 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface {
*
* This method sets PHP environment options we want to be sure are set
* correctly for security or just saneness.
*
* @param string $app_root
* (optional) The path to the application root as a string. If not supplied,
* the application root will be computed.
*/
public static function bootEnvironment() {
public static function bootEnvironment($app_root = NULL) {
if (static::$isEnvironmentInitialized) {
return;
}
// Determine the application root if it's not supplied.
if ($app_root === NULL) {
$app_root = static::guessApplicationRoot();
}
// Include our bootstrap file.
$core_root = dirname(dirname(dirname(__DIR__)));
require_once $core_root . '/includes/bootstrap.inc';
require_once $app_root . '/core/includes/bootstrap.inc';
// Enforce E_STRICT, but allow users to set levels not part of E_STRICT.
error_reporting(E_STRICT | E_ALL);
@ -915,6 +965,7 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface {
// Indicate that code is operating in a test child site.
if (!defined('DRUPAL_TEST_IN_CHILD_SITE')) {
if ($test_prefix = drupal_valid_test_ua()) {
$test_db = new TestDatabase($test_prefix);
// Only code that interfaces directly with tests should rely on this
// constant; e.g., the error/exception handler conditionally adds further
// error information into HTTP response headers that are consumed by
@ -929,7 +980,7 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface {
// Log fatal errors to the test site directory.
ini_set('log_errors', 1);
ini_set('error_log', DRUPAL_ROOT . '/sites/simpletest/' . substr($test_prefix, 10) . '/error.log');
ini_set('error_log', $app_root . '/' . $test_db->getTestSitePath() . '/error.log');
// Ensure that a rewritten settings.php is used if opcache is on.
ini_set('opcache.validate_timestamps', 'on');
@ -1193,7 +1244,8 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface {
// be automatically reinstantiated. Also include services tagged to persist.
$persist_ids = array();
foreach ($container->getDefinitions() as $id => $definition) {
if ($definition->isSynthetic() || $definition->getTag('persist')) {
// It does not make sense to persist the container itself, exclude it.
if ($id !== 'service_container' && ($definition->isSynthetic() || $definition->getTag('persist'))) {
$persist_ids[] = $id;
}
}
@ -1349,8 +1401,15 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface {
* Array where each key is a namespace like 'Drupal\system', and each value
* is either a PSR-4 base directory, or an array of PSR-4 base directories
* associated with this namespace.
* @param object $class_loader
* The class loader. Normally \Composer\Autoload\ClassLoader, as included by
* the front controller, but may also be decorated; e.g.,
* \Symfony\Component\ClassLoader\ApcClassLoader.
*/
protected function classLoaderAddMultiplePsr4(array $namespaces = array()) {
protected function classLoaderAddMultiplePsr4(array $namespaces = array(), $class_loader = NULL) {
if ($class_loader === NULL) {
$class_loader = $this->classLoader;
}
foreach ($namespaces as $prefix => $paths) {
if (is_array($paths)) {
foreach ($paths as $key => $value) {
@ -1360,7 +1419,7 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface {
elseif (is_string($paths)) {
$paths = $this->root . '/' . $paths;
}
$this->classLoader->addPsr4($prefix . '\\', $paths);
$class_loader->addPsr4($prefix . '\\', $paths);
}
}

View file

@ -58,7 +58,7 @@ interface DrupalKernelInterface extends HttpKernelInterface, ContainerAwareInter
*
* This also allows inspecting a built container for debugging purposes.
*
* @return array|NULL
* @return array|null
* The cached container definition or NULL if not found in cache.
*/
public function getCachedContainerDefinition();

View file

@ -436,6 +436,13 @@ abstract class ContentEntityStorageBase extends EntityStorageBase implements Con
$result = [];
$args = array_slice(func_get_args(), 2);
$langcodes = array_keys($entity->getTranslationLanguages());
// Ensure that the field method is invoked as first on the current entity
// translation and then on all other translations.
$current_entity_langcode = $entity->language()->getId();
if (reset($langcodes) != $current_entity_langcode) {
$langcodes = array_diff($langcodes, [$current_entity_langcode]);
array_unshift($langcodes, $current_entity_langcode);
}
foreach ($langcodes as $langcode) {
$translation = $entity->getTranslation($langcode);
// For non translatable fields, there is only one field object instance

View file

@ -5,6 +5,7 @@ namespace Drupal\Core\Entity;
use Drupal\Core\Extension\ModuleUninstallValidatorInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\StringTranslation\TranslationInterface;
use Drupal\Core\Url;
/**
* Validates module uninstall readiness based on existing content entities.
@ -37,10 +38,14 @@ class ContentUninstallValidator implements ModuleUninstallValidatorInterface {
*/
public function validate($module) {
$entity_types = $this->entityManager->getDefinitions();
$reasons = array();
$reasons = [];
foreach ($entity_types as $entity_type) {
if ($module == $entity_type->getProvider() && $entity_type instanceof ContentEntityTypeInterface && $this->entityManager->getStorage($entity_type->id())->hasData()) {
$reasons[] = $this->t('There is content for the entity type: @entity_type', array('@entity_type' => $entity_type->getLabel()));
$reasons[] = $this->t('There is content for the entity type: @entity_type. <a href=":url">Remove @entity_type_plural</a>.', [
'@entity_type' => $entity_type->getLabel(),
'@entity_type_plural' => $entity_type->getPluralLabel(),
':url' => Url::fromRoute('system.prepare_modules_entity_uninstall', ['entity_type_id' => $entity_type->id()])->toString(),
]);
}
}
return $reasons;

View file

@ -273,7 +273,7 @@ class EntityController implements ContainerInjectionInterface {
* (optional) The entity, set in
* \Drupal\Core\Entity\Enhancer\EntityRouteEnhancer.
*
* @return \Drupal\Core\Entity\EntityInterface|NULL
* @return \Drupal\Core\Entity\EntityInterface|null
* The entity, if it is passed in directly or if the first parameter of the
* active route is an entity; otherwise, NULL.
*/

View file

@ -346,8 +346,8 @@ class EntityAccessControlHandler extends EntityHandlerBase implements EntityAcce
* is checked for the field definition, without any specific value
* available. Defaults to NULL.
*
* @return bool
* TRUE if access is allowed, FALSE otherwise.
* @return \Drupal\Core\Access\AccessResultInterface
* The access result.
*/
protected function checkFieldAccess($operation, FieldDefinitionInterface $field_definition, AccountInterface $account, FieldItemListInterface $items = NULL) {
return AccessResult::allowed();

View file

@ -10,7 +10,9 @@ use Symfony\Component\DependencyInjection\ContainerAwareTrait;
/**
* Provides a wrapper around many other services relating to entities.
*
* @deprecated in Drupal 8.0.0, will be removed before Drupal 9.0.0.
* Deprecated in Drupal 8.0.0, will be removed before Drupal 9.0.0. We cannot
* use the deprecated PHPDoc tag because this service class is still used in
* legacy code paths. Symfony would fail test cases with deprecation warnings.
*
* @todo Enforce the deprecation of each method once
* https://www.drupal.org/node/2578361 is in.

Some files were not shown because too many files have changed in this diff Show more