"drupal/layout_plugin": "^1.0@alpha",
"drupal/draggableviews": "^1.0",
"roave/security-advisories": "dev-master",
- "phpunit/phpunit": "^4.8"
+ "phpunit/phpunit": "^4.8",
+
+ "drupal/video_embed_field": "^2.0",
+ "drupal/slick_media":"^2.0",
+ "drupal/media_entity_twitter":"^2.0",
+ "drupal/media_entity_slideshow":"^2.0",
+ "drupal/media_entity_instagram":"^2.0",
+ "drupal/image_widget_crop":"^2.1",
+ "drupal/crop":"^2.0",
+ "drupal/media_entity":"^2.0",
+ "drupal/media_entity_actions":"^1.0"
},
"require-dev": {
"behat/mink": "~1.7",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
- "content-hash": "3bf6ad42da4e57045e076b43e3ed0707",
+ "content-hash": "69e55683428b6248efcebe4900a9b8cd",
"packages": [
{
"name": "alchemy/zippy",
},
{
"name": "drupal/crop",
- "version": "1.5.0",
+ "version": "2.0.0-rc1",
"source": {
"type": "git",
"url": "https://git.drupal.org/project/crop",
- "reference": "8.x-1.5"
+ "reference": "8.x-2.0-rc1"
},
"dist": {
"type": "zip",
- "url": "https://ftp.drupal.org/files/projects/crop-8.x-1.5.zip",
- "reference": "8.x-1.5",
- "shasum": "bb275293508cb3988ca6ab766dc1f6ecc22cc03d"
+ "url": "https://ftp.drupal.org/files/projects/crop-8.x-2.0-rc1.zip",
+ "reference": "8.x-2.0-rc1",
+ "shasum": "ba84fa73e5c4df4caffcfa4a4cfb44c2c7d033d7"
},
"require": {
"drupal/core": "*"
"type": "drupal-module",
"extra": {
"branch-alias": {
- "dev-1.x": "1.x-dev"
+ "dev-2.x": "2.x-dev"
},
"drupal": {
- "version": "8.x-1.5",
- "datestamp": "1516357085",
+ "version": "8.x-2.0-rc1",
+ "datestamp": "1516298515",
"security-coverage": {
- "status": "covered",
- "message": "Covered by Drupal's security advisory policy"
+ "status": "not-covered",
+ "message": "RC releases are not covered by Drupal security advisories."
}
}
},
},
"drupal": {
"version": "8.x-1.0",
- "datestamp": "1477076039"
+ "datestamp": "1477076039",
+ "security-coverage": {
+ "status": "covered",
+ "message": "Covered by Drupal's security advisory policy"
+ }
},
"patches_applied": {
"Sort order not saved when using bootstrap theme": "https://www.drupal.org/files/issues/classes-defined-in-array-2729935-2.patch",
},
"notification-url": "https://packages.drupal.org/8/downloads",
"license": [
- "GPL-2.0+"
+ "GPL-2.0-or-later"
],
"authors": [
{
},
"type": "drupal-module",
"extra": {
- "installer-paths": {
- "web/core": [
- "type:drupal-core"
- ],
- "web/libraries/{$name}": [
- "type:drupal-library"
- ],
- "web/modules/contrib/{$name}": [
- "type:drupal-module"
- ],
- "web/profiles/contrib/{$name}": [
- "type:drupal-profile"
- ],
- "web/themes/contrib/{$name}": [
- "type:drupal-theme"
- ],
- "drush/contrib/{$name}": [
- "type:drupal-drush"
- ]
+ "branch-alias": {
+ "dev-2.x": "2.x-dev"
},
- "patches": {
- "drupal/security_review": {
- "Fix missing field review list": "https://www.drupal.org/files/issues/security_review-dangerous-tags-list-2744805-2.patch"
- },
- "drupal/draggableviews": {
- "Sort order not saved when using bootstrap theme": "https://www.drupal.org/files/issues/classes-defined-in-array-2729935-2.patch",
- "DraggableViews displays multiple node instances when used in multiple views": "https://www.drupal.org/files/issues/2867159_fixed_problems_with_duplicates_0.patch"
- },
- "drupal/hacked": {
- "Compatibility with diff module API change: Turn EntityComparisonBase into a service": "https://www.drupal.org/files/issues/hacked-diff-diff-service-2800645-2.patch"
- },
- "drupal/videojs": {
- "videojs-isapplicable": "https://www.drupal.org/files/issues/videojs-isapplicable.patch"
+ "drupal": {
+ "version": "8.x-2.0-beta2",
+ "datestamp": "1520956980",
+ "security-coverage": {
+ "status": "not-covered",
+ "message": "Project has not opted into security advisory coverage!"
}
- }
+ },
+ "patches_applied": []
},
"notification-url": "https://packages.drupal.org/8/downloads",
"license": [
},
{
"name": "drupal/media_entity",
- "version": "1.7.0",
+ "version": "2.0.0-beta2",
"source": {
"type": "git",
"url": "https://git.drupal.org/project/media_entity",
- "reference": "8.x-1.7"
+ "reference": "8.x-2.0-beta2"
},
"dist": {
"type": "zip",
- "url": "https://ftp.drupal.org/files/projects/media_entity-8.x-1.7.zip",
- "reference": "8.x-1.7",
- "shasum": "5f7ccdf1db07732f3c94e642e60d88746e73cc86"
+ "url": "https://ftp.drupal.org/files/projects/media_entity-8.x-2.0-beta2.zip",
+ "reference": "8.x-2.0-beta2",
+ "shasum": "2223e342634551041ef7fcb80c2860e5b62aed4e"
},
"require": {
"drupal/core": "*",
"drupal/entity": "*"
},
- "require-dev": {
- "drupal/entity": "*",
- "drupal/inline_entity_form": "*"
- },
"type": "drupal-module",
"extra": {
"branch-alias": {
- "dev-1.x": "1.x-dev"
+ "dev-2.x": "2.x-dev"
},
"drupal": {
- "version": "8.x-1.7",
- "datestamp": "1510737185",
+ "version": "8.x-2.0-beta2",
+ "datestamp": "1520603584",
"security-coverage": {
- "status": "covered",
- "message": "Covered by Drupal's security advisory policy"
+ "status": "not-covered",
+ "message": "Beta releases are not covered by Drupal security advisories."
}
}
},
"source": "http://cgit.drupalcode.org/media_entity"
}
},
+ {
+ "name": "drupal/media_entity_actions",
+ "version": "1.0.0-alpha2",
+ "source": {
+ "type": "git",
+ "url": "https://git.drupal.org/project/media_entity_actions",
+ "reference": "8.x-1.0-alpha2"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://ftp.drupal.org/files/projects/media_entity_actions-8.x-1.0-alpha2.zip",
+ "reference": "8.x-1.0-alpha2",
+ "shasum": "9bf7881f11fa182c1b6673c4cc8c32ce3a1bdb81"
+ },
+ "require": {
+ "drupal/core": "^8.4.0"
+ },
+ "type": "drupal-module",
+ "extra": {
+ "branch-alias": {
+ "dev-1.x": "1.x-dev"
+ },
+ "drupal": {
+ "version": "8.x-1.0-alpha2",
+ "datestamp": "1510588386",
+ "security-coverage": {
+ "status": "not-covered",
+ "message": "Project has not opted into security advisory coverage!"
+ }
+ }
+ },
+ "notification-url": "https://packages.drupal.org/8/downloads",
+ "license": [
+ "GPL-2.0-or-later"
+ ],
+ "authors": [
+ {
+ "name": "chr.fritsch",
+ "homepage": "https://www.drupal.org/user/2103716"
+ },
+ {
+ "name": "marcoscano",
+ "homepage": "https://www.drupal.org/user/1288796"
+ },
+ {
+ "name": "phenaproxima",
+ "homepage": "https://www.drupal.org/user/205645"
+ },
+ {
+ "name": "seanB",
+ "homepage": "https://www.drupal.org/user/545912"
+ },
+ {
+ "name": "slashrsm",
+ "homepage": "https://www.drupal.org/user/744628"
+ }
+ ],
+ "description": "Provides Actions plugins to be used with Media in core",
+ "homepage": "https://www.drupal.org/project/media_entity_actions",
+ "support": {
+ "source": "http://cgit.drupalcode.org/media_entity_actions"
+ }
+ },
{
"name": "drupal/media_entity_document",
- "version": "1.1.0",
+ "version": "1.0.0",
"source": {
"type": "git",
"url": "https://git.drupal.org/project/media_entity_document",
- "reference": "8.x-1.1"
+ "reference": "8.x-1.0"
},
"dist": {
"type": "zip",
- "url": "https://ftp.drupal.org/files/projects/media_entity_document-8.x-1.1.zip",
- "reference": "8.x-1.1",
- "shasum": "88a45820cf0aeb5f8a3ade3338007771191508e4"
+ "url": "https://ftp.drupal.org/files/projects/media_entity_document-8.x-1.0.zip",
+ "reference": "8.x-1.0",
+ "shasum": "fc4d87126ebb5ac3dc135809ff4dc96d955e6539"
},
"require": {
- "drupal/core": "~8.1",
- "drupal/media_entity": "~1.0 || ~8.1.0"
+ "drupal/core": "~8.0",
+ "drupal/media_entity": "*"
},
"type": "drupal-module",
"extra": {
"dev-1.x": "1.x-dev"
},
"drupal": {
- "version": "8.x-1.1",
- "datestamp": "1470211995"
+ "version": "8.x-1.0",
+ "datestamp": "1470211439",
+ "security-coverage": {
+ "status": "covered",
+ "message": "Covered by Drupal's security advisory policy"
+ }
}
},
"notification-url": "https://packages.drupal.org/8/downloads",
"license": [
- "GPL-2.0+"
+ "GPL-2.0-or-later"
],
"authors": [
{
"name": "NerOcrO",
- "homepage": "https://www.drupal.org/user/1728164",
- "role": "Maintainer"
+ "homepage": "https://www.drupal.org/user/1728164"
}
],
- "description": "Local documents integration for Drupal Media entity.",
+ "description": "Media entity local documents provider.",
"homepage": "https://www.drupal.org/project/media_entity_document",
- "keywords": [
- "Drupal",
- "document",
- "media"
- ],
"support": {
- "source": "https://www.drupal.org/project/media_entity_document",
- "issues": "https://www.drupal.org/project/issues/media_entity_document"
+ "source": "http://cgit.drupalcode.org/media_entity_document"
}
},
{
},
{
"name": "drupal/media_entity_instagram",
- "version": "1.4.0",
+ "version": "2.0.0-alpha1",
"source": {
"type": "git",
"url": "https://git.drupal.org/project/media_entity_instagram",
- "reference": "8.x-1.4"
+ "reference": "8.x-2.0-alpha1"
},
"dist": {
"type": "zip",
- "url": "https://ftp.drupal.org/files/projects/media_entity_instagram-8.x-1.4.zip",
- "reference": "8.x-1.4",
- "shasum": "2b69b90417f3c458b4db3ba890813c313d381f0e"
+ "url": "https://ftp.drupal.org/files/projects/media_entity_instagram-8.x-2.0-alpha1.zip",
+ "reference": "8.x-2.0-alpha1",
+ "shasum": "602d84d2e385ce2f3b0562f7cf50d1e084f92658"
},
"require": {
- "drupal/core": "~8.0",
- "drupal/media_entity": "*"
+ "drupal/core": "^8.4.0"
},
"type": "drupal-module",
"extra": {
"branch-alias": {
- "dev-1.x": "1.x-dev"
+ "dev-2.x": "2.x-dev"
},
"drupal": {
- "version": "8.x-1.4",
- "datestamp": "1495556283"
+ "version": "8.x-2.0-alpha1",
+ "datestamp": "1506671645",
+ "security-coverage": {
+ "status": "not-covered",
+ "message": "Alpha releases are not covered by Drupal security advisories."
+ }
}
},
"notification-url": "https://packages.drupal.org/8/downloads",
"license": [
- "GPL-2.0+"
+ "GPL-2.0-or-later"
],
"authors": [
{
},
{
"name": "drupal/media_entity_slideshow",
- "version": "1.2.0",
+ "version": "2.0.0-alpha1",
"source": {
"type": "git",
"url": "https://git.drupal.org/project/media_entity_slideshow",
- "reference": "8.x-1.2"
+ "reference": "8.x-2.0-alpha1"
},
"dist": {
"type": "zip",
- "url": "https://ftp.drupal.org/files/projects/media_entity_slideshow-8.x-1.2.zip",
- "reference": "8.x-1.2",
- "shasum": "c9d49eb6be7de0ea8e500554b89842842287cd1f"
+ "url": "https://ftp.drupal.org/files/projects/media_entity_slideshow-8.x-2.0-alpha1.zip",
+ "reference": "8.x-2.0-alpha1",
+ "shasum": "264358a2e03d2769459317841afdf7117927dc59"
},
"require": {
- "drupal/core": "~8.0",
- "drupal/media_entity": "*"
+ "drupal/core": "^8.4"
},
"type": "drupal-module",
"extra": {
"branch-alias": {
- "dev-1.x": "1.x-dev"
+ "dev-2.x": "2.x-dev"
},
"drupal": {
- "version": "8.x-1.2",
- "datestamp": "1470687839"
+ "version": "8.x-2.0-alpha1",
+ "datestamp": "1506688443",
+ "security-coverage": {
+ "status": "not-covered",
+ "message": "Alpha releases are not covered by Drupal security advisories."
+ }
}
},
"notification-url": "https://packages.drupal.org/8/downloads",
"license": [
- "GPL-2.0+"
+ "GPL-2.0-or-later"
],
"authors": [
{
},
{
"name": "drupal/media_entity_twitter",
- "version": "1.3.0",
+ "version": "2.0.0-alpha2",
"source": {
"type": "git",
"url": "https://git.drupal.org/project/media_entity_twitter",
- "reference": "8.x-1.3"
+ "reference": "8.x-2.0-alpha2"
},
"dist": {
"type": "zip",
- "url": "https://ftp.drupal.org/files/projects/media_entity_twitter-8.x-1.3.zip",
- "reference": "8.x-1.3",
- "shasum": "280406ba63e2c00befa9bb1434ad2d4d3113b239"
+ "url": "https://ftp.drupal.org/files/projects/media_entity_twitter-8.x-2.0-alpha2.zip",
+ "reference": "8.x-2.0-alpha2",
+ "shasum": "21925e1e1b02bbbcd6d8e9730bc587669edc0e5c"
},
"require": {
- "drupal/core": "~8.0",
- "drupal/media_entity": "*",
+ "drupal/core": "^8.4",
"j7mbo/twitter-api-php": "~1.0"
},
"type": "drupal-module",
"extra": {
"branch-alias": {
- "dev-1.x": "1.x-dev"
+ "dev-2.x": "2.x-dev"
},
"drupal": {
- "version": "8.x-1.3",
- "datestamp": "1478549339"
+ "version": "8.x-2.0-alpha2",
+ "datestamp": "1507907344",
+ "security-coverage": {
+ "status": "not-covered",
+ "message": "Alpha releases are not covered by Drupal security advisories."
+ }
}
},
"notification-url": "https://packages.drupal.org/8/downloads",
"license": [
- "GPL-2.0+"
+ "GPL-2.0-or-later"
],
"authors": [
{
"name": "Primsi",
"homepage": "https://www.drupal.org/user/282629"
},
+ {
+ "name": "chr.fritsch",
+ "homepage": "https://www.drupal.org/user/2103716"
+ },
{
"name": "slashrsm",
"homepage": "https://www.drupal.org/user/744628"
},
"type": "drupal-module",
"extra": {
- "installer-paths": {
- "web/core": [
- "type:drupal-core"
- ],
- "web/libraries/{$name}": [
- "type:drupal-library"
- ],
- "web/modules/contrib/{$name}": [
- "type:drupal-module"
- ],
- "web/profiles/contrib/{$name}": [
- "type:drupal-profile"
- ],
- "web/themes/contrib/{$name}": [
- "type:drupal-theme"
- ],
- "drush/contrib/{$name}": [
- "type:drupal-drush"
- ]
+ "branch-alias": {
+ "dev-1.x": "1.x-dev"
},
- "patches": {
- "drupal/security_review": {
- "Fix missing field review list": "https://www.drupal.org/files/issues/security_review-dangerous-tags-list-2744805-2.patch"
- },
- "drupal/draggableviews": {
- "Sort order not saved when using bootstrap theme": "https://www.drupal.org/files/issues/classes-defined-in-array-2729935-2.patch",
- "DraggableViews displays multiple node instances when used in multiple views": "https://www.drupal.org/files/issues/2867159_fixed_problems_with_duplicates_0.patch"
- },
- "drupal/hacked": {
- "Compatibility with diff module API change: Turn EntityComparisonBase into a service": "https://www.drupal.org/files/issues/hacked-diff-diff-service-2800645-2.patch"
- },
- "drupal/videojs": {
- "videojs-isapplicable": "https://www.drupal.org/files/issues/videojs-isapplicable.patch"
+ "drupal": {
+ "version": "8.x-1.x-dev",
+ "datestamp": "1519158780",
+ "security-coverage": {
+ "status": "not-covered",
+ "message": "Dev releases are not covered by Drupal security advisories."
}
- }
+ },
+ "patches_applied": []
},
"notification-url": "https://packages.drupal.org/8/downloads",
"license": [
},
{
"name": "drupal/slick_media",
- "version": "1.0.0",
+ "version": "2.0.0-alpha1",
"source": {
"type": "git",
"url": "https://git.drupal.org/project/slick_media",
- "reference": "8.x-1.0"
+ "reference": "8.x-2.0-alpha1"
},
"dist": {
"type": "zip",
- "url": "https://ftp.drupal.org/files/projects/slick_media-8.x-1.0.zip",
- "reference": "8.x-1.0",
- "shasum": "b85a9899c53ca2f59f7cdbba044e2f58ae71e092"
+ "url": "https://ftp.drupal.org/files/projects/slick_media-8.x-2.0-alpha1.zip",
+ "reference": "8.x-2.0-alpha1",
+ "shasum": "b7efb7edabd444be1f3ad925efcfa2eabb7a4fdf"
},
"require": {
- "drupal/core": "~8.0",
- "drupal/media_entity_image": "*",
+ "drupal/core": "^8.4",
"drupal/slick": "*",
"drupal/video_embed_media": "*"
},
"type": "drupal-module",
"extra": {
"branch-alias": {
- "dev-1.x": "1.x-dev"
+ "dev-2.x": "2.x-dev"
},
"drupal": {
- "version": "8.x-1.0",
- "datestamp": "1495747983"
+ "version": "8.x-2.0-alpha1",
+ "datestamp": "1514970784",
+ "security-coverage": {
+ "status": "not-covered",
+ "message": "Alpha releases are not covered by Drupal security advisories."
+ }
}
},
"notification-url": "https://packages.drupal.org/8/downloads",
"license": [
- "GPL-2.0+"
+ "GPL-2.0-or-later"
],
"authors": [
+ {
+ "name": "chr.fritsch",
+ "homepage": "https://www.drupal.org/user/2103716"
+ },
{
"name": "gausarts",
"homepage": "https://www.drupal.org/user/159062"
},
"drupal": {
"version": "8.x-1.0",
- "datestamp": "1454344739"
+ "datestamp": "1454344739",
+ "security-coverage": {
+ "status": "covered",
+ "message": "Covered by Drupal's security advisory policy"
+ }
},
"patches_applied": {
"videojs-isapplicable": "https://www.drupal.org/files/issues/videojs-isapplicable.patch"
},
"notification-url": "https://packages.drupal.org/8/downloads",
"license": [
- "GPL-2.0+"
+ "GPL-2.0-or-later"
],
"authors": [
{
},
{
"name": "symfony/debug",
- "version": "v3.4.9",
+ "version": "v3.4.10",
"source": {
"type": "git",
"url": "https://github.com/symfony/debug.git",
- "reference": "1b95888cfd996484527cb41e8952d9a5eaf7454f"
+ "reference": "b28fd73fefbac341f673f5efd707d539d6a19f68"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/debug/zipball/1b95888cfd996484527cb41e8952d9a5eaf7454f",
- "reference": "1b95888cfd996484527cb41e8952d9a5eaf7454f",
+ "url": "https://api.github.com/repos/symfony/debug/zipball/b28fd73fefbac341f673f5efd707d539d6a19f68",
+ "reference": "b28fd73fefbac341f673f5efd707d539d6a19f68",
"shasum": ""
},
"require": {
],
"description": "Symfony Debug Component",
"homepage": "https://symfony.com",
- "time": "2018-04-30T16:53:52+00:00"
+ "time": "2018-05-16T14:03:39+00:00"
},
{
"name": "symfony/dependency-injection",
- "version": "v3.4.9",
+ "version": "v3.4.10",
"source": {
"type": "git",
"url": "https://github.com/symfony/dependency-injection.git",
- "reference": "54ff9d78b56429f9a1ac12e60bfb6d169c0468e3"
+ "reference": "c2741b26377804e3d70775a3ef29335685ee9b71"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/54ff9d78b56429f9a1ac12e60bfb6d169c0468e3",
- "reference": "54ff9d78b56429f9a1ac12e60bfb6d169c0468e3",
+ "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/c2741b26377804e3d70775a3ef29335685ee9b71",
+ "reference": "c2741b26377804e3d70775a3ef29335685ee9b71",
"shasum": ""
},
"require": {
],
"description": "Symfony DependencyInjection Component",
"homepage": "https://symfony.com",
- "time": "2018-04-29T14:04:08+00:00"
+ "time": "2018-05-18T01:58:36+00:00"
},
{
"name": "symfony/dom-crawler",
- "version": "v3.4.9",
+ "version": "v3.4.10",
"source": {
"type": "git",
"url": "https://github.com/symfony/dom-crawler.git",
- "reference": "1a4cffeb059226ff6bee9f48acb388faf674afff"
+ "reference": "201b210fafcdd193c1e45b2994bf7133fb6263e8"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/1a4cffeb059226ff6bee9f48acb388faf674afff",
- "reference": "1a4cffeb059226ff6bee9f48acb388faf674afff",
+ "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/201b210fafcdd193c1e45b2994bf7133fb6263e8",
+ "reference": "201b210fafcdd193c1e45b2994bf7133fb6263e8",
"shasum": ""
},
"require": {
"php": "^5.5.9|>=7.0.8",
+ "symfony/polyfill-ctype": "~1.8",
"symfony/polyfill-mbstring": "~1.0"
},
"require-dev": {
],
"description": "Symfony DomCrawler Component",
"homepage": "https://symfony.com",
- "time": "2018-03-19T22:32:39+00:00"
+ "time": "2018-05-01T22:53:27+00:00"
},
{
"name": "symfony/event-dispatcher",
- "version": "v3.4.9",
+ "version": "v3.4.10",
"source": {
"type": "git",
"url": "https://github.com/symfony/event-dispatcher.git",
},
{
"name": "symfony/filesystem",
- "version": "v3.4.9",
+ "version": "v3.4.10",
"source": {
"type": "git",
"url": "https://github.com/symfony/filesystem.git",
- "reference": "253a4490b528597aa14d2bf5aeded6f5e5e4a541"
+ "reference": "8e03ca3fa52a0f56b87506f38cf7bd3f9442b3a0"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/filesystem/zipball/253a4490b528597aa14d2bf5aeded6f5e5e4a541",
- "reference": "253a4490b528597aa14d2bf5aeded6f5e5e4a541",
+ "url": "https://api.github.com/repos/symfony/filesystem/zipball/8e03ca3fa52a0f56b87506f38cf7bd3f9442b3a0",
+ "reference": "8e03ca3fa52a0f56b87506f38cf7bd3f9442b3a0",
"shasum": ""
},
"require": {
- "php": "^5.5.9|>=7.0.8"
+ "php": "^5.5.9|>=7.0.8",
+ "symfony/polyfill-ctype": "~1.8"
},
"type": "library",
"extra": {
],
"description": "Symfony Filesystem Component",
"homepage": "https://symfony.com",
- "time": "2018-02-22T10:48:49+00:00"
+ "time": "2018-05-16T08:49:21+00:00"
},
{
"name": "symfony/finder",
- "version": "v3.4.9",
+ "version": "v3.4.10",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
- "reference": "bd14efe8b1fabc4de82bf50dce62f05f9a102433"
+ "reference": "472a92f3df8b247b49ae364275fb32943b9656c6"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/finder/zipball/bd14efe8b1fabc4de82bf50dce62f05f9a102433",
- "reference": "bd14efe8b1fabc4de82bf50dce62f05f9a102433",
+ "url": "https://api.github.com/repos/symfony/finder/zipball/472a92f3df8b247b49ae364275fb32943b9656c6",
+ "reference": "472a92f3df8b247b49ae364275fb32943b9656c6",
"shasum": ""
},
"require": {
],
"description": "Symfony Finder Component",
"homepage": "https://symfony.com",
- "time": "2018-04-04T05:07:11+00:00"
+ "time": "2018-05-16T08:49:21+00:00"
},
{
"name": "symfony/http-foundation",
- "version": "v3.4.9",
+ "version": "v3.4.10",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-foundation.git",
- "reference": "edc43b1a50402bb06b5111eb86b275c87a93e373"
+ "reference": "9a7469ec3e0225e7f0e14264bcd9e838e16186fe"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/http-foundation/zipball/edc43b1a50402bb06b5111eb86b275c87a93e373",
- "reference": "edc43b1a50402bb06b5111eb86b275c87a93e373",
+ "url": "https://api.github.com/repos/symfony/http-foundation/zipball/9a7469ec3e0225e7f0e14264bcd9e838e16186fe",
+ "reference": "9a7469ec3e0225e7f0e14264bcd9e838e16186fe",
"shasum": ""
},
"require": {
],
"description": "Symfony HttpFoundation Component",
"homepage": "https://symfony.com",
- "time": "2018-04-30T01:05:13+00:00"
+ "time": "2018-05-16T08:49:21+00:00"
},
{
"name": "symfony/http-kernel",
- "version": "v3.4.9",
+ "version": "v3.4.10",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-kernel.git",
- "reference": "280fcedbcb3dabcc467a9c1734054af61928fe4f"
+ "reference": "66644bc7d17cc071d796efab9b950adbb86da134"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/http-kernel/zipball/280fcedbcb3dabcc467a9c1734054af61928fe4f",
- "reference": "280fcedbcb3dabcc467a9c1734054af61928fe4f",
+ "url": "https://api.github.com/repos/symfony/http-kernel/zipball/66644bc7d17cc071d796efab9b950adbb86da134",
+ "reference": "66644bc7d17cc071d796efab9b950adbb86da134",
"shasum": ""
},
"require": {
"psr/log": "~1.0",
"symfony/debug": "~2.8|~3.0|~4.0",
"symfony/event-dispatcher": "~2.8|~3.0|~4.0",
- "symfony/http-foundation": "^3.4.4|^4.0.4"
+ "symfony/http-foundation": "^3.4.4|^4.0.4",
+ "symfony/polyfill-ctype": "~1.8"
},
"conflict": {
"symfony/config": "<2.8",
],
"description": "Symfony HttpKernel Component",
"homepage": "https://symfony.com",
- "time": "2018-04-30T19:27:02+00:00"
+ "time": "2018-05-21T13:44:03+00:00"
},
{
"name": "symfony/polyfill-ctype",
},
{
"name": "symfony/serializer",
- "version": "v3.4.9",
+ "version": "v3.4.10",
"source": {
"type": "git",
"url": "https://github.com/symfony/serializer.git",
- "reference": "d4dc1551da627273230fe16511f4bb4844c02399"
+ "reference": "2f3630bb2b855de2284798db34d3ac5734766575"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/serializer/zipball/d4dc1551da627273230fe16511f4bb4844c02399",
- "reference": "d4dc1551da627273230fe16511f4bb4844c02399",
+ "url": "https://api.github.com/repos/symfony/serializer/zipball/2f3630bb2b855de2284798db34d3ac5734766575",
+ "reference": "2f3630bb2b855de2284798db34d3ac5734766575",
"shasum": ""
},
"require": {
- "php": "^5.5.9|>=7.0.8"
+ "php": "^5.5.9|>=7.0.8",
+ "symfony/polyfill-ctype": "~1.8"
},
"conflict": {
"phpdocumentor/type-resolver": "<0.2.1",
],
"description": "Symfony Serializer Component",
"homepage": "https://symfony.com",
- "time": "2018-03-15T19:08:29+00:00"
+ "time": "2018-05-16T12:49:49+00:00"
},
{
"name": "symfony/translation",
- "version": "v3.4.9",
+ "version": "v3.4.10",
"source": {
"type": "git",
"url": "https://github.com/symfony/translation.git",
- "reference": "d4af50f46cd8171fd5c1cdebdb9a8bbcd8078c6c"
+ "reference": "7047f725e35eab768137c677f8c38e4a2a8e38fb"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/translation/zipball/d4af50f46cd8171fd5c1cdebdb9a8bbcd8078c6c",
- "reference": "d4af50f46cd8171fd5c1cdebdb9a8bbcd8078c6c",
+ "url": "https://api.github.com/repos/symfony/translation/zipball/7047f725e35eab768137c677f8c38e4a2a8e38fb",
+ "reference": "7047f725e35eab768137c677f8c38e4a2a8e38fb",
"shasum": ""
},
"require": {
],
"description": "Symfony Translation Component",
"homepage": "https://symfony.com",
- "time": "2018-04-30T01:22:56+00:00"
+ "time": "2018-05-21T10:06:52+00:00"
},
{
"name": "symfony/validator",
- "version": "v3.4.9",
+ "version": "v3.4.10",
"source": {
"type": "git",
"url": "https://github.com/symfony/validator.git",
- "reference": "d562929598e5f3cb3947937c9ccfb18d977a16b3"
+ "reference": "62ccdf62042fbca3be1e7b2dae84965940023362"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/validator/zipball/d562929598e5f3cb3947937c9ccfb18d977a16b3",
- "reference": "d562929598e5f3cb3947937c9ccfb18d977a16b3",
+ "url": "https://api.github.com/repos/symfony/validator/zipball/62ccdf62042fbca3be1e7b2dae84965940023362",
+ "reference": "62ccdf62042fbca3be1e7b2dae84965940023362",
"shasum": ""
},
"require": {
"php": "^5.5.9|>=7.0.8",
+ "symfony/polyfill-ctype": "~1.8",
"symfony/polyfill-mbstring": "~1.0",
"symfony/translation": "~2.8|~3.0|~4.0"
},
],
"description": "Symfony Validator Component",
"homepage": "https://symfony.com",
- "time": "2018-04-20T10:02:27+00:00"
+ "time": "2018-05-18T02:00:55+00:00"
},
{
"name": "symfony/var-dumper",
- "version": "v3.4.9",
+ "version": "v3.4.10",
"source": {
"type": "git",
"url": "https://github.com/symfony/var-dumper.git",
},
{
"name": "symfony/yaml",
- "version": "v3.4.9",
+ "version": "v3.4.10",
"source": {
"type": "git",
"url": "https://github.com/symfony/yaml.git",
- "reference": "033cfa61ef06ee0847e056e530201842b6e926c3"
+ "reference": "c5010cc1692ce1fa328b1fb666961eb3d4a85bb0"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/yaml/zipball/033cfa61ef06ee0847e056e530201842b6e926c3",
- "reference": "033cfa61ef06ee0847e056e530201842b6e926c3",
+ "url": "https://api.github.com/repos/symfony/yaml/zipball/c5010cc1692ce1fa328b1fb666961eb3d4a85bb0",
+ "reference": "c5010cc1692ce1fa328b1fb666961eb3d4a85bb0",
"shasum": ""
},
"require": {
- "php": "^5.5.9|>=7.0.8"
+ "php": "^5.5.9|>=7.0.8",
+ "symfony/polyfill-ctype": "~1.8"
},
"conflict": {
"symfony/console": "<3.4"
],
"description": "Symfony Yaml Component",
"homepage": "https://symfony.com",
- "time": "2018-04-08T08:21:29+00:00"
+ "time": "2018-05-03T23:18:14+00:00"
},
{
"name": "twbs/bootstrap-sass",
},
{
"name": "symfony/browser-kit",
- "version": "v3.4.9",
+ "version": "v3.4.10",
"source": {
"type": "git",
"url": "https://github.com/symfony/browser-kit.git",
$baseDir = dirname($vendorDir);
return array(
- '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
'320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php',
+ '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
'5255c38a0faeba867671b61dfda6d864' => $vendorDir . '/paragonie/random_compat/lib/random.php',
'023d27dca8066ef29e6739335ea73bad' => $vendorDir . '/symfony/polyfill-php70/bootstrap.php',
'c964ee0ededf28c96ebd9db5099ef910' => $vendorDir . '/guzzlehttp/promises/src/functions_include.php',
class ComposerStaticInit045d6a3105edf51cf91c16e965235549
{
public static $files = array (
- '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
'320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php',
+ '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
'5255c38a0faeba867671b61dfda6d864' => __DIR__ . '/..' . '/paragonie/random_compat/lib/random.php',
'023d27dca8066ef29e6739335ea73bad' => __DIR__ . '/..' . '/symfony/polyfill-php70/bootstrap.php',
'c964ee0ededf28c96ebd9db5099ef910' => __DIR__ . '/..' . '/guzzlehttp/promises/src/functions_include.php',
},
{
"name": "drupal/crop",
- "version": "1.5.0",
- "version_normalized": "1.5.0.0",
+ "version": "2.0.0-rc1",
+ "version_normalized": "2.0.0.0-RC1",
"source": {
"type": "git",
"url": "https://git.drupal.org/project/crop",
- "reference": "8.x-1.5"
+ "reference": "8.x-2.0-rc1"
},
"dist": {
"type": "zip",
- "url": "https://ftp.drupal.org/files/projects/crop-8.x-1.5.zip",
- "reference": "8.x-1.5",
- "shasum": "bb275293508cb3988ca6ab766dc1f6ecc22cc03d"
+ "url": "https://ftp.drupal.org/files/projects/crop-8.x-2.0-rc1.zip",
+ "reference": "8.x-2.0-rc1",
+ "shasum": "ba84fa73e5c4df4caffcfa4a4cfb44c2c7d033d7"
},
"require": {
"drupal/core": "*"
"type": "drupal-module",
"extra": {
"branch-alias": {
- "dev-1.x": "1.x-dev"
+ "dev-2.x": "2.x-dev"
},
"drupal": {
- "version": "8.x-1.5",
- "datestamp": "1516357085",
+ "version": "8.x-2.0-rc1",
+ "datestamp": "1516298515",
"security-coverage": {
- "status": "covered",
- "message": "Covered by Drupal's security advisory policy"
+ "status": "not-covered",
+ "message": "RC releases are not covered by Drupal security advisories."
}
}
},
},
"drupal": {
"version": "8.x-1.0",
- "datestamp": "1477076039"
+ "datestamp": "1477076039",
+ "security-coverage": {
+ "status": "covered",
+ "message": "Covered by Drupal's security advisory policy"
+ }
},
"patches_applied": {
"Sort order not saved when using bootstrap theme": "https://www.drupal.org/files/issues/classes-defined-in-array-2729935-2.patch",
"installation-source": "dist",
"notification-url": "https://packages.drupal.org/8/downloads",
"license": [
- "GPL-2.0+"
+ "GPL-2.0-or-later"
],
"authors": [
{
},
"type": "drupal-module",
"extra": {
- "installer-paths": {
- "web/core": [
- "type:drupal-core"
- ],
- "web/libraries/{$name}": [
- "type:drupal-library"
- ],
- "web/modules/contrib/{$name}": [
- "type:drupal-module"
- ],
- "web/profiles/contrib/{$name}": [
- "type:drupal-profile"
- ],
- "web/themes/contrib/{$name}": [
- "type:drupal-theme"
- ],
- "drush/contrib/{$name}": [
- "type:drupal-drush"
- ]
+ "branch-alias": {
+ "dev-2.x": "2.x-dev"
},
- "patches": {
- "drupal/security_review": {
- "Fix missing field review list": "https://www.drupal.org/files/issues/security_review-dangerous-tags-list-2744805-2.patch"
- },
- "drupal/draggableviews": {
- "Sort order not saved when using bootstrap theme": "https://www.drupal.org/files/issues/classes-defined-in-array-2729935-2.patch",
- "DraggableViews displays multiple node instances when used in multiple views": "https://www.drupal.org/files/issues/2867159_fixed_problems_with_duplicates_0.patch"
- },
- "drupal/hacked": {
- "Compatibility with diff module API change: Turn EntityComparisonBase into a service": "https://www.drupal.org/files/issues/hacked-diff-diff-service-2800645-2.patch"
- },
- "drupal/videojs": {
- "videojs-isapplicable": "https://www.drupal.org/files/issues/videojs-isapplicable.patch"
+ "drupal": {
+ "version": "8.x-2.0-beta2",
+ "datestamp": "1520956980",
+ "security-coverage": {
+ "status": "not-covered",
+ "message": "Project has not opted into security advisory coverage!"
}
- }
+ },
+ "patches_applied": []
},
"installation-source": "dist",
"notification-url": "https://packages.drupal.org/8/downloads",
},
{
"name": "drupal/media_entity",
- "version": "1.7.0",
- "version_normalized": "1.7.0.0",
+ "version": "2.0.0-beta2",
+ "version_normalized": "2.0.0.0-beta2",
"source": {
"type": "git",
"url": "https://git.drupal.org/project/media_entity",
- "reference": "8.x-1.7"
+ "reference": "8.x-2.0-beta2"
},
"dist": {
"type": "zip",
- "url": "https://ftp.drupal.org/files/projects/media_entity-8.x-1.7.zip",
- "reference": "8.x-1.7",
- "shasum": "5f7ccdf1db07732f3c94e642e60d88746e73cc86"
+ "url": "https://ftp.drupal.org/files/projects/media_entity-8.x-2.0-beta2.zip",
+ "reference": "8.x-2.0-beta2",
+ "shasum": "2223e342634551041ef7fcb80c2860e5b62aed4e"
},
"require": {
"drupal/core": "*",
"drupal/entity": "*"
},
- "require-dev": {
- "drupal/entity": "*",
- "drupal/inline_entity_form": "*"
- },
"type": "drupal-module",
"extra": {
"branch-alias": {
- "dev-1.x": "1.x-dev"
+ "dev-2.x": "2.x-dev"
},
"drupal": {
- "version": "8.x-1.7",
- "datestamp": "1510737185",
+ "version": "8.x-2.0-beta2",
+ "datestamp": "1520603584",
"security-coverage": {
- "status": "covered",
- "message": "Covered by Drupal's security advisory policy"
+ "status": "not-covered",
+ "message": "Beta releases are not covered by Drupal security advisories."
}
}
},
"source": "http://cgit.drupalcode.org/media_entity"
}
},
+ {
+ "name": "drupal/media_entity_actions",
+ "version": "1.0.0-alpha2",
+ "version_normalized": "1.0.0.0-alpha2",
+ "source": {
+ "type": "git",
+ "url": "https://git.drupal.org/project/media_entity_actions",
+ "reference": "8.x-1.0-alpha2"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://ftp.drupal.org/files/projects/media_entity_actions-8.x-1.0-alpha2.zip",
+ "reference": "8.x-1.0-alpha2",
+ "shasum": "9bf7881f11fa182c1b6673c4cc8c32ce3a1bdb81"
+ },
+ "require": {
+ "drupal/core": "^8.4.0"
+ },
+ "type": "drupal-module",
+ "extra": {
+ "branch-alias": {
+ "dev-1.x": "1.x-dev"
+ },
+ "drupal": {
+ "version": "8.x-1.0-alpha2",
+ "datestamp": "1510588386",
+ "security-coverage": {
+ "status": "not-covered",
+ "message": "Project has not opted into security advisory coverage!"
+ }
+ }
+ },
+ "installation-source": "dist",
+ "notification-url": "https://packages.drupal.org/8/downloads",
+ "license": [
+ "GPL-2.0-or-later"
+ ],
+ "authors": [
+ {
+ "name": "chr.fritsch",
+ "homepage": "https://www.drupal.org/user/2103716"
+ },
+ {
+ "name": "marcoscano",
+ "homepage": "https://www.drupal.org/user/1288796"
+ },
+ {
+ "name": "phenaproxima",
+ "homepage": "https://www.drupal.org/user/205645"
+ },
+ {
+ "name": "seanB",
+ "homepage": "https://www.drupal.org/user/545912"
+ },
+ {
+ "name": "slashrsm",
+ "homepage": "https://www.drupal.org/user/744628"
+ }
+ ],
+ "description": "Provides Actions plugins to be used with Media in core",
+ "homepage": "https://www.drupal.org/project/media_entity_actions",
+ "support": {
+ "source": "http://cgit.drupalcode.org/media_entity_actions"
+ }
+ },
{
"name": "drupal/media_entity_document",
- "version": "1.1.0",
- "version_normalized": "1.1.0.0",
+ "version": "1.0.0",
+ "version_normalized": "1.0.0.0",
"source": {
"type": "git",
"url": "https://git.drupal.org/project/media_entity_document",
- "reference": "8.x-1.1"
+ "reference": "8.x-1.0"
},
"dist": {
"type": "zip",
- "url": "https://ftp.drupal.org/files/projects/media_entity_document-8.x-1.1.zip",
- "reference": "8.x-1.1",
- "shasum": "88a45820cf0aeb5f8a3ade3338007771191508e4"
+ "url": "https://ftp.drupal.org/files/projects/media_entity_document-8.x-1.0.zip",
+ "reference": "8.x-1.0",
+ "shasum": "fc4d87126ebb5ac3dc135809ff4dc96d955e6539"
},
"require": {
- "drupal/core": "~8.1",
- "drupal/media_entity": "~1.0 || ~8.1.0"
+ "drupal/core": "~8.0",
+ "drupal/media_entity": "*"
},
"type": "drupal-module",
"extra": {
"dev-1.x": "1.x-dev"
},
"drupal": {
- "version": "8.x-1.1",
- "datestamp": "1470211995"
+ "version": "8.x-1.0",
+ "datestamp": "1470211439",
+ "security-coverage": {
+ "status": "covered",
+ "message": "Covered by Drupal's security advisory policy"
+ }
}
},
"installation-source": "dist",
"notification-url": "https://packages.drupal.org/8/downloads",
"license": [
- "GPL-2.0+"
+ "GPL-2.0-or-later"
],
"authors": [
{
"name": "NerOcrO",
- "homepage": "https://www.drupal.org/user/1728164",
- "role": "Maintainer"
+ "homepage": "https://www.drupal.org/user/1728164"
}
],
- "description": "Local documents integration for Drupal Media entity.",
+ "description": "Media entity local documents provider.",
"homepage": "https://www.drupal.org/project/media_entity_document",
- "keywords": [
- "Drupal",
- "document",
- "media"
- ],
"support": {
- "source": "https://www.drupal.org/project/media_entity_document",
- "issues": "https://www.drupal.org/project/issues/media_entity_document"
+ "source": "http://cgit.drupalcode.org/media_entity_document"
}
},
{
},
{
"name": "drupal/media_entity_instagram",
- "version": "1.4.0",
- "version_normalized": "1.4.0.0",
+ "version": "2.0.0-alpha1",
+ "version_normalized": "2.0.0.0-alpha1",
"source": {
"type": "git",
"url": "https://git.drupal.org/project/media_entity_instagram",
- "reference": "8.x-1.4"
+ "reference": "8.x-2.0-alpha1"
},
"dist": {
"type": "zip",
- "url": "https://ftp.drupal.org/files/projects/media_entity_instagram-8.x-1.4.zip",
- "reference": "8.x-1.4",
- "shasum": "2b69b90417f3c458b4db3ba890813c313d381f0e"
+ "url": "https://ftp.drupal.org/files/projects/media_entity_instagram-8.x-2.0-alpha1.zip",
+ "reference": "8.x-2.0-alpha1",
+ "shasum": "602d84d2e385ce2f3b0562f7cf50d1e084f92658"
},
"require": {
- "drupal/core": "~8.0",
- "drupal/media_entity": "*"
+ "drupal/core": "^8.4.0"
},
"type": "drupal-module",
"extra": {
"branch-alias": {
- "dev-1.x": "1.x-dev"
+ "dev-2.x": "2.x-dev"
},
"drupal": {
- "version": "8.x-1.4",
- "datestamp": "1495556283"
+ "version": "8.x-2.0-alpha1",
+ "datestamp": "1506671645",
+ "security-coverage": {
+ "status": "not-covered",
+ "message": "Alpha releases are not covered by Drupal security advisories."
+ }
}
},
"installation-source": "dist",
"notification-url": "https://packages.drupal.org/8/downloads",
"license": [
- "GPL-2.0+"
+ "GPL-2.0-or-later"
],
"authors": [
{
},
{
"name": "drupal/media_entity_slideshow",
- "version": "1.2.0",
- "version_normalized": "1.2.0.0",
+ "version": "2.0.0-alpha1",
+ "version_normalized": "2.0.0.0-alpha1",
"source": {
"type": "git",
"url": "https://git.drupal.org/project/media_entity_slideshow",
- "reference": "8.x-1.2"
+ "reference": "8.x-2.0-alpha1"
},
"dist": {
"type": "zip",
- "url": "https://ftp.drupal.org/files/projects/media_entity_slideshow-8.x-1.2.zip",
- "reference": "8.x-1.2",
- "shasum": "c9d49eb6be7de0ea8e500554b89842842287cd1f"
+ "url": "https://ftp.drupal.org/files/projects/media_entity_slideshow-8.x-2.0-alpha1.zip",
+ "reference": "8.x-2.0-alpha1",
+ "shasum": "264358a2e03d2769459317841afdf7117927dc59"
},
"require": {
- "drupal/core": "~8.0",
- "drupal/media_entity": "*"
+ "drupal/core": "^8.4"
},
"type": "drupal-module",
"extra": {
"branch-alias": {
- "dev-1.x": "1.x-dev"
+ "dev-2.x": "2.x-dev"
},
"drupal": {
- "version": "8.x-1.2",
- "datestamp": "1470687839"
+ "version": "8.x-2.0-alpha1",
+ "datestamp": "1506688443",
+ "security-coverage": {
+ "status": "not-covered",
+ "message": "Alpha releases are not covered by Drupal security advisories."
+ }
}
},
"installation-source": "dist",
"notification-url": "https://packages.drupal.org/8/downloads",
"license": [
- "GPL-2.0+"
+ "GPL-2.0-or-later"
],
"authors": [
{
},
{
"name": "drupal/media_entity_twitter",
- "version": "1.3.0",
- "version_normalized": "1.3.0.0",
+ "version": "2.0.0-alpha2",
+ "version_normalized": "2.0.0.0-alpha2",
"source": {
"type": "git",
"url": "https://git.drupal.org/project/media_entity_twitter",
- "reference": "8.x-1.3"
+ "reference": "8.x-2.0-alpha2"
},
"dist": {
"type": "zip",
- "url": "https://ftp.drupal.org/files/projects/media_entity_twitter-8.x-1.3.zip",
- "reference": "8.x-1.3",
- "shasum": "280406ba63e2c00befa9bb1434ad2d4d3113b239"
+ "url": "https://ftp.drupal.org/files/projects/media_entity_twitter-8.x-2.0-alpha2.zip",
+ "reference": "8.x-2.0-alpha2",
+ "shasum": "21925e1e1b02bbbcd6d8e9730bc587669edc0e5c"
},
"require": {
- "drupal/core": "~8.0",
- "drupal/media_entity": "*",
+ "drupal/core": "^8.4",
"j7mbo/twitter-api-php": "~1.0"
},
"type": "drupal-module",
"extra": {
"branch-alias": {
- "dev-1.x": "1.x-dev"
+ "dev-2.x": "2.x-dev"
},
"drupal": {
- "version": "8.x-1.3",
- "datestamp": "1478549339"
+ "version": "8.x-2.0-alpha2",
+ "datestamp": "1507907344",
+ "security-coverage": {
+ "status": "not-covered",
+ "message": "Alpha releases are not covered by Drupal security advisories."
+ }
}
},
"installation-source": "dist",
"notification-url": "https://packages.drupal.org/8/downloads",
"license": [
- "GPL-2.0+"
+ "GPL-2.0-or-later"
],
"authors": [
{
"name": "Primsi",
"homepage": "https://www.drupal.org/user/282629"
},
+ {
+ "name": "chr.fritsch",
+ "homepage": "https://www.drupal.org/user/2103716"
+ },
{
"name": "slashrsm",
"homepage": "https://www.drupal.org/user/744628"
},
"type": "drupal-module",
"extra": {
- "installer-paths": {
- "web/core": [
- "type:drupal-core"
- ],
- "web/libraries/{$name}": [
- "type:drupal-library"
- ],
- "web/modules/contrib/{$name}": [
- "type:drupal-module"
- ],
- "web/profiles/contrib/{$name}": [
- "type:drupal-profile"
- ],
- "web/themes/contrib/{$name}": [
- "type:drupal-theme"
- ],
- "drush/contrib/{$name}": [
- "type:drupal-drush"
- ]
+ "branch-alias": {
+ "dev-1.x": "1.x-dev"
},
- "patches": {
- "drupal/security_review": {
- "Fix missing field review list": "https://www.drupal.org/files/issues/security_review-dangerous-tags-list-2744805-2.patch"
- },
- "drupal/draggableviews": {
- "Sort order not saved when using bootstrap theme": "https://www.drupal.org/files/issues/classes-defined-in-array-2729935-2.patch",
- "DraggableViews displays multiple node instances when used in multiple views": "https://www.drupal.org/files/issues/2867159_fixed_problems_with_duplicates_0.patch"
- },
- "drupal/hacked": {
- "Compatibility with diff module API change: Turn EntityComparisonBase into a service": "https://www.drupal.org/files/issues/hacked-diff-diff-service-2800645-2.patch"
- },
- "drupal/videojs": {
- "videojs-isapplicable": "https://www.drupal.org/files/issues/videojs-isapplicable.patch"
+ "drupal": {
+ "version": "8.x-1.x-dev",
+ "datestamp": "1519158780",
+ "security-coverage": {
+ "status": "not-covered",
+ "message": "Dev releases are not covered by Drupal security advisories."
}
- }
+ },
+ "patches_applied": []
},
"installation-source": "source",
"notification-url": "https://packages.drupal.org/8/downloads",
},
{
"name": "drupal/slick_media",
- "version": "1.0.0",
- "version_normalized": "1.0.0.0",
+ "version": "2.0.0-alpha1",
+ "version_normalized": "2.0.0.0-alpha1",
"source": {
"type": "git",
"url": "https://git.drupal.org/project/slick_media",
- "reference": "8.x-1.0"
+ "reference": "8.x-2.0-alpha1"
},
"dist": {
"type": "zip",
- "url": "https://ftp.drupal.org/files/projects/slick_media-8.x-1.0.zip",
- "reference": "8.x-1.0",
- "shasum": "b85a9899c53ca2f59f7cdbba044e2f58ae71e092"
+ "url": "https://ftp.drupal.org/files/projects/slick_media-8.x-2.0-alpha1.zip",
+ "reference": "8.x-2.0-alpha1",
+ "shasum": "b7efb7edabd444be1f3ad925efcfa2eabb7a4fdf"
},
"require": {
- "drupal/core": "~8.0",
- "drupal/media_entity_image": "*",
+ "drupal/core": "^8.4",
"drupal/slick": "*",
"drupal/video_embed_media": "*"
},
"type": "drupal-module",
"extra": {
"branch-alias": {
- "dev-1.x": "1.x-dev"
+ "dev-2.x": "2.x-dev"
},
"drupal": {
- "version": "8.x-1.0",
- "datestamp": "1495747983"
+ "version": "8.x-2.0-alpha1",
+ "datestamp": "1514970784",
+ "security-coverage": {
+ "status": "not-covered",
+ "message": "Alpha releases are not covered by Drupal security advisories."
+ }
}
},
"installation-source": "dist",
"notification-url": "https://packages.drupal.org/8/downloads",
"license": [
- "GPL-2.0+"
+ "GPL-2.0-or-later"
],
"authors": [
+ {
+ "name": "chr.fritsch",
+ "homepage": "https://www.drupal.org/user/2103716"
+ },
{
"name": "gausarts",
"homepage": "https://www.drupal.org/user/159062"
},
"drupal": {
"version": "8.x-1.0",
- "datestamp": "1454344739"
+ "datestamp": "1454344739",
+ "security-coverage": {
+ "status": "covered",
+ "message": "Covered by Drupal's security advisory policy"
+ }
},
"patches_applied": {
"videojs-isapplicable": "https://www.drupal.org/files/issues/videojs-isapplicable.patch"
"installation-source": "dist",
"notification-url": "https://packages.drupal.org/8/downloads",
"license": [
- "GPL-2.0+"
+ "GPL-2.0-or-later"
],
"authors": [
{
},
{
"name": "symfony/browser-kit",
- "version": "v3.4.9",
- "version_normalized": "3.4.9.0",
+ "version": "v3.4.10",
+ "version_normalized": "3.4.10.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/browser-kit.git",
},
{
"name": "symfony/debug",
- "version": "v3.4.9",
- "version_normalized": "3.4.9.0",
+ "version": "v3.4.10",
+ "version_normalized": "3.4.10.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/debug.git",
- "reference": "1b95888cfd996484527cb41e8952d9a5eaf7454f"
+ "reference": "b28fd73fefbac341f673f5efd707d539d6a19f68"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/debug/zipball/1b95888cfd996484527cb41e8952d9a5eaf7454f",
- "reference": "1b95888cfd996484527cb41e8952d9a5eaf7454f",
+ "url": "https://api.github.com/repos/symfony/debug/zipball/b28fd73fefbac341f673f5efd707d539d6a19f68",
+ "reference": "b28fd73fefbac341f673f5efd707d539d6a19f68",
"shasum": ""
},
"require": {
"require-dev": {
"symfony/http-kernel": "~2.8|~3.0|~4.0"
},
- "time": "2018-04-30T16:53:52+00:00",
+ "time": "2018-05-16T14:03:39+00:00",
"type": "library",
"extra": {
"branch-alias": {
},
{
"name": "symfony/dependency-injection",
- "version": "v3.4.9",
- "version_normalized": "3.4.9.0",
+ "version": "v3.4.10",
+ "version_normalized": "3.4.10.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/dependency-injection.git",
- "reference": "54ff9d78b56429f9a1ac12e60bfb6d169c0468e3"
+ "reference": "c2741b26377804e3d70775a3ef29335685ee9b71"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/54ff9d78b56429f9a1ac12e60bfb6d169c0468e3",
- "reference": "54ff9d78b56429f9a1ac12e60bfb6d169c0468e3",
+ "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/c2741b26377804e3d70775a3ef29335685ee9b71",
+ "reference": "c2741b26377804e3d70775a3ef29335685ee9b71",
"shasum": ""
},
"require": {
"symfony/proxy-manager-bridge": "Generate service proxies to lazy load them",
"symfony/yaml": ""
},
- "time": "2018-04-29T14:04:08+00:00",
+ "time": "2018-05-18T01:58:36+00:00",
"type": "library",
"extra": {
"branch-alias": {
},
{
"name": "symfony/dom-crawler",
- "version": "v3.4.9",
- "version_normalized": "3.4.9.0",
+ "version": "v3.4.10",
+ "version_normalized": "3.4.10.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/dom-crawler.git",
- "reference": "1a4cffeb059226ff6bee9f48acb388faf674afff"
+ "reference": "201b210fafcdd193c1e45b2994bf7133fb6263e8"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/1a4cffeb059226ff6bee9f48acb388faf674afff",
- "reference": "1a4cffeb059226ff6bee9f48acb388faf674afff",
+ "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/201b210fafcdd193c1e45b2994bf7133fb6263e8",
+ "reference": "201b210fafcdd193c1e45b2994bf7133fb6263e8",
"shasum": ""
},
"require": {
"php": "^5.5.9|>=7.0.8",
+ "symfony/polyfill-ctype": "~1.8",
"symfony/polyfill-mbstring": "~1.0"
},
"require-dev": {
"suggest": {
"symfony/css-selector": ""
},
- "time": "2018-03-19T22:32:39+00:00",
+ "time": "2018-05-01T22:53:27+00:00",
"type": "library",
"extra": {
"branch-alias": {
},
{
"name": "symfony/event-dispatcher",
- "version": "v3.4.9",
- "version_normalized": "3.4.9.0",
+ "version": "v3.4.10",
+ "version_normalized": "3.4.10.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/event-dispatcher.git",
},
{
"name": "symfony/filesystem",
- "version": "v3.4.9",
- "version_normalized": "3.4.9.0",
+ "version": "v3.4.10",
+ "version_normalized": "3.4.10.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/filesystem.git",
- "reference": "253a4490b528597aa14d2bf5aeded6f5e5e4a541"
+ "reference": "8e03ca3fa52a0f56b87506f38cf7bd3f9442b3a0"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/filesystem/zipball/253a4490b528597aa14d2bf5aeded6f5e5e4a541",
- "reference": "253a4490b528597aa14d2bf5aeded6f5e5e4a541",
+ "url": "https://api.github.com/repos/symfony/filesystem/zipball/8e03ca3fa52a0f56b87506f38cf7bd3f9442b3a0",
+ "reference": "8e03ca3fa52a0f56b87506f38cf7bd3f9442b3a0",
"shasum": ""
},
"require": {
- "php": "^5.5.9|>=7.0.8"
+ "php": "^5.5.9|>=7.0.8",
+ "symfony/polyfill-ctype": "~1.8"
},
- "time": "2018-02-22T10:48:49+00:00",
+ "time": "2018-05-16T08:49:21+00:00",
"type": "library",
"extra": {
"branch-alias": {
},
{
"name": "symfony/finder",
- "version": "v3.4.9",
- "version_normalized": "3.4.9.0",
+ "version": "v3.4.10",
+ "version_normalized": "3.4.10.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
- "reference": "bd14efe8b1fabc4de82bf50dce62f05f9a102433"
+ "reference": "472a92f3df8b247b49ae364275fb32943b9656c6"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/finder/zipball/bd14efe8b1fabc4de82bf50dce62f05f9a102433",
- "reference": "bd14efe8b1fabc4de82bf50dce62f05f9a102433",
+ "url": "https://api.github.com/repos/symfony/finder/zipball/472a92f3df8b247b49ae364275fb32943b9656c6",
+ "reference": "472a92f3df8b247b49ae364275fb32943b9656c6",
"shasum": ""
},
"require": {
"php": "^5.5.9|>=7.0.8"
},
- "time": "2018-04-04T05:07:11+00:00",
+ "time": "2018-05-16T08:49:21+00:00",
"type": "library",
"extra": {
"branch-alias": {
},
{
"name": "symfony/http-foundation",
- "version": "v3.4.9",
- "version_normalized": "3.4.9.0",
+ "version": "v3.4.10",
+ "version_normalized": "3.4.10.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-foundation.git",
- "reference": "edc43b1a50402bb06b5111eb86b275c87a93e373"
+ "reference": "9a7469ec3e0225e7f0e14264bcd9e838e16186fe"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/http-foundation/zipball/edc43b1a50402bb06b5111eb86b275c87a93e373",
- "reference": "edc43b1a50402bb06b5111eb86b275c87a93e373",
+ "url": "https://api.github.com/repos/symfony/http-foundation/zipball/9a7469ec3e0225e7f0e14264bcd9e838e16186fe",
+ "reference": "9a7469ec3e0225e7f0e14264bcd9e838e16186fe",
"shasum": ""
},
"require": {
"require-dev": {
"symfony/expression-language": "~2.8|~3.0|~4.0"
},
- "time": "2018-04-30T01:05:13+00:00",
+ "time": "2018-05-16T08:49:21+00:00",
"type": "library",
"extra": {
"branch-alias": {
},
{
"name": "symfony/http-kernel",
- "version": "v3.4.9",
- "version_normalized": "3.4.9.0",
+ "version": "v3.4.10",
+ "version_normalized": "3.4.10.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-kernel.git",
- "reference": "280fcedbcb3dabcc467a9c1734054af61928fe4f"
+ "reference": "66644bc7d17cc071d796efab9b950adbb86da134"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/http-kernel/zipball/280fcedbcb3dabcc467a9c1734054af61928fe4f",
- "reference": "280fcedbcb3dabcc467a9c1734054af61928fe4f",
+ "url": "https://api.github.com/repos/symfony/http-kernel/zipball/66644bc7d17cc071d796efab9b950adbb86da134",
+ "reference": "66644bc7d17cc071d796efab9b950adbb86da134",
"shasum": ""
},
"require": {
"psr/log": "~1.0",
"symfony/debug": "~2.8|~3.0|~4.0",
"symfony/event-dispatcher": "~2.8|~3.0|~4.0",
- "symfony/http-foundation": "^3.4.4|^4.0.4"
+ "symfony/http-foundation": "^3.4.4|^4.0.4",
+ "symfony/polyfill-ctype": "~1.8"
},
"conflict": {
"symfony/config": "<2.8",
"symfony/finder": "",
"symfony/var-dumper": ""
},
- "time": "2018-04-30T19:27:02+00:00",
+ "time": "2018-05-21T13:44:03+00:00",
"type": "library",
"extra": {
"branch-alias": {
},
{
"name": "symfony/serializer",
- "version": "v3.4.9",
- "version_normalized": "3.4.9.0",
+ "version": "v3.4.10",
+ "version_normalized": "3.4.10.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/serializer.git",
- "reference": "d4dc1551da627273230fe16511f4bb4844c02399"
+ "reference": "2f3630bb2b855de2284798db34d3ac5734766575"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/serializer/zipball/d4dc1551da627273230fe16511f4bb4844c02399",
- "reference": "d4dc1551da627273230fe16511f4bb4844c02399",
+ "url": "https://api.github.com/repos/symfony/serializer/zipball/2f3630bb2b855de2284798db34d3ac5734766575",
+ "reference": "2f3630bb2b855de2284798db34d3ac5734766575",
"shasum": ""
},
"require": {
- "php": "^5.5.9|>=7.0.8"
+ "php": "^5.5.9|>=7.0.8",
+ "symfony/polyfill-ctype": "~1.8"
},
"conflict": {
"phpdocumentor/type-resolver": "<0.2.1",
"symfony/property-info": "To deserialize relations.",
"symfony/yaml": "For using the default YAML mapping loader."
},
- "time": "2018-03-15T19:08:29+00:00",
+ "time": "2018-05-16T12:49:49+00:00",
"type": "library",
"extra": {
"branch-alias": {
},
{
"name": "symfony/translation",
- "version": "v3.4.9",
- "version_normalized": "3.4.9.0",
+ "version": "v3.4.10",
+ "version_normalized": "3.4.10.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/translation.git",
- "reference": "d4af50f46cd8171fd5c1cdebdb9a8bbcd8078c6c"
+ "reference": "7047f725e35eab768137c677f8c38e4a2a8e38fb"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/translation/zipball/d4af50f46cd8171fd5c1cdebdb9a8bbcd8078c6c",
- "reference": "d4af50f46cd8171fd5c1cdebdb9a8bbcd8078c6c",
+ "url": "https://api.github.com/repos/symfony/translation/zipball/7047f725e35eab768137c677f8c38e4a2a8e38fb",
+ "reference": "7047f725e35eab768137c677f8c38e4a2a8e38fb",
"shasum": ""
},
"require": {
"symfony/config": "",
"symfony/yaml": ""
},
- "time": "2018-04-30T01:22:56+00:00",
+ "time": "2018-05-21T10:06:52+00:00",
"type": "library",
"extra": {
"branch-alias": {
},
{
"name": "symfony/validator",
- "version": "v3.4.9",
- "version_normalized": "3.4.9.0",
+ "version": "v3.4.10",
+ "version_normalized": "3.4.10.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/validator.git",
- "reference": "d562929598e5f3cb3947937c9ccfb18d977a16b3"
+ "reference": "62ccdf62042fbca3be1e7b2dae84965940023362"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/validator/zipball/d562929598e5f3cb3947937c9ccfb18d977a16b3",
- "reference": "d562929598e5f3cb3947937c9ccfb18d977a16b3",
+ "url": "https://api.github.com/repos/symfony/validator/zipball/62ccdf62042fbca3be1e7b2dae84965940023362",
+ "reference": "62ccdf62042fbca3be1e7b2dae84965940023362",
"shasum": ""
},
"require": {
"php": "^5.5.9|>=7.0.8",
+ "symfony/polyfill-ctype": "~1.8",
"symfony/polyfill-mbstring": "~1.0",
"symfony/translation": "~2.8|~3.0|~4.0"
},
"symfony/property-access": "For accessing properties within comparison constraints",
"symfony/yaml": ""
},
- "time": "2018-04-20T10:02:27+00:00",
+ "time": "2018-05-18T02:00:55+00:00",
"type": "library",
"extra": {
"branch-alias": {
},
{
"name": "symfony/var-dumper",
- "version": "v3.4.9",
- "version_normalized": "3.4.9.0",
+ "version": "v3.4.10",
+ "version_normalized": "3.4.10.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/var-dumper.git",
},
{
"name": "symfony/yaml",
- "version": "v3.4.9",
- "version_normalized": "3.4.9.0",
+ "version": "v3.4.10",
+ "version_normalized": "3.4.10.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/yaml.git",
- "reference": "033cfa61ef06ee0847e056e530201842b6e926c3"
+ "reference": "c5010cc1692ce1fa328b1fb666961eb3d4a85bb0"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/yaml/zipball/033cfa61ef06ee0847e056e530201842b6e926c3",
- "reference": "033cfa61ef06ee0847e056e530201842b6e926c3",
+ "url": "https://api.github.com/repos/symfony/yaml/zipball/c5010cc1692ce1fa328b1fb666961eb3d4a85bb0",
+ "reference": "c5010cc1692ce1fa328b1fb666961eb3d4a85bb0",
"shasum": ""
},
"require": {
- "php": "^5.5.9|>=7.0.8"
+ "php": "^5.5.9|>=7.0.8",
+ "symfony/polyfill-ctype": "~1.8"
},
"conflict": {
"symfony/console": "<3.4"
"suggest": {
"symfony/console": "For validating YAML files using the lint command"
},
- "time": "2018-04-08T08:21:29+00:00",
+ "time": "2018-05-03T23:18:14+00:00",
"type": "library",
"extra": {
"branch-alias": {
public function handleError($type, $message, $file, $line)
{
// Level is the current error reporting level to manage silent error.
+ $level = error_reporting();
+ $silenced = 0 === ($level & $type);
// Strong errors are not authorized to be silenced.
- $level = error_reporting() | E_RECOVERABLE_ERROR | E_USER_ERROR | E_DEPRECATED | E_USER_DEPRECATED;
+ $level |= E_RECOVERABLE_ERROR | E_USER_ERROR | E_DEPRECATED | E_USER_DEPRECATED;
$log = $this->loggedErrors & $type;
$throw = $this->thrownErrors & $type & $level;
$type &= $level | $this->screamedErrors;
if (!$type || (!$log && !$throw)) {
- return $type && $log;
+ return !$silenced && $type && $log;
}
$scope = $this->scopedErrors & $type;
}
}
- return $type && $log;
+ return !$silenced && $type && $log;
}
/**
return $this->previous;
}
- public function setPrevious(FlattenException $previous)
+ public function setPrevious(self $previous)
{
$this->previous = $previous;
}
}
}
+ public function testErrorGetLast()
+ {
+ $handler = ErrorHandler::register();
+ $logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
+ $handler->setDefaultLogger($logger);
+ $handler->screamAt(E_ALL);
+
+ try {
+ @trigger_error('Hello', E_USER_WARNING);
+ $expected = array(
+ 'type' => E_USER_WARNING,
+ 'message' => 'Hello',
+ 'file' => __FILE__,
+ 'line' => __LINE__ - 5,
+ );
+ $this->assertSame($expected, error_get_last());
+ } catch (\Exception $e) {
+ restore_error_handler();
+ restore_exception_handler();
+
+ throw $e;
+ }
+ }
+
public function testNotice()
{
ErrorHandler::register();
{
throw new BadMethodCallException('A ChildDefinition cannot have instanceof conditionals set on it.');
}
-
- /**
- * @internal
- */
- public function setBindings(array $bindings)
- {
- throw new BadMethodCallException('A ChildDefinition cannot have bindings set on it.');
- }
}
class_alias(ChildDefinition::class, DefinitionDecorator::class);
$class = $definition->getClass();
- if (!$r = $this->container->getReflectionClass($class)) {
- throw new RuntimeException(sprintf('Invalid service "%s": class "%s" does not exist.', $this->currentId, $class));
+ try {
+ if (!$r = $this->container->getReflectionClass($class)) {
+ throw new RuntimeException(sprintf('Invalid service "%s": class "%s" does not exist.', $this->currentId, $class));
+ }
+ } catch (\ReflectionException $e) {
+ throw new RuntimeException(sprintf('Invalid service "%s": %s.', $this->currentId, lcfirst(rtrim($e->getMessage(), '.'))));
}
if (!$r = $r->getConstructor()) {
if ($required) {
return false;
}
- return true;
+ return $this->container->getDefinition($ids[0])->isShared();
}
}
{
private $usedBindings = array();
private $unusedBindings = array();
+ private $errorMessages = array();
/**
* {@inheritdoc}
parent::process($container);
foreach ($this->unusedBindings as list($key, $serviceId)) {
- throw new InvalidArgumentException(sprintf('Unused binding "%s" in service "%s".', $key, $serviceId));
+ $message = sprintf('Unused binding "%s" in service "%s".', $key, $serviceId);
+ if ($this->errorMessages) {
+ $message .= sprintf("\nCould be related to%s:", 1 < \count($this->errorMessages) ? ' one of' : '');
+ }
+ foreach ($this->errorMessages as $m) {
+ $message .= "\n - ".$m;
+ }
+ throw new InvalidArgumentException($message);
}
} finally {
$this->usedBindings = array();
$this->unusedBindings = array();
+ $this->errorMessages = array();
}
}
$calls[] = array($constructor, $value->getArguments());
}
} catch (RuntimeException $e) {
+ $this->errorMessages[] = $e->getMessage();
$this->container->getDefinition($this->currentId)->addError($e->getMessage());
return parent::processValue($value, $isRoot);
$def->setAutowired($parentDef->isAutowired());
$def->setChanges($parentDef->getChanges());
- $def->setBindings($parentDef->getBindings());
+ $def->setBindings($definition->getBindings() + $parentDef->getBindings());
// overwrite with values specified in the decorator
$changes = $definition->getChanges();
}
$envPlaceholders = $bag instanceof EnvPlaceholderParameterBag ? $bag->getEnvPlaceholders() : $this->envPlaceholders;
+ $completed = false;
foreach ($envPlaceholders as $env => $placeholders) {
foreach ($placeholders as $placeholder) {
if (false !== stripos($value, $placeholder)) {
}
if ($placeholder === $value) {
$value = $resolved;
+ $completed = true;
} else {
if (!is_string($resolved) && !is_numeric($resolved)) {
- throw new RuntimeException(sprintf('A string value must be composed of strings and/or numbers, but found parameter "env(%s)" of type %s inside string value "%s".', $env, gettype($resolved), $value));
+ throw new RuntimeException(sprintf('A string value must be composed of strings and/or numbers, but found parameter "env(%s)" of type %s inside string value "%s".', $env, gettype($resolved), $this->resolveEnvPlaceholders($value)));
}
$value = str_ireplace($placeholder, $resolved, $value);
}
$usedEnvs[$env] = $env;
$this->envCounters[$env] = isset($this->envCounters[$env]) ? 1 + $this->envCounters[$env] : 1;
+
+ if ($completed) {
+ break 2;
+ }
}
}
}
*
* @param string $fqcn
*
- * @return InstanceofConfigurator
+ * @return self
*/
final protected function setInstanceof($fqcn)
{
$this->assertNotSame($container->getDefinition('bar'), $arguments[2]);
}
- public function testProcessInlinesMixedServicesLoop()
+ public function testProcessDoesNotInlineMixedServicesLoop()
{
$container = new ContainerBuilder();
$container
$this->process($container);
- $this->assertEquals($container->getDefinition('foo')->getArgument(0), $container->getDefinition('bar'));
+ $this->assertEquals(new Reference('bar'), $container->getDefinition('foo')->getArgument(0));
}
/**
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Tests\Fixtures\NamedArgumentsDummy;
+use Symfony\Component\DependencyInjection\Tests\Fixtures\ParentNotExists;
use Symfony\Component\DependencyInjection\Tests\Fixtures\CaseSensitiveClass;
use Symfony\Component\DependencyInjection\TypedReference;
$pass->process($container);
}
+ /**
+ * @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException
+ * @expectedExceptionMessageRegexp Unused binding "$quz" in service [\s\S]+ Invalid service ".*\\ParentNotExists": class NotExists not found\.
+ */
+ public function testMissingParent()
+ {
+ $container = new ContainerBuilder();
+
+ $definition = $container->register(ParentNotExists::class, ParentNotExists::class);
+ $definition->setBindings(array('$quz' => '123'));
+
+ $pass = new ResolveBindingsPass();
+ $pass->process($container);
+ }
+
public function testTypedReferenceSupport()
{
$container = new ContainerBuilder();
$this->assertSame(array(2, 1, 'foo' => 3), $def->getArguments());
}
+ public function testBindings()
+ {
+ $container = new ContainerBuilder();
+
+ $container->register('parent', 'stdClass')
+ ->setBindings(array('a' => '1', 'b' => '2'))
+ ;
+
+ $child = $container->setDefinition('child', new ChildDefinition('parent'))
+ ->setBindings(array('b' => 'B', 'c' => 'C'))
+ ;
+
+ $this->process($container);
+
+ $bindings = array();
+ foreach ($container->getDefinition('child')->getBindings() as $k => $v) {
+ $bindings[$k] = $v->getValues()[0];
+ }
+ $this->assertEquals(array('b' => 'B', 'c' => 'C', 'a' => '1'), $bindings);
+ }
+
public function testSetAutoconfiguredOnServiceIsParent()
{
$container = new ContainerBuilder();
putenv('DUMMY_ENV_VAR');
}
+ public function testCompileWithArrayResolveEnv()
+ {
+ putenv('ARRAY={"foo":"bar"}');
+
+ $container = new ContainerBuilder();
+ $container->setParameter('foo', '%env(json:ARRAY)%');
+ $container->compile(true);
+
+ $this->assertSame(array('foo' => 'bar'), $container->getParameter('foo'));
+
+ putenv('ARRAY');
+ }
+
+ public function testCompileWithArrayAndAnotherResolveEnv()
+ {
+ putenv('DUMMY_ENV_VAR=abc');
+ putenv('ARRAY={"foo":"bar"}');
+
+ $container = new ContainerBuilder();
+ $container->setParameter('foo', '%env(json:ARRAY)%');
+ $container->setParameter('bar', '%env(DUMMY_ENV_VAR)%');
+ $container->compile(true);
+
+ $this->assertSame(array('foo' => 'bar'), $container->getParameter('foo'));
+ $this->assertSame('abc', $container->getParameter('bar'));
+
+ putenv('DUMMY_ENV_VAR');
+ putenv('ARRAY');
+ }
+
/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
- * @expectedExceptionMessage A string value must be composed of strings and/or numbers, but found parameter "env(ARRAY)" of type array inside string value "ABC %env(ARRAY)%".
+ * @expectedExceptionMessage A string value must be composed of strings and/or numbers, but found parameter "env(json:ARRAY)" of type array inside string value "ABC %env(json:ARRAY)%".
*/
- public function testCompileWithArrayResolveEnv()
+ public function testCompileWithArrayInStringResolveEnv()
{
- $bag = new TestingEnvPlaceholderParameterBag();
- $container = new ContainerBuilder($bag);
- $container->setParameter('foo', '%env(ARRAY)%');
- $container->setParameter('bar', 'ABC %env(ARRAY)%');
+ putenv('ARRAY={"foo":"bar"}');
+
+ $container = new ContainerBuilder();
+ $container->setParameter('foo', 'ABC %env(json:ARRAY)%');
$container->compile(true);
+
+ putenv('ARRAY');
}
/**
{
}
}
-
-class TestingEnvPlaceholderParameterBag extends EnvPlaceholderParameterBag
-{
- public function get($name)
- {
- return 'env(array)' === strtolower($name) ? array(123) : parent::get($name);
- }
-}
],
"require": {
"php": "^5.5.9|>=7.0.8",
+ "symfony/polyfill-ctype": "~1.8",
"symfony/polyfill-mbstring": "~1.0"
},
"require-dev": {
*/
class Filesystem
{
+ private static $lastError;
+
/**
* Copies a file.
*
continue;
}
- if (true !== @mkdir($dir, $mode, true)) {
- $error = error_get_last();
+ if (!self::box('mkdir', $dir, $mode, true)) {
if (!is_dir($dir)) {
// The directory was not created by a concurrent process. Let's throw an exception with a developer friendly error message if we have one
- if ($error) {
- throw new IOException(sprintf('Failed to create "%s": %s.', $dir, $error['message']), 0, null, $dir);
+ if (self::$lastError) {
+ throw new IOException(sprintf('Failed to create "%s": %s.', $dir, self::$lastError), 0, null, $dir);
}
throw new IOException(sprintf('Failed to create "%s"', $dir), 0, null, $dir);
}
foreach ($files as $file) {
if (is_link($file)) {
// See https://bugs.php.net/52176
- if (!@(unlink($file) || '\\' !== DIRECTORY_SEPARATOR || rmdir($file)) && file_exists($file)) {
- $error = error_get_last();
- throw new IOException(sprintf('Failed to remove symlink "%s": %s.', $file, $error['message']));
+ if (!(self::box('unlink', $file) || '\\' !== DIRECTORY_SEPARATOR || self::box('rmdir', $file)) && file_exists($file)) {
+ throw new IOException(sprintf('Failed to remove symlink "%s": %s.', $file, self::$lastError));
}
} elseif (is_dir($file)) {
$this->remove(new \FilesystemIterator($file, \FilesystemIterator::CURRENT_AS_PATHNAME | \FilesystemIterator::SKIP_DOTS));
- if (!@rmdir($file) && file_exists($file)) {
- $error = error_get_last();
- throw new IOException(sprintf('Failed to remove directory "%s": %s.', $file, $error['message']));
+ if (!self::box('rmdir', $file) && file_exists($file)) {
+ throw new IOException(sprintf('Failed to remove directory "%s": %s.', $file, self::$lastError));
}
- } elseif (!@unlink($file) && file_exists($file)) {
- $error = error_get_last();
- throw new IOException(sprintf('Failed to remove file "%s": %s.', $file, $error['message']));
+ } elseif (!self::box('unlink', $file) && file_exists($file)) {
+ throw new IOException(sprintf('Failed to remove file "%s": %s.', $file, self::$lastError));
}
}
}
$this->mkdir(dirname($targetDir));
- $ok = false;
if (is_link($targetDir)) {
- if (readlink($targetDir) != $originDir) {
- $this->remove($targetDir);
- } else {
- $ok = true;
+ if (readlink($targetDir) === $originDir) {
+ return;
}
+ $this->remove($targetDir);
}
- if (!$ok && true !== @symlink($originDir, $targetDir)) {
+ if (!self::box('symlink', $originDir, $targetDir)) {
$this->linkException($originDir, $targetDir, 'symbolic');
}
}
$this->remove($targetFile);
}
- if (true !== @link($originFile, $targetFile)) {
+ if (!self::box('link', $originFile, $targetFile)) {
$this->linkException($originFile, $targetFile, 'hard');
}
}
*/
private function linkException($origin, $target, $linkType)
{
- $report = error_get_last();
- if (is_array($report)) {
- if ('\\' === DIRECTORY_SEPARATOR && false !== strpos($report['message'], 'error code(1314)')) {
+ if (self::$lastError) {
+ if ('\\' === DIRECTORY_SEPARATOR && false !== strpos(self::$lastError, 'error code(1314)')) {
throw new IOException(sprintf('Unable to create %s link due to error code 1314: \'A required privilege is not held by the client\'. Do you have the required Administrator-rights?', $linkType), 0, null, $target);
}
}
return 2 === count($components) ? array($components[0], $components[1]) : array(null, $components[0]);
}
+
+ private static function box($func)
+ {
+ self::$lastError = null;
+ \set_error_handler(__CLASS__.'::handleError');
+ try {
+ $result = \call_user_func_array($func, \array_slice(\func_get_args(), 1));
+ \restore_error_handler();
+
+ return $result;
+ } catch (\Throwable $e) {
+ } catch (\Exception $e) {
+ }
+ \restore_error_handler();
+
+ throw $e;
+ }
+
+ /**
+ * @internal
+ */
+ public static function handleError($type, $msg)
+ {
+ self::$lastError = $msg;
+ }
}
}
],
"require": {
- "php": "^5.5.9|>=7.0.8"
+ "php": "^5.5.9|>=7.0.8",
+ "symfony/polyfill-ctype": "~1.8"
},
"autoload": {
"psr-4": { "Symfony\\Component\\Filesystem\\": "" },
*/
public function getContents()
{
- $level = error_reporting(0);
+ set_error_handler(function ($type, $msg) use (&$error) { $error = $msg; });
$content = file_get_contents($this->getPathname());
- error_reporting($level);
+ restore_error_handler();
if (false === $content) {
- $error = error_get_last();
- throw new \RuntimeException($error['message']);
+ throw new \RuntimeException($error);
}
return $content;
{
$target = $this->getTargetFile($directory, $name);
- if (!@rename($this->getPathname(), $target)) {
- $error = error_get_last();
- throw new FileException(sprintf('Could not move the file "%s" to "%s" (%s)', $this->getPathname(), $target, strip_tags($error['message'])));
+ set_error_handler(function ($type, $msg) use (&$error) { $error = $msg; });
+ $renamed = rename($this->getPathname(), $target);
+ restore_error_handler();
+ if (!$renamed) {
+ throw new FileException(sprintf('Could not move the file "%s" to "%s" (%s)', $this->getPathname(), $target, strip_tags($error)));
}
@chmod($target, 0666 & ~umask());
$target = $this->getTargetFile($directory, $name);
- if (!@move_uploaded_file($this->getPathname(), $target)) {
- $error = error_get_last();
- throw new FileException(sprintf('Could not move the file "%s" to "%s" (%s)', $this->getPathname(), $target, strip_tags($error['message'])));
+ set_error_handler(function ($type, $msg) use (&$error) { $error = $msg; });
+ $moved = move_uploaded_file($this->getPathname(), $target);
+ restore_error_handler();
+ if (!$moved) {
+ throw new FileException(sprintf('Could not move the file "%s" to "%s" (%s)', $this->getPathname(), $target, strip_tags($error)));
}
@chmod($target, 0666 & ~umask());
public static function setTrustedHosts(array $hostPatterns)
{
self::$trustedHostPatterns = array_map(function ($hostPattern) {
- return sprintf('#%s#i', $hostPattern);
+ return sprintf('{%s}i', $hostPattern);
}, $hostPatterns);
// we need to reset trusted hosts on trusted host patterns change
self::$trustedHosts = array();
*
* @param string $format The format
*
- * @return string The associated mime type (null if not found)
+ * @return string|null The associated mime type (null if not found)
*/
public function getMimeType($format)
{
{
switch ($this->driver) {
case 'mysql':
+ // MySQL 5.7.5 and later enforces a maximum length on lock names of 64 characters. Previously, no limit was enforced.
+ $lockId = \substr($sessionId, 0, 64);
// should we handle the return value? 0 on timeout, null on error
// we use a timeout of 50 seconds which is also the default for innodb_lock_wait_timeout
$stmt = $this->pdo->prepare('SELECT GET_LOCK(:key, 50)');
- $stmt->bindValue(':key', $sessionId, \PDO::PARAM_STR);
+ $stmt->bindValue(':key', $lockId, \PDO::PARAM_STR);
$stmt->execute();
$releaseStmt = $this->pdo->prepare('DO RELEASE_LOCK(:key)');
- $releaseStmt->bindValue(':key', $sessionId, \PDO::PARAM_STR);
+ $releaseStmt->bindValue(':key', $lockId, \PDO::PARAM_STR);
return $releaseStmt;
case 'pgsql':
{
// reset
Request::setTrustedProxies(array(), -1);
+ Request::setTrustedHosts(array());
}
public function testInitialize()
$request->headers->set('host', 'subdomain.trusted.com');
$this->assertEquals('subdomain.trusted.com', $request->getHost());
+ }
- // reset request for following tests
- Request::setTrustedHosts(array());
+ public function testSetTrustedHostsDoesNotBreakOnSpecialCharacters()
+ {
+ Request::setTrustedHosts(array('localhost(\.local){0,1}#,example.com', 'localhost'));
+
+ $request = Request::create('/');
+ $request->headers->set('host', 'localhost');
+ $this->assertSame('localhost', $request->getHost());
}
public function testFactory()
}
foreach ($reflection->getParameters() as $param) {
- $arguments[] = new ArgumentMetadata($param->getName(), $this->getType($param), $this->isVariadic($param), $this->hasDefaultValue($param), $this->getDefaultValue($param), $param->allowsNull());
+ $arguments[] = new ArgumentMetadata($param->getName(), $this->getType($param, $reflection), $this->isVariadic($param), $this->hasDefaultValue($param), $this->getDefaultValue($param), $param->allowsNull());
}
return $arguments;
*
* @return null|string
*/
- private function getType(\ReflectionParameter $parameter)
+ private function getType(\ReflectionParameter $parameter, \ReflectionFunctionAbstract $function)
{
if ($this->supportsParameterType) {
if (!$type = $parameter->getType()) {
return;
}
- $typeName = $type instanceof \ReflectionNamedType ? $type->getName() : $type->__toString();
- if ('array' === $typeName && !$type->isBuiltin()) {
+ $name = $type instanceof \ReflectionNamedType ? $type->getName() : $type->__toString();
+ if ('array' === $name && !$type->isBuiltin()) {
// Special case for HHVM with variadics
return;
}
-
- return $typeName;
+ } elseif (preg_match('/^(?:[^ ]++ ){4}([a-zA-Z_\x7F-\xFF][^ ]++)/', $parameter, $name)) {
+ $name = $name[1];
+ } else {
+ return;
}
+ $lcName = strtolower($name);
- if (preg_match('/^(?:[^ ]++ ){4}([a-zA-Z_\x7F-\xFF][^ ]++)/', $parameter, $info)) {
- return $info[1];
+ if ('self' !== $lcName && 'parent' !== $lcName) {
+ return $name;
+ }
+ if (!$function instanceof \ReflectionMethod) {
+ return;
+ }
+ if ('self' === $lcName) {
+ return $function->getDeclaringClass()->name;
+ }
+ if ($parent = $function->getDeclaringClass()->getParentClass()) {
+ return $parent->name;
}
}
}
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
+use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
use Symfony\Component\HttpKernel\Event\FinishRequestEvent;
use Symfony\Component\HttpKernel\Kernel;
use Symfony\Component\HttpKernel\KernelEvents;
unset($parameters['_route'], $parameters['_controller']);
$request->attributes->set('_route_params', $parameters);
} catch (ResourceNotFoundException $e) {
- if ($this->debug && $e instanceof NoConfigurationException) {
- $event->setResponse($this->createWelcomeResponse());
-
- return;
- }
-
$message = sprintf('No route found for "%s %s"', $request->getMethod(), $request->getPathInfo());
if ($referer = $request->headers->get('referer')) {
}
}
+ public function onKernelException(GetResponseForExceptionEvent $event)
+ {
+ if (!$this->debug || !($e = $event->getException()) instanceof NotFoundHttpException) {
+ return;
+ }
+
+ if ($e->getPrevious() instanceof NoConfigurationException) {
+ $event->setResponse($this->createWelcomeResponse());
+ }
+ }
+
public static function getSubscribedEvents()
{
return array(
KernelEvents::REQUEST => array(array('onKernelRequest', 32)),
KernelEvents::FINISH_REQUEST => array(array('onKernelFinishRequest', 0)),
+ KernelEvents::EXCEPTION => array('onKernelException', -64),
);
}
private $requestStackSize = 0;
private $resetServices = false;
- const VERSION = '3.4.9';
- const VERSION_ID = 30409;
+ const VERSION = '3.4.10';
+ const VERSION_ID = 30410;
const MAJOR_VERSION = 3;
const MINOR_VERSION = 4;
- const RELEASE_VERSION = 9;
+ const RELEASE_VERSION = 10;
const EXTRA_VERSION = '';
const END_OF_MAINTENANCE = '11/2020';
$errorLevel = error_reporting(\E_ALL ^ \E_WARNING);
$fresh = $oldContainer = false;
try {
- if (\is_object($this->container = include $cache->getPath())) {
+ if (file_exists($cache->getPath()) && \is_object($this->container = include $cache->getPath())) {
$this->container->set('kernel', $this);
$oldContainer = $this->container;
$fresh = true;
}
}
- if (null === $oldContainer) {
+ if (null === $oldContainer && file_exists($cache->getPath())) {
$errorLevel = error_reporting(\E_ALL ^ \E_WARNING);
try {
$oldContainer = include $cache->getPath();
private $enabled = true;
/**
- * @param bool $enable The initial enabled state
+ * @param bool $enable The initial enabled state
*/
public function __construct(ProfilerStorageInterface $storage, LoggerInterface $logger = null, $enable = true)
{
), $arguments);
}
- private function signature1(ArgumentMetadataFactoryTest $foo, array $bar, callable $baz)
+ private function signature1(self $foo, array $bar, callable $baz)
{
}
- private function signature2(ArgumentMetadataFactoryTest $foo = null, FakeClassThatDoesNotExist $bar = null, ImportedAndFake $baz = null)
+ private function signature2(self $foo = null, FakeClassThatDoesNotExist $bar = null, ImportedAndFake $baz = null)
{
}
class UnprocessableEntityHttpExceptionTest extends HttpExceptionTest
{
- /**
- * Test that setting the headers using the setter function
- * is working as expected.
- *
- * @param array $headers The headers to set
- *
- * @dataProvider headerDataProvider
- */
- public function testHeadersSetter($headers)
- {
- $exception = new UnprocessableEntityHttpException(10);
- $exception->setHeaders($headers);
- $this->assertSame($headers, $exception->getHeaders());
- }
-
protected function createException()
{
return new UnprocessableEntityHttpException();
class UnsupportedMediaTypeHttpExceptionTest extends HttpExceptionTest
{
- /**
- * @dataProvider headerDataProvider
- */
- public function testHeadersSetter($headers)
- {
- $exception = new UnsupportedMediaTypeHttpException(10);
- $exception->setHeaders($headers);
- $this->assertSame($headers, $exception->getHeaders());
- }
-
- protected function createException($headers = array())
+ protected function createException()
{
return new UnsupportedMediaTypeHttpException();
}
public function testReset()
{
$collector = $this->getMockBuilder(DataCollectorInterface::class)
- ->setMethods(['collect', 'getName', 'reset'])
+ ->setMethods(array('collect', 'getName', 'reset'))
->getMock();
$collector->expects($this->any())->method('getName')->willReturn('mock');
$collector->expects($this->once())->method('reset');
"symfony/event-dispatcher": "~2.8|~3.0|~4.0",
"symfony/http-foundation": "^3.4.4|^4.0.4",
"symfony/debug": "~2.8|~3.0|~4.0",
+ "symfony/polyfill-ctype": "~1.8",
"psr/log": "~1.0"
},
"require-dev": {
/**
* Merges an {@see AttributeMetadataInterface} with in the current one.
*/
- public function merge(AttributeMetadataInterface $attributeMetadata);
+ public function merge(self $attributeMetadata);
}
/**
* Merges a {@link ClassMetadataInterface} in the current one.
*/
- public function merge(ClassMetadataInterface $classMetadata);
+ public function merge(self $classMetadata);
/**
* Returns a {@link \ReflectionClass} instance for this class.
/**
* Sets an attribute and apply the name converter if necessary.
*
- * @param array $data
* @param string $attribute
* @param mixed $attributeValue
*
}
],
"require": {
- "php": "^5.5.9|>=7.0.8"
+ "php": "^5.5.9|>=7.0.8",
+ "symfony/polyfill-ctype": "~1.8"
},
"require-dev": {
"symfony/yaml": "~3.4|~4.0",
namespace Symfony\Component\Translation\Command;
use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Exception\RuntimeException;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
if (!$filename) {
if (!$stdin = $this->getStdin()) {
- throw new \RuntimeException('Please provide a filename or pipe file content to STDIN.');
+ throw new RuntimeException('Please provide a filename or pipe file content to STDIN.');
}
return $this->display($io, array($this->validate($stdin)));
}
if (!$this->isReadable($filename)) {
- throw new \RuntimeException(sprintf('File or directory "%s" is not readable.', $filename));
+ throw new RuntimeException(sprintf('File or directory "%s" is not readable.', $filename));
}
$filesInfo = array();
case 'json':
return $this->displayJson($io, $files);
default:
- throw new \InvalidArgumentException(sprintf('The format "%s" is not supported.', $this->format));
+ throw new InvalidArgumentException(sprintf('The format "%s" is not supported.', $this->format));
}
}
*
* The two catalogues must have the same locale.
*/
- public function addCatalogue(MessageCatalogueInterface $catalogue);
+ public function addCatalogue(self $catalogue);
/**
* Merges translations from the given Catalogue into the current one
*
* This is used to provide default translations when they do not exist for the current locale.
*/
- public function addFallbackCatalogue(MessageCatalogueInterface $catalogue);
+ public function addFallbackCatalogue(self $catalogue);
/**
* Gets the fallback catalogue.
case 'nl':
case 'nn':
case 'no':
+ case 'oc':
case 'om':
case 'or':
case 'pa':
Url::CHECK_DNS_TYPE_SOA,
Url::CHECK_DNS_TYPE_SRV,
Url::CHECK_DNS_TYPE_TXT,
- ))) {
+ ), true)) {
throw new InvalidOptionsException(sprintf('Invalid value for option "checkDNS" in constraint %s', get_class($constraint)), array('checkDNS'));
}
/**
* Merges the constraints of the given metadata into this object.
*/
- public function mergeConstraints(ClassMetadata $source)
+ public function mergeConstraints(self $source)
{
if ($source->isGroupSequenceProvider()) {
$this->setGroupSequenceProvider(true);
/**
* Prepares an object for validation.
*
- * Concrete implementations of this interface are used by {@link ValidationVisitorInterface}
+ * Concrete implementations of this interface are used by {@link Validator\ContextualValidatorInterface}
* to initialize objects just before validating them.
*
* @author Fabien Potencier <fabien@symfony.com>
],
"require": {
"php": "^5.5.9|>=7.0.8",
+ "symfony/polyfill-ctype": "~1.8",
"symfony/polyfill-mbstring": "~1.0",
"symfony/translation": "~2.8|~3.0|~4.0"
},
namespace Symfony\Component\Yaml\Command;
use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Exception\InvalidArgumentException;
+use Symfony\Component\Console\Exception\RuntimeException;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
if (!$filename) {
if (!$stdin = $this->getStdin()) {
- throw new \RuntimeException('Please provide a filename or pipe file content to STDIN.');
+ throw new RuntimeException('Please provide a filename or pipe file content to STDIN.');
}
return $this->display($io, array($this->validate($stdin, $flags)));
}
if (!$this->isReadable($filename)) {
- throw new \RuntimeException(sprintf('File or directory "%s" is not readable.', $filename));
+ throw new RuntimeException(sprintf('File or directory "%s" is not readable.', $filename));
}
$filesInfo = array();
case 'json':
return $this->displayJson($io, $files);
default:
- throw new \InvalidArgumentException(sprintf('The format "%s" is not supported.', $this->format));
+ throw new InvalidArgumentException(sprintf('The format "%s" is not supported.', $this->format));
}
}
}
],
"require": {
- "php": "^5.5.9|>=7.0.8"
+ "php": "^5.5.9|>=7.0.8",
+ "symfony/polyfill-ctype": "~1.8"
},
"require-dev": {
"symfony/console": "~3.4|~4.0"
sequence:
type: crop_type.third_party.[%key]
-media_entity.bundle.third_party.crop:
+media.type.*.third_party.crop:
type: mapping
label: 'Crop settings'
mapping:
package: Media
type: module
dependencies:
- - image
- - user
+ - drupal:image
+ - drupal:user
-# Information added by Drupal.org packaging script on 2018-01-19
-version: '8.x-1.5'
+# Information added by Drupal.org packaging script on 2018-01-16
+version: '8.x-2.0-rc1'
core: '8.x'
project: 'crop'
-datestamp: 1516357097
+datestamp: 1516120388
use Drupal\crop\Entity\Crop;
+/**
+ * Implements hook_requirements().
+ */
+function crop_requirements($phase) {
+ $requirements = [];
+
+ // This branch of Crop API shouldn't be used with core < 8.4.x or with
+ // media_entity 1.x enabled.
+ $incompatible = FALSE;
+ $drupal_version = explode('.', \Drupal::VERSION);
+ if ($drupal_version[1] < 4) {
+ $incompatible = TRUE;
+ }
+ elseif (\Drupal::moduleHandler()->moduleExists('media_entity')) {
+ $info = system_get_info('module', 'media_entity');
+ if (version_compare($info['version'], '8.x-2') < 0) {
+ $incompatible = TRUE;
+ }
+ }
+
+ if ($incompatible) {
+ $requirements['crop_media'] = [
+ 'title' => t('Crop API'),
+ 'value' => t('This branch of Crop API is not compatible with the version of Media Entity installed.'),
+ 'description' => t('This branch of Crop API is not compatible with the version of Media Entity installed.'),
+ 'severity' => REQUIREMENT_ERROR,
+ ];
+ }
+
+ return $requirements;
+}
+
/**
* Delete orphaned crop entities.
*/
\Drupal::service('config.installer')
->installDefaultConfig('module', 'crop');
}
-
-/**
- * Uninstall deprecated sub-module from active instance.
- */
-function crop_update_8003() {
- if (\Drupal::moduleHandler()->moduleExists('crop_media_entity')) {
- \Drupal::service('module_installer')->uninstall(['crop_media_entity']);
- }
-}
*
* Provides storage and API for image crops.
*/
+
use Drupal\Component\Utility\UrlHelper;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\StreamWrapper\PublicStream;
use Drupal\crop\Entity\Crop;
use Drupal\image\Entity\ImageStyle;
-use Drupal\media\Entity\MediaType;
+use Drupal\media\MediaSourceInterface;
use Drupal\media\MediaTypeInterface;
-use Drupal\media_entity\MediaBundleInterface;
use Drupal\file\FileInterface;
/**
/**
* Implements hook_form_FORM_ID_alter().
*
- * Adds crop configuration fields to media type form.
+ * Adds crop configuration fields to media form.
*/
function crop_form_media_type_edit_form_alter(array &$form, FormStateInterface $form_state, $form_id) {
- _crop_media_provider_form($form, $form_state);
-}
-
-/**
- * Implements hook_form_FORM_ID_alter().
- *
- * Adds crop configuration fields to media bundle form.
- */
-function crop_form_media_bundle_edit_form_alter(array &$form, FormStateInterface $form_state, $form_id) {
- _crop_media_provider_form($form, $form_state);
-}
-
-/**
- * Helper function to avoid uneeded code duplication.
- *
- * @todo Delete this and media entity fallback when media is stable.
- */
-function _crop_media_provider_form(array &$form, FormStateInterface $form_state) {
- /** @var \Drupal\Core\Config\Entity\ConfigEntityBundleBase $entity_type */
+ /** @var \Drupal\media\Entity\MediaType $entity_type */
$entity_type = $form_state->getFormObject()->getEntity();
$options = [];
$allowed_field_types = ['file', 'image'];
}
}
- // Maintain compatibility with Media Entity.
- if ($entity_type instanceof MediaType) {
- $form['#entity_builders'][] = 'crop_media_type_form_builder';
- }
- else {
- $form['#entity_builders'][] = 'crop_media_bundle_form_builder';
- }
-
+ $form['#entity_builders'][] = 'crop_media_type_form_builder';
$form['crop'] = [
'#type' => 'fieldset',
'#title' => t('Crop configuration'),
'#default_value' => $entity_type->getThirdPartySetting('crop', 'image_field'),
'#options' => $options,
'#empty_option' => t('- Skip field -'),
- '#empty_value' => '_none',
+ '#empty_value' => MediaSourceInterface::METADATA_FIELD_EMPTY,
'#description' => t('Select field that stores image which needs to be cropped.'),
];
-
- return $form;
-}
-
-/**
- * Entity builder for Media bundle.
- *
- * Adds third party settings to Media bundle config entity.
- *
- * @see crop_form_media_bundle_form_alter()
- */
-function crop_media_bundle_form_builder($entity_type, MediaBundleInterface $bundle, &$form, FormStateInterface $form_state) {
- $bundle->setThirdPartySetting('crop', 'image_field', $form_state->getValue('image_field'));
}
/**
+++ /dev/null
-name: Media entity crop
-description: 'Deprecated.'
-# core: 8.x
-package: Media
-type: module
-hidden: true
-
-# Information added by Drupal.org packaging script on 2018-01-19
-version: '8.x-1.5'
-core: '8.x'
-project: 'crop'
-datestamp: 1516357097
+++ /dev/null
-<?php
-
-/**
- * @file
- * Deprecated. This empty module will be removed in next release.
- */
* @CropEntityProvider(
* entity_type = "media",
* label = @Translation("Media"),
- * description = @Translation("Provides crop integration for Media.")
+ * description = @Translation("Provides crop integration for media.")
* )
*/
class Media extends EntityProviderBase implements ContainerFactoryPluginInterface {
* {@inheritdoc}
*/
public function uri(EntityInterface $entity) {
-
$bundle_entity_type = $entity->getEntityType()->getBundleEntityType();
/** @var \Drupal\Core\Config\Entity\ConfigEntityBase $entity_type */
$entity_type = $this->entityTypeManager->getStorage($bundle_entity_type)->load($entity->bundle());
-
$image_field = $entity_type->getThirdPartySetting('crop', 'image_field');
if ($entity->{$image_field}->first()->isEmpty()) {
// Build an image style derivative for the file URI.
$image_style_uri = $this->testStyle->buildUri($file_uri);
+
$image_style_uri_url = file_create_url($image_style_uri);
$this->assertTrue(strpos($image_style_uri_url, $shortened_hash) !== FALSE, 'The image style URL contains a shortened hash.');
- // Build an image style URL.
$image_style_url = $this->testStyle->buildUrl($file_uri);
$this->assertTrue(strpos($image_style_url, $shortened_hash) !== FALSE, 'The image style URL contains a shortened hash.');
$crop->setPosition('80', '80')->save();
$old_hash = $shortened_hash;
$new_hash = substr(md5(implode($crop->position()) . implode($crop->anchor())), 0, 8);
+
$image_style_url = $this->testStyle->buildUrl($file_uri);
$this->assertFalse(strpos($image_style_url, $old_hash) !== FALSE, 'The image style URL does not contain the old hash.');
$this->assertTrue(strpos($image_style_url, $new_hash) !== FALSE, 'The image style URL contains an updated hash.');
+++ /dev/null
-# @file
-# .travis.yml - Drupal for Travis CI Integration
-#
-# Template provided by https://github.com/LionsAd/drupal_ti.
-#
-# Based for simpletest upon:
-# https://github.com/sonnym/travis-ci-drupal-module-example
-
-language: php
-
-sudo: false
-
-php:
- - 5.5
- - 5.6
- - 7
- - hhvm
-
-matrix:
- fast_finish: true
- allow_failures:
- - php: hhvm
-
-env:
- global:
- # add composer's global bin directory to the path
- # see: https://github.com/drush-ops/drush#install---composer
- - PATH="$PATH:$HOME/.composer/vendor/bin"
-
- # Configuration variables.
- - DRUPAL_TI_MODULE_NAME="media_entity"
- - DRUPAL_TI_SIMPLETEST_GROUP="media_entity"
-
- # Define runners and environment vars to include before and after the
- # main runners / environment vars.
- #- DRUPAL_TI_SCRIPT_DIR_BEFORE="./drupal_ti/before"
- #- DRUPAL_TI_SCRIPT_DIR_AFTER="./drupal_ti/after"
-
- # The environment to use, supported are: drupal-7, drupal-8
- - DRUPAL_TI_ENVIRONMENT="drupal-8"
- - DRUPAL_TI_CORE_BRANCH="8.1.x"
-
- # The installation profile to use:
- #- DRUPAL_TI_INSTALL_PROFILE="testing"
-
- # Drupal specific variables.
- - DRUPAL_TI_DB="drupal_travis_db"
- - DRUPAL_TI_DB_URL="mysql://root:@127.0.0.1/drupal_travis_db"
- # Note: Do not add a trailing slash here.
- - DRUPAL_TI_WEBSERVER_URL="http://127.0.0.1"
- - DRUPAL_TI_WEBSERVER_PORT="8080"
-
- # Simpletest specific commandline arguments, the DRUPAL_TI_SIMPLETEST_GROUP is appended at the end.
- - DRUPAL_TI_SIMPLETEST_ARGS="--verbose --color --concurrency 4 --url $DRUPAL_TI_WEBSERVER_URL:$DRUPAL_TI_WEBSERVER_PORT"
-
- # === Behat specific variables.
- # This is relative to $TRAVIS_BUILD_DIR
- - DRUPAL_TI_BEHAT_DIR="./tests/behat"
- # These arguments are passed to the bin/behat command.
- - DRUPAL_TI_BEHAT_ARGS=""
- # Specify the filename of the behat.yml with the $DRUPAL_TI_DRUPAL_DIR variables.
- - DRUPAL_TI_BEHAT_YML="behat.yml.dist"
- # This is used to setup Xvfb.
- - DRUPAL_TI_BEHAT_SCREENSIZE_COLOR="1280x1024x16"
- # The version of selenium that should be used.
- - DRUPAL_TI_BEHAT_SELENIUM_VERSION="2.48.2"
- # Set DRUPAL_TI_BEHAT_DRIVER to "selenium" to use "firefox" or "chrome" here.
- - DRUPAL_TI_BEHAT_DRIVER="phantomjs"
- - DRUPAL_TI_BEHAT_BROWSER="firefox"
-
- # PHPUnit specific commandline arguments.
- - DRUPAL_TI_PHPUNIT_ARGS=""
- # Specifying the phpunit-core src/ directory is useful when e.g. a vendor/
- # directory is present in the module directory, which phpunit would then
- # try to find tests in. This option is relative to $TRAVIS_BUILD_DIR.
- #- DRUPAL_TI_PHPUNIT_CORE_SRC_DIRECTORY="./tests/src"
-
- # Code coverage via coveralls.io
- - DRUPAL_TI_COVERAGE="satooshi/php-coveralls:0.6.*"
- # This needs to match your .coveralls.yml file.
- - DRUPAL_TI_COVERAGE_FILE="build/logs/clover.xml"
-
- # Debug options
- #- DRUPAL_TI_DEBUG="-x -v"
- # Set to "all" to output all files, set to e.g. "xvfb selenium" or "selenium",
- # etc. to only output those channels.
- #- DRUPAL_TI_DEBUG_FILE_OUTPUT="selenium xvfb webserver"
-
- matrix:
- # [[[ SELECT ANY OR MORE OPTIONS ]]]
- #- DRUPAL_TI_RUNNERS="phpunit"
- - DRUPAL_TI_RUNNERS="simpletest"
- #- DRUPAL_TI_RUNNERS="behat"
- #- DRUPAL_TI_RUNNERS="phpunit simpletest behat"
- # Use phpunit-core to test modules with phpunit with Drupal 8 core.
- #- DRUPAL_TI_RUNNERS="phpunit-core"
-
-mysql:
- database: drupal_travis_db
- username: root
- encoding: utf8
-
-before_install:
- - composer self-update
- - cd ./tests
- - composer global require "lionsad/drupal_ti:dev-master"
- - drupal-ti before_install
-
-install:
- - drupal-ti install
-
-before_script:
- - drupal-ti before_script
-
-script:
- - drupal-ti script
-
-after_script:
- - drupal-ti after_script
-
-notifications:
- email: false
+++ /dev/null
-Media entity 8.x-1.x-dev
---------------------------------------------------
-- Issue #2099735 by jcisio: Fix typo in Media entity annotation.
-- Issue #2099735 by slashrsm: Create basic entity type definition.
+++ /dev/null
-# Developing
-
-* Issues should be filed at http://drupal.org/project/issues/media_entity
-* Pull requests can be made against https://github.com/drupal-media/media_entity/pulls
-
\ No newline at end of file
-## About Media entity
-
-[![Travis](https://img.shields.io/travis/drupal-media/media_entity.svg)]() [![Scrutinizer](https://img.shields.io/scrutinizer/g/drupal-media/media_entity.svg)]()
-
-Media entity provides a 'base' entity for media. This is a very basic entity
-which can reference to all kinds of media-objects (local files, YouTube
-videos, Tweets, Instagram photos, ...). Media entity provides a relation between
-Drupal and the media resource. You can reference to/use this entity within any
-other Drupal entity.
-
-This module attempts to provide the base storage component for the Drupal 8
-media ecosystem.
-
-Project page: https://drupal.org/project/media_entity
-
-## Official documentation
-
-You will find all the documentation about this module on the [official handbook](https://drupal-media.gitbooks.io/drupal8-guide/content/modules/media_entity/intro.html).
-
-## Contribute
-
-Our current development focus can be seen in [the roadmap issue](https://www.drupal.org/node/2577453).
-
-Development is generally done via [GitHub pull requests](https://github.com/drupal-media/media_entity/pulls).
-Every pull request should be linked to an [issue in drupal.org issue queue](http://drupal.org/project/issues/media_entity)
-and vice-versa.
-
-If you prefer usual patch-based workflow feel free to submit a patch. We started
-using GitHub mostly for easier review process. However, there are not strong opinions
-about that. Any contribution in any shape or form will be treated equally.
-
-## Media provider modules
-
-There are already several media provider modules that extend functionality of
-Media entity:
-
-- [Image](https://drupal.org/project/media_entity_image)
-- [Audio](https://drupal.org/project/media_entity_audio)
-- [Slideshow](https://drupal.org/project/media_entity_slideshow)
-- [Video embed field](https://drupal.org/project/video_embed_field)
-- [Twitter](https://drupal.org/project/media_entity_twitter)
-- [Instagram](https://drupal.org/project/media_entity_instagram)
-- [Document](https://drupal.org/project/media_entity_document)
-- [Slideshare](https://drupal.org/project/media_entity_slideshare)
-- [Video (local)](https://drupal.org/project/media_entity_video)
-- [Tumblr](https://drupal.org/project/media_entity_tumblr)
-- [Facebook](https://drupal.org/project/media_entity_facebook)
-- [Audio embed field (sandbox)](https://drupal.org/sandbox/vilepickle/2784301)
-
-## Other modules that integrate with media entity
-
-- [Entity browser](https://drupal.org/project/entity_browser): Provides entity browser
- widget that supports uploading [Media entity images](https://drupal.org/project/media_entity_image).
-- [DropzoneJS](https://drupal.org/project/dropzonejs): Extends entity browser [image
- upload widget](https://drupal.org/project/media_entity_image) with [DropzoneJS
- upload library](http://www.dropzonejs.com).
-- [Slick media](https://drupal.org/project/slick_media): Provides integration
-between [Slick carousel](https://drupal.org/project/slick) and Media entity. Slick media allows richer slideshows/carousel
- with a mix of text, image and video.
-- [Brightcove](https://github.com/dawehner/media_entity_brightcove)
-
-## Maintainers
-- Janez Urevc ([@slashrsm](https://github.com/slashrsm)) https://drupal.org/user/744628
-- Primož Hmeljak ([@primsi](https://github.com/primsi)) https://drupal.org/user/282629
-- Nguyễn Hải Nam (@jcisio) https://drupal.org/user/210762
-- Boris Gordon (@boztek) https://drupal.org/user/134410
-
-## Get in touch
-- http://groups.drupal.org/media
-- IRC: #drupal-media @ Freenode
+# Upgrade path from Media Entity to Media (core)
+
+This version of Media Entity is intended **only** to be used as a bridge to
+move to the new "Media" module included in Drupal core (>= 8.4.0). While the
+storage of media entities is the same, some aspects of the API have changed.
+Because of that, if you have an existing site using Media Entity 1.x, you need
+to follow the upgrade path indicated below in order to move to Media in core.
+
+## Upgrade instructions
+1. Backup your code and your database
+2. Test that you can successfully roll-back from the backup!
+3. Upgrade the codebase with:
+ - Core: >= **8.4.x**
+ - Media Entity: **8.x-2.x**
+ - All media entity providers: **8.x-2.x** (or use patches from #2860796: Plan for
+ contributed modules with Media Entity API in core). Note that the modules
+ Media Entity Image and Media Entity Document, if present, don't need to be
+ updated. Their configs will be updated by the main Media Entity updates.
+ - All modules that depend on or interact with Media Entity: **8.x-2.x**
+ - The new contrib module **Media Entity Actions**: **8.x-1.x**
+ - Note: If your site uses media entities with the "Generic" provider, make
+ sure you download to your codebase the **Media Entity Generic** module as
+ well.
+4. Clear your caches.
+5. (Optional) Check that all requirements for the upgrade are met with
+ `drush mecu`.
+ **IMPORTANT**: Please note that if you are running DB updates with Drush 9
+ (between 9.0.0-alpha1 and 9.0.0-beta7), you are **strongly** encouraged to
+ use this command prior to running the updates. Drush 9 will not run the
+ requirements validation and will try to run the updates even if your site has
+ some of the requisites misconfigured. Executing the updates in that scenario
+ will likely break your site. This was fixed in Drush 9.0.0-beta8. Drush 8
+ users don't need to worry about this.
+6. Run the DB Updates, either by visiting `/update.php`, or using `drush updb`.
+7. Double-check **Media Entity** is uninstalled, and remove it from the
+ codebase. Remove also **Media Entity Image** / **Document**, if present.
+8. Run your automated tests, if any, or manually verify that all media-related
+ functionality on your site works as expected.
+
+**Known issues concerning the upgrade path:**
+- If your existing site relies on the EXIF image metadata handling, please check
+ https://drupal.org/node/2927481 before proceeding with the upgrade.
+- Entity Browser has a 2.x branch that has new features for media in core, for
+ example the widget that was formerly present in the "Media Entity Image"
+ module. However, if you intend to upgrade Entity Browser to the 2.x branch, you
+ should do that only after performing the main Media Entity upgrades. There is
+ currently a bug preventing the Media Entity upgrade if the Entity Browser 2.x
+ is present in the codebase.
+++ /dev/null
-icon_base: 'public://media-icons/generic'
+++ /dev/null
-langcode: en
-status: true
-dependencies:
- module:
- - image
- - media_entity
- - user
-id: media
-label: Media
-module: views
-description: ''
-tag: ''
-base_table: media_field_data
-base_field: mid
-core: 8.x
-display:
- default:
- display_plugin: default
- id: default
- display_title: Master
- position: 0
- display_options:
- access:
- type: perm
- options:
- perm: 'access media overview'
- cache:
- type: tag
- options: { }
- query:
- type: views_query
- options:
- disable_sql_rewrite: false
- distinct: false
- replica: false
- query_comment: ''
- query_tags: { }
- exposed_form:
- type: basic
- options:
- submit_button: Apply
- reset_button: false
- reset_button_label: Reset
- exposed_sorts_label: 'Sort by'
- expose_sort_order: true
- sort_asc_label: Asc
- sort_desc_label: Desc
- pager:
- type: full
- options:
- items_per_page: 50
- offset: 0
- id: 0
- total_pages: null
- expose:
- items_per_page: false
- items_per_page_label: 'Items per page'
- items_per_page_options: '5, 10, 25, 50'
- items_per_page_options_all: false
- items_per_page_options_all_label: '- All -'
- offset: false
- offset_label: Offset
- tags:
- previous: '‹ Previous'
- next: 'Next ›'
- first: '« First'
- last: 'Last »'
- quantity: 9
- style:
- type: table
- options:
- grouping: { }
- row_class: ''
- default_row_class: true
- override: true
- sticky: false
- caption: ''
- summary: ''
- description: ''
- columns:
- name: name
- bundle: bundle
- changed: changed
- uid: uid
- status: status
- thumbnail__target_id: thumbnail__target_id
- info:
- name:
- sortable: true
- default_sort_order: asc
- align: ''
- separator: ''
- empty_column: false
- responsive: ''
- bundle:
- sortable: true
- default_sort_order: asc
- align: ''
- separator: ''
- empty_column: false
- responsive: ''
- changed:
- sortable: true
- default_sort_order: desc
- align: ''
- separator: ''
- empty_column: false
- responsive: ''
- uid:
- sortable: false
- default_sort_order: asc
- align: ''
- separator: ''
- empty_column: false
- responsive: ''
- status:
- sortable: true
- default_sort_order: asc
- align: ''
- separator: ''
- empty_column: false
- responsive: ''
- thumbnail__target_id:
- sortable: false
- default_sort_order: asc
- align: ''
- separator: ''
- empty_column: false
- responsive: ''
- default: changed
- empty_table: false
- row:
- type: fields
- fields:
- media_bulk_form:
- id: media_bulk_form
- table: media
- field: media_bulk_form
- relationship: none
- group_type: group
- admin_label: ''
- label: ''
- exclude: false
- alter:
- alter_text: false
- text: ''
- make_link: false
- path: ''
- absolute: false
- external: false
- replace_spaces: false
- path_case: none
- trim_whitespace: false
- alt: ''
- rel: ''
- link_class: ''
- prefix: ''
- suffix: ''
- target: ''
- nl2br: false
- max_length: 0
- word_boundary: true
- ellipsis: true
- more_link: false
- more_link_text: ''
- more_link_path: ''
- strip_tags: false
- trim: false
- preserve_tags: ''
- html: false
- element_type: ''
- element_class: ''
- element_label_type: ''
- element_label_class: ''
- element_label_colon: false
- element_wrapper_type: ''
- element_wrapper_class: ''
- element_default_classes: true
- empty: ''
- hide_empty: false
- empty_zero: false
- hide_alter_empty: true
- action_title: Action
- include_exclude: exclude
- selected_actions: { }
- entity_type: media
- plugin_id: media_bulk_form
- thumbnail__target_id:
- id: thumbnail__target_id
- table: media_field_data
- field: thumbnail__target_id
- relationship: none
- group_type: group
- admin_label: ''
- label: Thumbnail
- exclude: false
- alter:
- alter_text: false
- text: ''
- make_link: false
- path: ''
- absolute: false
- external: false
- replace_spaces: false
- path_case: none
- trim_whitespace: false
- alt: ''
- rel: ''
- link_class: ''
- prefix: ''
- suffix: ''
- target: ''
- nl2br: false
- max_length: 0
- word_boundary: true
- ellipsis: true
- more_link: false
- more_link_text: ''
- more_link_path: ''
- strip_tags: false
- trim: false
- preserve_tags: ''
- html: false
- element_type: ''
- element_class: ''
- element_label_type: ''
- element_label_class: ''
- element_label_colon: true
- element_wrapper_type: ''
- element_wrapper_class: ''
- element_default_classes: true
- empty: ''
- hide_empty: false
- empty_zero: false
- hide_alter_empty: true
- click_sort_column: target_id
- type: image
- settings:
- image_style: thumbnail
- image_link: ''
- group_column: ''
- group_columns: { }
- group_rows: true
- delta_limit: 0
- delta_offset: 0
- delta_reversed: false
- delta_first_last: false
- multi_type: separator
- separator: ', '
- field_api_classes: false
- entity_type: media
- entity_field: thumbnail
- plugin_id: field
- name:
- id: name
- table: media_field_data
- field: name
- entity_type: media
- entity_field: media
- alter:
- alter_text: false
- make_link: false
- absolute: false
- trim: false
- word_boundary: false
- ellipsis: false
- strip_tags: false
- html: false
- hide_empty: false
- empty_zero: false
- settings:
- link_to_entity: true
- plugin_id: field
- relationship: none
- group_type: group
- admin_label: ''
- label: 'Media name'
- exclude: false
- element_type: ''
- element_class: ''
- element_label_type: ''
- element_label_class: ''
- element_label_colon: true
- element_wrapper_type: ''
- element_wrapper_class: ''
- element_default_classes: true
- empty: ''
- hide_alter_empty: true
- click_sort_column: value
- type: string
- group_column: value
- group_columns: { }
- group_rows: true
- delta_limit: 0
- delta_offset: 0
- delta_reversed: false
- delta_first_last: false
- multi_type: separator
- separator: ', '
- field_api_classes: false
- bundle:
- id: bundle
- table: media_field_data
- field: bundle
- relationship: none
- group_type: group
- admin_label: ''
- label: Provider
- exclude: false
- alter:
- alter_text: false
- text: ''
- make_link: false
- path: ''
- absolute: false
- external: false
- replace_spaces: false
- path_case: none
- trim_whitespace: false
- alt: ''
- rel: ''
- link_class: ''
- prefix: ''
- suffix: ''
- target: ''
- nl2br: false
- max_length: 0
- word_boundary: true
- ellipsis: true
- more_link: false
- more_link_text: ''
- more_link_path: ''
- strip_tags: false
- trim: false
- preserve_tags: ''
- html: false
- element_type: ''
- element_class: ''
- element_label_type: ''
- element_label_class: ''
- element_label_colon: true
- element_wrapper_type: ''
- element_wrapper_class: ''
- element_default_classes: true
- empty: ''
- hide_empty: false
- empty_zero: false
- hide_alter_empty: true
- click_sort_column: target_id
- type: entity_reference_label
- settings:
- link: false
- group_column: target_id
- group_columns: { }
- group_rows: true
- delta_limit: 0
- delta_offset: 0
- delta_reversed: false
- delta_first_last: false
- multi_type: separator
- separator: ', '
- field_api_classes: false
- entity_type: media
- entity_field: bundle
- plugin_id: field
- uid:
- id: uid
- table: media_field_data
- field: uid
- relationship: none
- group_type: group
- admin_label: ''
- label: Author
- exclude: false
- alter:
- alter_text: false
- text: ''
- make_link: false
- path: ''
- absolute: false
- external: false
- replace_spaces: false
- path_case: none
- trim_whitespace: false
- alt: ''
- rel: ''
- link_class: ''
- prefix: ''
- suffix: ''
- target: ''
- nl2br: false
- max_length: 0
- word_boundary: true
- ellipsis: true
- more_link: false
- more_link_text: ''
- more_link_path: ''
- strip_tags: false
- trim: false
- preserve_tags: ''
- html: false
- element_type: ''
- element_class: ''
- element_label_type: ''
- element_label_class: ''
- element_label_colon: true
- element_wrapper_type: ''
- element_wrapper_class: ''
- element_default_classes: true
- empty: ''
- hide_empty: false
- empty_zero: false
- hide_alter_empty: true
- click_sort_column: target_id
- type: entity_reference_label
- settings:
- link: true
- group_column: target_id
- group_columns: { }
- group_rows: true
- delta_limit: 0
- delta_offset: 0
- delta_reversed: false
- delta_first_last: false
- multi_type: separator
- separator: ', '
- field_api_classes: false
- entity_type: media
- entity_field: uid
- plugin_id: field
- status:
- id: status
- table: media_field_data
- field: status
- relationship: none
- group_type: group
- admin_label: ''
- label: Status
- exclude: false
- alter:
- alter_text: false
- text: ''
- make_link: false
- path: ''
- absolute: false
- external: false
- replace_spaces: false
- path_case: none
- trim_whitespace: false
- alt: ''
- rel: ''
- link_class: ''
- prefix: ''
- suffix: ''
- target: ''
- nl2br: false
- max_length: 0
- word_boundary: true
- ellipsis: true
- more_link: false
- more_link_text: ''
- more_link_path: ''
- strip_tags: false
- trim: false
- preserve_tags: ''
- html: false
- element_type: ''
- element_class: ''
- element_label_type: ''
- element_label_class: ''
- element_label_colon: true
- element_wrapper_type: ''
- element_wrapper_class: ''
- element_default_classes: true
- empty: ''
- hide_empty: false
- empty_zero: false
- hide_alter_empty: true
- click_sort_column: value
- type: boolean
- settings:
- format: custom
- format_custom_true: Published
- format_custom_false: Unpublished
- group_column: value
- group_columns: { }
- group_rows: true
- delta_limit: 0
- delta_offset: 0
- delta_reversed: false
- delta_first_last: false
- multi_type: separator
- separator: ', '
- field_api_classes: false
- entity_type: media
- entity_field: status
- plugin_id: field
- changed:
- id: changed
- table: media_field_data
- field: changed
- relationship: none
- group_type: group
- admin_label: ''
- label: Updated
- exclude: false
- alter:
- alter_text: false
- text: ''
- make_link: false
- path: ''
- absolute: false
- external: false
- replace_spaces: false
- path_case: none
- trim_whitespace: false
- alt: ''
- rel: ''
- link_class: ''
- prefix: ''
- suffix: ''
- target: ''
- nl2br: false
- max_length: 0
- word_boundary: true
- ellipsis: true
- more_link: false
- more_link_text: ''
- more_link_path: ''
- strip_tags: false
- trim: false
- preserve_tags: ''
- html: false
- element_type: ''
- element_class: ''
- element_label_type: ''
- element_label_class: ''
- element_label_colon: true
- element_wrapper_type: ''
- element_wrapper_class: ''
- element_default_classes: true
- empty: ''
- hide_empty: false
- empty_zero: false
- hide_alter_empty: true
- click_sort_column: value
- type: timestamp
- settings:
- date_format: short
- custom_date_format: ''
- timezone: ''
- group_column: value
- group_columns: { }
- group_rows: true
- delta_limit: 0
- delta_offset: 0
- delta_reversed: false
- delta_first_last: false
- multi_type: separator
- separator: ', '
- field_api_classes: false
- entity_type: media
- entity_field: changed
- plugin_id: field
- operations:
- id: operations
- table: media
- field: operations
- relationship: none
- group_type: group
- admin_label: ''
- label: Operations
- exclude: false
- alter:
- alter_text: false
- text: ''
- make_link: false
- path: ''
- absolute: false
- external: false
- replace_spaces: false
- path_case: none
- trim_whitespace: false
- alt: ''
- rel: ''
- link_class: ''
- prefix: ''
- suffix: ''
- target: ''
- nl2br: false
- max_length: 0
- word_boundary: true
- ellipsis: true
- more_link: false
- more_link_text: ''
- more_link_path: ''
- strip_tags: false
- trim: false
- preserve_tags: ''
- html: false
- element_type: ''
- element_class: ''
- element_label_type: ''
- element_label_class: ''
- element_label_colon: true
- element_wrapper_type: ''
- element_wrapper_class: ''
- element_default_classes: true
- empty: ''
- hide_empty: false
- empty_zero: false
- hide_alter_empty: true
- destination: true
- entity_type: media
- plugin_id: entity_operations
- filters:
- status:
- id: status
- table: media_field_data
- field: status
- relationship: none
- group_type: group
- admin_label: ''
- operator: '='
- value: '1'
- group: 1
- exposed: true
- expose:
- operator_id: ''
- label: 'True'
- description: null
- use_operator: false
- operator: status_op
- identifier: status
- required: true
- remember: false
- multiple: false
- remember_roles:
- authenticated: authenticated
- is_grouped: true
- group_info:
- label: 'Publishing status'
- description: ''
- identifier: status
- optional: true
- widget: select
- multiple: false
- remember: false
- default_group: All
- default_group_multiple: { }
- group_items:
- 1:
- title: Published
- operator: '='
- value: '1'
- 2:
- title: Unpublished
- operator: '='
- value: '0'
- plugin_id: boolean
- entity_type: media
- entity_field: status
- bundle:
- id: bundle
- table: media_field_data
- field: bundle
- relationship: none
- group_type: group
- admin_label: ''
- operator: in
- value: { }
- group: 1
- exposed: true
- expose:
- operator_id: bundle_op
- label: Provider
- description: ''
- use_operator: false
- operator: bundle_op
- identifier: provider
- required: false
- remember: false
- multiple: false
- remember_roles:
- authenticated: authenticated
- anonymous: '0'
- administrator: '0'
- reduce: false
- is_grouped: false
- group_info:
- label: ''
- description: ''
- identifier: ''
- optional: true
- widget: select
- multiple: false
- remember: false
- default_group: All
- default_group_multiple: { }
- group_items: { }
- entity_type: media
- entity_field: bundle
- plugin_id: bundle
- name:
- id: name
- table: media_field_data
- field: name
- relationship: none
- group_type: group
- admin_label: ''
- operator: contains
- value: ''
- group: 1
- exposed: true
- expose:
- operator_id: name_op
- label: 'Media name'
- description: ''
- use_operator: false
- operator: name_op
- identifier: name
- required: false
- remember: false
- multiple: false
- remember_roles:
- authenticated: authenticated
- anonymous: '0'
- administrator: '0'
- is_grouped: false
- group_info:
- label: ''
- description: ''
- identifier: ''
- optional: true
- widget: select
- multiple: false
- remember: false
- default_group: All
- default_group_multiple: { }
- group_items: { }
- entity_type: media
- entity_field: name
- plugin_id: string
- langcode:
- id: langcode
- table: media_field_data
- field: langcode
- relationship: none
- group_type: group
- admin_label: ''
- operator: in
- value: { }
- group: 1
- exposed: true
- expose:
- operator_id: langcode_op
- label: Language
- description: ''
- use_operator: false
- operator: langcode_op
- identifier: langcode
- required: false
- remember: false
- multiple: false
- remember_roles:
- authenticated: authenticated
- anonymous: '0'
- administrator: '0'
- reduce: false
- is_grouped: false
- group_info:
- label: ''
- description: ''
- identifier: ''
- optional: true
- widget: select
- multiple: false
- remember: false
- default_group: All
- default_group_multiple: { }
- group_items: { }
- entity_type: media
- entity_field: langcode
- plugin_id: language
- sorts:
- created:
- id: created
- table: media_field_data
- field: created
- order: DESC
- entity_type: media
- entity_field: created
- plugin_id: date
- relationship: none
- group_type: group
- admin_label: ''
- exposed: false
- expose:
- label: ''
- granularity: second
- title: Media
- header: { }
- footer: { }
- empty:
- area_text_custom:
- id: area_text_custom
- table: views
- field: area_text_custom
- relationship: none
- group_type: group
- admin_label: ''
- empty: true
- tokenize: false
- content: 'No content available.'
- plugin_id: text_custom
- relationships: { }
- arguments: { }
- display_extenders: { }
- cache_metadata:
- max-age: 0
- contexts:
- - 'languages:language_content'
- - 'languages:language_interface'
- - url
- - url.query_args
- - user.permissions
- tags: { }
- media_page_list:
- display_plugin: page
- id: media_page_list
- display_title: Media
- position: 1
- display_options:
- display_extenders: { }
- path: admin/content/media
- menu:
- type: tab
- title: Media
- description: ''
- expanded: false
- parent: ''
- weight: 0
- context: '0'
- menu_name: main
- display_description: ''
- cache_metadata:
- max-age: 0
- contexts:
- - 'languages:language_content'
- - 'languages:language_interface'
- - url
- - url.query_args
- - user.permissions
- tags: { }
+++ /dev/null
-media_entity.settings:
- type: config_object
- label: 'Media entity settings'
- mapping:
- icon_base:
- type: string
- label: 'Base folder for icons installation'
-
-media_entity.bundle.*:
- type: config_entity
- label: 'Media bundle'
- mapping:
- id:
- type: string
- label: 'Machine name'
- label:
- type: label
- label: 'Label'
- description:
- type: text
- label: 'Description'
- type:
- type: string
- label: 'Type plugin ID'
- queue_thumbnail_downloads:
- type: boolean
- label: 'Queue thumbnail downloads'
- new_revision:
- type: boolean
- label: 'Whether a new revision should be created by default'
- type_configuration:
- type: media_entity.bundle.type.[%parent.type]
- field_map:
- type: sequence
- label: 'Field map'
- sequence:
- type: string
- third_party_settings:
- type: sequence
- label: 'Third party settings'
- sequence:
- type: media_entity.bundle.third_party.[%key]
-
-action.configuration.media_delete_action:
- type: action_configuration_default
- label: 'Delete media configuration'
-
-action.configuration.media_save_action:
- type: action_configuration_default
- label: 'Save media configuration'
-
-action.configuration.media_publish_action:
- type: action_configuration_default
- label: 'Publish media configuration'
-
-action.configuration.media_unpublish_action:
- type: action_configuration_default
- label: 'Unpublish media configuration'
-
-field.formatter.settings.media_thumbnail:
- type: mapping
- label: 'Media thumbnail field display format settings'
- mapping:
- image_link:
- type: string
- label: 'Link image to'
- image_style:
- type: string
- label: 'Image style'
+++ /dev/null
-# Schema for the views plugins of the Media Entity module.
-
-views.field.media_bulk_form:
- type: views_field_bulk_form
- label: 'Media Entity bulk form'
--- /dev/null
+services:
+ media_entity.drush.commands:
+ class: \Drupal\media_entity\Commands\DrushCommands
+ arguments: ['@media_entity.cli']
+ tags:
+ - { name: drush.command }
+++ /dev/null
-/**
- * @file
- * Javascript for the media bundle form.
- */
-
-(function ($, Drupal) {
- 'use strict';
-
- /**
- * Behaviors for setting summaries on media bundle form.
- *
- * @type {Drupal~behavior}
- *
- * @prop {Drupal~behaviorAttach} attach
- * Attaches summary behaviors on media bundle edit forms.
- */
- Drupal.behaviors.contentTypes = {
- attach: function (context) {
- var $context = $(context);
- // Provide the vertical tab summaries.
- $context.find('#edit-workflow').drupalSetSummary(function (context) {
- var vals = [];
- $(context).find('input[name^="options"]:checked').parent().each(function () {
- vals.push(Drupal.checkPlain($(this).find('label').text()));
- });
- if (!$(context).find('#edit-options-status').is(':checked')) {
- vals.unshift(Drupal.t('Not published'));
- }
- return vals.join(', ');
- });
- $('#edit-language', context).drupalSetSummary(function (context) {
- var vals = [];
-
- vals.push($('.js-form-item-language-configuration-langcode select option:selected', context).text());
-
- $('input:checked', context).next('label').each(function () {
- vals.push(Drupal.checkPlain($(this).text()));
- });
-
- return vals.join(', ');
- });
- }
- };
-
-})(jQuery, Drupal);
+++ /dev/null
-<?php
-
-/**
- * @file
- * Hooks related to media entity and it's plugins.
- */
-
-/**
- * @addtogroup hooks
- * @{
- */
-
-/**
- * Alter the information provided in \Drupal\media_entity\Annotation\MediaType.
- *
- * @param array $types
- * The array of type plugins, keyed on the machine-readable name.
- */
-function hook_media_entity_type_info_alter(&$types) {
- $types['youtube']['label'] = t('Youtube rocks!');
-}
-
-/**
- * @} End of "addtogroup hooks".
- */
--- /dev/null
+<?php
+
+/**
+ * @file
+ * Drush integration for media_entity.
+ */
+
+use Drush\Log\LogLevel;
+
+/**
+ * Implements drush_hook_COMMAND_validate().
+ */
+function drush_media_entity_updatedb_validate() {
+ // This hook exists because when running DB updates using drush,
+ // hook_requirements() is not enforced (see
+ // https://github.com/drush-ops/drush/pull/2708 for more info on that).
+ // Here we just re-evaluate all the checks from hook_requirements() and abort
+ // the "updatedb/updb" command by returning FALSE to this hook if any of them
+ // is not met.
+ drush_bootstrap_to_phase(DRUSH_BOOTSTRAP_DRUPAL_FULL);
+
+ // Normally users should remove Media Entity from the codebase after the
+ // upgrade. However, if they don't do so, this function will be called on
+ // subsequent DB upgrades, even if ME is not enabled. Don't proceed on those
+ // circumstances.
+ if (!\Drupal::moduleHandler()->moduleExists('media_entity')) {
+ return TRUE;
+ }
+
+ $checks = \Drupal::service('media_entity.cli')->validateDbUpdateRequirements();
+ if (empty($checks['errors'])) {
+ return TRUE;
+ }
+ else {
+ foreach ($checks['errors'] as $error_msg) {
+ // We can't use drush_log() inside this hook.
+ drush_print($error_msg);
+ }
+ return FALSE;
+ }
+}
+
+/**
+ * Implements hook_drush_command().
+ */
+function media_entity_drush_command() {
+
+ $items['media-entity-check-upgrade'] = [
+ 'description' => 'Check upgrade requirements for Media Entity into Media in core.',
+ 'aliases' => ['mecu'],
+ 'core' => ['8+'],
+ 'examples' => [
+ "drush mecu" => "Checks upgrade requirements for Media Entity while upgrading to Media in core.",
+ ],
+ ];
+
+ return $items;
+}
+
+/**
+ * Callback for drush commmand "media-entity-check-upgrade" (mecu).
+ */
+function drush_media_entity_check_upgrade() {
+ // This command is useless if the DB updates have already been run.
+ if (drupal_get_installed_schema_version('media_entity') >= 8004) {
+ drush_log(dt('Your site has already run the media_entity DB updates. If you believe this is not correct, you should consider rolling back your database to a previous backup and try again.'), LogLevel::WARNING);
+ return;
+ }
+
+ drush_bootstrap_to_phase(DRUSH_BOOTSTRAP_DRUPAL_FULL);
+ $checks = \Drupal::service('media_entity.cli')->validateDbUpdateRequirements();
+
+ if (empty($checks['errors'])) {
+ drush_log(sprintf("\033[1;32;40m\033[1m%s\033[0m", '✓') . ' ' . dt('SUCCESS: All upgrade requirements are met and you can proceed with the DB updates.'), LogLevel::OK);
+ }
+ else {
+ drush_log(sprintf("\033[31;40m\033[1m%s\033[0m", '✗') . ' ' . dt('ERROR: Your site did not pass all upgrade checks. You can find more information in the error messages below.'), LogLevel::ERROR);
+ }
+ foreach ($checks['passes'] as $pass_msg) {
+ drush_log($pass_msg, LogLevel::OK);
+ }
+ foreach ($checks['errors'] as $error_msg) {
+ drush_log($error_msg, LogLevel::ERROR);
+ }
+}
-name: Media entity
+name: Media entity (2.x)
description: 'Media entity API.'
type: module
package: Media
- drupal:user
- drupal:views
- entity:entity
- - drupal:system
-test_dependencies:
- - entity:entity
- - inline_entity_form:inline_entity_form
+ - drupal:system (>=8.5)
-# Information added by Drupal.org packaging script on 2017-11-15
-version: '8.x-1.7'
+# Information added by Drupal.org packaging script on 2018-03-09
+version: '8.x-2.0-beta2'
core: '8.x'
project: 'media_entity'
-datestamp: 1510737188
+datestamp: 1520603588
* Install, uninstall and update hooks for Media entity module.
*/
+use Drupal\Core\Utility\UpdateException;
+use Drupal\Core\Config\Entity\Query\QueryFactory;
+use Drupal\Core\Database\Database;
+use Drupal\Core\Url;
+use Drupal\user\Entity\Role;
+
/**
* Checks if required version of the Entity API is installed.
*
return FALSE;
}
+/**
+ * Checks if all contrib modules depending on media_entity were updated.
+ *
+ * @return array
+ * An empty array if all modules that depend on media_entity were updated, or
+ * an array of incompatible modules otherwise. This array will be keyed by
+ * either "providers" or "modules", depending if the incompatible module is a
+ * contrib module that provides a type plugin (in which case it is expected to
+ * have been upgraded to its 2.x branch) or just a module that depends on
+ * "media_entity", respectively.
+ */
+function _media_entity_get_incompatible_modules() {
+ \Drupal::service('plugin.cache_clearer')->clearCachedDefinitions();
+ $incompatible_modules = [];
+ // Modules that provide provider plugins need to have ben updated and be
+ // implementing now @MediaSource instead of @MediaType plugins.
+ $old_plugins = \Drupal::service('plugin.manager.media_entity.type')->getDefinitions();
+ // The main media_entity module defines a "generic" type. We are directly
+ // handling this provider's configs in the update hook.
+ unset($old_plugins['generic']);
+ foreach ($old_plugins as $definition) {
+ $incompatible_modules['providers'][$definition['provider']] = $definition['provider'];
+ }
+ // None of the enabled modules in the system should at this point depend on
+ // media_entity anymore.
+ /** @var \Drupal\Core\Extension\Extension[] $module_list */
+ $module_list = \Drupal::moduleHandler()->getModuleList();
+ foreach (array_keys($module_list) as $module_name) {
+ $info = system_get_info('module', $module_name);
+ if (!empty($info['dependencies'])) {
+ foreach ($info['dependencies'] as $dependency) {
+ if ($dependency === 'media_entity' || $dependency === 'media_entity:media_entity') {
+ $incompatible_modules['modules'][$module_name] = $module_name;
+ }
+ }
+ }
+ }
+
+ // Disregard "media_entity_document" and "media_entity_image", once we will
+ // uninstall them ourselves as part of the update hook.
+ unset($incompatible_modules['providers']['media_entity_document']);
+ unset($incompatible_modules['modules']['media_entity_document']);
+ unset($incompatible_modules['providers']['media_entity_image']);
+ unset($incompatible_modules['modules']['media_entity_image']);
+ if (empty($incompatible_modules['providers'])) {
+ unset($incompatible_modules['providers']);
+ }
+ if (empty($incompatible_modules['modules'])) {
+ unset($incompatible_modules['modules']);
+ }
+
+ return $incompatible_modules;
+}
+
+/**
+ * Helper function to rename config dependencies.
+ *
+ * @param string $dependency_type
+ * The type of the dependency, such as "module" or "config".
+ * @param string $dependency_id
+ * The name of the dependency to be updated.
+ * @param callable $map
+ * A callback to be passed to array_map() to actually perform the config name
+ * substitution.
+ */
+function _media_entity_fix_dependencies($dependency_type, $dependency_id, callable $map) {
+ $dependents = \Drupal::service('config.manager')
+ ->findConfigEntityDependents($dependency_type, [$dependency_id]);
+
+ $key = 'dependencies.' . $dependency_type;
+
+ foreach (array_keys($dependents) as $config) {
+ $config = \Drupal::configFactory()->getEditable($config);
+ $dependencies = $config->get($key);
+ if (is_array($dependencies)) {
+ $config->set($key, array_map($map, $dependencies))->save();
+ }
+ }
+}
+
+/**
+ * Helper function to determine the name of a source field.
+ *
+ * @return string
+ * The source field name. If one is already stored in configuration, it is
+ * returned. Otherwise, a new, unused one is generated.
+ */
+function _media_get_source_field_name($plugin_id) {
+ $base_id = 'field_media_' . $plugin_id;
+ $tries = 0;
+ $storage = \Drupal::entityTypeManager()->getStorage('field_storage_config');
+
+ // Iterate at least once, until no field with the generated ID is found.
+ do {
+ $id = $base_id;
+ // If we've tried before, increment and append the suffix.
+ if ($tries) {
+ $id .= '_' . $tries;
+ }
+ $field = $storage->load('media.' . $id);
+ $tries++;
+ } while ($field);
+
+ return $id;
+}
+
+/**
+ * Gets the names of all media bundles that use a particular type plugin.
+ *
+ * @param string $plugin_id
+ * The type plugin ID.
+ *
+ * @return string[]
+ * The media bundle IDs which use the specified plugin.
+ */
+function _media_entity_get_bundles_by_plugin($plugin_id) {
+ $types = [];
+ foreach (\Drupal::configFactory()->listAll('media_entity.bundle') as $name) {
+ if (\Drupal::config($name)->get('type') == $plugin_id) {
+ $types[] = explode('.', $name, 3)[2];
+ }
+ }
+ return $types;
+}
+
+/**
+ * Checks whether this site has image types with EXIF handling enabled.
+ *
+ * @return string[]
+ * The media bundle IDs which have the EXIF handling enabled, or an empty
+ * array if none have it so.
+ */
+function _media_entity_get_bundles_using_exif() {
+ $bundles = [];
+
+ foreach (_media_entity_get_bundles_by_plugin('image') as $bundle_name) {
+ $gather_exif = \Drupal::config("media_entity.bundle.$bundle_name")->get('type_configuration.gather_exif');
+ if ($gather_exif) {
+ $bundles[] = $bundle_name;
+ }
+ }
+
+ return $bundles;
+}
+
/**
* Implements hook_requirements().
*/
'severity' => REQUIREMENT_ERROR,
];
}
- if ($phase == 'install' && \Drupal::moduleHandler()->moduleExists('media')) {
- $version = explode('.', \Drupal::VERSION);
- if ($version[1] >= 4) {
- $requirements['media_module_incompatibility'] = [
+
+ // Prevent this branch from being installed on new sites.
+ if ($phase == 'install') {
+ $requirements['media_entity_update_only'] = [
+ 'title' => t('Media entity'),
+ 'description' => t('This branch of Media Entity is intended for site upgrades only. Please use the 1.x branch or Drupal core >= 8.4.x if you are building a new site.'),
+ 'severity' => REQUIREMENT_ERROR,
+ ];
+ }
+
+ if ($phase == 'update') {
+ // Here we want to ensure that a series of requirements are met before
+ // letting the DB updates continue. However, the batch processing of
+ // hook_update_N() triggers this validation again during the update process.
+ // Because of that, we want to make sure that these requirements checks are
+ // only evaluated once, and we use a state variable for that.
+ if (!\Drupal::state()->get('media_entity_core_upgrade_started')) {
+ $checks = \Drupal::service('media_entity.cli')->validateDbUpdateRequirements();
+ foreach ($checks['errors'] as $key => $error_msg) {
+ $requirements['media_entity_upgrade_' . $key] = [
+ 'title' => t('Media Entity'),
+ 'value' => t('Please fix the error below and try again.'),
+ 'description' => $error_msg,
+ 'severity' => REQUIREMENT_ERROR,
+ ];
+ }
+ }
+ }
+
+ if ($phase == 'runtime') {
+ if (drupal_get_installed_schema_version('media_entity') < 8201) {
+ $requirements['media_entity_update_status'] = [
+ 'title' => t('Media Entity'),
+ 'value' => t('DB updates for Media Entity pending.'),
+ 'description' => t('After updating the Media Entity code, you need to run the <a href=":update">database update script</a> as soon as possible.', [
+ ':update' => Url::fromRoute('system.db_update')->toString(),
+ ]),
+ 'severity' => REQUIREMENT_WARNING,
+ ];
+ }
+ else {
+ $requirements['media_entity_update_status'] = [
'title' => t('Media Entity'),
- 'value' => t('The Media Entity module is not compatible with media in core.'),
- 'description' => t('The 1.x branch of Media Entity cannot be used in conjunction with the media module in core. Please check the 2.x branch for an upgrade path.'),
- 'severity' => REQUIREMENT_ERROR,
+ 'value' => t('DB updates for Media Entity were run.'),
+ 'description' => t('The Media Entity upgrade path was executed, you can now uninstall and remove the Media Entity module from the codebase.'),
+ 'severity' => REQUIREMENT_OK,
];
}
}
*/
function media_entity_update_8003() {
if (!_media_entity_check_entity_version()) {
- throw new \Drupal\Core\Utility\UpdateException('Entity API >= 8.x-1.0-alpha3 (drupal.org/project/entity) module is now a dependency and needs to be installed before running updates.');
+ throw new UpdateException('Entity API >= 8.x-1.0-alpha3 (drupal.org/project/entity) module is now a dependency and needs to be installed before running updates.');
}
}
+
+/**
+ * Clears the module handler's hook implementation cache.
+ */
+function media_entity_update_8200() {
+ \Drupal::moduleHandler()->resetImplementations();
+ \Drupal::service('plugin.cache_clearer')->clearCachedDefinitions();
+}
+
+/**
+ * Replace Media Entity with Media.
+ */
+function media_entity_update_8201() {
+ $config_factory = \Drupal::configFactory();
+
+ \Drupal::state()->set('media_entity_core_upgrade_started', TRUE);
+
+ // When Media is installed, it assumes that it needs to create media bundles
+ // and fields. Because this is an upgrade from Media Entity, that's not the
+ // case. Track existing media types and fields, so that later when we delete
+ // the auto-created ones, we don't throw the baby out with the bathwater.
+ $preexisting_media_config = [];
+ $prefixes = [
+ 'media.type.',
+ 'field.field.media.',
+ 'field.storage.media.',
+ 'core.entity_form_display.media.',
+ 'core.entity_view_display.media.',
+ ];
+ foreach ($prefixes as $prefix) {
+ foreach ($config_factory->listAll($prefix) as $name) {
+ $preexisting_media_config[] = $name;
+ }
+ }
+
+ $snapshots = _media_entity_snapshot_config([
+ 'core.entity_form_display.media.file.default',
+ 'core.entity_form_display.media.image.default',
+ 'core.entity_view_display.media.file.default',
+ 'core.entity_view_display.media.image.default',
+ ], TRUE);
+
+ $install = ['media'];
+ // Install media_entity_generic if available. It stands to reason that this
+ // module will only be available if you have at least one media type that uses
+ // the generic plugin, since it has been split out into its own module and is
+ // only requested if there are media bundles that use it.
+ // See media_entity_requirements().
+ $module_data = system_rebuild_module_data();
+ if (isset($module_data['media_entity_generic'])) {
+ $install[] = 'media_entity_generic';
+ }
+ // Install media_entity_actions, if not enabled yet. Actions were not included
+ // in Media core, so we need this module to fill that gap until generic entity
+ // actions are part of core, likely in 8.5.x.
+ if (isset($module_data['media_entity_actions'])) {
+ $install[] = 'media_entity_actions';
+ }
+
+ // EXIF image handling was dropped from the patch that moved ME + MEI into
+ // core. Enable "Media Entity Image EXIF" if needed, which fills in that gap.
+ $bundles_with_exif = _media_entity_get_bundles_using_exif();
+ if (!empty($bundles_with_exif) && isset($module_data['media_entity_image_exif'])) {
+ $install[] = 'media_entity_image_exif';
+ }
+
+ \Drupal::service('module_installer')->install($install);
+
+ foreach ($snapshots as $name => $data) {
+ $config_factory->getEditable($name)->setData($data)->save(TRUE);
+ }
+ unset($snapshots);
+
+ // Fix the schema.
+ /** @var \Drupal\Core\Field\FieldStorageDefinitionInterface[] $field_definitions */
+ $field_definitions = \Drupal::service('entity_field.manager')->getFieldStorageDefinitions('media');
+ $db = Database::getConnection()->schema();
+ $db->changeField('media_revision', 'revision_uid', 'revision_user', $field_definitions['revision_user']->getColumns()[$field_definitions['revision_user']->getMainPropertyName()]);
+ $db->changeField('media_revision', 'revision_timestamp', 'revision_created', $field_definitions['revision_created']->getColumns()[$field_definitions['revision_created']->getMainPropertyName()]);
+ $db->changeField('media_revision', 'revision_log', 'revision_log_message', $field_definitions['revision_log_message']->getColumns()[$field_definitions['revision_log_message']->getMainPropertyName()]);
+
+ // Delete file/image media types automatically created by core media and
+ // associated fields.
+ $entity_definition_update_manager = \Drupal::entityDefinitionUpdateManager();
+ foreach ($prefixes as $prefix) {
+ foreach ($config_factory->listAll($prefix) as $name) {
+ if (!in_array($name, $preexisting_media_config)) {
+ $config_factory->getEditable($name)->delete();
+ if ($prefix === 'field.storage.media.') {
+ $field_name = substr($name, 20);
+ $storage_definition = $entity_definition_update_manager->getFieldStorageDefinition($field_name, 'media');
+ $entity_definition_update_manager->uninstallFieldStorageDefinition($storage_definition);
+ }
+ }
+ }
+ }
+
+ // Move all module dependencies on existing config entities from
+ // "media_entity" to "media".
+ _media_entity_fix_dependencies('module', 'media_entity', function ($module) {
+ return $module === 'media_entity' ? 'media' : $module;
+ });
+ // Move all module dependencies on existing config entities from
+ // "media_entity_document" to "media".
+ _media_entity_fix_dependencies('module', 'media_entity_document', function ($module) {
+ return $module === 'media_entity_document' ? 'media' : $module;
+ });
+ // Move all module dependencies on existing config entities from
+ // "media_entity_image" to "media".
+ _media_entity_fix_dependencies('module', 'media_entity_image', function ($module) {
+ return $module === 'media_entity_image' ? 'media' : $module;
+ });
+
+ // Move media_entity.settings to media.settings. Note that we don't read and
+ // save in bulk because the key "icon_base" moved to "icon_base_uri".
+ $config_factory->getEditable('media.settings')
+ ->set('icon_base_uri', $config_factory->get('media_entity.settings')->get('icon_base'))
+ ->save();
+ $config_factory->getEditable('media_entity.settings')->delete();
+
+ // Move all bundle configs to the new plugin namespace. This means moving all
+ // "media_entity.bundle.*" to "media.type.*".
+ foreach ($config_factory->listAll('media_entity.bundle.') as $original_name) {
+ $search = '/^media_entity\.bundle\./';
+ $replace = 'media.type.';
+
+ $new_name = preg_replace($search, $replace, $original_name);
+ $config_factory->rename($original_name, $new_name);
+
+ $config = $config_factory->getEditable($new_name);
+ $source_id = $config->get('type');
+ $config
+ ->set('source_configuration', $config->get('type_configuration'))
+ ->clear('type_configuration')
+ ->set('source', $source_id == 'document' ? 'file' : $source_id)
+ ->clear('type')
+ ->save();
+
+ _media_entity_fix_dependencies('config', $original_name, function ($bundle_id) use ($search, $replace) {
+ return preg_replace($search, $replace, $bundle_id);
+ });
+
+ /** @var \Drupal\media\MediaTypeInterface $media_type */
+ $media_type = \Drupal::entityTypeManager()->getStorage('media_type')
+ ->load($config->get('id'));
+ $media_source = $media_type->getSource();
+ $source_field = $media_source->getSourceFieldDefinition($media_type);
+ if (!$source_field) {
+ $source_field = $media_source->createSourceField($media_type);
+ $source_field->getFieldStorageDefinition()->save();
+ $source_field->save();
+
+ $media_type
+ ->set('source_configuration', [
+ 'source_field' => $source_field->getName(),
+ ]);
+ }
+ $media_type->save();
+ }
+ // Clear the old UUID map.
+ \Drupal::keyValue(QueryFactory::CONFIG_LOOKUP_PREFIX . 'media_bundle')->deleteAll();
+
+ // Update any views that use the entity:media_bundle argument validator.
+ _media_entity_update_views();
+
+ /** @var \Drupal\user\Entity\Role $role */
+ foreach (Role::loadMultiple() as $role) {
+ if ($role->hasPermission('administer media bundles')) {
+ $role
+ ->revokePermission('administer media bundles')
+ ->grantPermission('administer media types')
+ ->save();
+ }
+ }
+
+ // Disable media_entity_image, media_entity_document, and media_entity. They
+ // are all superseded by core Media.
+ if (isset($module_data['media_entity_image'])) {
+ \Drupal::service('module_installer')->uninstall(['media_entity_image']);
+ }
+ if (isset($module_data['media_entity_document'])) {
+ \Drupal::service('module_installer')->uninstall(['media_entity_document']);
+ }
+ \Drupal::service('module_installer')->uninstall(['media_entity']);
+}
+
+/**
+ * Updates any views that use the entity:media_bundle argument validator.
+ */
+function _media_entity_update_views() {
+ $config_factory = \Drupal::configFactory();
+
+ foreach ($config_factory->listAll('views.view') as $name) {
+ $view = $config_factory->getEditable($name);
+ $changed = FALSE;
+
+ foreach ($view->get('display') as $display_id => $display) {
+ $key = "display.$display_id.display_options.arguments";
+
+ // If there are no arguments, get() will return NULL, which is [] when
+ // cast to an array.
+ $arguments = (array) $view->get($key);
+
+ foreach ($arguments as $id => $argument) {
+ if ($argument['validate']['type'] == 'entity:media_bundle') {
+ $view->set("$key.$id.validate.type", 'entity:media_type');
+ $changed = TRUE;
+ }
+ }
+ }
+ if ($changed) {
+ $view->save();
+ }
+ }
+}
+
+/**
+ * Collects snapshots of config objects.
+ *
+ * @param string[] $names
+ * The names of the config objects to snapshot.
+ * @param bool $delete
+ * (optional) Whether to delete the original config objects. Defaults to
+ * FALSE.
+ *
+ * @return array
+ * The config data, keyed by object name.
+ */
+function _media_entity_snapshot_config(array $names, $delete = FALSE) {
+ $snapshots = [];
+ foreach ($names as $name) {
+ $config = \Drupal::configFactory()->getEditable($name);
+
+ if (!$config->isNew()) {
+ $snapshots[$name] = $config->get();
+
+ if ($delete) {
+ $config->delete();
+ }
+ }
+ }
+ return $snapshots;
+}
+
+/**
+ * Implements hook_update_dependencies().
+ */
+function media_entity_update_dependencies() {
+ $dependencies = [];
+
+ // Ensure that system_update_8402() is aware of the media entity type, which
+ // is declared dynamically in hook_entity_type_build(). We need to clear the
+ // module handler's hook implementation cache so as to guarantee that it is
+ // aware of media_entity_entity_type_build().
+ $dependencies['system'][8402]['media_entity'] = 8200;
+
+ // Ensure that system_update_8501() before the media update, so that the
+ // new revision_default field is installed in the correct table.
+ $dependencies['media_entity'][8201]['system'] = 8501;
+
+ return $dependencies;
+}
+++ /dev/null
-media_bundle_form:
- version: VERSION
- js:
- 'js/media_bundle_form.js': {}
- dependencies:
- - core/jquery
- - core/drupal
- - core/drupal.form
+++ /dev/null
-media.bundle_add:
- route_name: entity.media_bundle.add_form
- title: 'Add media bundle'
- appears_on:
- - entity.media_bundle.collection
-
-media.add:
- route_name: entity.media.add_page
- title: 'Add media'
- weight: 10
- appears_on:
- - view.media.media_page_list
+++ /dev/null
-entity.media.edit_form:
- route_name: entity.media.edit_form
- group: media
- title: Edit
-entity.media.delete_form:
- route_name: entity.media.delete_form
- group: media
- title: Delete
- weight: 10
+++ /dev/null
-entity.media_bundle.collection:
- title: 'Media bundles'
- parent: system.admin_structure
- description: 'Manage media bundles.'
- route_name: entity.media_bundle.collection
-
-entity.media.collection:
- title: 'Media'
- parent: system.admin_content
- description: 'Find and manage media.'
- route_name: view.media.media_page_list
-
-entity.media.add:
- title: 'Add a new media'
- parent: entity.media.collection
- description: 'Add a new media entity.'
- route_name: entity.media.add_page
+++ /dev/null
-entity.media.canonical:
- route_name: entity.media.canonical
- base_route: entity.media.canonical
- title: 'View'
-entity.media.edit_form:
- route_name: entity.media.edit_form
- base_route: entity.media.canonical
- title: Edit
-entity.media.delete_form:
- route_name: entity.media.delete_form
- base_route: entity.media.canonical
- title: Delete
- weight: 10
-entity.media_bundle.edit_form:
- title: 'Edit'
- route_name: entity.media_bundle.edit_form
- base_route: entity.media_bundle.edit_form
-entity.media_bundle.collection:
- title: List
- route_name: entity.media_bundle.collection
- base_route: entity.media_bundle.collection
* Provides media entities.
*/
-use Drupal\Core\Routing\RouteMatchInterface;
+// This empty file needs to be here so that drush commands that automatically
+// include .module files on enabled modules don't complain.
-/**
- * Implements hook_help().
- */
-function media_entity_help($route_name, RouteMatchInterface $route_match) {
- switch ($route_name) {
- case 'help.page.media_entity':
- $output = '<h3>' . t('About') . '</h3>';
- $output .= '<p>' . t('The <a href=":media_entity_url">Media Entity</a> module provides a "base" entity for media. This is a very basic entity which can reference to all kinds of media-objects (local files, YouTube videos, Tweets, Instagram photos, ...). Media entity provides a relation between your website and the media resource. You can reference to/use this entity within any other entity on your site. For more information, see the <a href=":media_entity_handbook">online documentation for the Media Entity module</a>.',
- [
- ':media_entity_url' => 'https://www.drupal.org/project/media_entity',
- ':media_entity_handbook' => 'https://drupal-media.gitbooks.io/drupal8-guide/content/modules/media_entity/intro.html',
- ]) . '</p>';
- $output .= '<h3>' . t('Uses') . '</h3>';
- $output .= '<p>' . t('For detailed information about the usage of this module please refer to <a href=":media_entity_handbook">the official documentation</a>.',
- [
- ':media_entity_handbook' => 'https://drupal-media.gitbooks.io/drupal8-guide/content/modules/media_entity/intro.html',
- ]) . '</p>';
-
- return $output;
- }
-}
-
-/**
- * Implements hook_theme().
- */
-function media_entity_theme() {
- return [
- 'media' => [
- 'render element' => 'elements',
- 'file' => 'media_entity.theme.inc',
- 'template' => 'media',
- ],
- ];
-}
+use Drupal\Core\Config\Entity\ConfigEntityType;
+use Drupal\Core\Entity\ContentEntityType;
+use Drupal\media_entity\Media;
+use Drupal\media_entity\MediaBundle;
/**
- * Implements hook_theme_suggestions_HOOK().
+ * Implements hook_entity_type_build().
*/
-function media_entity_theme_suggestions_media(array $variables) {
- $suggestions = [];
- $media = $variables['elements']['#media'];
- $sanitized_view_mode = strtr($variables['elements']['#view_mode'], '.', '_');
-
- $suggestions[] = 'media__' . $sanitized_view_mode;
- $suggestions[] = 'media__' . $media->bundle();
- $suggestions[] = 'media__' . $media->bundle() . '__' . $sanitized_view_mode;
- $suggestions[] = 'media__' . $media->id();
- $suggestions[] = 'media__' . $media->id() . '__' . $sanitized_view_mode;
-
- return $suggestions;
-}
-
-/**
- * Copy the media file icons to files directory for use with image styles.
- *
- * @param string $source
- * Source folder.
- * @param string $destination
- * Destination folder.
- *
- * @throws Exception
- */
-function media_entity_copy_icons($source, $destination) {
- if (!file_prepare_directory($destination, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS)) {
- throw new Exception("Unable to create directory $destination.");
- }
-
- $files = file_scan_directory($source, '/.*\.(png|jpg)$/');
- foreach ($files as $file) {
- $result = file_unmanaged_copy($file->uri, $destination, FILE_EXISTS_REPLACE);
- if (!$result) {
- throw new Exception("Unable to copy {$file->uri} to $destination.");
- }
+function media_entity_entity_type_build(array &$entity_types) {
+ if (!\Drupal::moduleHandler()->moduleExists('media')) {
+ $entity_types['media'] = new ContentEntityType([
+ 'id' => 'media',
+ 'provider' => 'media_entity',
+ 'class' => Media::class,
+ 'base_table' => 'media',
+ 'data_table' => 'media_field_data',
+ 'revision_table' => 'media_revision',
+ 'revision_data_table' => 'media_field_revision',
+ 'translatable' => TRUE,
+ 'entity_keys' => [
+ 'id' => 'mid',
+ 'revision' => 'vid',
+ 'bundle' => 'bundle',
+ 'label' => 'name',
+ 'langcode' => 'langcode',
+ 'uuid' => 'uuid',
+ 'published' => 'status',
+ ],
+ 'revision_metadata_keys' => [
+ 'revision_user' => 'revision_user',
+ 'revision_created' => 'revision_created',
+ 'revision_log_message' => 'revision_log_message',
+ ],
+ 'bundle_entity_type' => 'media_bundle',
+ ]);
+ $entity_types['media_bundle'] = new ConfigEntityType([
+ 'id' => 'media_bundle',
+ 'provider' => 'media_entity',
+ 'class' => MediaBundle::class,
+ 'bundle_of' => 'media',
+ 'entity_keys' => [
+ 'id' => 'id',
+ 'label' => 'label',
+ ],
+ ]);
}
}
+++ /dev/null
-administer media:
- title: 'Administer media'
- restrict access: TRUE
-administer media bundles:
- title: 'Administer media bundles'
- restrict access: TRUE
-access media overview:
- title: 'Access the Media overview page'
- description: 'Get an overview of all media items.'
-view media:
- title: 'View media'
-update media:
- title: 'Update media'
-update any media:
- title: 'Update any media'
-delete media:
- title: 'Delete media'
-delete any media:
- title: 'Delete any media'
-create media:
- title: 'Create media'
+++ /dev/null
-media_type:
- label: 'Media type'
- plugin_manager_service_id: plugin.manager.media_entity.type
- plugin_definition_decorator_class: \Drupal\plugin\PluginDefinition\ArrayPluginDefinitionDecorator
- plugin_configuration_schema_id: media_entity.bundle.type.[plugin_id]
+++ /dev/null
-entity.media.multiple_delete_confirm:
- path: '/admin/content/media/delete'
- defaults:
- _form: '\Drupal\media_entity\Form\DeleteMultiple'
- requirements:
- _permission: 'delete any media'
-
-entity.media_bundle.collection:
- path: '/admin/structure/media'
- defaults:
- _entity_list: 'media_bundle'
- _title: 'Media bundles'
- requirements:
- _permission: 'administer media bundles'
plugin.manager.media_entity.type:
class: Drupal\media_entity\MediaTypeManager
parent: default_plugin_manager
+ media_entity.cli:
+ class: Drupal\media_entity\CliService
+ arguments: ['@module_handler']
+++ /dev/null
-<?php
-
-/**
- * @file
- * Theme functions for the media_entity module.
- */
-
-use Drupal\Core\Render\Element;
-use Drupal\Core\Link;
-use Drupal\Component\Utility\Html;
-
-/**
- * Prepares variables for list of available media bundles.
- *
- * Default template: media-add-list.html.twig.
- *
- * @param array $variables
- * An associative array containing:
- * - content: An array of content types.
- */
-function template_preprocess_media_add_list(&$variables) {
- $variables['bundles'] = [];
- if (!empty($variables['content'])) {
- foreach ($variables['content'] as $bundle) {
- /** @var \Drupal\media_entity\MediaBundleInterface $bundle */
- $variables['bundles'][$bundle->id()] = [
- 'type' => $bundle->id(),
- 'add_link' => Link::createFromRoute($bundle->label(), 'media.add', ['media_bundle' => $bundle->id()]),
- 'description' => [
- '#markup' => $bundle->getDescription(),
- ],
- ];
- }
- }
-}
-
-/**
- * Prepares variables for media templates.
- *
- * Default template: media.html.twig.
- *
- * @param array $variables
- * An associative array containing:
- * - media: An individual media for display.
- */
-function template_preprocess_media(&$variables) {
- /** @var \Drupal\media_entity\MediaInterface $media */
- $media = $variables['elements']['#media'];
-
- $variables['name'] = $media->label();
-
- // Helpful $content variable for templates.
- foreach (Element::children($variables['elements']) as $key) {
- $variables['content'][$key] = $variables['elements'][$key];
- }
-
- $variables['attributes']['class'][] = 'media';
- $variables['attributes']['class'][] = Html::getClass('media-' . $media->bundle());
- if (!$media->isPublished()) {
- $variables['attributes']['class'][] = 'unpublished';
- }
- if ($variables['elements']['#view_mode']) {
- $variables['attributes']['class'][] = Html::getClass('view-mode-' . $variables['elements']['#view_mode']);
- }
-}
+++ /dev/null
-<?php
-
-/**
- * @file
- * Builds placeholder replacement tokens for media_entity-related data.
- */
-
-use Drupal\Component\Utility\Html;
-use Drupal\Core\Datetime\Entity\DateFormat;
-use Drupal\Core\Language\LanguageInterface;
-use Drupal\Core\Render\BubbleableMetadata;
-use Drupal\media_entity\Entity\MediaBundle;
-
-/**
- * Implements hook_token_info().
- */
-function media_entity_token_info() {
- $type = [
- 'name' => t('Media'),
- 'description' => t('Tokens related to individual media items.'),
- 'needs-data' => 'media',
- ];
-
- // Core tokens for media.
- $media['mid'] = [
- 'name' => t("Media ID"),
- 'description' => t('The unique ID of the media item.'),
- ];
- $media['uuid'] = [
- 'name' => t("Media UUID"),
- 'description' => t('The unique UUID of the media item.'),
- ];
- $media['vid'] = [
- 'name' => t("Revision ID"),
- 'description' => t("The unique ID of the media's latest revision."),
- ];
- $media['bundle'] = [
- 'name' => t("Media bundle"),
- ];
- $media['bundle-name'] = [
- 'name' => t("Media bundle name"),
- 'description' => t("The human-readable name of the media bundle."),
- ];
- $media['langcode'] = [
- 'name' => t('Language code'),
- 'description' => t('The language code of the language the media is written in.'),
- ];
- $media['name'] = [
- 'name' => t('Name'),
- 'description' => t('The name of this media.'),
- ];
- $media['type'] = [
- 'name' => t("Type"),
- 'description' => t("The type of this media."),
- ];
- $node['author'] = [
- 'name' => t("Author"),
- 'type' => 'user',
- ];
- $media['url'] = [
- 'name' => t("URL"),
- 'description' => t("The URL of the media."),
- ];
- $media['edit-url'] = [
- 'name' => t("Edit URL"),
- 'description' => t("The URL of the media's edit page."),
- ];
-
- // Chained tokens for media.
- $media['created'] = [
- 'name' => t("Date created"),
- 'type' => 'date',
- ];
- $media['changed'] = [
- 'name' => t("Date changed"),
- 'description' => t("The date the media was most recently updated."),
- 'type' => 'date',
- ];
-
- return [
- 'types' => ['media' => $type],
- 'tokens' => ['media' => $media],
- ];
-}
-
-/**
- * Implements hook_tokens().
- */
-function media_entity_tokens($type, $tokens, array $data, array $options, BubbleableMetadata $bubbleable_metadata) {
- $token_service = \Drupal::token();
-
- $url_options = ['absolute' => TRUE];
- if (isset($options['langcode'])) {
- $url_options['language'] = \Drupal::languageManager()->getLanguage($options['langcode']);
- $langcode = $options['langcode'];
- }
- else {
- $langcode = LanguageInterface::LANGCODE_DEFAULT;
- }
- $sanitize = !empty($options['sanitize']);
-
- $replacements = [];
-
- if ($type == 'media' && !empty($data['media'])) {
- /** @var \Drupal\media_entity\MediaInterface $media */
- $media = \Drupal::service('entity.repository')->getTranslationFromContext($data['media'], $langcode, ['operation' => 'media_entity_tokens']);
-
- foreach ($tokens as $name => $original) {
- switch ($name) {
- // Simple key values on the media_entity.
- case 'mid':
- $replacements[$original] = $media->id();
- break;
-
- case 'uuid':
- $replacements[$original] = $media->uuid();
- break;
-
- case 'vid':
- $replacements[$original] = $media->getRevisionId();
- break;
-
- case 'bundle':
- $replacements[$original] = $sanitize ? Html::escape($media->bundle()) : $media->bundle();
- break;
-
- case 'bundle-name':
- $bundle_name = MediaBundle::load($media->bundle())->label();
- $replacements[$original] = $sanitize ? Html::escape($bundle_name) : $bundle_name;
- break;
-
- case 'langcode':
- $replacements[$original] = $sanitize ? Html::escape($media->language()->getId()) : $media->language()->getId();
- break;
-
- case 'name':
- $media_name = $media->get('name')->value;
- $replacements[$original] = $sanitize ? Html::escape($media_name) : $media_name;
- break;
-
- case 'type':
- $media_type = $media->get('name')->value;
- $replacements[$original] = $sanitize ? Html::escape($media_type) : $media_type;
- break;
-
- case 'url':
- $replacements[$original] = $media->toUrl('canonical', $url_options);
- break;
-
- case 'edit-url':
- $replacements[$original] = $media->toUrl('edit-form', $url_options);
- break;
-
- // Default values for the chained tokens handled below.
- case 'author':
- /** @var \Drupal\user\UserInterface $account */
- $account = $media->get('uid')->entity;
- $bubbleable_metadata->addCacheableDependency($account);
- $replacements[$original] = $sanitize ? Html::escape($account->label()) : $account->label();
- break;
-
- case 'created':
- $date_format = DateFormat::load('medium');
- $bubbleable_metadata->addCacheableDependency($date_format);
- $replacements[$original] = \Drupal::service('date.formatter')
- ->format($media->getCreatedTime(), 'medium', '', NULL, $langcode);
- break;
-
- case 'changed':
- $date_format = DateFormat::load('medium');
- $bubbleable_metadata->addCacheableDependency($date_format);
- $replacements[$original] = \Drupal::service('date.formatter')
- ->format($media->getChangedTime(), 'medium', '', NULL, $langcode);
- break;
- }
- }
-
- if ($author_tokens = $token_service->findWithPrefix($tokens, 'author')) {
- $account = $media->get('uid')->entity;
- $replacements += $token_service->generate('user', $author_tokens, ['user' => $account], $options, $bubbleable_metadata);
- }
-
- if ($created_tokens = $token_service->findWithPrefix($tokens, 'created')) {
- $replacements += $token_service->generate('date', $created_tokens, ['date' => $media->getCreatedTime()], $options, $bubbleable_metadata);
- }
-
- if ($changed_tokens = $token_service->findWithPrefix($tokens, 'changed')) {
- $replacements += $token_service->generate('date', $changed_tokens, ['date' => $media->getChangedTime()], $options, $bubbleable_metadata);
- }
- }
-
- return $replacements;
-}
--- /dev/null
+<?php
+
+namespace Drupal\media_entity;
+
+use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
+
+/**
+ * Class CliService.
+ *
+ * @internal
+ */
+class CliService {
+
+ use StringTranslationTrait;
+
+ /**
+ * The module handler.
+ *
+ * @var \Drupal\Core\Extension\ModuleHandlerInterface
+ */
+ protected $moduleHandler;
+
+ /**
+ * CliService constructor.
+ *
+ * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
+ * The module handler.
+ */
+ public function __construct(ModuleHandlerInterface $module_handler) {
+ $this->moduleHandler = $module_handler;
+ }
+
+ /**
+ * Verify if the upgrade to Media in core is possible.
+ *
+ * @return array
+ * An associative array with two keys:
+ * - errors: An array of error messages, one per requirement that failed.
+ * An empty array here means that the site can proceed with the upgrade
+ * path.
+ * - passes: An array of success messages, one per requirement verified.
+ */
+ public function validateDbUpdateRequirements() {
+ $checks = [
+ 'errors' => [],
+ 'passes' => [],
+ ];
+
+ module_load_install('media_entity');
+
+ // This update only makes sense with core >= 8.4.x.
+ $version = explode('.', \Drupal::VERSION);
+ if ($version[1] < 4) {
+ $checks['errors'][] = $this->t('The Media Entity 2.x upgrade path only works with Drupal core >= 8.4.x');
+ }
+ else {
+ $checks['passes'][] = $this->t('Drupal core is the correct version (>= 8.4.0). [@version detected]', ['@version' => \Drupal::VERSION]);
+ }
+
+ // This update can't proceed if there already is an enabled module called
+ // "media".
+ if ($this->moduleHandler->moduleExists('media')) {
+ $checks['errors'][] = $this->t('In order to run the Media Entity 2.x upgrade, please uninstall and remove from the codebase the contributed "Media" module.');
+ }
+ else {
+ $checks['passes'][] = $this->t('The contributed "Media" module is not installed.');
+ }
+
+ // Prevent the updates from running if there is a type-provider that is
+ // still on the 1.x branch.
+ $incompatible_modules = _media_entity_get_incompatible_modules();
+ if (!empty($incompatible_modules)) {
+ $provider_modules = !empty($incompatible_modules['providers']) ? implode(", ", $incompatible_modules['providers']) : '';
+ $additional_msg_providers = !empty($provider_modules) ? ' ' . $this->t('The following modules provide source plugins and need to be upgraded: @provider_modules.', [
+ '@provider_modules' => $provider_modules,
+ ]) : '';
+ $dependent_modules = !empty($incompatible_modules['modules']) ? implode(", ", $incompatible_modules['modules']) : '';
+ $additional_msg_dependent = !empty($dependent_modules) ? ' ' . $this->t('The following modules depend on media entity and need to be either upgraded or uninstalled: @dependent_modules.', [
+ '@dependent_modules' => $dependent_modules,
+ ]) : '';
+ $checks['errors'][] = $this->t('Before continuing, please make sure all modules that provide plugins for Media Entity (or depend on it) have their code updated to their respective 2.x branches. Note that you will probably need to revert to the 1.x branch of the Media Entity module if you want to uninstall existing plugin modules.') . $additional_msg_providers . $additional_msg_dependent;
+ }
+ else {
+ $checks['passes'][] = $this->t('All provider plugins and modules depending on media_entity are up-to-date.');
+ }
+
+ $module_data = system_rebuild_module_data();
+
+ // Generic media types should now live in the contrib Media Entity Generic
+ // module, which should be available at the codebase.
+ $generic_types = _media_entity_get_bundles_by_plugin('generic');
+ if ($generic_types) {
+ if (!isset($module_data['media_entity_generic'])) {
+ $checks['errors'][] = $this->t('One or more of your existing media types are using the Generic source, which has been moved into a separate "Media Entity Generic" module. You need to download this module to your codebase before continuing.');
+ }
+ else {
+ $checks['passes'][] = $this->t('The "Media Entity Generic" module is available.');
+ }
+ }
+
+ // Actions now live in the contributed media_entity_actions, until generic
+ // entity actions are part of Drupal core (2916740).
+ if (!isset($module_data['media_entity_actions']) && !file_exists(\Drupal::root() . '/core/modules/media/src/Plugin/Action/PublishMedia.php')) {
+ $checks['errors'][] = $this->t('Media Actions (for example, for bulk operations) have been moved into a separate "Media Entity Actions" module. You need to download this module to your codebase before continuing.');
+ }
+ else {
+ $checks['passes'][] = $this->t('The "Media Entity Actions" module is available.');
+ }
+
+ // EXIF image handling was dropped from the patch that moved ME + MEI into
+ // core. If a site was using it, we need to ensure the contrib module
+ // media_entity_image_exif is present, to fill in that gap.
+ if (!empty(_media_entity_get_bundles_using_exif()) && !isset($module_data['media_entity_image_exif'])) {
+ $checks['errors'][] = $this->t('Your site uses EXIF mapping on image types, and these were not initially incorporated in Media in core. In order not to lose that functionality, you need to download the module "Media Entity Image EXIF" into your codebase before continuing.');
+ }
+ else {
+ $checks['passes'][] = $this->t('Site uses EXIF handling and the "Media Entity Image EXIF" module is available.');
+ }
+
+ return $checks;
+ }
+
+}
--- /dev/null
+<?php
+
+namespace Drupal\media_entity\Commands;
+
+use Drush\Commands\DrushCommands as DrushCommandsBase;
+use Drupal\media_entity\CliService;
+
+/**
+ * Add commands for Drush 9.
+ */
+class DrushCommands extends DrushCommandsBase {
+
+ /**
+ * The cli service.
+ *
+ * @var \Drupal\media_entity\CliService
+ */
+ protected $cliService;
+
+ /**
+ * MediaEntityCommands constructor.
+ *
+ * @param \Drupal\media_entity\CliService $cli_service
+ * The CLI service which allows interoperability.
+ */
+ public function __construct(CliService $cli_service) {
+ $this->cliService = $cli_service;
+ }
+
+ /**
+ * Check upgrade requirements for Media Entity into Media in core.
+ *
+ * @command media_entity:check-upgrade
+ * @usage drush mecu
+ * Checks upgrade requirements for Media Entity while upgrading to Media in
+ * core.
+ * @aliases mecu,media-entity-check-upgrade
+ */
+ public function mediaEntityCheckUpgrade() {
+ drush_bootstrap_to_phase(DRUSH_BOOTSTRAP_DRUPAL_FULL);
+ $logger = $this->logger();
+ // This command is useless if the DB updates have already been run.
+ if (drupal_get_installed_schema_version('media_entity') >= 8201) {
+ $logger(dt('Your site has already run the media_entity DB updates. If you believe this is not correct, you should consider rolling back your database to a previous backup and try again.'));
+ return;
+ }
+
+ $checks = $this->cliService->validateDbUpdateRequirements();
+
+ if (empty($checks['errors'])) {
+ $logger->success(sprintf("\033[1;32;40m\033[1m%s\033[0m", '✓') . ' ' . dt('All upgrade requirements are met and you can proceed with the DB updates.'));
+ }
+ else {
+ $logger->error(sprintf("\033[31;40m\033[1m%s\033[0m", '✗') . ' ' . dt('Your site did not pass all upgrade checks. You can find more information in the error messages below.'));
+ }
+ foreach ($checks['passes'] as $pass_msg) {
+ $logger->success($pass_msg);
+ }
+ foreach ($checks['errors'] as $error_msg) {
+ $logger->error($error_msg);
+ }
+ }
+
+}
+++ /dev/null
-<?php
-
-namespace Drupal\media_entity;
-
-use Drupal\Core\Field\FieldItemInterface;
-
-/**
- * A trait to assist with handling external embed codes.
- */
-trait EmbedCodeValueTrait {
-
- /**
- * Extracts the raw embed code from input which may or may not be wrapped.
- *
- * @param mixed $value
- * The input value. Can be a normal string or a value wrapped by the
- * Typed Data API.
- *
- * @return string|null
- * The raw embed code.
- */
- protected function getEmbedCode($value) {
- if (is_string($value)) {
- return $value;
- }
- elseif ($value instanceof FieldItemInterface) {
- $class = get_class($value);
- $property = $class::mainPropertyName();
- if ($property) {
- return $value->$property;
- }
- }
- }
-
-}
+++ /dev/null
-<?php
-
-namespace Drupal\media_entity\Entity;
-
-use Drupal\Core\Entity\ContentEntityBase;
-use Drupal\Core\Entity\EntityStorageInterface;
-use Drupal\Core\Entity\EntityTypeInterface;
-use Drupal\Core\Field\BaseFieldDefinition;
-use Drupal\media_entity\MediaInterface;
-use Drupal\Core\Entity\EntityChangedTrait;
-use Drupal\user\UserInterface;
-
-/**
- * Defines the media entity class.
- *
- * @ContentEntityType(
- * id = "media",
- * label = @Translation("Media"),
- * bundle_label = @Translation("Media bundle"),
- * handlers = {
- * "storage" = "Drupal\media_entity\MediaStorage",
- * "view_builder" = "Drupal\Core\Entity\EntityViewBuilder",
- * "list_builder" = "Drupal\Core\Entity\EntityListBuilder",
- * "access" = "Drupal\media_entity\MediaAccessController",
- * "form" = {
- * "default" = "Drupal\media_entity\MediaForm",
- * "delete" = "Drupal\media_entity\Form\MediaDeleteForm",
- * "edit" = "Drupal\media_entity\MediaForm"
- * },
- * "inline_form" = "Drupal\media_entity\Form\MediaInlineForm",
- * "translation" = "Drupal\content_translation\ContentTranslationHandler",
- * "views_data" = "Drupal\media_entity\MediaViewsData",
- * "route_provider" = {
- * "html" = "Drupal\Core\Entity\Routing\AdminHtmlRouteProvider",
- * }
- * },
- * base_table = "media",
- * data_table = "media_field_data",
- * revision_table = "media_revision",
- * revision_data_table = "media_field_revision",
- * translatable = TRUE,
- * render_cache = TRUE,
- * entity_keys = {
- * "id" = "mid",
- * "revision" = "vid",
- * "bundle" = "bundle",
- * "label" = "name",
- * "langcode" = "langcode",
- * "uuid" = "uuid"
- * },
- * bundle_entity_type = "media_bundle",
- * permission_granularity = "entity_type",
- * admin_permission = "administer media",
- * field_ui_base_route = "entity.media_bundle.edit_form",
- * links = {
- * "add-page" = "/media/add",
- * "add-form" = "/media/add/{media_bundle}",
- * "canonical" = "/media/{media}",
- * "delete-form" = "/media/{media}/delete",
- * "edit-form" = "/media/{media}/edit",
- * "admin-form" = "/admin/structure/media/manage/{media_bundle}"
- * }
- * )
- */
-class Media extends ContentEntityBase implements MediaInterface {
-
- use EntityChangedTrait;
-
- /**
- * Value that represents the media being published.
- */
- const PUBLISHED = 1;
-
- /**
- * Value that represents the media being unpublished.
- */
- const NOT_PUBLISHED = 0;
-
- /**
- * A queue based media operation to download thumbnails is being performed.
- *
- * @var boolean
- */
- protected $queued_thumbnail_download = FALSE;
-
- /**
- * {@inheritdoc}
- */
- public function getCreatedTime() {
- return $this->get('created')->value;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setCreatedTime($timestamp) {
- $this->set('created', $timestamp);
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getChangedTime() {
- return $this->get('changed')->value;
- }
-
- /**
- * {@inheritdoc}
- */
- public function isPublished() {
- return (bool) $this->get('status')->value;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setPublished($published) {
- $this->set('status', $published ? Media::PUBLISHED : Media::NOT_PUBLISHED);
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getPublisher() {
- return $this->get('uid')->entity;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setQueuedThumbnailDownload() {
- $this->queued_thumbnail_download = TRUE;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getPublisherId() {
- return $this->get('uid')->target_id;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setPublisherId($uid) {
- $this->set('uid', $uid);
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getType() {
- return $this->bundle->entity->getType();
- }
-
- /**
- * {@inheritdoc}
- */
- public function preSave(EntityStorageInterface $storage) {
- parent::preSave($storage);
-
- // If no revision author has been set explicitly, make the media owner the
- // revision author.
- if (!$this->get('revision_uid')->entity) {
- $this->set('revision_uid', $this->getPublisherId());
- }
-
- // Set thumbnail.
- if (!$this->get('thumbnail')->entity || !empty($this->queued_thumbnail_download)) {
- $this->automaticallySetThumbnail();
- }
-
- // Try to set fields provided by type plugin and mapped in bundle
- // configuration.
- foreach ($this->bundle->entity->field_map as $source_field => $destination_field) {
- // Only save value in entity field if empty. Do not overwrite existing
- // data.
- // @TODO We might modify that in the future but let's leave it like this
- // for now.
- if ($this->hasField($destination_field) && $this->{$destination_field}->isEmpty() && ($value = $this->getType()->getField($this, $source_field))) {
- $this->set($destination_field, $value);
- }
- }
-
- // Try to set a default name for this media, if there is no label provided.
- if (empty($this->label())) {
- $this->set('name', $this->getType()->getDefaultName($this));
- }
-
- }
-
- /**
- * {@inheritdoc}
- */
- public function postSave(EntityStorageInterface $storage, $update = TRUE) {
- parent::postSave($storage, $update);
- if (!$update && $this->bundle->entity->getQueueThumbnailDownloads()) {
- $queue = \Drupal::queue('media_entity_thumbnail');
- $queue->createItem(['id' => $this->id()]);
- }
- }
-
- /**
- * {@inheritdoc}
- */
- public function automaticallySetThumbnail() {
- /** @var \Drupal\media_entity\MediaBundleInterface $bundle */
- if ($this->bundle->entity->getQueueThumbnailDownloads() && $this->isNew()) {
- $thumbnail_uri = $this->getType()->getDefaultThumbnail();
- }
- else {
- $thumbnail_uri = $this->getType()->thumbnail($this);
- }
- $existing = \Drupal::entityQuery('file')
- ->condition('uri', $thumbnail_uri)
- ->execute();
-
- if ($existing) {
- $this->thumbnail->target_id = reset($existing);
- }
- else {
- /** @var \Drupal\file\FileInterface $file */
- $file = $this->entityTypeManager()->getStorage('file')->create(['uri' => $thumbnail_uri]);
- if ($publisher = $this->getPublisher()) {
- $file->setOwner($publisher);
- }
- $file->setPermanent();
- $file->save();
- $this->thumbnail->target_id = $file->id();
- }
-
- // TODO - We should probably use something smarter (tokens, ...).
- $this->thumbnail->alt = t('Thumbnail');
- $this->thumbnail->title = $this->label();
- }
-
- /**
- * {@inheritdoc}
- */
- public function preSaveRevision(EntityStorageInterface $storage, \stdClass $record) {
- parent::preSaveRevision($storage, $record);
-
- if (!$this->isNewRevision() && isset($this->original) && (!isset($record->revision_log) || $record->revision_log === '')) {
- // If we are updating an existing node without adding a new revision, we
- // need to make sure $entity->revision_log is reset whenever it is empty.
- // Therefore, this code allows us to avoid clobbering an existing log
- // entry with an empty one.
- $record->revision_log = $this->original->revision_log->value;
- }
- }
-
- /**
- * {@inheritdoc}
- */
- public function validate() {
- $this->getType()->attachConstraints($this);
- return parent::validate();
- }
-
- /**
- * {@inheritdoc}
- */
- public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
- $fields['mid'] = BaseFieldDefinition::create('integer')
- ->setLabel(t('Media ID'))
- ->setDescription(t('The media ID.'))
- ->setReadOnly(TRUE)
- ->setSetting('unsigned', TRUE);
-
- $fields['uuid'] = BaseFieldDefinition::create('uuid')
- ->setLabel(t('UUID'))
- ->setDescription(t('The media UUID.'))
- ->setReadOnly(TRUE);
-
- $fields['vid'] = BaseFieldDefinition::create('integer')
- ->setLabel(t('Revision ID'))
- ->setDescription(t('The media revision ID.'))
- ->setReadOnly(TRUE)
- ->setSetting('unsigned', TRUE);
-
- $fields['bundle'] = BaseFieldDefinition::create('entity_reference')
- ->setLabel(t('Bundle'))
- ->setDescription(t('The media bundle.'))
- ->setSetting('target_type', 'media_bundle')
- ->setReadOnly(TRUE);
-
- $fields['langcode'] = BaseFieldDefinition::create('language')
- ->setLabel(t('Language code'))
- ->setDescription(t('The media language code.'))
- ->setTranslatable(TRUE)
- ->setRevisionable(TRUE)
- ->setDisplayOptions('view', [
- 'type' => 'hidden',
- ])
- ->setDisplayOptions('form', [
- 'type' => 'language_select',
- 'weight' => 2,
- ]);
-
- $fields['name'] = BaseFieldDefinition::create('string')
- ->setLabel(t('Media name'))
- ->setDescription(t('The name of this media.'))
- ->setRequired(TRUE)
- ->setTranslatable(TRUE)
- ->setRevisionable(TRUE)
- ->setDefaultValue('')
- ->setSetting('max_length', 255)
- ->setDisplayOptions('form', [
- 'type' => 'string_textfield',
- 'weight' => -5,
- ])
- ->setDisplayConfigurable('form', TRUE)
- ->setDisplayOptions('view', [
- 'label' => 'hidden',
- 'type' => 'string',
- 'weight' => -5,
- ])
- ->setDisplayConfigurable('view', TRUE);
-
- $fields['thumbnail'] = BaseFieldDefinition::create('image')
- ->setLabel(t('Thumbnail'))
- ->setDescription(t('The thumbnail of the media.'))
- ->setRevisionable(TRUE)
- ->setDisplayOptions('view', [
- 'type' => 'image',
- 'weight' => 1,
- 'label' => 'hidden',
- 'settings' => [
- 'image_style' => 'thumbnail',
- ],
- ])
- ->setDisplayConfigurable('view', TRUE)
- ->setReadOnly(TRUE);
-
- $fields['uid'] = BaseFieldDefinition::create('entity_reference')
- ->setLabel(t('Publisher ID'))
- ->setDescription(t('The user ID of the media publisher.'))
- ->setRevisionable(TRUE)
- ->setDefaultValueCallback('Drupal\media_entity\Entity\Media::getCurrentUserId')
- ->setSetting('target_type', 'user')
- ->setTranslatable(TRUE)
- ->setDisplayOptions('view', [
- 'label' => 'hidden',
- 'type' => 'author',
- 'weight' => 0,
- ])
- ->setDisplayConfigurable('view', TRUE)
- ->setDisplayOptions('form', [
- 'type' => 'entity_reference_autocomplete',
- 'weight' => 5,
- 'settings' => [
- 'match_operator' => 'CONTAINS',
- 'size' => '60',
- 'autocomplete_type' => 'tags',
- 'placeholder' => '',
- ],
- ])
- ->setDisplayConfigurable('form', TRUE);
-
- $fields['status'] = BaseFieldDefinition::create('boolean')
- ->setLabel(t('Publishing status'))
- ->setDescription(t('A boolean indicating whether the media is published.'))
- ->setTranslatable(TRUE)
- ->setRevisionable(TRUE)
- ->setDefaultValue(TRUE);
-
- $fields['created'] = BaseFieldDefinition::create('created')
- ->setLabel(t('Created'))
- ->setDescription(t('The time that the media was created.'))
- ->setTranslatable(TRUE)
- ->setRevisionable(TRUE)
- ->setDisplayOptions('view', [
- 'label' => 'hidden',
- 'type' => 'timestamp',
- 'weight' => 0,
- ])
- ->setDisplayConfigurable('view', TRUE)
- ->setDisplayOptions('form', [
- 'type' => 'datetime_timestamp',
- 'weight' => 10,
- ])
- ->setDisplayConfigurable('form', TRUE);
-
- $fields['changed'] = BaseFieldDefinition::create('changed')
- ->setLabel(t('Changed'))
- ->setDescription(t('The time that the media was last edited.'))
- ->setTranslatable(TRUE)
- ->setRevisionable(TRUE);
-
- $fields['revision_timestamp'] = BaseFieldDefinition::create('created')
- ->setLabel(t('Revision timestamp'))
- ->setDescription(t('The time that the current revision was created.'))
- ->setQueryable(FALSE)
- ->setRevisionable(TRUE);
-
- $fields['revision_uid'] = BaseFieldDefinition::create('entity_reference')
- ->setLabel(t('Revision publisher ID'))
- ->setDescription(t('The user ID of the publisher of the current revision.'))
- ->setSetting('target_type', 'user')
- ->setQueryable(FALSE)
- ->setRevisionable(TRUE);
-
- $fields['revision_log'] = BaseFieldDefinition::create('string_long')
- ->setLabel(t('Revision Log'))
- ->setDescription(t('The log entry explaining the changes in this revision.'))
- ->setRevisionable(TRUE)
- ->setTranslatable(TRUE);
-
- return $fields;
- }
-
- /**
- * Default value callback for 'uid' base field definition.
- *
- * @see ::baseFieldDefinitions()
- *
- * @return array
- * An array of default values.
- */
- public static function getCurrentUserId() {
- return [\Drupal::currentUser()->id()];
- }
-
- /**
- * {@inheritdoc}
- */
- public function getRevisionCreationTime() {
- return $this->revision_timestamp->value;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setRevisionCreationTime($timestamp) {
- $this->revision_timestamp->value = $timestamp;
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getRevisionUser() {
- return $this->revision_uid->entity;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setRevisionUser(UserInterface $account) {
- $this->revision_uid->entity = $account;
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getRevisionUserId() {
- return $this->revision_uid->target_id;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setRevisionUserId($user_id) {
- $this->revision_uid->target_id = $user_id;
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getRevisionLogMessage() {
- return $this->revision_log->value;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setRevisionLogMessage($revision_log_message) {
- $this->revision_log->value = $revision_log_message;
- return $this;
- }
-
-}
+++ /dev/null
-<?php
-
-namespace Drupal\media_entity\Entity;
-
-use Drupal\Core\Entity\EntityDescriptionInterface;
-use Drupal\Core\Config\Entity\ConfigEntityBundleBase;
-use Drupal\Core\Entity\EntityWithPluginCollectionInterface;
-use Drupal\Core\Plugin\DefaultSingleLazyPluginCollection;
-use Drupal\media_entity\MediaBundleInterface;
-use Drupal\media_entity\MediaInterface;
-
-/**
- * Defines the Media bundle configuration entity.
- *
- * @ConfigEntityType(
- * id = "media_bundle",
- * label = @Translation("Media bundle"),
- * handlers = {
- * "form" = {
- * "add" = "Drupal\media_entity\MediaBundleForm",
- * "edit" = "Drupal\media_entity\MediaBundleForm",
- * "delete" = "Drupal\media_entity\Form\MediaBundleDeleteConfirm"
- * },
- * "list_builder" = "Drupal\media_entity\MediaBundleListBuilder",
- * "route_provider" = {
- * "html" = "Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider",
- * }
- * },
- * admin_permission = "administer media bundles",
- * config_prefix = "bundle",
- * bundle_of = "media",
- * entity_keys = {
- * "id" = "id",
- * "label" = "label"
- * },
- * config_export = {
- * "id",
- * "label",
- * "description",
- * "type",
- * "queue_thumbnail_downloads",
- * "new_revision",
- * "third_party_settings",
- * "type_configuration",
- * "field_map",
- * "status",
- * },
- * links = {
- * "add-form" = "/admin/structure/media/add",
- * "edit-form" = "/admin/structure/media/manage/{media_bundle}",
- * "delete-form" = "/admin/structure/media/manage/{media_bundle}/delete",
- * "collection" = "/admin/structure/media",
- * }
- * )
- */
-class MediaBundle extends ConfigEntityBundleBase implements MediaBundleInterface, EntityWithPluginCollectionInterface, EntityDescriptionInterface {
-
- /**
- * The machine name of this media bundle.
- *
- * @var string
- */
- public $id;
-
- /**
- * The human-readable name of the media bundle.
- *
- * @var string
- */
- public $label;
-
- /**
- * A brief description of this media bundle.
- *
- * @var string
- */
- public $description;
-
- /**
- * The type plugin id.
- *
- * @var string
- */
- public $type = 'generic';
-
- /**
- * Are thumbnail downloads queued.
- *
- * @var bool
- */
- public $queue_thumbnail_downloads = FALSE;
-
- /**
- * Default value of the 'Create new revision' checkbox of this media bundle.
- *
- * @var bool
- */
- protected $new_revision = FALSE;
-
- /**
- * The type plugin configuration.
- *
- * @var array
- */
- public $type_configuration = [];
-
- /**
- * Type lazy plugin collection.
- *
- * @var \Drupal\Core\Plugin\DefaultSingleLazyPluginCollection
- */
- protected $typePluginCollection;
-
- /**
- * Field map. Fields provided by type plugin to be stored as entity fields.
- *
- * @var array
- */
- public $field_map = [];
-
- /**
- * Default status of this media bundle.
- *
- * @var array
- */
- public $status = TRUE;
-
- /**
- * {@inheritdoc}
- */
- public function id() {
- return $this->id;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getPluginCollections() {
- return [
- 'type_configuration' => $this->typePluginCollection(),
- ];
- }
-
- /**
- * {@inheritdoc}
- */
- public static function getLabel(MediaInterface $media) {
- $bundle = static::load($media->bundle());
- return $bundle ? $bundle->label() : FALSE;
- }
-
- /**
- * {@inheritdoc}
- */
- public static function exists($id) {
- return (bool) static::load($id);
- }
-
- /**
- * {@inheritdoc}
- */
- public function getDescription() {
- return $this->description;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setDescription($description) {
- $this->description = $description;
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getTypeConfiguration() {
- return $this->type_configuration;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setTypeConfiguration($configuration) {
- $this->type_configuration = $configuration;
- $this->typePluginCollection = NULL;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getQueueThumbnailDownloads() {
- return $this->queue_thumbnail_downloads;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setQueueThumbnailDownloads($queue_thumbnail_downloads) {
- $this->queue_thumbnail_downloads = $queue_thumbnail_downloads;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getType() {
- return $this->typePluginCollection()->get($this->type);
- }
-
- /**
- * Returns type lazy plugin collection.
- *
- * @return \Drupal\Core\Plugin\DefaultSingleLazyPluginCollection
- * The tag plugin collection.
- */
- protected function typePluginCollection() {
- if (!$this->typePluginCollection) {
- $this->typePluginCollection = new DefaultSingleLazyPluginCollection(\Drupal::service('plugin.manager.media_entity.type'), $this->type, $this->type_configuration);
- }
- return $this->typePluginCollection;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getStatus() {
- return $this->status;
- }
-
- /**
- * {@inheritdoc}
- */
- public function shouldCreateNewRevision() {
- return $this->new_revision;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setNewRevision($new_revision) {
- $this->new_revision = $new_revision;
- }
-
-}
+++ /dev/null
-<?php
-
-namespace Drupal\media_entity\Form;
-
-use Drupal\Core\Entity\EntityTypeManagerInterface;
-use Drupal\Core\Form\ConfirmFormBase;
-use Drupal\Core\Form\FormStateInterface;
-use Drupal\Core\Url;
-use Drupal\user\PrivateTempStoreFactory;
-use Symfony\Component\DependencyInjection\ContainerInterface;
-use Symfony\Component\HttpFoundation\RedirectResponse;
-
-/**
- * Provides a media deletion confirmation form.
- */
-class DeleteMultiple extends ConfirmFormBase {
-
- /**
- * The array of media entities to delete.
- *
- * @var string[][]
- */
- protected $entityInfo = [];
-
- /**
- * The tempstore factory.
- *
- * @var \Drupal\user\PrivateTempStoreFactory
- */
- protected $tempStoreFactory;
-
- /**
- * The entity storage.
- *
- * @var \Drupal\Core\Entity\EntityStorageInterface
- */
- protected $storage;
-
- /**
- * Constructs a DeleteMultiple form object.
- *
- * @param \Drupal\user\PrivateTempStoreFactory $temp_store_factory
- * The tempstore factory.
- * @param \Drupal\Core\Entity\EntityTypeManagerInterface $manager
- * The entity manager.
- */
- public function __construct(PrivateTempStoreFactory $temp_store_factory, EntityTypeManagerInterface $manager) {
- $this->tempStoreFactory = $temp_store_factory;
- $this->storage = $manager->getStorage('media');
- }
-
- /**
- * {@inheritdoc}
- */
- public static function create(ContainerInterface $container) {
- return new static(
- $container->get('user.private_tempstore'),
- $container->get('entity_type.manager')
- );
- }
-
- /**
- * {@inheritdoc}
- */
- public function getFormId() {
- return 'media_multiple_delete_confirm';
- }
-
- /**
- * {@inheritdoc}
- */
- public function getQuestion() {
- return $this->formatPlural(count($this->entityInfo), 'Are you sure you want to delete this item?', 'Are you sure you want to delete these items?');
- }
-
- /**
- * {@inheritdoc}
- */
- public function getCancelUrl() {
- return new Url('system.admin_content');
- }
-
- /**
- * {@inheritdoc}
- */
- public function getConfirmText() {
- return $this->t('Delete');
- }
-
- /**
- * {@inheritdoc}
- */
- public function buildForm(array $form, FormStateInterface $form_state) {
- $this->entityInfo = $this->tempStoreFactory->get('media_multiple_delete_confirm')->get(\Drupal::currentUser()->id());
- if (empty($this->entityInfo)) {
- return new RedirectResponse($this->getCancelUrl()->setAbsolute()->toString());
- }
- /** @var \Drupal\media_entity\MediaInterface[] $entities */
- $entities = $this->storage->loadMultiple(array_keys($this->entityInfo));
-
- $items = [];
- foreach ($this->entityInfo as $id => $langcodes) {
- foreach ($langcodes as $langcode) {
- $entity = $entities[$id]->getTranslation($langcode);
- $key = $id . ':' . $langcode;
- $default_key = $id . ':' . $entity->getUntranslated()->language()->getId();
-
- // If we have a translated entity we build a nested list of translations
- // that will be deleted.
- $languages = $entity->getTranslationLanguages();
- if (count($languages) > 1 && $entity->isDefaultTranslation()) {
- $names = [];
- foreach ($languages as $translation_langcode => $language) {
- $names[] = $language->getName();
- unset($items[$id . ':' . $translation_langcode]);
- }
- $items[$default_key] = [
- 'label' => [
- '#markup' => $this->t('@label (Original translation) - <em>The following media translations will be deleted:</em>', ['@label' => $entity->label()]),
- ],
- 'deleted_translations' => [
- '#theme' => 'item_list',
- '#items' => $names,
- ],
- ];
- }
- elseif (!isset($items[$default_key])) {
- $items[$key] = $entity->label();
- }
- }
- }
-
- $form['entities'] = [
- '#theme' => 'item_list',
- '#items' => $items,
- ];
- $form = parent::buildForm($form, $form_state);
-
- return $form;
- }
-
- /**
- * {@inheritdoc}
- */
- public function submitForm(array &$form, FormStateInterface $form_state) {
- if ($form_state->getValue('confirm') && !empty($this->entityInfo)) {
- $total_count = 0;
- $delete_entities = [];
- /** @var \Drupal\Core\Entity\ContentEntityInterface[][] $delete_translations */
- $delete_translations = [];
- /** @var \Drupal\media_entity\MediaInterface[] $entities */
- $entities = $this->storage->loadMultiple(array_keys($this->entityInfo));
-
- foreach ($this->entityInfo as $id => $langcodes) {
- foreach ($langcodes as $langcode) {
- $entity = $entities[$id]->getTranslation($langcode);
- if ($entity->isDefaultTranslation()) {
- $delete_entities[$id] = $entity;
- unset($delete_translations[$id]);
- $total_count += count($entity->getTranslationLanguages());
- }
- elseif (!isset($delete_entities[$id])) {
- $delete_translations[$id][] = $entity;
- }
- }
- }
-
- if ($delete_entities) {
- $this->storage->delete($delete_entities);
- $this->logger('media_entity')->notice('Deleted @count media entities.', ['@count' => count($delete_entities)]);
- }
-
- if ($delete_translations) {
- $count = 0;
- foreach ($delete_translations as $id => $translations) {
- $entity = $entities[$id]->getUntranslated();
- foreach ($translations as $translation) {
- $entity->removeTranslation($translation->language()->getId());
- }
- $entity->save();
- $count += count($translations);
- }
- if ($count) {
- $total_count += $count;
- $this->logger('media_entity')->notice('Deleted @count media translations.', ['@count' => $count]);
- }
- }
-
- if ($total_count) {
- drupal_set_message($this->formatPlural($total_count, 'Deleted 1 media entity.', 'Deleted @count media entities.'));
- }
-
- $this->tempStoreFactory->get('media_multiple_delete_confirm')->delete(\Drupal::currentUser()->id());
- }
-
- $form_state->setRedirect('system.admin_content');
- }
-
-}
+++ /dev/null
-<?php
-
-namespace Drupal\media_entity\Form;
-
-use Drupal\Core\Entity\Query\QueryFactory;
-use Drupal\Core\Entity\EntityDeleteForm;
-use Drupal\Core\Form\FormStateInterface;
-use Symfony\Component\DependencyInjection\ContainerInterface;
-
-/**
- * Provides a form for media bundle deletion.
- */
-class MediaBundleDeleteConfirm extends EntityDeleteForm {
-
- /**
- * The query factory to create entity queries.
- *
- * @var \Drupal\Core\Entity\Query\QueryFactory
- */
- protected $queryFactory;
-
- /**
- * Constructs a new MediaBundleDeleteConfirm object.
- *
- * @param \Drupal\Core\Entity\Query\QueryFactory $query_factory
- * The entity query object.
- */
- public function __construct(QueryFactory $query_factory) {
- $this->queryFactory = $query_factory;
- }
-
- /**
- * {@inheritdoc}
- */
- public static function create(ContainerInterface $container) {
- return new static(
- $container->get('entity.query')
- );
- }
-
- /**
- * {@inheritdoc}
- */
- public function buildForm(array $form, FormStateInterface $form_state) {
- $num_entities = $this->queryFactory->get('media')
- ->condition('bundle', $this->entity->id())
- ->count()
- ->execute();
- if ($num_entities) {
- $caption = '<p>' . $this->formatPlural($num_entities, '%type is used by 1 piece of content on your site. You can not remove this content type until you have removed all of the %type content.', '%type is used by @count pieces of content on your site. You may not remove %type until you have removed all of the %type content.', ['%type' => $this->entity->label()]) . '</p>';
- $form['#title'] = $this->getQuestion();
- $form['description'] = ['#markup' => $caption];
- return $form;
- }
-
- return parent::buildForm($form, $form_state);
- }
-
-}
+++ /dev/null
-<?php
-
-namespace Drupal\media_entity\Form;
-
-use Drupal\Core\Entity\ContentEntityDeleteForm;
-use Drupal\Core\Url;
-
-/**
- * Provides a form for deleting a media.
- */
-class MediaDeleteForm extends ContentEntityDeleteForm {
-
- /**
- * {@inheritdoc}
- */
- public function getCancelUrl() {
- return Url::fromUri('internal:/');
- }
-
-}
+++ /dev/null
-<?php
-
-namespace Drupal\media_entity\Form;
-
-use Drupal\Core\Form\FormStateInterface;
-use Drupal\Core\StringTranslation\StringTranslationTrait;
-use Drupal\inline_entity_form\Form\EntityInlineForm;
-
-/**
- * Media inline form handler.
- */
-class MediaInlineForm extends EntityInlineForm {
-
- use StringTranslationTrait;
-
- /**
- * {@inheritdoc}
- */
- public function getTableFields($bundles) {
- $fields = parent::getTableFields($bundles);
-
- unset($fields['name']);
-
- $fields['thumbnail'] = [
- 'type' => 'field',
- 'label' => $this->t('Thumbnail'),
- 'weight' => 1,
- 'display_options' => [
- 'type' => 'image',
- 'settings' => [
- 'image_style' => 'thumbnail',
- ],
- ],
- ];
-
- return $fields;
- }
-
- /**
- * {@inheritdoc}
- */
- public function entityFormSubmit(array &$entity_form, FormStateInterface $form_state) {
- parent::entityFormSubmit($entity_form, $form_state);
-
- /** @var \Drupal\media_entity\MediaInterface $entity */
- $entity = $entity_form['#entity'];
-
- // Make sure media thumbnail is set correctly.
- $entity->automaticallySetThumbnail();
-
- if ($entity_form['#save_entity']) {
- $entity->save();
- }
- }
-
-}
--- /dev/null
+<?php
+
+namespace Drupal\media_entity;
+
+use Drupal\Core\Entity\EditorialContentEntityBase;
+use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\Core\Field\BaseFieldDefinition;
+
+final class Media extends EditorialContentEntityBase {
+
+ /**
+ * {@inheritdoc}
+ */
+ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
+ $fields = parent::baseFieldDefinitions($entity_type);
+
+ $fields['name'] = BaseFieldDefinition::create('string')
+ ->setLabel(t('Name'))
+ ->setRequired(TRUE)
+ ->setTranslatable(TRUE)
+ ->setRevisionable(TRUE)
+ ->setDefaultValue('')
+ ->setSetting('max_length', 255)
+ ->setDisplayOptions('form', [
+ 'type' => 'string_textfield',
+ 'weight' => -5,
+ ])
+ ->setDisplayConfigurable('form', TRUE)
+ ->setDisplayOptions('view', [
+ 'label' => 'hidden',
+ 'type' => 'string',
+ 'weight' => -5,
+ ]);
+
+ $fields['thumbnail'] = BaseFieldDefinition::create('image')
+ ->setLabel(t('Thumbnail'))
+ ->setDescription(t('The thumbnail of the media item.'))
+ ->setRevisionable(TRUE)
+ ->setTranslatable(TRUE)
+ ->setDisplayOptions('view', [
+ 'type' => 'image',
+ 'weight' => 5,
+ 'label' => 'hidden',
+ 'settings' => [
+ 'image_style' => 'thumbnail',
+ ],
+ ])
+ ->setDisplayConfigurable('view', TRUE)
+ ->setReadOnly(TRUE);
+
+ $fields['uid'] = BaseFieldDefinition::create('entity_reference')
+ ->setLabel(t('Authored by'))
+ ->setDescription(t('The user ID of the author.'))
+ ->setRevisionable(TRUE)
+ ->setDefaultValueCallback(static::class . '::getCurrentUserId')
+ ->setSetting('target_type', 'user')
+ ->setTranslatable(TRUE)
+ ->setDisplayOptions('form', [
+ 'type' => 'entity_reference_autocomplete',
+ 'weight' => 5,
+ 'settings' => [
+ 'match_operator' => 'CONTAINS',
+ 'size' => '60',
+ 'autocomplete_type' => 'tags',
+ 'placeholder' => '',
+ ],
+ ])
+ ->setDisplayConfigurable('form', TRUE)
+ ->setDisplayOptions('view', [
+ 'label' => 'hidden',
+ 'type' => 'author',
+ 'weight' => 0,
+ ])
+ ->setDisplayConfigurable('view', TRUE);
+
+ $fields['status']
+ ->setDisplayOptions('form', [
+ 'type' => 'boolean_checkbox',
+ 'settings' => [
+ 'display_label' => TRUE,
+ ],
+ 'weight' => 100,
+ ])
+ ->setDisplayConfigurable('form', TRUE);
+
+ $fields['created'] = BaseFieldDefinition::create('created')
+ ->setLabel(t('Authored on'))
+ ->setDescription(t('The time the media item was created.'))
+ ->setTranslatable(TRUE)
+ ->setRevisionable(TRUE)
+ ->setDefaultValueCallback(static::class . '::getRequestTime')
+ ->setDisplayOptions('form', [
+ 'type' => 'datetime_timestamp',
+ 'weight' => 10,
+ ])
+ ->setDisplayConfigurable('form', TRUE)
+ ->setDisplayOptions('view', [
+ 'label' => 'hidden',
+ 'type' => 'timestamp',
+ 'weight' => 0,
+ ])
+ ->setDisplayConfigurable('view', TRUE);
+
+ $fields['changed'] = BaseFieldDefinition::create('changed')
+ ->setLabel(t('Changed'))
+ ->setDescription(t('The time the media item was last edited.'))
+ ->setTranslatable(TRUE)
+ ->setRevisionable(TRUE);
+
+ return $fields;
+ }
+
+}
+++ /dev/null
-<?php
-
-namespace Drupal\media_entity;
-
-use Drupal\Core\Access\AccessResult;
-use Drupal\Core\Entity\EntityAccessControlHandler;
-use Drupal\Core\Entity\EntityInterface;
-use Drupal\Core\Session\AccountInterface;
-
-/**
- * Defines an access controller for the media entity.
- */
-class MediaAccessController extends EntityAccessControlHandler {
-
- /**
- * {@inheritdoc}
- */
- protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) {
- if ($account->hasPermission('administer media')) {
- return AccessResult::allowed()->cachePerPermissions();
- }
-
- $is_owner = ($account->id() && $account->id() == $entity->getPublisherId()) ? TRUE : FALSE;
- switch ($operation) {
- case 'view':
- return AccessResult::allowedIf($account->hasPermission('view media') && $entity->status->value);
-
- case 'update':
- return AccessResult::allowedIf(($account->hasPermission('update media') && $is_owner) || $account->hasPermission('update any media'))->cachePerPermissions()->cachePerUser()->addCacheableDependency($entity);
-
- case 'delete':
- return AccessResult::allowedIf(($account->hasPermission('delete media') && $is_owner) || $account->hasPermission('delete any media'))->cachePerPermissions()->cachePerUser()->addCacheableDependency($entity);
- }
-
- // No opinion.
- return AccessResult::neutral()->cachePerPermissions();
- }
-
- /**
- * {@inheritdoc}
- */
- protected function checkCreateAccess(AccountInterface $account, array $context, $entity_bundle = NULL) {
- return AccessResult::allowedIfHasPermission($account, 'create media');
- }
-
-}
--- /dev/null
+<?php
+
+namespace Drupal\media_entity;
+
+use Drupal\Core\Config\Entity\ConfigEntityBase;
+
+final class MediaBundle extends ConfigEntityBase {
+}
+++ /dev/null
-<?php
-
-namespace Drupal\media_entity;
-
-use Drupal\Core\Ajax\AjaxResponse;
-use Drupal\Core\Ajax\ReplaceCommand;
-use Drupal\Core\Entity\EntityFieldManagerInterface;
-use Drupal\Core\Entity\EntityForm;
-use Drupal\Core\Entity\EntityInterface;
-use Drupal\Core\Form\FormStateInterface;
-use Drupal\language\Entity\ContentLanguageSettings;
-use Symfony\Component\DependencyInjection\ContainerInterface;
-
-/**
- * Form controller for node type forms.
- */
-class MediaBundleForm extends EntityForm {
-
- /**
- * The instantiated plugin instances that have configuration forms.
- *
- * @var \Drupal\Core\Plugin\PluginFormInterface[]
- */
- protected $configurableInstances = [];
-
- /**
- * Manager for media entity type plugins.
- *
- * @var \Drupal\media_entity\MediaTypeManager
- */
- protected $mediaTypeManager;
-
- /**
- * Entity field manager service.
- *
- * @var \Drupal\Core\Entity\EntityFieldManagerInterface
- */
- protected $entityFieldManager;
-
- /**
- * Constructs a new class instance.
- *
- * @param \Drupal\media_entity\MediaTypeManager $media_type_manager
- * Media type manager.
- */
- public function __construct(MediaTypeManager $media_type_manager, EntityFieldManagerInterface $entity_field_manager) {
- $this->mediaTypeManager = $media_type_manager;
- $this->entityFieldManager = $entity_field_manager;
- }
-
- /**
- * {@inheritdoc}
- */
- public static function create(ContainerInterface $container) {
- return new static(
- $container->get('plugin.manager.media_entity.type'),
- $container->get('entity_field.manager')
- );
- }
-
- /**
- * Ajax callback triggered by the type provider select element.
- *
- * @param array $form
- * The form array.
- * @param \Drupal\Core\Form\FormStateInterface $form_state
- * Current form state.
- *
- * @return \Drupal\Core\Ajax\AjaxResponse
- * The ajax response.
- */
- public function ajaxTypeProviderData(array $form, FormStateInterface $form_state) {
- $response = new AjaxResponse();
- $plugin = $this->entity->getType()->getPluginId();
-
- $response->addCommand(new ReplaceCommand('#edit-type-configuration-plugin-wrapper', $form['type_configuration'][$plugin]));
- $response->addCommand(new ReplaceCommand('#field-mapping-wrapper', $form['field_mapping']));
-
- return $response;
- }
-
- /**
- * {@inheritdoc}
- */
- public function form(array $form, FormStateInterface $form_state) {
- $form = parent::form($form, $form_state);
-
- /** @var \Drupal\media_entity\MediaBundleInterface $bundle */
- $form['#entity'] = $bundle = $this->entity;
- $form_state->set('bundle', $bundle->id());
-
- if ($this->operation == 'add') {
- $form['#title'] = $this->t('Add media bundle');
- }
- elseif ($this->operation == 'edit') {
- $form['#title'] = $this->t('Edit %label media bundle', ['%label' => $bundle->label()]);
- }
-
- $form['label'] = [
- '#title' => $this->t('Label'),
- '#type' => 'textfield',
- '#default_value' => $bundle->label(),
- '#description' => $this->t('The human-readable name of this media bundle.'),
- '#required' => TRUE,
- '#size' => 30,
- '#weight' => -100,
- ];
-
- // @todo: '#disabled' not always FALSE.
- $form['id'] = [
- '#type' => 'machine_name',
- '#default_value' => $bundle->id(),
- '#maxlength' => 32,
- '#disabled' => !$bundle->isNew(),
- '#machine_name' => [
- 'exists' => ['\Drupal\media_entity\Entity\MediaBundle', 'exists'],
- 'source' => ['label'],
- ],
- '#description' => $this->t('A unique machine-readable name for this media bundle.'),
- '#weight' => -90,
- ];
-
- $form['description'] = [
- '#title' => $this->t('Description'),
- '#type' => 'textarea',
- '#default_value' => $bundle->getDescription(),
- '#description' => $this->t('Describe this media bundle. The text will be displayed on the <em>Add new media</em> page.'),
- '#weight' => -80,
- ];
-
- $plugins = $this->mediaTypeManager->getDefinitions();
- $options = [];
- foreach ($plugins as $plugin => $definition) {
- $options[$plugin] = $definition['label'];
- }
-
- $form['type'] = [
- '#type' => 'select',
- '#title' => $this->t('Type provider'),
- '#default_value' => $bundle->getType()->getPluginId(),
- '#options' => $options,
- '#description' => $this->t('Media type provider plugin that is responsible for additional logic related to this media.'),
- '#weight' => -70,
- '#ajax' => [
- 'callback' => '::ajaxTypeProviderData',
- 'progress' => [
- 'type' => 'throbber',
- 'message' => $this->t('Updating type provider configuration form.'),
- ],
- ],
- ];
-
- // Media type plugin configuration.
- $form['type_configuration'] = [
- '#type' => 'fieldset',
- '#title' => $this->t('Type provider configuration'),
- '#tree' => TRUE,
- '#weight' => -60,
- ];
-
- /** @var \Drupal\media_entity\MediaTypeInterface $plugin */
- if ($plugin = $bundle->getType()) {
- $plugin_configuration = (empty($this->configurableInstances[$plugin->getPluginId()]['plugin_config'])) ? $bundle->type_configuration : $this->configurableInstances[$plugin->getPluginId()]['plugin_config'];
- /** @var \Drupal\media_entity\MediaTypeBase $instance */
- $instance = $this->mediaTypeManager->createInstance($plugin->getPluginId(), $plugin_configuration);
- // Store the configuration for validate and submit handlers.
- $this->configurableInstances[$plugin->getPluginId()]['plugin_config'] = $plugin_configuration;
-
- $form['type_configuration'][$plugin->getPluginId()] = [
- '#type' => 'container',
- '#attributes' => [
- 'id' => 'edit-type-configuration-plugin-wrapper',
- ],
- ];
- $form['type_configuration'][$plugin->getPluginId()] += $instance->buildConfigurationForm([], $form_state);
- }
-
- // Field mapping configuration.
- $form['field_mapping'] = [
- '#type' => 'fieldset',
- '#title' => $this->t('Field mapping'),
- '#tree' => TRUE,
- '#attributes' => ['id' => 'field-mapping-wrapper'],
- 'description' => [
- '#type' => 'html_tag',
- '#tag' => 'p',
- '#value' => $this->t('Media type plugins can provide metadata fields such as title, caption, size information, credits, ... Media entity can automatically save this metadata information to entity fields, which can be configured below. Information will only be mapped if the entity field is empty.'),
- ],
- '#weight' => -50,
- ];
-
- if (empty($plugin) || empty($plugin->providedFields())) {
- $form['field_mapping']['empty_message'] = [
- '#prefix' => '<em>',
- '#suffix' => '</em>',
- '#markup' => $this->t('No metadata fields available.'),
- ];
- }
- else {
- $skipped_fields = [
- 'mid',
- 'uuid',
- 'vid',
- 'bundle',
- 'langcode',
- 'default_langcode',
- 'uid',
- 'revision_timestamp',
- 'revision_log',
- 'revision_uid',
- ];
- $options = ['_none' => $this->t('- Skip field -')];
- foreach ($this->entityFieldManager->getFieldDefinitions('media', $bundle->id()) as $field_name => $field) {
- if (!in_array($field_name, $skipped_fields)) {
- $options[$field_name] = $field->getLabel();
- }
- }
-
- foreach ($plugin->providedFields() as $field_name => $field_label) {
- $form['field_mapping'][$field_name] = [
- '#type' => 'select',
- '#title' => $field_label,
- '#options' => $options,
- '#default_value' => isset($bundle->field_map[$field_name]) ? $bundle->field_map[$field_name] : '_none',
- ];
- }
- }
-
- $form['additional_settings'] = [
- '#type' => 'vertical_tabs',
- '#attached' => [
- 'library' => ['media_entity/media_bundle_form'],
- ],
- '#weight' => 100,
- ];
-
- $form['workflow'] = [
- '#type' => 'details',
- '#title' => $this->t('Publishing options'),
- '#group' => 'additional_settings',
- ];
-
- $workflow_options = [
- 'status' => $bundle->getStatus(),
- 'new_revision' => $bundle->shouldCreateNewRevision(),
- 'queue_thumbnail_downloads' => $bundle->getQueueThumbnailDownloads(),
- ];
- // Prepare workflow options to be used for 'checkboxes' form element.
- $keys = array_keys(array_filter($workflow_options));
- $workflow_options = array_combine($keys, $keys);
- $form['workflow']['options'] = [
- '#type' => 'checkboxes',
- '#title' => $this->t('Default options'),
- '#default_value' => $workflow_options,
- '#options' => [
- 'status' => $this->t('Published'),
- 'new_revision' => $this->t('Create new revision'),
- 'queue_thumbnail_downloads' => $this->t('Queue thumbnail downloads'),
- ],
- ];
-
- $form['workflow']['options']['status']['#description'] = $this->t('Entities will be automatically published when they are created.');
- $form['workflow']['options']['new_revision']['#description'] = $this->t('Automatically create a new revision of media entities. Users with the Administer media permission will be able to override this option.');
- $form['workflow']['options']['queue_thumbnail_downloads']['#description'] = $this->t('Download thumbnails via a queue.');
-
- if ($this->moduleHandler->moduleExists('language')) {
- $form['language'] = [
- '#type' => 'details',
- '#title' => $this->t('Language settings'),
- '#group' => 'additional_settings',
- ];
-
- $language_configuration = ContentLanguageSettings::loadByEntityTypeBundle('media', $bundle->id());
-
- $form['language']['language_configuration'] = [
- '#type' => 'language_configuration',
- '#entity_information' => [
- 'entity_type' => 'media',
- 'bundle' => $bundle->id(),
- ],
- '#default_value' => $language_configuration,
- ];
- }
-
- return $form;
- }
-
- /**
- * {@inheritdoc}
- */
- public function validateForm(array &$form, FormStateInterface $form_state) {
- parent::validateForm($form, $form_state);
-
- // Let the selected plugin validate its settings.
- $plugin = $this->entity->getType()->getPluginId();
- $plugin_configuration = !empty($this->configurableInstances[$plugin]['plugin_config']) ? $this->configurableInstances[$plugin]['plugin_config'] : [];
- $instance = $this->mediaTypeManager->createInstance($plugin, $plugin_configuration);
- $instance->validateConfigurationForm($form, $form_state);
- }
-
- /**
- * {@inheritdoc}
- */
- public function submitForm(array &$form, FormStateInterface $form_state) {
- parent::submitForm($form, $form_state);
-
- $workflow_options = ['status', 'queue_thumbnail_downloads'];
- foreach ($workflow_options as $option) {
- $this->entity->$option = (bool) $form_state->getValue(['options', $option]);
- }
-
- $this->entity->setNewRevision((bool) $form_state->getValue(['options', 'new_revision']));
-
- // Let the selected plugin save its settings.
- $plugin = $this->entity->getType()->getPluginId();
- $plugin_configuration = !empty($this->configurableInstances[$plugin]['plugin_config']) ? $this->configurableInstances[$plugin]['plugin_config'] : [];
- $instance = $this->mediaTypeManager->createInstance($plugin, $plugin_configuration);
- $instance->submitConfigurationForm($form, $form_state);
- }
-
- /**
- * {@inheritdoc}
- */
- protected function actions(array $form, FormStateInterface $form_state) {
- $actions = parent::actions($form, $form_state);
- $actions['submit']['#value'] = $this->t('Save media bundle');
- $actions['delete']['#value'] = $this->t('Delete media bundle');
- $actions['delete']['#access'] = $this->entity->access('delete');
- return $actions;
- }
-
- /**
- * {@inheritdoc}
- */
- protected function copyFormValuesToEntity(EntityInterface $entity, array $form, FormStateInterface $form_state) {
- $configuration = $form_state->getValue('type_configuration');
-
- // Store previous plugin config.
- $plugin = $entity->getType()->getPluginId();
- $this->configurableInstances[$plugin]['plugin_config'] = empty($configuration[$plugin]) ? [] : $configuration[$plugin];
-
- /** @var \Drupal\media_entity\MediaBundleInterface $entity */
- parent::copyFormValuesToEntity($entity, $form, $form_state);
-
- // Use type configuration for the plugin that was chosen.
- $plugin = $entity->getType()->getPluginId();
- $plugin_configuration = empty($configuration[$plugin]) ? [] : $configuration[$plugin];
- $entity->set('type_configuration', $plugin_configuration);
-
- // Save field mapping.
- $entity->field_map = array_filter(
- $form_state->getValue('field_mapping', []),
- function ($item) { return $item != '_none'; }
- );
- }
-
- /**
- * {@inheritdoc}
- */
- public function save(array $form, FormStateInterface $form_state) {
- /** @var \Drupal\media_entity\MediaBundleInterface $bundle */
- $bundle = $this->entity;
- $status = $bundle->save();
-
- $t_args = ['%name' => $bundle->label()];
- if ($status == SAVED_UPDATED) {
- drupal_set_message($this->t('The media bundle %name has been updated.', $t_args));
- }
- elseif ($status == SAVED_NEW) {
- drupal_set_message($this->t('The media bundle %name has been added.', $t_args));
- $this->logger('media')->notice('Added bundle %name.', $t_args);
- }
-
- // Override the "status" base field default value, for this bundle.
- $fields = $this->entityFieldManager->getFieldDefinitions('media', $bundle->id());
- $media = $this->entityTypeManager->getStorage('media')->create(array('bundle' => $bundle->id()));
- $value = (bool) $form_state->getValue(['options', 'status']);
- if ($media->status->value != $value) {
- $fields['status']->getConfig($bundle->id())->setDefaultValue($value)->save();
- }
-
- $form_state->setRedirectUrl($bundle->toUrl('collection'));
- }
-
-}
+++ /dev/null
-<?php
-
-namespace Drupal\media_entity;
-
-use Drupal\Core\Config\Entity\ConfigEntityInterface;
-use Drupal\entity\Entity\RevisionableEntityBundleInterface;
-
-/**
- * Provides an interface defining a media bundle entity.
- */
-interface MediaBundleInterface extends ConfigEntityInterface, RevisionableEntityBundleInterface {
-
- /**
- * Returns the label.
- *
- * @param \Drupal\media_entity\MediaInterface $media
- * The Media entity.
- *
- * @return string|bool
- * Returns the label of the bundle that entity belongs to.
- */
- public static function getLabel(MediaInterface $media);
-
- /**
- * Checks if the bundle exists.
- *
- * @param int $id
- * The Media bundle ID.
- *
- * @return bool
- * TRUE if the bundle with the given ID exists, FALSE otherwise.
- */
- public static function exists($id);
-
- /**
- * Returns whether thumbnail downloads are queued.
- *
- * @return bool
- * Returns download now or later.
- */
- public function getQueueThumbnailDownloads();
-
- /**
- * Sets a flag to indicate that thumbnails should be downloaded via a queue.
- *
- * @param bool $queue_thumbnail_downloads
- * The queue downloads flag.
- */
- public function setQueueThumbnailDownloads($queue_thumbnail_downloads);
-
- /**
- * Returns the Media bundle description.
- *
- * @return string
- * Returns the Media bundle description.
- */
- public function getDescription();
-
- /**
- * Returns the media type plugin.
- *
- * @return \Drupal\media_entity\MediaTypeInterface
- * The type.
- */
- public function getType();
-
- /**
- * Returns the media type configuration.
- *
- * @return array
- * The type configuration.
- */
- public function getTypeConfiguration();
-
- /**
- * Sets the media type configuration.
- *
- * @param array $configuration
- * The type configuration.
- */
- public function setTypeConfiguration($configuration);
-
- /**
- * Returns the media type status.
- *
- * @return bool
- * The status.
- */
- public function getStatus();
-
- /**
- * Sets whether a new revision should be created by default.
- *
- * @param bool $new_revision
- * TRUE if a new revision should be created by default.
- */
- public function setNewRevision($new_revision);
-
-}
+++ /dev/null
-<?php
-
-namespace Drupal\media_entity;
-
-use Drupal\Core\Config\Entity\ConfigEntityListBuilder;
-use Drupal\Core\Entity\EntityHandlerInterface;
-use Drupal\Core\Entity\EntityInterface;
-use Drupal\Component\Utility\Xss;
-use Drupal\Core\Url;
-
-/**
- * Provides a listing of media bundles.
- */
-class MediaBundleListBuilder extends ConfigEntityListBuilder implements EntityHandlerInterface {
-
- /**
- * {@inheritdoc}
- */
- public function buildHeader() {
- $header['title'] = $this->t('Name');
- $header['description'] = [
- 'data' => $this->t('Description'),
- 'class' => [RESPONSIVE_PRIORITY_MEDIUM],
- ];
- return $header + parent::buildHeader();
- }
-
- /**
- * {@inheritdoc}
- */
- public function buildRow(EntityInterface $entity) {
- $row['title'] = [
- 'data' => $entity->label(),
- 'class' => ['menu-label'],
- ];
- $row['description'] = Xss::filterAdmin($entity->getDescription());
- return $row + parent::buildRow($entity);
- }
-
- /**
- * {@inheritdoc}
- */
- public function render() {
- $build = parent::render();
- $build['#empty'] = $this->t('No media bundle available. <a href="@link">Add media bundle</a>.', [
- '@link' => Url::fromRoute('entity.media_bundle.add_form')->toString(),
- ]);
- return $build;
- }
-
-}
+++ /dev/null
-<?php
-
-namespace Drupal\media_entity;
-
-use Drupal\Core\Form\FormStateInterface;
-use Drupal\entity\Form\RevisionableContentEntityForm;
-
-/**
- * Form controller for the media edit forms.
- */
-class MediaForm extends RevisionableContentEntityForm {
-
- /**
- * Default settings for this media bundle.
- *
- * @var array
- */
- protected $settings;
-
- /**
- * The entity being used by this form.
- *
- * @var \Drupal\media_entity\Entity\Media
- */
- protected $entity;
-
- /**
- * {@inheritdoc}
- */
- protected function prepareEntity() {
- parent::prepareEntity();
- $media = $this->entity;
-
- // If this is a new media, fill in the default values.
- if ($media->isNew()) {
- $media->setPublisherId($this->currentUser()->id());
- $media->setCreatedTime(REQUEST_TIME);
- }
- }
-
- /**
- * {@inheritdoc}
- */
- public function form(array $form, FormStateInterface $form_state) {
- $form = parent::form($form, $form_state);
-
- // Media author information for administrators.
- if (isset($form['uid']) || isset($form['created'])) {
- $form['author'] = [
- '#type' => 'details',
- '#title' => $this->t('Authoring information'),
- '#group' => 'advanced',
- '#attributes' => [
- 'class' => ['node-form-author'],
- ],
- '#attached' => [
- 'library' => ['node/drupal.node'],
- ],
- '#weight' => 90,
- '#optional' => TRUE,
- ];
- }
-
- if (isset($form['uid'])) {
- $form['uid']['#group'] = 'author';
- }
-
- if (isset($form['created'])) {
- $form['created']['#group'] = 'author';
- }
-
- $form['#attached']['library'][] = 'node/form';
-
- $form['#entity_builders']['update_status'] = [$this, 'updateStatus'];
-
- return $form;
- }
-
- /**
- * {@inheritdoc}
- */
- protected function actions(array $form, FormStateInterface $form_state) {
- $element = parent::actions($form, $form_state);
- $media = $this->entity;
-
- // Add a "Publish" button.
- $element['publish'] = $element['submit'];
- // If the "Publish" button is clicked, we want to update the status to
- // "published".
- $element['publish']['#published_status'] = TRUE;
- $element['publish']['#dropbutton'] = 'save';
- if ($media->isNew()) {
- $element['publish']['#value'] = $this->t('Save and publish');
- }
- else {
- $element['publish']['#value'] = $media->isPublished() ? $this->t('Save and keep published') : $this->t('Save and publish');
- }
- $element['publish']['#weight'] = 0;
-
- // Add a "Unpublish" button.
- $element['unpublish'] = $element['submit'];
- // If the "Unpublish" button is clicked, we want to update the status to
- // "unpublished".
- $element['unpublish']['#published_status'] = FALSE;
- $element['unpublish']['#dropbutton'] = 'save';
- if ($media->isNew()) {
- $element['unpublish']['#value'] = $this->t('Save as unpublished');
- }
- else {
- $element['unpublish']['#value'] = !$media->isPublished() ? $this->t('Save and keep unpublished') : $this->t('Save and unpublish');
- }
- $element['unpublish']['#weight'] = 10;
-
- // If already published, the 'publish' button is primary.
- if ($media->isPublished()) {
- unset($element['unpublish']['#button_type']);
- }
- // Otherwise, the 'unpublish' button is primary and should come first.
- else {
- unset($element['publish']['#button_type']);
- $element['unpublish']['#weight'] = -10;
- }
-
- // Remove the "Save" button.
- $element['submit']['#access'] = FALSE;
-
- $element['delete']['#access'] = $media->access('delete');
- $element['delete']['#weight'] = 100;
-
- return $element;
- }
-
- /**
- * Entity builder updating the media status with the submitted value.
- *
- * @param string $entity_type_id
- * The entity type identifier.
- * @param \Drupal\media_entity\MediaInterface $media
- * The media updated with the submitted values.
- * @param array $form
- * The complete form array.
- * @param \Drupal\Core\Form\FormStateInterface $form_state
- * The current state of the form.
- *
- * @see \Drupal\media\MediaForm::form()
- */
- public function updateStatus($entity_type_id, MediaInterface $media, array $form, FormStateInterface $form_state) {
- $element = $form_state->getTriggeringElement();
- if (isset($element['#published_status'])) {
- $media->setPublished($element['#published_status']);
- }
- }
-
-}
+++ /dev/null
-<?php
-
-namespace Drupal\media_entity;
-
-use Drupal\Core\Entity\EntityChangedInterface;
-use Drupal\Core\Entity\ContentEntityInterface;
-use Drupal\Core\Entity\RevisionLogInterface;
-
-/**
- * Provides an interface defining a media entity.
- */
-interface MediaInterface extends ContentEntityInterface, EntityChangedInterface, RevisionLogInterface {
-
- /**
- * Returns the media creation timestamp.
- *
- * @return int
- * Creation timestamp of the media.
- */
- public function getCreatedTime();
-
- /**
- * Sets the media creation timestamp.
- *
- * @param int $timestamp
- * The media creation timestamp.
- *
- * @return \Drupal\media_entity\MediaInterface
- * The called media entity.
- */
- public function setCreatedTime($timestamp);
-
- /**
- * Sets a flag to indicate the thumbnail will be retrieved via a queue.
- */
- public function setQueuedThumbnailDownload();
-
- /**
- * Returns the media publisher user entity.
- *
- * @return \Drupal\user\UserInterface
- * The author user entity.
- */
- public function getPublisher();
-
- /**
- * Returns the media publisher user ID.
- *
- * @return int
- * The author user ID.
- */
- public function getPublisherId();
-
- /**
- * Sets the media publisher user ID.
- *
- * @param int $uid
- * The author user id.
- *
- * @return \Drupal\media_entity\MediaInterface
- * The called media entity.
- */
- public function setPublisherId($uid);
-
- /**
- * Returns the media published status indicator.
- *
- * Unpublished media are only visible to their authors and to administrators.
- *
- * @return bool
- * TRUE if the media is published.
- */
- public function isPublished();
-
- /**
- * Sets the published status of a media.
- *
- * @param bool $published
- * TRUE to set this media to published, FALSE to set it to unpublished.
- *
- * @return \Drupal\media_entity\MediaInterface
- * The called media entity.
- */
- public function setPublished($published);
-
- /**
- * Returns the media type.
- *
- * @return \Drupal\media_entity\MediaTypeInterface
- * The media type.
- */
- public function getType();
-
- /**
- * Automatically determines the most appropriate thumbnail and sets
- * "thumbnail" field.
- */
- public function automaticallySetThumbnail();
-
-}
+++ /dev/null
-<?php
-
-namespace Drupal\media_entity;
-
-use Drupal\Core\Entity\Sql\SqlContentEntityStorage;
-
-/**
- * Media storage class.
- */
-class MediaStorage extends SqlContentEntityStorage implements MediaStorageInterface {
-
-}
+++ /dev/null
-<?php
-
-namespace Drupal\media_entity;
-
-use Drupal\Core\Entity\EntityStorageInterface;
-
-/**
- * Provides an interface defining a media storage controller.
- */
-interface MediaStorageInterface extends EntityStorageInterface {
-
-}
+++ /dev/null
-<?php
-
-namespace Drupal\media_entity;
-
-use Drupal\Component\Plugin\PluginBase;
-use Drupal\Core\Config\Config;
-use Drupal\Core\Entity\EntityFieldManagerInterface;
-use Drupal\Core\Entity\EntityTypeManagerInterface;
-use Drupal\Core\StringTranslation\StringTranslationTrait;
-use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
-use Drupal\Component\Utility\NestedArray;
-use Symfony\Component\DependencyInjection\ContainerInterface;
-use Drupal\Core\Form\FormStateInterface;
-
-/**
- * Base implementation of media type plugin.
- */
-abstract class MediaTypeBase extends PluginBase implements MediaTypeInterface, ContainerFactoryPluginInterface {
- use StringTranslationTrait;
-
- /**
- * Plugin label.
- *
- * @var string
- */
- protected $label;
-
- /**
- * The entity type manager service.
- *
- * @var \Drupal\Core\Entity\EntityTypeManagerInterface;
- */
- protected $entityTypeManager;
-
- /**
- * The entity field manager service.
- *
- * @var \Drupal\Core\Entity\EntityFieldManagerInterface;
- */
- protected $entityFieldManager;
-
- /**
- * Media entity image config object.
- *
- * @var \Drupal\Core\Config\Config
- */
- protected $config;
-
- /**
- * Constructs a new class instance.
- *
- * @param array $configuration
- * A configuration array containing information about the plugin instance.
- * @param string $plugin_id
- * The plugin_id for the plugin instance.
- * @param mixed $plugin_definition
- * The plugin implementation definition.
- * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
- * Entity type manager service.
- * @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager
- * Entity field manager service.
- * @param \Drupal\Core\Config\Config $config
- * Media entity config object.
- */
- public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager, Config $config) {
- parent::__construct($configuration, $plugin_id, $plugin_definition);
- $this->entityTypeManager = $entity_type_manager;
- $this->entityFieldManager = $entity_field_manager;
- $this->config = $config;
- $this->setConfiguration($configuration);
- }
-
- /**
- * {@inheritdoc}
- */
- public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
- return new static(
- $configuration,
- $plugin_id,
- $plugin_definition,
- $container->get('entity_type.manager'),
- $container->get('entity_field.manager'),
- $container->get('config.factory')->get('media_entity.settings')
- );
- }
-
- /**
- * {@inheritdoc}
- */
- public function setConfiguration(array $configuration) {
- $this->configuration = NestedArray::mergeDeep(
- $this->defaultConfiguration(),
- $configuration
- );
- }
-
- /**
- * {@inheritdoc}
- */
- public function getConfiguration() {
- return $this->configuration;
- }
-
- /**
- * {@inheritdoc}
- */
- public function defaultConfiguration() {
- return [];
- }
-
- /**
- * {@inheritdoc}
- */
- public function getDefaultThumbnail() {
- return '';
- }
-
- /**
- * {@inheritdoc}
- */
- public function label() {
- return $this->label;
- }
-
- /**
- * {@inheritdoc}
- */
- public function attachConstraints(MediaInterface $media) {}
-
- /**
- * {@inheritdoc}
- */
- public function calculateDependencies() {
- return [];
- }
-
- /**
- * {@inheritdoc}
- */
- public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
- return [];
- }
-
- /**
- * {@inheritdoc}
- */
- public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {}
-
- /**
- * {@inheritdoc}
- */
- public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {}
-
- /**
- * {@inheritdoc}
- */
- public function getDefaultName(MediaInterface $media) {
- return 'media:' . $media->bundle() . ':' . $media->uuid();
- }
-
-}
+++ /dev/null
-<?php
-
-namespace Drupal\media_entity;
-
-/**
- * Generic Plugin exception class to be thrown when no more specific class
- * is applicable.
- */
-class MediaTypeException extends \Exception {
-
- /**
- * Form element name that this exception belongs to.
- *
- * @var string
- */
- protected $element;
-
- /**
- * Construct the exception.
- *
- * @param string $element
- * [optional] Name of form element that exception refers to.
- * @param string $message
- * [optional] The Exception message to throw.
- * @param int $code
- * [optional] The Exception code.
- * @param \Exception $previous
- * [optional] The previous exception used for the exception chaining.
- */
- public function __construct($element = NULL, $message = "", $code = 0, \Exception $previous = NULL) {
- parent::__construct($message, $code, $previous);
- $this->element = $element;
- }
-
- /**
- * Gets element.
- *
- * @return string
- * Element name.
- */
- public function getElement() {
- return $this->element;
- }
-
-}
+++ /dev/null
-<?php
-
-namespace Drupal\media_entity;
-
-use Drupal\Component\Plugin\PluginInspectionInterface;
-use Drupal\Component\Plugin\ConfigurablePluginInterface;
-use Drupal\Core\Plugin\PluginFormInterface;
-
-/**
- * Defines the interface for media types.
- */
-interface MediaTypeInterface extends PluginInspectionInterface, ConfigurablePluginInterface, PluginFormInterface {
-
- /**
- * Returns the display label.
- *
- * @return string
- * The display label.
- */
- public function label();
-
- /**
- * Gets list of fields provided by this plugin.
- *
- * @return array
- * Associative array with field names as keys and descriptions as values.
- */
- public function providedFields();
-
- /**
- * Gets a media-related field/value.
- *
- * @param MediaInterface $media
- * Media object.
- * @param string $name
- * Name of field to fetch.
- *
- * @return mixed
- * Field value or FALSE if data unavailable.
- */
- public function getField(MediaInterface $media, $name);
-
- /**
- * Attaches type-specific constraints to media.
- *
- * @param MediaInterface $media
- * Media entity.
- */
- public function attachConstraints(MediaInterface $media);
-
- /**
- * Gets thumbnail image.
- *
- * Media type plugin is responsible for returning URI of the generic thumbnail
- * if no other is available. This functions should always return a valid URI.
- *
- * @param MediaInterface $media
- * Media.
- *
- * @return string
- * URI of the thumbnail.
- */
- public function thumbnail(MediaInterface $media);
-
- /**
- * Gets the default thumbnail image.
- *
- * @return string
- * Uri of the default thumbnail image.
- */
- public function getDefaultThumbnail();
-
- /**
- * Provide a default name for the media.
- *
- * Plugins defining media bundles are suggested to override this method and
- * provide a default name, to be used when there is no user-defined label
- * available.
- *
- * @param \Drupal\media_entity\MediaInterface $media
- * The media object.
- *
- * @return string
- * The string that should be used as default media name.
- */
- public function getDefaultName(MediaInterface $media);
-
-}
+++ /dev/null
-<?php
-
-namespace Drupal\media_entity;
-
-use Drupal\views\EntityViewsData;
-
-/**
- * Provides the views data for the media entity type.
- */
-class MediaViewsData extends EntityViewsData {
-
- /**
- * {@inheritdoc}
- */
- public function getViewsData() {
- $data = parent::getViewsData();
-
- $data['media_field_data']['table']['wizard_id'] = 'media';
- $data['media_field_revision']['table']['wizard_id'] = 'media_revision';
- $data['media']['media_bulk_form'] = [
- 'title' => $this->t('Media operations bulk form'),
- 'help' => $this->t('Add a form element that lets you run operations on multiple media entities.'),
- 'field' => [
- 'id' => 'media_bulk_form',
- ],
- ];
-
- return $data;
- }
-
-}
+++ /dev/null
-<?php
-
-namespace Drupal\media_entity\Plugin\Action;
-
-use Drupal\Core\Action\ActionBase;
-use Drupal\Core\Session\AccountInterface;
-use Drupal\media_entity\Entity\Media;
-
-/**
- * Publishes a media entity.
- *
- * @Action(
- * id = "media_publish_action",
- * label = @Translation("Publish media"),
- * type = "media"
- * )
- */
-class PublishMedia extends ActionBase {
-
- /**
- * {@inheritdoc}
- */
- public function execute(Media $entity = NULL) {
- $entity->setPublished(TRUE)->save();
- }
-
- /**
- * {@inheritdoc}
- */
- public function access($object, AccountInterface $account = NULL, $return_as_object = FALSE) {
- /** @var \Drupal\media_entity\MediaInterface $object */
- $result = $object->access('update', $account, TRUE)
- ->andIf($object->status->access('edit', $account, TRUE));
-
- return $return_as_object ? $result : $result->isAllowed();
- }
-
-}
+++ /dev/null
-<?php
-
-namespace Drupal\media_entity\Plugin\Action;
-
-use Drupal\Core\Action\ActionBase;
-use Drupal\Core\Session\AccountInterface;
-use Drupal\media_entity\Entity\Media;
-
-/**
- * Unpublishes a media entity.
- *
- * @Action(
- * id = "media_unpublish_action",
- * label = @Translation("Unpublish media"),
- * type = "media"
- * )
- */
-class UnpublishMedia extends ActionBase {
-
- /**
- * {@inheritdoc}
- */
- public function execute(Media $entity = NULL) {
- $entity->setPublished(FALSE)->save();
- }
-
- /**
- * {@inheritdoc}
- */
- public function access($object, AccountInterface $account = NULL, $return_as_object = FALSE) {
- /** @var \Drupal\media_entity\MediaInterface $object */
- $result = $object->access('update', $account, TRUE)
- ->andIf($object->status->access('edit', $account, TRUE));
-
- return $return_as_object ? $result : $result->isAllowed();
- }
-
-}
+++ /dev/null
-<?php
-
-namespace Drupal\media_entity\Plugin\DevelGenerate;
-
-use Drupal\Core\Datetime\DateFormatter;
-use Drupal\Core\Entity\EntityStorageInterface;
-use Drupal\Core\Extension\ModuleHandlerInterface;
-use Drupal\Core\Form\FormStateInterface;
-use Drupal\Core\Language\LanguageInterface;
-use Drupal\Core\Language\LanguageManagerInterface;
-use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
-use Drupal\Core\Routing\UrlGeneratorInterface;
-use Drupal\devel_generate\DevelGenerateBase;
-use Drupal\media_entity\MediaStorageInterface;
-use Symfony\Component\DependencyInjection\ContainerInterface;
-
-/**
- * Provides a MediaDevelGenerate plugin.
- *
- * @DevelGenerate(
- * id = "media",
- * label = @Translation("media"),
- * description = @Translation("Generate a given number of media entities."),
- * url = "media",
- * permission = "administer devel_generate",
- * settings = {
- * "num" = 50,
- * "kill" = FALSE,
- * "name_length" = 4
- * }
- * )
- */
-class MediaDevelGenerate extends DevelGenerateBase implements ContainerFactoryPluginInterface {
-
- /**
- * The media storage.
- *
- * @var \Drupal\media_entity\MediaStorageInterface
- */
- protected $mediaStorage;
-
- /**
- * The media bundle storage.
- *
- * @var \Drupal\Core\Entity\EntityStorageInterface
- */
- protected $mediaBundleStorage;
-
- /**
- * The user storage.
- *
- * @var \Drupal\Core\Entity\EntityStorageInterface
- */
- protected $userStorage;
-
- /**
- * The module handler.
- *
- * @var \Drupal\Core\Extension\ModuleHandlerInterface
- */
- protected $moduleHandler;
-
- /**
- * The language manager.
- *
- * @var \Drupal\Core\Language\LanguageManagerInterface
- */
- protected $languageManager;
-
- /**
- * The url generator service.
- *
- * @var \Drupal\Core\Routing\UrlGeneratorInterface
- */
- protected $urlGenerator;
-
- /**
- * The date formatter service.
- *
- * @var \Drupal\Core\Datetime\DateFormatter
- */
- protected $dateFormatter;
-
- /**
- * Database connection.
- *
- * @var Connection
- */
- protected $database;
-
- /**
- * Constructs MediaDevelGenerate class.
- *
- * @param array $configuration
- * A configuration array containing information about the plugin instance.
- * @param string $plugin_id
- * The plugin ID for the plugin instance.
- * @param array $plugin_definition
- * The plugin definition.
- * @param \Drupal\media_entity\MediaStorageInterface $media_storage
- * The media storage.
- * @param \Drupal\Core\Entity\EntityStorageInterface $user_storage
- * The user storage.
- * @param \Drupal\Core\Entity\EntityStorageInterface $media_bundle_storage
- * The media bundle storage.
- * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
- * The module handler.
- * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
- * The language manager.
- * @param \Drupal\Core\Routing\UrlGeneratorInterface $url_generator
- * The url generator service.
- * @param \Drupal\Core\Datetime\DateFormatter $date_formatter
- * The date formatter service.
- */
- public function __construct(array $configuration, $plugin_id, array $plugin_definition, MediaStorageInterface $media_storage, EntityStorageInterface $user_storage, EntityStorageInterface $media_bundle_storage, ModuleHandlerInterface $module_handler, LanguageManagerInterface $language_manager, UrlGeneratorInterface $url_generator, DateFormatter $date_formatter) {
- parent::__construct($configuration, $plugin_id, $plugin_definition);
-
- $this->moduleHandler = $module_handler;
- $this->mediaStorage = $media_storage;
- $this->mediaBundleStorage = $media_bundle_storage;
- $this->userStorage = $user_storage;
- $this->languageManager = $language_manager;
- $this->urlGenerator = $url_generator;
- $this->dateFormatter = $date_formatter;
- }
-
- /**
- * {@inheritdoc}
- */
- public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
- $entity_manager = $container->get('entity.manager');
- return new static(
- $configuration, $plugin_id, $plugin_definition,
- $entity_manager->getStorage('media'),
- $entity_manager->getStorage('user'),
- $entity_manager->getStorage('media_bundle'),
- $container->get('module_handler'),
- $container->get('language_manager'),
- $container->get('url_generator'),
- $container->get('date.formatter')
- );
- }
-
- /**
- * {@inheritdoc}
- */
- public function settingsForm(array $form, FormStateInterface $form_state) {
- $bundles = $this->mediaBundleStorage->loadMultiple();
-
- if (empty($bundles)) {
- $create_url = $this->urlGenerator->generateFromRoute('media.bundle_add');
- $this->setMessage($this->t('You do not have any media bundles that can be generated. <a href="@create-bundle">Go create a new media bundle</a>', ['@create-bundle' => $create_url]), 'error', FALSE);
- return [];
- }
-
- $options = [];
- foreach ($bundles as $bundle) {
- $options[$bundle->id()] = ['bundle' => ['#markup' => $bundle->label()]];
- }
-
- $form['media_bundles'] = [
- '#type' => 'tableselect',
- '#header' => ['bundle' => $this->t('Media bundle')],
- '#options' => $options,
- ];
-
- $form['kill'] = [
- '#type' => 'checkbox',
- '#title' => $this->t('<strong>Delete all media</strong> in these bundles before generating new media.'),
- '#default_value' => $this->getSetting('kill'),
- ];
- $form['num'] = [
- '#type' => 'number',
- '#title' => $this->t('How many media items would you like to generate?'),
- '#default_value' => $this->getSetting('num'),
- '#required' => TRUE,
- '#min' => 0,
- ];
-
- $options = [1 => $this->t('Now')];
- foreach ([3600, 86400, 604800, 2592000, 31536000] as $interval) {
- $options[$interval] = $this->dateFormatter->formatInterval($interval, 1) . ' ' . $this->t('ago');
- }
- $form['time_range'] = [
- '#type' => 'select',
- '#title' => $this->t('How far back in time should the media be dated?'),
- '#description' => $this->t('Media creation dates will be distributed randomly from the current time, back to the selected time.'),
- '#options' => $options,
- '#default_value' => 604800,
- ];
-
- $form['name_length'] = [
- '#type' => 'number',
- '#title' => $this->t('Maximum number of words in names'),
- '#default_value' => $this->getSetting('name_length'),
- '#required' => TRUE,
- '#min' => 1,
- '#max' => 255,
- ];
-
- $options = [];
- // We always need a language.
- $languages = $this->languageManager->getLanguages(LanguageInterface::STATE_ALL);
- foreach ($languages as $langcode => $language) {
- $options[$langcode] = $language->getName();
- }
-
- $form['add_language'] = [
- '#type' => 'select',
- '#title' => $this->t('Set language on media'),
- '#multiple' => TRUE,
- '#description' => $this->t('Requires locale.module'),
- '#options' => $options,
- '#default_value' => [
- $this->languageManager->getDefaultLanguage()->getId(),
- ],
- ];
-
- $form['#redirect'] = FALSE;
-
- return $form;
- }
-
- /**
- * {@inheritdoc}
- */
- protected function generateElements(array $values) {
- if ($values['num'] <= 50) {
- $this->generateMedia($values);
- }
- else {
- $this->generateBatchMedia($values);
- }
- }
-
- /**
- * Method for creating media when number of elements is less than 50.
- *
- * @param array $values
- * Array of values submitted through a form.
- */
- private function generateMedia($values) {
- $values['media_bundles'] = array_filter($values['media_bundles']);
- if (!empty($values['kill']) && $values['media_bundles']) {
- $this->mediaKill($values);
- }
-
- if (!empty($values['media_bundles'])) {
- // Generate media.
- $this->preGenerate($values);
- $start = time();
- for ($i = 1; $i <= $values['num']; $i++) {
- $this->createMediaItem($values);
- if (function_exists('drush_log') && $i % drush_get_option('feedback', 1000) == 0) {
- $now = time();
- drush_log(dt('Completed !feedback media items (!rate media/min)', [
- '!feedback' => drush_get_option('feedback', 1000),
- '!rate' => (drush_get_option('feedback', 1000) * 60) / ($now - $start),
- ]), 'ok');
- $start = $now;
- }
- }
- }
- $this->setMessage($this->formatPlural($values['num'], '1 media created.', 'Finished creating @count media items.'));
- }
-
- /**
- * Method for creating media when number of elements is greater than 50.
- *
- * @param array $values
- * The input values from the settings form.
- */
- private function generateBatchMedia($values) {
- // Setup the batch operations and save the variables.
- $operations[] = [
- 'devel_generate_operation',
- [$this, 'batchPreGenerate', $values],
- ];
-
- // Add the kill operation.
- if ($values['kill']) {
- $operations[] = [
- 'devel_generate_operation',
- [$this, 'batchMediaKill', $values],
- ];
- }
-
- // Add the operations to create the media.
- for ($num = 0; $num < $values['num']; $num++) {
- $operations[] = [
- 'devel_generate_operation',
- [$this, 'batchCreateMediaItem', $values],
- ];
- }
-
- // Start the batch.
- $batch = [
- 'title' => $this->t('Generating media'),
- 'operations' => $operations,
- 'finished' => 'devel_generate_batch_finished',
- 'file' => drupal_get_path('module', 'devel_generate') . '/devel_generate.batch.inc',
- ];
- batch_set($batch);
- }
-
- /**
- * Batch version of preGenerate().
- *
- * @param array $vars
- * The input values from the settings form.
- * @param array $context
- * Batch job context.
- */
- public function batchPreGenerate($vars, &$context) {
- $context['results'] = $vars;
- $context['results']['num'] = 0;
- $this->preGenerate($context['results']);
- }
-
- /**
- * Batch version of createMediaItem().
- *
- * @param array $vars
- * The input values from the settings form.
- * @param array $context
- * Batch job context.
- */
- public function batchCreateMediaItem($vars, &$context) {
- $this->createMediaItem($context['results']);
- $context['results']['num']++;
- }
-
- /**
- * Batch version of mediaKill().
- *
- * @param array $vars
- * The input values from the settings form.
- * @param array $context
- * Batch job context.
- */
- public function batchMediaKill($vars, &$context) {
- $this->mediaKill($context['results']);
- }
-
- /**
- * {@inheritdoc}
- */
- public function validateDrushParams($args) {
- $add_language = drush_get_option('languages');
- if (!empty($add_language)) {
- $add_language = explode(',', str_replace(' ', '', $add_language));
- // Intersect with the enabled languages to make sure the language args
- // passed are actually enabled.
- $values['values']['add_language'] = array_intersect($add_language, array_keys($this->languageManager->getLanguages(LanguageInterface::STATE_ALL)));
- }
-
- $values['kill'] = drush_get_option('kill');
- $values['name_length'] = drush_get_option('name_length', 6);
- $values['num'] = array_shift($args);
- $selected_bundles = _convert_csv_to_array(drush_get_option('bundles', []));
-
- if (empty($selected_bundles)) {
- return drush_set_error('DEVEL_GENERATE_NO_MEDIA_BUNDLES', dt('No media bundles available'));
- }
-
- $values['media_bundles'] = array_combine($selected_bundles, $selected_bundles);
-
- return $values;
- }
-
- /**
- * Deletes all media of given media bundles.
- *
- * @param array $values
- * The input values from the settings form.
- */
- protected function mediaKill($values) {
- $mids = $this->mediaStorage->getQuery()
- ->condition('bundle', $values['media_bundles'], 'IN')
- ->execute();
-
- if (!empty($mids)) {
- $media = $this->mediaStorage->loadMultiple($mids);
- $this->mediaStorage->delete($media);
- $this->setMessage($this->t('Deleted %count media items.', ['%count' => count($mids)]));
- }
- }
-
- /**
- * Code to be run before generating items.
- *
- * Returns the same array passed in as parameter, but with an array of uids
- * for the key 'users'.
- *
- * @param array $results
- * The input values from the settings form.
- */
- protected function preGenerate(&$results) {
- // Get user id.
- $users = $this->userStorage->getQuery()
- ->range(0, 50)
- ->execute();
- $users = array_merge($users, ['0']);
- $results['users'] = $users;
- }
-
- /**
- * Create one media item. Used by both batch and non-batch code branches.
- *
- * @param array $results
- * The input values from the settings form.
- */
- protected function createMediaItem(&$results) {
- if (!isset($results['time_range'])) {
- $results['time_range'] = 0;
- }
- $users = $results['users'];
-
- $bundle = array_rand(array_filter($results['media_bundles']));
- $uid = $users[array_rand($users)];
-
- $media = $this->mediaStorage->create([
- 'bundle' => $bundle,
- 'name' => $this->getRandom()->sentences(mt_rand(1, $results['name_length']), TRUE),
- 'uid' => $uid,
- 'revision' => mt_rand(0, 1),
- 'status' => TRUE,
- 'created' => REQUEST_TIME - mt_rand(0, $results['time_range']),
- 'langcode' => $this->getLangcode($results),
- ]);
-
- // A flag to let hook implementations know that this is a generated item.
- $media->devel_generate = $results;
-
- // Populate all fields with sample values.
- $this->populateFields($media);
-
- $media->save();
- }
-
- /**
- * Determine language based on $results.
- *
- * @param array $results
- * The input values from the settings form.
- */
- protected function getLangcode($results) {
- if (isset($results['add_language'])) {
- $langcodes = $results['add_language'];
- $langcode = $langcodes[array_rand($langcodes)];
- }
- else {
- $langcode = $this->languageManager->getDefaultLanguage()->getId();
- }
- return $langcode;
- }
-
-}
+++ /dev/null
-<?php
-
-namespace Drupal\media_entity\Plugin\Field\FieldFormatter;
-
-use Drupal\Core\Field\FieldItemListInterface;
-use Drupal\Core\Form\FormStateInterface;
-use Drupal\Core\Session\AccountInterface;
-use Drupal\image\Plugin\Field\FieldFormatter\ImageFormatter;
-use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem;
-use Drupal\Core\Render\RendererInterface;
-use Symfony\Component\DependencyInjection\ContainerInterface;
-use Drupal\Core\Field\FieldDefinitionInterface;
-use Drupal\Core\Entity\EntityStorageInterface;
-
-/**
- * Plugin implementation of the 'media_thumbnail' formatter.
- *
- * @FieldFormatter(
- * id = "media_thumbnail",
- * label = @Translation("Thumbnail"),
- * field_types = {
- * "entity_reference"
- * }
- * )
- */
-class MediaThumbnailFormatter extends ImageFormatter {
-
- /**
- * The renderer service.
- *
- * @var \Drupal\Core\Render\RendererInterface
- */
- protected $renderer;
-
- /**
- * Constructs an ImageFormatter object.
- *
- * @param string $plugin_id
- * The plugin_id for the formatter.
- * @param mixed $plugin_definition
- * The plugin implementation definition.
- * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
- * The definition of the field to which the formatter is associated.
- * @param array $settings
- * The formatter settings.
- * @param string $label
- * The formatter label display setting.
- * @param string $view_mode
- * The view mode.
- * @param array $third_party_settings
- * Any third party settings settings.
- * @param \Drupal\Core\Session\AccountInterface $current_user
- * The current user.
- * @param \Drupal\Core\Render\RendererInterface $renderer
- * The renderer service.
- */
- public function __construct($plugin_id, $plugin_definition, FieldDefinitionInterface $field_definition, array $settings, $label, $view_mode, array $third_party_settings, AccountInterface $current_user, EntityStorageInterface $image_style_storage, RendererInterface $renderer) {
- parent::__construct($plugin_id, $plugin_definition, $field_definition, $settings, $label, $view_mode, $third_party_settings, $current_user, $image_style_storage);
- $this->renderer = $renderer;
- }
-
- /**
- * {@inheritdoc}
- */
- public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
- return new static(
- $plugin_id,
- $plugin_definition,
- $configuration['field_definition'],
- $configuration['settings'],
- $configuration['label'],
- $configuration['view_mode'],
- $configuration['third_party_settings'],
- $container->get('current_user'),
- $container->get('entity.manager')->getStorage('image_style'),
- $container->get('renderer')
- );
- }
-
- /**
- * {@inheritdoc}
- *
- * This has to be overriden because FileFormatterBase expects $item to be
- * of type \Drupal\file\Plugin\Field\FieldType\FileItem and calls
- * isDisplayed() which is not in FieldItemInterface.
- */
- protected function needsEntityLoad(EntityReferenceItem $item) {
- return !$item->hasNewEntity();
- }
-
- /**
- * {@inheritdoc}
- */
- public function settingsForm(array $form, FormStateInterface $form_state) {
- $element = parent::settingsForm($form, $form_state);
-
- $link_types = [
- 'content' => $this->t('Content'),
- 'media' => $this->t('Media entity'),
- ];
- $element['image_link']['#options'] = $link_types;
-
- return $element;
- }
-
- /**
- * {@inheritdoc}
- */
- public function settingsSummary() {
- $summary = parent::settingsSummary();
-
- $link_types = [
- 'content' => $this->t('Linked to content'),
- 'media' => $this->t('Linked to media entity'),
- ];
- // Display this setting only if image is linked.
- $image_link_setting = $this->getSetting('image_link');
- if (isset($link_types[$image_link_setting])) {
- $summary[] = $link_types[$image_link_setting];
- }
-
- return $summary;
- }
-
- /**
- * {@inheritdoc}
- */
- public function viewElements(FieldItemListInterface $items, $langcode) {
- $elements = [];
- $media = $this->getEntitiesToView($items, $langcode);
-
- // Early opt-out if the field is empty.
- if (empty($media)) {
- return $elements;
- }
-
- $url = NULL;
- $image_link_setting = $this->getSetting('image_link');
- // Check if the formatter involves a link.
- if ($image_link_setting == 'content') {
- $entity = $items->getEntity();
- if (!$entity->isNew()) {
- $url = $entity->toUrl();
- }
- }
- elseif ($image_link_setting == 'media') {
- $link_media = TRUE;
- }
-
- $image_style_setting = $this->getSetting('image_style');
-
- /** @var \Drupal\media_entity\MediaInterface $media_item */
- foreach ($media as $delta => $media_item) {
- if (isset($link_media)) {
- $url = $media_item->toUrl();
- }
-
- $elements[$delta] = [
- '#theme' => 'image_formatter',
- '#item' => $media_item->get('thumbnail'),
- '#item_attributes' => [],
- '#image_style' => $image_style_setting,
- '#url' => $url,
- ];
-
- // Collect cache tags to be added for each item in the field.
- $this->renderer->addCacheableDependency($elements[$delta], $media_item);
- }
-
- // Collect cache tags related to the image style setting.
- $image_style = $this->imageStyleStorage->load($image_style_setting);
- $this->renderer->addCacheableDependency($elements, $image_style);
-
- return $elements;
- }
-
- /**
- * {@inheritdoc}
- */
- public static function isApplicable(FieldDefinitionInterface $field_definition) {
- // This formatter is only available for entity types that reference
- // media entities.
- $target_type = $field_definition->getFieldStorageDefinition()->getSetting('target_type');
- return $target_type == 'media';
- }
-
-}
+++ /dev/null
-<?php
-
-namespace Drupal\media_entity\Plugin\MediaEntity\Type;
-
-use Drupal\Core\Form\FormStateInterface;
-use Drupal\media_entity\MediaInterface;
-use Drupal\media_entity\MediaTypeBase;
-
-/**
- * Provides generic media type.
- *
- * @MediaType(
- * id = "generic",
- * label = @Translation("Generic media"),
- * description = @Translation("Generic media type.")
- * )
- */
-class Generic extends MediaTypeBase {
-
- /**
- * {@inheritdoc}
- */
- public function providedFields() {
- return [];
- }
-
- /**
- * {@inheritdoc}
- */
- public function getField(MediaInterface $media, $name) {
- return FALSE;
- }
-
- /**
- * {@inheritdoc}
- */
- public function thumbnail(MediaInterface $media) {
- return $this->config->get('icon_base') . '/generic.png';
- }
-
- /**
- * {@inheritdoc}
- */
- public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
- $form['text'] = [
- '#type' => 'markup',
- '#markup' => $this->t("This type provider doesn't need configuration."),
- ];
-
- return $form;
- }
-
-}
+++ /dev/null
-<?php
-
-namespace Drupal\media_entity\Plugin\QueueWorker;
-
-use Drupal\media_entity\Entity\Media;
-use Drupal\Core\Queue\QueueWorkerBase;
-
-/**
- * Download images.
- *
- * @QueueWorker(
- * id = "media_entity_thumbnail",
- * title = @Translation("Thumbnail downloader"),
- * cron = {"time" = 60}
- * )
- */
-class ThumbnailDownloader extends QueueWorkerBase {
-
- /**
- * {@inheritdoc}
- */
- public function processItem($data) {
- if ($entity = Media::load($data['id'])) {
- // Indicate that the entity is being processed from a queue and that
- // thumbnail images should be downloaded.
- $entity->setQueuedThumbnailDownload();
- $entity->save();
- }
- }
-
-}
+++ /dev/null
-<?php
-
-namespace Drupal\media_entity\Plugin\views\wizard;
-
-use Drupal\views\Plugin\views\wizard\WizardPluginBase;
-
-/**
- * Tests creating media views with the wizard.
- *
- * @ViewsWizard(
- * id = "media",
- * base_table = "media_field_data",
- * title = @Translation("Media")
- * )
- */
-class Media extends WizardPluginBase {
-
- /**
- * Set the created column.
- */
- protected $createdColumn = 'media_field_data-created';
-
- /**
- * Set default values for the filters.
- */
- protected $filters = [
- 'status' => [
- 'value' => TRUE,
- 'table' => 'media_field_data',
- 'field' => 'status',
- 'plugin_id' => 'boolean',
- 'entity_type' => 'media',
- 'entity_field' => 'status',
- ],
- ];
-
- /**
- * {@inheritdoc}
- */
- public function getAvailableSorts() {
- return [
- 'media_field_data-name:DESC' => $this->t('Media name'),
- ];
- }
-
- /**
- * {@inheritdoc}
- */
- protected function defaultDisplayOptions() {
- $display_options = parent::defaultDisplayOptions();
-
- // Add permission-based access control.
- $display_options['access']['type'] = 'perm';
- $display_options['access']['options']['perm'] = 'access content';
-
- // Remove the default fields, since we are customizing them here.
- unset($display_options['fields']);
-
- // Add the name field, so that the display has content if the user switches
- // to a row style that uses fields.
- /* Field: Media: Name */
- $display_options['fields']['name']['id'] = 'name';
- $display_options['fields']['name']['table'] = 'media_field_data';
- $display_options['fields']['name']['field'] = 'name';
- $display_options['fields']['name']['entity_type'] = 'media';
- $display_options['fields']['name']['entity_field'] = 'media';
- $display_options['fields']['name']['label'] = '';
- $display_options['fields']['name']['alter']['alter_text'] = 0;
- $display_options['fields']['name']['alter']['make_link'] = 0;
- $display_options['fields']['name']['alter']['absolute'] = 0;
- $display_options['fields']['name']['alter']['trim'] = 0;
- $display_options['fields']['name']['alter']['word_boundary'] = 0;
- $display_options['fields']['name']['alter']['ellipsis'] = 0;
- $display_options['fields']['name']['alter']['strip_tags'] = 0;
- $display_options['fields']['name']['alter']['html'] = 0;
- $display_options['fields']['name']['hide_empty'] = 0;
- $display_options['fields']['name']['empty_zero'] = 0;
- $display_options['fields']['name']['settings']['link_to_entity'] = 1;
- $display_options['fields']['name']['plugin_id'] = 'field';
-
- return $display_options;
- }
-
-}
+++ /dev/null
-<?php
-
-namespace Drupal\media_entity\Plugin\views\wizard;
-
-use Drupal\views\Plugin\views\wizard\WizardPluginBase;
-
-/**
- * Tests creating media revision views with the wizard.
- *
- * @ViewsWizard(
- * id = "media_revision",
- * base_table = "media_field_revision",
- * title = @Translation("Media revisions")
- * )
- */
-class MediaRevision extends WizardPluginBase {
-
- /**
- * Set the created column.
- */
- protected $createdColumn = 'changed';
-
- /**
- * Set default values for the filters.
- */
- protected $filters = [
- 'status' => [
- 'value' => TRUE,
- 'table' => 'media_field_revision',
- 'field' => 'status',
- 'plugin_id' => 'boolean',
- 'entity_type' => 'media',
- 'entity_field' => 'status',
- ],
- ];
-
- /**
- * {@inheritdoc}
- */
- protected function defaultDisplayOptions() {
- $display_options = parent::defaultDisplayOptions();
-
- // Add permission-based access control.
- $display_options['access']['type'] = 'perm';
- $display_options['access']['options']['perm'] = 'view all revisions';
-
- // Remove the default fields, since we are customizing them here.
- unset($display_options['fields']);
-
- /* Field: Media revision: Created date */
- $display_options['fields']['changed']['id'] = 'changed';
- $display_options['fields']['changed']['table'] = 'media_field_revision';
- $display_options['fields']['changed']['field'] = 'changed';
- $display_options['fields']['changed']['entity_type'] = 'media';
- $display_options['fields']['changed']['entity_field'] = 'changed';
- $display_options['fields']['changed']['alter']['alter_text'] = FALSE;
- $display_options['fields']['changed']['alter']['make_link'] = FALSE;
- $display_options['fields']['changed']['alter']['absolute'] = FALSE;
- $display_options['fields']['changed']['alter']['trim'] = FALSE;
- $display_options['fields']['changed']['alter']['word_boundary'] = FALSE;
- $display_options['fields']['changed']['alter']['ellipsis'] = FALSE;
- $display_options['fields']['changed']['alter']['strip_tags'] = FALSE;
- $display_options['fields']['changed']['alter']['html'] = FALSE;
- $display_options['fields']['changed']['hide_empty'] = FALSE;
- $display_options['fields']['changed']['empty_zero'] = FALSE;
- $display_options['fields']['changed']['plugin_id'] = 'field';
- $display_options['fields']['changed']['type'] = 'timestamp';
- $display_options['fields']['changed']['settings']['date_format'] = 'medium';
- $display_options['fields']['changed']['settings']['custom_date_format'] = '';
- $display_options['fields']['changed']['settings']['timezone'] = '';
-
- /* Field: Media revision: Name */
- $display_options['fields']['name']['id'] = 'name';
- $display_options['fields']['name']['table'] = 'media_field_revision';
- $display_options['fields']['name']['field'] = 'name';
- $display_options['fields']['name']['entity_type'] = 'media';
- $display_options['fields']['name']['entity_field'] = 'name';
- $display_options['fields']['name']['label'] = '';
- $display_options['fields']['name']['alter']['alter_text'] = 0;
- $display_options['fields']['name']['alter']['make_link'] = 0;
- $display_options['fields']['name']['alter']['absolute'] = 0;
- $display_options['fields']['name']['alter']['trim'] = 0;
- $display_options['fields']['name']['alter']['word_boundary'] = 0;
- $display_options['fields']['name']['alter']['ellipsis'] = 0;
- $display_options['fields']['name']['alter']['strip_tags'] = 0;
- $display_options['fields']['name']['alter']['html'] = 0;
- $display_options['fields']['name']['hide_empty'] = 0;
- $display_options['fields']['name']['empty_zero'] = 0;
- $display_options['fields']['name']['settings']['link_to_entity'] = 0;
- $display_options['fields']['name']['plugin_id'] = 'field';
-
- return $display_options;
- }
-
-}
+++ /dev/null
-{#
-/**
- * @file
- * Default theme implementation to present a media entity.
- *
- * Available variables:
- * - name: Name of the media.
- * - content: Media content.
- *
- * @see template_preprocess_media()
- *
- * @ingroup themeable
- */
-#}
-<article{{ attributes }}>
- {% if content %}
- {{ content }}
- {% endif %}
-</article>
+++ /dev/null
-id: test
-label: 'Test bundle'
-description: 'Test bundle.'
-type: generic
-type_configuration: { }
-status: true
-langcode: en
-dependencies: { }
-field_map: { }
+++ /dev/null
-name: 'Media entity test bundle'
-type: module
-description: 'Provides test bundle for media entity.'
-# core: 8.x
-package: Testing
-# version: VERSION
-
-# Information added by Drupal.org packaging script on 2017-11-15
-version: '8.x-1.7'
-core: '8.x'
-project: 'media_entity'
-datestamp: 1510737188
+++ /dev/null
-media_entity.bundle.type.test_type:
- type: mapping
- label: 'Test type configuration'
- mapping:
- test_config_value:
- type: string
- label: 'Test config value'
+++ /dev/null
-name: 'Test media type'
-type: module
-description: 'Provides test media type plugin to test configuration forms.'
-# core: 8.x
-package: Testing
-# version: VERSION
-
-# Information added by Drupal.org packaging script on 2017-11-15
-version: '8.x-1.7'
-core: '8.x'
-project: 'media_entity'
-datestamp: 1510737188
+++ /dev/null
-<?php
-
-namespace Drupal\media_entity_test_type\Plugin\MediaEntity\Type;
-
-use Drupal\Core\Form\FormStateInterface;
-use Drupal\media_entity\Plugin\MediaEntity\Type\Generic;
-
-/**
- * Provides generic media type.
- *
- * @MediaType(
- * id = "test_type",
- * label = @Translation("Test type"),
- * description = @Translation("Test media type.")
- * )
- */
-class TestType extends Generic {
-
- /**
- * {@inheritdoc}
- */
- public function providedFields() {
- return [
- 'field_1' => $this->t('Field 1'),
- 'field_2' => $this->t('Field 2'),
- ];
- }
-
- /**
- * {@inheritdoc}
- */
- public function defaultConfiguration() {
- return [
- 'test_config_value' => 'This is default value.',
- ];
- }
-
- /**
- * {@inheritdoc}
- */
- public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
- $form['test_config_value'] = [
- '#type' => 'textfield',
- '#title' => $this->t('Test config value'),
- '#default_value' => empty($this->configuration['test_config_value']) ? NULL : $this->configuration['test_config_value'],
- ];
-
- return $form;
- }
-
-}
+++ /dev/null
-name: 'Media Entity test views'
-type: module
-description: 'Provides default views for views media entity tests.'
-package: Testing
-# version: VERSION
-# core: 8.x
-dependencies:
- - media_entity
- - views
-
-# Information added by Drupal.org packaging script on 2017-11-15
-version: '8.x-1.7'
-core: '8.x'
-project: 'media_entity'
-datestamp: 1510737188
--- /dev/null
+<?php
+
+namespace Drupal\Tests\media_entity\Functional;
+
+use Drupal\Core\Config\Entity\Query\QueryFactory;
+use Drupal\FunctionalTests\Update\UpdatePathTestBase;
+
+/**
+ * @group media_entity
+ */
+class CoreMediaUpdatePathTest extends UpdatePathTestBase {
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function setDatabaseDumpFiles() {
+ $this->databaseDumpFiles = [
+ __DIR__ . '/../../fixtures/drupal-8.4.0-media-entity.php.gz',
+ ];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function setUp() {
+ parent::setUp();
+
+ // All this can be removed when #2877383 lands.
+ $this->config('system.action.media_delete_action')->delete();
+ $this->config('system.action.media_publish_action')->delete();
+ $this->config('system.action.media_save_action')->delete();
+ $this->config('system.action.media_unpublish_action')->delete();
+
+ $this->config('views.view.media')
+ ->clear('display.default.display_options.fields.media_bulk_form')
+ ->save();
+ }
+
+ public function testUpdatePath() {
+ $icon_base_uri = $this->config('media_entity.settings')->get('icon_base');
+
+ $this->runUpdates();
+ $assert = $this->assertSession();
+
+ // As with all translatable, versionable content entity types, media
+ // entities should have the revision_translation_affected base field.
+ // This may have been created during the update path by system_update_8402,
+ // so we should check for it here.
+ /** @var \Drupal\Core\Entity\EntityFieldManagerInterface $field_manager */
+ $field_manager = $this->container->get('entity_field.manager');
+ $this->assertArrayHasKey('revision_translation_affected', $field_manager->getBaseFieldDefinitions('media'));
+ $field_manager->clearCachedFieldDefinitions();
+
+ $this->drupalLogin($this->rootUser);
+ $this->drupalGet('/admin/modules');
+ $assert->checkboxNotChecked('modules[media_entity_document][enable]');
+ $assert->checkboxNotChecked('modules[media_entity_image][enable]');
+ $assert->checkboxNotChecked('modules[media_entity][enable]');
+ $assert->checkboxChecked('modules[media_entity_generic][enable]');
+ // Media is not currently displayed on the Modules page.
+ $this->assertArrayHasKey('media', $this->config('core.extension')->get('module'));
+
+ $this->drupalGet('/admin/structure/media/manage/file');
+ $assert->statusCodeEquals(200);
+ $assert->fieldValueEquals('source', 'file');
+ $assert->pageTextContains('File field is used to store the essential information');
+
+ $this->drupalGet('/admin/structure/media/manage/image');
+ $assert->statusCodeEquals(200);
+ $assert->fieldValueEquals('source', 'image');
+ $assert->pageTextContains('Image field is used to store the essential information');
+
+ $this->drupalGet('/admin/structure/media/manage/generic');
+ $assert->statusCodeEquals(200);
+ $assert->fieldValueEquals('source', 'generic');
+ $assert->pageTextContains('Generic media field is used to store the essential information');
+
+ $this->assertFrontPageMedia('Image 3', 'main img');
+ $this->assertFrontPageMedia('Generic 1', 'main img[src *= "/media-icons/generic/generic.png"]');
+ $this->assertFrontPageMedia('File 2', 'main img[src *= "/media-icons/generic/document.png"]');
+ $this->assertFrontPageMedia('File 3', 'main img[src *= "/media-icons/generic/document.png"]');
+ $this->assertFrontPageMedia('Image 1', 'main img');
+ $this->assertFrontPageMedia('Generic 3', 'main img[src *= "/media-icons/generic/generic.png"]');
+
+ // Assert that Media Entity's config is migrated.
+ $this->assertTrue($this->config('media_entity.settings')->isNew());
+ $this->assertEquals($icon_base_uri, $this->config('media.settings')->get('icon_base_uri'));
+ $this->assertEmpty(
+ $this->container->get('config.factory')->listAll('media_entity.bundle')
+ );
+
+ $this->activateModule();
+ /** @var \Drupal\Core\Entity\EntityStorageInterface $storage */
+ $storage = $this->container
+ ->get('entity_type.manager')
+ ->getStorage('media_type');
+
+ foreach (['file', 'image', 'generic'] as $type) {
+ $config = $this->config("media.type.$type");
+ $this->assertFalse($config->isNew());
+ $this->assertNull($config->get('type'));
+ $this->assertNull($config->get('type_configuration'));
+ $this->assertInternalType('string', $config->get('source'));
+ $this->assertInternalType('array', $config->get('source_configuration'));
+ $this->assertInternalType('string', $config->get('source_configuration.source_field'));
+
+ // Ensure that the media type can be queried by UUID.
+ $uuid = $config->get('uuid');
+ $this->assertNotEmpty($uuid);
+ $result = $storage->getQuery()->condition('uuid', $uuid)->execute();
+ $this->assertEquals($result[$type], $type);
+ }
+
+ // The UUID map for legacy media bundles should be cleared out.
+ $old_uuid_map = $this->container
+ ->get('keyvalue')
+ ->get(QueryFactory::CONFIG_LOOKUP_PREFIX . 'media_bundle')
+ ->getAll();
+ $this->assertEmpty($old_uuid_map);
+ }
+
+ protected function assertFrontPageMedia($link, $assert_selectors) {
+ $this->drupalGet('<front>');
+ $this->clickLink($link);
+
+ $assert = $this->assertSession();
+ foreach ((array) $assert_selectors as $selector) {
+ $assert->elementExists('css', $selector);
+ }
+ }
+
+ /**
+ * Activates the Media module in PHPUnit's memory space.
+ */
+ protected function activateModule() {
+ $this->container
+ ->get('module_handler')
+ ->addModule('media', 'core/modules/media');
+
+ /** @var \ArrayObject $namespaces */
+ $namespaces = $this->container->get('container.namespaces');
+ $namespaces['Drupal\\media'] = 'core/modules/media/src';
+
+ $this->container
+ ->get('entity_type.manager')
+ ->clearCachedDefinitions();
+ }
+
+}
+++ /dev/null
-<?php
-
-namespace Drupal\Tests\media_entity\Functional;
-
-use Drupal\media_entity\Entity\Media;
-use Drupal\user\Entity\Role;
-
-/**
- * Basic access tests for Media Entity.
- *
- * @group media_entity
- */
-class MediaAccessTest extends MediaEntityFunctionalTestBase {
-
- /**
- * The test media bundle.
- *
- * @var \Drupal\media_entity\MediaBundleInterface
- */
- protected $testBundle;
-
- /**
- * {@inheritdoc}
- */
- protected function setUp() {
- parent::setUp();
- $this->testBundle = $this->drupalCreateMediaBundle();
- }
-
- /**
- * Test some access control functionality.
- */
- public function testMediaAccess() {
-
- $assert_session = $this->assertSession();
-
- // Create media.
- $media = Media::create([
- 'bundle' => $this->testBundle->id(),
- 'name' => 'Unnamed',
- ]);
- $media->save();
- $user_media = Media::create([
- 'bundle' => $this->testBundle->id(),
- 'name' => 'Unnamed',
- 'uid' => $this->nonAdminUser->id(),
- ]);
- $user_media->save();
-
- // We are logged-in as admin, so test 'administer media' permission.
- $this->drupalGet('media/' . $user_media->id());
- $assert_session->statusCodeEquals(200);
- $this->drupalGet('media/' . $user_media->id() . '/edit');
- $assert_session->statusCodeEquals(200);
- $this->drupalGet('media/' . $user_media->id() . '/delete');
- $assert_session->statusCodeEquals(200);
-
- $this->drupalLogin($this->nonAdminUser);
- /** @var \Drupal\user\RoleInterface $role */
- $role = Role::load('authenticated');
-
- // Test 'view media' permission.
- $this->drupalGet('media/' . $media->id());
- $assert_session->statusCodeEquals(403);
- $this->grantPermissions($role, ['view media']);
- $this->drupalGet('media/' . $media->id());
- $assert_session->statusCodeEquals(200);
-
- // Test 'create media' permission.
- $this->drupalGet('media/add/' . $this->testBundle->id());
- $assert_session->statusCodeEquals(403);
- $this->grantPermissions($role, ['create media']);
- $this->drupalGet('media/add/' . $this->testBundle->id());
- $assert_session->statusCodeEquals(200);
-
- // Test 'update media' and 'delete media' permissions.
- $this->drupalGet('media/' . $user_media->id() . '/edit');
- $assert_session->statusCodeEquals(403);
- $this->drupalGet('media/' . $user_media->id() . '/delete');
- $assert_session->statusCodeEquals(403);
- $this->grantPermissions($role, ['update media']);
- $this->grantPermissions($role, ['delete media']);
- $this->drupalGet('media/' . $user_media->id() . '/edit');
- $assert_session->statusCodeEquals(200);
- $this->drupalGet('media/' . $user_media->id() . '/delete');
- $assert_session->statusCodeEquals(200);
-
- // Test 'update any media' and 'delete any media' permissions.
- $this->drupalGet('media/' . $media->id() . '/edit');
- $assert_session->statusCodeEquals(403);
- $this->drupalGet('media/' . $media->id() . '/delete');
- $assert_session->statusCodeEquals(403);
- $this->grantPermissions($role, ['update any media']);
- $this->grantPermissions($role, ['delete any media']);
- $this->drupalGet('media/' . $media->id() . '/edit');
- $assert_session->statusCodeEquals(200);
- $this->drupalGet('media/' . $media->id() . '/delete');
- $assert_session->statusCodeEquals(200);
-
- }
-
-}
+++ /dev/null
-<?php
-
-namespace Drupal\Tests\media_entity\Functional;
-
-use Drupal\Tests\BrowserTestBase;
-
-/**
- * Base class for Media Entity functional tests.
- *
- * @package Drupal\Tests\media_entity\Functional
- */
-abstract class MediaEntityFunctionalTestBase extends BrowserTestBase {
-
- use MediaEntityFunctionalTestTrait;
-
- /**
- * Modules to enable.
- *
- * @var array
- */
- public static $modules = [
- 'system',
- 'node',
- 'field_ui',
- 'views_ui',
- 'entity',
- 'media_entity',
- ];
-
- /**
- * Permissions for the admin user that will be logged-in for test.
- *
- * @var array
- */
- protected static $adminUserPermissions = [
- // Media entity permissions.
- 'administer media',
- 'administer media fields',
- 'administer media form display',
- 'administer media display',
- 'administer media bundles',
- 'view media',
- 'create media',
- 'update media',
- 'update any media',
- 'delete media',
- 'delete any media',
- 'access media overview',
- // Other permissions.
- 'administer views',
- 'access content overview',
- 'view all revisions',
- 'administer content types',
- 'administer node fields',
- 'administer node form display',
- 'bypass node access',
- ];
-
- /**
- * An admin test user account.
- *
- * @var \Drupal\Core\Session\AccountInterface;
- */
- protected $adminUser;
-
- /**
- * A non-admin test user account.
- *
- * @var \Drupal\Core\Session\AccountInterface;
- */
- protected $nonAdminUser;
-
- /**
- * The storage service.
- *
- * @var \Drupal\Core\Entity\EntityStorageInterface;
- */
- protected $storage;
-
- /**
- * {@inheritdoc}
- */
- protected function setUp() {
- parent::setUp();
-
- // Have two users ready to be used in tests.
- $this->adminUser = $this->drupalCreateUser(static::$adminUserPermissions);
- $this->nonAdminUser = $this->drupalCreateUser([]);
- // Start off logged in as admin.
- $this->drupalLogin($this->adminUser);
-
- $this->storage = $this->container->get('entity_type.manager')->getStorage('media');
- }
-
-}
+++ /dev/null
-<?php
-
-namespace Drupal\Tests\media_entity\Functional;
-
-use Drupal\media_entity\Entity\MediaBundle;
-
-/**
- * Trait with helpers for Media Entity functional tests.
- *
- * @package Drupal\Tests\media_entity\Functional
- */
-trait MediaEntityFunctionalTestTrait {
-
- /**
- * Creates a media bundle.
- *
- * @param array $values
- * The media bundle values.
- * @param string $type_name
- * (optional) The media type provider plugin that is responsible for
- * additional logic related to this media).
- *
- * @return \Drupal\Core\Entity\EntityInterface
- * Returns newly created media bundle.
- */
- protected function drupalCreateMediaBundle(array $values = [], $type_name = 'generic') {
- if (!isset($values['bundle'])) {
- $id = strtolower($this->randomMachineName());
- }
- else {
- $id = $values['bundle'];
- }
- $values += [
- 'id' => $id,
- 'label' => $id,
- 'type' => $type_name,
- 'type_configuration' => [],
- 'field_map' => [],
- 'new_revision' => FALSE,
- ];
-
- $bundle = MediaBundle::create($values);
- $status = $bundle->save();
-
- $this->assertEquals($status, SAVED_NEW, 'Could not create a media bundle of type ' . $type_name . '.');
-
- return $bundle;
- }
-
-}
+++ /dev/null
-<?php
-
-namespace Drupal\Tests\media_entity\Functional;
-
-use Drupal\media_entity\Entity\Media;
-
-/**
- * Ensures that media UI works correctly.
- *
- * @group media_entity
- */
-class MediaUiFunctionalTest extends MediaEntityFunctionalTestBase {
-
- /**
- * Modules to enable.
- *
- * @var array
- */
- public static $modules = [
- 'block',
- 'media_entity_test_type',
- ];
-
- /**
- * The test media bundle.
- *
- * @var \Drupal\media_entity\MediaBundleInterface
- */
- protected $testBundle;
-
- /**
- * {@inheritdoc}
- */
- protected function setUp() {
- parent::setUp();
- $this->drupalPlaceBlock('local_actions_block');
- $this->drupalPlaceBlock('local_tasks_block');
- }
-
- /**
- * Tests the media actions (add/edit/delete).
- */
- public function testMediaWithOnlyOneBundle() {
- $session = $this->getSession();
- $page = $session->getPage();
- $assert_session = $this->assertSession();
-
- /** @var \Drupal\media_entity\MediaBundleInterface $bundle */
- $bundle = $this->drupalCreateMediaBundle();
-
- // Assert that media item list is empty.
- $this->drupalGet('admin/content/media');
- $assert_session->statusCodeEquals(200);
- $assert_session->pageTextContains('No content available.');
-
- $this->drupalGet('media/add');
- $assert_session->statusCodeEquals(200);
- $assert_session->addressEquals('media/add/' . $bundle->id());
- $assert_session->checkboxChecked('edit-revision');
-
- // Tests media item add form.
- $media_name = $this->randomMachineName();
- $page->fillField('name[0][value]', $media_name);
- $revision_log_message = $this->randomString();
- $page->fillField('revision_log', $revision_log_message);
- $page->pressButton('Save and publish');
- $media_id = $this->container->get('entity.query')->get('media')->execute();
- $media_id = reset($media_id);
- /** @var \Drupal\media_entity\MediaInterface $media */
- $media = $this->container->get('entity_type.manager')
- ->getStorage('media')
- ->loadUnchanged($media_id);
- $this->assertEquals($media->getRevisionLogMessage(), $revision_log_message);
- $assert_session->titleEquals($media->label() . ' | Drupal');
-
- // Test if the media list contains exactly 1 media bundle.
- $this->drupalGet('admin/content/media');
- $assert_session->statusCodeEquals(200);
- $assert_session->pageTextContains($media->label());
-
- // Tests media edit form.
- $media_name2 = $this->randomMachineName();
- $this->drupalGet('media/' . $media_id . '/edit');
- $assert_session->checkboxNotChecked('edit-revision');
- $media_name = $this->randomMachineName();
- $page->fillField('name[0][value]', $media_name2);
- $page->pressButton('Save and keep published');
- $assert_session->titleEquals($media_name2 . ' | Drupal');
-
- // Assert that the media list updates after an edit.
- $this->drupalGet('admin/content/media');
- $assert_session->statusCodeEquals(200);
- $assert_session->pageTextContains($media_name2);
-
- // Test that there is no empty vertical tabs element, if the container is
- // empty (see #2750697).
- // Make the "Publisher ID" and "Created" fields hidden.
- $this->drupalGet('/admin/structure/media/manage/' . $bundle->id . '/form-display');
- $page->selectFieldOption('fields[created][parent]', 'hidden');
- $page->selectFieldOption('fields[uid][parent]', 'hidden');
- $page->pressButton('Save');
- // Assure we are testing with a user without permission to manage revisions.
- $this->drupalLogin($this->nonAdminUser);
- // Check the container is not present.
- $this->drupalGet('media/' . $media_id . '/edit');
- // An empty tab container would look like this.
- $raw_html = '<div data-drupal-selector="edit-advanced" data-vertical-tabs-panes><input class="vertical-tabs__active-tab" data-drupal-selector="edit-advanced-active-tab" type="hidden" name="advanced__active_tab" value="" />' . "\n" . '</div>';
- $assert_session->responseNotContains($raw_html);
- // Continue testing as admin.
- $this->drupalLogin($this->adminUser);
-
- // Enable revisions by default.
- $bundle->setNewRevision(TRUE);
- $bundle->save();
- $this->drupalGet('media/' . $media_id . '/edit');
- $assert_session->checkboxChecked('edit-revision');
- $page->fillField('name[0][value]', $media_name);
- $page->fillField('revision_log', $revision_log_message);
- $page->pressButton('Save and keep published');
- $assert_session->titleEquals($media_name . ' | Drupal');
- /** @var \Drupal\media_entity\MediaInterface $media */
- $media = $this->container->get('entity_type.manager')
- ->getStorage('media')
- ->loadUnchanged($media_id);
- $this->assertEquals($media->getRevisionLogMessage(), $revision_log_message);
-
- // Tests media delete form.
- $this->drupalGet('media/' . $media_id . '/edit');
- $page->clickLink('Delete');
- $assert_session->pageTextContains('This action cannot be undone');
- $page->pressButton('Delete');
- $media_id = \Drupal::entityQuery('media')->execute();
- $this->assertFalse($media_id);
-
- // Assert that the media list is empty after deleting the media item.
- $this->drupalGet('admin/content/media');
- $assert_session->statusCodeEquals(200);
- $assert_session->pageTextNotContains($media_name);
- $assert_session->pageTextContains('No content available.');
-
- }
-
- /**
- * Tests the "media/add" and "admin/content/media" pages.
- *
- * Tests if the "media/add" page gives you a selecting option if there are
- * multiple media bundles available.
- */
- public function testMediaWithMultipleBundles() {
- $session = $this->getSession();
- $page = $session->getPage();
- $assert_session = $this->assertSession();
-
- // Test access to media overview page.
- $this->drupalLogout();
- $this->drupalGet('admin/content/media');
- $assert_session->statusCodeEquals(403);
-
- $this->drupalLogin($this->adminUser);
- $this->drupalGet('admin/content');
-
- // Test there is a media tab in the menu.
- $page->clickLink('Media');
- $assert_session->statusCodeEquals(200);
- $assert_session->pageTextContains('No content available.');
-
- // Tests and creates the first media bundle.
- $first_media_bundle = $this->drupalCreateMediaBundle(['description' => $this->randomMachineName(32)]);
-
- // Test and create a second media bundle.
- $second_media_bundle = $this->drupalCreateMediaBundle(['description' => $this->randomMachineName(32)]);
-
- // Test if media/add displays two media bundle options.
- $this->drupalGet('media/add');
-
- // Checks for the first media bundle.
- $assert_session->pageTextContains($first_media_bundle->label());
- $assert_session->pageTextContains($first_media_bundle->description);
- // Checks for the second media bundle.
- $assert_session->pageTextContains($second_media_bundle->label());
- $assert_session->pageTextContains($second_media_bundle->description);
-
- // Continue testing media bundle filter.
- $first_media_item = Media::create(['bundle' => $first_media_bundle->id()]);
- $first_media_item->save();
- $second_media_item = Media::create(['bundle' => $second_media_bundle->id()]);
- $second_media_item->save();
-
- // Go to media item list.
- $this->drupalGet('admin/content/media');
- $assert_session->statusCodeEquals(200);
- $assert_session->linkExists('Add media');
-
- // Assert that all available media items are in the list.
- $assert_session->pageTextContains($first_media_item->label());
- $assert_session->pageTextContains($first_media_bundle->label());
- $assert_session->pageTextContains($second_media_item->label());
- $assert_session->pageTextContains($second_media_bundle->label());
-
- // Filter for each bundle and assert that the list has been updated.
- $this->drupalGet('admin/content/media', ['query' => ['provider' => $first_media_bundle->id()]]);
- $assert_session->statusCodeEquals(200);
- $assert_session->pageTextContains($first_media_item->label());
- $assert_session->pageTextNotContains($second_media_item->label());
-
- // Filter all and check for all items again.
- $this->drupalGet('admin/content/media', ['query' => ['provider' => 'All']]);
- $assert_session->statusCodeEquals(200);
- $assert_session->pageTextContains($first_media_item->label());
- $assert_session->pageTextContains($first_media_bundle->label());
- $assert_session->pageTextContains($second_media_item->label());
- $assert_session->pageTextContains($second_media_bundle->label());
-
- }
-
-}
+++ /dev/null
-<?php
-
-namespace Drupal\Tests\media_entity\FunctionalJavascript;
-
-use Drupal\FunctionalJavascriptTests\JavascriptTestBase;
-use Drupal\Tests\media_entity\Functional\MediaEntityFunctionalTestTrait;
-
-/**
- * Base class for Media Entity Javascript functional tests.
- *
- * @package Drupal\Tests\media_entity\FunctionalJavascript
- */
-abstract class MediaEntityJavascriptTestBase extends JavascriptTestBase {
-
- use MediaEntityFunctionalTestTrait;
-
- /**
- * Modules to enable.
- *
- * @var array
- */
- public static $modules = [
- 'system',
- 'node',
- 'field_ui',
- 'views_ui',
- 'entity',
- 'media_entity',
- ];
-
- /**
- * Permissions for the admin user that will be logged-in for test.
- *
- * @var array
- */
- protected static $adminUserPermissions = [
- // Media entity permissions.
- 'administer media',
- 'administer media fields',
- 'administer media form display',
- 'administer media display',
- 'administer media bundles',
- 'view media',
- 'create media',
- 'update media',
- 'update any media',
- 'delete media',
- 'delete any media',
- 'access media overview',
- // Other permissions.
- 'administer views',
- 'access content overview',
- 'view all revisions',
- 'administer content types',
- 'administer node fields',
- 'administer node form display',
- 'bypass node access',
- ];
-
- /**
- * An admin test user account.
- *
- * @var \Drupal\Core\Session\AccountInterface;
- */
- protected $adminUser;
-
- /**
- * A non-admin test user account.
- *
- * @var \Drupal\Core\Session\AccountInterface;
- */
- protected $nonAdminUser;
-
- /**
- * The storage service.
- *
- * @var \Drupal\Core\Entity\EntityStorageInterface;
- */
- protected $storage;
-
- /**
- * {@inheritdoc}
- */
- protected function setUp() {
- parent::setUp();
-
- // Have two users ready to be used in tests.
- $this->adminUser = $this->drupalCreateUser(static::$adminUserPermissions);
- $this->nonAdminUser = $this->drupalCreateUser([]);
- // Start off logged in as admin.
- $this->drupalLogin($this->adminUser);
-
- $this->storage = $this->container->get('entity_type.manager')->getStorage('media');
- }
-
- /**
- * Waits and asserts that a given element is visible.
- *
- * @param string $selector
- * The CSS selector.
- * @param int $timeout
- * (Optional) Timeout in milliseconds, defaults to 1000.
- * @param string $message
- * (Optional) Message to pass to assertJsCondition().
- */
- protected function waitUntilVisible($selector, $timeout = 1000, $message = '') {
- $condition = "jQuery('" . $selector . ":visible').length > 0";
- $this->assertJsCondition($condition, $timeout, $message);
- }
-
-}
+++ /dev/null
-<?php
-
-namespace Drupal\Tests\media_entity\FunctionalJavascript;
-
-use Drupal\Core\Field\FieldStorageDefinitionInterface;
-use Drupal\field\Entity\FieldConfig;
-use Drupal\field\Entity\FieldStorageConfig;
-use Drupal\media_entity\Entity\Media;
-
-/**
- * Tests the integration between Inline Entity Form and Media Entity.
- *
- * @group media_entity
- */
-class MediaIefIntegrationTest extends MediaEntityJavascriptTestBase {
-
- /**
- * Modules to enable.
- *
- * @var array
- */
- public static $modules = ['inline_entity_form'];
-
- /**
- * {@inheritdoc}
- */
- protected function setUp() {
- parent::setUp();
-
- /** @var \Drupal\media_entity\MediaBundleInterface $media_bundle */
- $media_bundle = $this->drupalCreateMediaBundle();
-
- // Create a new content type.
- $values = [
- 'name' => 'Media entity CT',
- 'title_label' => 'An example Custom Content type.',
- 'type' => 'media_entity_ct',
- ];
- $content_type = $this->createContentType($values);
- // Create an entity_reference field.
- FieldStorageConfig::create([
- 'field_name' => 'ref_media_entities',
- 'type' => 'entity_reference',
- 'entity_type' => 'node',
- 'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED,
- 'settings' => [
- 'target_type' => 'media',
- ],
- ])->save();
- FieldConfig::create([
- 'field_name' => 'ref_media_entities',
- 'field_type' => 'entity_reference',
- 'entity_type' => 'node',
- 'bundle' => $content_type->id(),
- 'label' => 'Media referenced',
- 'settings' => [
- 'handler' => 'default:media',
- 'handler_settings' => [
- 'target_bundles' => [
- $media_bundle->id() => $media_bundle->id(),
- ],
- 'sort' => [
- 'field' => '_none',
- ],
- 'auto_create' => FALSE,
- 'auto_create_bundle' => $media_bundle->id(),
- ],
- ],
- ])->save();
-
- // Set widget to inline_entity_form.
- /** @var \Drupal\Core\Entity\Display\EntityFormDisplayInterface $form_display */
- $form_display = $this->container->get('entity_type.manager')
- ->getStorage('entity_form_display')
- ->load('node.media_entity_ct.default');
- $form_display->setComponent('ref_media_entities', [
- 'type' => 'inline_entity_form_complex',
- 'settings' => [],
- ])->save();
-
- }
-
- /**
- * Tests inline_entity_form integration with media entities.
- */
- public function testMediaIefIntegration() {
-
- $session = $this->getSession();
- $page = $session->getPage();
- $assert_session = $this->assertSession();
-
- // Open up a node form and check the IEF widget.
- $this->drupalGet('/node/add/media_entity_ct');
- $assert_session->buttonExists('edit-ref-media-entities-actions-ief-add');
- $page->pressButton('edit-ref-media-entities-actions-ief-add');
- $assert_session->assertWaitOnAjaxRequest();
-
- // Check the presence of the entity's label field.
- $page->findField('ref_media_entities[form][inline_entity_form][name][0][value]')->isVisible();
-
- // Submit the form to create a media entity and verify that it is correctly
- // created.
- $media_name = $this->randomMachineName();
- $page->fillField('ref_media_entities[form][inline_entity_form][name][0][value]', $media_name);
- $page->fillField('ref_media_entities[form][inline_entity_form][uid][0][target_id]', $this->adminUser->getDisplayName() . ' (' . $this->adminUser->id() . ')');
- $page->pressButton('Create media');
- $assert_session->assertWaitOnAjaxRequest();
-
- // We need to save the node in order for IEF to do its thing.
- $page->fillField('title[0][value]', $this->randomString());
- $page->pressButton('Save');
-
- $media_id = $this->container->get('entity.query')->get('media')->execute();
- $media_id = reset($media_id);
- /** @var \Drupal\media_entity\MediaInterface $media */
- $media = Media::load($media_id);
- $this->assertEquals($media_name, $media->label(), 'A media inside IEF was correctly created.');
-
- }
-
-}
+++ /dev/null
-<?php
-
-namespace Drupal\Tests\media_entity\FunctionalJavascript;
-
-use Drupal\media_entity\Entity\Media;
-
-/**
- * Ensures that media UI works correctly.
- *
- * @group media_entity
- */
-class MediaUiJavascriptTest extends MediaEntityJavascriptTestBase {
-
- /**
- * Modules to enable.
- *
- * @var array
- */
- public static $modules = [
- 'block',
- 'media_entity_test_type',
- ];
-
- /**
- * The test media bundle.
- *
- * @var \Drupal\media_entity\MediaBundleInterface
- */
- protected $testBundle;
-
- /**
- * {@inheritdoc}
- */
- protected function setUp() {
- parent::setUp();
- $this->drupalPlaceBlock('local_actions_block');
- $this->drupalPlaceBlock('local_tasks_block');
- }
-
- /**
- * Tests a media bundle administration.
- */
- public function testMediaBundles() {
- $session = $this->getSession();
- $page = $session->getPage();
- $assert_session = $this->assertSession();
-
- // Test the creation of a media bundle using the UI.
- $name = $this->randomMachineName();
- $description = $this->randomMachineName();
- $this->drupalGet('admin/structure/media/add');
- $page->fillField('label', $name);
- $session->wait(2000);
- $page->selectFieldOption('type', 'generic');
- $page->fillField('description', $description);
- $page->pressButton('Save media bundle');
- $assert_session->statusCodeEquals(200);
- $assert_session->pageTextContains('The media bundle ' . $name . ' has been added.');
- $this->drupalGet('admin/structure/media');
- $assert_session->statusCodeEquals(200);
- $assert_session->pageTextContains($name);
- $assert_session->pageTextContains($description);
-
- /** @var \Drupal\media_entity\MediaBundleInterface $bundle_storage */
- $bundle_storage = $this->container->get('entity_type.manager')->getStorage('media_bundle');
- $this->testBundle = $bundle_storage->load(strtolower($name));
-
- // Check if all action links exist.
- $assert_session->linkByHrefExists('admin/structure/media/add');
- $assert_session->linkByHrefExists('admin/structure/media/manage/' . $this->testBundle->id());
- $assert_session->linkByHrefExists('admin/structure/media/manage/' . $this->testBundle->id() . '/fields');
- $assert_session->linkByHrefExists('admin/structure/media/manage/' . $this->testBundle->id() . '/form-display');
- $assert_session->linkByHrefExists('admin/structure/media/manage/' . $this->testBundle->id() . '/display');
-
- // Assert that fields have expected values before editing.
- $page->clickLink('Edit');
- $assert_session->fieldValueEquals('label', $name);
- $assert_session->fieldValueEquals('description', $description);
- $assert_session->fieldValueEquals('type', 'generic');
- $assert_session->fieldValueEquals('label', $name);
- $assert_session->checkboxNotChecked('edit-options-new-revision');
- $assert_session->checkboxChecked('edit-options-status');
- $assert_session->checkboxNotChecked('edit-options-queue-thumbnail-downloads');
- $assert_session->pageTextContains('Create new revision');
- $assert_session->pageTextContains('Automatically create a new revision of media entities. Users with the Administer media permission will be able to override this option.');
- $assert_session->pageTextContains('Download thumbnails via a queue.');
- $assert_session->pageTextContains('Entities will be automatically published when they are created.');
- $assert_session->pageTextContains("This type provider doesn't need configuration.");
- $assert_session->pageTextContains('No metadata fields available.');
- $assert_session->pageTextContains('Media type plugins can provide metadata fields such as title, caption, size information, credits, ... Media entity can automatically save this metadata information to entity fields, which can be configured below. Information will only be mapped if the entity field is empty.');
-
- // Try to change media type and check if new configuration sub-form appears.
- $page->selectFieldOption('type', 'test_type');
- $assert_session->assertWaitOnAjaxRequest();
- $assert_session->fieldExists('Test config value');
- $assert_session->fieldValueEquals('Test config value', 'This is default value.');
- $assert_session->fieldExists('Field 1');
- $assert_session->fieldExists('Field 2');
-
- // Test if the edit machine name is not editable.
- $assert_session->fieldDisabled('Machine-readable name');
-
- // Edit and save media bundle form fields with new values.
- $new_name = $this->randomMachineName();
- $new_description = $this->randomMachineName();
- $page->fillField('label', $new_name);
- $page->fillField('description', $new_description);
- $page->selectFieldOption('type', 'test_type');
- $page->fillField('Test config value', 'This is new config value.');
- $page->selectFieldOption('field_mapping[field_1]', 'name');
- $page->checkField('options[new_revision]');
- $page->uncheckField('options[status]');
- $page->checkField('options[queue_thumbnail_downloads]');
- $page->pressButton('Save media bundle');
- $assert_session->statusCodeEquals(200);
-
- // Test if edit worked and if new field values have been saved as expected.
- $this->drupalGet('admin/structure/media/manage/' . $this->testBundle->id());
- $assert_session->fieldValueEquals('label', $new_name);
- $assert_session->fieldValueEquals('description', $new_description);
- $assert_session->fieldValueEquals('type', 'test_type');
- $assert_session->checkboxChecked('options[new_revision]');
- $assert_session->checkboxNotChecked('options[status]');
- $assert_session->checkboxChecked('options[queue_thumbnail_downloads]');
- $assert_session->fieldValueEquals('Test config value', 'This is new config value.');
- $assert_session->fieldValueEquals('Field 1', 'name');
- $assert_session->fieldValueEquals('Field 2', '_none');
-
- /** @var \Drupal\media_entity\MediaBundleInterface $loaded_bundle */
- $loaded_bundle = $this->container->get('entity_type.manager')
- ->getStorage('media_bundle')
- ->load($this->testBundle->id());
- $this->assertEquals($loaded_bundle->id(), $this->testBundle->id());
- $this->assertEquals($loaded_bundle->label(), $new_name);
- $this->assertEquals($loaded_bundle->getDescription(), $new_description);
- $this->assertEquals($loaded_bundle->getType()->getPluginId(), 'test_type');
- $this->assertEquals($loaded_bundle->getType()->getConfiguration()['test_config_value'], 'This is new config value.');
- $this->assertTrue($loaded_bundle->shouldCreateNewRevision());
- $this->assertTrue($loaded_bundle->getQueueThumbnailDownloads());
- $this->assertFalse($loaded_bundle->getStatus());
- $this->assertEquals($loaded_bundle->field_map, ['field_1' => 'name']);
-
- // Test that a media being created with default status to "FALSE" will be
- // created unpublished.
- /** @var \Drupal\media_entity\MediaInterface $unpublished_media */
- $unpublished_media = Media::create(['name' => 'unpublished test media', 'bundle' => $loaded_bundle->id()]);
- $this->assertFalse($unpublished_media->isPublished());
- $unpublished_media->delete();
-
- // Tests media bundle delete form.
- $page->clickLink('Delete');
- $assert_session->addressEquals('admin/structure/media/manage/' . $this->testBundle->id() . '/delete');
- $page->pressButton('Delete');
- $assert_session->addressEquals('admin/structure/media');
- $assert_session->pageTextContains('The media bundle ' . $new_name . ' has been deleted.');
-
- // Test bundle delete prevention when there is existing media.
- $bundle2 = $this->drupalCreateMediaBundle();
- $label2 = $bundle2->label();
- $media = Media::create(['name' => 'lorem ipsum', 'bundle' => $bundle2->id()]);
- $media->save();
- $this->drupalGet('admin/structure/media/manage/' . $bundle2->id());
- $page->clickLink('Delete');
- $assert_session->addressEquals('admin/structure/media/manage/' . $bundle2->id() . '/delete');
- $assert_session->fieldNotExists('edit-submit');
- $assert_session->pageTextContains("$label2 is used by 1 piece of content on your site. You can not remove this content type until you have removed all of the $label2 content.");
-
- }
-
-}
+++ /dev/null
-<?php
-
-namespace Drupal\Tests\media_entity\FunctionalJavascript;
-
-use Drupal\views\Views;
-
-/**
- * Tests the media entity type integration into the wizard.
- *
- * @group media_entity
- *
- * @see \Drupal\media_entity\Plugin\views\wizard\Media
- * @see \Drupal\media_entity\Plugin\views\wizard\MediaRevision
- */
-class MediaViewsWizardTest extends MediaEntityJavascriptTestBase {
-
- /**
- * Tests adding a view of media.
- */
- public function testMediaWizard() {
- $session = $this->getSession();
- $page = $session->getPage();
- $assert_session = $this->assertSession();
-
- $view_id = strtolower($this->randomMachineName(16));
- $this->drupalGet('admin/structure/views/add');
- $page->fillField('label', $view_id);
- $session->wait(2000);
- $page->selectFieldOption('show[wizard_key]', 'media');
- $assert_session->assertWaitOnAjaxRequest();
- $page->checkField('page[create]');
- $page->fillField('page[path]', $this->randomMachineName(16));
- $page->pressButton('Save and edit');
- $assert_session->assertWaitOnAjaxRequest();
- $this->assertEquals($session->getCurrentUrl(), $this->baseUrl . '/admin/structure/views/view/' . $view_id);
-
- $view = Views::getView($view_id);
- $view->initHandlers();
- $row = $view->display_handler->getOption('row');
- $this->assertEquals($row['type'], 'fields');
- // Check for the default filters.
- $this->assertEquals($view->filter['status']->table, 'media_field_data');
- $this->assertEquals($view->filter['status']->field, 'status');
- $this->assertTrue($view->filter['status']->value);
- // Check for the default fields.
- $this->assertEquals($view->field['name']->table, 'media_field_data');
- $this->assertEquals($view->field['name']->field, 'name');
-
- }
-
- /**
- * Tests adding a view of media revisions.
- */
- public function testMediaRevisionWizard() {
- $session = $this->getSession();
- $page = $session->getPage();
- $assert_session = $this->assertSession();
-
- $view_id = strtolower($this->randomMachineName(16));
- $this->drupalGet('admin/structure/views/add');
- $page->fillField('label', $view_id);
- $session->wait(2000);
- $page->selectFieldOption('show[wizard_key]', 'media_revision');
- $assert_session->assertWaitOnAjaxRequest();
- $page->checkField('page[create]');
- $page->fillField('page[path]', $this->randomMachineName(16));
- $page->pressButton('Save and edit');
- $assert_session->assertWaitOnAjaxRequest();
- $this->assertEquals($session->getCurrentUrl(), $this->baseUrl . '/admin/structure/views/view/' . $view_id);
-
- $view = Views::getView($view_id);
- $view->initHandlers();
- $row = $view->display_handler->getOption('row');
- $this->assertEquals($row['type'], 'fields');
-
- // Check for the default filters.
- $this->assertEquals($view->filter['status']->table, 'media_field_revision');
- $this->assertEquals($view->filter['status']->field, 'status');
- $this->assertTrue($view->filter['status']->value);
-
- // Check for the default fields.
- $this->assertEquals($view->field['name']->table, 'media_field_revision');
- $this->assertEquals($view->field['name']->field, 'name');
- $this->assertEquals($view->field['changed']->table, 'media_field_revision');
- $this->assertEquals($view->field['changed']->field, 'changed');
-
- }
-
-}
+++ /dev/null
-<?php
-
-namespace Drupal\Tests\media_entity\Kernel;
-
-use Drupal\KernelTests\KernelTestBase;
-use Drupal\media_entity\Entity\Media;
-use Drupal\media_entity\Entity\MediaBundle;
-
-/**
- * Tests creation of Media Bundles and Media Entities.
- *
- * @group media_entity
- */
-class BasicCreationTest extends KernelTestBase {
-
- /**
- * Modules to install.
- *
- * @var array
- */
- public static $modules = [
- 'media_entity',
- 'entity',
- 'image',
- 'user',
- 'field',
- 'system',
- 'file',
- ];
-
-
- /**
- * The test media bundle.
- *
- * @var \Drupal\media_entity\MediaBundleInterface
- */
- protected $testBundle;
-
- /**
- * {@inheritdoc}
- */
- protected function setUp() {
- parent::setUp();
-
- $this->installEntitySchema('user');
- $this->installEntitySchema('file');
- $this->installSchema('file', 'file_usage');
- $this->installEntitySchema('media');
- $this->installConfig(['field', 'system', 'image', 'file']);
-
- // Create a test bundle.
- $id = strtolower($this->randomMachineName());
- $this->testBundle = MediaBundle::create([
- 'id' => $id,
- 'label' => $id,
- 'type' => 'generic',
- 'type_configuration' => [],
- 'field_map' => [],
- 'new_revision' => FALSE,
- ]);
- $this->testBundle->save();
-
- }
-
- /**
- * Tests creating a media bundle programmatically.
- */
- public function testMediaBundleCreation() {
- /** @var \Drupal\media_entity\MediaBundleInterface $bundle_storage */
- $bundle_storage = $this->container->get('entity_type.manager')->getStorage('media_bundle');
-
- $bundle_exists = (bool) $bundle_storage->load($this->testBundle->id());
- $this->assertTrue($bundle_exists, 'The new media bundle has not been correctly created in the database.');
-
- // Test default bundle created from default configuration.
- $this->container->get('module_installer')->install(['media_entity_test_bundle']);
- $test_bundle = $bundle_storage->load('test');
- $this->assertTrue((bool) $test_bundle, 'The media bundle from default configuration has not been created in the database.');
- $this->assertEquals($test_bundle->get('label'), 'Test bundle', 'Could not assure the correct bundle label.');
- $this->assertEquals($test_bundle->get('description'), 'Test bundle.', 'Could not assure the correct bundle description.');
- $this->assertEquals($test_bundle->get('type'), 'generic', 'Could not assure the correct bundle plugin type.');
- $this->assertEquals($test_bundle->get('type_configuration'), [], 'Could not assure the correct plugin configuration.');
- $this->assertEquals($test_bundle->get('field_map'), [], 'Could not assure the correct field map.');
- }
-
- /**
- * Tests creating a media entity programmatically.
- */
- public function testMediaEntityCreation() {
- $media = Media::create([
- 'bundle' => $this->testBundle->id(),
- 'name' => 'Unnamed',
- ]);
- $media->save();
-
- $media_not_exist = (bool) Media::load(rand(1000, 9999));
- $this->assertFalse($media_not_exist, 'Failed asserting a non-existent media.');
-
- $media_exists = (bool) Media::load($media->id());
- $this->assertTrue($media_exists, 'The new media entity has not been created in the database.');
- $this->assertEquals($media->bundle(), $this->testBundle->id(), 'The media was not created with the correct bundle.');
- $this->assertEquals($media->label(), 'Unnamed', 'The media was not created with the correct name.');
-
- // Test the creation of a media without user-defined label and check if a
- // default name is provided.
- $media = Media::create([
- 'bundle' => $this->testBundle->id(),
- ]);
- $media->save();
- $expected_name = 'media' . ':' . $this->testBundle->id() . ':' . $media->uuid();
- $this->assertEquals($media->bundle(), $this->testBundle->id(), 'The media was not created with correct bundle.');
- $this->assertEquals($media->label(), $expected_name, 'The media was not created with a default name.');
- }
-
-}
+++ /dev/null
-<?php
-
-namespace Drupal\Tests\media_entity\Kernel;
-
-use Drupal\Core\Language\Language;
-use Drupal\KernelTests\Core\Entity\EntityKernelTestBase;
-use Drupal\media_entity\Entity\Media;
-use Drupal\media_entity\Entity\MediaBundle;
-
-/**
- * Tests token handling.
- *
- * @group media_entity
- */
-class TokensTest extends EntityKernelTestBase {
-
- /**
- * Modules to install.
- *
- * @var array
- */
- public static $modules = [
- 'media_entity',
- 'path',
- 'file',
- 'image',
- 'entity',
- 'datetime',
- 'language',
- ];
-
- /**
- * {@inheritdoc}
- */
- protected function setUp() {
- parent::setUp();
- $this->installEntitySchema('file');
- $this->installSchema('file', 'file_usage');
- $this->installEntitySchema('media');
- $this->installConfig(['language', 'datetime', 'field', 'system']);
- }
-
- /**
- * Tests some of the tokens provided by media_entity.
- */
- public function testMediaEntityTokens() {
- // Create a generic media bundle.
- $bundle_name = $this->randomMachineName();
-
- MediaBundle::create([
- 'id' => $bundle_name,
- 'label' => $bundle_name,
- 'type' => 'generic',
- 'type_configuration' => [],
- 'field_map' => [],
- 'status' => 1,
- 'new_revision' => FALSE,
- ])->save();
-
- // Create a media entity.
- $media = Media::create([
- 'name' => $this->randomMachineName(),
- 'bundle' => $bundle_name,
- 'uid' => '1',
- 'langcode' => Language::LANGCODE_DEFAULT,
- 'status' => Media::PUBLISHED,
- ]);
- $media->save();
-
- $token_service = $this->container->get('token');
-
- $replaced_value = $token_service->replace('[media:name]', ['media' => $media]);
- $this->assertEquals($media->label(), $replaced_value, 'Token replacement for the media label was sucessful.');
-
- }
-
-}
--- /dev/null
+ 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.
--- /dev/null
+# Media Entity Actions
+
+This module is intended to serve as a bridge between sites that relied on the
+ Actions plugins present on the Media Entity 1.x branch, which were removed in
+ Drupal core 8.4.x. You can use this module together with Media in core 8.4.x to
+ achieve the same functionality.
+
+Generic entity actions will likely be added to core in future minor versions
+ (>8.5.x), at which point this module will become obsolete and an upgrade path,
+ if needed, will be provided. See https://www.drupal.org/node/2916740 for more
+ information.
status: true
dependencies:
module:
- - media_entity
+ - media
id: media_delete_action
label: 'Delete media'
type: media
status: true
dependencies:
module:
- - media_entity
+ - media
id: media_publish_action
label: 'Publish media'
type: media
status: true
dependencies:
module:
- - media_entity
+ - media
id: media_save_action
label: 'Save media'
type: media
status: true
dependencies:
module:
- - media_entity
+ - media
id: media_unpublish_action
label: 'Unpublish media'
type: media
--- /dev/null
+action.configuration.media_delete_action:
+ type: action_configuration_default
+ label: 'Delete media configuration'
+
+action.configuration.media_save_action:
+ type: action_configuration_default
+ label: 'Save media configuration'
+
+action.configuration.media_publish_action:
+ type: action_configuration_default
+ label: 'Publish media configuration'
+
+action.configuration.media_unpublish_action:
+ type: action_configuration_default
+ label: 'Unpublish media configuration'
--- /dev/null
+# Schema for the views plugins of the Media module (on behalf of).
+views.field.media_bulk_form:
+ type: views_field_bulk_form
+ label: 'Media bulk form'
--- /dev/null
+name: Media Entity Actions
+description: 'Provides Actions plugins to be used with Media in core'
+type: module
+package: Media
+# core: 8.x
+dependencies:
+ - drupal:media (>= 8.4.0)
+
+# Information added by Drupal.org packaging script on 2017-11-13
+version: '8.x-1.0-alpha2'
+core: '8.x'
+project: 'media_entity_actions'
+datestamp: 1510588393
--- /dev/null
+<?php
+
+/**
+ * @file
+ * Install, uninstall and update hooks for Media Entity Actions module.
+ */
+
+/**
+ * Implements hook_requirements().
+ */
+function media_entity_actions_requirements($phase) {
+ $requirements = [];
+
+ // Prevent installation if Media Entity 1.x is enabled.
+ if (\Drupal::moduleHandler()->moduleExists('media_entity')) {
+ $info = system_get_info('module', 'media_entity');
+ if (version_compare($info['version'], '8.x-2') < 0) {
+ $requirements['media_entity_generic_incompatibility'] = [
+ 'title' => t('Media'),
+ 'description' => t('The Media Entity Actions module is not compatible with contrib <a href=":url">Media Entity</a> 1.x branch. You don\'t need to enable this module manually, when performing the upgrade to Media in core, this module will be automatically enabled.', [
+ ':url' => 'https://drupal.org/project/media_entity',
+ ]),
+ 'severity' => REQUIREMENT_ERROR,
+ ];
+ }
+ }
+
+ return $requirements;
+}
--- /dev/null
+<?php
+
+/**
+ * @file
+ * Hook implementations for the Media Entity Actions module.
+ */
<?php
-namespace Drupal\media_entity\Plugin\Action;
+namespace Drupal\media_entity_actions\Plugin\Action;
use Drupal\Core\Action\ActionBase;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
- * Redirects to a media deletion form.
+ * Redirects to a media item deletion form.
*
* @Action(
* id = "media_delete_action",
* label = @Translation("Delete media"),
* type = "media",
- * confirm_form_route_name = "entity.media.multiple_delete_confirm"
+ * confirm_form_route_name = "entity.media.multiple_delete_confirm",
* )
*/
class DeleteMedia extends ActionBase implements ContainerFactoryPluginInterface {
/**
- * The tempstore object.
+ * The temp store factory.
*
- * @var \Drupal\user\SharedTempStore
+ * @var \Drupal\user\PrivateTempStoreFactory
*/
protected $tempStore;
* @param mixed $plugin_definition
* The plugin implementation definition.
* @param \Drupal\user\PrivateTempStoreFactory $temp_store_factory
- * The tempstore factory.
- * @param AccountInterface $current_user
+ * The temp store factory.
+ * @param \Drupal\Core\Session\AccountInterface $current_user
* Current user.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, PrivateTempStoreFactory $temp_store_factory, AccountInterface $current_user) {
*/
public function executeMultiple(array $entities) {
$info = [];
- /** @var \Drupal\media_entity\MediaInterface $media */
+ /** @var \Drupal\media\MediaInterface $media */
foreach ($entities as $media) {
$langcode = $media->language()->getId();
$info[$media->id()][$langcode] = $langcode;
* {@inheritdoc}
*/
public function execute($object = NULL) {
- $this->executeMultiple(array($object));
+ $this->executeMultiple($object ? [$object] : []);
}
/**
* {@inheritdoc}
*/
public function access($object, AccountInterface $account = NULL, $return_as_object = FALSE) {
- /** @var \Drupal\media_entity\MediaInterface $object */
+ /** @var \Drupal\media\MediaInterface $object */
return $object->access('delete', $account, $return_as_object);
}
--- /dev/null
+<?php
+
+namespace Drupal\media_entity_actions\Plugin\Action;
+
+use Drupal\Core\Action\ActionBase;
+use Drupal\Core\Session\AccountInterface;
+use Drupal\media\MediaInterface;
+
+/**
+ * Publishes a media item.
+ *
+ * @Action(
+ * id = "media_publish_action",
+ * label = @Translation("Publish media"),
+ * type = "media"
+ * )
+ */
+class PublishMedia extends ActionBase {
+
+ /**
+ * {@inheritdoc}
+ */
+ public function execute(MediaInterface $entity = NULL) {
+ if ($entity) {
+ $entity->setPublished()->save();
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function access($object, AccountInterface $account = NULL, $return_as_object = FALSE) {
+ /** @var \Drupal\media\MediaInterface $object */
+ $access = $object->access('update', $account, TRUE)
+ ->andIf($object->status->access('update', $account, TRUE));
+
+ return $return_as_object ? $access : $access->isAllowed();
+ }
+
+}
<?php
-namespace Drupal\media_entity\Plugin\Action;
+namespace Drupal\media_entity_actions\Plugin\Action;
use Drupal\Core\Action\ActionBase;
use Drupal\Core\Session\AccountInterface;
+use Drupal\media\MediaInterface;
/**
- * Provides an action that can save any entity.
+ * Saves a media item.
*
* @Action(
* id = "media_save_action",
/**
* {@inheritdoc}
*/
- public function execute($entity = NULL) {
- // We need to change at least one value, otherwise the changed timestamp
- // will not be updated.
- $entity->changed = 0;
- $entity->save();
+ public function execute(MediaInterface $entity = NULL) {
+ if ($entity) {
+ // We need to change at least one value, otherwise the changed timestamp
+ // will not be updated.
+ $entity->setChangedTime(0)->save();
+ }
}
/**
* {@inheritdoc}
*/
public function access($object, AccountInterface $account = NULL, $return_as_object = FALSE) {
- /** @var \Drupal\media_entity\MediaInterface $object */
+ /** @var \Drupal\media\MediaInterface $object */
return $object->access('update', $account, $return_as_object);
}
--- /dev/null
+<?php
+
+namespace Drupal\media_entity_actions\Plugin\Action;
+
+use Drupal\Core\Action\ActionBase;
+use Drupal\Core\Session\AccountInterface;
+use Drupal\media\MediaInterface;
+
+/**
+ * Unpublishes a media item.
+ *
+ * @Action(
+ * id = "media_unpublish_action",
+ * label = @Translation("Unpublish media"),
+ * type = "media"
+ * )
+ */
+class UnpublishMedia extends ActionBase {
+
+ /**
+ * {@inheritdoc}
+ */
+ public function execute(MediaInterface $entity = NULL) {
+ if ($entity) {
+ $entity->setUnpublished()->save();
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function access($object, AccountInterface $account = NULL, $return_as_object = FALSE) {
+ /** @var \Drupal\media\MediaInterface $object */
+ $access = $object->access('update', $account, TRUE)
+ ->andIf($object->status->access('update', $account, TRUE));
+
+ return $return_as_object ? $access : $access->isAllowed();
+ }
+
+}
<?php
-namespace Drupal\media_entity\Plugin\views\field;
+namespace Drupal\media_entity_actions\Plugin\views\field;
use Drupal\system\Plugin\views\field\BulkForm;
status: true
dependencies:
module:
- - media_entity
+ - media
- user
-id: test_media_entity_bulk_form
+id: test_media_bulk_form
label: ''
module: views
description: ''
display_title: Page
position: 1
display_options:
- path: test-media-entity-bulk-form
+ path: test-media-bulk-form
--- /dev/null
+name: 'Media Entity Actions test views'
+type: module
+description: 'Provides default views for views media tests.'
+package: Testing
+# version: VERSION
+# core: 8.x
+dependencies:
+ - media
+ - views
+
+# Information added by Drupal.org packaging script on 2017-11-13
+version: '8.x-1.0-alpha2'
+core: '8.x'
+project: 'media_entity_actions'
+datestamp: 1510588393
<?php
-namespace Drupal\Tests\media_entity\Functional;
+namespace Drupal\Tests\media_entity_actions\Functional;
-use Drupal\media_entity\Entity\Media;
+use Drupal\media\Entity\Media;
+use Drupal\Tests\media\Functional\MediaFunctionalTestBase;
use Drupal\views\Views;
/**
* Tests a media bulk form.
*
- * @group media_entity
+ * @group media
*/
-class MediaBulkFormTest extends MediaEntityFunctionalTestBase {
+class MediaBulkFormTest extends MediaFunctionalTestBase {
/**
* Modules to be enabled.
*
* @var array
*/
- public static $modules = ['media_entity_test_views'];
+ public static $modules = ['media_entity_actions_test_views'];
/**
- * The test media bundle.
+ * The test media type.
*
- * @var \Drupal\media_entity\MediaBundleInterface
+ * @var \Drupal\media\MediaTypeInterface
*/
- protected $testBundle;
+ protected $testMediaType;
/**
- * The test media entities.
+ * The test media items.
*
- * @var \Drupal\media_entity\MediaInterface[]
+ * @var \Drupal\media\MediaInterface[]
*/
- protected $mediaEntities;
+ protected $mediaItems;
/**
* {@inheritdoc}
protected function setUp() {
parent::setUp();
- $this->testBundle = $this->drupalCreateMediaBundle();
+ $this->testMediaType = $this->createMediaType();
- // Create some test media entities.
- $this->mediaEntities = [];
+ // Create some test media items.
+ $this->mediaItems = [];
for ($i = 1; $i <= 5; $i++) {
$media = Media::create([
- 'bundle' => $this->testBundle->id(),
+ 'bundle' => $this->testMediaType->id(),
]);
$media->save();
- $this->mediaEntities[] = $media;
+ $this->mediaItems[] = $media;
}
-
}
/**
* Tests the media bulk form.
*/
public function testBulkForm() {
-
$session = $this->getSession();
$page = $session->getPage();
$assert_session = $this->assertSession();
- // Check that all created entities are present in the test view.
- $view = Views::getView('test_media_entity_bulk_form');
+ // Check that all created items are present in the test view.
+ $view = Views::getView('test_media_bulk_form');
$view->execute();
$this->assertEquals($view->total_rows, 5);
// Check the operations are accessible to the logged in user.
- $this->drupalGet('test-media-entity-bulk-form');
+ $this->drupalGet('test-media-bulk-form');
// Current available actions: Delete, Save, Publish, Unpublish.
$available_actions = [
'media_delete_action',
$page->selectFieldOption('action', 'media_unpublish_action');
$page->pressButton('Apply to selected items');
$assert_session->pageTextContains('Unpublish media was applied to 3 items');
- for ($i = 1; $i <= 3; $i++) {
- $this->assertFalse($this->storage->loadUnchanged($i)->isPublished(), 'The unpublish action failed in some of the media entities.');
- }
+ $this->assertFalse($this->storage->loadUnchanged(1)->isPublished(), 'The unpublish action failed in some of the media items.');
+ $this->assertFalse($this->storage->loadUnchanged(2)->isPublished(), 'The unpublish action failed in some of the media items.');
+ $this->assertFalse($this->storage->loadUnchanged(3)->isPublished(), 'The unpublish action failed in some of the media items.');
// Test publishing in bulk.
$page->checkField('media_bulk_form[0]');
$page->selectFieldOption('action', 'media_publish_action');
$page->pressButton('Apply to selected items');
$assert_session->pageTextContains('Publish media was applied to 2 items');
- for ($i = 1; $i <= 2; $i++) {
- $this->assertTrue($this->storage->loadUnchanged($i)->isPublished(), 'The publish action failed in some of the media entities.');
- }
+ $this->assertTrue($this->storage->loadUnchanged(1)->isPublished(), 'The publish action failed in some of the media items.');
+ $this->assertTrue($this->storage->loadUnchanged(2)->isPublished(), 'The publish action failed in some of the media items.');
// Test deletion in bulk.
$page->checkField('media_bulk_form[0]');
$page->pressButton('Apply to selected items');
$assert_session->pageTextContains('Are you sure you want to delete these items?');
$page->pressButton('Delete');
- $assert_session->pageTextContains('Deleted 2 media entities.');
- for ($i = 1; $i <= 2; $i++) {
- $this->assertNull($this->storage->loadUnchanged($i), 'Could not delete some of the media entities.');
- }
-
+ $assert_session->pageTextContains('Deleted 2 media items.');
+ $this->assertNull($this->storage->loadUnchanged(1), 'Could not delete some of the media items.');
+ $this->assertNull($this->storage->loadUnchanged(2), 'Could not delete some of the media items.');
}
}
+++ /dev/null
-{
- "name": "drupal/media_entity_document",
- "type": "drupal-module",
- "description": "Local documents integration for Drupal Media entity.",
- "keywords": ["Drupal", "media", "document"],
- "license": "GPL-2.0+",
- "homepage": "https://www.drupal.org/project/media_entity_document",
- "authors": [
- {
- "name": "NerOcrO",
- "homepage": "https://www.drupal.org/user/1728164",
- "role": "Maintainer"
- }
- ],
- "minimum-stability": "dev",
- "support": {
- "issues": "https://www.drupal.org/project/issues/media_entity_document",
- "source": "https://www.drupal.org/project/media_entity_document"
- },
- "repositories": [
- {
- "type": "composer",
- "url": "https://packagist.drupal-composer.org"
- }
- ],
- "require": {
- "drupal/core": "~8.1",
- "drupal/media_entity": "~1.0 || ~8.1.0"
- }
-}
dependencies:
- media_entity
-# Information added by Drupal.org packaging script on 2016-08-03
-version: '8.x-1.1'
+# Information added by Drupal.org packaging script on 2016-06-02
+version: '8.x-1.0'
core: '8.x'
project: 'media_entity_document'
-datestamp: 1470211440
+datestamp: 1464882942
namespace Drupal\media_entity_document\Plugin\EntityBrowser\Widget;
use Drupal\Core\Form\FormStateInterface;
-use Drupal\Core\Url;
use Drupal\entity_browser\Plugin\EntityBrowser\Widget\Upload as FileUpload;
-use Drupal\media_entity\MediaInterface;
+use Drupal\Core\Url;
/**
* Uses upload to create media entity documents.
public function defaultConfiguration() {
return [
'extensions' => 'txt, pdf',
- 'media_bundle' => NULL,
+ 'media bundle' => NULL,
] + parent::defaultConfiguration();
}
*/
public function getForm(array &$original_form, FormStateInterface $form_state, array $aditional_widget_parameters) {
/** @var \Drupal\media_entity\MediaBundleInterface $bundle */
- if (!$this->configuration['media_bundle'] || !($bundle = $this->entityTypeManager->getStorage('media_bundle')->load($this->configuration['media_bundle']))) {
+ if (!$this->configuration['media bundle'] || !($bundle = $this->entityManager->getStorage('media_bundle')->load($this->configuration['media bundle']))) {
return ['#markup' => $this->t('The media bundle is not configured correctly.')];
}
}
$form = parent::getForm($original_form, $form_state, $aditional_widget_parameters);
- $form['upload']['#upload_validators']['file_validate_extensions'] = [$this->configuration['extensions']];
+ $form['upload']['upload_validators']['file_validate_extensions'] = [$this->configuration['extensions']];
return $form;
}
/**
* {@inheritdoc}
*/
- protected function prepareEntities(array $form, FormStateInterface $form_state) {
- $files = parent::prepareEntities($form, $form_state);
+ public function submit(array &$element, array &$form, FormStateInterface $form_state) {
+ $documents = [];
/** @var \Drupal\media_entity\MediaBundleInterface $bundle */
- $bundle = $this->entityTypeManager
+ $bundle = $this->entityManager
->getStorage('media_bundle')
- ->load($this->configuration['media_bundle']);
+ ->load($this->configuration['media bundle']);
+ $files = $this->extractFiles($form_state);
- $documents = [];
foreach ($files as $file) {
/** @var \Drupal\media_entity\MediaInterface $document */
- $document = $this->entityTypeManager->getStorage('media')->create([
+ $document = $this->entityManager->getStorage('media')->create([
'bundle' => $bundle->id(),
$bundle->getTypeConfiguration()['source_field'] => $file,
]);
+ $filename = $file->filename->value;
+ if ($filename) {
+ $document->set('name', $filename);
+ }
+
+ $document->save();
$documents[] = $document;
}
- return $documents;
- }
-
- /**
- * {@inheritdoc}
- */
- public function submit(array &$element, array &$form, FormStateInterface $form_state) {
- if (!empty($form_state->getTriggeringElement()['#eb_widget_main_submit'])) {
- $documents = $this->prepareEntities($form, $form_state);
- array_walk(
- $documents,
- function (MediaInterface $media) { $media->save(); }
- );
-
- $this->selectEntities($documents, $form_state);
- $this->clearFormValues($element, $form_state);
- }
+ $this->selectEntities($documents, $form_state);
+ $this->clearFormValues($element, $form_state);
}
/**
'#required' => TRUE,
];
- $bundles = $this->entityTypeManager
+ $bundles = $this->entityManager
->getStorage('media_bundle')
->loadByProperties(['type' => 'document']);
- /** @var \Drupal\media_entity\MediaBundleInterface $bundle */
foreach ($bundles as $bundle) {
$bundle_options[$bundle->id()] = $bundle->label();
}
- if (empty($bundle_options)) {
- $url = Url::fromRoute('media.bundle_add')->toString();
- $form['media_bundle'] = [
- '#markup' => $this->t("You don't have media bundle of the Document type. You should <a href='!link'>create one</a>", ['!link' => $url]),
- ];
- }
- else {
- $form['media_bundle'] = [
- '#type' => 'select',
- '#title' => $this->t('Media bundle'),
- '#default_value' => $this->configuration['media_bundle'],
- '#options' => $bundle_options,
- ];
+ switch (count($bundle_options)) {
+ case 0:
+ $url = Url::fromRoute('media.bundle_add')->toString();
+ $form['media bundle'] = [
+ '#markup' => $this->t("You don't have media bundle of the Document type. You should <a href='!link'>create one</a>", ['!link' => $url]),
+ ];
+ break;
+
+ case 1:
+ $form['media bundle'] = [
+ '#value' => key($bundle_options),
+ '#type' => 'value',
+ ];
+ break;
+
+ default:
+ $form['media bundle'] = [
+ '#type' => 'select',
+ '#title' => $this->t('Media bundle'),
+ '#default_value' => $this->configuration['media bundle'],
+ '#options' => $bundle_options,
+ ];
}
return $form;
<?php
-
namespace Drupal\media_entity_document\Plugin\MediaEntity\Type;
use Drupal\media_entity\MediaInterface;
*/
public function providedFields() {
return [
- 'mime' => $this->t('File MIME'),
- 'size' => $this->t('Size'),
+ 'mime' => t('File MIME'),
+ 'size' => t('Size'),
];
}
*/
public function getField(MediaInterface $media, $name) {
$source_field = $this->configuration['source_field'];
+ $property_name = $media->{$source_field}->first()->mainPropertyName();
// Get the file document.
/** @var \Drupal\file\FileInterface $file */
- $file = $media->{$source_field}->entity;
+ $file = $this->entityTypeManager->getStorage('file')->load($media->{$source_field}->first()->{$property_name});
// Return the field.
switch ($name) {
$bundle = $form_state->getFormObject()->getEntity();
$options = [];
$allowed_field_types = ['file'];
-
- /** @var \Drupal\Core\Field\FieldDefinitionInterface $field */
foreach ($this->entityFieldManager->getFieldDefinitions('media', $bundle->id()) as $field_name => $field) {
if (in_array($field->getType(), $allowed_field_types) && !$field->getFieldStorageDefinition()->isBaseField()) {
$options[$field_name] = $field->getLabel();
$form['source_field'] = [
'#type' => 'select',
- '#title' => $this->t('Field with source information'),
- '#description' => $this->t('Field on media entity that stores Document file. You can create a bundle without selecting a value for this dropdown initially. This dropdown can be populated after adding fields to the bundle.'),
+ '#title' => t('Field with source information'),
+ '#description' => t('Field on media entity that stores Document file. You can create a bundle without selecting a value for this dropdown initially. This dropdown can be populated after adding fields to the bundle.'),
'#default_value' => empty($this->configuration['source_field']) ? NULL : $this->configuration['source_field'],
'#options' => $options,
];
public function thumbnail(MediaInterface $media) {
$source_field = $this->configuration['source_field'];
/** @var \Drupal\file\FileInterface $file */
- $file = $media->{$source_field}->entity;
+ $file = $this->entityTypeManager->getStorage('file')->load($media->{$source_field}->target_id);
+ $mimetype = $file->getMimeType();
+ $mimetype = explode('/', $mimetype);
+ $thumbnail = $this->config->get('icon_base') . "/{$mimetype[0]}-{$mimetype[1]}.png";
- if ($file) {
- $mimetype = $file->getMimeType();
- $mimetype = explode('/', $mimetype);
- $thumbnail = $this->config->get('icon_base') . "/{$mimetype[0]}-{$mimetype[1]}.png";
+ if (!is_file($thumbnail)) {
+ $thumbnail = $this->config->get('icon_base') . "/{$mimetype[1]}.png";
if (!is_file($thumbnail)) {
- $thumbnail = $this->config->get('icon_base') . "/{$mimetype[1]}.png";
-
- if (!is_file($thumbnail)) {
- $thumbnail = $this->config->get('icon_base') . '/document.png';
- }
+ $thumbnail = $this->config->get('icon_base') . '/document.png';
}
}
- else {
- $thumbnail = $this->config->get('icon_base') . '/document.png';
- }
return $thumbnail;
}
- /**
- * {@inheritdoc}
- */
- public function getDefaultName(MediaInterface $media) {
- // The default name will be the filename of the source_field, if present.
- $source_field = $this->configuration['source_field'];
-
- /** @var \Drupal\file\FileInterface $file */
- if (!empty($source_field) && ($file = $media->{$source_field}->entity)) {
- return $file->getFilename();
- }
-
- return parent::getDefaultName($media);
- }
-
}
script:
- phpcs --report=full --standard=Drupal "$TRAVIS_BUILD_DIR" || true
- cd ~/
- - git clone --depth 1 --branch 8.0.x http://git.drupal.org/project/drupal.git
+ - git clone --depth 1 --branch 8.4.x http://git.drupal.org/project/drupal.git
- cd drupal/modules
- - git clone --depth 1 --branch 8.x-1.x http://git.drupal.org/project/media_entity.git
- ln -s $TRAVIS_BUILD_DIR
- cd ../
- ./vendor/bin/phpunit -c core modules/media_entity_instagram/tests/src/Unit
-## About Media entity
-
-Media entity provides a 'base' entity for a media element. This is a very basic
-entity which can reference to all kinds of media-objects (local files, YouTube
-videos, tweets, CDN-files, ...). This entity only provides a relation between
-Drupal (because it is an entity) and the resource. You can reference to this
-entity within any other Drupal entity.
-
## About Media entity Instagram
-This module provides Instagram integration for Media entity (i.e. media type provider
+This module provides Instagram integration for Media (i.e. media type provider
plugin).
### Instagram API
-This module uses Instagrams oembed API to fetch the instagram html and all the metadata.
-You will need to:
-
-- Create a Media bundle with the type provider "Instagram".
-- On that bundle create a field for the Instagram url/source (this should be a plain text or link field).
-- Return to the bundle configuration and set "Field with source information" to use that field.
-
-### Storing field values
-If you want to store the fields that are retrieved from Instagram you should create appropriate fields on the created media bundle (id) and map this to the fields provided by Instagram.php.
-
-**NOTE:** At the moment there is no GUI for that, so the only method of doing that for now is via CMI.
-
-This would be an example of that (the field_map section):
-
-```
-langcode: en
-status: true
-dependencies:
- module:
- - media_entity_instagram
-id: instagram
-label: Instagram
-description: 'Instagram photo/video to be used with content.'
-type: instagram
-type_configuration:
- source_field: link
-field_map:
- id: instagram_id
- type: instagram_type
- thumbnail: instagram_thumbnail
- username: instagram_username
- caption: instagram_caption
-```
+This module uses Instagrams oembed API to fetch the instagram html and all the
+metadata.
+
+After enabling the module, you can create a new Media Type choosing "Instagram"
+on the provider dropdown.
+
+A source field will be automatically created and configured on the Media Type if
+this is the first Instagram type on the site. If you need to have additional
+types, you can choose to reuse an existing field as source, or create one field
+per type. Source fields for the Instagram Media Type need to be plain text or
+link fields.
+
+Please refer to the Media documentation for more instructions on how to work
+with Media Types.
Project page: http://drupal.org/project/media_entity_instagram
type: string
label: 'Base folder for thumbnails'
-media_entity.bundle.type.instagram:
- type: mapping
- label: 'Instagram type configuration'
- mapping:
- source_field:
- type: string
- label: 'Field with embed code/URL'
+media.source.instagram:
+ type: media.source.field_aware
+ label: '"Instagram" media source configuration'
field.formatter.settings.instagram_embed:
type: mapping
package: Media
# core: 8.x
dependencies:
- - media_entity:media_entity
+ - drupal:media (>= 8.4.0)
-# Information added by Drupal.org packaging script on 2017-05-23
-version: '8.x-1.4'
+# Information added by Drupal.org packaging script on 2017-09-29
+version: '8.x-2.0-alpha1'
core: '8.x'
project: 'media_entity_instagram'
-datestamp: 1495556288
+datestamp: 1506671648
*/
function media_entity_instagram_install() {
$source = drupal_get_path('module', 'media_entity_instagram') . '/images/icons';
- $destination = \Drupal::config('media_entity.settings')->get('icon_base');
- media_entity_copy_icons($source, $destination);
+ $destination = \Drupal::config('media.settings')->get('icon_base_uri');
+ file_prepare_directory($destination, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
+
+ $files = file_scan_directory($source, '/.*\.(svg|png|jpg|jpeg|gif)$/');
+ foreach ($files as $file) {
+ // When reinstalling we don't want to copy the icons when
+ // they already exist. The icons could be replaced (by a contrib module or
+ // manually), so we don't want to replace the existing files. Removing the
+ // files when we uninstall could also be a problem if the files are
+ // referenced somewhere else. Since showing an error that it was not
+ // possible to copy the files is also confusing, we silently do nothing.
+ if (!file_exists($destination . DIRECTORY_SEPARATOR . $file->filename)) {
+ file_unmanaged_copy($file->uri, $destination, FILE_EXISTS_ERROR);
+ }
+ }
}
namespace Drupal\media_entity_instagram\Plugin\Field\FieldFormatter;
use Drupal\Core\Field\FieldDefinitionInterface;
+use Drupal\Core\Field\FieldItemInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\FormatterBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
-use Drupal\media_entity\EmbedCodeValueTrait;
-use Drupal\media_entity_instagram\Plugin\MediaEntity\Type\Instagram;
+use Drupal\media_entity_instagram\Plugin\media\Source\Instagram;
use Drupal\media_entity_instagram\InstagramEmbedFetcher;
use Symfony\Component\DependencyInjection\ContainerInterface;
*/
class InstagramEmbedFormatter extends FormatterBase implements ContainerFactoryPluginInterface {
- use EmbedCodeValueTrait;
-
/**
* The instagram fetcher.
*
- * @var \Drupal\media_entity_instagram\Plugin\MediaEntity\Type\InstagramEmbedFetcher
+ * @var \Drupal\media_entity_instagram\InstagramEmbedFetcher
*/
protected $fetcher;
return $summary;
}
+ /**
+ * Extracts the raw embed code from input which may or may not be wrapped.
+ *
+ * @param mixed $value
+ * The input value. Can be a normal string or a value wrapped by the
+ * Typed Data API.
+ *
+ * @return string|null
+ * The raw embed code.
+ */
+ protected function getEmbedCode($value) {
+ if (is_string($value)) {
+ return $value;
+ }
+ elseif ($value instanceof FieldItemInterface) {
+ $class = get_class($value);
+ $property = $class::mainPropertyName();
+ if ($property) {
+ return $value->$property;
+ }
+ }
+ }
+
}
namespace Drupal\media_entity_instagram\Plugin\Validation\Constraint;
-use Drupal\media_entity\EmbedCodeValueTrait;
-use Drupal\media_entity_instagram\Plugin\MediaEntity\Type\Instagram;
+use Drupal\Core\Field\FieldItemInterface;
+use Drupal\media_entity_instagram\Plugin\media\Source\Instagram;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
*/
class InstagramEmbedCodeConstraintValidator extends ConstraintValidator {
- use EmbedCodeValueTrait;
-
/**
* {@inheritdoc}
*/
public function validate($value, Constraint $constraint) {
- $value = $this->getEmbedCode($value);
- if (!isset($value)) {
- return;
+ $data = '';
+ if (is_string($value)) {
+ $data = $value;
}
-
- $matches = [];
- foreach (Instagram::$validationRegexp as $pattern => $key) {
- if (preg_match($pattern, $value, $item_matches)) {
- $matches[] = $item_matches;
+ elseif ($value instanceof FieldItemInterface) {
+ $class = get_class($value);
+ $property = $class::mainPropertyName();
+ if ($property) {
+ $data = $value->{$property};
}
}
- if (empty($matches)) {
- $this->context->addViolation($constraint->message);
+ if ($data) {
+ $matches = [];
+ foreach (Instagram::$validationRegexp as $pattern => $key) {
+ if (preg_match($pattern, $data, $item_matches)) {
+ $matches[] = $item_matches;
+ }
+ }
+ if (empty($matches)) {
+ $this->context->addViolation($constraint->message);
+ }
}
+
}
}
<?php
-namespace Drupal\media_entity_instagram\Plugin\MediaEntity\Type;
+namespace Drupal\media_entity_instagram\Plugin\media\Source;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
-use Drupal\Core\Form\FormStateInterface;
-use Drupal\media_entity\MediaInterface;
-use Drupal\media_entity\MediaTypeBase;
+use Drupal\Core\Field\FieldTypePluginManagerInterface;
+use Drupal\media\MediaInterface;
+use Drupal\media\MediaSourceBase;
+use Drupal\media\MediaSourceFieldConstraintsInterface;
use Drupal\media_entity_instagram\InstagramEmbedFetcher;
use GuzzleHttp\Client;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Provides media type plugin for Instagram.
*
- * @MediaType(
+ * @MediaSource(
* id = "instagram",
* label = @Translation("Instagram"),
- * description = @Translation("Provides business logic and metadata for Instagram.")
+ * description = @Translation("Provides business logic and metadata for Instagram."),
+ * allowed_field_types = {"string", "string_long", "link"},
+ * default_thumbnail_filename = "instagram.png"
* )
*/
-class Instagram extends MediaTypeBase {
-
- /**
- * Config factory service.
- *
- * @var \Drupal\Core\Config\ConfigFactoryInterface
- */
- protected $configFactory;
+class Instagram extends MediaSourceBase implements MediaSourceFieldConstraintsInterface {
/**
* The instagram fetcher.
* Entity field manager service.
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* Config factory service.
+ * @param \Drupal\Core\Field\FieldTypePluginManagerInterface $field_type_manager
+ * The field type plugin manager service.
* @param \Drupal\media_entity_instagram\InstagramEmbedFetcher $fetcher
* Instagram fetcher service.
* @param \GuzzleHttp\Client $httpClient
* Guzzle client.
*/
- public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager, ConfigFactoryInterface $config_factory, InstagramEmbedFetcher $fetcher, Client $httpClient) {
- parent::__construct($configuration, $plugin_id, $plugin_definition, $entity_type_manager, $entity_field_manager, $config_factory->get('media_entity.settings'));
- $this->configFactory = $config_factory;
+ public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager, ConfigFactoryInterface $config_factory, FieldTypePluginManagerInterface $field_type_manager, InstagramEmbedFetcher $fetcher, Client $httpClient) {
+ parent::__construct($configuration, $plugin_id, $plugin_definition, $entity_type_manager, $entity_field_manager, $field_type_manager, $config_factory);
$this->fetcher = $fetcher;
$this->httpClient = $httpClient;
}
$container->get('entity_type.manager'),
$container->get('entity_field.manager'),
$container->get('config.factory'),
+ $container->get('plugin.manager.field.field_type'),
$container->get('media_entity_instagram.instagram_embed_fetcher'),
$container->get('http_client')
);
/**
* {@inheritdoc}
*/
- public function providedFields() {
+ public function getMetadataAttributes() {
return [
'shortcode' => $this->t('Instagram shortcode'),
'id' => $this->t('Media ID'),
/**
* {@inheritdoc}
*/
- public function getField(MediaInterface $media, $name) {
+ public function getMetadata(MediaInterface $media, $attribute_name) {
+ if ($attribute_name == 'default_name') {
+ // Try to get some fields that need the API, if not available, just use
+ // the shortcode as default name.
+ $username = $this->getMetadata($media, 'username');
+ $id = $this->getMetadata($media, 'id');
+ if ($username && $id) {
+ return $username . ' - ' . $id;
+ }
+ else {
+ $code = $this->getMetadata($media, 'shortcode');
+ if (!empty($code)) {
+ return $code;
+ }
+ }
+ // Fallback to the parent's default name if everything else failed.
+ return parent::getMetadata($media, 'default_name');
+ }
+ elseif ($attribute_name == 'thumbnail_uri') {
+ return $this->getMetadata($media, 'thumbnail_local');
+ }
+
$matches = $this->matchRegexp($media);
if (!$matches['shortcode']) {
return FALSE;
}
- if ($name == 'shortcode') {
+ if ($attribute_name == 'shortcode') {
return $matches['shortcode'];
}
// If we have auth settings return the other fields.
if ($instagram = $this->fetcher->fetchInstagramEmbed($matches['shortcode'])) {
- switch ($name) {
+ switch ($attribute_name) {
case 'id':
if (isset($instagram['media_id'])) {
return $instagram['media_id'];
return 'http://instagram.com/p/' . $matches['shortcode'] . '/media/?size=m';
case 'thumbnail_local':
- $local_uri = $this->getField($media, 'thumbnail_local_uri');
+ $local_uri = $this->getMetadata($media, 'thumbnail_local_uri');
if ($local_uri) {
if (file_exists($local_uri)) {
$directory = dirname($local_uri);
file_prepare_directory($directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
- $image_url = $this->getField($media, 'thumbnail');
+ $image_url = $this->getMetadata($media, 'thumbnail');
$response = $this->httpClient->get($image_url);
if ($response->getStatusCode() == 200) {
/**
* {@inheritdoc}
*/
- public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
- $options = [];
- $bundle = $form_state->getFormObject()->getEntity();
- $allowed_field_types = ['string', 'string_long', 'link'];
- foreach ($this->entityFieldManager->getFieldDefinitions('media', $bundle->id()) as $field_name => $field) {
- if (in_array($field->getType(), $allowed_field_types) && !$field->getFieldStorageDefinition()->isBaseField()) {
- $options[$field_name] = $field->getLabel();
- }
- }
-
- $form['source_field'] = [
- '#type' => 'select',
- '#title' => $this->t('Field with source information'),
- '#description' => $this->t('Field on media entity that stores Instagram embed code or URL. You can create a bundle without selecting a value for this dropdown initially. This dropdown can be populated after adding fields to the bundle.'),
- '#default_value' => empty($this->configuration['source_field']) ? NULL : $this->configuration['source_field'],
- '#options' => $options,
- ];
-
- return $form;
- }
-
- /**
- * {@inheritdoc}
- */
- public function attachConstraints(MediaInterface $media) {
- parent::attachConstraints($media);
-
- if (isset($this->configuration['source_field'])) {
- $source_field_name = $this->configuration['source_field'];
- if ($media->hasField($source_field_name)) {
- foreach ($media->get($source_field_name) as &$embed_code) {
- /** @var \Drupal\Core\TypedData\DataDefinitionInterface $typed_data */
- $typed_data = $embed_code->getDataDefinition();
- $typed_data->addConstraint('InstagramEmbedCode');
- }
- }
- }
+ public function getSourceFieldConstraints() {
+ return ['InstagramEmbedCode' => []];
}
/**
* Runs preg_match on embed code/URL.
*
- * @param \Drupal\media_entity\MediaInterface $media
+ * @param \Drupal\media\MediaInterface $media
* Media object.
*
* @return array|bool
return FALSE;
}
- /**
- * {@inheritdoc}
- */
- public function getDefaultThumbnail() {
- return $this->config->get('icon_base') . '/instagram.png';
- }
-
- /**
- * {@inheritdoc}
- */
- public function thumbnail(MediaInterface $media) {
- if ($local_image = $this->getField($media, 'thumbnail_local')) {
- return $local_image;
- }
-
- return $this->getDefaultThumbnail();
- }
-
- /**
- * {@inheritdoc}
- */
- public function getDefaultName(MediaInterface $media) {
- // Try to get some fields that need the API, if not available, just use the
- // shortcode as default name.
- $username = $this->getField($media, 'username');
- $id = $this->getField($media, 'id');
- if ($username && $id) {
- return $username . ' - ' . $id;
- }
- else {
- $code = $this->getField($media, 'shortcode');
- if (!empty($code)) {
- return $code;
- }
- }
-
- return parent::getDefaultName($media);
- }
-
}
<?php
-namespace Drupal\media_entity_instagram\Tests;
+namespace Drupal\Tests\media_entity_instagram\Functional;
-use Drupal\simpletest\WebTestBase;
+use Drupal\media_entity\Entity\MediaBundle;
use Drupal\media_entity\Tests\MediaTestTrait;
+use Drupal\Tests\BrowserTestBase;
/**
* Tests for Instagram embed formatter.
*
* @group media_entity_instagram
*/
-class InstagramEmbedFormatterTest extends WebTestBase {
+class InstagramEmbedFormatterTest extends BrowserTestBase {
/**
* Modules to enable.
// Assert that the media bundle has the expected values before proceeding.
$this->drupalGet('admin/structure/media/manage/' . $bundle->id());
- $this->assertFieldByName('label', $bundle->label());
- $this->assertFieldByName('type', 'instagram');
+ $this->assertSession()->fieldValueEquals('label', $bundle->label());
+ $this->assertSession()->fieldValueEquals('type', 'instagram');
// Add and save field settings (Embed code).
$this->drupalGet('admin/structure/media/manage/' . $bundle->id() . '/fields/add-field');
'field_name' => 'embed_code',
];
$this->drupalPostForm(NULL, $edit_conf, t('Save and continue'));
- $this->assertText('These settings apply to the ' . $edit_conf['label'] . ' field everywhere it is used.');
+ $this->assertSession()->pageTextContains('These settings apply to the ' . $edit_conf['label'] . ' field everywhere it is used.');
$edit = [
'cardinality' => 'number',
'cardinality_number' => '1',
];
$this->drupalPostForm(NULL, $edit, t('Save field settings'));
- $this->assertText('Updated field ' . $edit_conf['label'] . ' field settings.');
+ $this->assertSession()->pageTextContains('Updated field ' . $edit_conf['label'] . ' field settings.');
// Set the new field as required.
$edit = [
'required' => TRUE,
];
$this->drupalPostForm(NULL, $edit, t('Save settings'));
- $this->assertText('Saved ' . $edit_conf['label'] . ' configuration.');
+ $this->assertSession()->pageTextContains('Saved ' . $edit_conf['label'] . ' configuration.');
// Assert that the new field configuration has been successfully saved.
- $xpath = $this->xpath('//*[@id="field-embed-code"]');
- $this->assertEqual((string) $xpath[0]->td[0], 'Embed code');
- $this->assertEqual((string) $xpath[0]->td[1], 'field_embed_code');
- $this->assertEqual((string) $xpath[0]->td[2]->a, 'Text (plain, long)');
+ $this->assertEquals('Embed code', $this->xpath('//*[@id="field-embed-code"]/td[1]')[0]->getText());
+ $this->assertEquals('field_embed_code', $this->xpath('//*[@id="field-embed-code"]/td[2]')[0]->getText());
+ $this->assertEquals('Text (plain, long)', $this->xpath('//*[@id="field-embed-code"]/td[3]')[0]->getText());
// Test if edit worked and if new field values have been saved as
// expected.
$this->drupalGet('admin/structure/media/manage/' . $bundle->id());
- $this->assertFieldByName('label', $bundle->label());
- $this->assertFieldByName('type', 'instagram');
- $this->assertFieldByName('type_configuration[instagram][source_field]', 'field_embed_code');
+ $this->assertSession()->fieldValueEquals('label', $bundle->label());
+ $this->assertSession()->fieldValueEquals('type', 'instagram');
+ $this->assertSession()->fieldValueEquals('type_configuration[instagram][source_field]', 'field_embed_code');
$this->drupalPostForm(NULL, NULL, t('Save media bundle'));
- $this->assertText('The media bundle ' . $bundle->label() . ' has been updated.');
- $this->assertText($bundle->label());
+ $this->assertSession()->pageTextContains('The media bundle ' . $bundle->label() . ' has been updated.');
+ $this->assertSession()->pageTextContains($bundle->label());
$this->drupalGet('admin/structure/media/manage/' . $bundle->id() . '/display');
'fields[field_embed_code][type]' => 'instagram_embed',
];
$this->drupalPostForm(NULL, $edit, t('Save'));
- $this->assertText('Your settings have been saved.');
+ $this->assertSession()->pageTextContains('Your settings have been saved.');
// First set absolute size of the embed.
- $this->drupalPostAjaxForm(NULL, [], 'field_embed_code_settings_edit');
+ $this->submitForm([], 'field_embed_code_settings_edit');
$edit = [
'fields[field_embed_code][settings_edit_form][settings][hidecaption]' => FALSE,
];
- $this->drupalPostAjaxForm(NULL, $edit, 'field_embed_code_plugin_settings_update');
+ $this->submitForm($edit, 'field_embed_code_plugin_settings_update');
$this->drupalPostForm(NULL, [], t('Save'));
- $this->assertText('Your settings have been saved.');
- $this->assertText('Caption: Visible');
+ $this->assertSession()->pageTextContains('Your settings have been saved.');
+ $this->assertSession()->pageTextContains('Caption: Visible');
// Create and save the media with an instagram media code.
$this->drupalGet('media/add/' . $bundle->id());
$this->drupalPostForm(NULL, $edit, t('Save and publish'));
// Assert that the media has been successfully saved.
- $this->assertText('My test instagram');
- $this->assertText('Embed code');
+ $this->assertSession()->pageTextContains('My test instagram');
+ $this->assertSession()->pageTextContains('Embed code');
// Assert that the formatter exists on this page and that it has absolute
// size.
$this->assertFieldByXPath('//blockquote');
- $this->assertRaw('platform.instagram.com/en_US/embeds.js');
+ $this->assertSession()->responseContains('platform.instagram.com/en_US/embeds.js');
+ }
+
+ /**
+ * Creates media bundle.
+ *
+ * @param array $values
+ * The media bundle values.
+ * @param string $type_name
+ * (optional) The media type provider plugin that is responsible for
+ * additional logic related to this media).
+ *
+ * @return \Drupal\Core\Entity\EntityInterface
+ * Returns newly created media bundle.
+ */
+ protected function drupalCreateMediaBundle(array $values = [], $type_name = 'generic') {
+ if (!isset($values['bundle'])) {
+ $id = strtolower($this->randomMachineName());
+ }
+ else {
+ $id = $values['bundle'];
+ }
+ $values += [
+ 'id' => $id,
+ 'label' => $id,
+ 'type' => $type_name,
+ 'type_configuration' => [],
+ 'field_map' => [],
+ 'new_revision' => FALSE,
+ ];
+
+ $bundle = MediaBundle::create($values);
+ $status = $bundle->save();
+
+ $this->assertEquals(SAVED_NEW, $status, t('Created media bundle %bundle.', ['%bundle' => $bundle->id()]));
+
+ return $bundle;
}
}
/**
* Tests media_entity_instagram constrains.
*
- * @group media_entity
+ * @group media
*/
class ConstraintsTest extends UnitTestCase {
-media_entity.bundle.type.slideshow:
- type: mapping
- label: 'Slideshow type configuration'
- mapping:
- source_field:
- type: string
- label: 'Field with slideshow items'
+media.source.slideshow:
+ type: media.source.field_aware
+ label: '"Slideshow" media source configuration'
package: Media
# core: 8.x
dependencies:
- - media_entity
+ - drupal:media (>= 8.4)
-# Information added by Drupal.org packaging script on 2016-08-08
-version: '8.x-1.2'
+# Information added by Drupal.org packaging script on 2017-09-29
+version: '8.x-2.0-alpha1'
core: '8.x'
project: 'media_entity_slideshow'
-datestamp: 1470687840
+datestamp: 1506688453
*/
function media_entity_slideshow_install() {
$source = drupal_get_path('module', 'media_entity_slideshow') . '/images/icons';
- $destination = \Drupal::config('media_entity.settings')->get('icon_base');
- media_entity_copy_icons($source, $destination);
+ $destination = \Drupal::config('media.settings')->get('icon_base_uri');
+ file_prepare_directory($destination, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
+
+ $files = file_scan_directory($source, '/.*\.(svg|png|jpg|jpeg|gif)$/');
+ foreach ($files as $file) {
+ // When reinstalling the media module we don't want to copy the icons when
+ // they already exist. The icons could be replaced (by a contrib module or
+ // manually), so we don't want to replace the existing files. Removing the
+ // files when we uninstall could also be a problem if the files are
+ // referenced somewhere else. Since showing an error that it was not
+ // possible to copy the files is also confusing, we silently do nothing.
+ if (!file_exists($destination . DIRECTORY_SEPARATOR . $file->filename)) {
+ file_unmanaged_copy($file->uri, $destination, FILE_EXISTS_ERROR);
+ }
+ }
+}
+
+/**
+ * Implements hook_requirements().
+ */
+function media_entity_slideshow_requirements($phase) {
+ $requirements = [];
+ if ($phase == 'install') {
+ $destination = 'public://media-icons/generic';
+ file_prepare_directory($destination, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
+ $is_writable = is_writable($destination);
+ $is_directory = is_dir($destination);
+ if (!$is_writable || !$is_directory) {
+ if (!$is_directory) {
+ $error = t('The directory %directory does not exist.', ['%directory' => $destination]);
+ }
+ else {
+ $error = t('The directory %directory is not writable.', ['%directory' => $destination]);
+ }
+ $description = t('An automated attempt to create this directory failed, possibly due to a permissions problem. To proceed with the installation, either create the directory and modify its permissions manually or ensure that the installer has the permissions to create it automatically. For more information, see INSTALL.txt or the <a href=":handbook_url">online handbook</a>.', [':handbook_url' => 'https://www.drupal.org/server-permissions']);
+ if (!empty($error)) {
+ $description = $error . ' ' . $description;
+ $requirements['media_entity_slideshow']['description'] = $description;
+ $requirements['media_entity_slideshow']['severity'] = REQUIREMENT_ERROR;
+ }
+ }
+ }
+
+ return $requirements;
}
+++ /dev/null
-<?php
-
-namespace Drupal\media_entity_slideshow\Plugin\MediaEntity\Type;
-
-use Drupal\media_entity\MediaInterface;
-use Drupal\media_entity\MediaTypeBase;
-use Drupal\Core\Form\FormStateInterface;
-
-/**
- * Provides media type plugin for Slideshows.
- *
- * @MediaType(
- * id = "slideshow",
- * label = @Translation("Slideshow"),
- * description = @Translation("Provides business logic and metadata for slideshows.")
- * )
- */
-class Slideshow extends MediaTypeBase {
-
- /**
- * {@inheritdoc}
- */
- public function providedFields() {
- $fields = array(
- 'length' => $this->t('Slideshow length'),
- );
-
- return $fields;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getField(MediaInterface $media, $name) {
- $source_field = $this->configuration['source_field'];
-
- switch ($name) {
- case 'length':
- return $media->{$source_field}->count();
- }
-
- return FALSE;
- }
-
- /**
- * {@inheritdoc}
- */
- public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
- /** @var MediaBundleInterface $bundle */
- $bundle = $form_state->getFormObject()->getEntity();
- $options = [];
- $allowed_field_types = ['entity_reference'];
- /** @var \Drupal\Core\Field\FieldDefinitionInterface $field */
- foreach ($this->entityFieldManager->getFieldDefinitions('media', $bundle->id()) as $field_name => $field) {
- if (in_array($field->getType(), $allowed_field_types)) {
- $storage = $field->getFieldStorageDefinition();
- if (!$storage->isBaseField() && $storage->getSetting('target_type') == 'media') {
- $options[$field_name] = $field->getLabel();
- }
- }
- }
-
- $form['source_field'] = [
- '#type' => 'select',
- '#title' => $this->t('Field with source information'),
- '#description' => $this->t('Field on media entity that stores slideshow items. You can create a bundle without selecting a value for this dropdown initially. This dropdown can be populated after adding fields to the bundle.'),
- '#default_value' => empty($this->configuration['source_field']) ? NULL : $this->configuration['source_field'],
- '#options' => $options,
- ];
-
- return $form;
- }
-
- /**
- * {@inheritdoc}
- */
- public function attachConstraints(MediaInterface $media) {
- parent::attachConstraints($media);
-
- $source_field_name = $this->configuration['source_field'];
- // Validate slideshow items count.
- $media->getTypedData()->getDataDefinition()->addConstraint('ItemsCount', array('sourceFieldName' => $source_field_name));
- }
-
- /**
- * {@inheritdoc}
- */
- public function getDefaultThumbnail() {
- return $this->config->get('icon_base') . '/slideshow.png';
- }
-
- /**
- * {@inheritdoc}
- */
- public function thumbnail(MediaInterface $media) {
- $source_field = $this->configuration['source_field'];
-
- /** @var \Drupal\media_entity\MediaInterface $slideshow_item */
- $slideshow_item = $this->entityTypeManager->getStorage('media')->load($media->{$source_field}->target_id);
- if (!$slideshow_item) {
- return $this->getDefaultThumbnail();
- }
-
- /** @var \Drupal\media_entity\MediaBundleInterface $bundle */
- $bundle = $this->entityTypeManager->getStorage('media_bundle')->load($slideshow_item->bundle());
- if (!$bundle) {
- return $this->getDefaultThumbnail();
- }
-
- $thumbnail = $bundle->getType()->thumbnail($slideshow_item);
- if (!$thumbnail) {
- return $this->getDefaultThumbnail();
- }
-
- return $thumbnail;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getDefaultName(MediaInterface $media) {
- // The default name will be the timestamp + number of slides.
- $length = $this->getField($media, 'length');
- if (!empty($length)) {
- return $this->formatPlural($length,
- '1 slide, created on @date',
- '@count slides, created on @date',
- ['@date' => \Drupal::service('date.formatter')->format($media->getCreatedTime(), 'custom', 'd/M/Y - H:i:s')]);
- }
-
- return parent::getDefaultName($media);
- }
-
-}
--- /dev/null
+<?php
+
+namespace Drupal\media_entity_slideshow\Plugin\media\Source;
+
+use Drupal\media\MediaInterface;
+use Drupal\media\MediaSourceBase;
+use Drupal\media\MediaSourceEntityConstraintsInterface;
+
+/**
+ * Provides media type plugin for Slideshows.
+ *
+ * @MediaSource(
+ * id = "slideshow",
+ * label = @Translation("Slideshow"),
+ * description = @Translation("Provides business logic and metadata for slideshows."),
+ * default_thumbnail_filename = "slideshow.png",
+ * allowed_field_types = {"entity_reference"},
+ * )
+ */
+class Slideshow extends MediaSourceBase implements MediaSourceEntityConstraintsInterface {
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getMetadataAttributes() {
+ $attributes = [
+ 'length' => $this->t('Slideshow length'),
+ ];
+
+ return $attributes;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getMetadata(MediaInterface $media, $name) {
+ $source_field = $this->configuration['source_field'];
+
+ switch ($name) {
+ case 'default_name':
+ // The default name will be the timestamp + number of slides.
+ $length = $this->getMetadata($media, 'length');
+ if (!empty($length)) {
+ return $this->formatPlural($length,
+ '1 slide, created on @date',
+ '@count slides, created on @date',
+ [
+ '@date' => \Drupal::service('date.formatter')
+ ->format($media->getCreatedTime(), 'custom', DATETIME_DATETIME_STORAGE_FORMAT),
+ ]);
+ }
+ return parent::getMetadata($media, 'default_name');
+
+ case 'length':
+ return $media->{$source_field}->count();
+
+ case 'thumbnail_uri':
+ $source_field = $this->configuration['source_field'];
+
+ /** @var \Drupal\media\MediaInterface $slideshow_item */
+ $slideshow_item = $this->entityTypeManager->getStorage('media')->load($media->{$source_field}->target_id);
+ if (!$slideshow_item) {
+ return parent::getMetadata($media, 'thumbnail_uri');
+ }
+
+ /** @var \Drupal\media\MediaTypeInterface $bundle */
+ $bundle = $this->entityTypeManager->getStorage('media_type')->load($slideshow_item->bundle());
+ if (!$bundle) {
+ return parent::getMetadata($media, 'thumbnail_uri');
+ }
+
+ $thumbnail = $bundle->getSource()->getMetadata($slideshow_item, 'thumbnail_uri');
+ if (!$thumbnail) {
+ return parent::getMetadata($media, 'thumbnail_uri');
+ }
+
+ return $thumbnail;
+
+ default:
+ return parent::getMetadata($media, $name);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getEntityConstraints() {
+ $source_field = $this->configuration['source_field'];
+
+ return ['ItemsCount' => ['sourceFieldName' => $source_field]];
+ }
+
+}
--- /dev/null
+<?php
+
+namespace Drupal\media_entity_slideshow\Tests;
+
+use Drupal\Core\Language\Language;
+use Drupal\file\Entity\File;
+use Drupal\media\Entity\Media;
+use Drupal\simpletest\WebTestBase;
+
+/**
+ * Tests for media entity slideshow.
+ *
+ * @group media_entity_slideshow
+ */
+class MediaEntitySlideshowTest extends WebTestBase {
+
+ /**
+ * Modules to install.
+ *
+ * @var array
+ */
+ public static $modules = [
+ 'media_entity_slideshow_test',
+ 'node',
+ ];
+
+ /**
+ * The slideshow media bundle.
+ *
+ * @var \Drupal\media\MediaTypeInterface
+ */
+ protected $slideshowMediaBundle;
+
+ /**
+ * The image media bundle.
+ *
+ * @var \Drupal\media\MediaTypeInterface
+ */
+ protected $imageMediaBundle;
+
+ /**
+ * A collection of media entities, to be used in our test.
+ *
+ * @var \Drupal\media\MediaInterface[]
+ */
+ protected $mediaImageCollection;
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setUp() {
+ parent::setUp();
+ $bundle_storage = $this->container->get('entity_type.manager')->getStorage('media_type');
+ $this->slideshowMediaBundle = $bundle_storage->load('slideshow_bundle');
+ $this->imageMediaBundle = $bundle_storage->load('image_bundle');
+ $adminUser = $this->drupalCreateUser([
+ 'view media',
+ 'create media',
+ 'update media',
+ 'update any media',
+ 'delete media',
+ 'delete any media',
+ ]);
+ $this->drupalLogin($adminUser);
+
+ $this->mediaImageCollection = $this->createMediaImageCollection();
+ }
+
+ /**
+ * Tests media entity slideshow.
+ */
+ public function testMediaEntitySlideshow() {
+
+ // If we have a bundle already the schema is correct.
+ $this->assertTrue((bool) $this->slideshowMediaBundle, 'The media bundle from default configuration has been created in the database.');
+
+ // Test the creation of a media entity of the slidehsow bundle.
+ $this->drupalGet('media/add/' . $this->slideshowMediaBundle->id());
+ $edit = [
+ 'name[0][value]' => 'My first slideshow',
+ 'field_slides[0][target_id]' => $this->mediaImageCollection[0]->label() . ' (' . $this->mediaImageCollection[0]->id() . ')',
+ ];
+ $this->drupalPostForm(NULL, $edit, t('Save'));
+ $this->assertText('Slideshow bundle My first slideshow has been created', 'Slideshow media entity was correctly created.');
+ $slideshow_id = $this->container->get('entity.query')
+ ->get('media')
+ ->condition('bundle', 'slideshow_bundle')
+ ->sort('created', 'DESC')
+ ->execute();
+ $slideshow = $this->loadMedia(reset($slideshow_id));
+
+ // Add one more slide to it.
+ $this->drupalGet('media/' . $slideshow->id() . '/edit');
+ $edit = [
+ 'field_slides[0][target_id]' => $this->mediaImageCollection[0]->label() . ' (' . $this->mediaImageCollection[0]->id() . ')',
+ 'field_slides[1][target_id]' => $this->mediaImageCollection[1]->label() . ' (' . $this->mediaImageCollection[1]->id() . ')',
+ ];
+ $this->drupalPostForm(NULL, $edit, t('Save'));
+ $this->assertResponse(200, 'Form submitted correctly');
+ $slideshow = $this->loadMedia($slideshow->id());
+ $this->assertEqual($slideshow->field_slides->count(), 2, 'A new slide was correctly added to the slideshow.');
+
+ // Test removing one of the slides.
+ $this->drupalGet('media/' . $slideshow->id() . '/edit');
+ $edit = [
+ 'field_slides[0][target_id]' => $this->mediaImageCollection[0]->label() . ' (' . $this->mediaImageCollection[0]->id() . ')',
+ 'field_slides[1][target_id]' => '',
+ ];
+ $this->drupalPostForm(NULL, $edit, t('Save'));
+ $this->assertResponse(200, 'Form submitted correctly');
+ $slideshow = $this->loadMedia($slideshow->id());
+ $this->assertEqual($slideshow->field_slides->count(), 1, 'The deletion of one slide worked properly.');
+
+ // Delete the slideshow entirely.
+ $this->drupalGet('/media/' . $slideshow->id() . '/delete');
+ $this->drupalPostForm(NULL, [], t('Delete'));
+ $this->assertResponse(200, 'Form submitted correctly');
+ $this->assertText('The media My first slideshow has been deleted', 'The slideshow was correctly deleted.');
+ }
+
+ /**
+ * Creates an array of media images to be used in testing.
+ *
+ * @param int $count
+ * (optional) The number of items to create. Defaults to 3.
+ *
+ * @return \Drupal\media\MediaInterface[]
+ * An indexed array of fully-loaded media objects of bundle image.
+ */
+ private function createMediaImageCollection($count = 3) {
+ $collection = [];
+ for ($i = 1; $i <= $count; $i++) {
+ $media = Media::create([
+ 'bundle' => $this->imageMediaBundle->id(),
+ 'name' => 'Image media ' . $i,
+ 'uid' => '1',
+ 'langcode' => Language::LANGCODE_DEFAULT,
+ 'status' => TRUE,
+ ]);
+ $image = $this->getTestFile('image');
+ $media->field_imagefield->target_id = $image->id();
+ $media->save();
+ $collection[] = $media;
+ }
+ return $collection;
+ }
+
+ /**
+ * Load the specified media from the storage.
+ *
+ * @param int $id
+ * The media identifier.
+ *
+ * @return \Drupal\Core\Entity\EntityInterface
+ * The loaded media entity.
+ */
+ protected function loadMedia($id) {
+ /** @var \Drupal\Core\Entity\ContentEntityStorageInterface $storage */
+ $storage = $this->container->get('entity_type.manager')->getStorage('media');
+ return $storage->loadUnchanged($id);
+ }
+
+ /**
+ * Retrieves a sample file of the specified type.
+ *
+ * @return \Drupal\file\FileInterface
+ * A file object recently created and saved.
+ */
+ protected function getTestFile($type_name, $size = NULL) {
+ $file = current($this->drupalGetTestFiles($type_name, $size));
+ $file->filesize = filesize($file->uri);
+ /** @var \Drupal\file\FileInterface $file */
+ $file = File::create((array) $file);
+ $file->setPermanent();
+ $file->save();
+ return $file;
+ }
+
+}
--- /dev/null
+langcode: en
+status: true
+dependencies:
+ config:
+ - field.field.media.image_bundle.field_imagefield
+ - image.style.thumbnail
+ - media.type.image_bundle
+ module:
+ - image
+id: media.image_bundle.default
+targetEntityType: media
+bundle: image_bundle
+mode: default
+content:
+ created:
+ type: datetime_timestamp
+ weight: 10
+ settings: { }
+ third_party_settings: { }
+ field_imagefield:
+ weight: 11
+ settings:
+ progress_indicator: throbber
+ preview_image_style: thumbnail
+ third_party_settings: { }
+ type: image_image
+ name:
+ type: string_textfield
+ weight: -5
+ settings:
+ size: 60
+ placeholder: ''
+ third_party_settings: { }
+ uid:
+ type: entity_reference_autocomplete
+ weight: 5
+ settings:
+ match_operator: CONTAINS
+ size: 60
+ placeholder: ''
+ third_party_settings: { }
+hidden: { }
--- /dev/null
+langcode: en
+status: true
+dependencies:
+ config:
+ - field.field.media.slideshow_bundle.field_slides
+ - media.type.slideshow_bundle
+id: media.slideshow_bundle.default
+targetEntityType: media
+bundle: slideshow_bundle
+mode: default
+content:
+ created:
+ type: datetime_timestamp
+ weight: 10
+ settings: { }
+ third_party_settings: { }
+ field_slides:
+ weight: 11
+ settings:
+ match_operator: CONTAINS
+ size: 60
+ placeholder: ''
+ third_party_settings: { }
+ type: entity_reference_autocomplete
+ name:
+ type: string_textfield
+ weight: -5
+ settings:
+ size: 60
+ placeholder: ''
+ third_party_settings: { }
+ uid:
+ type: entity_reference_autocomplete
+ weight: 5
+ settings:
+ match_operator: CONTAINS
+ size: 60
+ placeholder: ''
+ third_party_settings: { }
+hidden: { }
--- /dev/null
+langcode: en
+status: true
+dependencies:
+ config:
+ - field.field.media.image_bundle.field_imagefield
+ - image.style.thumbnail
+ - media.type.image_bundle
+ module:
+ - image
+ - user
+id: media.image_bundle.default
+targetEntityType: media
+bundle: image_bundle
+mode: default
+content:
+ created:
+ label: hidden
+ type: timestamp
+ weight: 0
+ settings:
+ date_format: medium
+ custom_date_format: ''
+ timezone: ''
+ third_party_settings: { }
+ field_imagefield:
+ weight: 2
+ label: above
+ settings:
+ image_style: ''
+ image_link: ''
+ third_party_settings: { }
+ type: image
+ name:
+ label: hidden
+ type: string
+ weight: -5
+ settings:
+ link_to_entity: false
+ third_party_settings: { }
+ thumbnail:
+ type: image
+ weight: 1
+ label: hidden
+ settings:
+ image_style: thumbnail
+ image_link: ''
+ third_party_settings: { }
+ uid:
+ label: hidden
+ type: author
+ weight: 0
+ settings: { }
+ third_party_settings: { }
+hidden: { }
--- /dev/null
+langcode: en
+status: true
+dependencies:
+ config:
+ - field.field.media.slideshow_bundle.field_slides
+ - image.style.thumbnail
+ - media.type.slideshow_bundle
+ module:
+ - image
+ - user
+id: media.slideshow_bundle.default
+targetEntityType: media
+bundle: slideshow_bundle
+mode: default
+content:
+ created:
+ label: hidden
+ type: timestamp
+ weight: 0
+ settings:
+ date_format: medium
+ custom_date_format: ''
+ timezone: ''
+ third_party_settings: { }
+ field_slides:
+ weight: 2
+ label: above
+ settings:
+ link: true
+ third_party_settings: { }
+ type: entity_reference_label
+ name:
+ label: hidden
+ type: string
+ weight: -5
+ settings:
+ link_to_entity: false
+ third_party_settings: { }
+ thumbnail:
+ type: image
+ weight: 1
+ label: hidden
+ settings:
+ image_style: thumbnail
+ image_link: ''
+ third_party_settings: { }
+ uid:
+ label: hidden
+ type: author
+ weight: 0
+ settings: { }
+ third_party_settings: { }
+hidden: { }
--- /dev/null
+langcode: en
+status: true
+dependencies:
+ config:
+ - field.storage.media.field_imagefield
+ - media.type.image_bundle
+ module:
+ - image
+id: media.image_bundle.field_imagefield
+field_name: field_imagefield
+entity_type: media
+bundle: image_bundle
+label: Imagefield
+description: ''
+required: false
+translatable: false
+default_value: { }
+default_value_callback: ''
+settings:
+ file_directory: '[date:custom:Y]-[date:custom:m]'
+ file_extensions: 'png gif jpg jpeg'
+ max_filesize: ''
+ max_resolution: ''
+ min_resolution: ''
+ alt_field: true
+ alt_field_required: false
+ title_field: false
+ title_field_required: false
+ default_image:
+ uuid: ''
+ alt: ''
+ title: ''
+ width: null
+ height: null
+ handler: 'default:file'
+ handler_settings: { }
+field_type: image
--- /dev/null
+langcode: en
+status: true
+dependencies:
+ config:
+ - field.storage.media.field_slides
+ - media.type.image_bundle
+ - media.type.slideshow_bundle
+id: media.slideshow_bundle.field_slides
+field_name: field_slides
+entity_type: media
+bundle: slideshow_bundle
+label: Slides
+description: ''
+required: false
+translatable: false
+default_value: { }
+default_value_callback: ''
+settings:
+ handler: 'default:media'
+ handler_settings:
+ target_bundles:
+ image_bundle: image_bundle
+ sort:
+ field: _none
+ auto_create: false
+ auto_create_bundle: ''
+field_type: entity_reference
--- /dev/null
+langcode: en
+status: true
+dependencies:
+ module:
+ - file
+ - image
+ - media
+id: media.field_imagefield
+field_name: field_imagefield
+entity_type: media
+type: image
+settings:
+ uri_scheme: public
+ default_image:
+ uuid: ''
+ alt: ''
+ title: ''
+ width: null
+ height: null
+ target_type: file
+ display_field: false
+ display_default: false
+module: image
+locked: false
+cardinality: 1
+translatable: true
+indexes: { }
+persist_with_no_fields: false
+custom_storage: false
--- /dev/null
+langcode: en
+status: true
+dependencies:
+ module:
+ - media
+id: media.field_slides
+field_name: field_slides
+entity_type: media
+type: entity_reference
+settings:
+ target_type: media
+module: core
+locked: false
+cardinality: -1
+translatable: true
+indexes: { }
+persist_with_no_fields: false
+custom_storage: false
--- /dev/null
+langcode: en
+status: true
+dependencies:
+ module:
+ - media
+id: image_bundle
+label: 'Image bundle'
+description: ''
+source: image
+queue_thumbnail_downloads: false
+new_revision: false
+source_configuration:
+ source_field: field_imagefield
+field_map: { }
--- /dev/null
+langcode: en
+status: true
+dependencies:
+ module:
+ - media_entity_slideshow
+id: slideshow_bundle
+label: 'Slideshow bundle'
+description: ''
+source: slideshow
+queue_thumbnail_downloads: false
+new_revision: false
+source_configuration:
+ source_field: field_slides
+field_map: { }
--- /dev/null
+name: 'Media entity slideshow test'
+type: module
+description: 'Provides test bundle for media entity slideshow.'
+# core: 8.x
+package: Testing
+
+dependencies:
+ - media_entity_slideshow:media_entity_slideshow
+ - drupal:media (>= 8.4)
+ - drupal:file
+ - drupal:image
+
+# Information added by Drupal.org packaging script on 2017-09-29
+version: '8.x-2.0-alpha1'
+core: '8.x'
+project: 'media_entity_slideshow'
+datestamp: 1506688453
/**
* Tests media_entity_slideshow constraints.
*
- * @group media_entity
+ * @group media_entity_slideshow
*/
class ConstraintsTest extends UnitTestCase {
*
* @var array
*/
- protected $sourceFields = array();
+ protected $sourceFields = [];
/**
* TestMediaEntityConstraints constructor.
type: string
label: 'Base folder for thumbnails'
-media_entity.bundle.type.twitter:
- type: mapping
- label: 'Twitter type configuration'
+media.source.twitter:
+ type: media.source.field_aware
+ label: '"Twitter" media source configuration'
mapping:
- source_field:
- type: string
- label: 'Field with embed code/URL'
use_twitter_api:
type: boolean
label: 'Whether to use twitter api or not'
package: Media
# core: 8.x
dependencies:
- - media_entity
+ - drupal:media (>= 8.4)
-# Information added by Drupal.org packaging script on 2016-11-07
-version: '8.x-1.3'
+# Information added by Drupal.org packaging script on 2017-10-13
+version: '8.x-2.0-alpha2'
core: '8.x'
project: 'media_entity_twitter'
-datestamp: 1478549340
+datestamp: 1507907346
*/
function media_entity_twitter_install() {
$source = drupal_get_path('module', 'media_entity_twitter') . '/images/icons';
- $destination = \Drupal::config('media_entity.settings')->get('icon_base');
- media_entity_copy_icons($source, $destination);
+ $destination = \Drupal::config('media.settings')->get('icon_base_uri');
+ file_prepare_directory($destination, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
+
+ $files = file_scan_directory($source, '/.*\.(svg|png|jpg|jpeg|gif)$/');
+ foreach ($files as $file) {
+ // When reinstalling the media module we don't want to copy the icons when
+ // they already exist. The icons could be replaced (by a contrib module or
+ // manually), so we don't want to replace the existing files. Removing the
+ // files when we uninstall could also be a problem if the files are
+ // referenced somewhere else. Since showing an error that it was not
+ // possible to copy the files is also confusing, we silently do nothing.
+ if (!file_exists($destination . DIRECTORY_SEPARATOR . $file->filename)) {
+ file_unmanaged_copy($file->uri, $destination, FILE_EXISTS_ERROR);
+ }
+ }
+}
+
+/**
+ * Implements hook_requirements().
+ */
+function media_entity_twitter_requirements($phase) {
+ $requirements = [];
+ if ($phase == 'install') {
+ $destination = \Drupal::config('media.settings')->get('icon_base_uri');
+ file_prepare_directory($destination, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
+ $is_writable = is_writable($destination);
+ $is_directory = is_dir($destination);
+ if (!$is_writable || !$is_directory) {
+ if (!$is_directory) {
+ $error = t('The directory %directory does not exist.', ['%directory' => $destination]);
+ }
+ else {
+ $error = t('The directory %directory is not writable.', ['%directory' => $destination]);
+ }
+ $description = t('An automated attempt to create this directory failed, possibly due to a permissions problem. To proceed with the installation, either create the directory and modify its permissions manually or ensure that the installer has the permissions to create it automatically. For more information, see INSTALL.txt or the <a href=":handbook_url">online handbook</a>.', [':handbook_url' => 'https://www.drupal.org/server-permissions']);
+ if (!empty($error)) {
+ $description = $error . ' ' . $description;
+ $requirements['media_entity_twitter']['description'] = $description;
+ $requirements['media_entity_twitter']['severity'] = REQUIREMENT_ERROR;
+ }
+ }
+ }
+ return $requirements;
}
* and 'code' elements.
* @param int $code
* (optional) The general error code for the exception.
- * @param \Exception|NULL $previous
+ * @param \Exception|null $previous
* (optional) The previous exception.
*
* @see https://dev.twitter.com/overview/api/response-codes
use Drupal\Core\Field\FieldItemInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\FormatterBase;
-use Drupal\media_entity_twitter\Plugin\MediaEntity\Type\Twitter;
+use Drupal\media_entity_twitter\Plugin\media\Source\Twitter;
/**
* Plugin implementation of the 'twitter_embed' formatter.
* {@inheritdoc}
*/
public function viewElements(FieldItemListInterface $items, $langcode) {
- $element = array();
+ $element = [];
foreach ($items as $delta => $item) {
$matches = [];
namespace Drupal\media_entity_twitter\Plugin\Validation\Constraint;
-use Drupal\media_entity\EmbedCodeValueTrait;
-use Drupal\media_entity_twitter\Plugin\MediaEntity\Type\Twitter;
+use Drupal\media_entity_twitter\Plugin\media\Source\Twitter;
+use Drupal\Core\Field\FieldItemList;
+use Drupal\Core\Field\FieldItemInterface;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
*/
class TweetEmbedCodeConstraintValidator extends ConstraintValidator {
- use EmbedCodeValueTrait;
-
/**
* {@inheritdoc}
*/
public function validate($value, Constraint $constraint) {
- $value = $this->getEmbedCode($value);
- if (!isset($value)) {
- return;
+ $data = '';
+ if (is_string($value)) {
+ $data = $value;
}
-
- foreach (Twitter::$validationRegexp as $pattern => $key) {
- if (preg_match($pattern, $value)) {
- return;
+ elseif ($value instanceof FieldItemList) {
+ $fieldtype = $value->getFieldDefinition()->getType();
+ $field_value = $value->getValue();
+ if ($fieldtype == 'link') {
+ $data = empty($field_value[0]['uri']) ? "" : $field_value[0]['uri'];
+ }
+ else {
+ $data = empty($field_value[0]['value']) ? "" : $field_value[0]['value'];
+ }
+ }
+ elseif ($value instanceof FieldItemInterface) {
+ $class = get_class($value);
+ $property = $class::mainPropertyName();
+ if ($property) {
+ $data = $value->{$property};
+ }
+ }
+ if ($data) {
+ $matches = [];
+ foreach (Twitter::$validationRegexp as $pattern => $key) {
+ if (preg_match($pattern, $data, $item_matches)) {
+ $matches[] = $item_matches;
+ }
+ }
+ if (empty($matches)) {
+ $this->context->addViolation($constraint->message);
}
}
-
- $this->context->addViolation($constraint->message);
}
}
namespace Drupal\media_entity_twitter\Plugin\Validation\Constraint;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
-use Drupal\media_entity\EmbedCodeValueTrait;
-use Drupal\media_entity_twitter\Plugin\MediaEntity\Type\Twitter;
+use Drupal\media_entity_twitter\Plugin\media\Source\Twitter;
+use Drupal\Core\Field\FieldItemInterface;
use GuzzleHttp\Client;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Validator\Constraint;
*/
class TweetVisibleConstraintValidator extends ConstraintValidator implements ContainerInjectionInterface {
- use EmbedCodeValueTrait;
-
/**
* The HTTP client to fetch the feed data with.
*
* {@inheritdoc}
*/
public function validate($value, Constraint $constraint) {
- $value = $this->getEmbedCode($value);
- if (!isset($value)) {
- return;
+ $data = '';
+ if (is_string($value)) {
+ $data = $value;
+ }
+ elseif ($value instanceof FieldItemList) {
+ $fieldtype = $value->getFieldDefinition()->getType();
+ $field_value = $value->getValue();
+ if ($fieldtype == 'link') {
+ $data = empty($field_value[0]['uri']) ? "" : $field_value[0]['uri'];
+ }
+ else {
+ $data = empty($field_value[0]['value']) ? "" : $field_value[0]['value'];
+ }
+ }
+ elseif ($value instanceof FieldItemInterface) {
+ $class = get_class($value);
+ $property = $class::mainPropertyName();
+ if ($property) {
+ $data = $value->{$property};
+ }
}
-
- $matches = [];
-
foreach (Twitter::$validationRegexp as $pattern => $key) {
- if (preg_match($pattern, $value, $item_matches)) {
+ if (preg_match($pattern, $data, $item_matches)) {
$matches[] = $item_matches;
}
}
<?php
-namespace Drupal\media_entity_twitter\Plugin\MediaEntity\Type;
+namespace Drupal\media_entity_twitter\Plugin\media\Source;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Logger\LoggerChannelInterface;
use Drupal\Core\Render\RendererInterface;
-use Drupal\media_entity\MediaInterface;
-use Drupal\media_entity\MediaTypeBase;
-use Drupal\media_entity\MediaTypeException;
+use Drupal\media\MediaInterface;
+use Drupal\media\MediaSourceBase;
+use Drupal\media\MediaTypeInterface;
use Drupal\media_entity_twitter\TweetFetcherInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
+use Drupal\Core\Field\FieldTypePluginManagerInterface;
+use Drupal\media\MediaSourceFieldConstraintsInterface;
/**
- * Provides media type plugin for Twitter.
+ * Twitter entity media source.
*
- * @MediaType(
+ * @MediaSource(
* id = "twitter",
* label = @Translation("Twitter"),
+ * allowed_field_types = {"string", "string_long", "link"},
+ * default_thumbnail_filename = "twitter.png",
* description = @Translation("Provides business logic and metadata for Twitter.")
* )
*/
-class Twitter extends MediaTypeBase {
-
- /**
- * Config factory service.
- *
- * @var \Drupal\Core\Config\ConfigFactoryInterface
- */
- protected $configFactory;
+class Twitter extends MediaSourceBase implements MediaSourceFieldConstraintsInterface {
/**
* The renderer.
$plugin_definition,
$container->get('entity_type.manager'),
$container->get('entity_field.manager'),
+ $container->get('plugin.manager.field.field_type'),
$container->get('config.factory'),
$container->get('renderer'),
$container->get('media_entity_twitter.tweet_fetcher'),
*
* @var array
*/
- public static $validationRegexp = array(
+ public static $validationRegexp = [
'@((http|https):){0,1}//(www\.){0,1}twitter\.com/(?<user>[a-z0-9_-]+)/(status(es){0,1})/(?<id>[\d]+)@i' => 'id',
- );
+ ];
/**
* Constructs a new class instance.
* Entity type manager service.
* @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager
* Entity field manager service.
+ * @param \Drupal\Core\Field\FieldTypePluginManagerInterface $field_type_manager
+ * Config field type manager service.
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* Config factory service.
* @param \Drupal\Core\Render\RendererInterface $renderer
* @param \Drupal\Core\Logger\LoggerChannelInterface $logger
* The logger channel.
*/
- public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager, ConfigFactoryInterface $config_factory, RendererInterface $renderer, TweetFetcherInterface $tweet_fetcher, LoggerChannelInterface $logger) {
- parent::__construct($configuration, $plugin_id, $plugin_definition, $entity_type_manager, $entity_field_manager, $config_factory->get('media_entity.settings'));
- $this->configFactory = $config_factory;
+ public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager, FieldTypePluginManagerInterface $field_type_manager, ConfigFactoryInterface $config_factory, RendererInterface $renderer, TweetFetcherInterface $tweet_fetcher, LoggerChannelInterface $logger) {
+ parent::__construct($configuration, $plugin_id, $plugin_definition, $entity_type_manager, $entity_field_manager, $field_type_manager, $config_factory);
$this->renderer = $renderer;
$this->tweetFetcher = $tweet_fetcher;
$this->logger = $logger;
*/
public function defaultConfiguration() {
return [
+ 'source_field' => '',
'use_twitter_api' => FALSE,
'generate_thumbnails' => FALSE,
+ 'consumer_key' => '',
+ 'consumer_secret' => '',
+ 'oauth_access_token' => '',
+ 'oauth_access_token_secret' => '',
];
}
/**
* {@inheritdoc}
*/
- public function providedFields() {
- $fields = array(
+ public function getMetadataAttributes() {
+ $attributes = [
'id' => $this->t('Tweet ID'),
'user' => $this->t('Twitter user information'),
- );
+ ];
if ($this->configuration['use_twitter_api']) {
- $fields += array(
+ $attributes += [
'image' => $this->t('Link to the twitter image'),
'image_local' => $this->t('Copies tweet image to the local filesystem and returns the URI.'),
'image_local_uri' => $this->t('Gets URI of the locally saved image.'),
'content' => $this->t('This tweet content'),
'retweet_count' => $this->t('Retweet count for this tweet'),
- 'profile_image_url_https' => $this->t('Link to profile image')
- );
+ 'profile_image_url_https' => $this->t('Link to profile image'),
+ ];
}
- return $fields;
+ return $attributes;
}
/**
* {@inheritdoc}
*/
- public function getField(MediaInterface $media, $name) {
+ public function getMetadata(MediaInterface $media, $attribute_name) {
$matches = $this->matchRegexp($media);
if (!$matches['id']) {
- return FALSE;
+ return NULL;
}
// First we return the fields that are available from regex.
- switch ($name) {
+ switch ($attribute_name) {
case 'id':
return $matches['id'];
case 'user':
- if ($matches['user']) {
- return $matches['user'];
+ return $matches['user'] ?: NULL;
+
+ case 'thumbnail_uri':
+ // If there's already a local image, use it.
+ if ($local_image = $this->getMetadata($media, 'image_local')) {
+ return $local_image;
+ }
+
+ // If thumbnail generation is disabled, use the default thumbnail.
+ if (empty($this->configuration['generate_thumbnails'])) {
+ return parent::getMetadata($media, $attribute_name);
+ }
+
+ // We might need to generate a thumbnail...
+ $id = $this->getMetadata($media, 'id');
+ $thumbnail_uri = $this->getLocalImageUri($id, $media);
+
+ // ...unless we already have, in which case, use it.
+ if (file_exists($thumbnail_uri)) {
+ return $thumbnail_uri;
}
- return FALSE;
+
+ // Render the thumbnail SVG using the theme system.
+ $thumbnail = [
+ '#theme' => 'media_entity_twitter_tweet_thumbnail',
+ '#content' => $this->getMetadata($media, 'content'),
+ '#author' => $this->getMetadata($media, 'user'),
+ '#avatar' => $this->getMetadata($media, 'profile_image_url_https'),
+ ];
+ $svg = $this->renderer->renderRoot($thumbnail);
+
+ return file_unmanaged_save_data($svg, $thumbnail_uri, FILE_EXISTS_ERROR) ?: parent::getMetadata($media, $attribute_name);
}
// If we have auth settings return the other fields.
if ($this->configuration['use_twitter_api'] && $tweet = $this->fetchTweet($matches['id'])) {
- switch ($name) {
+ switch ($attribute_name) {
case 'image':
if (isset($tweet['extended_entities']['media'][0]['media_url'])) {
return $tweet['extended_entities']['media'][0]['media_url'];
}
- return FALSE;
+ return NULL;
case 'image_local':
- $local_uri = $this->getField($media, 'image_local_uri');
+ $local_uri = $this->getMetadata($media, 'image_local_uri');
if ($local_uri) {
if (file_exists($local_uri)) {
return $local_uri;
}
else {
- $image_url = $this->getField($media, 'image');
+ $image_url = $this->getMetadata($media, 'image');
// @TODO: Use Guzzle, possibly in a service, for this.
$image_data = file_get_contents($image_url);
if ($image_data) {
}
}
}
- return FALSE;
+ return NULL;
case 'image_local_uri':
- $image_url = $this->getField($media, 'image');
+ $image_url = $this->getMetadata($media, 'image');
if ($image_url) {
- return $this->getLocalImageUri($matches['id'], $image_url);
+ return $this->getLocalImageUri($matches['id'], $media, $image_url);
}
- return FALSE;
+ return NULL;
case 'content':
if (isset($tweet['text'])) {
return $tweet['text'];
}
- return FALSE;
+ return NULL;
case 'retweet_count':
if (isset($tweet['retweet_count'])) {
return $tweet['retweet_count'];
}
- return FALSE;
+ return NULL;
case 'profile_image_url_https':
if (isset($tweet['user']['profile_image_url_https'])) {
return $tweet['user']['profile_image_url_https'];
}
- return FALSE;
+ return NULL;
+
+ case 'default_name':
+ $user = $this->getMetadata($media, 'user');
+ $id = $this->getMetadata($media, 'id');
+ if (!empty($user) && !empty($id)) {
+ return $user . ' - ' . $id;
+ }
+ return NULL;
}
}
- return FALSE;
+ return NULL;
}
/**
* {@inheritdoc}
*/
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
- $options = [];
- $allowed_field_types = ['string', 'string_long', 'link'];
- /** @var \Drupal\media_entity\MediaBundleInterface $bundle */
- $bundle = $form_state->getFormObject()->getEntity();
- foreach ($this->entityFieldManager->getFieldDefinitions('media', $bundle->id()) as $field_name => $field) {
- if (in_array($field->getType(), $allowed_field_types) && !$field->getFieldStorageDefinition()->isBaseField()) {
- $options[$field_name] = $field->getLabel();
- }
- }
+ $form = parent::buildConfigurationForm($form, $form_state);
- $form['source_field'] = array(
- '#type' => 'select',
- '#title' => $this->t('Field with source information'),
- '#description' => $this->t('Field on media entity that stores Twitter embed code or URL. You can create a bundle without selecting a value for this dropdown initially. This dropdown can be populated after adding fields to the bundle.'),
- '#default_value' => empty($this->configuration['source_field']) ? NULL : $this->configuration['source_field'],
- '#options' => $options,
- );
-
- $form['use_twitter_api'] = array(
+ $form['use_twitter_api'] = [
'#type' => 'select',
'#title' => $this->t('Whether to use Twitter api to fetch tweets or not.'),
'#description' => $this->t("In order to use Twitter's api you have to create a developer account and an application. For more information consult the readme file."),
'#default_value' => empty($this->configuration['use_twitter_api']) ? 0 : $this->configuration['use_twitter_api'],
- '#options' => array(
+ '#options' => [
0 => $this->t('No'),
1 => $this->t('Yes'),
- ),
- );
+ ],
+ ];
- // @todo Evauate if this should be a site-wide configuration.
- $form['consumer_key'] = array(
+ // @todo: Evaluate if this should be a site-wide configuration.
+ $form['consumer_key'] = [
'#type' => 'textfield',
'#title' => $this->t('Consumer key'),
'#default_value' => empty($this->configuration['consumer_key']) ? NULL : $this->configuration['consumer_key'],
- '#states' => array(
- 'visible' => array(
- ':input[name="type_configuration[twitter][use_twitter_api]"]' => array('value' => '1'),
- ),
- ),
- );
+ '#states' => [
+ 'visible' => [
+ ':input[name="source_configuration[use_twitter_api]"]' => ['value' => '1'],
+ ],
+ ],
+ ];
- $form['consumer_secret'] = array(
+ $form['consumer_secret'] = [
'#type' => 'textfield',
'#title' => $this->t('Consumer secret'),
'#default_value' => empty($this->configuration['consumer_secret']) ? NULL : $this->configuration['consumer_secret'],
- '#states' => array(
- 'visible' => array(
- ':input[name="type_configuration[twitter][use_twitter_api]"]' => array('value' => '1'),
- ),
- ),
- );
+ '#states' => [
+ 'visible' => [
+ ':input[name="source_configuration[use_twitter_api]"]' => ['value' => '1'],
+ ],
+ ],
+ ];
- $form['oauth_access_token'] = array(
+ $form['oauth_access_token'] = [
'#type' => 'textfield',
'#title' => $this->t('Oauth access token'),
'#default_value' => empty($this->configuration['oauth_access_token']) ? NULL : $this->configuration['oauth_access_token'],
- '#states' => array(
- 'visible' => array(
- ':input[name="type_configuration[twitter][use_twitter_api]"]' => array('value' => '1'),
- ),
- ),
- );
+ '#states' => [
+ 'visible' => [
+ ':input[name="source_configuration[use_twitter_api]"]' => ['value' => '1'],
+ ],
+ ],
+ ];
- $form['oauth_access_token_secret'] = array(
+ $form['oauth_access_token_secret'] = [
'#type' => 'textfield',
'#title' => $this->t('Oauth access token secret'),
'#default_value' => empty($this->configuration['oauth_access_token_secret']) ? NULL : $this->configuration['oauth_access_token_secret'],
- '#states' => array(
- 'visible' => array(
- ':input[name="type_configuration[twitter][use_twitter_api]"]' => array('value' => '1'),
- ),
- ),
- );
+ '#states' => [
+ 'visible' => [
+ ':input[name="source_configuration[use_twitter_api]"]' => ['value' => '1'],
+ ],
+ ],
+ ];
$form['generate_thumbnails'] = [
'#type' => 'checkbox',
'#default_value' => $this->configuration['generate_thumbnails'],
'#states' => [
'visible' => [
- ':input[name="type_configuration[twitter][use_twitter_api]"]' => [
+ ':input[name="source_configuration[use_twitter_api]"]' => [
'checked' => TRUE,
],
],
/**
* {@inheritdoc}
*/
- public function attachConstraints(MediaInterface $media) {
- parent::attachConstraints($media);
-
- if (isset($this->configuration['source_field'])) {
- $source_field_name = $this->configuration['source_field'];
- if ($media->hasField($source_field_name)) {
- foreach ($media->get($source_field_name) as &$embed_code) {
- /** @var \Drupal\Core\TypedData\DataDefinitionInterface $typed_data */
- $typed_data = $embed_code->getDataDefinition();
- $typed_data->addConstraint('TweetEmbedCode');
- $typed_data->addConstraint('TweetVisible');
- }
- }
- }
+ public function getSourceFieldConstraints() {
+ return [
+ 'TweetEmbedCode' => [],
+ 'TweetVisible' => [],
+ ];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function createSourceField(MediaTypeInterface $type) {
+ return parent::createSourceField($type)->set('label', 'Tweet URL');
}
/**
*
* @param mixed $id
* The tweet ID.
+ * @param \Drupal\media\MediaInterface $media
+ * The media entity.
* @param string|null $media_url
* The URL of the media (i.e., photo, video, etc.) associated with the
* tweet.
* @return string
* The desired local URI.
*/
- protected function getLocalImageUri($id, $media_url = NULL) {
+ protected function getLocalImageUri($id, MediaInterface $media, $media_url = NULL) {
$directory = $this->configFactory
->get('media_entity_twitter.settings')
->get('local_images');
$this->logger->warning('Could not prepare thumbnail destination directory @dir', [
'@dir' => $directory,
]);
- return $this->getDefaultThumbnail();
+ return parent::getMetadata($media, 'thumbnail_uri');
}
$local_uri = $directory . '/' . $id . '.';
return $local_uri;
}
- /**
- * {@inheritdoc}
- */
- public function getDefaultThumbnail() {
- return $this->config->get('icon_base') . '/twitter.png';
- }
-
- /**
- * {@inheritdoc}
- */
- public function thumbnail(MediaInterface $media) {
- // If there's already a local image, use it.
- if ($local_image = $this->getField($media, 'image_local')) {
- return $local_image;
- }
-
- // If thumbnail generation is disabled, use the default thumbnail.
- if (empty($this->configuration['generate_thumbnails'])) {
- return $this->getDefaultThumbnail();
- }
-
- // We might need to generate a thumbnail...
- $id = $this->getField($media, 'id');
- $thumbnail_uri = $this->getLocalImageUri($id);
-
- // ...unless we already have, in which case, use it.
- if (file_exists($thumbnail_uri)) {
- return $thumbnail_uri;
- }
-
- // Render the thumbnail SVG using the theme system.
- $thumbnail = [
- '#theme' => 'media_entity_twitter_tweet_thumbnail',
- '#content' => $this->getField($media, 'content'),
- '#author' => $this->getField($media, 'user'),
- '#avatar' => $this->getField($media, 'profile_image_url_https'),
- ];
- $svg = $this->renderer->renderRoot($thumbnail);
-
- return file_unmanaged_save_data($svg, $thumbnail_uri, FILE_EXISTS_ERROR) ?: $this->getDefaultThumbnail();
- }
-
/**
* Runs preg_match on embed code/URL.
*
- * @param MediaInterface $media
+ * @param \Drupal\media\MediaInterface $media
* Media object.
*
* @return array|bool
* @see preg_match()
*/
protected function matchRegexp(MediaInterface $media) {
- $matches = array();
-
- if (isset($this->configuration['source_field'])) {
- $source_field = $this->configuration['source_field'];
- if ($media->hasField($source_field)) {
- $property_name = $media->{$source_field}->first()->mainPropertyName();
- foreach (static::$validationRegexp as $pattern => $key) {
- if (preg_match($pattern, $media->{$source_field}->{$property_name}, $matches)) {
- return $matches;
- }
+ $matches = [];
+
+ $source_field = $this->getSourceFieldDefinition($media->bundle->entity)->getName();
+ if ($media->hasField($source_field)) {
+ $property_name = $media->get($source_field)->first()->mainPropertyName();
+ foreach (static::$validationRegexp as $pattern => $key) {
+ if (preg_match($pattern, $media->get($source_field)->{$property_name}, $matches)) {
+ return $matches;
}
}
}
* Get a single tweet.
*
* @param int $id
- * The tweet id.
+ * The tweet ID.
+ *
+ * @return array
+ * The tweet information.
*/
protected function fetchTweet($id) {
$this->tweetFetcher->setCredentials(
$this->configuration['oauth_access_token_secret']
);
- try {
- return $this->tweetFetcher->fetchTweet($id);
- }
- catch (\Exception $e) {
- throw new MediaTypeException(NULL, $e->getMessage());
- }
- }
-
- /**
- * {@inheritdoc}
- */
- public function getDefaultName(MediaInterface $media) {
- // The default name will be the twitter username of the author + the
- // tweet ID.
- $user = $this->getField($media, 'user');
- $id = $this->getField($media, 'id');
- if (!empty($user) && !empty($id)) {
- return $user . ' - ' . $id;
- }
-
- return parent::getDefaultName($media);
+ return $this->tweetFetcher->fetchTweet($id);
}
}
+++ /dev/null
-<?php
-
-namespace Drupal\media_entity_twitter\Tests;
-
-use Drupal\simpletest\WebTestBase;
-use Drupal\media_entity\Tests\MediaTestTrait;
-
-/**
- * Tests for Twitter embed formatter.
- *
- * @group media_entity_twitter
- */
-class TweetEmbedFormatterTest extends WebTestBase {
-
- use MediaTestTrait;
-
- /**
- * Modules to enable.
- *
- * @var array
- */
- public static $modules = array(
- 'media_entity_twitter',
- 'media_entity',
- 'node',
- 'field_ui',
- 'views_ui',
- 'block',
- 'link',
- );
-
- /**
- * The test user.
- *
- * @var \Drupal\User\UserInterface
- */
- protected $adminUser;
-
- /**
- * Media entity machine id.
- *
- * @var string
- */
- protected $mediaId = 'twitter';
-
- /**
- * The test media bundle.
- *
- * @var \Drupal\media_entity\MediaBundleInterface
- */
- protected $testBundle;
-
- /**
- * {@inheritdoc}
- */
- protected function setUp() {
- parent::setUp();
-
- $bundle['bundle'] = $this->mediaId;
- $this->testBundle = $this->drupalCreateMediaBundle($bundle, 'twitter');
- $this->drupalPlaceBlock('local_actions_block');
- $this->adminUser = $this->drupalCreateUser([
- 'administer media',
- 'administer media bundles',
- 'administer media fields',
- 'administer media form display',
- 'administer media display',
- // Media entity permissions.
- 'view media',
- 'create media',
- 'update media',
- 'update any media',
- 'delete media',
- 'delete any media',
- // Other permissions.
- 'administer views',
- ]);
- $this->drupalLogin($this->adminUser);
- }
-
- /**
- * Tests adding and editing a twitter embed formatter.
- */
- public function testManageEmbedFormatter() {
- // Test and create one media bundle.
- $bundle = $this->testBundle;
-
- // Assert that the media bundle has the expected values before proceeding.
- $this->drupalGet('admin/structure/media/manage/' . $bundle->id());
- $this->assertFieldByName('label', $bundle->label());
- $this->assertFieldByName('type', 'twitter');
-
- // Add and save link field type settings (Embed code).
- $this->drupalGet('admin/structure/media/manage/' . $bundle->id() . '/fields/add-field');
- $edit_conf = [
- 'new_storage_type' => 'link',
- 'label' => 'Link URL',
- 'field_name' => 'link_url',
- ];
- $this->drupalPostForm(NULL, $edit_conf, t('Save and continue'));
- $this->assertText('These settings apply to the ' . $edit_conf['label'] . ' field everywhere it is used.');
- $edit = [
- 'cardinality' => 'number',
- 'cardinality_number' => '1',
- ];
- $this->drupalPostForm(NULL, $edit, t('Save field settings'));
- $this->assertText('Updated field ' . $edit_conf['label'] . ' field settings.');
-
- // Set the new link field type as required.
- $edit = [
- 'required' => TRUE,
- 'settings[link_type]' => '16',
- 'settings[title]' => '0',
- ];
- $this->drupalPostForm(NULL, $edit, t('Save settings'));
- $this->assertText('Saved ' . $edit_conf['label'] . ' configuration.');
-
- // Add and save string_long field type settings (Embed code).
- $this->drupalGet('admin/structure/media/manage/' . $bundle->id() . '/fields/add-field');
- $edit_conf = [
- 'new_storage_type' => 'string_long',
- 'label' => 'Embed code',
- 'field_name' => 'embed_code',
- ];
- $this->drupalPostForm(NULL, $edit_conf, t('Save and continue'));
- $this->assertText('These settings apply to the ' . $edit_conf['label'] . ' field everywhere it is used.');
- $edit = [
- 'cardinality' => 'number',
- 'cardinality_number' => '1',
- ];
- $this->drupalPostForm(NULL, $edit, t('Save field settings'));
- $this->assertText('Updated field ' . $edit_conf['label'] . ' field settings.');
-
- // Set the new string_long field type as required.
- $edit = [
- 'required' => TRUE,
- ];
- $this->drupalPostForm(NULL, $edit, t('Save settings'));
- $this->assertText('Saved ' . $edit_conf['label'] . ' configuration.');
-
- // Assert that the new field types configurations have been successfully
- // saved.
- $xpath = $this->xpath('//*[@id="field-link-url"]');
- $this->assertEqual((string) $xpath[0]->td[0], 'Link URL');
- $this->assertEqual((string) $xpath[0]->td[1], 'field_link_url');
- $this->assertEqual((string) $xpath[0]->td[2]->a, 'Link');
-
- $xpath = $this->xpath('//*[@id="field-embed-code"]');
- $this->assertEqual((string) $xpath[0]->td[0], 'Embed code');
- $this->assertEqual((string) $xpath[0]->td[1], 'field_embed_code');
- $this->assertEqual((string) $xpath[0]->td[2]->a, 'Text (plain, long)');
-
- // Test if edit worked and if new fields values have been saved as
- // expected.
- $this->drupalGet('admin/structure/media/manage/' . $bundle->id());
- $this->assertFieldByName('label', $bundle->label());
- $this->assertFieldByName('type', 'twitter');
- $this->assertFieldByName('type_configuration[twitter][source_field]', 'field_embed_code');
- $this->drupalPostForm(NULL, NULL, t('Save media bundle'));
- $this->assertText('The media bundle ' . $bundle->label() . ' has been updated.');
- $this->assertText($bundle->label());
-
- $this->drupalGet('admin/structure/media/manage/' . $bundle->id() . '/display');
-
- // Set and save the settings of the new field types.
- $edit = [
- 'fields[field_link_url][label]' => 'above',
- 'fields[field_link_url][type]' => 'twitter_embed',
- 'fields[field_embed_code][label]' => 'above',
- 'fields[field_embed_code][type]' => 'twitter_embed',
- ];
- $this->drupalPostForm(NULL, $edit, t('Save'));
- $this->assertText('Your settings have been saved.');
-
- // Create and save the media with a twitter media code.
- $this->drupalGet('media/add/' . $bundle->id());
-
- // Random image url from twitter.
- $tweet_url = 'https://twitter.com/RamzyStinson/status/670650348319576064';
-
- // Random image from twitter.
- $tweet = '<blockquote class="twitter-tweet" lang="it"><p lang="en" dir="ltr">' .
- 'Midnight project. I ain't got no oven. So I improvise making this milo crunchy kek batik. hahahaha ' .
- '<a href="https://twitter.com/hashtag/itssomething?src=hash">#itssomething</a> ' .
- '<a href="https://t.co/Nvn4Q1v2ae">pic.twitter.com/Nvn4Q1v2ae</a></p>— Zi (@RamzyStinson) ' .
- '<a href="https://twitter.com/RamzyStinson/status/670650348319576064">' .
- '28 Novembre 2015</a></blockquote><script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>';
-
- $edit = [
- 'name[0][value]' => 'Title',
- 'field_link_url[0][uri]' => $tweet_url,
- 'field_embed_code[0][value]' => $tweet,
- ];
- $this->drupalPostForm(NULL, $edit, t('Save and publish'));
-
- // Assert that the media has been successfully saved.
- $this->assertText('Title');
-
- // Assert that the link url formatter exists on this page.
- $this->assertText('Link URL');
- $this->assertRaw('<a href="https://twitter.com/RamzyStinson/statuses/670650348319576064">', 'Link in embedded Tweet found.');
-
- // Assert that the string_long code formatter exists on this page.
- $this->assertText('Embed code');
- $this->assertRaw('<blockquote class="twitter-tweet', 'Embedded Tweet found.');
- }
-
-}
/**
* TweetFetcher constructor.
*
- * @param \Drupal\Core\Cache\CacheBackendInterface|NULL $cache
+ * @param \Drupal\Core\Cache\CacheBackendInterface|null $cache
* (optional) A cache bin for storing fetched tweets.
*/
public function __construct(CacheBackendInterface $cache = NULL) {
*
* @param int $id
* The tweet ID.
-
+ *
* @return array
* The tweet information.
*
*
* @param string $consumer_key
* The consumer key.
- * @param $consumer_secret
+ * @param string $consumer_secret
* The consumer secret.
* @param string $oauth_access_token
* The OAuth access token.
--- /dev/null
+<?php
+
+namespace Drupal\Tests\media_entity_twitter\Functional;
+
+use Drupal\Tests\media\Functional\MediaFunctionalTestBase;
+
+/**
+ * Tests for Twitter embed formatter.
+ *
+ * @group media_entity_twitter
+ */
+class TweetEmbedFormatterTest extends MediaFunctionalTestBase {
+
+ /**
+ * Modules to enable.
+ *
+ * @var array
+ */
+ public static $modules = [
+ 'media_entity_twitter',
+ 'link',
+ ];
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function setUp() {
+ parent::setUp();
+ }
+
+ /**
+ * Tests adding and editing a twitter embed formatter.
+ */
+ public function testManageEmbedFormatter() {
+ // Test and create one media type.
+ $bundle = $this->createMediaType(['bundle' => 'twitter'], 'twitter');
+
+ // We need to fix widget and formatter config for the default field.
+ $source = $bundle->getSource();
+ $source_field = $source->getSourceFieldDefinition($bundle);
+ // Use the default widget and settings.
+ $component = \Drupal::service('plugin.manager.field.widget')
+ ->prepareConfiguration('string', []);
+
+ // @todo Replace entity_get_form_display() when #2367933 is done.
+ // https://www.drupal.org/node/2872159.
+ entity_get_form_display('media', $bundle->id(), 'default')
+ ->setComponent($source_field->getName(), $component)
+ ->save();
+
+ // Assert that the media type has the expected values before proceeding.
+ $this->drupalGet('admin/structure/media/manage/' . $bundle->id());
+ $this->assertFieldByName('label', $bundle->label());
+ $this->assertFieldByName('source', 'twitter');
+
+ // Add and save string_long field type settings (Embed code).
+ $this->drupalGet('admin/structure/media/manage/' . $bundle->id() . '/fields/add-field');
+ $edit_conf = [
+ 'new_storage_type' => 'string_long',
+ 'label' => 'Embed code',
+ 'field_name' => 'embed_code',
+ ];
+ $this->drupalPostForm(NULL, $edit_conf, t('Save and continue'));
+ $this->assertText('These settings apply to the ' . $edit_conf['label'] . ' field everywhere it is used.');
+ $edit = [
+ 'cardinality' => 'number',
+ 'cardinality_number' => '1',
+ ];
+ $this->drupalPostForm(NULL, $edit, t('Save field settings'));
+ $this->assertText('Updated field ' . $edit_conf['label'] . ' field settings.');
+
+ // Set the new string_long field type as required.
+ $edit = [
+ 'required' => TRUE,
+ ];
+ $this->drupalPostForm(NULL, $edit, t('Save settings'));
+ $this->assertText('Saved ' . $edit_conf['label'] . ' configuration.');
+
+ // Assert that the new field types configurations have been successfully
+ // saved.
+ $this->drupalGet('admin/structure/media/manage/' . $bundle->id() . '/fields');
+ $xpath = $this->xpath('//*[@id=:id]/td', [':id' => 'field-media-twitter']);
+ $this->assertEqual((string) $xpath[0]->getText(), 'Tweet Url');
+ $this->assertEqual((string) $xpath[1]->getText(), 'field_media_twitter');
+ $this->assertEqual((string) $xpath[2]->find('css', 'a')->getText(), 'Text (plain)');
+
+ $xpath = $this->xpath('//*[@id=:id]/td', [':id' => 'field-embed-code']);
+ $this->assertEqual((string) $xpath[0]->getText(), 'Embed code');
+ $this->assertEqual((string) $xpath[1]->getText(), 'field_embed_code');
+ $this->assertEqual((string) $xpath[2]->find('css', 'a')->getText(), 'Text (plain, long)');
+
+ $this->drupalGet('admin/structure/media/manage/' . $bundle->id() . '/display');
+
+ // Set and save the settings of the new field types.
+ $edit = [
+ 'fields[field_media_twitter][parent]' => 'content',
+ 'fields[field_media_twitter][region]' => 'content',
+ 'fields[field_media_twitter][label]' => 'above',
+ 'fields[field_media_twitter][type]' => 'twitter_embed',
+ 'fields[field_embed_code][label]' => 'above',
+ 'fields[field_embed_code][type]' => 'twitter_embed',
+ ];
+ $this->drupalPostForm(NULL, $edit, t('Save'));
+ $this->assertText('Your settings have been saved.');
+
+ // Create and save the media with a twitter media code.
+ $this->drupalGet('media/add/' . $bundle->id());
+
+ // Random image url from twitter.
+ $tweet_url = 'https://twitter.com/RamzyStinson/status/670650348319576064';
+
+ // Random image from twitter.
+ $tweet = '<blockquote class="twitter-tweet" lang="it"><p lang="en" dir="ltr">' .
+ 'Midnight project. I ain't got no oven. So I improvise making this milo crunchy kek batik. hahahaha ' .
+ '<a href="https://twitter.com/hashtag/itssomething?src=hash">#itssomething</a> ' .
+ '<a href="https://t.co/Nvn4Q1v2ae">pic.twitter.com/Nvn4Q1v2ae</a></p>— Zi (@RamzyStinson) ' .
+ '<a href="https://twitter.com/RamzyStinson/status/670650348319576064">' .
+ '28 Novembre 2015</a></blockquote><script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>';
+
+ $edit = [
+ 'name[0][value]' => 'Title',
+ 'field_media_twitter[0][value]' => $tweet_url,
+ 'field_embed_code[0][value]' => $tweet,
+ ];
+ $this->drupalPostForm(NULL, $edit, t('Save'));
+
+ // Assert that the media has been successfully saved.
+ $this->assertText('Title');
+
+ // Assert that the link url formatter exists on this page.
+ $this->assertText('Tweet Url');
+ $this->assertRaw('<a href="https://twitter.com/RamzyStinson/statuses/670650348319576064">', 'Link in embedded Tweet found.');
+
+ // Assert that the string_long code formatter exists on this page.
+ $this->assertText('Embed code');
+ $this->assertRaw('<blockquote class="twitter-tweet', 'Embedded Tweet found.');
+ }
+
+}
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\KernelTests\KernelTestBase;
-use Drupal\media_entity\Entity\Media;
-use Drupal\media_entity\Entity\MediaBundle;
-use Drupal\media_entity\MediaInterface;
-use Drupal\media_entity_twitter\Plugin\MediaEntity\Type\Twitter;
+use Drupal\media\Entity\Media;
+use Drupal\media\Entity\MediaType;
+use Drupal\media_entity_twitter\Plugin\media\Source\Twitter;
use Drupal\media_entity_twitter\TweetFetcherInterface;
/**
/**
* The mocked tweet fetcher.
*
- * @var TweetFetcherInterface
+ * @var \Drupal\media_entity_twitter\TweetFetcherInterface
*/
protected $tweetFetcher;
/**
* The plugin under test.
*
- * @var Twitter
+ * @var \Drupal\media_entity_twitter\Plugin\media\Source\Twitter
*/
protected $plugin;
/**
* A tweet media entity.
*
- * @var MediaInterface
+ * @var \Drupal\media\MediaInterface
*/
protected $entity;
'field',
'file',
'image',
- 'media_entity',
+ 'media',
'media_entity_twitter',
'system',
'text',
$this->tweetFetcher = $this->getMock(TweetFetcherInterface::class);
$this->container->set('media_entity_twitter.tweet_fetcher', $this->tweetFetcher);
- MediaBundle::create([
+ MediaType::create([
'id' => 'tweet',
- 'type' => 'twitter',
- 'type_configuration' => [
+ 'source' => 'twitter',
+ 'source_configuration' => [
'source_field' => 'tweet',
'use_twitter_api' => TRUE,
'consumer_key' => $this->randomString(),
$this->plugin = Twitter::create(
$this->container,
- MediaBundle::load('tweet')->getTypeConfiguration(),
+ MediaType::load('tweet')->get('source_configuration'),
'twitter',
- []
+ MediaType::load('tweet')->getSource()->getPluginDefinition()
);
$dir = $this->container
$uri = 'public://twitter-thumbnails/12345.ico';
touch($uri);
- $this->assertEquals($uri, $this->plugin->thumbnail($this->entity));
+ $this->assertEquals($uri, $this->plugin->getMetadata($this->entity, 'thumbnail_uri'));
}
/**
],
]);
- $this->plugin->thumbnail($this->entity);
+ $this->plugin->getMetadata($this->entity, 'thumbnail_uri');
$this->assertFileExists('public://twitter-thumbnails/12345.ico');
}
*/
public function testNoLocalImage() {
$this->assertEquals(
- $this->plugin->getDefaultThumbnail(),
- $this->plugin->thumbnail($this->entity)
+ '/twitter.png',
+ $this->plugin->getMetadata($this->entity, 'thumbnail_uri')
);
}
$configuration['generate_thumbnails'] = TRUE;
$this->plugin->setConfiguration($configuration);
- $uri = $this->plugin->thumbnail($this->entity);
+ $uri = $this->plugin->getMetadata($this->entity, 'thumbnail_uri');
$this->assertFileExists($uri);
}
module:
- slick_media
module:
- - media_entity
+ - media
id: media.slick
label: 'Slick carousel'
targetEntityType: media
package: Slick
dependencies:
- slick:slick
- - media_entity_image:media_entity_image
+ - drupal:media (>= 8.4)
- video_embed_field:video_embed_media
-# Information added by Drupal.org packaging script on 2017-05-25
-version: '8.x-1.0'
+# Information added by Drupal.org packaging script on 2018-01-03
+version: '8.x-2.0-alpha1'
core: '8.x'
project: 'slick_media'
-datestamp: 1495747986
+datestamp: 1514970793