search for the right OOP pattern

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • Dormilich
    Recognized Expert Expert
    • Aug 2008
    • 8694

    search for the right OOP pattern

    Hi guys,

    I'm want to write a class for validating xml files, but I'm not sure about the pattern the class shall have.

    what I have so far:
    a class that's doing XSLT transformation:
    Code:
    class XSLTransform
    {
      __construct() // checking if files are loaded from file or string
      load() // loading XML & XSL files/strings
      process() // doing transformation
      checkResult() // well...
    }
    in the load() method I check the XML files for validaty too, but that's taking too long (4 - 10s) so I decided to do the validation only when the files were recently changed. which leaves me with the task of storing the last validation results.

    Now the problem.
    in every call of this class I need the validation file to be checked if I have to do validation or not (basicly if the last successful validation is after the last modified time). I'd like to create a class (or an instance of a class) that holds the complete validation results (better than reading the file each time).

    But which pattern should that class be? I thought of either singleton or registry pattern.
    singleton
    + file reading while instantiation
    – more (complex) code
    registry
    + less code
    + can be deserialized (as a whole)
    – needs external initialization

    what do you think about that? or do you have a better idea than I?

    thanks
  • pbmods
    Recognized Expert Expert
    • Apr 2007
    • 5821

    #2
    Heya, Dormi.

    You'll need to save a timestamp somewhere for each file and compare it with the modification time of that file when you load it.

    My suggestion is to build it directly into the XSLTransform class (consider storing the timestamps in a SQLite database or flat file). If you need this functionality available to other classes, you might try a static XMLLoader or similar class.

    WRT to validation speed, check out DOMDocument->schemaValidate () (http://php.net/domdocument.schemavalidate).

    Comment

    • Dormilich
      Recognized Expert Expert
      • Aug 2008
      • 8694

      #3
      Originally posted by pbmods
      My suggestion is to build it directly into the XSLTransform class (consider storing the timestamps in a SQLite database or flat file)..
      that would require the XSLTransform class to be an abstract or singleton class... (I'll go for a file)

      Originally posted by pbmods
      WRT to validation speed, check out DOMDocument->schemaValidate ().
      is XML Schema validation that much faster? the long validation times originate from a complex DTD (using several parameter entities).

      Comment

      • pbmods
        Recognized Expert Expert
        • Apr 2007
        • 5821

        #4
        Originally posted by Dormilich
        is XML Schema validation that much faster? the long validation times originate from a complex DTD (using several parameter entities).
        No idea. The only reason that I suggested it is because DOMDocument's code is compiled C code, which runs faster than interpreted PHP code. On the other hand, your code might be tailored to your specific application so that it'll jump through fewer hoops. YMMV, really.

        Comment

        • Dormilich
          Recognized Expert Expert
          • Aug 2008
          • 8694

          #5
          Originally posted by pbmods
          The only reason that I suggested it is because DOMDocument's code is compiled C code, which runs faster than interpreted PHP code.
          currently I'm using DOMDocument->validate();
          current DTD

          Comment

          • Dormilich
            Recognized Expert Expert
            • Aug 2008
            • 8694

            #6
            Originally posted by pbmods
            My suggestion is to build it directly into the XSLTransform class
            after some rewriting (and not as many errors as I expected) I got it working. runs like a flash (total page request time ~50 ms).

            for those interested in the code (though comments and improvements are welcome):
            Code:
            class XSLTransform extends Validator
            {
                private static $instance  = NULL;
                private static $inDOM_xml = NULL;
                private static $inDOM_xsl = NULL;
                private $xml_loaded = false;
                private $xsl_loaded = false;
                public  $emptyResult = XSLT_FORCE_RESULT;
            
                private function __construct() {}
                private function __clone() {}
                    
                public static function getInstance($source_file = NULL)
                {
                    if (self::$instance === NULL)
                    {
                        self::$instance  = new self;
                        self::$inDOM_xml = new DOMDocument();
                        self::$inDOM_xsl = new DOMDocument();
                        parent::load($source_file);
                    }
                    return self::$instance;
                }   
                
                public function loadXML($file, $f_isFile = true)
                {
                    $b_load = ($f_isFile) ? self::$inDOM_xml->load(XML_DIR . $file) : self::$inDOM_xml->loadXML($file);
            
                    if (!$b_load)
                    {
                        $emsg = "Die Datei '$file' konnte nicht geladen werden.";
                        throw new ProcException(30, __METHOD__, $emsg);
                    }
            
                    $this->xml_loaded = true;
                    
                    if ($this->requireValidation($file))
                    {
                        if (self::$inDOM_xml->validate())
                        {
                            $this->setTime($file);
                        }
                        else
                        {
                            $emsg = "Die Datei '$file' entspricht nicht der DTD, bzw. es liegt ein DTD Ladefehler vor.";
                            trigger_error($emsg, E_USER_WARNING);
                        }
                    }
                }
                
                public function loadXSL($file, $f_isFile = true)
                {
                    $b_load = ($f_isFile) ? self::$inDOM_xsl->load(XSL_DIR . $file) : self::$inDOM_xsl->loadXML($file);
            
                    if (!$b_load)
                    {
                        $emsg = "Die Datei '$file' konnte nicht geladen werden.";
                        throw new ProcException(30, __METHOD__, $emsg);
                    }
            
                    $this->xsl_loaded = true;
                }
                
                public function Process($param = array())
                {
                    if (!$this->xml_loaded or !$this->xsl_loaded)
                    {
                        return NULL;
                    }
                    
                    $inXSL_proc = new XSLTProcessor();
                    
                    foreach ($param as $key => $value)
                    {
                        $inXSL_proc->setParameter('', $key, $value);
                    }
                     
                    $inXSL_proc->importStyleSheet(self::$inDOM_xsl); 
                    $result = $inXSL_proc->transformToXML(self::$inDOM_xml);
                    
                    $this->xml_loaded = false;
                    $this->xsl_loaded = false;
                    
                    $this->checkResult($result);
                    
                    return $result; 
                }
            
                private function checkResult($data)
                { 
                    if ($data === false)
                    {
                        $emsg = "Fehler bei der XSL Transformation. Fehler bei der Verarbeitung. (z.B. ungültiger XPath)";
                        throw new ProcException(30, __METHOD__, $emsg);
                    }
                    
                    if (empty($data) and !$this->emptyResult)
                    {
                        $emsg = "Fehler bei der XSL Transformation, leeres Ergebnis. Eingaben prüfen!";
                        throw new ProcException(40, __METHOD__, $emsg);
                    }
                }
            }
            Code:
            abstract class Validator
            {
                private $changed   = false;
                private static $validated = array();
                public  static $source    = NULL;
            
                function __destruct()
                {
                    if ($this->changed)
                    {
                        $wddx_string = wddx_serialize_value(self::$validated, "validation timestamps");
                        if ($wddx_string !== false)
                        {
                            $fh = fopen(self::$source, "w") or die("<div>Speichern der neuen Validation (Datei öffnen) gescheitert.</div>");
                            fwrite($fh, $wddx_string) or die("<div>Speichern der neuen Validation (Datei speichern) gescheitert.</div>");
                            fclose($fh);
                        }
                    }
                }
            
                protected static function load($src_file = NULL)
                {
                    self::$source = ($src_file) ? $src_file : "validation.xml";
                    if (file_exists(self::$source))
                    {
                        $inWDDX = new WDDXProcess(__CLASS__);
                        $inWDDX->loadFile(self::$source);
                        self::$validated = $inWDDX->isResultArray(XSLT_EMPTY_RESULT);
                    }
                }
                
                public function setTime($file)
                {
                    self::$validated[$file] = time();
                    $this->changed = true;
                }
                
                public function requireValidation($file, $path = XML_DIR)
                {
                    if (isset(self::$validated[$file]))
                    { 
                        if (file_exists($path . $file))
                        {
                            $vtime = self::$validated[$file];
                            if (filemtime($path . $file) < $vtime)
                            {
                                return false;
                            }
                            return true;
                        }
                        unset(self::$validated[$file]);
                        return NULL;
                    }
                    return true;
                }
            }

            Comment

            Working...