diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..5ec2adb
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,32 @@
+name: ci
+on: [push, pull_request]
+jobs:
+ tests:
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ php_version: ["7.4", "8.0", "8.1"]
+ drupal_version: ["9", "10"]
+ exclude:
+ - php_version: "7.4"
+ drupal_version: "10"
+ - php_version: "8.0"
+ drupal_version: "10"
+ env:
+ PHP_VERSION: ${{ matrix.php_version }}
+ DRUPAL_VERSION: ${{ matrix.drupal_version }}
+ DOCKER_USER_ID: "1001"
+ steps:
+ - name: clone
+ uses: actions/checkout@v3
+ - name: docker-compose up -d
+ run: docker-compose up -d
+ - name: composer self-update
+ run: docker-compose exec -T php composer self-update
+ - name: composer require
+ run: docker-compose exec -u ${DOCKER_USER_ID} -T php composer require --no-interaction --dev --no-update drupal/core:^${DRUPAL_VERSION}
+ - name: composer install
+ run: docker-compose exec -T php composer install
+ - name: composer test
+ run: docker-compose exec -T php composer test
diff --git a/.gitignore b/.gitignore
index 50dd546..102fcde 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,5 +5,8 @@ composer.lock
reports
vendor
drush
+/drupal
.phpunit.result.cache
+/.editorconfig
+/.gitattributes
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 69e2c7c..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,12 +0,0 @@
-language: php
-
-php:
- - 7.4
- - 8.0
- - 8.1
-
-install:
- - composer install
-
-script:
- - composer test
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 52956b6..1e57de1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
## [Unreleased]
+## [2.2.1]
+ * [#250](https://github.com/jhedstrom/DrupalDriver/pull/250) Drupal 10 compatibility.
## [2.2.0]
### Fixed
* [#232](https://github.com/jhedstrom/DrupalDriver/pull/232) Fixes typo in ImageHandler.
diff --git a/composer.json b/composer.json
index 6c7af2a..8bfda1a 100644
--- a/composer.json
+++ b/composer.json
@@ -15,16 +15,26 @@
"php": ">=7.4",
"symfony/process": "~2.5|~3.0|~4.4|^6",
"symfony/dependency-injection": "~2.6|~3.0|~4.4|^6",
- "drupal/core-utility": "^8.4 || ^9 || ^10.0.0-alpha1"
+ "drupal/core-utility": "^8.4 || ^9 || ^10@beta"
},
"require-dev": {
+ "composer/installers": "^2.1",
"drupal/coder": "~8.3.0",
"phpspec/phpspec": "~2.0 || ~4.0 || ~6.1 || dev-main",
"phpunit/phpunit": "~6.0 || ~7.0 || ^9",
- "mockery/mockery": "^0.9.4",
+ "mockery/mockery": "^1.5",
+ "drupal/core-composer-scaffold": "^8.4 || ^9 || ^10@beta",
+ "drupal/core-recommended": "^8.4 || ^9 || ^10@beta",
+ "drupal/mailsystem": "^4.4",
"drush-ops/behat-drush-endpoint": "*",
"php-parallel-lint/php-parallel-lint": "^1.0",
- "dms/phpunit-arraysubset-asserts": "^0.4.0"
+ "dms/phpunit-arraysubset-asserts": "^0.4.0",
+ "mglaman/drupal-check": "^1",
+ "palantirnet/drupal-rector": "^0.13",
+ "symfony/phpunit-bridge": "^6.1"
+ },
+ "conflict": {
+ "drupal/core": ">=8.0 <9.3"
},
"scripts": {
"test": [
@@ -32,8 +42,11 @@
"parallel-lint src spec tests",
"phpunit",
"phpspec run -f pretty --no-interaction",
- "phpcs --standard=./phpcs-ruleset.xml ."
-
+ "phpcs --standard=./phpcs-ruleset.xml .",
+ "./vendor/bin/drupal-check --drupal-root=drupal ./src/Drupal/Driver/Cores/Drupal8.php ./src/Drupal/Driver/Fields/Drupal8",
+ "cp ./vendor/palantirnet/drupal-rector/rector.php drupal/.",
+ "cd drupal && ../vendor/bin/rector process ../src/Drupal/Driver/Cores/Drupal8.php --dry-run",
+ "cd drupal && ../vendor/bin/rector process ../src/Drupal/Driver/Fields/Drupal8 --dry-run"
]
},
"autoload": {
@@ -42,9 +55,34 @@
"Drupal\\Tests\\Driver" : "tests/"
}
},
+ "repositories": {
+ "drupal": {
+ "type": "composer",
+ "url": "https://packages.drupal.org/8"
+ }
+ },
+ "prefer-stable": true,
+ "minimum-stability": "beta",
+ "extra": {
+ "installer-paths": {
+ "drupal/core": [
+ "type:drupal-core"
+ ],
+ "drupal/modules/{$name}": [
+ "type:drupal-module"
+ ]
+ },
+ "drupal-scaffold": {
+ "locations": {
+ "web-root": "drupal/"
+ }
+ }
+ },
"config": {
"allow-plugins": {
- "dealerdirect/phpcodesniffer-composer-installer": true
+ "dealerdirect/phpcodesniffer-composer-installer": true,
+ "drupal/core-composer-scaffold": true,
+ "composer/installers": true
}
}
}
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..38dd332
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,17 @@
+version: "2"
+services:
+
+ php:
+ image: wodby/drupal-php:${PHP_VERSION}
+ environment:
+ PHP_FPM_USER: wodby
+ PHP_FPM_GROUP: wodby
+ PHP_FPM_CLEAR_ENV: "yes"
+ PHP_OPCACHE_PRELOAD_USER: wodby
+ PHP_XDEBUG_MODE: "off"
+ PHP_XDEBUG_REMOTE_CONNECT_BACK: 1
+ PHP_XDEBUG_REMOTE_HOST: "10.254.254.254"
+ PHP_XDEBUG_IDEKEY: "PHPSTORM"
+ PHP_IDE_CONFIG: "serverName=drupaldriver"
+ volumes:
+ - ./:/var/www/html
diff --git a/phpcs-ruleset.xml b/phpcs-ruleset.xml
index 97abe68..f87e72f 100644
--- a/phpcs-ruleset.xml
+++ b/phpcs-ruleset.xml
@@ -24,5 +24,6 @@
*/vendor/*
*/CHANGELOG.md
*/README.md
+ ./drupal/*
diff --git a/src/Drupal/Driver/Cores/Drupal7.php b/src/Drupal/Driver/Cores/Drupal7.php
index 7c8d133..4736104 100644
--- a/src/Drupal/Driver/Cores/Drupal7.php
+++ b/src/Drupal/Driver/Cores/Drupal7.php
@@ -346,7 +346,7 @@ public function languageCreate(\stdClass $language) {
// If the language code is not valid then throw an InvalidArgumentException.
if (!isset($predefined_languages[$language->langcode])) {
- throw new InvalidArgumentException("There is no predefined language with langcode '{$language->langcode}'.");
+ throw new \InvalidArgumentException("There is no predefined language with langcode '{$language->langcode}'.");
}
// Enable a language only if it has not been enabled already.
diff --git a/src/Drupal/Driver/Cores/Drupal8.php b/src/Drupal/Driver/Cores/Drupal8.php
index 4379c16..a681767 100644
--- a/src/Drupal/Driver/Cores/Drupal8.php
+++ b/src/Drupal/Driver/Cores/Drupal8.php
@@ -4,6 +4,7 @@
use Drupal\Core\DrupalKernel;
use Drupal\Core\Field\BaseFieldDefinition;
+use Drupal\Core\Routing\RouteObjectInterface;
use Drupal\Driver\Exception\BootstrapException;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\language\Entity\ConfigurableLanguage;
@@ -15,7 +16,6 @@
use Drupal\taxonomy\TermInterface;
use Drupal\user\Entity\Role;
use Drupal\user\Entity\User;
-use Symfony\Cmf\Component\Routing\RouteObjectInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Route;
@@ -53,9 +53,12 @@ public function bootstrap() {
$request = Request::createFromGlobals();
$kernel = DrupalKernel::createFromRequest($request, $autoloader, 'prod');
$kernel->boot();
- // A route is required for route matching.
- $request->attributes->set(RouteObjectInterface::ROUTE_OBJECT, new Route(''));
- $request->attributes->set(RouteObjectInterface::ROUTE_NAME, '');
+ // A route is required for route matching. In order to support Drupal 10
+ // along with 8/9, we use the hardcoded values of RouteObjectInterface
+ // constants ROUTE_NAME and ROUTE_OBJECT.
+ // @see https://www.drupal.org/node/3151009
+ $request->attributes->set('_route_object', new Route(''));
+ $request->attributes->set('_route', '');
$kernel->preHandle($request);
// Initialise an anonymous session. required for the bootstrap.
@@ -75,6 +78,7 @@ public function clearCache() {
*/
public function nodeCreate($node) {
// Throw an exception if the node type is missing or does not exist.
+ /** @var \Drupal\node\Entity\Node $node */
if (!isset($node->type) || !$node->type) {
throw new \Exception("Cannot create content because it is missing the required property 'type'.");
}
@@ -83,11 +87,12 @@ public function nodeCreate($node) {
$bundle_info = \Drupal::service('entity_type.bundle.info');
$bundles = $bundle_info->getBundleInfo('node');
if (!in_array($node->type, array_keys($bundles))) {
- throw new \Exception("Cannot create content because provided content type '$node->type' does not exist.");
+ throw new \Exception(sprintf('Cannot create content because provided content type %s does not exist.', $node->type));
}
// If 'author' is set, remap it to 'uid'.
if (isset($node->author)) {
$user = user_load_by_name($node->author);
+ /** @var \Drupal\user\Entity\User $user */
if ($user) {
$node->uid = $user->id();
}
@@ -329,8 +334,13 @@ public function termCreate(\stdClass $term) {
$term->vid = $term->vocabulary_machine_name;
if (isset($term->parent)) {
- $parent = \taxonomy_term_load_multiple_by_name($term->parent, $term->vocabulary_machine_name);
+ $query = \Drupal::entityQuery('taxonomy_term')
+ ->accessCheck(FALSE)
+ ->condition('id', $term->parent)
+ ->condition('vid', $term->vocabulary_machine_name);
+ $parent = $query->execute();
if (!empty($parent)) {
+ /** @var \Drupal\taxonomy\Entity\Term $parent */
$parent = reset($parent);
$term->parent = $parent->id();
}
@@ -380,12 +390,12 @@ public function getExtensionPathList() {
*
* @param string $entity_type
* The entity type for which to return the field types.
- * @param object $entity
+ * @param \StdClass $entity
* Entity object.
* @param array $base_fields
* Base fields to be expanded in addition to user defined fields.
*/
- public function expandEntityBaseFields($entity_type, \stdClass $entity, array $base_fields) {
+ public function expandEntityBaseFields($entity_type, \StdClass $entity, array $base_fields) {
$this->expandEntityFields($entity_type, $entity, $base_fields);
}
@@ -436,7 +446,7 @@ public function languageCreate(\stdClass $language) {
if (!ConfigurableLanguage::load($langcode)) {
$created_language = ConfigurableLanguage::createFromLangcode($language->langcode);
if (!$created_language) {
- throw new InvalidArgumentException("There is no predefined language with langcode '{$langcode}'.");
+ throw new \InvalidArgumentException("There is no predefined language with langcode '{$langcode}'.");
}
$created_language->save();
return $language;
diff --git a/src/Drupal/Driver/DrushDriver.php b/src/Drupal/Driver/DrushDriver.php
index 2086e8a..bc50179 100644
--- a/src/Drupal/Driver/DrushDriver.php
+++ b/src/Drupal/Driver/DrushDriver.php
@@ -414,7 +414,7 @@ public function drush($command, array $arguments = [], array $options = []) {
// Add any global arguments.
$global = $this->getArguments();
- $process = new Process("{$this->binary} {$alias} {$string_options} {$global} {$command} {$arguments}");
+ $process = Process::fromShellCommandline("{$this->binary} {$alias} {$string_options} {$global} {$command} {$arguments}");
$process->setTimeout(3600);
$process->run();
diff --git a/src/Drupal/Driver/Fields/Drupal8/AbstractHandler.php b/src/Drupal/Driver/Fields/Drupal8/AbstractHandler.php
index cda97d5..62bb0f3 100644
--- a/src/Drupal/Driver/Fields/Drupal8/AbstractHandler.php
+++ b/src/Drupal/Driver/Fields/Drupal8/AbstractHandler.php
@@ -25,7 +25,7 @@ abstract class AbstractHandler implements FieldHandlerInterface {
/**
* Constructs an AbstractHandler object.
*
- * @param object $entity
+ * @param \StdClass $entity
* The simulated entity object containing field information.
* @param string $entity_type
* The entity type.
@@ -35,7 +35,7 @@ abstract class AbstractHandler implements FieldHandlerInterface {
* @throws \Exception
* Thrown when the given field name does not exist on the entity.
*/
- public function __construct(\stdClass $entity, $entity_type, $field_name) {
+ public function __construct(\StdClass $entity, $entity_type, $field_name) {
if (empty($entity_type)) {
throw new \Exception("You must specify an entity type in order to parse entity fields.");
}
diff --git a/src/Drupal/Driver/Fields/Drupal8/ImageHandler.php b/src/Drupal/Driver/Fields/Drupal8/ImageHandler.php
index d042bfb..b314fcc 100644
--- a/src/Drupal/Driver/Fields/Drupal8/ImageHandler.php
+++ b/src/Drupal/Driver/Fields/Drupal8/ImageHandler.php
@@ -17,9 +17,7 @@ public function expand($values) {
}
/** @var \Drupal\file\FileInterface $file */
- $file = file_save_data(
- $data,
- 'public://' . uniqid() . '.jpg');
+ $file = \Drupal::service('file.repository')->writeData($data, 'public://' . uniqid() . '.jpg');
if (FALSE === $file) {
throw new \Exception("Error saving file");