Version 1
[yaffs-website] / web / core / modules / node / src / Plugin / migrate / source / d6 / Node.php
1 <?php
2
3 namespace Drupal\node\Plugin\migrate\source\d6;
4
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;
13
14 /**
15  * Drupal 6 node source from database.
16  *
17  * @MigrateSource(
18  *   id = "d6_node"
19  * )
20  */
21 class Node extends DrupalSqlBase {
22
23   /**
24    * The join options between the node and the node_revisions table.
25    */
26   const JOIN = 'n.vid = nr.vid';
27
28   /**
29    * The default filter format.
30    *
31    * @var string
32    */
33   protected $filterDefaultFormat;
34
35   /**
36    * Cached field and field instance definitions.
37    *
38    * @var array
39    */
40   protected $fieldInfo;
41
42   /**
43    * The module handler.
44    *
45    * @var \Drupal\Core\Extension\ModuleHandler
46    */
47   protected $moduleHandler;
48
49   /**
50    * {@inheritdoc}
51    */
52   public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, StateInterface $state, EntityManagerInterface $entity_manager, ModuleHandler $module_handler) {
53     parent::__construct($configuration, $plugin_id, $plugin_definition, $migration, $state, $entity_manager);
54     $this->moduleHandler = $module_handler;
55   }
56
57   /**
58    * {@inheritdoc}
59    */
60   public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration = NULL) {
61     return new static(
62       $configuration,
63       $plugin_id,
64       $plugin_definition,
65       $migration,
66       $container->get('state'),
67       $container->get('entity.manager'),
68       $container->get('module_handler')
69     );
70   }
71
72   /**
73    * {@inheritdoc}
74    */
75   public function query() {
76     $query = $this->select('node_revisions', 'nr');
77     $query->innerJoin('node', 'n', static::JOIN);
78     $this->handleTranslations($query);
79
80     $query->fields('n', [
81         'nid',
82         'type',
83         'language',
84         'status',
85         'created',
86         'changed',
87         'comment',
88         'promote',
89         'moderate',
90         'sticky',
91         'tnid',
92         'translate',
93       ])
94       ->fields('nr', [
95         'title',
96         'body',
97         'teaser',
98         'log',
99         'timestamp',
100         'format',
101         'vid',
102       ]);
103     $query->addField('n', 'uid', 'node_uid');
104     $query->addField('nr', 'uid', 'revision_uid');
105
106     // If the content_translation module is enabled, get the source langcode
107     // to fill the content_translation_source field.
108     if ($this->moduleHandler->moduleExists('content_translation')) {
109       $query->leftJoin('node', 'nt', 'n.tnid = nt.nid');
110       $query->addField('nt', 'language', 'source_langcode');
111     }
112
113     if (isset($this->configuration['node_type'])) {
114       $query->condition('n.type', $this->configuration['node_type']);
115     }
116
117     return $query;
118   }
119
120   /**
121    * {@inheritdoc}
122    */
123   protected function initializeIterator() {
124     $this->filterDefaultFormat = $this->variableGet('filter_default_format', '1');
125     return parent::initializeIterator();
126   }
127
128   /**
129    * {@inheritdoc}
130    */
131   public function fields() {
132     $fields = [
133       'nid' => $this->t('Node ID'),
134       'type' => $this->t('Type'),
135       'title' => $this->t('Title'),
136       'body' => $this->t('Body'),
137       'format' => $this->t('Format'),
138       'teaser' => $this->t('Teaser'),
139       'node_uid' => $this->t('Node authored by (uid)'),
140       'revision_uid' => $this->t('Revision authored by (uid)'),
141       'created' => $this->t('Created timestamp'),
142       'changed' => $this->t('Modified timestamp'),
143       'status' => $this->t('Published'),
144       'promote' => $this->t('Promoted to front page'),
145       'sticky' => $this->t('Sticky at top of lists'),
146       'revision' => $this->t('Create new revision'),
147       'language' => $this->t('Language (fr, en, ...)'),
148       'tnid' => $this->t('The translation set id for this node'),
149       'timestamp' => $this->t('The timestamp the latest revision of this node was created.'),
150     ];
151     return $fields;
152   }
153
154   /**
155    * {@inheritdoc}
156    */
157   public function prepareRow(Row $row) {
158     // format = 0 can happen when the body field is hidden. Set the format to 1
159     // to avoid migration map issues (since the body field isn't used anyway).
160     if ($row->getSourceProperty('format') === '0') {
161       $row->setSourceProperty('format', $this->filterDefaultFormat);
162     }
163
164     if ($this->moduleExists('content') && $this->getModuleSchemaVersion('content') >= 6001) {
165       foreach ($this->getFieldValues($row) as $field => $values) {
166         $row->setSourceProperty($field, $values);
167       }
168     }
169
170     // Make sure we always have a translation set.
171     if ($row->getSourceProperty('tnid') == 0) {
172       $row->setSourceProperty('tnid', $row->getSourceProperty('nid'));
173     }
174
175     return parent::prepareRow($row);
176   }
177
178   /**
179    * Gets CCK field values for a node.
180    *
181    * @param \Drupal\migrate\Row $node
182    *   The node.
183    *
184    * @return array
185    *   CCK field values, keyed by field name.
186    */
187   protected function getFieldValues(Row $node) {
188     $values = [];
189     foreach ($this->getFieldInfo($node->getSourceProperty('type')) as $field => $info) {
190       $values[$field] = $this->getCckData($info, $node);
191     }
192     return $values;
193   }
194
195   /**
196    * Gets CCK field and instance definitions from the database.
197    *
198    * @param string $node_type
199    *   The node type for which to get field info.
200    *
201    * @return array
202    *   Field and instance information for the node type, keyed by field name.
203    */
204   protected function getFieldInfo($node_type) {
205     if (!isset($this->fieldInfo)) {
206       $this->fieldInfo = [];
207
208       // Query the database directly for all CCK field info.
209       $query = $this->select('content_node_field_instance', 'cnfi');
210       $query->join('content_node_field', 'cnf', 'cnf.field_name = cnfi.field_name');
211       $query->fields('cnfi');
212       $query->fields('cnf');
213
214       foreach ($query->execute() as $field) {
215         $this->fieldInfo[ $field['type_name'] ][ $field['field_name'] ] = $field;
216       }
217
218       foreach ($this->fieldInfo as $type => $fields) {
219         foreach ($fields as $field => $info) {
220           foreach ($info as $property => $value) {
221             if ($property == 'db_columns' || preg_match('/_settings$/', $property)) {
222               $this->fieldInfo[$type][$field][$property] = unserialize($value);
223             }
224           }
225         }
226       }
227     }
228
229     return isset($this->fieldInfo[$node_type]) ? $this->fieldInfo[$node_type] : [];
230   }
231
232   /**
233    * Retrieves raw CCK field data for a node.
234    *
235    * @param array $field
236    *   A field and instance definition from getFieldInfo().
237    * @param \Drupal\migrate\Row $node
238    *   The node.
239    *
240    * @return array
241    *   The field values, keyed by delta.
242    */
243   protected function getCckData(array $field, Row $node) {
244     $field_table = 'content_' . $field['field_name'];
245     $node_table = 'content_type_' . $node->getSourceProperty('type');
246
247     /** @var \Drupal\Core\Database\Schema $db */
248     $db = $this->getDatabase()->schema();
249
250     if ($db->tableExists($field_table)) {
251       $query = $this->select($field_table, 't');
252
253       // If the delta column does not exist, add it as an expression to
254       // normalize the query results.
255       if ($db->fieldExists($field_table, 'delta')) {
256         $query->addField('t', 'delta');
257       }
258       else {
259         $query->addExpression(0, 'delta');
260       }
261     }
262     elseif ($db->tableExists($node_table)) {
263       $query = $this->select($node_table, 't');
264
265       // Every row should have a delta of 0.
266       $query->addExpression(0, 'delta');
267     }
268
269     if (isset($query)) {
270       $columns = array_keys($field['db_columns']);
271
272       // Add every column in the field's schema.
273       foreach ($columns as $column) {
274         $query->addField('t', $field['field_name'] . '_' . $column, $column);
275       }
276
277       return $query
278         // This call to isNotNull() is a kludge which relies on the convention
279         // that CCK field schemas usually define their most important
280         // column first. A better way would be to allow cckfield plugins to
281         // alter the query directly before it's run, but this will do for
282         // the time being.
283         ->isNotNull($field['field_name'] . '_' . $columns[0])
284         ->condition('nid', $node->getSourceProperty('nid'))
285         ->condition('vid', $node->getSourceProperty('vid'))
286         ->execute()
287         ->fetchAllAssoc('delta');
288     }
289     else {
290       return [];
291     }
292   }
293
294   /**
295    * {@inheritdoc}
296    */
297   public function getIds() {
298     $ids['nid']['type'] = 'integer';
299     $ids['nid']['alias'] = 'n';
300     return $ids;
301   }
302
303   /**
304    * Adapt our query for translations.
305    *
306    * @param \Drupal\Core\Database\Query\SelectInterface $query
307    *   The generated query.
308    */
309   protected function handleTranslations(SelectInterface $query) {
310     // Check whether or not we want translations.
311     if (empty($this->configuration['translations'])) {
312       // No translations: Yield untranslated nodes, or default translations.
313       $query->where('n.tnid = 0 OR n.tnid = n.nid');
314     }
315     else {
316       // Translations: Yield only non-default translations.
317       $query->where('n.tnid <> 0 AND n.tnid <> n.nid');
318     }
319   }
320
321 }