/** * Creates four nodes and ensures that they are loaded correctly. */ function testNodeMultipleLoad() { $node1 = $this->drupalCreateNode(array('type' => 'article', 'promote' => 1)); $node2 = $this->drupalCreateNode(array('type' => 'article', 'promote' => 1)); $node3 = $this->drupalCreateNode(array('type' => 'article', 'promote' => 0)); $node4 = $this->drupalCreateNode(array('type' => 'page', 'promote' => 0)); // Confirm that promoted nodes appear in the default node listing. $this->drupalGet('node'); $this->assertText($node1->label(), 'Node title appears on the default listing.'); $this->assertText($node2->label(), 'Node title appears on the default listing.'); $this->assertNoText($node3->label(), 'Node title does not appear in the default listing.'); $this->assertNoText($node4->label(), 'Node title does not appear in the default listing.'); // Load nodes with only a condition. Nodes 3 and 4 will be loaded. $nodes = entity_load_multiple_by_properties('node', array('promote' => 0)); $this->assertEqual($node3->label(), $nodes[$node3->id()]->label(), 'Node was loaded.'); $this->assertEqual($node4->label(), $nodes[$node4->id()]->label(), 'Node was loaded.'); $count = count($nodes); $this->assertTrue($count == 2, format_string('@count nodes loaded.', array('@count' => $count))); // Load nodes by nid. Nodes 1, 2 and 4 will be loaded. $nodes = Node::loadMultiple(array(1, 2, 4)); $count = count($nodes); $this->assertTrue(count($nodes) == 3, format_string('@count nodes loaded', array('@count' => $count))); $this->assertTrue(isset($nodes[$node1->id()]), 'Node is correctly keyed in the array'); $this->assertTrue(isset($nodes[$node2->id()]), 'Node is correctly keyed in the array'); $this->assertTrue(isset($nodes[$node4->id()]), 'Node is correctly keyed in the array'); foreach ($nodes as $node) { $this->assertTrue(is_object($node), 'Node is an object'); } }
/** * Tests the Drupal 6 term-node association to Drupal 8 migration. */ public function testTermNode() { $this->container->get('entity.manager')->getStorage('node')->resetCache([1, 2]); $nodes = Node::loadMultiple([1, 2]); $node = $nodes[1]; $this->assertIdentical(1, count($node->vocabulary_1_i_0_)); $this->assertIdentical('1', $node->vocabulary_1_i_0_[0]->target_id); $node = $nodes[2]; $this->assertIdentical(2, count($node->vocabulary_2_i_1_)); $this->assertIdentical('2', $node->vocabulary_2_i_1_[0]->target_id); $this->assertIdentical('3', $node->vocabulary_2_i_1_[1]->target_id); }
/** * Tests the Drupal 6 term-node association to Drupal 8 migration. */ public function testTermNode() { // This is a base plugin id and we want to run all derivatives. $this->executeMigrations(['d6_term_node']); $this->container->get('entity.manager')->getStorage('node')->resetCache([1, 2]); $nodes = Node::loadMultiple([1, 2]); $node = $nodes[1]; $this->assertIdentical(1, count($node->vocabulary_1_i_0_)); $this->assertIdentical('1', $node->vocabulary_1_i_0_[0]->target_id); $node = $nodes[2]; $this->assertIdentical(2, count($node->vocabulary_2_i_1_)); $this->assertIdentical('2', $node->vocabulary_2_i_1_[0]->target_id); $this->assertIdentical('3', $node->vocabulary_2_i_1_[1]->target_id); }
/** * Test upload migration from Drupal 6 to Drupal 8. */ function testUpload() { $this->container->get('entity.manager')->getStorage('node')->resetCache([1, 2]); $nodes = Node::loadMultiple([1, 2]); $node = $nodes[1]; $this->assertIdentical(1, count($node->upload)); $this->assertIdentical('1', $node->upload[0]->target_id); $this->assertIdentical('file 1-1-1', $node->upload[0]->description); $this->assertIdentical(FALSE, $node->upload[0]->isDisplayed()); $node = $nodes[2]; $this->assertIdentical(2, count($node->upload)); $this->assertIdentical('3', $node->upload[0]->target_id); $this->assertIdentical('file 2-3-3', $node->upload[0]->description); $this->assertIdentical(FALSE, $node->upload[0]->isDisplayed()); $this->assertIdentical('2', $node->upload[1]->target_id); $this->assertIdentical(TRUE, $node->upload[1]->isDisplayed()); $this->assertIdentical('file 2-3-2', $node->upload[1]->description); }
/** * Tests generate commands */ public function testDevelGenerate() { // Creating users. $edit = array('num' => 4); $this->drupalPostForm('admin/config/development/generate/user', $edit, t('Generate')); $this->assertText(t('4 users created.')); $this->assertText(t('Generate process complete.')); // Creating content. // First we create a node in order to test the Delete content checkbox. $this->drupalCreateNode(array('type' => 'article')); $edit = array('num' => 4, 'kill' => TRUE, 'node_types[article]' => TRUE, 'time_range' => 604800, 'max_comments' => 3, 'title_length' => 4, 'add_alias' => 1); $this->drupalPostForm('admin/config/development/generate/content', $edit, t('Generate')); $this->assertText(t('Deleted 1 nodes.')); $this->assertText(t('Finished creating 4 nodes')); $this->assertText(t('Generate process complete.')); // Tests that nodes have been created in the generation process. $nodes = Node::loadMultiple(); $this->assert(count($nodes) == 4, 'Nodes generated successfully.'); // Tests url alias for the generated nodes. foreach ($nodes as $node) { $alias = 'node-' . $node->id() . '-' . $node->bundle(); $this->drupalGet($alias); $this->assertResponse('200'); $this->assertText($node->getTitle(), 'Generated url alias for the node works.'); } // Creating terms. $edit = array('vids[]' => $this->vocabulary->id(), 'num' => 5, 'title_length' => 12); $this->drupalPostForm('admin/config/development/generate/term', $edit, t('Generate')); $this->assertText(t('Created the following new terms: ')); $this->assertText(t('Generate process complete.')); // Creating vocabularies. $edit = array('num' => 5, 'title_length' => 12, 'kill' => TRUE); $this->drupalPostForm('admin/config/development/generate/vocabs', $edit, t('Generate')); $this->assertText(t('Created the following new vocabularies: ')); $this->assertText(t('Generate process complete.')); // Creating menus. $edit = array('num_menus' => 5, 'num_links' => 7, 'title_length' => 12, 'link_types[node]' => 1, 'link_types[front]' => 1, 'link_types[external]' => 1, 'max_depth' => 4, 'max_width' => 6, 'kill' => 1); $this->drupalPostForm('admin/config/development/generate/menu', $edit, t('Generate')); $this->assertText(t('Created the following new menus: ')); $this->assertText(t('Created 7 new menu links')); $this->assertText(t('Generate process complete.')); }
/** * Tests the Drupal 6 book structure to Drupal 8 migration. */ public function testBook() { $nodes = Node::loadMultiple(array(4, 5, 6, 7, 8)); $this->assertIdentical('4', $nodes[4]->book['bid']); $this->assertIdentical('0', $nodes[4]->book['pid']); $this->assertIdentical('4', $nodes[5]->book['bid']); $this->assertIdentical('4', $nodes[5]->book['pid']); $this->assertIdentical('4', $nodes[6]->book['bid']); $this->assertIdentical('5', $nodes[6]->book['pid']); $this->assertIdentical('4', $nodes[7]->book['bid']); $this->assertIdentical('5', $nodes[7]->book['pid']); $this->assertIdentical('8', $nodes[8]->book['bid']); $this->assertIdentical('0', $nodes[8]->book['pid']); $tree = \Drupal::service('book.manager')->bookTreeAllData(4); $this->assertIdentical('4', $tree['49990 Node 4 4']['link']['nid']); $this->assertIdentical('5', $tree['49990 Node 4 4']['below']['50000 Node 5 5']['link']['nid']); $this->assertIdentical('6', $tree['49990 Node 4 4']['below']['50000 Node 5 5']['below']['50000 Node 6 6']['link']['nid']); $this->assertIdentical('7', $tree['49990 Node 4 4']['below']['50000 Node 5 5']['below']['50000 Node 7 7']['link']['nid']); $this->assertIdentical(array(), $tree['49990 Node 4 4']['below']['50000 Node 5 5']['below']['50000 Node 6 6']['below']); $this->assertIdentical(array(), $tree['49990 Node 4 4']['below']['50000 Node 5 5']['below']['50000 Node 7 7']['below']); }
/** * Builds and returns the node information. * * @param bool $debug_mode * The level of detail to include. * * @return array */ public static function buildNodeInfo($debug_mode) { global $user; $visible_nodes = self::visibleNodes(); if (count($visible_nodes) == 0) { return array(); } else { $single_nid = reset($visible_nodes); } // Find out whether our DnaUser block is active or not. //dpm($blocks = \Drupal::entityTypeManager()->getStorage('block')->load()); $user_block_active = FALSE; //foreach ($blocks as $block) { // if ($block->get('plugin') == 'devel_dna_user_block') { // $user_block_active = TRUE; // } //} // Include rows where nid == 0. $nids = array_merge(array(0 => 0), $visible_nodes); $query = \Drupal::database()->select('node_access', 'na'); $query->fields('na')->condition('na.nid', $nids, 'IN'); $query->orderBy('na.nid')->orderBy('na.realm')->orderBy('na.gid'); $nodes = Node::loadMultiple($nids); if (!$debug_mode) { $headers = array('node', 'realm', 'gid', 'view', 'update', 'delete', 'explained'); $rows = array(); foreach ($query->execute() as $row) { $explained = \Drupal::moduleHandler()->invokeAll('node_access_explain', [$row]); $node_title = self::get_node_title($nodes[$row->nid]); $title_attribute = \Drupal::request()->getRequestUri(); if (Unicode::strlen($node_title) > 20) { $title_attribute = $title_attribute . ': ' . $node_title; $node_title = Unicode::substr($node_title, 0, 18) . '...'; } $rows[] = array(empty($row->nid) ? '0' : Link::fromTextAndUrl($node_title, Url::fromUri(\Drupal::request()->getUri(), ['fragment' => 'node-' . $row->nid, 'attributes' => ['title' => $title_attribute]])), $row->realm, $row->gid, $row->grant_view, $row->grant_update, $row->grant_delete, implode('<br />', $explained)); } $output[] = array('#theme' => 'table', '#header' => $headers, '#rows' => $rows, '#attributes' => array('style' => 'text-align: left')); } else { $tr = 't'; $variables = array('!na' => '{node_access}'); $states = array('default' => array(t('default'), 'ok', t('Default record supplied by core in the absence of any other non-empty records; in !na.', $variables)), 'ok' => array(t('ok'), 'ok', t('Highest priority record; in !na.', $variables)), 'removed' => array(t('removed'), '', t('Was removed in @func; not in !na.', $variables + array('@func' => 'hook_node_access_records_alter()'))), 'static' => array(t('static'), 'ok', t('Non-standard record in !na.', $variables)), 'unexpected' => array(t('unexpected'), 'warning', t('The 0/all/0/... record applies to all nodes and all users -- usually it should not be present in !na if any node access module is active!')), 'ignored' => array(t('ignored'), 'warning', t('Lower priority record; not in !na and thus ignored.', $variables)), 'empty' => array(t('empty'), 'warning', t('Does not grant any access, but could block lower priority records; not in !na.', $variables)), 'wrong' => array(t('wrong'), 'error', t('Is rightfully in !na but at least one access flag is wrong!', $variables)), 'missing' => array(t('missing'), 'error', t("Should be in !na but isn't!", $variables)), 'removed!' => array(t('removed!'), 'error', t('Was removed in @func; should NOT be in !na!', $variables + array('@func' => 'hook_node_access_records_alter()'))), 'illegitimate' => array(t('illegitimate'), 'error', t('Should NOT be in !na because of lower priority!', $variables)), 'alien' => array(t('alien'), 'error', t('Should NOT be in !na because of unknown origin!', $variables))); $active_states = array('default', 'ok', 'static', 'unexpected', 'wrong', 'illegitimate', 'alien'); $headers = array(t('node'), t('prio'), t('status'), t('realm'), t('gid'), t('view'), t('update'), t('delete'), t('explained')); $headers = self::format_row($headers); $active_records = array(); foreach ($query->execute() as $active_record) { $active_records[$active_record->nid][$active_record->realm][$active_record->gid] = $active_record; } $all_records = $grants_data = $checked_grants = $grants = array(); foreach (array('view', 'update', 'delete') as $op) { $grants[$op] = self::simulate_module_invoke_all('node_grants', $user, $op); // Call all hook_node_grants_alter() implementations. $grants_data[$op] = self::simulate_node_grants_alter($grants[$op], $user, $op); } foreach ($nids as $nid) { $top_priority = -99999; $acquired_records_nid = array(); if ($node = Node::load($nid)) { // Check node_access_acquire_grants(). $records = self::simulate_module_invoke_all('node_access_records', $node); // Check drupal_alter('node_access_records'). $data = self::simulate_node_access_records_alter($records, $node); if (!empty($data)) { foreach ($data as $data_by_realm) { foreach ($data_by_realm as $data_by_realm_gid) { if (isset($data_by_realm_gid['current'])) { $record = $data_by_realm_gid['current']; } elseif (isset($data_by_realm_gid['original'])) { $record = $data_by_realm_gid['original']; $record['#removed'] = 1; } else { continue; } $priority = intval(isset($record['priority']) ? $record['priority'] : 0); $top_priority = isset($top_priority) ? max($top_priority, $priority) : $priority; $record['priority'] = isset($record['priority']) ? $priority : '– '; $record['history'] = $data_by_realm_gid; $acquired_records_nid[$priority][$record['realm']][$record['gid']] = $record + array('#title' => self::get_node_title($node), '#module' => isset($record['#module']) ? $record['#module'] : ''); } } krsort($acquired_records_nid); } //dpm($acquired_records_nid, "acquired_records_nid ="); // Check node_access_grants(). if ($node->id()) { foreach (array('view', 'update', 'delete') as $op) { $checked_grants[$nid][$op] = array_merge(array('all' => array(0)), $grants[$op]); } } } // Check for records in the node_access table that aren't returned by // node_access_acquire_grants(). if (isset($active_records[$nid])) { foreach ($active_records[$nid] as $realm => $active_records_realm) { foreach ($active_records_realm as $gid => $active_record) { $found = FALSE; $count_nonempty_records = 0; foreach ($acquired_records_nid as $priority => $acquired_records_nid_priority) { if (isset($acquired_records_nid_priority[$realm][$gid])) { $found = TRUE; } } // Take the highest priority only. // TODO This has changed in D8! if ($acquired_records_nid_priority = reset($acquired_records_nid)) { foreach ($acquired_records_nid_priority as $acquired_records_nid_priority_realm) { foreach ($acquired_records_nid_priority_realm as $acquired_records_nid_priority_realm_gid) { $count_nonempty_records += !empty($acquired_records_nid_priority_realm_gid['grant_view']) || !empty($acquired_records_nid_priority_realm_gid['grant_update']) || !empty($acquired_records_nid_priority_realm_gid['grant_delete']); } } } $fixed_record = (array) $active_record; if ($count_nonempty_records == 0 && $realm == 'all' && $gid == 0) { $fixed_record += array('priority' => '–', 'state' => 'default'); } elseif (!$found) { $acknowledged = self::simulate_module_invoke_all('node_access_acknowledge', $fixed_record); if (empty($acknowledged)) { // No module acknowledged this record, mark it as alien. $fixed_record += array('priority' => '?', 'state' => 'alien'); } else { // At least one module acknowledged the record, // attribute it to the first one. $fixed_record += array('priority' => '–', 'state' => 'static', '#module' => reset(array_keys($acknowledged))); } } else { continue; } $fixed_record += array('nid' => $nid, '#title' => self::get_node_title($node)); $all_records[] = $fixed_record; } } } // Order records and evaluate their status. foreach ($acquired_records_nid as $priority => $acquired_records_priority) { ksort($acquired_records_priority); foreach ($acquired_records_priority as $realm => $acquired_records_realm) { ksort($acquired_records_realm); foreach ($acquired_records_realm as $gid => $acquired_record) { // TODO: Handle priority. //if ($priority == $top_priority) { if (empty($acquired_record['grant_view']) && empty($acquired_record['grant_update']) && empty($acquired_record['grant_delete'])) { $acquired_record['state'] = 'empty'; } else { if (isset($active_records[$nid][$realm][$gid])) { $acquired_record['state'] = isset($acquired_record['#removed']) ? 'removed!' : 'ok'; } else { $acquired_record['state'] = isset($acquired_record['#removed']) ? 'removed' : 'missing'; } if ($acquired_record['state'] == 'ok') { foreach (array('view', 'update', 'delete') as $op) { $active_record = (array) $active_records[$nid][$realm][$gid]; if (empty($acquired_record["grant_{$op}"]) != empty($active_record["grant_{$op}"])) { $acquired_record["grant_{$op}!"] = $active_record["grant_{$op}"]; } } } } //} //else { // $acquired_record['state'] = (isset($active_records[$nid][$realm][$gid]) ? 'illegitimate' : 'ignored'); //} $all_records[] = $acquired_record + array('nid' => $nid); } } } } // Fill in the table rows. $rows = array(); $error_count = 0; foreach ($all_records as $record) { $row = new \stdClass(); $row->nid = $record['nid']; $row->title = $record['#title']; $row->priority = $record['priority']; $row->state = array('data' => $states[$record['state']][0], 'title' => $states[$record['state']][2]); $row->realm = $record['realm']; $row->gid = $record['gid']; $row->grant_view = $record['grant_view']; $row->grant_update = $record['grant_update']; $row->grant_delete = $record['grant_delete']; $row->explained = implode('<br />', \Drupal::moduleHandler()->invokeAll('node_access_explain', $row)); unset($row->title); if ($row->nid == 0 && $row->gid == 0 && $row->realm == 'all' && count($all_records) > 1) { $row->state = array('data' => $states['unexpected'][0], 'title' => $states['unexpected'][2]); $class = $states['unexpected'][1]; } else { $class = $states[$record['state']][1]; } $row = (array) $row; foreach (array('view', 'update', 'delete') as $op) { $row["grant_{$op}"] = array('data' => $row["grant_{$op}"]); if ((isset($checked_grants[$record['nid']][$op][$record['realm']]) && in_array($record['gid'], $checked_grants[$record['nid']][$op][$record['realm']]) || $row['nid'] == 0 && $row['gid'] == 0 && $row['realm'] == 'all') && !empty($row["grant_{$op}"]['data']) && in_array($record['state'], $active_states)) { $row["grant_{$op}"]['data'] .= '′'; $row["grant_{$op}"]['title'] = t('This entry grants access to this node to this user.'); } if (isset($record["grant_{$op}!"])) { $row["grant_{$op}"]['data'] = $record["grant_{$op}!"] . '>' . (!$row["grant_{$op}"]['data'] ? 0 : $row["grant_{$op}"]['data']); $row["grant_{$op}"]['class'][] = 'error'; if ($class == 'ok') { $row['state'] = array('data' => $states['wrong'][0], 'title' => $states['wrong'][2]); $class = $states['wrong'][1]; } } } $error_count += $class == 'error'; $row['nid'] = array('data' => '<a href="#node-' . $record['nid'] . '">' . $row['nid'] . '</a>', 'title' => $record['#title']); if (empty($record['#module']) || strpos($record['realm'], $record['#module']) === 0) { $row['realm'] = $record['realm']; } else { $row['realm'] = array('data' => '(' . $record['#module'] . '::) ' . $record['realm'], 'title' => t("The '@module' module fails to adhere to the best practice of naming its realm(s) after itself.", array('@module' => $record['#module']))); } // Prepend information from the D7 hook_node_access_records_alter(). $next_style = array(); if (isset($record['history'])) { $history = $record['history']; if (($num_changes = count($history['changes']) - empty($history['current'])) > 0) { $first_row = TRUE; while (isset($history['original']) || $num_changes--) { if (isset($history['original'])) { $this_record = $history['original']; $this_action = '[ Original by ' . $this_record['#module'] . ':'; unset($history['original']); } else { $change = $history['changes'][0]; $this_record = $change['record']; $this_action = ($first_row ? '[ ' : '') . $change['op'] . ':'; array_shift($history['changes']); } $rows[] = array('data' => array('data' => array('data' => $this_action, 'style' => array('padding-bottom: 0;'))), 'style' => array_merge($first_row ? array() : array('border-top-style: dashed;', 'border-top-width: 1px;'), array('border-bottom-style: none;'))); $next_style = array('border-top-style: none;'); if (count($history['changes'])) { $g = $this_record; $rows[] = array('data' => array('v', $g['priority'], '', $g['realm'], $g['gid'], $g['grant_view'], $g['grant_update'], $g['grant_delete'], 'v'), 'style' => array('border-top-style: none;', 'border-bottom-style: dashed;')); $next_style = array('border-top-style: dashed;'); } $first_row = FALSE; } } } // Fix up the main row cells with the proper class (needed for Bartik). foreach ($row as $key => $value) { if (!is_array($value)) { $row[$key] = array('data' => $value); } $row[$key]['class'] = array($class); } // Add the main row. $will_append = empty($history['current']) && !empty($history['changes']); $rows[] = array('data' => array_values($row), 'class' => array($class), 'style' => array_merge($next_style, $will_append ? array('border-bottom-style: none;') : array())); // Append information from the D7 hook_node_access_records_alter(). if ($will_append) { $last_change = end($history['changes']); $rows[] = array('data' => array('data' => array('data' => $last_change['op'] . ' ]', 'style' => array('padding-top: 0;'))), 'style' => array('border-top-style: none;')); } } foreach ($rows as $i => $row) { $rows[$i] = self::format_row($row); } $output[] = array('#theme' => 'table', '#header' => $headers, '#rows' => $rows, '#attributes' => array('class' => array('system-status-report'), 'style' => 'text-align: left;')); $output[] = array('#theme' => 'form_element', '#description' => t('(Some of the table elements provide additional information if you hover your mouse over them.)')); if ($error_count > 0) { $variables['!Rebuild_permissions'] = '<a href="' . url('admin/reports/status/rebuild') . '">' . $tr('Rebuild permissions') . '</a>'; $output[] = array('#prefix' => "\n<span class=\"error\">", '#markup' => t("You have errors in your !na table! You may be able to fix these for now by running !Rebuild_permissions, but this is likely to destroy the evidence and make it impossible to identify the underlying issues. If you don't fix those, the errors will probably come back again. <br /> DON'T do this just yet if you intend to ask for help with this situation.", $variables), '#suffix' => "</span><br />\n"); } // Explain whether access is granted or denied, and why // (using code from node_access()). $tr = 't'; array_shift($nids); // Remove the 0. $accounts = array(); $variables += array('!username' => '<em class="placeholder">' . $user->getDisplayName() . '</em>', '%uid' => $user->id()); if (\Drupal::currentUser()->hasPermission('bypass node access')) { $variables['%bypass_node_access'] = $tr('bypass node access'); $output[] = array('#markup' => t('!username has the %bypass_node_access permission and thus full access to all nodes.', $variables), '#suffix' => '<br /> '); } else { $variables['!list'] = '<div style="margin-left: 2em">' . self::get_grant_list($grants_data['view']) . '</div>'; $variables['%access'] = 'view'; $output[] = array('#prefix' => "\n<div style='text-align: left' title='" . t('These are the grants returned by hook_node_grants() for this user.') . "'>", '#markup' => t('!username (user %uid) can use these grants (if they are present above) for %access access: !list', $variables), '#suffix' => "</div>\n"); $accounts[] = $user; } if (isset($single_nid) && !$user_block_active) { // Only for single nodes. if (\Drupal::currentUser()->isAuthenticated()) { $accounts[] = User::load(0); // Anonymous, too. } foreach ($accounts as $account) { $nid_items = array(); foreach ($nids as $nid) { $op_items = array(); foreach (array('create', 'view', 'update', 'delete') as $op) { $explain = self::explainAccess($op, Node::load($nid), $account); $op_items[] = "<div style='width: 5em; display: inline-block'>" . t('%op:', array('%op' => $op)) . ' </div>' . $explain[2]; } $nid_items[] = array('#theme' => 'item_list', '#items' => $op_items, '#type' => 'ul', '#prefix' => t('to node !nid:', array('!nid' => l($nid, 'node/' . $nid))) . "\n<div style='margin-left: 2em'>", '#suffix' => '</div>'); } if (count($nid_items) == 1) { $account_items = $nid_items[0]; } else { $account_items = array('#theme' => 'item_list', '#items' => $nid_items, '#type' => 'ul', '#prefix' => "\n<div style='margin-left: 2em'>", '#suffix' => '</div>'); } $variables['!username'] = '******' . theme('username', array('account' => $account)) . '</em>'; $output[] = array('#prefix' => "\n<div style='text-align: left'>", '#type' => 'item', 'lead-in' => array('#markup' => t("!username has the following access", $variables) . ' '), 'items' => $account_items, '#suffix' => "\n</div>\n"); } } } return $output; }
/** * Tests uninstalling content_translation. */ protected function doUninstallTest() { // Delete all the nodes so there is no data. $nodes = Node::loadMultiple(); foreach ($nodes as $node) { $node->delete(); } $language_count = count(\Drupal::configFactory()->listAll('language.content_settings.')); \Drupal::service('module_installer')->uninstall(['content_translation']); $this->rebuildContainer(); $this->assertEqual($language_count, count(\Drupal::configFactory()->listAll('language.content_settings.')), 'Languages have been fixed rather than deleted during content_translation uninstall.'); }
/** * Check whether the rendered output matches expectations. * * @param \Drupal\Core\Session\AccountInterface $account * The user account to tests rendering with. * @param bool $check_cache * (optional) Whether explicitly test render cache entries. */ protected function doTestRenderedOutput(AccountInterface $account, $check_cache = FALSE) { $this->setCurrentUser($account); $view = Views::getView('test_row_render_cache'); $view->setDisplay(); $view->preview(); /** @var \Drupal\Core\Render\RenderCacheInterface $render_cache */ $render_cache = $this->container->get('render_cache'); /** @var \Drupal\views\Plugin\views\cache\CachePluginBase $cache_plugin */ $cache_plugin = $view->display_handler->getPlugin('cache'); // Retrieve nodes and sort them in alphabetical order to match view results. $nodes = Node::loadMultiple(); usort($nodes, function (NodeInterface $a, NodeInterface $b) { return strcmp($a->label(), $b->label()); }); $index = 0; foreach ($nodes as $node) { $nid = $node->id(); $access = $node->access('update'); $counter = $index + 1; $expected = "{$nid}: {$counter} (just in case: {$nid})"; $counter_output = $view->style_plugin->getField($index, 'counter'); $this->assertEqual($counter_output, $expected); $node_url = $node->url(); $expected = "<a href=\"{$node_url}\"><span class=\"da-title\">{$node->label()}</span> <span class=\"counter\">{$counter_output}</span></a>"; $output = $view->style_plugin->getField($index, 'title'); $this->assertEqual($output, $expected); $expected = $access ? "<a href=\"{$node_url}/edit?destination=/\" hreflang=\"en\">edit</a>" : ""; $output = $view->style_plugin->getField($index, 'edit_node'); $this->assertEqual($output, $expected); $expected = $access ? "<a href=\"{$node_url}/delete?destination=/\" hreflang=\"en\">delete</a>" : ""; $output = $view->style_plugin->getField($index, 'delete_node'); $this->assertEqual($output, $expected); $expected = $access ? " <div class=\"dropbutton-wrapper\"><div class=\"dropbutton-widget\"><ul class=\"dropbutton\">" . "<li class=\"edit\"><a href=\"{$node_url}/edit?destination=/\" hreflang=\"en\">Edit</a></li>" . "<li class=\"delete\"><a href=\"{$node_url}/delete?destination=/\" hreflang=\"en\">Delete</a></li>" . "</ul></div></div>" : ""; $output = $view->style_plugin->getField($index, 'operations'); $this->assertEqual($output, $expected); if ($check_cache) { $keys = $cache_plugin->getRowCacheKeys($view->result[$index]); $user_context = !$account->hasPermission('edit any test content') ? 'user' : 'user.permissions'; $element = $render_cache->get(['#cache' => ['keys' => $keys, 'contexts' => ['languages:language_interface', 'theme', $user_context]]]); $this->assertTrue($element); } $index++; } }
/** * Display FAQ questions and answers filtered by category. * * @param $faq_display * Define the way the FAQ is being shown; can have the values: * 'questions top',hide answers','questions inline','new page'. * @param $category_display * The layout of categories which should be used. * @param $term * The category / term to display FAQs for. * @param $display_header * Set if the header will be shown or not. * @param &$output * Reference which holds the content of the page, HTML formatted. * @param &$output_answer * Reference which holds the answers from the FAQ, when showing questions * on top. */ private function _displayFaqByCategory($faq_display, $category_display, $term, $display_header, &$output, &$output_answers) { $default_sorting = \Drupal::config('faq.settings')->get('default_sorting'); $term_id = $term->id(); $query = db_select('node', 'n'); $query->join('node_field_data', 'd', 'd.nid = n.nid'); $query->innerJoin('taxonomy_index', 'ti', 'n.nid = ti.nid'); $query->leftJoin('faq_weights', 'w', 'w.tid = ti.tid AND n.nid = w.nid'); $query->fields('n', array('nid'))->condition('n.type', 'faq')->condition('d.status', 1)->condition("ti.tid", $term_id)->addTag('node_access'); $default_weight = 0; if ($default_sorting == 'ASC') { $default_weight = 1000000; } // Works, but involves variable concatenation - safe though, since // $default_weight is an integer. $query->addExpression("COALESCE(w.weight, {$default_weight})", 'effective_weight'); // Doesn't work in Postgres. //$query->addExpression('COALESCE(w.weight, CAST(:default_weight as SIGNED))', 'effective_weight', array(':default_weight' => $default_weight)); $query->orderBy('effective_weight', 'ASC')->orderBy('d.sticky', 'DESC'); if ($default_sorting == 'ASC') { $query->orderBy('d.created', 'ASC'); } else { $query->orderBy('d.created', 'DESC'); } // We only want the first column, which is nid, so that we can load all // related nodes. $nids = $query->execute()->fetchCol(); $data = Node::loadMultiple($nids); // Handle indenting of categories. $depth = 0; if (!isset($term->depth)) { $children = taxonomy_term_load_children($term->id()); $term->depth = count($children); } while ($depth < $term->depth) { $display_header = 1; $indent = '<div class="faq-category-indent">'; $output .= $indent; $depth++; } // Set up the class name for hiding the q/a for a category if required. $faq_class = "faq-qa"; if ($category_display == "hide_qa") { $faq_class = "faq-qa-hide"; } $output_render = $output_answers_render = array('#data' => $data, '#display_header' => $display_header, '#category_display' => $category_display, '#term' => $term, '#class' => $faq_class, '#parent_term' => $term); switch ($faq_display) { case 'questions_top': $output_render['#theme'] = 'faq_category_questions_top'; $output .= drupal_render($output_render); $output_answers_render['#theme'] = 'faq_category_questions_top_answers'; $output_answers .= drupal_render($output_answers_render); break; case 'hide_answer': $output_render['#theme'] = 'faq_category_hide_answer'; $output .= drupal_render($output_render); break; case 'questions_inline': $output_render['#theme'] = 'faq_category_questions_inline'; $output .= drupal_render($output_render); break; case 'new_page': $output_render['#theme'] = 'faq_category_new_page'; $output .= drupal_render($output_render); break; } // Handle indenting of categories. while ($depth > 0) { $output .= '</div>'; $depth--; } }
/** * Tests that auto saving in a component executed as action works. */ public function testComponentActionAutoSave() { $entity_type_manager = $this->container->get('entity_type.manager'); $entity_type_manager->getStorage('node_type')->create(['type' => 'page'])->save(); $nested_rule = $this->expressionManager->createRule(); // Create a node entity with the action. $nested_rule->addAction('rules_entity_create:node', ContextConfig::create()->setValue('type', 'page')); // Set the title of the new node so that it is marked for auto-saving. $nested_rule->addAction('rules_data_set', ContextConfig::create()->map('data', 'entity.title')->setValue('value', 'new title')); $rules_config = new RulesComponentConfig(['id' => 'test_rule', 'label' => 'Test rule'], 'rules_component'); $rules_config->setExpression($nested_rule); $rules_config->save(); // Invoke the rules component in another rule. $rule = $this->expressionManager->createRule(); $rule->addAction('rules_component:test_rule'); RulesComponent::create($rule)->execute(); $nodes = Node::loadMultiple(); $node = reset($nodes); $this->assertEquals('new title', $node->getTitle()); $this->assertNotNull($node->id(), 'Node ID is set, which means that the node has been auto-saved.'); }
/** * Helper function for retrieving the sub-categories faqs. * * @param $term * The category / term to display FAQs for. * @param $theme_function * Theme function to use to format the Q/A layout for sub-categories. * @param $default_weight * Is 0 for $default_sorting = DESC; is 1000000 for $default_sorting = ASC. * @param $default_sorting * If 'DESC', nodes are sorted by creation date descending; if 'ASC', nodes * are sorted by creation date ascending. * @param $category_display * The layout of categories which should be used. * @param $class * CSS class which the HTML div will be using. A special class name is * required in order to hide and questions / answers. * @param $parent_term * The original, top-level, term we're displaying FAQs for. */ public static function getChildCategoriesFaqs($term, $theme_function, $default_weight, $default_sorting, $category_display, $class, $parent_term = NULL) { $output = array(); $list = taxonomy_term_load_children($term->id()); if (!is_array($list)) { return ''; } foreach ($list as $tid => $child_term) { $child_term->depth = $term->depth + 1; if (FaqHelper::taxonomyTermCountNodes($child_term->id())) { $query = db_select('node', 'n'); $query->join('node_field_data', 'd', 'n.nid = d.nid'); $ti_alias = $query->innerJoin('taxonomy_index', 'ti', '(n.nid = %alias.nid)'); $w_alias = $query->leftJoin('faq_weights', 'w', "%alias.tid = {$ti_alias}.tid AND n.nid = %alias.nid"); $query->fields('n', array('nid'))->condition('n.type', 'faq')->condition('d.status', 1)->condition("{$ti_alias}.tid", $child_term->id())->addTag('node_access'); $default_weight = 0; if ($default_sorting == 'ASC') { $default_weight = 1000000; } // Works, but involves variable concatenation - safe though, since // $default_weight is an integer. $query->addExpression("COALESCE(w.weight, {$default_weight})", 'effective_weight'); // Doesn't work in Postgres. //$query->addExpression('COALESCE(w.weight, CAST(:default_weight as SIGNED))', 'effective_weight', array(':default_weight' => $default_weight)); $query->orderBy('effective_weight', 'ASC')->orderBy('d.sticky', 'DESC'); if ($default_sorting == 'ASC') { $query->orderBy('d.created', 'ASC'); } else { $query->orderBy('d.created', 'DESC'); } // We only want the first column, which is nid, so that we can load all // related nodes. $nids = $query->execute()->fetchCol(); $data = Node::loadMultiple($nids); $to_render = array('#theme' => $theme_function, '#data' => $data, '#display_header' => 1, '#category_display' => $category_display, '#term' => $child_term, '#class' => $class, '#parent_term' => $parent_term); $output[] = drupal_render($to_render); } } return $output; }
/** * Deletes all nodes. */ protected function deleteNodes() { $nodes = \Drupal\node\Entity\Node::loadMultiple(); foreach ($nodes as $node) { // Node::delete() does not work here as expected by some reasons. $this->drupalPostForm(sprintf('node/%d/delete', $node->id()), [], t('Delete')); } }
/** * {@inheritdoc} */ public function updateSendStatus() { $counts = array(); // number of pending emails in the spool $sum = array(); // sum of emails in the spool per tnid (translation id) $send = array(); // nodes with the status 'send' // For each pending newsletter count the number of pending emails in the spool. $query = \Drupal::entityQuery('node'); $nids = $query->condition('simplenews_issue.status', SIMPLENEWS_STATUS_SEND_PENDING)->execute(); $nodes = Node::loadMultiple($nids); if ($nodes) { foreach ($nodes as $nid => $node) { $counts[$node->simplenews_issue->target_id][$nid] = \Drupal::service('simplenews.spool_storage')->countMails(array('entity_id' => $nid, 'entity_type' => 'node')); } } // Determine which nodes are send per translation group and per individual node. foreach ($counts as $newsletter_id => $node_count) { // The sum of emails per tnid is the combined status result for the group of translated nodes. // Untranslated nodes have tnid == 0 which will be ignored later. $sum[$newsletter_id] = array_sum($node_count); foreach ($node_count as $nid => $count) { // Translated nodes (tnid != 0) if ($newsletter_id != '0' && $sum[$newsletter_id] == '0') { $send[] = $nid; } elseif ($newsletter_id == '0' && $count == '0') { $send[] = $nid; } } } // Update overall newsletter status if (!empty($send)) { foreach ($send as $nid) { $node = Node::load($nid); $node->simplenews_issue->status = SIMPLENEWS_STATUS_SEND_READY; $node->save(); } } }