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.
21 class Node extends DrupalSqlBase {
24 * The join options between the node and the node_revisions table.
26 const JOIN = 'n.vid = nr.vid';
29 * The default filter format.
33 protected $filterDefaultFormat;
36 * Cached field and field instance definitions.
45 * @var \Drupal\Core\Extension\ModuleHandler
47 protected $moduleHandler;
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;
60 public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration = NULL) {
66 $container->get('state'),
67 $container->get('entity.manager'),
68 $container->get('module_handler')
75 public function query() {
76 $query = $this->select('node_revisions', 'nr');
77 $query->innerJoin('node', 'n', static::JOIN);
78 $this->handleTranslations($query);
103 $query->addField('n', 'uid', 'node_uid');
104 $query->addField('nr', 'uid', 'revision_uid');
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');
113 if (isset($this->configuration['node_type'])) {
114 $query->condition('n.type', $this->configuration['node_type']);
123 protected function initializeIterator() {
124 $this->filterDefaultFormat = $this->variableGet('filter_default_format', '1');
125 return parent::initializeIterator();
131 public function 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.'),
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);
164 if ($this->moduleExists('content') && $this->getModuleSchemaVersion('content') >= 6001) {
165 foreach ($this->getFieldValues($row) as $field => $values) {
166 $row->setSourceProperty($field, $values);
170 // Make sure we always have a translation set.
171 if ($row->getSourceProperty('tnid') == 0) {
172 $row->setSourceProperty('tnid', $row->getSourceProperty('nid'));
175 return parent::prepareRow($row);
179 * Gets CCK field values for a node.
181 * @param \Drupal\migrate\Row $node
185 * CCK field values, keyed by field name.
187 protected function getFieldValues(Row $node) {
189 foreach ($this->getFieldInfo($node->getSourceProperty('type')) as $field => $info) {
190 $values[$field] = $this->getCckData($info, $node);
196 * Gets CCK field and instance definitions from the database.
198 * @param string $node_type
199 * The node type for which to get field info.
202 * Field and instance information for the node type, keyed by field name.
204 protected function getFieldInfo($node_type) {
205 if (!isset($this->fieldInfo)) {
206 $this->fieldInfo = [];
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');
214 foreach ($query->execute() as $field) {
215 $this->fieldInfo[ $field['type_name'] ][ $field['field_name'] ] = $field;
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);
229 return isset($this->fieldInfo[$node_type]) ? $this->fieldInfo[$node_type] : [];
233 * Retrieves raw CCK field data for a node.
235 * @param array $field
236 * A field and instance definition from getFieldInfo().
237 * @param \Drupal\migrate\Row $node
241 * The field values, keyed by delta.
243 protected function getCckData(array $field, Row $node) {
244 $field_table = 'content_' . $field['field_name'];
245 $node_table = 'content_type_' . $node->getSourceProperty('type');
247 /** @var \Drupal\Core\Database\Schema $db */
248 $db = $this->getDatabase()->schema();
250 if ($db->tableExists($field_table)) {
251 $query = $this->select($field_table, 't');
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');
259 $query->addExpression(0, 'delta');
262 elseif ($db->tableExists($node_table)) {
263 $query = $this->select($node_table, 't');
265 // Every row should have a delta of 0.
266 $query->addExpression(0, 'delta');
270 $columns = array_keys($field['db_columns']);
272 // Add every column in the field's schema.
273 foreach ($columns as $column) {
274 $query->addField('t', $field['field_name'] . '_' . $column, $column);
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
283 ->isNotNull($field['field_name'] . '_' . $columns[0])
284 ->condition('nid', $node->getSourceProperty('nid'))
285 ->condition('vid', $node->getSourceProperty('vid'))
287 ->fetchAllAssoc('delta');
297 public function getIds() {
298 $ids['nid']['type'] = 'integer';
299 $ids['nid']['alias'] = 'n';
304 * Adapt our query for translations.
306 * @param \Drupal\Core\Database\Query\SelectInterface $query
307 * The generated query.
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');
316 // Translations: Yield only non-default translations.
317 $query->where('n.tnid <> 0 AND n.tnid <> n.nid');