php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Request #57814 SCA ability to exclude certain public functions
Submitted: 2007-08-30 17:26 UTC Modified: 2007-09-12 03:54 UTC
From: mattsch at gmail dot com Assigned:
Status: Closed Package: SCA_SDO (PECL)
PHP Version: 5.2.3 OS: Gentoo Linux
Private report: No CVE-ID: None
View Add Comment Developer Edit
Anyone can comment on a bug. Have a simpler test case? Does it work for you on a different platform? Let us know!
Just going to say 'Me too!'? Don't clutter the database with that please !
Your email address:
MUST BE VALID
Solve the problem:
40 + 28 = ?
Subscribe to this entry?

 
 [2007-08-30 17:26 UTC] mattsch at gmail dot com
Description:
------------
I would like to see the ability for SCA to not parse public functions that don't have PHPDocumentor-style annotations.  Currently I'm forced to extend the component class in php just so the public functions I want to use within php are not also available in the wsdl.

Reproduce code:
---------------
<?php
include "SCA/SCA.php";
/**
 * Scaffold implementation for a remote StockQuote Web service.
 *
 * @service
 * @binding.soap
 *
 */
class StockQuote {
	/**
	* Get a stock quote for a given ticker symbol.
	*
	* @param string $ticker The ticker symbol.
	* @return float The stock quote.
	*/
	function getQuote($ticker) {
		return 80.9;
	}
	
	function foo($bar){
		return $bar;
	}
}
?>

Expected result:
----------------
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns2="http://stockquote" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" targetNamespace="http://stockquote">
  <types>
    <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" 
      targetNamespace="http://stockquote"
      elementFormDefault="qualified">
      <xs:element name="getQuote">
        <xs:complexType>
          <xs:sequence>
            <xs:element name="ticker" type="xs:string"/>
          </xs:sequence>
        </xs:complexType>

      </xs:element>
      <xs:element name="getQuoteResponse">
        <xs:complexType>
          <xs:sequence>
            <xs:element name="getQuoteReturn" type="xs:float"/>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
    </xs:schema>

  </types>

  <wsdl:message name="getQuoteRequest">
    <wsdl:part name="getQuoteRequest" element="tns2:getQuote"/>
  </wsdl:message>
  <wsdl:message name="getQuoteResponse">
    <wsdl:part name="return" element="tns2:getQuoteResponse"/>
  </wsdl:message>
  <wsdl:portType name="stockquotePortType">

    <wsdl:operation name="getQuote">
      <wsdl:input message="tns2:getQuoteRequest"/>
      <wsdl:output message="tns2:getQuoteResponse"/>
    </wsdl:operation>
  </wsdl:portType>
  <wsdl:binding name="stockquoteBinding" type="tns2:stockquotePortType">
    <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
    <wsdl:operation name="getQuote">
      <soap:operation soapAction=""/>

      <wsdl:input>
        <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output>
        <soap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>
  <wsdl:service name="stockquoteService">

    <wsdl:port name="stockquotePort" binding="tns2:stockquoteBinding">
      <soap:address location="http://portal.work/stockquote.php"/>
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>

<!-- this line identifies this file as WSDL generated by SCA for PHP. Do not remove -->

Actual result:
--------------
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns2="http://stockquote" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" targetNamespace="http://stockquote">
  <types>
    <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" 
      targetNamespace="http://stockquote"
      elementFormDefault="qualified">
      <xs:element name="getQuote">
        <xs:complexType>
          <xs:sequence>
            <xs:element name="ticker" type="xs:string"/>
          </xs:sequence>
        </xs:complexType>

      </xs:element>
      <xs:element name="getQuoteResponse">
        <xs:complexType>
          <xs:sequence>
            <xs:element name="getQuoteReturn" type="xs:float"/>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
      <xs:element name="foo">

        <xs:complexType>
          <xs:sequence>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
      <xs:element name="fooResponse">
        <xs:complexType>
          <xs:sequence>
          </xs:sequence>

        </xs:complexType>
      </xs:element>
    </xs:schema>
  </types>

  <wsdl:message name="getQuoteRequest">
    <wsdl:part name="getQuoteRequest" element="tns2:getQuote"/>
  </wsdl:message>
  <wsdl:message name="getQuoteResponse">

    <wsdl:part name="return" element="tns2:getQuoteResponse"/>
  </wsdl:message>
  <wsdl:message name="fooRequest">
    <wsdl:part name="fooRequest" element="tns2:foo"/>
  </wsdl:message>
  <wsdl:message name="fooResponse">
    <wsdl:part name="return" element="tns2:fooResponse"/>
  </wsdl:message>
  <wsdl:portType name="stockquotePortType">

    <wsdl:operation name="getQuote">
      <wsdl:input message="tns2:getQuoteRequest"/>
      <wsdl:output message="tns2:getQuoteResponse"/>
    </wsdl:operation>
    <wsdl:operation name="foo">
      <wsdl:input message="tns2:fooRequest"/>
      <wsdl:output message="tns2:fooResponse"/>
    </wsdl:operation>
  </wsdl:portType>

  <wsdl:binding name="stockquoteBinding" type="tns2:stockquotePortType">
    <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
    <wsdl:operation name="getQuote">
      <soap:operation soapAction=""/>
      <wsdl:input>
        <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output>
        <soap:body use="literal"/>

      </wsdl:output>
    </wsdl:operation>
    <wsdl:operation name="foo">
      <soap:operation soapAction=""/>
      <wsdl:input>
        <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output>
        <soap:body use="literal"/>

      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>
  <wsdl:service name="stockquoteService">
    <wsdl:port name="stockquotePort" binding="tns2:stockquoteBinding">
      <soap:address location="http://portal.work/stockquote.php"/>
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>

<!-- this line identifies this file as WSDL generated by SCA for PHP. Do not remove -->

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2007-08-30 17:28 UTC] mattsch at gmail dot com
Changed php version.
 [2007-08-30 18:04 UTC] mattsch at gmail dot com
Disregard the last comment about leaving out PHPDocumentor-style annotations.  In retrospect, that would not be a good idea.  I think a better idea would be to specify a custom tag specifically for SCA.  I was thinking about something like @scaExcludeMethod true/false.  If you don't specify it, then it assumes you don't want to exclude and if you do specify it, you can toggle the display.
 [2007-08-30 19:17 UTC] mattsch at gmail dot com
Apparently you guys already had this in mind, so I finished it:

--- SCA_AnnotationReader.php.orig	2007-08-30 17:50:40.000000000 -0500
+++ SCA_AnnotationReader.php	2007-08-30 17:51:05.000000000 -0500
@@ -222,13 +222,13 @@
                 $methodAnnotations =
                 SCA_AnnotationRules::createEmptyAnnotationArray();
                 $comment = $public_method->getDocComment();
-
+                $isWebMethod = true;
                 /* When the method has a doc comment ....                     */
                 if ( $comment != false ) {
                     $method_reader = new SCA_CommentReader($comment);
-
+                    $isWebMethod = $method_reader->isWebMethod();
                     /* ... and the method a web service method ....           */
-                    if ($method_reader->isWebMethod()) {
+                    if ($isWebMethod) {
                         /* ... decode any method annotations.                 */
                         $methodAnnotations =
                         $method_reader->getMethodAnnotations();
@@ -280,7 +280,8 @@
                 }/* End comment has value                                      */
 
                 /* Save the annotation set indexed by the method name.         */
-                $operations[$public_method->getName()] = $methodAnnotations ;
+                if ($isWebMethod)
+                    $operations[$public_method->getName()] = $methodAnnotations ;
 
             }/* End every method                                               */
 



--- SCA_CommentReader.php.orig	2007-08-30 17:50:55.000000000 -0500
+++ SCA_CommentReader.php	2007-08-30 17:51:10.000000000 -0500
@@ -417,8 +417,8 @@
 
         public function isWebMethod()
         {
-            // currently exposing all methods if the class is a web service
-            // leave this test in place in case we want to change our mind
+            if ($this->_hasAnnotation('webmethod') && ! $this->_getBooleanFollowing('webmethod'))
+                return false;
             return true;
         }
 [2007-08-31 03:46 UTC] gcc@php.net
Thanks for the feedback and suggested enhancement.  The current behavior is by design, making use of existing language visibility construct (public, private, etc) to identify those methods which should be available on the Web service.  I'd imagined using delegation in these kinds of scenarios where the Web service is a front-end for the real implementation (still a bit clunky :-( ).

I do have a concern about adding more annotations for cases which are perhaps not in the 80-20 and where there are alternative approach (albeit not ideal).  We did have the intention to also support annotated interfaces and I wonder whether this would be a suitable alternative (I don't think this is supported today).  So, for example, having the @service on the interface and not the implementation would say that only the public methods defined by that interface should be exposed.  Or perhaps having the @service on an implementation identify the service interface (this is how it is handled in SCA Java).

Mine is just one opinion, and for this kind of feature request, I think it would be good to raise it on the phpsoa google group.  I've put a quick post there pointing to this request (see http://groups.google.co.uk/group/phpsoa/browse_thread/thread/1b11c0e6bc0cf441/#).  I hope you'll be happy to follow/contribute to the discussion there.

Thanks again for the feedback.
 [2007-09-12 03:54 UTC] gcc@php.net
This bug has been fixed in CVS.

In case this was a documentation problem, the fix will show up at the
end of next Sunday (CET) on pecl.php.net.

In case this was a pecl.php.net website problem, the change will show
up on the website in short time.
 
Thank you for the report, and for helping us make PECL better.

The code/unit tests to support this have now been checked into the FULMAR branch.  The service operations made available can now be controlled by specifying an interface in the @service annotation (e.g @service MyServiceInterface). 

Note, because of the different way in which PHP defines standalone classes versus those which extend classes or implement interfaces, the include for SCA.php much come after the service implementation class declaration.  

For example:

<?php

require 'MyPrivateInterface.php';
require 'MyServiceInterface.php';


/**
 * MyService with a nonServiceMethod
 * @service MyServiceInterface
 *
 */
class MyService implements MyServiceInterface, MyPrivateInterface {

    /**
     * A method that I don't want to appear
     *
     */
    public function nonServiceMethod() {}
    
    /**
     * A private method that should not appear
     *
     */
    private function privateMethod() {}
    
    /**
     * My first service method defined in MyServiceInterface
     *
     * @param string $in1
     * @return float
     */
    public function serviceMethod1($in1) {}
    
    /**
     * My second service method defined in MyServiceInterface
     *
     * @param string $in1
     * @param float $in2
     * @return integer
     */
    public function serviceMethod2($in1, $in2) {}

}

include 'SCA/SCA.php';

?>
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Mar 28 08:01:28 2024 UTC