Bladeren bron

Improved rendering and context: new messages system, tidy output processing

- code reordered
- new Drupal 7 functions brought in: check_plain, drupal_attributes
- messages array in context, with automatic display on destructor if applicable
- output tidying with tidy
Frederic G. MARAND 12 jaren geleden
bovenliggende
commit
eebafabeef
2 gewijzigde bestanden met toevoegingen van 346 en 132 verwijderingen
  1. 22 0
      memcache_ui.css
  2. 324 132
      memcache_ui.php

+ 22 - 0
memcache_ui.css

@@ -199,3 +199,25 @@ input {
   margin-right:1em;
   padding:0.1em 0.5em 0.1em 0.5em;
   }
+
+/**
+ * New version styles
+ */
+ 
+div.messages { 
+  border: thin solid;
+  box-shadow: 5px 5px 5px silver;
+  margin: 0.5em 1em;
+  padding: 0.5em 1em;
+}
+
+div.messages ul {
+  margin-bottom: 0;
+  margin-top: 0;
+  padding-left: 1em;
+}
+
+div.messages li {
+  list-style: square;
+  margin-left: 1em;
+}

+ 324 - 132
memcache_ui.php

@@ -1,49 +1,28 @@
 <?php
-class GraphicsContext {
-  protected $palette = array();
-}
 
 /**
- * A wrapper for XML elements.
+ * Wrapper around php tidy class.
+ *
+ * @param string $html
+ *
+ * @return void
  */
-class Element {
-  public $name = NULL;
-  public $attributes = array();
-  public $value = NULL;
-  public $new_line; // Add a new line after element
-
-  public function __construct($name, $attr = NULL, $value = NULL) {
-    $this->name = $name;
-    $this->attributes = $attr;
-    $this->value = $value;
-  }
-
-  public function __toString() {
-    $ret = '<'. $this->name;
-    if (!empty($this->attributes)) {
-      $ret .= ' ' . implode(' ', $this->attributes);
-    }
-    if (empty($this->value)) {
-      $ret .= ' />';
-    }
-    else {
-      $ret .= '>';
-      if ($this->value instanceof Element) {
-        $ret .= (string) $this->value; // force __toString()
-      }
-      elseif (is_array($this->value)) {
-        $ret .= implode('', $this->value);
-      }
-      else {
-        $ret .= $this->value;
-      }
-      $ret .= "</$this->name>";
-    }
-    return $ret;
-  }
+function applyTidy (&$html) {
+  $config = array(
+      'indent'          => TRUE,
+      'output-xhtml'    => TRUE,
+      'sort-attributes' => 'alpha',
+      'wrap'            => 80,
+  );
+  $tidy = new tidy();
+  $tidy->parseString($html, $config, 'utf8');
+  $tidy->cleanRepair();
+  $html = (string) $tidy;
 }
 
 class Context {
+  protected $logLevelClasses = NULL;
+
   /**
    * Directory in which the current script is located.
    *
@@ -55,6 +34,29 @@ class Context {
    */
   protected $dirname;
 
+  /**
+   * Graphics context
+   *
+   * @var GraphicsContext
+   */
+  protected $gc = NULL;
+
+  /**
+   * Logging level, as per RFC5424
+   *
+   * @link http://php.net/network.constants.php
+   *
+   * @var integer
+   */
+  protected $logLevel = NULL;
+
+  /**
+   * Messages for display.
+   *
+   * @var array
+   */
+  protected $messages = array();
+
   /**
    * Requested path: <$PHP_SELF>?q=a/b/c
    *
@@ -63,11 +65,31 @@ class Context {
   protected $path = NULL;
 
   /**
-   * Graphics context
+   * Tidy the output ?
    *
-   * @var GraphicsContext
+   * @var boolean
    */
-  protected $gc = NULL;
+  protected $tidy = NULL;
+
+  /**
+   * User information: logged or not ?
+   *
+   * @var boolean
+   */
+  protected $user = FALSE;
+
+  function __destruct() {
+    if (!empty($this->messages)) {
+      $ret = (string) new Element('pre', array('class' => array('messages')),
+        implode("\n", $this->getMessage(TRUE)));
+      echo $ret;
+    }
+  }
+
+  function __toString() {
+    $ret = '<pre>' . print_r($this, TRUE) . '</pre>';
+    return $ret;
+  }
 
   public function getDirname() {
     if (!isset($this->dirname)) {
@@ -77,6 +99,64 @@ class Context {
     return $this->dirname;
   }
 
+  public function getLogLevel() {
+    if (!isset($this->logLevel)) {
+      $usLogLevel = NULL;
+      foreach ($_GET as $key => $value) {
+        if (strtolower($key) === 'loglevel') {
+          $usLogLevel = (int) $value;
+          break;
+        }
+      }
+      if (!isset($usLogLevel)) {
+        $usLogLevel = LOG_NOTICE;
+      }
+
+      if ($usLogLevel < LOG_EMERG) {
+        $this->logLevel = LOG_EMERG;
+      }
+      elseif ($usLogLevel > LOG_DEBUG) {
+        $this->logLevel = LOG_DEBUG;
+      }
+      else {
+        $this->logLevel = $usLogLevel; // We now know it to be safe
+      }
+    }
+
+    return $this->logLevel;
+  }
+
+  public function getLogLevelClass($logLevel) {
+    if (!isset($this->logLevelClasses)) {
+      $this->logLevelClasses = array(
+        LOG_EMERG   => 'error',
+        LOG_ALERT   => 'error',
+        LOG_CRIT    => 'error',
+        LOG_ERR     => 'error',
+        LOG_WARNING => 'warning',
+        LOG_NOTICE  => 'warning',
+        LOG_INFO    => 'status',
+        LOG_DEBUG   => 'status',
+      );
+    }
+    if ($logLevel < LOG_EMERG) {
+      $logLevel = LOG_EMERG;
+    }
+    elseif ($logLevel > LOG_DEBUG) {
+      $logLevel = LOG_DEBUG;
+    }
+    return $this->logLevelClasses[$logLevel];
+  }
+
+  public function getMessage($clear = FALSE) {
+    $ret = $this->messages;
+    if ($clear) {
+      $this->messages = array();
+    }
+
+    return $ret;
+  }
+
   /**
    * Return the requested path.
    *
@@ -90,67 +170,161 @@ class Context {
     return $this->path;
   }
 
+  public function getTidy() {
+    if (!isset($this->tidy)) {
+      $this->tidy = TRUE;
+      foreach ($_GET as $key => $value) {
+        if (strtolower($key) === 'tidy') {
+          $this->tidy = !!$value;
+          break;
+        }
+      }
+    }
+
+    return $this->tidy;
+  }
+
   /**
-   * User information: logged or not ?
+   * Add a message to the messages list if it is above the current logging level.
    *
-   * @var boolean
+   * @param string $text
+   * @param integer $logLevel
+   *
+   * @return void
    */
-  protected $user = FALSE;
+  public function setMessage($text, $logLevel = LOG_NOTICE) {
+    if ($logLevel <= $this->getlogLevel()) {
+      if (is_array($text) || (is_object($text) && !method_exists($text, '__toString'))) {
+        $this->messages[] = array(print_r($text, TRUE), $logLevel);
+      }
+      else {
+        $this->messages[] = array((string) $text, $logLevel);
+      }
+    }
+  }
+}
 
+/**
+ * A wrapper for XML elements.
+ */
+class Element {
+  public $attributes = array();
+  public $name = NULL;
+  public $new_line; // Add a new line after element
+  public $value = NULL;
 
-  function __construct() {
-    $this->getPath();
+  public function __construct($name, $attr = NULL, $value = NULL) {
+    $this->name = $name;
+    $this->attributes = $attr;
+    $this->value = $value;
   }
 
-  function __toString() {
-    $ret = '<pre>' . print_r($this, TRUE) . '</pre>';
+  /**
+   * @link drupal7/includes/common.inc#check_plain()
+   */
+  public static function check_plain($text) {
+    return htmlspecialchars($text, ENT_QUOTES, 'UTF-8');
+  }
+
+  /**
+   * @link drupal7/includes/common.inc#drupal_attributes()
+   */
+  public static function getSerializedAttributes(array $attributes = array()) {
+    foreach ($attributes as $attribute => &$data) {
+      $data = implode(' ', (array) $data);
+      $data = $attribute . '="' . self::check_plain($data) . '"';
+    }
+
+  return $attributes ? ' ' . implode(' ', $attributes) : '';
+  }
+
+  public function __toString() {
+    $ret = '<'. $this->name;
+    if (!empty($this->attributes) && is_array($this->attributes)) {
+      $ret .= self::getSerializedAttributes($this->attributes);
+    }
+    if (empty($this->value)) {
+      $ret .= ' />';
+    }
+    else {
+      $ret .= '>';
+      if ($this->value instanceof Element) {
+        $ret .= (string) $this->value; // force __toString()
+      }
+      elseif (is_array($this->value)) {
+        $ret .= implode('', $this->value);
+      }
+      else {
+        $ret .= $this->value;
+      }
+      $ret .= "</$this->name>";
+    }
     return $ret;
   }
 }
 
+class GraphicsContext {
+  protected $palette = array();
+}
+
 class Page extends Element {
+
+  /**
+   * The HTML body element of the page.
+   *
+   * @var array
+   */
+  protected $body;
+
   /**
    * @var Context
    */
   protected $context;
 
   /**
+   * Ths HTML head element of the page.
+   *
    * @var array
    */
-  protected $styles;
-
+  protected $head;
   /**
    * @var array
    */
   protected $finalized = array();
 
-  public function getHeader($name) {
-  }
-
-  public function setHeader($name, $value) {
-
-  }
-
-  public function getHead() {
-    $this->finalizeHead();
-    $head = new Element('head', NULL, $this->head);
-    $ret = (string) $head;
-    return $ret;
-  }
-
-  public function setHead($item) {
-
-  }
+  /**
+   * @var array
+   */
+  protected $styles;
 
-  public function getBody() {
-    $this->finalizeBody();
-    $body = new Element('body', NULL, $this->body);
-    $ret = (string) $body;
-    return $ret;
+  /**
+   * Page constructor.
+   *
+   * @param Context $context
+   * @param array $item
+   *   A router info array.
+   *
+   * @see Router::getInfo()
+   */
+  public function __construct(Context $context, array $item) {
+    parent::__construct('html');
+    $this->context = $context;
   }
 
-  public function setBody($fragment) {
-    $this->body[] = $fragment;
+  public function finalizeBody() {
+    if (isset($this->finalized['body'])) {
+      throw new Exception('Attempt to finalize already finalized body');
+    }
+    if ($message = $this->context->getMessage(TRUE)) {
+      $items = array();
+      foreach ($message as $row) {
+        $items[] = new Element('li', array(
+          'class' => array($this->context->getLogLevelClass($row[1])),
+        ), $row[0]);
+      }
+      $this->setBody(new Element('div', array('class' => array('messages')), $items));
+    }
+    $this->finalized['body'] = TRUE;
   }
 
   public function finalizeHead() {
@@ -167,11 +341,21 @@ class Page extends Element {
     $this->finalized['head'] = TRUE;
   }
 
-  public function finalizeBody() {
-    if (isset($this->finalized['body'])) {
-      throw new Exception('Attempt to finalize already finalized body');
-    }
-    $this->finalized['body'] = TRUE;
+  public function getBody() {
+    $this->finalizeBody();
+    $body = new Element('body', NULL, $this->body);
+    $ret = (string) $body;
+    return $ret;
+  }
+
+  public function getHead() {
+    $this->finalizeHead();
+    $head = new Element('head', NULL, $this->head);
+    $ret = (string) $head;
+    return $ret;
+  }
+
+  public function getHeader($name) {
   }
 
   public function render() {
@@ -179,22 +363,34 @@ class Page extends Element {
     return (string) $html;
   }
 
-  /**
-   * Page constructor.
-   *
-   * @param Context $context
-   * @param array $item
-   *   A router info array.
-   *
-   * @see Router::getInfo()
-   */
-  public function __construct(Context $context, array $item) {
-    parent::__construct('html');
-    $this->context = $context;
+  public function setBody($fragment) {
+    $this->body[] = $fragment;
+  }
+
+  public function setHead($item) {
+    $this->head[] = $item;
+  }
+
+  public function setHeader($name, $value) {
+
+  }
+
+}
+
+class Page_Main extends Page {
+  function finalizeBody() {
+    $hello = new Element('p', NULL, 'Hello world');
+    $this->setBody($hello);
+    parent::finalizeBody();
   }
+
 }
 
 class Router {
+  function __construct(Context $context) {
+    $this->context = $context;
+  }
+
   function getInfo() {
     $ret = array(
       '^server/(\w+)/flush/(\w+)$' => array(
@@ -266,25 +462,27 @@ class Router {
   function getRoute() {
     $found = FALSE;
     $path = $this->context->getPath();
-    // echo "<pre>Path: [". $path . "]</p>";
     $matches = array();
+    $infoDefaults = array(
+      'page arguments' => array(),
+    );
     foreach ($this->getInfo() as $regex => $info) {
       $regex = "@$regex@";
       $count = preg_match($regex, $path, $matches);
-      // echo "<pre>$regex: $count";
-      // if ($count) print_r($matches);
-      // echo "</pre>";
       if ($count) {
         $found = TRUE;
         break;
       }
     }
     if ($found) {
-      // echo "Found at $regex<pre>";
-      // print_r($info);
-      $regexes = array_fill(0, count($info['page arguments']), $regex);
-      $paths = array_fill(0, count($info['page arguments']), $path);
-      $info['page arguments'] = preg_replace($regexes, $info['page arguments'], $paths);
+      $this->context->setMessage("Found at $regex", LOG_DEBUG);
+      $this->context->setMessage("Info: ". print_r($info, TRUE), LOG_DEBUG);
+      $info = array_merge($infoDefaults, $info);
+      if (!empty($info['page arguments'])) {
+        $regexes = array_fill(0, count($info['page arguments']), $regex);
+        $paths = array_fill(0, count($info['page arguments']), $path);
+        $info['page arguments'] = preg_replace($regexes, $info['page arguments'], $paths);
+      }
     }
     else {
       $info = NULL;
@@ -292,39 +490,33 @@ class Router {
 
     return $info;
   }
-
-  function __construct(Context $context) {
-    $this->context = $context;
-  }
-}
-
-class Page_Main extends Page {
-  function finalizeBody() {
-    $hello = new Element('p', NULL, 'Hello world');
-    $this->setBody($hello);
-    parent::finalizeBody();
-  }
-
 }
 
 function main() {
-  $context = new Context();
-  // echo "<p>Dirname: [". $context->getDirname() . "]</p>";
-  // echo "<p>Path: [". $context->getPath() . "]</p><pre>";
-
-  $router = new Router($context);
-  $item = $router->getRoute();
-  $page = new $item['page class']($context, $item);
-  // echo '<pre>'; var_dump($page);
-  echo $page->render();
+  try {
+    ob_start();
+    $context = new Context();
+    $context->setMessage("Dirname: [". $context->getDirname() . "]", LOG_DEBUG);
+    $context->setMessage("Path: [". $context->getPath() . "]", LOG_DEBUG);
+
+    $router = new Router($context);
+    $item = $router->getRoute();
+    $page = new $item['page class']($context, $item);
+    // echo '<pre>'; var_dump($page);
+    echo $page->render();
+
+    $html = ob_get_clean();
+    if ($context->getTidy()) {
+      applyTidy($html);
+    }
+    echo $html;
+  }
+  catch (Exception $e) {
+    echo '<pre>';
+    echo $e->getMessage() . PHP_EOL;
+    echo $e->getTraceAsString();
+    echo "</pre>";
+  }
 }
 
-try {
-  main();
-}
-catch (Exception $e) {
-  echo '<pre>';
-  echo $e->getMessage() . PHP_EOL;
-  echo $e->getTraceAsString();
-  echo "</pre>";
-}
+main();