From 8f8e5df5929eb4e99348275910295c549ceafbc3 Mon Sep 17 00:00:00 2001
From: Yousef Bajawi <jose@josebcdev.com>
Date: Mon, 29 Jan 2018 16:27:52 +0200
Subject: [PATCH] Issue 2874050: Add adopt table functionality

---
 data.services.yml             |   3 ++
 src/Form/TableAdoptForm.php   |  79 ++++++++++++++++++++++++++++++-
 src/TableManager.php          | 107 ++++++++++++++++++++++++++++++++++++++++++
 src/TableManagerInterface.php |  33 +++++++++++++
 4 files changed, 221 insertions(+), 1 deletion(-)
 create mode 100644 src/TableManager.php
 create mode 100644 src/TableManagerInterface.php

diff --git a/data.services.yml b/data.services.yml
index aa58e67..099117c 100644
--- a/data.services.yml
+++ b/data.services.yml
@@ -2,4 +2,7 @@ services:
   data.row_manager:
     class: Drupal\data\RowManager
     arguments: ['@database']
+  data.table_manager:
+    class: Drupal\data\TableManager
+    arguments: ['@database', '@entity_type.manager', '@module_handler', '@config.factory']
 
diff --git a/src/Form/TableAdoptForm.php b/src/Form/TableAdoptForm.php
index d1d4ec7..d480fdc 100644
--- a/src/Form/TableAdoptForm.php
+++ b/src/Form/TableAdoptForm.php
@@ -4,6 +4,9 @@ namespace Drupal\data\Form;
 
 use Drupal\Core\Form\FormBase;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\data\TableManagerInterface;
+use Drupal\Core\Extension\ModuleHandlerInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Class TableAdoptForm.
@@ -12,27 +15,101 @@ use Drupal\Core\Form\FormStateInterface;
  */
 class TableAdoptForm extends FormBase {
 
+  /**
+   * tableManager service.
+   *
+   * @var \Drupal\data\TableManager
+   */
+  protected $TableManager;
+
+  /**
+   * The module handler.
+   *
+   * @var \Drupal\Core\Extension\ModuleHandlerInterface
+   */
+  protected $moduleHandler;
+
+  /**
+   * Constructs a new TableAdoptForm.
+   *
+   * @param \Drupal\data\TableManagerInterface $table_manager
+   *   The book manager.
+   */
+  public function __construct(TableManagerInterface $table_manager, ModuleHandlerInterface $module_handler) {
+    $this->tableManager = $table_manager;
+    $this->moduleHandler = $module_handler;
+  }
 
   /**
    * {@inheritdoc}
    */
+  public static function create(ContainerInterface $container) {
+    return new static(
+      $container->get('data.table_manager'),
+      $container->get('module_handler')
+    );
+  }
+
+  /**
+   *
+   * {@inheritdoc}
+   */
   public function getFormId() {
     return 'table_adopt_form';
   }
 
   /**
+   *
    * {@inheritdoc}
    */
   public function buildForm(array $form, FormStateInterface $form_state) {
+    if (!$this->moduleHandler->moduleExists('schema')) {
+      $form['schema_not_enabled'] = [
+        '#type' => 'markup',
+        '#markup' => $this->t('You need to enable the Schema module to adopt tables.')
+      ];
+      return $form;
+    }
+    $schema = schema_get_schema(TRUE);
+    $info = schema_compare_schemas($schema);
+    // We have now subtracted all the tables created via hook_schema.
+    $orphaned_tables = $info['extra'];
+    if (count($orphaned_tables) < 1) {
+      $form['no_orphaned_tables'] = [
+        '#type' => 'markup',
+        '#markup' => $this->t('There are no orphaned tables in your database.')
+      ];
+    }
+    else {
+      $form['orphaned_tables'] = [
+        '#type' => 'checkboxes',
+        '#title' => $this->t('Orphaned Tables'),
+        '#options' => array_combine($orphaned_tables, $orphaned_tables)
+      ];
 
+      $form['submit'] = [
+        '#type' => 'submit',
+        '#value' => $this->t('Adopt')
+      ];
+    }
     return $form;
   }
 
   /**
+   *
    * {@inheritdoc}
    */
   public function submitForm(array &$form, FormStateInterface $form_state) {
-
+    $tables = array_filter($form_state->getValue('orphaned_tables'));
+    foreach ($tables as $table_name) {
+      $status = $this->tableManager->adopt($table_name);
+      if ($status) {
+        drupal_set_message($this->t("Table @table has been adopted.", [
+          '@table' => $table_name
+        ]));
+      }
+    }
+    $form_state->setRedirect('entity.data_table_config.collection');
   }
 
 }
diff --git a/src/TableManager.php b/src/TableManager.php
new file mode 100644
index 0000000..ebbe6ed
--- /dev/null
+++ b/src/TableManager.php
@@ -0,0 +1,107 @@
+<?php
+
+namespace Drupal\data;
+
+use Drupal\data\TableManagerInterface;
+use Drupal\Core\Database\Connection;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Config\ConfigFactory;
+
+
+/**
+ * Class TableManager.
+ *
+ * @package Drupal\data
+ */
+class TableManager implements TableManagerInterface {
+
+  /**
+   * The database connection object.
+   *
+   * @var \Drupal\Core\Database\Connection
+   */
+  protected $connection;
+
+  /**
+   * The entity type manager.
+   *
+   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
+   */
+  protected $entityTypeManager;
+
+  /**
+   * The module handler.
+   *
+   * @var \Drupal\Core\Extension\ModuleHandlerInterface
+   */
+  protected $moduleHandler;
+
+  /**
+   * Config factory.
+   *
+   * @var \Drupal\Core\Config\ConfigFactoryInterface
+   */
+  protected $configFactory;
+
+  /**
+   * Constructs the object.
+   *
+   * @param \Drupal\Core\Database\Connection $connection
+   *   The database connection object.
+   * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
+   *   The entity manager.
+   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
+   *   The module handler.
+   */
+  public function __construct(Connection $connection, EntityTypeManagerInterface $entity_type_manager, ModuleHandlerInterface $module_handler, ConfigFactory $config_factory) {
+    $this->connection = $connection;
+    $this->entityTypeManager = $entity_type_manager;
+    $this->moduleHandler = $module_handler;
+    $this->configFactory = $config_factory;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function adopt($table_name) {
+    if ($this->defined($table_name) || !$this->moduleHandler->moduleExists('schema')) {
+      return FALSE;
+    }
+    $storage = $this->entityTypeManager->getStorage('data_table_config');
+    $config = $this->configFactory->get('schema.settings');
+    $schema = schema_dbobject()->inspect($config->get('schema_database_connection'), $table_name);
+    $fields = [];
+    foreach ($schema[$table_name]['fields'] as $key => $value) {
+      $fields[] = [
+        'name' => $key,
+        'label' => $key,
+        'type' => $value['type'],
+        'size' => $value['size'],
+        'length' => isset($value['length']) ? $value['length'] : FALSE,
+        'unsigned' => isset($value['unsigned']) ? $value['unsigned'] : FALSE,
+        'index' => isset($value['index']) ? $value['index'] : FALSE,
+        'primary' => isset($value['primary']) ? $value['primary'] : FALSE,
+      ];
+    }
+    $table = $storage->create([
+      'id' => $table_name,
+      'title' => data_natural_name($table_name),
+      'table_schema' => array_filter($fields),
+      'meta' => '',
+    ]);
+    //TODO: find a better way than enforceIsNew to avoid data entity class attempting creating the db table.
+    $table->enforceIsNew(FALSE);
+    $table->save();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function defined($table_name) {
+    if ($this->entityTypeManager->getStorage('data_table_config')->load($table_name)) {
+      return TRUE;
+    }
+  }
+
+}
diff --git a/src/TableManagerInterface.php b/src/TableManagerInterface.php
new file mode 100644
index 0000000..c9a650d
--- /dev/null
+++ b/src/TableManagerInterface.php
@@ -0,0 +1,33 @@
+<?php
+
+namespace Drupal\data;
+
+/**
+ * Class TableManagerInterface.
+ *
+ * @package Drupal\data
+ */
+interface TableManagerInterface {
+
+  /**
+   * @param string $table_name
+   *   Table to adopt.
+   *
+   * @return bool
+   *   Result of save operation.
+   */
+  public function adopt($table_name);
+
+  /**
+   * Determine whether a table is defined.
+   *
+   * @param string $table_name
+   *   Table to check.
+   * @return
+   *   TRUE if the table is defined, FALSE otherwise.
+   *   Note: If a table is defined it does not mean that it actually exists in the
+   *   database.
+   */
+  public function defined($table_name);
+
+}
-- 
2.7.4

