Update to Drupal 8.0.0 beta 14. For more information, see https://drupal.org/node/2544542

This commit is contained in:
Pantheon Automation 2015-08-27 12:03:05 -07:00 committed by Greg Anderson
parent 3b2511d96d
commit 81ccda77eb
2155 changed files with 54307 additions and 46870 deletions

View file

@ -7,7 +7,7 @@
namespace Drupal\aggregator\Controller;
use Drupal\Component\Utility\Xss;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Datetime\DateFormatter;
use Drupal\aggregator\FeedInterface;
@ -187,7 +187,7 @@ class AggregatorController extends ControllerBase {
* The feed label.
*/
public function feedTitle(FeedInterface $aggregator_feed) {
return Xss::filter($aggregator_feed->label());
return SafeMarkup::xssFilter($aggregator_feed->label());
}
}

View file

@ -225,13 +225,15 @@ class Item extends ContentEntityBase implements ItemInterface {
// handles the regular cases. The Item entity has one special case: a newly
// created Item is *also* associated with a Feed, so we must invalidate the
// associated Feed's cache tag.
Cache::invalidateTags($this->getCacheTags());
if (!$update) {
Cache::invalidateTags($this->getCacheTagsToInvalidate());
}
}
/**
* {@inheritdoc}
*/
public function getCacheTags() {
public function getCacheTagsToInvalidate() {
return Feed::load($this->getFeedId())->getCacheTags();
}

View file

@ -122,7 +122,7 @@ class OpmlFeedAdd extends FormBase {
// @todo Move this to a fetcher implementation.
try {
$response = $this->httpClient->get($form_state->getValue('remote'));
$data = $response->getBody(TRUE);
$data = (string) $response->getBody();
}
catch (RequestException $e) {
$this->logger('aggregator')->warning('Failed to download OPML file due to "%error".', array('%error' => $e->getMessage()));

View file

@ -154,32 +154,27 @@ class AggregatorFeedBlock extends BlockBase implements ContainerFactoryPluginInt
->sort('iid', 'DESC')
->execute();
$items = $this->itemStorage->loadMultiple($result);
if ($result) {
// Only display the block if there are items to show.
$items = $this->itemStorage->loadMultiple($result);
$more_link = array(
'#type' => 'more_link',
'#url' => $feed->urlInfo(),
'#attributes' => array('title' => $this->t("View this feed's recent news.")),
);
$read_more = drupal_render($more_link);
$rendered_items = array();
foreach ($items as $item) {
$aggregator_block_item = array(
'#type' => 'link',
'#url' => $item->urlInfo(),
'#title' => $item->label(),
);
$rendered_items[] = drupal_render($aggregator_block_item);
}
// Only display the block if there are items to show.
if (count($rendered_items) > 0) {
$item_list = array(
$build['list'] = [
'#theme' => 'item_list',
'#items' => $rendered_items,
);
return array(
'#children' => drupal_render($item_list) . $read_more,
);
'#items' => [],
];
foreach ($items as $item) {
$build['list']['#items'][$item->id()] = [
'#type' => 'link',
'#url' => $item->urlInfo(),
'#title' => $item->label(),
];
}
$build['more_link'] = [
'#type' => 'more_link',
'#url' => $feed->urlInfo(),
'#attributes' => ['title' => $this->t("View this feed's recent news.")],
];
return $build;
}
}
}

View file

@ -10,9 +10,13 @@ namespace Drupal\aggregator\Plugin\aggregator\fetcher;
use Drupal\aggregator\Plugin\FetcherInterface;
use Drupal\aggregator\FeedInterface;
use Drupal\Component\Datetime\DateTimePlus;
use Drupal\Core\Http\ClientFactory;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use GuzzleHttp\ClientInterface;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Psr7\Request;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\UriInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
@ -32,9 +36,9 @@ class DefaultFetcher implements FetcherInterface, ContainerFactoryPluginInterfac
/**
* The HTTP client to fetch the feed data with.
*
* @var \GuzzleHttp\ClientInterface
* @var \Drupal\Core\Http\ClientFactory
*/
protected $httpClient;
protected $httpClientFactory;
/**
* A logger instance.
@ -46,13 +50,13 @@ class DefaultFetcher implements FetcherInterface, ContainerFactoryPluginInterfac
/**
* Constructs a DefaultFetcher object.
*
* @param \GuzzleHttp\ClientInterface $http_client
* @param \Drupal\Core\Http\ClientFactory $http_client_factory
* A Guzzle client object.
* @param \Psr\Log\LoggerInterface $logger
* A logger instance.
*/
public function __construct(ClientInterface $http_client, LoggerInterface $logger) {
$this->httpClient = $http_client;
public function __construct(ClientFactory $http_client_factory, LoggerInterface $logger) {
$this->httpClientFactory = $http_client_factory;
$this->logger = $logger;
}
@ -61,7 +65,7 @@ class DefaultFetcher implements FetcherInterface, ContainerFactoryPluginInterfac
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$container->get('http_client'),
$container->get('http_client_factory'),
$container->get('logger.factory')->get('aggregator')
);
}
@ -70,19 +74,26 @@ class DefaultFetcher implements FetcherInterface, ContainerFactoryPluginInterfac
* {@inheritdoc}
*/
public function fetch(FeedInterface $feed) {
$request = $this->httpClient->createRequest('GET', $feed->getUrl());
$request = new Request('GET', $feed->getUrl());
$feed->source_string = FALSE;
// Generate conditional GET headers.
if ($feed->getEtag()) {
$request->addHeader('If-None-Match', $feed->getEtag());
$request = $request->withAddedHeader('If-None-Match', $feed->getEtag());
}
if ($feed->getLastModified()) {
$request->addHeader('If-Modified-Since', gmdate(DateTimePlus::RFC7231, $feed->getLastModified()));
$request = $request->withAddedHeader('If-Modified-Since', gmdate(DateTimePlus::RFC7231, $feed->getLastModified()));
}
try {
$response = $this->httpClient->send($request);
/** @var \Psr\Http\Message\UriInterface $actual_uri */
$actual_uri = NULL;
$response = $this->httpClientFactory->fromOptions(['allow_redirects' => [
'on_redirect' => function(RequestInterface $request, ResponseInterface $response, UriInterface $uri) use (&$actual_uri) {
$actual_uri = (string) $uri;
}
]])->send($request);
// In case of a 304 Not Modified, there is no new content, so return
// FALSE.
@ -91,13 +102,17 @@ class DefaultFetcher implements FetcherInterface, ContainerFactoryPluginInterfac
}
$feed->source_string = (string) $response->getBody();
$feed->setEtag($response->getHeader('ETag'));
$feed->setLastModified(strtotime($response->getHeader('Last-Modified')));
if ($response->hasHeader('ETag')) {
$feed->setEtag($response->getHeaderLine('ETag'));
}
if ($response->hasHeader('Last-Modified')) {
$feed->setLastModified(strtotime($response->getHeaderLine('Last-Modified')));
}
$feed->http_headers = $response->getHeaders();
// Update the feed URL in case of a 301 redirect.
if ($response->getEffectiveUrl() != $feed->getUrl()) {
$feed->setUrl($response->getEffectiveUrl());
if ($actual_uri && $actual_uri !== $feed->getUrl()) {
$feed->setUrl($actual_uri);
}
return TRUE;
}

View file

@ -0,0 +1,72 @@
<?php
/**
* @file
* Contains \Drupal\aggregator\Plugin\migrate\source\d6\AggregatorFeed.
*/
namespace Drupal\aggregator\Plugin\migrate\source\d6;
use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
/**
* Drupal 6 feed source from database.
*
* @MigrateSource(
* id = "d6_aggregator_feed",
* source_provider = "aggregator"
* )
*/
class AggregatorFeed extends DrupalSqlBase {
/**
* {@inheritdoc}
*/
public function query() {
$query = $this->select('aggregator_feed', 'af')
->fields('af', array(
'fid',
'title',
'url',
'refresh',
'checked',
'link',
'description',
'image',
'etag',
'modified',
'block',
));
$query->orderBy('fid');
return $query;
}
/**
* {@inheritdoc}
*/
public function fields() {
return array(
'fid' => $this->t('The feed ID.'),
'title' => $this->t('Title of the feed.'),
'url' => $this->t('URL to the feed.'),
'refresh' => $this->t('Refresh frequency in seconds.'),
'checked' => $this->t('Last-checked unix timestamp.'),
'link' => $this->t('Parent website of feed.'),
'description' => $this->t('Parent website\'s description fo the feed.'),
'image' => $this->t('An image representing the feed.'),
'etag' => $this->t('Entity tag HTTP response header.'),
'modified' => $this->t('When the feed was last modified.'),
'block' => $this->t("Number of items to display in the feed's block."),
);
}
/**
* {@inheritdoc}
*/
public function getIds() {
$ids['fid']['type'] = 'integer';
return $ids;
}
}

View file

@ -0,0 +1,57 @@
<?php
/**
* @file
* Contains \Drupal\aggregator\Plugin\migrate\source\d6\AggregatorItem.
*/
namespace Drupal\aggregator\Plugin\migrate\source\d6;
use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
/**
* Drupal 6 aggregator item source from database.
*
* @MigrateSource(
* id = "d6_aggregator_item",
* source_provider = "aggregator"
* )
*/
class AggregatorItem extends DrupalSqlBase {
/**
* {@inheritdoc}
*/
public function query() {
$query = $this->select('aggregator_item', 'ai')
->fields('ai', array('iid', 'fid', 'title', 'link', 'author',
'description', 'timestamp', 'guid'))
->orderBy('iid');
return $query;
}
/**
* {@inheritdoc}
*/
public function fields() {
return array(
'iid' => $this->t('Primary Key: Unique ID for feed item.'),
'fid' => $this->t('The {aggregator_feed}.fid to which this item belongs.'),
'title' => $this->t('Title of the feed item.'),
'link' => $this->t('Link to the feed item.'),
'author' => $this->t('Author of the feed item.'),
'description' => $this->t('Body of the feed item.'),
'timestamp' => $this->t('Post date of feed item, as a Unix timestamp.'),
'guid' => $this->t('Unique identifier for the feed item.'),
);
}
/**
* {@inheritdoc}
*/
public function getIds() {
$ids['iid']['type'] = 'integer';
return $ids;
}
}

View file

@ -26,11 +26,6 @@ class FeedParserTest extends AggregatorTestBase {
// feeds have hardcoded dates in them (which may be expired when this test
// is run).
$this->config('aggregator.settings')->set('items.expire', AGGREGATOR_CLEAR_NEVER)->save();
// Reset any reader cache between tests.
Reader::reset();
// Set our bridge extension manager to Zend Feed.
$bridge = $this->container->get('feed.bridge.reader');
Reader::setExtensionManager($bridge);
}
/**
@ -68,6 +63,15 @@ class FeedParserTest extends AggregatorTestBase {
$this->assertLinkByHref('http://example.org/2003/12/13/atom03');
$this->assertText('Some text.');
$this->assertEqual('urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a', db_query('SELECT guid FROM {aggregator_item} WHERE link = :link', array(':link' => 'http://example.org/2003/12/13/atom03'))->fetchField(), 'Atom entry id element is parsed correctly.');
// Check for second feed entry.
$this->assertText('We tried to stop them, but we failed.');
$this->assertLinkByHref('http://example.org/2003/12/14/atom03');
$this->assertText('Some other text.');
$db_guid = db_query('SELECT guid FROM {aggregator_item} WHERE link = :link', array(
':link' => 'http://example.org/2003/12/14/atom03',
))->fetchField();
$this->assertEqual('urn:uuid:1225c695-cfb8-4ebb-bbbb-80da344efa6a', $db_guid, 'Atom entry id element is parsed correctly.');
}
/**

View file

@ -0,0 +1,53 @@
<?php
/**
* @file
* Contains \Drupal\aggregator\Tests\Migrate\d6\MigrateAggregatorConfigsTest.
*/
namespace Drupal\aggregator\Tests\Migrate\d6;
use Drupal\config\Tests\SchemaCheckTestTrait;
use Drupal\migrate_drupal\Tests\d6\MigrateDrupal6TestBase;
/**
* Upgrade variables to aggregator.settings.yml.
*
* @group aggregator
*/
class MigrateAggregatorConfigsTest extends MigrateDrupal6TestBase {
use SchemaCheckTestTrait;
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('aggregator');
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->loadDumps(['Variable.php']);
$this->executeMigration('d6_aggregator_settings');
}
/**
* Tests migration of aggregator variables to aggregator.settings.yml.
*/
public function testAggregatorSettings() {
$config = $this->config('aggregator.settings');
$this->assertIdentical('aggregator', $config->get('fetcher'));
$this->assertIdentical('aggregator', $config->get('parser'));
$this->assertIdentical(array('aggregator'), $config->get('processors'));
$this->assertIdentical(600, $config->get('items.teaser_length'));
$this->assertIdentical('<a> <b> <br /> <dd> <dl> <dt> <em> <i> <li> <ol> <p> <strong> <u> <ul>', $config->get('items.allowed_html'));
$this->assertIdentical(9676800, $config->get('items.expire'));
$this->assertIdentical(3, $config->get('source.list_max'));
$this->assertConfigSchema(\Drupal::service('config.typed'), 'aggregator.settings', $config->get());
}
}

View file

@ -0,0 +1,51 @@
<?php
/**
* @file
* Contains \Drupal\aggregator\Tests\Migrate\d6\MigrateAggregatorFeedTest.
*/
namespace Drupal\aggregator\Tests\Migrate\d6;
use Drupal\aggregator\Entity\Feed;
use Drupal\migrate_drupal\Tests\d6\MigrateDrupal6TestBase;
/**
* Upgrade variables to aggregator_feed entities.
*
* @group aggregator
*/
class MigrateAggregatorFeedTest extends MigrateDrupal6TestBase {
static $modules = array('aggregator');
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installEntitySchema('aggregator_feed');
$this->loadDumps(['AggregatorFeed.php']);
$this->executeMigration('d6_aggregator_feed');
}
/**
* Tests migration of aggregator feeds.
*/
public function testAggregatorFeedImport() {
/** @var Feed $feed */
$feed = Feed::load(5);
$this->assertNotNull($feed->uuid());
$this->assertIdentical('Know Your Meme', $feed->title->value);
$this->assertIdentical('en', $feed->language()->getId());
$this->assertIdentical('http://knowyourmeme.com/newsfeed.rss', $feed->url->value);
$this->assertIdentical('900', $feed->refresh->value);
$this->assertIdentical('1387659487', $feed->checked->value);
$this->assertIdentical('0', $feed->queued->value);
$this->assertIdentical('http://knowyourmeme.com', $feed->link->value);
$this->assertIdentical('New items added to the News Feed', $feed->description->value);
$this->assertIdentical('http://b.thumbs.redditmedia.com/harEHsUUZVajabtC.png', $feed->image->value);
$this->assertIdentical('"213cc1365b96c310e92053c5551f0504"', $feed->etag->value);
$this->assertIdentical('0', $feed->modified->value);
}
}

View file

@ -0,0 +1,70 @@
<?php
/**
* @file
* Contains \Drupal\aggregator\Tests\Migrate\d6\MigrateAggregatorItemTest.
*/
namespace Drupal\aggregator\Tests\Migrate\d6;
use Drupal\aggregator\Entity\Item;
use Drupal\migrate_drupal\Tests\d6\MigrateDrupal6TestBase;
/**
* Upgrade aggregator items.
*
* @group aggregator
*/
class MigrateAggregatorItemTest extends MigrateDrupal6TestBase {
static $modules = array('aggregator');
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installEntitySchema('aggregator_feed');
$this->installEntitySchema('aggregator_item');
// Add some id mappings for the dependant migrations.
$id_mappings = array(
'd6_aggregator_feed' => array(
array(array(5), array(5)),
),
);
$this->prepareMigrations($id_mappings);
$entity = entity_create('aggregator_feed', array(
'fid' => 5,
'title' => 'Drupal Core',
'url' => 'https://groups.drupal.org/not_used/167169',
'refresh' => 900,
'checked' => 1389919932,
'description' => 'Drupal Core Group feed',
));
$entity->enforceIsNew();
$entity->save();
$this->loadDumps(['AggregatorItem.php']);
$this->executeMigration('d6_aggregator_item');
}
/**
* Test Drupal 6 aggregator item migration to Drupal 8.
*/
public function testAggregatorItem() {
/** @var Item $item */
$item = Item::load(1);
$this->assertIdentical('1', $item->id());
$this->assertIdentical('5', $item->getFeedId());
$this->assertIdentical('This (three) weeks in Drupal Core - January 10th 2014', $item->label());
$this->assertIdentical('larowlan', $item->getAuthor());
$this->assertIdentical("<h2 id='new'>What's new with Drupal 8?</h2>", $item->getDescription());
$this->assertIdentical('https://groups.drupal.org/node/395218', $item->getLink());
$this->assertIdentical('1389297196', $item->getPostedTime());
$this->assertIdentical('en', $item->language()->getId());
$this->assertIdentical('395218 at https://groups.drupal.org', $item->getGuid());
}
}

View file

@ -0,0 +1,45 @@
<?php
/**
* @file
* Contains \Drupal\aggregator\Tests\Migrate\d7\MigrateAggregatorSettingsTest.
*/
namespace Drupal\aggregator\Tests\Migrate\d7;
use Drupal\migrate_drupal\Tests\d7\MigrateDrupal7TestBase;
/**
* Tests migration of Aggregator's variables to configuration.
*
* @group aggregator
*/
class MigrateAggregatorSettingsTest extends MigrateDrupal7TestBase {
public static $modules = ['aggregator'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installConfig(static::$modules);
$this->loadDumps(['Variable.php']);
$this->executeMigration('d7_aggregator_settings');
}
/**
* Tests migration of Aggregator variables to configuration.
*/
public function testMigration() {
$config = \Drupal::config('aggregator.settings')->get();
$this->assertIdentical('aggregator', $config['fetcher']);
$this->assertIdentical('aggregator', $config['parser']);
$this->assertIdentical(['aggregator'], $config['processors']);
$this->assertIdentical('<p> <div> <a>', $config['items']['allowed_html']);
$this->assertIdentical(500, $config['items']['teaser_length']);
$this->assertIdentical(86400, $config['items']['expire']);
$this->assertIdentical(6, $config['source']['list_max']);
}
}

View file

@ -7,6 +7,7 @@
namespace Drupal\aggregator\Tests\Views;
use Drupal\Core\Render\RenderContext;
use Drupal\Core\Url;
use Drupal\views\Views;
use Drupal\views\Tests\ViewTestData;
@ -66,6 +67,9 @@ class IntegrationTest extends ViewUnitTestBase {
* Tests basic aggregator_item view.
*/
public function testAggregatorItemView() {
/** @var \Drupal\Core\Render\RendererInterface $renderer */
$renderer = \Drupal::service('renderer');
$feed = $this->feedStorage->create(array(
'title' => $this->randomMachineName(),
'url' => 'https://www.drupal.org/',
@ -112,13 +116,22 @@ class IntegrationTest extends ViewUnitTestBase {
foreach ($view->result as $row) {
$iid = $view->field['iid']->getValue($row);
$expected_link = \Drupal::l($items[$iid]->getTitle(), Url::fromUri($items[$iid]->getLink(), ['absolute' => TRUE]));
$this->assertEqual($view->field['title']->advancedRender($row), $expected_link, 'Ensure the right link is generated');
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($view, $row) {
return $view->field['title']->advancedRender($row);
});
$this->assertEqual($output, $expected_link, 'Ensure the right link is generated');
$expected_author = aggregator_filter_xss($items[$iid]->getAuthor());
$this->assertEqual($view->field['author']->advancedRender($row), $expected_author, 'Ensure the author got filtered');
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($view, $row) {
return $view->field['author']->advancedRender($row);
});
$this->assertEqual($output, $expected_author, 'Ensure the author got filtered');
$expected_description = aggregator_filter_xss($items[$iid]->getDescription());
$this->assertEqual($view->field['description']->advancedRender($row), $expected_description, 'Ensure the author got filtered');
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($view, $row) {
return $view->field['description']->advancedRender($row);
});
$this->assertEqual($output, $expected_description, 'Ensure the author got filtered');
}
}