Commit 451a7ba8 authored by catch's avatar catch

Issue #2701829 by alexpott, andypost, Soul88, Graber, EduardoMadrid, dawehner,...

Issue #2701829 by alexpott, andypost, Soul88, Graber, EduardoMadrid, dawehner, Berdir, jibran, pingwin4eg, httang12: Extension objects should not implement \Serializable
parent f864e1b6
......@@ -4,8 +4,13 @@
/**
* Defines an extension (file) object.
*
* This class does not implement the Serializable interface since problems
* occurred when using the serialize method.
*
* @see https://bugs.php.net/bug.php?id=66052
*/
class Extension implements \Serializable {
class Extension {
/**
* The type of the extension (e.g., 'module').
......@@ -156,47 +161,27 @@ public function __call($method, array $args) {
}
/**
* Implements Serializable::serialize().
* Magic method implementation to serialize the extension object.
*
* Serializes the Extension object in the most optimized way.
* @return array
* The names of all variables that should be serialized.
*/
public function serialize() {
// Don't serialize the app root, since this could change if the install is
// moved.
$data = [
'type' => $this->type,
'pathname' => $this->pathname,
'filename' => $this->filename,
];
public function __sleep() {
// @todo \Drupal\Core\Extension\ThemeExtensionList is adding custom
// properties to the Extension object.
$info = new \ReflectionObject($this);
foreach ($info->getProperties(\ReflectionProperty::IS_PUBLIC) as $property) {
$data[$property->getName()] = $property->getValue($this);
}
return serialize($data);
$properties = get_object_vars($this);
// Don't serialize the app root, since this could change if the install is
// moved. Don't serialize splFileInfo because it can not be.
unset($properties['splFileInfo'], $properties['root']);
return array_keys($properties);
}
/**
* {@inheritdoc}
* Magic method implementation to unserialize the extension object.
*/
public function unserialize($data) {
$data = unserialize($data);
public function __wakeup() {
// Get the app root from the container.
$this->root = \Drupal::hasService('app.root') ? \Drupal::root() : DRUPAL_ROOT;
$this->type = $data['type'];
$this->pathname = $data['pathname'];
$this->filename = $data['filename'];
// @todo ThemeHandler::listInfo(), ThemeHandler::rebuildThemeData(), and
// system_list() are adding custom properties to the Extension object.
foreach ($data as $property => $value) {
if (!isset($this->$property)) {
$this->$property = $value;
}
}
}
}
name: 'Theme test subseven'
type: theme
description: 'Test theme which uses seven as the base theme.'
version: VERSION
core: 8.x
base theme: seven
langcode: en
status: true
dependencies:
module:
- user
id: user_batch_action_test_action
label: 'Process user in batch'
type: user
plugin: user_batch_action_test_action
configuration: { }
action.configuration.user_batch_action_test_action:
type: action_configuration_default
label: 'Process user in batch'
<?php
namespace Drupal\user_batch_action_test\Plugin\Action;
use Drupal\Core\Action\ActionBase;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Session\AccountInterface;
/**
* Provides action that sets batch precessing.
*
* @Action(
* id = "user_batch_action_test_action",
* label = @Translation("Process user in batch"),
* type = "user",
* )
*/
class BatchUserAction extends ActionBase {
/**
* {@inheritdoc}
*/
public function executeMultiple(array $entities) {
$operations = [];
foreach ($entities as $entity) {
$operations[] = [
[get_class($this), 'processBatch'],
[
[
'entity_type' => $entity->getEntityTypeId(),
'entity_id' => $entity->id(),
],
],
];
}
if ($operations) {
$batch = [
'operations' => $operations,
'finished' => [get_class($this), 'finishBatch'],
];
batch_set($batch);
}
}
/**
* {@inheritdoc}
*/
public function execute(ContentEntityInterface $entity = NULL) {
$this->executeMultiple([$entity]);
}
/**
* {@inheritdoc}
*/
public function access($object, AccountInterface $account = NULL, $return_as_object = FALSE) {
return TRUE;
}
/**
* Processes the batch item.
*
* @param array $data
* Keyed array of data to process.
* @param array $context
* The batch context.
*/
public static function processBatch($data, &$context) {
if (!isset($context['results']['processed'])) {
$context['results']['processed'] = 0;
$context['results']['theme'] = \Drupal::service('theme.manager')->getActiveTheme(\Drupal::routeMatch())->getName();
}
$context['results']['processed']++;
}
/**
* Finish batch.
*
* @param bool $success
* Indicates whether the batch process was successful.
* @param array $results
* Results information passed from the processing callback.
*/
public static function finishBatch($success, $results) {
\Drupal::messenger()->addMessage(
\Drupal::translation()->formatPlural($results['processed'], 'One item has been processed.', '@count items have been processed.')
);
\Drupal::messenger()->addMessage($results['theme'] . ' theme used');
}
}
name: 'User batch action test'
type: module
description: 'Support module for user batch action testing.'
package: Testing
version: VERSION
core: 8.x
dependencies:
- views
- user
<?php
namespace Drupal\Tests\views\Functional;
use Drupal\Tests\BrowserTestBase;
/**
* Tests the views bulk form with batch action.
*
* @group action
* @see \Drupal\action\Plugin\views\field\BulkForm
*/
class UserBatchActionTest extends BrowserTestBase {
/**
* Modules to install.
*
* @var array
*/
public static $modules = ['user', 'user_batch_action_test', 'views'];
/**
* Tests user admin batch.
*/
public function testUserAction() {
$themes = ['classy', 'seven', 'bartik', 'test_subseven'];
$this->container->get('theme_installer')->install($themes);
$this->drupalLogin($this->rootUser);
foreach ($themes as $theme) {
$this->config('system.theme')->set('default', $theme)->save();
$this->drupalGet('admin/people');
$edit = [
'user_bulk_form[0]' => TRUE,
'action' => 'user_batch_action_test_action',
];
$this->drupalPostForm(NULL, $edit, t('Apply'));
$this->assertSession()->pageTextContains('One item has been processed.');
$this->assertSession()->pageTextContains($theme . ' theme used');
}
}
}
......@@ -7,12 +7,12 @@
use Drupal\Core\DependencyInjection\ContainerBuilder;
/**
* Tests preferred use of service application root over DRUPAL_ROOT.
* Tests Extension serialization.
*
* @coversDefaultClass \Drupal\Core\Extension\Extension
* @group Extension
*/
class ExtensionUnserializedServiceAppRootUsageTest extends UnitTestCase {
class ExtensionSerializationTest extends UnitTestCase {
/**
* Tests that the Extension class unserialize method uses the preferred root.
......@@ -22,7 +22,8 @@ class ExtensionUnserializedServiceAppRootUsageTest extends UnitTestCase {
* container's app.root and not the DRUPAL_ROOT constant if the service
* container app.root is available.
*
* @covers ::unserialize
* @covers ::__sleep
* @covers ::__wakeup
*/
public function testServiceAppRouteUsage() {
// The assumption of our test is that DRUPAL_ROOT is not defined.
......@@ -33,9 +34,26 @@ public function testServiceAppRouteUsage() {
\Drupal::setContainer($container);
// Instantiate an Extension object for testing unserialization.
$extension = new Extension($container->get('app.root'), 'module', 'core/modules/system/system.info.yml', 'system.module');
$data = $extension->serialize();
$extension->unserialize($data);
$extension = unserialize(serialize($extension));
$this->assertEquals('/dummy/app/root', $this->readAttribute($extension, 'root'));
}
/**
* Tests dynamically assigned public properties kept when serialized.
*
* @covers ::__sleep
* @covers ::__wakeup
*/
public function testPublicProperties() {
$container = new ContainerBuilder();
// Set a dummy container app.root to test against.
$container->set('app.root', '/dummy/app/root');
\Drupal::setContainer($container);
$extension = new Extension($container->get('app.root'), 'module', 'core/modules/system/system.info.yml', 'system.module');
// Assign a public property dynamically.
$extension->test = 'foo';
$extension = unserialize(serialize($extension));
$this->assertSame('foo', $extension->test);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment