Maarten Balliauw {blog}

ASP.NET, ASP.NET MVC, Windows Azure, PHP, ...

NAVIGATION - SEARCH

OpenXML in Healthcare in PHP

Here's a cool present just before the weekend... 2 days ago, Wouter posted on his blog about an article he co-operated on for MSDN: OpenXML in Healthcare.

Being both a Microsoft and PHP fan (yes, you can curse me, I don't care), I thought of porting (part of) the sample code from his article into PHP. Except for the document signing, as I did not have many time to write this sample code...

The scenario for the article is quite simple: Contoso provides a central medical records database. Whenever a physician has to register a new patient, he downloads a Word 2007 document from the Contoso server, fills it out, and uploads it back. Contoso then strips out the necessary data and saves it back in their systems.

 

This Word 2007 document is crafted around embedded custom XML data, which is displayed and edited using Word 2007. In short: to do the above exercise, you just need to strip out the custom XML and you're done.

Stripping out the custom XML is also quite easy. First, locate the main relationships part in the OpenXML package. Then, search it for the main document part. From there, loop over the relationships to this document part and look for any relationship of the type "http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXml". When that one's found, you just need to parse the referenced document and you're done!

Want to see a demo? Check this out.
Want the sample code? 2007HealthCareSamplePHP.zip (49.76 kb)
 Want the OpenXML background? Read the original article.

Generic arrays in PHP

Assuming everyone knows what generics are, let's get down to business right away. PHP does not support generics or something similar, though it could be very useful in PHP development.  Luckily, using some standard OO-practises, a semi-generic array can easily be created, even in multiple ways! Here's the road to PHP generics. 

The hard way...

One of the roads to PHP generics is some simple inheritance and type hinting. Let's have a look at PHP's ArrayObject. This class has 2 interesting methods, namely offsetSet() and append(). This would mean I can simply create a new class which inherits from ArrayObject, and uses type hinting to restrict some additions:

[code:c#]

// Example class
class Example {
  public $SomeProperty;
}

// Example class generic ArrayObject
class ExampleArrayObject extends ArrayObject {
  public function append(Example $value) {
    parent::append($value);
  }

  public function offsetSet($index, Example $value) {
    parent::offsetSet($index, $value);
  }
}


// Example additions
$myArray = new ExampleArrayObject();
$myArray->append( new Example() ); // Works fine
$myArray->append( "Some data..." ); // Will throw an Exception!

[/code]

The flexible way

There are some disadvantages to the above solution. For a start, you can't create a generic "string" array unless you encapsulate strings in a specific object type. Same goes for other primitive types. Let's counter this problem! Here's the same code as above using a "GenericArrayObject":

[code:c#]

// Example class
class Example {
  public $SomeProperty;
}

// Validation function
function is_class_example($value) {
  return $value instanceof Example;
}

/**
 * Class GenericArrayObject
 *
 * Contains overrides for ArrayObject methods providing generics-like functionality.
 *
 * @author    Maarten Balliauw
 */
class GenericArrayObject extends ArrayObject {
    /**
     * Validation function
     *
     * @var     string
     * @access    private
     */
    private $_validationFunction = '';
       
    /**
     * Set validation function
     *
     * @param     string    $functionName    Validation function
     * @throws     Exception
     * @access    public
     */
    public function setValidationFunction($functionName = 'is_string') {
        if ($this->_validationFunction == '') {
            $this->_validationFunction = $functionName;
            return;
        }
       
        $iterator = $this->getIterator();
        while ($iterator->valid()) {
            if (!call_user_func_array($functionName, array($iterator->current()))) {
                throw new Exception("Switching from " . $this->_validationFunction . " to " . $functionName . " is not possible for all elements.");
            }
           
            $iterator->next();
        }
       
        $this->_validationFunction = $functionName;
    }
   
    /**
     * Append
     *
     * @param     mixed    $value
     * @throws     Exception
     * @access    public
     */
    public function append($value) {
        if ($this->_validationFunction == '') {
            throw new Exception("No validation function has been set.");
        }
       
        if (call_user_func_array($this->_validationFunction, array($value))) {
            parent::append($value);
        } else {
            throw new Exception("Appended type does not meet constraint " . $this->_validationFunction);
        }
    }
   
    /**
     * offsetSet
     *
     * @param     mixed    $index
     * @param     string    $newval
     * @throws     Exception
     * @access    public
     */
    public function offsetSet($index, $newval) {
        if ($this->_validationFunction == '') {
            throw new Exception("No validation function has been set.");
        }
       
        if (call_user_func_array($this->_validationFunction, array($newval))) {
            parent::offsetSet($index, $newval);
        } else {
            throw new Exception("Appended type does not meet constraint " . $this->_validationFunction);
        }
    }
}

// Example additions
$myArray = new GenericArrayObject();
$myArray->setValidationFunction('is_class_example');
$myArray->append( new Example() ); // Works fine
$myArray->append( "Some data..." ); // Will throw an Exception!

[/code]

Using this flexible class, you can simply set a validation function on the GenericArrayObject, which enabels you to use PHP's built-in functions like is_string (string-only ArrayObject), is_int, ... You can even write a small validation function which matches a string against a regular expression and for example create an e-mail address ArrayObject rejecting any string that does not match this regular expression.

Inheritance is evil!

Read this on Bernie's blog:

"All of the pain caused by inheritance can be traced back to the fact that inheritance forces 'is-a' rather than 'has-a' relationships. If class R2Unit extends Droid, then a R2Unit is-a Droid. If class Jedi contains an instance variable of type Lightsabre, then a Jedi has-a Lightsabre.

The difference between is-a and has-a relationships is well known and a fundamental part of OOAD, but what is less well known is that almost every is-a relationship would be better off re-articulated as a has-a relationship."

I suggest you read the full story, as it's very interesting! Bottom line is that you should be careful using OO inheritance, and use the Strategy pattern instead.

Enabling HTTP proxy for .NET webservice client

Have you ever written code that makes external (Soap) webservice calls? Tried that same code on your company network? Most of the time, this does not work very well due to a proxy server sitting in between, requiring authentication etc.

You can start tweaking your Web.config file to set this proxy the right way, or you can override the generated web service class and include the following code snippet:

[code:c#]

using System;
using System.Net;

public class SomethingProxyEnabledService : com.example.service.something {
    protected override System.Net.WebRequest GetWebRequest(Uri uri) {
        WebRequest request = base.GetWebRequest(uri);

        request.Proxy = WebRequest.DefaultWebProxy;
        request.Proxy.Credentials = CredentialCache.DefaultNetworkCredentials;

        return request;
    }
}

[/code]

The only thing left to do is use this "SomethingProxyEnabledService" class instead of the regular "com.example.service.something". There you go, automagical proxy authentication!