3 namespace Drupal\node\Plugin\migrate\source\d6;
5 use Drupal\Core\Database\Query\SelectInterface;
6 use Drupal\Core\Entity\EntityManagerInterface;
7 use Drupal\Core\Extension\ModuleHandler;
8 use Drupal\Core\State\StateInterface;
9 use Drupal\migrate\Plugin\MigrationInterface;
10 use Drupal\migrate\Row;
11 use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
12 use Symfony\Component\DependencyInjection\ContainerInterface;
15 * Drupal 6 node source from database.
19 * source_module = "node"
23 class Node extends DrupalSqlBase {
26 * The join options between the node and the node_revisions table.
28 const JOIN = 'n.vid = nr.vid';
31 * The default filter format.
35 protected $filterDefaultFormat;
38 * Cached field and field instance definitions.
47 * @var \Drupal\Core\Extension\ModuleHandler
49 protected $moduleHandler;
54 public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, StateInterface $state, EntityManagerInterface $entity_manager, ModuleHandler $module_handler) {
55 parent::__construct($configuration, $plugin_id, $plugin_definition, $migration, $state, $entity_manager);
56 $this->moduleHandler = $module_handler;
62 public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration = NULL) {
68 $container->get('state'),
69 $container->get('entity.manager'),
70 $container->get('module_handler')
77 public function query() {
78 $query = $this->select('node_revisions', 'nr');
79 $query->innerJoin('node', 'n', static::JOIN);
80 $this->handleTranslations($query);
105 $query->addField('n', 'uid', 'node_uid');
106 $query->addField('nr', 'uid', 'revision_uid');
108 // If the content_translation module is enabled, get the source langcode
109 // to fill the content_translation_source field.
110 if ($this->moduleHandler->moduleExists('content_translation')) {
111 $query->leftJoin('node', 'nt', 'n.tnid = nt.nid');
112 $query->addField('nt', 'language', 'source_langcode');
115 if (isset($this->configuration['node_type'])) {
116 $query->condition('n.type', $this->configuration['node_type']);
125 protected function initializeIterator() {
126 $this->filterDefaultFormat = $this->variableGet('filter_default_format', '1');
127 return parent::initializeIterator();
133 public function fields() {
135 'nid' => $this->t('Node ID'),
136 'type' => $this->t('Type'),
137 'title' => $this->t('Title'),
138 'body' => $this->t('Body'),
139 'format' => $this->t('Format'),
140 'teaser' => $this->t('Teaser'),
141 'node_uid' => $this->t('Node authored by (uid)'),
142 'revision_uid' => $this->t('Revision authored by (uid)'),
143 'created' => $this->t('Created timestamp'),
144 'changed' => $this->t('Modified timestamp'),
145 'status' => $this->t('Published'),
146 'promote' => $this->t('Promoted to front page'),
147 'sticky' => $this->t('Sticky at top of lists'),
148 'revision' => $this->t('Create new revision'),
149 'language' => $this->t('Language (fr, en, ...)'),
150 'tnid' => $this->t('The translation set id for this node'),
151 'timestamp' => $this->t('The timestamp the latest revision of this node was created.'),
159 public function prepareRow(Row $row) {
160 // format = 0 can happen when the body field is hidden. Set the format to 1
161 // to avoid migration map issues (since the body field isn't used anyway).
162 if ($row->getSourceProperty('format') === '0') {
163 $row->setSourceProperty('format', $this->filterDefaultFormat);
166 if ($this->moduleExists('content') && $this->getModuleSchemaVersion('content') >= 6001) {
167 foreach ($this->getFieldValues($row) as $field => $values) {
168 $row->setSourceProperty($field, $values);
172 // Make sure we always have a translation set.
173 if ($row->getSourceProperty('tnid') == 0) {
174 $row->setSourceProperty('tnid', $row->getSourceProperty('nid'));
177 return parent::prepareRow($row);
181 * Gets field values for a node.
183 * @param \Drupal\migrate\Row $node
187 * Field values, keyed by field name.
189 protected function getFieldValues(Row $node) {
191 foreach ($this->getFieldInfo($node->getSourceProperty('type')) as $field => $info) {
192 $values[$field] = $this->getFieldData($info, $node);
198 * Gets field and instance definitions from the database.
200 * @param string $node_type
201 * The node type for which to get field info.
204 * Field and instance information for the node type, keyed by field name.
206 protected function getFieldInfo($node_type) {
207 if (!isset($this->fieldInfo)) {
208 $this->fieldInfo = [];
210 // Query the database directly for all field info.
211 $query = $this->select('content_node_field_instance', 'cnfi');
212 $query->join('content_node_field', 'cnf', 'cnf.field_name = cnfi.field_name');
213 $query->fields('cnfi');
214 $query->fields('cnf');
216 foreach ($query->execute() as $field) {
217 $this->fieldInfo[$field['type_name']][$field['field_name']] = $field;
220 foreach ($this->fieldInfo as $type => $fields) {
221 foreach ($fields as $field => $info) {
222 foreach ($info as $property => $value) {
223 if ($property == 'db_columns' || preg_match('/_settings$/', $property)) {
224 $this->fieldInfo[$type][$field][$property] = unserialize($value);
231 return isset($this->fieldInfo[$node_type]) ? $this->fieldInfo[$node_type] : [];
235 * Retrieves raw field data for a node.
237 * @param array $field
238 * A field and instance definition from getFieldInfo().
239 * @param \Drupal\migrate\Row $node
243 * The field values, keyed by delta.
245 protected function getFieldData(array $field, Row $node) {
246 $field_table = 'content_' . $field['field_name'];
247 $node_table = 'content_type_' . $node->getSourceProperty('type');
249 /** @var \Drupal\Core\Database\Schema $db */
250 $db = $this->getDatabase()->schema();
252 if ($db->tableExists($field_table)) {
253 $query = $this->select($field_table, 't');
255 // If the delta column does not exist, add it as an expression to
256 // normalize the query results.
257 if ($db->fieldExists($field_table, 'delta')) {
258 $query->addField('t', 'delta');
261 $query->addExpression(0, 'delta');
264 elseif ($db->tableExists($node_table)) {
265 $query = $this->select($node_table, 't');
267 // Every row should have a delta of 0.
268 $query->addExpression(0, 'delta');
272 $columns = array_keys($field['db_columns']);
274 // Add every column in the field's schema.
275 foreach ($columns as $column) {
276 $query->addField('t', $field['field_name'] . '_' . $column, $column);
280 // This call to isNotNull() is a kludge which relies on the convention
281 // that field schemas usually define their most important column first.
282 // A better way would be to allow field plugins to alter the query
283 // directly before it's run, but this will do for the time being.
284 ->isNotNull($field['field_name'] . '_' . $columns[0])
285 ->condition('nid', $node->getSourceProperty('nid'))
286 ->condition('vid', $node->getSourceProperty('vid'))
288 ->fetchAllAssoc('delta');
296 * Retrieves raw field data for a node.
298 * @deprecated in Drupal 8.2.x, to be removed in Drupal 9.0.x. Use
299 * getFieldData() instead.
301 * @param array $field
302 * A field and instance definition from getFieldInfo().
303 * @param \Drupal\migrate\Row $node
307 * The field values, keyed by delta.
309 protected function getCckData(array $field, Row $node) {
310 return $this->getFieldData($field, $node);
316 public function getIds() {
317 $ids['nid']['type'] = 'integer';
318 $ids['nid']['alias'] = 'n';
323 * Adapt our query for translations.
325 * @param \Drupal\Core\Database\Query\SelectInterface $query
326 * The generated query.
328 protected function handleTranslations(SelectInterface $query) {
329 // Check whether or not we want translations.
330 if (empty($this->configuration['translations'])) {
331 // No translations: Yield untranslated nodes, or default translations.
332 $query->where('n.tnid = 0 OR n.tnid = n.nid');
335 // Translations: Yield only non-default translations.
336 $query->where('n.tnid <> 0 AND n.tnid <> n.nid');