- 2011-09-01: Building an Unfuddle to Drupal Casetracker import module using Migrate
- 2011-08-28: Back from DrupalCon London and its WSCCI code sprint. Wow.
- 2010-12-21: Madame Figaro brand new site by OSInet and others
- 2010-08-16: France.FR is back online with OSInet and Typhon
- 2010-06-15: the new http://www.franceculture.com/, which OSInet helped reach its performance goals, is now online
- 2010-06-13: the OSInet Features Server is live
- 2009-11-29: mongodb_watchdog module created by dereine, ported to D7 by me in about half an hour, and migrated in a larger MongoDB project by damz before the hour ended. Wow...
- 2009-02-03: the new Drupal-based site for the golden jubilee of the french "Ministère de la Culture", which OSInet helped build, is now online
SOAP box: accessing VIES from PHP-GTK
With OSInet having a large part of its business with suppliers and customers within the EU at large, I often find myself having to check the validity of the VAT information for third parties, and the EU VIES database comes in handy.
However,
although I had been discussing remote access
using XML-RPC or SOAP as early at 2004 with the database
administrators, the UI had remained web 1.0-only until quite
recently (apparently march 2007), when an
AXIS
SOAP service went online, just as I had suggested three years
ago. So I figured I really couldn't let the occasion pass, and did a
PHP-GTK client to VIES, which happens to be my first production
SOAP application in PHP-GTK, previous ones having always been
done in Pascal using Delphi or Kylix.
Let's see how this can be done... (code updated 2010-09-21)
UI layout
OK, you have already noticed I'm not much of a designer, so the
UI is rather minimal on eye-candy, but it gets the job done. The
structure is simple: within the main GtkWindow,
a GtkVBox delimits four areas, from top to
bottom:
- a
GtkHBoxfor the input values, containing itself aGtkComboBoxfor the country codes, and aGtkEntryto key in the VAT ID to be tested. - a
GtkButtonto fire the SOAP call - a work area (more about it later)
- a
GtkStatusBarfor miscellaneous information
Within the work area, two types of content can be displayed: either informational messages, to appear on application startup and when the VIES server returns an exception, or actual results from the VIES server, properly structured.
The first type
of content is best served by a simple memo, which
in PHPGTK2 is created as a GtkTextView, while a
tabular layout renders structured results more nicely, especially
when a visual cue like a Red/Green indicator is simple to add,
thanks to the stock image support added in PHP-GTK 2.
So how does one toggled from one content type to the next:
simply enough, using a GtkNotebook with hidden
tabs.
You can check the Glade used for the UI in the download attached to this post.
Installing SOAP
Unlike XML-RPC, which needed Zend Framework to eventually become really convenient to use with PHP-GTK, SOAP is very usable from the basic PHP distribution. The only problem is that, for now, the SOAP extension is not bundled with Gnope, the most popular PHP-GTK distribution.
If your distribution does not have the SOAP extension, this is
simple to fix: just download it from the PHP archives to obtain a version of PHP matching the version of PHP used in your PHP-GTK distribution, copy the
php_soap.dll to <php-gtk dir>/ext,
add a line for the extension to your php.ini, and
you're done.
Using SOAP
Using PHP SOAP with a supplied WSDL schema is even simpler than installing it, and luckily, the EU supplies their WSDL schema online at http://ec.europa.eu/taxation_customs/vies/api/checkVatPort?wsdl.
All it take is three lines of code:
<?php
$vies = new SoapClient($wsdl);
$nii = new checkVat($cc, $vat);
$ret = $vies->checkVat($nii);
?>The first line creates the SOAP client in WSDL mode, which fetches the WSDL schema for the service from the passed-in URL, while the second line builds the object parameter expected by the VIES service, and the third line invokes the remote procedure and returns its result.
This needs some polishing, though: as with any distributed operation, this can fail and cause exceptions, so here is a more refined implementation of the client:
<?php
/**
* Straight from the WSDL schema
*/
class checkVat
{
/**
* @var string
*/
var $countryCode;
/**
* @var string
*/
var $vatNumber;
function __construct($cc, $vat)
{
$this->countryCode = $cc;
$this->vatNumber = $vat;
}
}
/* [...snip...] */
/**
* Invoke the VIES service to check an EU VAT number
*
* @param string $cc Country Code
* @param string $vat VAT number
* @return mixed
*/
function checkVat($cc, $vat)
{
$wsdl = 'http://ec.europa.eu/taxation_customs/vies/api/checkVatPort?wsdl';
$vies = new SoapClient($wsdl);
/*
var_dump($vies->__getFunctions());
var_dump($vies->__getTypes());
*/
$nii = new checkVat($cc, $vat);
try
{
$ret = $vies->checkVat($nii);
}
catch (SoapFault $e)
{
$ret = $e->faultstring;
$regex = '/\{ \'([A-Z_]*)\' \}/';
$n = preg_match($regex, $ret, $matches);
$ret = $matches[1];
$faults = array
(
'INVALID_INPUT' => 'The provided CountryCode is invalid or the VAT number is empty',
'SERVICE_UNAVAILABLE' => 'The SOAP service is unavailable, try again later',
'MS_UNAVAILABLE' => 'The Member State service is unavailable, try again later or with another Member State',
'TIMEOUT' => 'The Member State service could not be reached in time, try again later or with another Member State',
'SERVER_BUSY' => 'The service cannot process your request. Try again later.'
);
$ret = $faults[$ret];
}
return $ret;
}
?>In case you wonder about the constants in the
$faults array, these are documented in the VIES
WSDL schema. The only slightly weird part in all this is the fact
that VIES returns errors as a full line of text about a Java
exception, which needs to be reduced to the constant specified
in the WSDL schema, thanks to the small regexp.
Wrapping it up
All that remains is to wrap the SOAP call in the PHP-GTK UI, and, as usual with Glade UIs, we'll just create a UI class definition, to gather the event callbacks and the basic functions needed for the UI. First, our constructor:
<?php
class UI
{
/**
* @var GladeXML
*/
var $glade ;
function __construct()
{
$this->glade = new GladeXML('vies.glade');
$this->glade->signal_autoconnect_instance($this);
}
?>This just loads the Glade file discussed previously, and connects the callbacks as defined within the Glade file to the class instance. Some basic methods are useful too:
<?php
/**
* Return a widget from the loaded Glade file
*
* @param GtkWidget $name
*/
function get_widget($name)
{
$ret = $this->glade->get_widget($name);
return $ret;
}
function run()
{
$w = $this->get_widget('w');
$w->show_all();
Gtk::main();
}
?>This will allows the application body to be reduced to :
<?php
$ui = new UI();
$ui->run();
?>The only important remaining part is the callback for the UI button invoking the SOAP service:
<?php
function on_btn_clicked()
{
$sb = $this->get_widget('sb');
$cc = $this->get_widget('cb_country');
$cc = $cc->get_active_text();
$cc = substr($cc, 0, 2);
// ...
$vat = $this->get_widget('en_vat');
$vat = $vat->get_text();
// ...
?>Nothing much yet: we fetch widgets from the Glade file, and set or extract their values. Now, if we have a valid country code and something in the VAT field, we can prepare to submit, so we start by switching the UI to the message page, and setting a wait message in the status bar, after what we can start the long-running SOAP call:
<?php
$nb = $this->get_widget('nb');
$nb->set_current_page(0);
$sb->push(0, 'Invoking VIES web service. Please wait.');
yield();
$ret = checkVat($cc, $vat);
$sb->pop(0);
yield();
?>yield() is just a shortcut to the canonical PHP-GTK
code to process events and allow the UI to refresh:
<?php
function yield()
{
while (Gtk::events_pending())
{
Gtk::main_iteration();
}
}
?>At this point, we have a return from SOAP, which can either be an error message, or the object documented in the WSDL schema, so we can just check on the return type, and either set the text of the message in the main area, or set widget values on the structured answer page:
<?php
if (!is_object($ret)) // An error occurred
{
$tv = $this->get_widget('tv');
$text_buffer->set_text($ret);
$tv->set_buffer($text_buffer);
}
else // We got a result
{
print_r($ret);
$val = $this->get_widget('lbCountryCodeVal');
$val->set_text($ret->countryCode);
// ... continue setting widget values
?>A specific case is the GtkImage widget set using
a stock image:
<?php
$val = $this->get_widget('imgValid');
if ($ret->valid)
{
$val->set_from_stock(Gtk::STOCK_YES,
Gtk::ICON_SIZE_LARGE_TOOLBAR);
}
else
{
$val->set_from_stock(Gtk::STOCK_NO,
Gtk::ICON_SIZE_LARGE_TOOLBAR);
}
?>And finally, still some more widgets, not forgetting that in most countries, the national VAT database does not return the name or address bound to a VAT number:
<?php
$val = $this->get_widget('lbNameVal');
$val->set_text(empty($ret->name)
? '(not returned)'
: $ret->name);
$val = $this->get_widget('lbAddressVal');
$val->set_text(empty($ret->address)
? '(not returned)'
: $ret->address);
?>We've been doing this hidden, since the displayed page is still the message page, so now that everything is in order, we can switch to the structured answer page:
<?php
$nb->set_current_page(1);
}
yield();
}
?>And it's over ! You can give it a spin by downloading the full
project. The checkVatPort.xml file is a cached copy
of the WSDL schema to avoid overloading the EU site with requests
while you are testing.
The code is provided under the (Open Source / Free Software) CeCILL 2.0 license.
| Attachment | Size |
|---|---|
| VIES 1.2 (tar.gz) | 187.35 KB |
| VIES 1.0 (tar.gz) | 4.95 KB |





PHP-GTK SOAP
WSDL has been changed
For some unknown reason, the WSDL has been changed to 'http://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl'
Updated VIES client version
Thanks for the heads up about the URL change.
I've taken advantage of the occasion to update the code somehow. The attached version in the article is now more recent.