updated core to 8.6.3

This commit is contained in:
2018-11-21 12:49:46 +01:00
parent 8ca34853a3
commit c92c348eee
521 changed files with 12199 additions and 4578 deletions
Generated
+6 -6
View File
@@ -1639,16 +1639,16 @@
},
{
"name": "drupal/core",
"version": "8.6.2",
"version": "8.6.3",
"source": {
"type": "git",
"url": "https://github.com/drupal/core.git",
"reference": "356292934802bb1aecc478e88a3cba77442d7c62"
"reference": "9e9a1dd9e280ebaf10622217e54448b529167965"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/drupal/core/zipball/356292934802bb1aecc478e88a3cba77442d7c62",
"reference": "356292934802bb1aecc478e88a3cba77442d7c62",
"url": "https://api.github.com/repos/drupal/core/zipball/9e9a1dd9e280ebaf10622217e54448b529167965",
"reference": "9e9a1dd9e280ebaf10622217e54448b529167965",
"shasum": ""
},
"require": {
@@ -1814,7 +1814,7 @@
"jcalderonzumba/gastonjs": "^1.0.2",
"jcalderonzumba/mink-phantomjs-driver": "^0.3.1",
"mikey179/vfsstream": "^1.2",
"phpspec/prophecy": "^1.4",
"phpspec/prophecy": "^1.7",
"phpunit/phpunit": "^4.8.35 || ^6.5",
"symfony/css-selector": "^3.4.0",
"symfony/debug": "^3.4.0",
@@ -1873,7 +1873,7 @@
"GPL-2.0-or-later"
],
"description": "Drupal is an open source content management platform powering millions of websites and applications.",
"time": "2018-10-17T22:19:50+00:00"
"time": "2018-11-07T14:45:40+00:00"
},
{
"name": "drush/drush",
+4 -1
View File
@@ -11,7 +11,10 @@
"no-duplicate-selectors": null,
"no-unknown-animations": true,
"media-feature-name-no-unknown": [true, {
"ignoreMediaFeatureNames": ["prefers-reduced-motion"]
"ignoreMediaFeatureNames": [
"prefers-reduced-motion",
"min--moz-device-pixel-ratio"
]
}],
"number-leading-zero": "always",
"plugin/no-browser-hacks": [true, {
+1 -1
View File
@@ -113,7 +113,6 @@ CKEditor
Classy
- David Hernandez 'davidhernandez' https://www.drupal.org/u/davidhernandez
- Morten Birch Heide-Jørgensen 'mortendk' https://www.drupal.org/u/mortendk
Color
- ?
@@ -475,6 +474,7 @@ their responsibilities. The initiative coordinators for Drupal 8 are:
API-first Initiative
- Wim Leers 'Wim Leers' https://www.drupal.org/u/wim-leers
- Mateu Aguiló Bosch 'e0ipso' https://www.drupal.org/u/e0ipso
- Gabe Sullice 'gabesullice' https://www.drupal.org/u/gabesullice
Admin UI & JavaScript Modernisation Initiative
- Angela Byron 'webchick' https://www.drupal.org/u/webchick
+123 -25
View File
@@ -64,15 +64,51 @@ following the instructions in the INTRODUCTION section at the top of this file:
Enable the "Put site into maintenance mode" checkbox and save the
configuration.
3. Remove the 'core' and 'vendor' directories. Also remove all of the files
in the top-level directory, except any that you added manually.
3. Determine if your project is managed by Composer.
If you made modifications to files like .htaccess, composer.json, or
robots.txt you will need to re-apply them from your backup, after the new
files are in place.
On a typical Unix/Linux command line, this can be determined by running the
following command (replace /PATH/TO/composer with the appropriate location
for your system):
Sometimes an update includes changes to default.settings.php (this will be
noted in the release notes). If that's the case, follow these steps:
/PATH/TO/composer info drupal/core
If this is successful, your project is managed by Composer.
If you don't have Composer installed or access to the command line, you can
check the contents of composer.json. If "drupal/core" is present in the
"require" section of your composer.json file, then the project is managed by
Composer.
If the project is not managed by Composer, follow the steps under "UPDATING
CODE WITHOUT COMPOSER", otherwise go to "UPDATING CODE WITH COMPOSER".
UPDATING CODE WITH COMPOSER
---------------------------
1. On a typical Unix/Linux command line, run the following command from the root
directory (replace /PATH/TO/composer with the appropriate location for your
system):
/PATH/TO/composer update
Note, if Composer is not installed you will need to install it in order to
update Drupal.
Note, if you want to only update drupal/core the following command will
probably work:
/PATH/TO/composer update drupal/core symfony/* --with-all-dependencies
2. Check the release notes for the updated version of Drupal to find out if
there is a change to default.settings.php.
You can find the release notes for your version at
https://www.drupal.org/project/drupal. At bottom of the project page under
"Downloads" use the link for your version of Drupal to view the release
notes. If your version is not listed, use the 'View all releases' link. From
this page you can scroll down or use the filter to find your version and its
release notes.
If there is a change to default.settings.php, follow these steps:
- Locate your settings.php file in the /sites/* directory. (Typically
sites/default.)
@@ -87,16 +123,32 @@ following the instructions in the INTRODUCTION section at the top of this file:
database information, and you will also want to copy in any other
customizations you have added.
You can find the release notes for your version at
https://www.drupal.org/project/drupal. At bottom of the project page under
"Downloads" use the link for your version of Drupal to view the release
notes. If your version is not listed, use the 'View all releases' link. From
this page you can scroll down or use the filter to find your version and its
release notes.
3. Determine if there are any modifications to files such as .htaccess or
robots.txt and re-apply them. The Drupal Scaffold composer plugin
(https://github.com/drupal-composer/drupal-scaffold) can help you with
excluding files you'd like to always preserve when updating Drupal.
4. Download the latest Drupal 8.x.x release from https://www.drupal.org to a
directory outside of your web root. Extract the archive and copy the files
into your Drupal directory.
4. Go to the "UPLOADING THE CODE" section
UPDATING CODE WITHOUT COMPOSER
------------------------------
1. Remove the 'core' and 'vendor' directories. Also remove all of the files
in the top-level directory, except any that you added manually.
If you made modifications to files like .htaccess, composer.json, or
robots.txt you will need to re-apply them from your backup, after the new
files are in place.
This should leave you with the modules, profiles, sites, and themes
directories. These directories should only contain code that you've used to
extend Drupal.
2. Download the latest Drupal 8.x.x release from https://www.drupal.org/download
to a directory outside of your web root. Extract the archive and copy the
files into your Drupal directory.
Copy all the files, but do not accidentally overwrite your modules, profiles,
sites, or themes directories.
On a typical Unix/Linux command line, use the following commands to download
and extract:
@@ -110,13 +162,60 @@ following the instructions in the INTRODUCTION section at the top of this file:
cp -R drupal-x.y.z/* drupal-x.y.z/.htaccess /path/to/your/installation
If you do not have command line access to your server, download the archive
from https://www.drupal.org using your web browser, extract it, and then use
an FTP client to upload the files to your web root.
from https://www.drupal.org using your web browser and extract it locally.
5. Re-apply any modifications to files such as .htaccess, composer.json, or
robots.txt.
3. Check the release notes for the updated version of Drupal to find out if
there is a change to default.settings.php.
6. Run update.php by visiting http://www.example.com/update.php (replace
You can find the release notes for your updated version at
https://www.drupal.org/project/drupal. At bottom of the project page under
"Downloads" use the link for your updated version of Drupal to view the
release notes. If your updated version is not listed, use the 'View all
releases' link. From this page you can scroll down or use the filter to find
your updated version and its release notes.
If there is a change to default.settings.php, follow these steps:
- Locate your settings.php file in the /sites/* directory. (Typically
sites/default.)
- Make a backup copy of your settings.php file, with a different file name.
- Make a copy of the new default.settings.php file, and name the copy
settings.php (overwriting your previous settings.php file).
- Copy the custom and site-specific entries from the backup you made into the
new settings.php file. You will definitely need the lines giving the
database information, and you will also want to copy in any other
customizations you have added.
4. Re-apply any modifications to files such as .htaccess or robots.txt.
If you have added requirements in composer.json, it is recommended that you
re-add the requirements using Composer instead of applying the changes by
hand. For example, on a typical Unix/Linux command line, to reinstall the
Address module and its dependencies run (replace /PATH/TO/composer with the
appropriate location for your system):
/PATH/TO/composer require drupal/address
If you do not have command line access to your server, you will need to run
the Composer commands locally before uploading the file system to your
server.
5. Go to the "UPLOADING THE CODE" section
UPLOADING THE CODE
------------------
1. If you updated the code in a different environment from where it is running
you need to upload the files to your web root including the vendor/
directory.
2. Go to the "UPDATING THE DATABASE" section
UPDATING THE DATABASE
---------------------
1. Run update.php by visiting http://www.example.com/update.php (replace
www.example.com with your domain name). This will update the core database
tables.
@@ -133,12 +232,11 @@ following the instructions in the INTRODUCTION section at the top of this file:
- Once the update is done, $settings['update_free_access'] must be reverted
to FALSE.
7. Go to Administration > Reports > Status report. Verify that everything is
2. Go to Administration > Reports > Status report. Verify that everything is
working as expected.
8. Ensure that $settings['update_free_access'] is FALSE in settings.php.
3. Ensure that $settings['update_free_access'] is FALSE in settings.php.
9. Go to Administration > Configuration > Development > Maintenance mode.
4. Go to Administration > Configuration > Development > Maintenance mode.
Disable the "Put site into maintenance mode" checkbox and save the
configuration.
+296 -266
View File
File diff suppressed because it is too large Load Diff
+701 -701
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 14 KiB

@@ -3,13 +3,13 @@
For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
CKEDITOR.dialog.add("image2",function(f){function C(){var a=this.getValue().match(D);(a=!(!a||0===parseInt(a[1],10)))||alert(c.invalidLength.replace("%1",c[this.id]).replace("%2","px"));return a}function N(){function a(a,c){q.push(b.once(a,function(a){for(var b;b=q.pop();)b.removeListener();c(a)}))}var b=r.createElement("img"),q=[];return function(q,c,e){a("load",function(){var a=E(b);c.call(e,b,a.width,a.height)});a("error",function(){c(null)});a("abort",function(){c(null)});b.setAttribute("src",
(w.baseHref||"")+q+"?"+Math.random().toString(16).substring(2))}}function F(){var a=this.getValue();t(!1);a!==x.data.src?(G(a,function(a,b,c){t(!0);if(!a)return k(!1);g.setValue(!1===f.config.image2_prefillDimensions?0:b);h.setValue(!1===f.config.image2_prefillDimensions?0:c);u=b;v=c;k(H.checkHasNaturalRatio(a))}),l=!0):l?(t(!0),g.setValue(m),h.setValue(n),l=!1):t(!0)}function I(){if(e){var a=this.getValue();if(a&&(a.match(D)||k(!1),"0"!==a)){var b="width"==this.id,c=m||u,d=n||v,a=b?Math.round(a/
c*d):Math.round(a/d*c);isNaN(a)||(b?h:g).setValue(a)}}}function k(a){if(d){if("boolean"==typeof a){if(y)return;e=a}else a=g.getValue(),y=!0,(e=!e)&&a&&(a*=n/m,isNaN(a)||h.setValue(Math.round(a)));d[e?"removeClass":"addClass"]("cke_btn_unlocked");d.setAttribute("aria-checked",e);CKEDITOR.env.hc&&d.getChild(0).setHtml(e?CKEDITOR.env.ie?"■":"▣":CKEDITOR.env.ie?"□":"▢")}}function t(a){a=a?"enable":"disable";g[a]();h[a]()}var D=/(^\s*(\d+)(px)?\s*$)|^$/i,J=CKEDITOR.tools.getNextId(),K=CKEDITOR.tools.getNextId(),
(w.baseHref||"")+q+"?"+Math.random().toString(16).substring(2))}}function F(){var a=this.getValue();t(!1);a!==x.data.src?(G(a,function(a,b,c){t(!0);if(!a)return m(!1);g.setValue(!1===f.config.image2_prefillDimensions?0:b);h.setValue(!1===f.config.image2_prefillDimensions?0:c);u=k=b;v=l=c;m(H.checkHasNaturalRatio(a))}),n=!0):n?(t(!0),g.setValue(k),h.setValue(l),n=!1):t(!0)}function I(){if(e){var a=this.getValue();if(a&&(a.match(D)||m(!1),"0"!==a)){var b="width"==this.id,c=k||u,d=l||v,a=b?Math.round(a/
c*d):Math.round(a/d*c);isNaN(a)||(b?h:g).setValue(a)}}}function m(a){if(d){if("boolean"==typeof a){if(y)return;e=a}else a=g.getValue(),y=!0,(e=!e)&&a&&(a*=l/k,isNaN(a)||h.setValue(Math.round(a)));d[e?"removeClass":"addClass"]("cke_btn_unlocked");d.setAttribute("aria-checked",e);CKEDITOR.env.hc&&d.getChild(0).setHtml(e?CKEDITOR.env.ie?"■":"▣":CKEDITOR.env.ie?"□":"▢")}}function t(a){a=a?"enable":"disable";g[a]();h[a]()}var D=/(^\s*(\d+)(px)?\s*$)|^$/i,J=CKEDITOR.tools.getNextId(),K=CKEDITOR.tools.getNextId(),
b=f.lang.image2,c=f.lang.common,O=(new CKEDITOR.template('\x3cdiv\x3e\x3ca href\x3d"javascript:void(0)" tabindex\x3d"-1" title\x3d"'+b.lockRatio+'" class\x3d"cke_btn_locked" id\x3d"{lockButtonId}" role\x3d"checkbox"\x3e\x3cspan class\x3d"cke_icon"\x3e\x3c/span\x3e\x3cspan class\x3d"cke_label"\x3e'+b.lockRatio+'\x3c/span\x3e\x3c/a\x3e\x3ca href\x3d"javascript:void(0)" tabindex\x3d"-1" title\x3d"'+b.resetSize+'" class\x3d"cke_btn_reset" id\x3d"{resetButtonId}" role\x3d"button"\x3e\x3cspan class\x3d"cke_label"\x3e'+
b.resetSize+"\x3c/span\x3e\x3c/a\x3e\x3c/div\x3e")).output({lockButtonId:J,resetButtonId:K}),H=CKEDITOR.plugins.image2,w=f.config,z=!(!w.filebrowserImageBrowseUrl&&!w.filebrowserBrowseUrl),A=f.widgets.registered.image.features,E=H.getNatural,r,x,L,G,m,n,u,v,l,e,y,d,p,g,h,B,M=[{id:"src",type:"text",label:c.url,onKeyup:F,onChange:F,setup:function(a){this.setValue(a.data.src)},commit:function(a){a.setData("src",this.getValue())},validate:CKEDITOR.dialog.validate.notEmpty(b.urlMissing)}];z&&M.push({type:"button",
id:"browse",style:"display:inline-block;margin-top:14px;",align:"center",label:f.lang.common.browseServer,hidden:!0,filebrowser:"info:src"});return{title:b.title,minWidth:250,minHeight:100,onLoad:function(){r=this._.element.getDocument();G=N()},onShow:function(){x=this.widget;L=x.parts.image;l=y=e=!1;B=E(L);u=m=B.width;v=n=B.height},contents:[{id:"info",label:b.infoTab,elements:[{type:"vbox",padding:0,children:[{type:"hbox",widths:["100%"],className:"cke_dialog_image_url",children:M}]},{id:"alt",
b.resetSize+"\x3c/span\x3e\x3c/a\x3e\x3c/div\x3e")).output({lockButtonId:J,resetButtonId:K}),H=CKEDITOR.plugins.image2,w=f.config,z=!(!w.filebrowserImageBrowseUrl&&!w.filebrowserBrowseUrl),A=f.widgets.registered.image.features,E=H.getNatural,r,x,L,G,k,l,u,v,n,e,y,d,p,g,h,B,M=[{id:"src",type:"text",label:c.url,onKeyup:F,onChange:F,setup:function(a){this.setValue(a.data.src)},commit:function(a){a.setData("src",this.getValue())},validate:CKEDITOR.dialog.validate.notEmpty(b.urlMissing)}];z&&M.push({type:"button",
id:"browse",style:"display:inline-block;margin-top:14px;",align:"center",label:f.lang.common.browseServer,hidden:!0,filebrowser:"info:src"});return{title:b.title,minWidth:250,minHeight:100,onLoad:function(){r=this._.element.getDocument();G=N()},onShow:function(){x=this.widget;L=x.parts.image;n=y=e=!1;B=E(L);u=k=B.width;v=l=B.height},contents:[{id:"info",label:b.infoTab,elements:[{type:"vbox",padding:0,children:[{type:"hbox",widths:["100%"],className:"cke_dialog_image_url",children:M}]},{id:"alt",
type:"text",label:b.alt,setup:function(a){this.setValue(a.data.alt)},commit:function(a){a.setData("alt",this.getValue())},validate:!0===f.config.image2_altRequired?CKEDITOR.dialog.validate.notEmpty(b.altMissing):null},{type:"hbox",widths:["25%","25%","50%"],requiredContent:A.dimension.requiredContent,children:[{type:"text",width:"45px",id:"width",label:c.width,validate:C,onKeyUp:I,onLoad:function(){g=this},setup:function(a){this.setValue(a.data.width)},commit:function(a){a.setData("width",this.getValue())}},
{type:"text",id:"height",width:"45px",label:c.height,validate:C,onKeyUp:I,onLoad:function(){h=this},setup:function(a){this.setValue(a.data.height)},commit:function(a){a.setData("height",this.getValue())}},{id:"lock",type:"html",style:"margin-top:18px;width:40px;height:20px;",onLoad:function(){function a(a){a.on("mouseover",function(){this.addClass("cke_btn_over")},a);a.on("mouseout",function(){this.removeClass("cke_btn_over")},a)}var b=this.getDialog();d=r.getById(J);p=r.getById(K);d&&(b.addFocusable(d,
4+z),d.on("click",function(a){k();a.data&&a.data.preventDefault()},this.getDialog()),a(d));p&&(b.addFocusable(p,5+z),p.on("click",function(a){l?(g.setValue(u),h.setValue(v)):(g.setValue(m),h.setValue(n));a.data&&a.data.preventDefault()},this),a(p))},setup:function(a){k(a.data.lock)},commit:function(a){a.setData("lock",e)},html:O}]},{type:"hbox",id:"alignment",requiredContent:A.align.requiredContent,children:[{id:"align",type:"radio",items:[[c.alignNone,"none"],[c.left,"left"],[c.center,"center"],
4+z),d.on("click",function(a){m();a.data&&a.data.preventDefault()},this.getDialog()),a(d));p&&(b.addFocusable(p,5+z),p.on("click",function(a){n?(g.setValue(u),h.setValue(v)):(g.setValue(k),h.setValue(l));a.data&&a.data.preventDefault()},this),a(p))},setup:function(a){m(a.data.lock)},commit:function(a){a.setData("lock",e)},html:O}]},{type:"hbox",id:"alignment",requiredContent:A.align.requiredContent,children:[{id:"align",type:"radio",items:[[c.alignNone,"none"],[c.left,"left"],[c.center,"center"],
[c.right,"right"]],label:c.align,setup:function(a){this.setValue(a.data.align)},commit:function(a){a.setData("align",this.getValue())}}]},{id:"hasCaption",type:"checkbox",label:b.captioned,requiredContent:A.caption.requiredContent,setup:function(a){this.setValue(a.data.hasCaption)},commit:function(a){a.setData("hasCaption",this.getValue())}}]},{id:"Upload",hidden:!0,filebrowser:"uploadButton",label:b.uploadTab,elements:[{type:"file",id:"upload",label:b.btnUpload,style:"height:40px"},{type:"fileButton",
id:"uploadButton",filebrowser:"info:src",label:b.btnUpload,"for":["Upload","upload"]}]}]}});
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 14 KiB

+1 -1
View File
@@ -125,7 +125,7 @@ if ($is_allowed) {
$links = $results['tasks'];
}
else {
// Since this is being called outsite of the primary front controller,
// Since this is being called outside of the primary front controller,
// the base_url needs to be set explicitly to ensure that links are
// relative to the site root.
// @todo Simplify with https://www.drupal.org/node/2548095
+1 -1
View File
@@ -59,7 +59,7 @@
"jcalderonzumba/mink-phantomjs-driver": "^0.3.1",
"mikey179/vfsStream": "^1.2",
"phpunit/phpunit": "^4.8.35 || ^6.5",
"phpspec/prophecy": "^1.4",
"phpspec/prophecy": "^1.7",
"symfony/css-selector": "^3.4.0",
"symfony/phpunit-bridge": "^3.4.3",
"symfony/debug": "^3.4.0"
+2 -2
View File
@@ -24,10 +24,10 @@ classList:
ckeditor:
remote: https://github.com/ckeditor/ckeditor-dev
version: "4.10.0"
version: "4.10.1"
license:
name: GNU-GPL-2.0-or-later
url: https://github.com/ckeditor/ckeditor-dev/blob/4.10.0/LICENSE.md
url: https://github.com/ckeditor/ckeditor-dev/blob/4.10.1/LICENSE.md
gpl-compatible: true
js:
assets/vendor/ckeditor/ckeditor.js: { preprocess: false, minified: true }
+1 -3
View File
@@ -431,9 +431,7 @@ services:
factory: Drupal\Core\Site\Settings::getInstance
state:
class: Drupal\Core\State\State
arguments: ['@keyvalue', '@cache.bootstrap', '@lock']
tags:
- { name: needs_destruction }
arguments: ['@keyvalue']
queue:
class: Drupal\Core\Queue\QueueFactory
arguments: ['@settings']
+10 -6
View File
@@ -572,14 +572,14 @@ function drupal_get_user_timezone() {
* @param $message
* The error message.
* @param $filename
* The filename that the error was raised in.
* (optional) The filename that the error was raised in.
* @param $line
* The line number the error was raised at.
* (optional) The line number the error was raised at.
* @param $context
* An array that points to the active symbol table at the point the error
* occurred.
* (optional) An array that points to the active symbol table at the point the
* error occurred.
*/
function _drupal_error_handler($error_level, $message, $filename, $line, $context) {
function _drupal_error_handler($error_level, $message, $filename = NULL, $line = NULL, $context = NULL) {
require_once __DIR__ . '/errors.inc';
_drupal_error_handler_real($error_level, $message, $filename, $line, $context);
}
@@ -1033,8 +1033,12 @@ function _drupal_shutdown_function() {
chdir(DRUPAL_ROOT);
try {
foreach ($callbacks as &$callback) {
reset($callbacks);
// Do not use foreach() here because it is possible that the callback will
// add to the $callbacks array via drupal_register_shutdown_function().
while ($callback = current($callbacks)) {
call_user_func_array($callback['callback'], $callback['arguments']);
next($callbacks);
}
}
// PHP 7 introduces Throwable, which covers both Error and
+16 -7
View File
@@ -1270,12 +1270,19 @@ function install_select_profile(&$install_state) {
/**
* Determines the installation profile to use in the installer.
*
* A profile will be selected in the following order of conditions:
* Depending on the context from which it's being called, this method
* may be used to:
* - Automatically select a profile under certain conditions.
* - Indicate which profile has already been selected.
* - Indicate that a profile still needs to be selected.
*
* A profile will be selected automatically if one of the following conditions
* is met. They are checked in the given order:
* - Only one profile is available.
* - A specific profile name is requested in installation parameters:
* - For interactive installations via request query parameters.
* - For non-interactive installations via install_drupal() settings.
* - A discovered profile that is a distribution. If multiple profiles are
* - One of the available profiles is a distribution. If multiple profiles are
* distributions, then the first discovered profile will be selected.
* - Only one visible profile is available.
*
@@ -1283,35 +1290,37 @@ function install_select_profile(&$install_state) {
* The current installer state, containing a 'profiles' key, which is an
* associative array of profiles with the machine-readable names as keys.
*
* @return
* @return string|null
* The machine-readable name of the selected profile or NULL if no profile was
* selected.
*
* @see install_select_profile()
*/
function _install_select_profile(&$install_state) {
// Don't need to choose profile if only one available.
// If there is only one profile available it will always be the one selected.
if (count($install_state['profiles']) == 1) {
return key($install_state['profiles']);
}
// If a valid profile has already been selected, return the selection.
if (!empty($install_state['parameters']['profile'])) {
$profile = $install_state['parameters']['profile'];
if (isset($install_state['profiles'][$profile])) {
return $profile;
}
}
// Check for a distribution profile.
// If any of the profiles are distribution profiles, return the first one.
foreach ($install_state['profiles'] as $profile) {
$profile_info = install_profile_info($profile->getName());
if (!empty($profile_info['distribution'])) {
return $profile->getName();
}
}
// Get all visible (not hidden) profiles.
$visible_profiles = array_filter($install_state['profiles'], function ($profile) {
$profile_info = install_profile_info($profile->getName());
return !isset($profile_info['hidden']) || !$profile_info['hidden'];
});
// If there is only one visible profile, return it.
if (count($visible_profiles) == 1) {
return (key($visible_profiles));
}
+17
View File
@@ -11,6 +11,7 @@ use Drupal\Component\Utility\Crypt;
use Drupal\Component\Utility\OpCodeCache;
use Drupal\Component\Utility\UrlHelper;
use Drupal\Core\Extension\ExtensionDiscovery;
use Drupal\Core\Extension\ModuleHandler;
use Drupal\Core\Site\Settings;
/**
@@ -990,6 +991,12 @@ function drupal_check_profile($profile) {
}
}
// Add the profile requirements.
$function = $profile . '_requirements';
if (function_exists($function)) {
$requirements = array_merge($requirements, $function('install'));
}
return $requirements;
}
@@ -1113,6 +1120,16 @@ function install_profile_info($profile, $langcode = 'en') {
$info = \Drupal::service('info_parser')->parse("$profile_path/$profile.info.yml");
$info += $defaults;
// Convert dependencies in [project:module] format.
$info['dependencies'] = array_map(function ($dependency) {
return ModuleHandler::parseDependency($dependency)['name'];
}, $info['dependencies']);
// Convert install key in [project:module] format.
$info['install'] = array_map(function ($dependency) {
return ModuleHandler::parseDependency($dependency)['name'];
}, $info['install']);
// drupal_required_modules() includes the current profile as a dependency.
// Remove that dependency, since a module cannot depend on itself.
$required = array_diff(drupal_required_modules(), [$profile]);
+2 -2
View File
@@ -82,7 +82,7 @@ class Drupal {
/**
* The current system version.
*/
const VERSION = '8.6.2';
const VERSION = '8.6.3';
/**
* Core API compatibility.
@@ -229,7 +229,7 @@ class Drupal {
}
/**
* Retrives the request stack.
* Retrieves the request stack.
*
* @return \Symfony\Component\HttpFoundation\RequestStack
* The request stack
@@ -200,7 +200,7 @@ class PhpArrayContainer extends Container {
// The PhpArrayDumper just uses the hash of the private service
// definition to generate a unique ID.
//
// @see \Drupal\Component\DependecyInjection\Dumper\OptimizedPhpArrayDumper::getPrivateServiceCall
// @see \Drupal\Component\DependencyInjection\Dumper\OptimizedPhpArrayDumper::getPrivateServiceCall
if ($type == 'private_service') {
$id = $argument->id;
@@ -394,7 +394,7 @@ class PoStreamReader implements PoStreamInterface, PoReaderInterface {
($this->context != 'MSGCTXT') &&
($this->context != 'MSGID_PLURAL') &&
($this->context != 'MSGSTR_ARR')) {
// Plural message strings must come after msgid, msgxtxt,
// Plural message strings must come after msgid, msgctxt,
// msgid_plural, or other msgstr[] entries.
$this->errors[] = new FormattableMarkup('The translation stream %uri contains an error: "msgstr[]" is unexpected on line %line.', $log_vars);
return FALSE;
@@ -36,7 +36,7 @@ abstract class SecuredRedirectResponse extends RedirectResponse {
* Copies over the values from the given response.
*
* @param \Symfony\Component\HttpFoundation\RedirectResponse $response
* The redirect reponse object.
* The redirect response object.
*/
protected function fromResponse(RedirectResponse $response) {
$this->setProtocolVersion($response->getProtocolVersion());
@@ -29,7 +29,7 @@ abstract class PluginManagerBase implements PluginManagerInterface {
/**
* The object that returns the preconfigured plugin instance appropriate for a particular runtime condition.
*
* @var \Drupal\Component\Plugin\Mapper\MapperInterface
* @var \Drupal\Component\Plugin\Mapper\MapperInterface|null
*/
protected $mapper;
@@ -104,6 +104,9 @@ abstract class PluginManagerBase implements PluginManagerInterface {
* {@inheritdoc}
*/
public function getInstance(array $options) {
if (!$this->mapper) {
throw new \BadMethodCallException(sprintf('%s does not support this method unless %s::$mapper is set.', static::class, static::class));
}
return $this->mapper->getInstance($options);
}
+3 -3
View File
@@ -49,7 +49,7 @@
* The following changes have been done:
* Added namespace Drupal\Core\Archiver.
* Removed require_once 'PEAR.php'.
* Added defintion of OS_WINDOWS taken from PEAR.php.
* Added definition of OS_WINDOWS taken from PEAR.php.
* Renamed class to ArchiveTar.
* Removed extends PEAR from class.
* Removed call parent:: __construct().
@@ -181,7 +181,7 @@ class ArchiveTar
if ($data == "\37\213") {
$this->_compress = true;
$this->_compress_type = 'gz';
// No sure it's enought for a magic code ....
// Not sure it's enough for a magic code ....
} elseif ($data == "BZ") {
$this->_compress = true;
$this->_compress_type = 'bz2';
@@ -2385,7 +2385,7 @@ class ArchiveTar
/**
* Compress path by changing for example "/dir/foo/../bar" to "/dir/bar",
* rand emove double slashes.
* and remove double slashes.
*
* @param string $p_dir path to reduce
*
@@ -9,7 +9,7 @@ namespace Drupal\Core\Cache;
* Drupal\Core\Cache\DatabaseBackend provides the default implementation, which
* can be consulted as an example.
*
* The cache indentifiers are case sensitive.
* The cache identifiers are case sensitive.
*
* @ingroup cache
*/
+1 -3
View File
@@ -157,9 +157,7 @@ class MemoryBackend implements CacheBackendInterface, CacheTagsInvalidatorInterf
*/
public function invalidateMultiple(array $cids) {
foreach ($cids as $cid) {
if (isset($this->cache[$cid])) {
$this->cache[$cid]->expire = $this->getRequestTime() - 1;
}
$this->cache[$cid]->expire = $this->getRequestTime() - 1;
}
}
@@ -160,7 +160,10 @@ class ConfigInstaller implements ConfigInstallerInterface {
*/
public function installOptionalConfig(StorageInterface $storage = NULL, $dependency = []) {
$profile = $this->drupalGetProfile();
$optional_profile_config = [];
$enabled_extensions = $this->getEnabledExtensions();
$existing_config = $this->getActiveStorages()->listAll();
// Create the storages to read configuration from.
if (!$storage) {
// Search the install profile's optional configuration too.
$storage = new ExtensionInstallStorage($this->getActiveStorages(StorageInterface::DEFAULT_COLLECTION), InstallStorage::CONFIG_OPTIONAL_DIRECTORY, StorageInterface::DEFAULT_COLLECTION, TRUE, $this->installProfile);
@@ -171,7 +174,6 @@ class ConfigInstaller implements ConfigInstallerInterface {
// Creates a profile storage to search for overrides.
$profile_install_path = $this->drupalGetPath('module', $profile) . '/' . InstallStorage::CONFIG_OPTIONAL_DIRECTORY;
$profile_storage = new FileStorage($profile_install_path, StorageInterface::DEFAULT_COLLECTION);
$optional_profile_config = $profile_storage->listAll();
}
else {
// Profile has not been set yet. For example during the first steps of the
@@ -179,10 +181,17 @@ class ConfigInstaller implements ConfigInstallerInterface {
$profile_storage = NULL;
}
$enabled_extensions = $this->getEnabledExtensions();
$existing_config = $this->getActiveStorages()->listAll();
// Build the list of possible configuration to create.
$list = $storage->listAll();
if ($profile_storage && !empty($dependency)) {
// Only add the optional profile configuration into the list if we are
// have a dependency to check. This ensures that optional profile
// configuration is not unexpectedly re-created after being deleted.
$list = array_unique(array_merge($list, $profile_storage->listAll()));
}
$list = array_unique(array_merge($storage->listAll(), $optional_profile_config));
// Filter the list of configuration to only include configuration that
// should be created.
$list = array_filter($list, function ($config_name) use ($existing_config) {
// Only list configuration that:
// - does not already exist
@@ -226,6 +235,8 @@ class ConfigInstaller implements ConfigInstallerInterface {
unset($all_config[$config_name]);
}
}
// Create the optional configuration if there is any left after filtering.
if (!empty($config_to_create)) {
$this->createConfiguration(StorageInterface::DEFAULT_COLLECTION, $config_to_create, TRUE);
}
@@ -43,7 +43,8 @@ interface ConfigInstallerInterface {
* @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.
* configuration directories including the install profile's will be
* searched.
* @param array $dependency
* (optional) If set, ensures that the configuration being installed has
* this dependency. The format is dependency type as the key ('module',
@@ -189,7 +189,7 @@ interface ConfigEntityInterface extends EntityInterface, ThirdPartySettingsInter
* For example, a default view might not be installable if the base table
* doesn't exist.
*
* @retun bool
* @return bool
* TRUE if the entity is installable, FALSE otherwise.
*/
public function isInstallable();
+6 -2
View File
@@ -46,7 +46,7 @@ class FileStorage implements StorageInterface {
$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
// internal static caching of FileCache is used and thus avoids blowing up
// the APCu cache.
$this->fileCache = FileCacheFactory::get('config', ['cache_backend_class' => NULL]);
}
@@ -279,6 +279,9 @@ class FileStorage implements StorageInterface {
* {@inheritdoc}
*/
public function getAllCollectionNames() {
if (!is_dir($this->directory)) {
return [];
}
$collections = $this->getAllCollectionNamesHelper($this->directory);
sort($collections);
return $collections;
@@ -305,7 +308,8 @@ class FileStorage implements StorageInterface {
* @param string $directory
* The directory to check for sub directories. This allows this
* function to be used recursively to discover all the collections in the
* storage.
* storage. It is the responsibility of the caller to ensure the directory
* exists.
*
* @return array
* A list of collection names contained within the provided directory.
@@ -65,7 +65,7 @@ class Tasks extends InstallTasks {
Database::getConnection();
}
catch (\Exception $e) {
// Detect utf8mb4 incompability.
// Detect utf8mb4 incompatibility.
if ($e->getCode() == Connection::UNSUPPORTED_CHARSET || ($e->getCode() == Connection::SQLSTATE_SYNTAX_ERROR && $e->errorInfo[1] == Connection::UNKNOWN_CHARSET)) {
$this->fail(t('Your MySQL server and PHP MySQL driver must support utf8mb4 character encoding. Make sure to use a database system that supports this (such as MySQL/MariaDB/Percona 5.5.3 and up), and that the utf8mb4 character set is compiled in. See the <a href=":documentation" target="_blank">MySQL documentation</a> for more information.', [':documentation' => 'https://dev.mysql.com/doc/refman/5.0/en/cannot-initialize-character-set.html']));
$info = Database::getConnectionInfo();
@@ -38,7 +38,7 @@ class Connection extends DatabaseConnection {
/**
* A map of condition operators to PostgreSQL operators.
*
* In PostgreSQL, 'LIKE' is case-sensitive. ILKE should be used for
* In PostgreSQL, 'LIKE' is case-sensitive. ILIKE should be used for
* case-insensitive statements.
*/
protected static $postgresqlConditionOperatorMap = [
@@ -914,6 +914,8 @@ class Select extends Query implements SelectInterface {
* {@inheritdoc}
*/
public function __clone() {
parent::__clone();
// On cloning, also clone the dependent objects. However, we do not
// want to clone the database connection object as that would duplicate the
// connection itself.
@@ -923,6 +925,11 @@ class Select extends Query implements SelectInterface {
foreach ($this->union as $key => $aggregate) {
$this->union[$key]['query'] = clone($aggregate['query']);
}
foreach ($this->tables as $alias => $table) {
if ($table['table'] instanceof SelectInterface) {
$this->tables[$alias]['table'] = clone $table['table'];
}
}
}
}
@@ -20,7 +20,7 @@ class StatementPrefetch implements \Iterator, StatementInterface {
/**
* Driver-specific options. Can be used by child classes.
*
* @var Array
* @var array
*/
protected $driverOptions;
@@ -41,14 +41,14 @@ class StatementPrefetch implements \Iterator, StatementInterface {
/**
* Main data store.
*
* @var Array
* @var array
*/
protected $data = [];
/**
* The current row, retrieved in \PDO::FETCH_ASSOC format.
*
* @var Array
* @var array
*/
protected $currentRow = NULL;
@@ -62,7 +62,7 @@ class StatementPrefetch implements \Iterator, StatementInterface {
/**
* The list of column names in this result set.
*
* @var Array
* @var array
*/
protected $columnNames = NULL;
@@ -91,7 +91,7 @@ class StatementPrefetch implements \Iterator, StatementInterface {
/**
* Holds supplementary current fetch options (which will be used by the next fetch).
*
* @var Array
* @var array
*/
protected $fetchOptions = [
'class' => 'stdClass',
@@ -110,7 +110,7 @@ class StatementPrefetch implements \Iterator, StatementInterface {
/**
* Holds supplementary default fetch options.
*
* @var Array
* @var array
*/
protected $defaultFetchOptions = [
'class' => 'stdClass',
@@ -22,7 +22,7 @@ class CorsCompilerPass implements CompilerPassInterface {
$enabled = !empty($cors_config['enabled']);
}
// Remove the CORS middleware completly in case it was not enabled.
// Remove the CORS middleware completely in case it was not enabled.
if (!$enabled) {
$container->removeDefinition('http_middleware.cors');
}
+6 -2
View File
@@ -298,12 +298,16 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface {
}
/**
* Determine the application root directory based on assumptions.
* Determine the application root directory based on this file's location.
*
* @return string
* The application root.
*/
protected static function guessApplicationRoot() {
// Determine the application root by:
// - Removing the namespace directories from the path.
// - Getting the path to the directory two levels up from the path
// determined in the previous step.
return dirname(dirname(substr(__DIR__, 0, -strlen(__NAMESPACE__))));
}
@@ -1091,7 +1095,7 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface {
// misses.
$old_loader = $this->classLoader;
$this->classLoader = $loader;
// Our class loaders are preprended to ensure they come first like the
// Our class loaders are prepended to ensure they come first like the
// class loader they are replacing.
$old_loader->register(TRUE);
$loader->register(TRUE);
@@ -60,6 +60,7 @@ class ContentEntityDeleteForm extends ContentEntityConfirmFormBase {
public function submitForm(array &$form, FormStateInterface $form_state) {
/** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
$entity = $this->getEntity();
$message = $this->getDeletionMessage();
// Make sure that deleting a translation does not delete the whole entity.
if (!$entity->isDefaultTranslation()) {
@@ -73,7 +74,7 @@ class ContentEntityDeleteForm extends ContentEntityConfirmFormBase {
$form_state->setRedirectUrl($this->getRedirectUrl());
}
$this->messenger()->addStatus($this->getDeletionMessage());
$this->messenger()->addStatus($message);
$this->logDeletionMessage();
}
@@ -251,8 +251,8 @@ class EntityAutocomplete extends Textfield {
/**
* Finds an entity from an autocomplete input without an explicit ID.
*
* The method will return an entity ID if one single entity unambuguously
* matches the incoming input, and sill assign form errors otherwise.
* The method will return an entity ID if one single entity unambiguously
* matches the incoming input, and assign form errors otherwise.
*
* @param \Drupal\Core\Entity\EntityReferenceSelection\SelectionInterface $handler
* Entity reference selection plugin.
@@ -68,6 +68,7 @@ class EntityBundleListener implements EntityBundleListenerInterface {
}
// Invoke hook_entity_bundle_create() hook.
$this->moduleHandler->invokeAll('entity_bundle_create', [$entity_type_id, $bundle]);
$this->entityFieldManager->clearCachedFieldDefinitions();
}
/**
@@ -497,7 +497,7 @@ class EntityFieldManager implements EntityFieldManagerInterface {
}
}
$this->cacheSet($cid, $this->fieldMap, Cache::PERMANENT, ['entity_types']);
$this->cacheSet($cid, $this->fieldMap, Cache::PERMANENT, ['entity_types', 'entity_field_info']);
}
}
return $this->fieldMap;
@@ -194,7 +194,7 @@ abstract class EntityStorageBase extends EntityHandlerBase implements EntityStor
* Invokes a hook on behalf of the entity.
*
* @param string $hook
* One of 'presave', 'insert', 'update', 'predelete', 'delete', or
* One of 'create', 'presave', 'insert', 'update', 'predelete', 'delete', or
* 'revision_delete'.
* @param \Drupal\Core\Entity\EntityInterface $entity
* The entity object.
@@ -16,7 +16,7 @@ use Drupal\Core\TypedData\DataReferenceBase;
* or the entity ID may be passed.
*
* Note that the definition of the referenced entity's type is required, whereas
* defining referencable entity bundle(s) is optional. A reference defining the
* defining referenceable entity bundle(s) is optional. A reference defining the
* type and bundle of the referenced entity can be created as following:
* @code
* $definition = \Drupal\Core\Entity\EntityDefinition::create($entity_type)
@@ -518,7 +518,7 @@ class SqlContentEntityStorage extends ContentEntityStorageBase implements SqlEnt
// Some fields can have more then one columns in the data table so
// column names are needed.
foreach ($data_fields as $data_field) {
// \Drupal\Core\Entity\Sql\TableMappingInterface:: getColumNames()
// \Drupal\Core\Entity\Sql\TableMappingInterface::getColumnNames()
// returns an array keyed by property names so remove the keys
// before array_merge() to avoid losing data with fields having the
// same columns i.e. value.
@@ -1174,12 +1174,12 @@ class SqlContentEntityStorageSchema implements DynamicallyFieldableEntityStorage
* The entity type.
* @param array $schema
* The table schema, passed by reference.
*
* @return array
* A partial schema array for the base table.
*/
protected function processBaseTable(ContentEntityTypeInterface $entity_type, array &$schema) {
$this->processIdentifierSchema($schema, $entity_type->getKey('id'));
// Process the schema for the 'id' entity key only if it exists.
if ($entity_type->hasKey('id')) {
$this->processIdentifierSchema($schema, $entity_type->getKey('id'));
}
}
/**
@@ -1189,12 +1189,12 @@ class SqlContentEntityStorageSchema implements DynamicallyFieldableEntityStorage
* The entity type.
* @param array $schema
* The table schema, passed by reference.
*
* @return array
* A partial schema array for the base table.
*/
protected function processRevisionTable(ContentEntityTypeInterface $entity_type, array &$schema) {
$this->processIdentifierSchema($schema, $entity_type->getKey('revision'));
// Process the schema for the 'revision' entity key only if it exists.
if ($entity_type->hasKey('revision')) {
$this->processIdentifierSchema($schema, $entity_type->getKey('revision'));
}
}
/**
@@ -1333,11 +1333,23 @@ class SqlContentEntityStorageSchema implements DynamicallyFieldableEntityStorage
// Create field columns.
$schema[$table_name] = $this->getSharedTableFieldSchema($storage_definition, $table_name, $column_names);
if (!$only_save) {
// The entity schema needs to be checked because the field schema is
// potentially incomplete.
// @todo Fix this in https://www.drupal.org/node/2929120.
$entity_schema = $this->getEntitySchema($this->entityType);
foreach ($schema[$table_name]['fields'] as $name => $specifier) {
// Check if the field is part of the primary keys and pass along
// this information when adding the field.
// @see \Drupal\Core\Database\Schema::addField()
$new_keys = [];
if (isset($entity_schema[$table_name]['primary key']) && array_intersect($column_names, $entity_schema[$table_name]['primary key'])) {
$new_keys = ['primary key' => $entity_schema[$table_name]['primary key']];
}
// Check if the field exists because it might already have been
// created as part of the earlier entity type update event.
if (!$schema_handler->fieldExists($table_name, $name)) {
$schema_handler->addField($table_name, $name, $specifier);
$schema_handler->addField($table_name, $name, $specifier, $new_keys);
}
}
if (!empty($schema[$table_name]['indexes'])) {
@@ -60,10 +60,7 @@ class KernelDestructionSubscriber implements EventSubscriberInterface, Container
* An array of event listener definitions.
*/
public static function getSubscribedEvents() {
// Run this subscriber after others as those might use services that need
// to be terminated as well or run code that needs to run before
// termination.
$events[KernelEvents::TERMINATE][] = ['onKernelTerminate', -100];
$events[KernelEvents::TERMINATE][] = ['onKernelTerminate', 100];
return $events;
}
@@ -5,6 +5,7 @@ namespace Drupal\Core\Field\Plugin\Field\FieldFormatter;
use Drupal\Component\Render\FormattableMarkup;
use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Datetime\DateFormatterInterface;
use Drupal\Core\Datetime\DrupalDateTime;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\FormatterBase;
@@ -104,7 +105,7 @@ class TimestampAgoFormatter extends FormatterBase implements ContainerFactoryPlu
* {@inheritdoc}
*/
public function settingsForm(array $form, FormStateInterface $form_state) {
$elements = parent::settingsForm($form, $form_state);
$form = parent::settingsForm($form, $form_state);
$form['future_format'] = [
'#type' => 'textfield',
@@ -120,7 +121,7 @@ class TimestampAgoFormatter extends FormatterBase implements ContainerFactoryPlu
'#description' => $this->t('Use <em>@interval</em> where you want the formatted interval text to appear.'),
];
$elements['granularity'] = [
$form['granularity'] = [
'#type' => 'number',
'#title' => $this->t('Granularity'),
'#description' => $this->t('How many time interval units should be shown in the formatted output.'),
@@ -129,7 +130,7 @@ class TimestampAgoFormatter extends FormatterBase implements ContainerFactoryPlu
'#max' => 6,
];
return $elements;
return $form;
}
/**
@@ -138,10 +139,19 @@ class TimestampAgoFormatter extends FormatterBase implements ContainerFactoryPlu
public function settingsSummary() {
$summary = parent::settingsSummary();
$future_date = strtotime('1 year 1 month 1 week 1 day 1 hour 1 minute');
$past_date = strtotime('-1 year -1 month -1 week -1 day -1 hour -1 minute');
$summary[] = $this->t('Future date: %display', ['%display' => $this->formatTimestamp($future_date)]);
$summary[] = $this->t('Past date: %display', ['%display' => $this->formatTimestamp($past_date)]);
$future_date = new DrupalDateTime('1 year 1 month 1 week 1 day 1 hour 1 minute');
$past_date = new DrupalDateTime('-1 year -1 month -1 week -1 day -1 hour -1 minute');
$granularity = $this->getSetting('granularity');
$options = [
'granularity' => $granularity,
'return_as_object' => FALSE,
];
$future_date_interval = new FormattableMarkup($this->getSetting('future_format'), ['@interval' => $this->dateFormatter->formatTimeDiffUntil($future_date->getTimestamp(), $options)]);
$past_date_interval = new FormattableMarkup($this->getSetting('past_format'), ['@interval' => $this->dateFormatter->formatTimeDiffSince($past_date->getTimestamp(), $options)]);
$summary[] = $this->t('Future date: %display', ['%display' => $future_date_interval]);
$summary[] = $this->t('Past date: %display', ['%display' => $past_date_interval]);
return $summary;
}
@@ -10,7 +10,7 @@ interface ConfirmFormInterface extends FormInterface {
/**
* Returns the question to ask the user.
*
* @return string
* @return \Drupal\Core\StringTranslation\TranslatableMarkup
* The form question. The page title will be set to this value.
*/
public function getQuestion();
@@ -26,7 +26,7 @@ interface ConfirmFormInterface extends FormInterface {
/**
* Returns additional text to display as a description.
*
* @return string
* @return \Drupal\Core\StringTranslation\TranslatableMarkup
* The form description.
*/
public function getDescription();
@@ -34,7 +34,7 @@ interface ConfirmFormInterface extends FormInterface {
/**
* Returns a caption for the button that confirms the action.
*
* @return string
* @return \Drupal\Core\StringTranslation\TranslatableMarkup
* The form confirmation text.
*/
public function getConfirmText();
@@ -42,7 +42,7 @@ interface ConfirmFormInterface extends FormInterface {
/**
* Returns a caption for the link which cancels the action.
*
* @return string
* @return \Drupal\Core\StringTranslation\TranslatableMarkup
* The form cancellation text.
*/
public function getCancelText();
+1 -1
View File
@@ -687,7 +687,7 @@ class FormBuilder implements FormBuilderInterface, FormValidatorInterface, FormS
// will be replaced at the very last moment. This ensures forms with
// dynamically generated action URLs don't have poor cacheability.
// Use the proper API to generate the placeholder, when we have one. See
// https://www.drupal.org/node/2562341. The placholder uses a fixed string
// https://www.drupal.org/node/2562341. The placeholder uses a fixed string
// that is Crypt::hashBase64('Drupal\Core\Form\FormBuilder::prepareForm');
$placeholder = 'form_action_p_pvdeGsVG5zNF_XLGPTvYSKCf43t8qZYSwcfZl2uzM';
+2 -2
View File
@@ -87,8 +87,8 @@ class FormState implements FormStateInterface {
* copy of the form is immediately built and sent to the browser, instead of a
* redirect. This is used for multi-step forms, such as wizards and
* confirmation forms. Normally, self::$rebuild is set by a submit handler,
* since its is usually logic within a submit handler that determines whether
* a form is done or requires another step. However, a validation handler may
* since it is usually logic within a submit handler that determines whether a
* form is done or requires another step. However, a validation handler may
* already set self::$rebuild to cause the form processing to bypass submit
* handlers and rebuild the form instead, even if there are no validation
* errors.
@@ -43,7 +43,7 @@ class HandlerStackConfigurator {
protected $container;
/**
* Contructs a new HandlerStackConfigurator object.
* Constructs a new HandlerStackConfigurator object.
*
* @param \Symfony\Component\DependencyInjection\ContainerInterface $container
* The service container.
@@ -44,7 +44,7 @@ class TrustedHostsRequestFactory {
* @param array $request
* (optional) An array of request variables.
* @param array $attributes
* (optioanl) An array of attributes.
* (optional) An array of attributes.
* @param array $cookies
* (optional) The request cookies ($_COOKIE).
* @param array $files
@@ -19,7 +19,7 @@ class InstallProfileMismatchException extends InstallerException {
* @param string $settings_profile
* The profile in settings.php.
* @param string $settings_file
* The path to settigns.php.
* The path to settings.php.
* @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation
* The string translation manager.
*
+10
View File
@@ -2,7 +2,9 @@
namespace Drupal\Core\Mail;
use Drupal\Component\Render\MarkupInterface;
use Drupal\Component\Render\PlainTextOutput;
use Drupal\Component\Utility\Html;
use Drupal\Component\Utility\Unicode;
use Drupal\Core\Logger\LoggerChannelFactoryInterface;
use Drupal\Core\Messenger\MessengerTrait;
@@ -10,6 +12,7 @@ use Drupal\Core\Plugin\DefaultPluginManager;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Render\Markup;
use Drupal\Core\Render\RenderContext;
use Drupal\Core\Render\RendererInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
@@ -277,6 +280,13 @@ class MailManager extends DefaultPluginManager implements MailManagerInterface {
// Retrieve the responsible implementation for this message.
$system = $this->getInstance(['module' => $module, 'key' => $key]);
// Attempt to convert relative URLs to absolute.
foreach ($message['body'] as &$body_part) {
if ($body_part instanceof MarkupInterface) {
$body_part = Markup::create(Html::transformRootRelativeUrlsToAbsolute((string) $body_part, \Drupal::request()->getSchemeAndHttpHost()));
}
}
// Format the message body.
$message = $system->format($message);
@@ -83,33 +83,36 @@ class LocalActionDefault extends PluginBase implements LocalActionInterface, Con
* {@inheritdoc}
*/
public function getRouteParameters(RouteMatchInterface $route_match) {
$parameters = isset($this->pluginDefinition['route_parameters']) ? $this->pluginDefinition['route_parameters'] : [];
$route_parameters = isset($this->pluginDefinition['route_parameters']) ? $this->pluginDefinition['route_parameters'] : [];
$route = $this->routeProvider->getRouteByName($this->getRouteName());
$variables = $route->compile()->getVariables();
// Normally the \Drupal\Core\ParamConverter\ParamConverterManager has
// processed the Request attributes, and in that case the _raw_variables
// attribute holds the original path strings keyed to the corresponding
// slugs in the path patterns. For example, if the route's path pattern is
// run, and the route parameters have been upcast. The original values can
// be retrieved from the raw parameters. For example, if the route's path is
// /filter/tips/{filter_format} and the path is /filter/tips/plain_text then
// $raw_variables->get('filter_format') == 'plain_text'.
$raw_variables = $route_match->getRawParameters();
// $raw_parameters->get('filter_format') == 'plain_text'. Parameters that
// are not represented in the route path as slugs might be added by a route
// enhancer and will not be present in the raw parameters.
$raw_parameters = $route_match->getRawParameters();
$parameters = $route_match->getParameters();
foreach ($variables as $name) {
if (isset($parameters[$name])) {
if (isset($route_parameters[$name])) {
continue;
}
if ($raw_variables && $raw_variables->has($name)) {
$parameters[$name] = $raw_variables->get($name);
if ($raw_parameters->has($name)) {
$route_parameters[$name] = $raw_parameters->get($name);
}
elseif ($value = $route_match->getRawParameter($name)) {
$parameters[$name] = $value;
elseif ($parameters->has($name)) {
$route_parameters[$name] = $parameters->get($name);
}
}
// The UrlGenerator will throw an exception if expected parameters are
// missing. This method should be overridden if that is possible.
return $parameters;
return $route_parameters;
}
/**
@@ -196,9 +196,10 @@ class LocalActionManager extends DefaultPluginManager implements LocalActionMana
}
}
$links = [];
$cacheability = new CacheableMetadata();
$cacheability->addCacheContexts(['route']);
/** @var $plugin \Drupal\Core\Menu\LocalActionInterface */
foreach ($this->instances[$route_appears] as $plugin_id => $plugin) {
$cacheability = new CacheableMetadata();
$route_name = $plugin->getRouteName();
$route_parameters = $plugin->getRouteParameters($this->routeMatch);
$access = $this->accessManager->checkNamedRoute($route_name, $route_parameters, $this->account, TRUE);
@@ -213,9 +214,8 @@ class LocalActionManager extends DefaultPluginManager implements LocalActionMana
'#weight' => $plugin->getWeight(),
];
$cacheability->addCacheableDependency($access)->addCacheableDependency($plugin);
$cacheability->applyTo($links[$plugin_id]);
}
$links['#cache']['contexts'][] = 'route';
$cacheability->applyTo($links);
return $links;
}
+15 -13
View File
@@ -41,34 +41,36 @@ class LocalTaskDefault extends PluginBase implements LocalTaskInterface, Cacheab
* {@inheritdoc}
*/
public function getRouteParameters(RouteMatchInterface $route_match) {
$parameters = isset($this->pluginDefinition['route_parameters']) ? $this->pluginDefinition['route_parameters'] : [];
$route_parameters = isset($this->pluginDefinition['route_parameters']) ? $this->pluginDefinition['route_parameters'] : [];
$route = $this->routeProvider()->getRouteByName($this->getRouteName());
$variables = $route->compile()->getVariables();
// Normally the \Drupal\Core\ParamConverter\ParamConverterManager has
// processed the Request attributes, and in that case the _raw_variables
// attribute holds the original path strings keyed to the corresponding
// slugs in the path patterns. For example, if the route's path pattern is
// run, and the route parameters have been upcast. The original values can
// be retrieved from the raw parameters. For example, if the route's path is
// /filter/tips/{filter_format} and the path is /filter/tips/plain_text then
// $raw_variables->get('filter_format') == 'plain_text'.
$raw_variables = $route_match->getRawParameters();
// $raw_parameters->get('filter_format') == 'plain_text'. Parameters that
// are not represented in the route path as slugs might be added by a route
// enhancer and will not be present in the raw parameters.
$raw_parameters = $route_match->getRawParameters();
$parameters = $route_match->getParameters();
foreach ($variables as $name) {
if (isset($parameters[$name])) {
if (isset($route_parameters[$name])) {
continue;
}
if ($raw_variables && $raw_variables->has($name)) {
$parameters[$name] = $raw_variables->get($name);
if ($raw_parameters->has($name)) {
$route_parameters[$name] = $raw_parameters->get($name);
}
elseif ($value = $route_match->getRawParameter($name)) {
$parameters[$name] = $value;
elseif ($parameters->has($name)) {
$route_parameters[$name] = $parameters->get($name);
}
}
// The UrlGenerator will throw an exception if expected parameters are
// missing. This method should be overridden if that is possible.
return $parameters;
return $route_parameters;
}
/**
@@ -30,7 +30,7 @@ interface MenuLinkTreeInterface {
*
* Builds menu link tree parameters that:
* - Expand all links in the active trail based on route being viewed.
* - Expand the descendents of the links in the active trail whose
* - Expand the descendants of the links in the active trail whose
* 'expanded' flag is enabled.
*
* This only sets the (relatively complex) parameters to achieve the two above
@@ -11,7 +11,7 @@ use Symfony\Component\HttpFoundation\Request;
*
* Do not serve cached pages to authenticated users, or to anonymous users when
* $_SESSION is non-empty. $_SESSION may contain status messages from a form
* submission, the contents of a shopping cart, or other userspecific content
* submission, the contents of a shopping cart, or other user-specific content
* that should not be cached and displayed to other users.
*/
class NoSessionOpen implements RequestPolicyInterface {
@@ -12,10 +12,17 @@ interface InboundPathProcessorInterface {
/**
* Processes the inbound path.
*
* Implementations may make changes to the request object passed in but should
* avoid all other side effects. This method can be called to process requests
* other than the current request.
*
* @param string $path
* The path to process, with a leading slash.
* @param \Symfony\Component\HttpFoundation\Request $request
* The HttpRequest object representing the current request.
* The HttpRequest object representing the request to process. Note, if this
* method is being called via the path_processor_manager service and is not
* part of routing, the current request object must be cloned before being
* passed in.
*
* @return string
* The processed path.
@@ -6,6 +6,7 @@ use Drupal\Component\Plugin\Context\Context as ComponentContext;
use Drupal\Component\Plugin\Exception\ContextException;
use Drupal\Core\Cache\CacheableDependencyInterface;
use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\DependencyInjection\DependencySerializationTrait;
use Drupal\Core\TypedData\TypedDataInterface;
use Drupal\Core\TypedData\TypedDataTrait;
@@ -15,6 +16,7 @@ use Drupal\Core\TypedData\TypedDataTrait;
class Context extends ComponentContext implements ContextInterface {
use TypedDataTrait;
use DependencySerializationTrait;
/**
* The data associated with the context.
@@ -5,7 +5,7 @@ namespace Drupal\Core\ProxyBuilder;
use Drupal\Component\ProxyBuilder\ProxyBuilder as BaseProxyBuilder;
/**
* Extend the component proxy builder by using the DependencySerialziationTrait.
* Extend the component proxy builder by using the DependencySerializationTrait.
*/
class ProxyBuilder extends BaseProxyBuilder {
@@ -11,12 +11,14 @@ use Drupal\Core\Render\Element;
* Properties:
* - #default_value: An RFC-compliant email address.
* - #size: The size of the input element in characters.
* - #pattern: A string for the native HTML5 pattern attribute.
*
* Example usage:
* @code
* $form['email'] = array(
* '#type' => 'email',
* '#title' => $this->t('Email'),
* '#pattern' => '*@example.com',
* );
* @end
*
@@ -10,6 +10,7 @@ use Drupal\Core\Render\Element;
*
* Properties:
* - #size: The size of the input element in characters.
* - #pattern: A string for the native HTML5 pattern attribute.
*
* Usage example:
* @code
@@ -17,6 +18,7 @@ use Drupal\Core\Render\Element;
* '#type' => 'password',
* '#title' => $this->t('Password'),
* '#size' => 25,
* '#pattern' => '[01]+',
* );
* @endcode
*
@@ -32,7 +32,7 @@ use Drupal\Core\Url;
* strings, if they are literals provided by your module, should be
* internationalized and translated; see the
* @link i18n Internationalization topic @endlink for more information. Note
* that although in the properies list that follows, they are designated to be
* that although in the properties list that follows, they are designated to be
* of type string, they would generally end up being
* \Drupal\Core\StringTranslation\TranslatableMarkup objects instead.
*
@@ -12,12 +12,14 @@ use Drupal\Core\Render\Element;
*
* Properties:
* - #size: The size of the input element in characters.
* - #pattern: A string for the native HTML5 pattern attribute.
*
* Usage example:
* @code
* $form['phone'] = array(
* '#type' => 'tel',
* '#title' => $this->t('Phone'),
* '#pattern' => '[^\d]*',
* );
* @endcode
*
@@ -15,6 +15,7 @@ use Drupal\Core\Render\Element;
* autocomplete JavaScript library.
* - #autocomplete_route_parameters: An array of parameters to be used in
* conjunction with the route name.
* - #pattern: A string for the native HTML5 pattern attribute.
*
* Usage example:
* @code
@@ -24,7 +25,8 @@ use Drupal\Core\Render\Element;
* '#default_value' => $node->title,
* '#size' => 60,
* '#maxlength' => 128,
* '#required' => TRUE,
* '#pattern' => 'some-prefix-[a-z]+',
* '#required' => TRUE,
* );
* @endcode
*
@@ -12,6 +12,7 @@ use Drupal\Core\Render\Element;
* Properties:
* - #default_value: A valid URL string.
* - #size: The size of the input element in characters.
* - #pattern: A string for the native HTML5 pattern attribute.
*
* Usage example:
* @code
@@ -19,6 +20,7 @@ use Drupal\Core\Render\Element;
* '#type' => 'url',
* '#title' => $this->t('Home Page'),
* '#size' => 30,
* '#pattern' => '*.example.com',
* ...
* );
* @endcode
@@ -106,7 +106,7 @@ class SessionConfiguration implements SessionConfigurationInterface {
* Return the session cookie domain.
*
* The Set-Cookie response header and its domain attribute are defined in RFC
* 2109, RFC 2965 and RFC 6265 each one superseeding the previous version.
* 2109, RFC 2965 and RFC 6265 each one superseding the previous version.
*
* @see http://tools.ietf.org/html/rfc2109
* @see http://tools.ietf.org/html/rfc2965
@@ -14,8 +14,7 @@ interface WriteSafeSessionHandlerInterface {
* only capable of forcibly disabling that session data is written to storage.
*
* @param bool $flag
* TRUE if the session the session is allowed to be written, FALSE
* otherwise.
* TRUE if the session is allowed to be written, FALSE otherwise.
*/
public function setSessionWritable($flag);
@@ -23,8 +22,7 @@ interface WriteSafeSessionHandlerInterface {
* Returns whether or not a session may be written to storage.
*
* @return bool
* TRUE if the session the session is allowed to be written, FALSE
* otherwise.
* TRUE if the session is allowed to be written, FALSE otherwise.
*/
public function isSessionWritable();
+41 -29
View File
@@ -2,15 +2,12 @@
namespace Drupal\Core\State;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Cache\CacheCollector;
use Drupal\Core\KeyValueStore\KeyValueFactoryInterface;
use Drupal\Core\Lock\LockBackendInterface;
/**
* Provides the state system using a key value store.
*/
class State extends CacheCollector implements StateInterface {
class State implements StateInterface {
/**
* The key value store to use.
@@ -19,18 +16,20 @@ class State extends CacheCollector implements StateInterface {
*/
protected $keyValueStore;
/**
* Static state cache.
*
* @var array
*/
protected $cache = [];
/**
* Constructs a State object.
*
* @param \Drupal\Core\KeyValueStore\KeyValueFactoryInterface $key_value_factory
* The key value store to use.
* @param \Drupal\Core\Cache\CacheBackendInterface $cache
* The cache backend.
* @param \Drupal\Core\Lock\LockBackendInterface $lock
* The lock backend.
*/
public function __construct(KeyValueFactoryInterface $key_value_factory, CacheBackendInterface $cache, LockBackendInterface $lock) {
parent::__construct('state', $cache, $lock);
public function __construct(KeyValueFactoryInterface $key_value_factory) {
$this->keyValueStore = $key_value_factory->get('state');
}
@@ -38,18 +37,8 @@ class State extends CacheCollector implements StateInterface {
* {@inheritdoc}
*/
public function get($key, $default = NULL) {
$value = parent::get($key);
return $value !== NULL ? $value : $default;
}
/**
* {@inheritdoc}
*/
protected function resolveCacheMiss($key) {
$value = $this->keyValueStore->get($key);
$this->storage[$key] = $value;
$this->persist($key);
return $value;
$values = $this->getMultiple([$key]);
return isset($values[$key]) ? $values[$key] : $default;
}
/**
@@ -57,9 +46,33 @@ class State extends CacheCollector implements StateInterface {
*/
public function getMultiple(array $keys) {
$values = [];
$load = [];
foreach ($keys as $key) {
$values[$key] = $this->get($key);
// Check if we have a value in the cache.
if (isset($this->cache[$key])) {
$values[$key] = $this->cache[$key];
}
// Load the value if we don't have an explicit NULL value.
elseif (!array_key_exists($key, $this->cache)) {
$load[] = $key;
}
}
if ($load) {
$loaded_values = $this->keyValueStore->getMultiple($load);
foreach ($load as $key) {
// If we find a value, even one that is NULL, add it to the cache and
// return it.
if (isset($loaded_values[$key]) || array_key_exists($key, $loaded_values)) {
$values[$key] = $loaded_values[$key];
$this->cache[$key] = $loaded_values[$key];
}
else {
$this->cache[$key] = NULL;
}
}
}
return $values;
}
@@ -67,7 +80,7 @@ class State extends CacheCollector implements StateInterface {
* {@inheritdoc}
*/
public function set($key, $value) {
parent::set($key, $value);
$this->cache[$key] = $value;
$this->keyValueStore->set($key, $value);
}
@@ -76,7 +89,7 @@ class State extends CacheCollector implements StateInterface {
*/
public function setMultiple(array $data) {
foreach ($data as $key => $value) {
parent::set($key, $value);
$this->cache[$key] = $value;
}
$this->keyValueStore->setMultiple($data);
}
@@ -85,8 +98,7 @@ class State extends CacheCollector implements StateInterface {
* {@inheritdoc}
*/
public function delete($key) {
parent::delete($key);
$this->keyValueStore->delete($key);
$this->deleteMultiple([$key]);
}
/**
@@ -94,7 +106,7 @@ class State extends CacheCollector implements StateInterface {
*/
public function deleteMultiple(array $keys) {
foreach ($keys as $key) {
parent::delete($key);
unset($this->cache[$key]);
}
$this->keyValueStore->deleteMultiple($keys);
}
@@ -103,7 +115,7 @@ class State extends CacheCollector implements StateInterface {
* {@inheritdoc}
*/
public function resetCache() {
$this->clear();
$this->cache = [];
}
}
@@ -82,7 +82,7 @@ interface StreamWrapperInterface extends PhpStreamWrapperInterface {
const READ_VISIBLE = 0x0014;
/**
* This is the default 'type' falg. This does not include
* This is the default 'type' flag. This does not include
* StreamWrapperInterface::LOCAL, because PHP grants a greater trust level to
* local files (for example, they can be used in an "include" statement,
* regardless of the "allow_url_include" setting), so stream wrappers need to
@@ -123,6 +123,7 @@ class PrivateTempStore {
if ($this->currentUser->isAnonymous()) {
// @todo when https://www.drupal.org/node/2865991 is resolved, use force
// start session API rather than setting an arbitrary value directly.
$this->startSession();
$this->requestStack
->getCurrentRequest()
->getSession()
@@ -219,7 +220,34 @@ class PrivateTempStore {
* The owner.
*/
protected function getOwner() {
return $this->currentUser->id() ?: $this->requestStack->getCurrentRequest()->getSession()->getId();
$owner = $this->currentUser->id();
if ($this->currentUser->isAnonymous()) {
$this->startSession();
$owner = $this->requestStack->getCurrentRequest()->getSession()->getId();
}
return $owner;
}
/**
* Start session because it is required for a private temp store.
*
* Ensures that an anonymous user has a session created for them, as
* otherwise subsequent page loads will not be able to retrieve their
* tempstore data.
*
* @todo when https://www.drupal.org/node/2865991 is resolved, use force
* start session API.
*/
protected function startSession() {
$has_session = $this->requestStack
->getCurrentRequest()
->hasSession();
if (!$has_session) {
/** @var \Symfony\Component\HttpFoundation\Session\SessionInterface $session */
$session = \Drupal::service('session');
$this->requestStack->getCurrentRequest()->setSession($session);
$session->start();
}
}
}
@@ -188,7 +188,7 @@ class TypedDataManager extends DefaultPluginManager implements TypedDataManagerI
throw new \InvalidArgumentException("Property $property_name is unknown.");
}
// Create the prototype without any value, but with initial parenting
// so that constructors can set up the objects correclty.
// so that constructors can set up the objects correctly.
$this->prototypes[$key] = $this->create($definition, NULL, $property_name, $object);
}
@@ -197,7 +197,7 @@ class UpdateRegistry {
}
/**
* Registers that update fucntions got executed.
* Registers that update functions were executed.
*
* @param string[] $function_names
* The executed update functions.
+1 -1
View File
@@ -105,7 +105,7 @@ class Module extends Updater implements UpdaterInterface {
* {@inheritdoc}
*/
public function postInstallTasks() {
// Since this is being called outsite of the primary front controller,
// Since this is being called outside of the primary front controller,
// the base_url needs to be set explicitly to ensure that links are
// relative to the site root.
// @todo Simplify with https://www.drupal.org/node/2548095
+1 -1
View File
@@ -87,7 +87,7 @@ class Theme extends Updater implements UpdaterInterface {
* {@inheritdoc}
*/
public function postInstallTasks() {
// Since this is being called outsite of the primary front controller,
// Since this is being called outside of the primary front controller,
// the base_url needs to be set explicitly to ensure that links are
// relative to the site root.
// @todo Simplify with https://www.drupal.org/node/2548095
@@ -78,7 +78,6 @@ class UnroutedUrlAssembler implements UnroutedUrlAssemblerInterface {
$options += ['query' => []];
$options['query'] = NestedArray::mergeDeep($parsed['query'], $options['query']);
ksort($options['query']);
if ($parsed['fragment'] && !$options['fragment']) {
$options['fragment'] = '#' . $parsed['fragment'];
+1 -1
View File
@@ -28,7 +28,7 @@
* @type {Drupal~behavior}
*
* @prop {Drupal~behaviorAttach} attach
* Attaches the behavior for drupalAnnouce.
* Attaches the behavior for drupalAnnounce.
*/
Drupal.behaviors.drupalAnnounce = {
attach(context) {
+1 -1
View File
@@ -218,7 +218,7 @@
.find('input.form-autocomplete')
.once('autocomplete');
if ($autocomplete.length) {
// Allow options to be overriden per instance.
// Allow options to be overridden per instance.
const blacklist = $autocomplete.attr(
'data-autocomplete-first-character-blacklist',
);
+1 -1
View File
@@ -6,7 +6,7 @@
/**
* Fix problem with details/summary lines missing the drop arrows.
*/
@-moz-document url-prefix() {
@media (min--moz-device-pixel-ratio: 0) {
summary {
display: list-item;
}
+38 -12
View File
@@ -59,6 +59,30 @@
return typeof a === 'undefined' || typeof b === 'undefined';
}
/**
* Bitwise AND with a third undefined state.
*
* @function Drupal.states~ternary
*
* @param {*} a
* Value a.
* @param {*} b
* Value b
*
* @return {bool}
* The result.
*/
function ternary(a, b) {
if (typeof a === 'undefined') {
return b;
}
if (typeof b === 'undefined') {
return a;
}
return a && b;
}
/**
* Attaches the states.
*
@@ -305,18 +329,20 @@
// bogus, we don't want to end up with an infinite loop.
else if ($.isPlainObject(constraints)) {
// This constraint is an object (AND).
result = Object.keys(constraints).every(constraint => {
const check = this.checkConstraints(
constraints[constraint],
selector,
constraint,
);
/**
* The checkConstraints() function's return value can be undefined. If
* this so, consider it to have returned true.
*/
return typeof check === 'undefined' ? true : check;
});
// eslint-disable-next-line no-restricted-syntax
for (const n in constraints) {
if (constraints.hasOwnProperty(n)) {
result = ternary(
result,
this.checkConstraints(constraints[n], selector, n),
);
// False and anything else will evaluate to false, so return when
// any false condition is found.
if (result === false) {
return false;
}
}
}
}
return result;
},
+21 -8
View File
@@ -24,6 +24,17 @@
return typeof a === 'undefined' || typeof b === 'undefined';
}
function ternary(a, b) {
if (typeof a === 'undefined') {
return b;
}
if (typeof b === 'undefined') {
return a;
}
return a && b;
}
Drupal.behaviors.states = {
attach: function attach(context, settings) {
var $states = $(context).find('[data-drupal-states]');
@@ -127,8 +138,6 @@
}
},
verifyConstraints: function verifyConstraints(constraints, selector) {
var _this3 = this;
var result = void 0;
if ($.isArray(constraints)) {
var hasXor = $.inArray('xor', constraints) === -1;
@@ -144,11 +153,15 @@
}
}
} else if ($.isPlainObject(constraints)) {
result = Object.keys(constraints).every(function (constraint) {
var check = _this3.checkConstraints(constraints[constraint], selector, constraint);
for (var n in constraints) {
if (constraints.hasOwnProperty(n)) {
result = ternary(result, this.checkConstraints(constraints[n], selector, n));
return typeof check === 'undefined' ? true : check;
});
if (result === false) {
return false;
}
}
}
}
return result;
},
@@ -197,7 +210,7 @@
states.Trigger.prototype = {
initialize: function initialize() {
var _this4 = this;
var _this3 = this;
var trigger = states.Trigger.states[this.state];
@@ -205,7 +218,7 @@
trigger.call(window, this.element);
} else {
Object.keys(trigger || {}).forEach(function (event) {
_this4.defaultTrigger(event, trigger[event]);
_this3.defaultTrigger(event, trigger[event]);
});
}
@@ -40,7 +40,7 @@ class GotoAction extends ConfigurableActionBase implements ContainerFactoryPlugi
protected $unroutedUrlAssembler;
/**
* Constructs a new DeleteNode object.
* Constructs a GotoAction object.
*
* @param array $configuration
* A configuration array containing information about the plugin instance.
@@ -94,7 +94,7 @@ class ItemsImporter implements ItemsImporterInterface {
watchdog_exception('aggregator', $e);
}
// Store instances in an array so we dont have to instantiate new objects.
// Store instances in an array so we don't have to instantiate new objects.
$processor_instances = [];
foreach ($this->config->get('processors') as $processor) {
try {
@@ -33,7 +33,7 @@ class BlockedIP extends DestinationBase implements ContainerFactoryPluginInterfa
* @param string $plugin_id
* The plugin ID.
* @param mixed $plugin_definition
* The plugin definiiton.
* The plugin definition.
* @param \Drupal\migrate\Plugin\MigrationInterface $migration
* The current migration.
* @param \Drupal\ban\BanIpManagerInterface $ban_manager
@@ -2,8 +2,7 @@
namespace Drupal\block_content\Plugin\migrate\source\d6;
use Drupal\migrate\Row;
use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
use Drupal\block_content\Plugin\migrate\source\d7\BlockCustomTranslation as D7BlockCustomTranslation;
/**
* Gets Drupal 6 i18n custom block translations from database.
@@ -13,97 +12,12 @@ use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
* source_module = "i18nblocks"
* )
*/
class BoxTranslation extends DrupalSqlBase {
class BoxTranslation extends D7BlockCustomTranslation {
/**
* {@inheritdoc}
* Drupal 6 table names.
*/
public function query() {
// Build a query based on i18n_strings table where each row has the
// translation for only one property, either title or description. The
// method prepareRow() is then used to obtain the translation for the
// other property.
$query = $this->select('boxes', 'b')
->fields('b', ['bid', 'format', 'body'])
->fields('i18n', ['property'])
->fields('lt', ['lid', 'translation', 'language'])
->orderBy('b.bid')
->isNotNull('lt.lid');
// Use 'title' for the info field to match the property name in the
// i18n_strings table.
$query->addField('b', 'info', 'title');
// Add in the property, which is either title or body. Cast the bid to text
// so PostgreSQL can make the join.
$query->leftJoin('i18n_strings', 'i18n', 'i18n.objectid = CAST(b.bid as CHAR(255))');
$query->condition('i18n.type', 'block');
// Add in the translation for the property.
$query->leftJoin('locales_target', 'lt', 'lt.lid = i18n.lid');
return $query;
}
/**
* {@inheritdoc}
*/
public function prepareRow(Row $row) {
$language = $row->getSourceProperty('language');
$bid = $row->getSourceProperty('bid');
// If this row has been migrated it is a duplicate then skip it.
if ($this->idMap->lookupDestinationIds(['bid' => $bid, 'language' => $language])) {
return FALSE;
}
// Save the translation for this property.
$property = $row->getSourceProperty('property');
$row->setSourceProperty($property . '_translated', $row->getSourceProperty('translation'));
// Get the translation for the property not already in the row.
$translation = ($property === 'title') ? 'body' : 'title';
$query = $this->select('i18n_strings', 'i18n')
->fields('i18n', ['lid'])
->condition('i18n.property', $translation)
->condition('i18n.objectid', $bid);
$query->leftJoin('locales_target', 'lt', 'i18n.lid = lt.lid');
$query->condition('lt.language', $language)
->addField('lt', 'translation');
$results = $query->execute()->fetchAssoc();
if (!$results) {
$row->setSourceProperty($translation . '_translated', NULL);
}
else {
$row->setSourceProperty($translation . '_translated', $results['translation']);
}
}
/**
* {@inheritdoc}
*/
public function fields() {
return [
'bid' => $this->t('The block numeric identifier.'),
'format' => $this->t('Input format of the custom block/box content.'),
'lid' => $this->t('i18n_string table id'),
'language' => $this->t('Language for this field.'),
'property' => $this->t('Block property'),
'translation' => $this->t('The translation of the value of "property".'),
'title' => $this->t('Block title.'),
'title_translated' => $this->t('Block title translation.'),
'body' => $this->t('Block body.'),
'body_translated' => $this->t('Block body translation.'),
];
}
/**
* {@inheritdoc}
*/
public function getIds() {
$ids['bid']['type'] = 'integer';
$ids['bid']['alias'] = 'b';
$ids['language']['type'] = 'string';
return $ids;
}
const CUSTOM_BLOCK_TABLE = 'boxes';
const I18N_STRING_TABLE = 'i18n_strings';
}
@@ -0,0 +1,99 @@
<?php
namespace Drupal\block_content\Plugin\migrate\source\d7;
use Drupal\migrate\Row;
use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
use Drupal\content_translation\Plugin\migrate\source\I18nQueryTrait;
/**
* Gets Drupal 7 custom block translation from database.
*
* @MigrateSource(
* id = "d7_block_custom_translation",
* source_module = "block"
* )
*/
class BlockCustomTranslation extends DrupalSqlBase {
use I18nQueryTrait;
/**
* Drupal 7 table names.
*/
const CUSTOM_BLOCK_TABLE = 'block_custom';
const I18N_STRING_TABLE = 'i18n_string';
/**
* {@inheritdoc}
*/
public function query() {
// Build a query based on blockCustomTable table where each row has the
// translation for only one property, either title or description. The
// method prepareRow() is then used to obtain the translation for the
// other property.
$query = $this->select(static::CUSTOM_BLOCK_TABLE, 'b')
->fields('b', ['bid', 'format', 'body'])
->fields('i18n', ['property'])
->fields('lt', ['lid', 'translation', 'language'])
->orderBy('b.bid')
->isNotNull('lt.lid');
// Use 'title' for the info field to match the property name in
// i18nStringTable.
$query->addField('b', 'info', 'title');
// Add in the property, which is either title or body. Cast the bid to text
// so PostgreSQL can make the join.
$query->leftJoin(static::I18N_STRING_TABLE, 'i18n', 'i18n.objectid = CAST(b.bid as CHAR(255))');
$query->condition('i18n.type', 'block');
// Add in the translation for the property.
$query->leftJoin('locales_target', 'lt', 'lt.lid = i18n.lid');
return $query;
}
/**
* {@inheritdoc}
*/
public function prepareRow(Row $row) {
parent::prepareRow($row);
// Set the i18n string table for use in I18nQueryTrait.
$this->i18nStringTable = static::I18N_STRING_TABLE;
// Save the translation for this property.
$property_in_row = $row->getSourceProperty('property');
// Get the translation for the property not already in the row and save it
// in the row.
$property_not_in_row = ($property_in_row === 'title') ? 'body' : 'title';
return $this->getPropertyNotInRowTranslation($row, $property_not_in_row, 'bid', $this->idMap);
}
/**
* {@inheritdoc}
*/
public function fields() {
return [
'bid' => $this->t('The block numeric identifier.'),
'format' => $this->t('Input format of the custom block/box content.'),
'lid' => $this->t('i18n_string table id'),
'language' => $this->t('Language for this field.'),
'property' => $this->t('Block property'),
'translation' => $this->t('The translation of the value of "property".'),
'title' => $this->t('Block title.'),
'title_translated' => $this->t('Block title translation.'),
'body' => $this->t('Block body.'),
'body_translated' => $this->t('Block body translation.'),
];
}
/**
* {@inheritdoc}
*/
public function getIds() {
$ids['bid']['type'] = 'integer';
$ids['bid']['alias'] = 'b';
$ids['language']['type'] = 'string';
return $ids;
}
}
@@ -0,0 +1,69 @@
<?php
namespace Drupal\Tests\block_content\Kernel\Migrate\d7;
use Drupal\block_content\Entity\BlockContent;
use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase;
/**
* Tests migration of i18n custom block strings.
*
* @group migrate_drupal_7
*/
class MigrateCustomBlockContentTranslationTest extends MigrateDrupal7TestBase {
/**
* {@inheritdoc}
*/
public static $modules = [
'block_content',
'content_translation',
'filter',
'language',
'text',
// Required for translation migrations.
'migrate_drupal_multilingual',
];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installConfig(['block_content']);
$this->installEntitySchema('block_content');
$this->executeMigrations([
'language',
'd7_filter_format',
'block_content_type',
'block_content_body_field',
'd7_custom_block',
'd7_custom_block_translation',
]);
}
/**
* Tests the Drupal 7 i18n custom block strings to Drupal 8 migration.
*/
public function testCustomBlockContentTranslation() {
/** @var \Drupal\block_content\Entity\BlockContent $block */
$block = BlockContent::load(1)->getTranslation('fr');
$this->assertSame('fr - Mildly amusing limerick of the day', $block->label());
$this->assertGreaterThanOrEqual($block->getChangedTime(), \Drupal::time()->getRequestTime());
$this->assertLessThanOrEqual(time(), $block->getChangedTime());
$this->assertSame('fr', $block->language()->getId());
$translation = "fr - A fellow jumped off a high wall\r\nAnd had a most terrible fall\r\nHe went back to bed\r\nWith a bump on his head\r\nThat's why you don't jump off a wall";
$this->assertSame($translation, $block->body->value);
$this->assertSame('filtered_html', $block->body->format);
$block = $block->getTranslation('is');
$this->assertSame('is - Mildly amusing limerick of the day', $block->label());
$this->assertGreaterThanOrEqual($block->getChangedTime(), \Drupal::time()->getRequestTime());
$this->assertLessThanOrEqual(time(), $block->getChangedTime());
$this->assertSame('is', $block->language()->getId());
$text = "A fellow jumped off a high wall\r\nAnd had a most terrible fall\r\nHe went back to bed\r\nWith a bump on his head\r\nThat's why you don't jump off a wall";
$this->assertSame($text, $block->body->value);
$this->assertSame('filtered_html', $block->body->format);
}
}
@@ -0,0 +1,148 @@
<?php
namespace Drupal\Tests\block_content\Kernel\Plugin\migrate\source\d7;
use Drupal\Tests\migrate\Kernel\MigrateSqlSourceTestBase;
/**
* Tests i18n custom block translations source plugin.
*
* @covers \Drupal\block_content\Plugin\migrate\source\d7\BlockCustomTranslation
*
* @group content_translation
*/
class BlockCustomTranslationTest extends MigrateSqlSourceTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['block_content', 'migrate_drupal'];
/**
* {@inheritdoc}
*/
public function providerSource() {
$tests = [];
// The source data.
$tests[0]['database']['block_custom'] = [
[
'bid' => 1,
'body' => 'box 1 body',
'info' => 'box 1 title',
'format' => '2',
],
[
'bid' => 2,
'body' => 'box 2 body',
'info' => 'box 2 title',
'format' => '2',
],
];
$tests[0]['database']['i18n_string'] = [
[
'lid' => 1,
'objectid' => 1,
'type' => 'block',
'property' => 'title',
'objectindex' => 1,
'format' => 0,
],
[
'lid' => 2,
'objectid' => 1,
'type' => 'block',
'property' => 'body',
'objectindex' => 1,
'format' => 0,
],
[
'lid' => 3,
'objectid' => 2,
'type' => 'block',
'property' => 'body',
'objectindex' => 2,
'format' => 2,
],
];
$tests[0]['database']['locales_target'] = [
[
'lid' => 1,
'language' => 'fr',
'translation' => 'fr - title translation',
'plid' => 0,
'plural' => 0,
'i18n_status' => 0,
],
[
'lid' => 2,
'language' => 'fr',
'translation' => 'fr - body translation',
'plid' => 0,
'plural' => 0,
'i18n_status' => 0,
],
[
'lid' => 3,
'language' => 'zu',
'translation' => 'zu - body translation',
'plid' => 0,
'plural' => 0,
'i18n_status' => 0,
],
];
$tests[0]['database']['system'] = [
[
'type' => 'module',
'name' => 'system',
'schema_version' => '7001',
'status' => '1',
],
];
$tests[0]['expected_results'] = [
[
'lid' => '1',
'property' => 'title',
'language' => 'fr',
'translation' => 'fr - title translation',
'bid' => '1',
'format' => '2',
'title_translated' => 'fr - title translation',
'body_translated' => 'fr - body translation',
'title' => 'box 1 title',
'body' => 'box 1 body',
],
[
'lid' => '2',
'property' => 'body',
'language' => 'fr',
'translation' => 'fr - body translation',
'bid' => '1',
'format' => '2',
'title_translated' => 'fr - title translation',
'body_translated' => 'fr - body translation',
'title' => 'box 1 title',
'body' => 'box 1 body',
],
[
'lid' => '3',
'property' => 'body',
'language' => 'zu',
'translation' => 'zu - body translation',
'bid' => '2',
'format' => '2',
'title_translated' => NULL,
'body_translated' => 'zu - body translation',
'title' => 'box 2 title',
'body' => 'box 2 body',
],
];
return $tests;
}
}

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