forena-8.x-1.x-dev/src/FrxPlugin/Driver/DriverBase.php

src/FrxPlugin/Driver/DriverBase.php
<?php
// $Id$
/**
 * @file
 * Class that defines default methods for access control in an DriverBase
 *
 */
namespace Drupal\forena\FrxPlugin\Driver;
use Behat\Mink\Exception\Exception;
use Drupal\forena\AppService;
use Drupal\forena\File\DataFileSystem;
use Drupal\forena\FrxAPI;
use \SimpleXMLElement;
use Symfony\Component\Yaml\Parser;

abstract class DriverBase implements DriverInterface {
  use FrxAPI;
  // Dependency injection for drupal code.
  public $name;
  public $conf;
  public $block_path;
  public $comment_prefix;
  public $comment_suffix;
  public $block_ext;
  public $block_extensions;
  public $types;
  public $block_name;
  public $fileSvc;
  protected $te;
  public $debug = FALSE;

  public function __construct($name, $conf, DataFileSystem $fileSystem) {
    $this->conf = $conf;
    $this->fileSvc = $fileSystem;
    $this->comment_prefix = '--';
    $this->block_ext = 'sql';
    $this->block_extensions = array('inc', 'sql', 'xml');
    $this->name = $name;
    $this->debug = @$conf['debug'];
  }

  /**
   * Implements the basic default security check of calling
   * an access method.
   *
   * @param string $arg
   * @return bool
   *   True indicates allowed access. 
   */
  public function access($arg) {
    $obj_access = TRUE;
    $f = @$this->conf['access callback'];
    if ($arg) {
      if ($f && is_callable($f)) {
        $obj_access =  $f($arg);
      }
      elseif (isset($this->conf['access block'])) {
        $block = @$this->conf['access block'];
        $path='';
        if (isset($this->conf['access path'])) $path = $this->conf['access path'];
        $obj_access =  $this->dataManager()->blockAccess($block, $path, $arg);
      }
    }
    return $obj_access;
  }

  protected function loadBlockFromFile($block_name) {
    $full_name = $this->name . '/' . $block_name;
    $php_class = $block_name;
    if ($this->fileSvc->exists($block_name . '.sql')) {
      $contents = $this->fileSvc->contents($block_name . '.sql');
      $block = $this->parseSQLFile($contents);
      $block['type'] = 'sql';
    }
    elseif ($this->fileSvc->exists($block_name . '.xml')) {
      $contents = $this->fileSvc->contents($block_name . '.xml');
      $block = $this->parseXMLFile($contents);
      $block['type'] = 'xml';
    }
    elseif ($this->fileSvc->exists($block_name . '.php')) {
      $php_file = $this->fileSvc->path($php_class . '.php');
      include_once $php_file;

      if (class_exists($php_class)) {
        $o = new $php_class();
        $block['type'] = 'php';
        $block['access'] = @$o->access;
        $block['object'] = $o;
        if (method_exists($o, 'tokens' )) {
          $block['tokens'] = $o->tokens();
        }
        elseif (isset($o->tokens)) {
          $block['tokens'] = $o->tokens;
        }
        else{
          $block['tokens'] = array();
        }
      }
    }
    else {
      return array();
    }
    $block['locked']=1;
    return $block;
  }


  /**
   * Load blcok data from filesystem
   * @param $block_name
   * @return array 
   *   Block definition. 
   */
  function loadBlock($block_name, $include=FALSE) {
    if ($include) $this->block_name = $block_name;
    $block = $this->loadBlockFromFile($block_name);
    return $block;
  }


  /**
   * Load tokens from block source
   */
  public function tokens($source) {
    $tokens = array();
    // If we have a regular expression token parser, then get the tokens out of the block.
    if ($this->te) {
      $tokens = @$this->te->tokens($source);
      $tokens = array_diff($tokens, array('current_user'));
      //check tokens in the where clause
    }

    return $tokens;
  }

  /**
   * Return data based on block definition.
   *
   * @param array $block
   *   Block definition.
   * @param bool|FALSE $raw_mode
   *   True to reutrn raw record/states or data structures
   * @return string
   */
  public function data(Array $block, $raw_mode=FALSE) {
    $xml = '';
    $right = @$block['access'];
    if ($block && $this->access($right)) {
      if ($raw_mode) $block['options']['return_type'] = 'raw';
      switch ($block['type'])  {
        case 'sql':
          $xml = $this->sqlData($block['source'], @$block['options']);
          break;
        case 'xml':
          $xml = $this->xmlData($block['source']);
          break;
        case 'php':
          $data = $this->dataManager()->dataSvc->currentContextArray();
          $xml = $this->phpData($block['object'], $data );
          break;
      }
    }
    return $xml;
  }

  /**
   * @param $search
   * @param $data_blocks
   * @TODO: Determine whether we still need this.
   */
  public function listDBBlocks($search, &$data_blocks) {
    $search = '%' . $search . '%';
    $sql = 'SELECT * from {forena_data_blocks} WHERE repository=:repos
      AND block_name like :search ';
    $rs = db_query($sql, array(':repos' => $this->name, ':search' => $search ));
    foreach ($rs as $block) {
      $data_blocks[] = $block->block_name;
    }
  }


  /**
   * Find all the blocks matching a provided search string
   *
   * @param string $search 
   *   partial block names to search for
   * @param array $block_list
   *   List of blocks to build 
   * @param string $subdir
   *   Subdirectory being examined.  Used primarily for recursion.
   * @TODO: MOve toDat Manageer
   */
  public function listDataBlocks($search, &$block_list, $subdir='') {
    $count=0;
    // First find files that match the search string
    $path = $this->fileSvc->includes[0] . '/';
    if ($subdir) $path .= $subdir . '/';
    $block_path = $path . '*' . $search . '*';
    // Find sql files
    // @TODO: Refactor to use file service to list files
    $d = glob($block_path);
    if ($d) foreach ($d as $file_name) {
      // Split off the extention
      $p = strripos($file_name, '.');
      if ($p!==FALSE) {
        $ext = substr($file_name, $p+1);
        $block_name = substr($file_name, 0, $p);
      }
      else {
        $ext = '';
        $block_name = $file_name;
      }
      switch ($ext) {
        case 'inc':
          require_once $file_name;
          $class = str_replace($path, '', $block_name);
          $methods = get_class_methods($class);
          if ($methods) foreach ($methods as $method) {
            if ($method != 'tokens') {
              $block_list[] = $class . '.' . $method;
            }
          }

          break;
        default:
          if (array_search($ext, $this->block_extensions)!==FALSE) {
            $block_list[] = str_replace($apth . '/', '', $block_name);

          }
      }
    }
    $count++;
    // Find directories
    $d = glob($path . '*');
    if ($d) foreach ($d as $dir_name) {
      if (is_dir($dir_name)) {
        $dir_name = str_replace($path . '/', '', $dir_name);
        $this->listDataBlocks($search, $block_list, $dir_name);
      }
    }
    // Date
    if (!$subdir && \Drupal::moduleHandler()->moduleExists('forena_query'))  {
      $this->listDBBlocks($search, $block_list);
    }
  }


  /**
   * Parse XML File contents into contents.
   * @param $contents
   * @return array
   */
  public function parseXMLFile($contents) {
    $comment = $this->comment_prefix;
    $trim = '->';
    $lines = explode("\n", $contents);
    $cnt = count($lines);
    $access = '';
    $i=0;
    $block = '';
    $data = '';
    while ($i<$cnt) {
      $l = trim($lines[$i], "\r");
      @list($d, $c) = explode($comment, $l, 2);
      if ($trim) $c = trim($c, $trim);
      if  ($c) {
        list($a, $o) = explode('=', $c, 2);
        $a = trim($a);
        if ($a && $o) {
          switch ($a) {
            case 'ACCESS':
              $access = trim($o);
              break;
            default:
          }

        }

      }
      if (strpos($l, $comment)!==0) {
        $data .= "$l\n";
      }
      $i++;
    }
    return array('access' => $access, 'source' => $data, 'tokens' => $this->tokens($data));
  }


  public function getSQLInclude($block_name) {
    //@TODO: allow relative block includes
    $block = $this->loadBlock($block_name, TRUE);
    if ($block && $block['type'] == 'sql') {
      return $block;
    }
    else {
      $this->app()->error("Include $block_name.sql not found");
      return NULL; 
    }
  }


  /**
   * Break the contents of a sql file down to its source.
   * @param $contents
   * @return array
   */
  public function parseSQLFile($contents) {
    $comment = $this->comment_prefix;
    $trim = $this->comment_suffix;
    $lines = explode("\n", $contents);
    $cnt = count($lines);
    $access = '';
    $i=0;
    $data = '';
    $file = '';
    $skip = FALSE;
    $in_info = FALSE;
    $found_case = FALSE;
    $info_text = '';
    $tokens = array();
    $options = array();
    $switch = '';
    while ($i<$cnt) {
      $l = trim($lines[$i], "\r");
      @list($d, $c) = explode($comment, $l, 2);
      if ($trim) $c = trim($c, $trim);
      if  ($c) {
        $c = trim($c);
        @list($a, $o) = explode('=', $c, 2);
        $a = trim($a);
        if (($a && $o) || $c == 'END' || $c == 'ELSE' || $c == 'INFO') {
          if ($c != 'INFO' ) {
            $in_info = false;
          }
          switch ($a) {
            case 'ACCESS':
              $access = trim($o);
              break;
            case 'SWITCH':
              $switch = trim($o);
              $found_case = FALSE;
              break;
            case 'CASE':
              $match = $this->te->replace($switch, TRUE) == $this->te->replace($o);
              if ($match) $found_case = TRUE;
              $skip = !$match;
              break;
            case 'IF':
              $skip = !$this->te->test(trim($o));
              break;
            case 'END':
              $skip = FALSE;
              $switch = '';
              break;
            case 'ELSE':
              $skip = $switch ? $found_case : !$skip;
              break;
            case 'INFO':
              $in_info = TRUE;
              break;
            case 'INCLUDE':
              if (!$skip) {
                $inc_block = $this->getSQLInclude(trim($o));
                if ($inc_block) {
                  $data .= $inc_block['source'];
                  $tokens = array_merge($tokens, $inc_block['tokens']);
                }
              }
              break;
          }

        }
        if ($a != 'ACCESS') $file .= "$l\n";

      }
      else {

        $file .= "$l\n";
      }
      if ($in_info) {
        if (strpos($l, $comment)!==0 && $l) $info_text .= "$l\n";
      } elseif (!$skip) {
        if (strpos($l, $comment)!==0 && $l) {
          $data .= "$l\n";
        }
      }

      $i++;
    }
    $tokens = array_merge($tokens, $this->tokens($contents));
    if ($info_text) {
      $parser = new Parser();
      try  {
        $options = $parser->parse($info_text);
      }
      catch (Exception $e) {
        $options = [];
      }
    }

    $block = array( 'source' => $data, 'file' => trim($file, " \n"),
      'tokens' => $tokens, 'options' => $options, 'access' => $access);
    return $block;
  }

  /**
   * Implement static XML functioin
   * @param string $xmlData 
   *   XML Source data from block load
   * @return SimpleXMLElement 
   *  XML node  
   */
  public function xmlData($xmlData) {
    $xml ='';
    if (trim($xmlData)) {
      try {
        $xml = new SimpleXMLElement($xmlData);
      } catch (\Exception $e) {
        $this->app()->error("Error processing xml\n", $e->getMessage() . "\n" . $xmlData);
      }
    }
    return $xml;
  }

  public function phpData($o, $parameters) {
    $data = NULL;

    if (is_object($o) && is_callable(array($o, 'data'))) {
      $data = $o->data($parameters);
    }
    return $data;
  }

  /**
   * Build the SQL clause based on builder data.
   * @param  $data
   * @return string 
   *   Where clause for SQL. 
   */
  public function buildFilterSQL($data) {
    $clause = '';
    $op = $data['op'];
    $i=0;
    if ($data['filter']) foreach ($data['filter'] as $cond) {
      $i++;
      $conj = ($i==1) ? '' : $op . ' ';
      if (isset($cond['filter'])) {
        $clause .= $conj . ' (' . $this->buildFilterSQL($cond) . " )\n";
      }
      else {

        switch ($cond['op']) {
          case 'IS NULL':
          case 'IS NOT NULL':
            $expr = $cond['field'] . ' ' . $cond['op'];
            break;
          default:
            $expr = $cond['field'] . ' ' . $cond['op'] . ' ' . $this->format($cond['value'], $cond['field'], array());
        }
        $clause .= ' ' . $conj . $expr;
      }
    }
    return $clause;
  }

  /**
   * Perform generic type conversion based on attributes.
   * @param  string $key 
   *   The token key for parameter replacement.
   * @param  string $value 
   *   The value of the parameter
   * @return mixed 
   *   Value of the parameter.
   */
  public function parmConvert($key, $value) {
    if (isset($this->types[$key]) && $this->types[$key]) {
      if ($value === NULL || $value ==='') {
        $value = NULL;
      }
      else {
        switch (strtolower($this->types[$key])) {
          case 'date':
            $time = @new \DateTime($value);
            if ($time) {
              $value   = date_format($time, 'Y-m-d H:i:s');
            }
            else {
              $value = NULL;
            }
            break;
          case 'unixtime':
            $time = @new \DateTime($value);
            if ($time) {
              $value   = $time->getTimestamp();
            }
            else {
              $value = NULL;
            }
            break;
          case 'numeric':
          case 'float':
            $value = (float)$value;
            break;
          case 'int':
          case 'integer':
            $value = (int)$value;
            break;
          case 'array':
            $value = (array)$value;
            break;
        }
      }
    }
    return $value;
  }

  /**
   * Method to return an array of tables that start with the string
   * indicated in $str
   * @param string $str 
   *   Partial table Name to search.
   * @return array
   *   Array of tables to search. :
   */
  public function searchTables($str) {
    return array();
  }

  public function searchTableColumns($table, $str) {
    return array();
  }

  public function searchTablesSQL() {

    switch ($this->db_type) {
      CASE 'mysql':
        $sql = "SHOW TABLES LIKE :str";
        break;
      CASE 'postgres':
      CASE 'postgresql':
      CASE 'pgsql':
        $sql = "SELECT tablename from (
            SELECT schemaname, tablename FROM pg_catalog.pg_tables
            UNION SELECT schemaname, viewname from pg_catalog.pg_views) v
            where schemaname NOT IN ('pg_catalog', 'information_schema') and tablename like :str
            order by 1";
        break;
      CASE 'oracle':
      CASE 'oci':
        $sql = "SELECT object_name FROM all_objects where object_type in ('TABLE','VIEW')
          AND owner not in ('SYS') AND object_name LIKE :str";
        break;
      CASE 'mssql':
        $sql = "SELECT table_name FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE'
             and table_name like :str";
        break;
      CASE 'sqlite':
        $sql = 'SELECT name FROM sqlite_master WHERE name like :str';
        break;
      default:
        $this->app()->error($this->app()->t('Unknown database type: %s', array('%s' => $this->db_type)),'error');
    }
    return $sql;
  }

  public function searchTableColumnsSQL() {

    switch ($this->db_type) {
      CASE 'mysql':
        $sql = "select column_name from information_schema.COLUMNS where
             table_schema = :database
             AND table_name = :table AND column_name like :str";
        break;
      CASE 'postgres':
      CASE 'postgresql':
      CASE 'pgsql':
        $sql = "SELECT column_name from
            information_schema.columns
            WHERE
              table_catalog = :database
              AND table_name = :table
              AND column_name like :str
            order by 1";
        break;
      CASE 'oracle':
      CASE 'oci':
        $sql = "SELECT column_name FROM all_tab_columns where
          table_name = :table_name
          AND column_name LIKE :str";
        break;
      CASE 'mssql':
        $sql = "SELECT * FROM INFORMATION_SCHEMA.COLUMNS
            WHERE TABLE_NAME = :table and column_name like :str";
        break;
      CASE 'sqlite':
        $sql = 'PRAGMA table_info(:table)';
        break;
      default:
        $this->app()->error($this->app()->t('Unknown database type: %s', array('%s' => $this->db_type)),'error');
    }
    return $sql;
  }
}


Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc