Dynamic Web Service using ckWebServicePlugin

To implement Web Service in symfony, ckWebServicePlugin can offer integration of symfony module as web service. The instruction detail can be found at http://www.symfony-project.org/plugins/ckWebServicePlugin/3_0_0?tab=plugin_readme.

But, to make the plugin installation work, you need additional files:

Then follow the instruction to configure the plugin. But, the readme is rather outdated. For example:

<?php

// apps/frontend/modules/math/actions/actions.class.php
class mathActions extends sfActions
{
  /**
   * An action multiplying two numbers.
   *
   * @ws-enable
   * @ws-method SimpleMultiply
   *
   * @param double $a Factor A
   * @param double $b Factor B
   *
   * @return double The result
   */
  public function executeMultiply($request)
  {
    // nothing changed here...
  }
}

But, it should be:

<?php

// apps/frontend/modules/math/actions/actions.class.php
class mathActions extends sfActions
{
  /**
   * An action multiplying two numbers.
   *
   * @WSMethod(name='SimpleMultiply', webservice='MathApi')
   *
   * @param float $a Factor A
   * @param float $b Factor B
   *
   * @return float The result
   */
  public function executeMultiply($request)
  {
    // nothing changed here...
  }
}

Notice the comment doc tag, it should @WSMethod(name='SimpleMultiply', webservice='MathApi') instead @ws-method and @ws-enable is removed. You can view the complete module at [project]/plugins/ckWebServicePlugin/test/fixtures/project/apps/tutorial/modules/math/actions/actions.class.php.

By default, the generated WSDL will be located under SF_WEB_DIR, so the wsdl location is at http://localhost/MathApi.wsdl, and the front controller will be http://localhost/MathApi.php. Notice that the front controller defined in the MathApi.wsdl using static address. So if you move your Web Service to production server, you need to alter the front controller manually.

Now the part to make the wsdl front controller dynamically changed. Generate a module named wsdl:

php symfony generate:module frontend wsdl

And change the content of index action to:

<?php

// apps/frontend/modules/wsdl/actions/actions.class.php
class wsdlActions extends sfActions
{
  /**
   * Executes index action
   *
   * @param sfRequest $request A request object
   */
  public function executeIndex(sfWebRequest $request)
  {
    $this->forward404Unless($service = $request->getParameter('service'));
    $wsdl = sprintf('%s/wsdl/%s.wsdl', sfConfig::get('sf_data_dir'), $service);
    if (!file_exists($wsdl))
    {
      $this->forward404('WSDL "'.$wsdl.'" is not found.');
    }

    // generate the wsdl controller based on current request
    $wsdlController = $request->getUriPrefix().$request->getRelativeUrlRoot().'/'.$service.'.php';

    $dom = new DOMDocument();
    if ($dom->load($wsdl))
    {
      // query the soap:address node to change location
      $xpath = new DOMXPath($dom);
      $nodes = $xpath->query('/wsdl:definitions/wsdl:service/wsdl:port/soap:address');
      foreach ($nodes as $node)
      {
        if ($node->hasAttribute('location'))
        {
          $node->setAttribute('location', $wsdlController);
        }
      }

      // output
      $this->response->setContentType($request->getMimeType('xml'));

      return $this->renderText($dom->saveXML());
    }

    throw new sfException('"'.$wsdl.'" is not a valid xml document.');
  }
}

Add a route to your [project]/apps/frontend/config/routing.yml:

wsdl:
  url:   /:service.wsdl
  param: { module: wsdl, action: index }

Move your wsdl from [project]/web/MathApi.wsdl to [project]/data/wsdl/MathApi.wsdl, and last modify your [project]/frontend/config/app.yml, from:

soap:
  ck_web_service_plugin:
    wsdl:                  %SF_WEB_DIR%/MathApi.wsdl

to:

soap:
  ck_web_service_plugin:
    wsdl:                  %SF_DATA_DIR%/wsdl/MathApi.wsdl

If you want to enabled debugging on wsdl front controller, edit your [project]/web/MathApi.php to:

<?php

require_once(dirname(__FILE__).'/../config/ProjectConfiguration.class.php');

$configuration = ProjectConfiguration::getApplicationConfiguration('frontend', 'soap', true);
sfContext::createInstance($configuration)->dispatch();

3 Comments

  1. Thanks that is very help full form me

  2. Pingback:Web Services and Symfony | SymfonyLab

  3. Thanks for the article!

    I’ve implemented that feature in the development branch:
    http://trac.symfony-project.org/changeset/29916

    I’ve also mentioned this article in the comments of the implementation.

Leave a Reply