【问题标题】:Using Typo3 eID for nusoap call使用 Typo3 eID 进行 nusoap 呼叫
【发布时间】:2020-03-29 19:45:48
【问题描述】:

我在我的肥皂电话中使用以下代码。

如果我添加 wsdl 并拨打我的客户电话,我只会得到没有整个肥皂包装的响应。

declare(strict_types=1);
namespace Vendor\DocBasics\Controller;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;

use TYPO3\CMS\Extbase\Object\ObjectManager;
use TYPO3\CMS\Core\Localization\LanguageService;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use Vendor\DocBasics\Domain\Repository\EventsRepository;
use Vendor\CartExtended\Domain\Repository\Order\ItemRepository;

require_once(PATH_site . 'typo3conf/ext/doc_basics/Classes/Libs/nusoap/nusoap.php');

class EventsController
{
protected $action = '';
protected $order;
protected $Vbeln = '';
protected $Zaehl = '';
protected $objectManager;

/**
 * @var array
 */
protected $responseArray = [
    'hasErrors' => false,
    'message' => 'Nothing to declare'
];

/**
 * @param ServerRequestInterface $request
 * @param ResponseInterface $response
 * @return ResponseInterface
 */
public function processRequest(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
    $this->initializeData(file_get_contents('php://input')); //xml datas from soap call

    switch (isset($request->getQueryParams()['action']) ? (string)$request->getQueryParams()['action'] : '') {
        case 'create':
            $this->createAction();
            break;
        case 'update':
            $this->updateAction();
            break;
        default:
            $this->updateAction(); //call it as default, so i can call it as endpoint without action parameter
    }
    $this->prepareResponse($response,$request->getQueryParams()['action']);
    return $response;
}

/**
 * action create
 *
 * @return void
 */
public function createAction()
{

    $server = new \soap_server();
    $server->configureWSDL("updateorderservice", "https://domain.tld/updateorderservice", "https://domain.tld/index.php?eID=update_order");
    $server->register(
        "update",
        array("Vbeln" => 'xsd:string', "Zaehl" => 'xsd:integer'),
        array("return" => 'xsd:string'),
        "https://domain.tld/updateorderservice",
        "update",
        "rpc",
        "encoded",
        "Update a given order"
    );

    $this->responseArray['message']= $server->service(file_get_contents('php://input'));

}

public function updateAction() 
{
    $this->objectManager = GeneralUtility::makeInstance(ObjectManager::class);
    $this->itemRepository = $this->objectManager->get(ItemRepository::class);

    $order=$this->itemRepository->findOrderByOrder($this->Vbeln);

    if($order){
        $order->setCancelDate($this->Veindat);
        $this->itemRepository->update($order);
        $this->persistenceManager->persistAll();
        $msg= '<MESSAGE><TYPE>S</TYPE><MSGTXT>Auftrag '.$this->Vbeln.' aktualisiert!</MSGTXT></MESSAGE>';
    }
    else $msg= '<MESSAGE><TYPE>E</TYPE><MSGTXT>Auftrag '.$this->Vbeln.' konnte nicht aktualisiert!</MSGTXT></MESSAGE>';

    $this->responseArray['message'] = $msg; //receive the message but don't know how to wrap it
}

/**
 * @param ResponseInterface $response
 * @param String $action
 * @return void
 */
protected function prepareResponse(ResponseInterface &$response, $action)
{
    if($action=='create'){
        $response = $response->withHeader('Content-Type', 'text/html; charset=utf-8');
        $response->getBody()->write($this->responseArray['message']);
    }
    else{
        $response = $response->withHeader('Content-Type', 'text/xml; charset=utf-8'); 
        $response->getBody()->write($this->responseArray['message']);
    }
}

/**
 * @param  $request
 * @return void
 */
protected function initializeData($request)
{
    $resp= $this->parseResult($request);
    if($resp->Vbeln[0]) $this->Vbeln  = (string)($resp->Vbeln[0]);
    if($resp->Zaehl[0]) $this->Zaehl  = intval($resp->Zaehl[0]);
}

public function parseResult($result){
    $result = str_ireplace(['soapenv:','soap:','upd:'], '', $result);
    $result = simplexml_load_string($result);
    $notification = $result->Body->Update;
    return $notification;
}
 }

我的响应只是我写的小 xml 作为对 updateAction() 的返回。我的回复应该包含在等等之间 可能是我遗漏了什么,或者我使用 eID 概念的方式是错误的。

【问题讨论】:

    标签: typo3-9.x nusoap


    【解决方案1】:

    您的案例在这里比在 facebook 上更有意义,但是在您以后在 stackoverflow 上的帖子中,您应该为所有其他像我一样没有背景信息的开发人员写更多的背景信息。

    一般来说:你把事情复杂化了。 :-)

    首先,您在 facebook 上告诉我,您的肥皂服务器本身(没有 TYPO3 集成作为 eID)可以正常工作。是这样吗?我从您的代码中看不到这一点:-) 只有当值为“create”时,您才处理一些控制 http 参数“action”并创建 SOAP 服务器。 但是对于“action”值“update”,有没有服务器初始化?这怎么能行? 您必须记住,必须在每个请求上初始化 SOAP 服务器。 它不是一个只启动一次就在后台运行的守护进程。

    在输入端绝对不需要这样的“动作”控制参数。这就是 NuSOAP 服务器的“SOAP 远程方法”注册的用途 - 具有可分辨名称的方法,您可以在客户端显式调用它。

    那么你的 parseResultparseResponse 方法呢?您是否尝试手动处理 SOAP 协议? NuSOAP 应该为您处理所有这些。 您只需注册适当的数据类型 (ComplexType)。

    您需要首先获得更多关于 NuSOAP 本身的背景知识。

    这是我在一个非常古老的项目中使用的一个简单的工作示例。我对其进行了简化以向您展示 NuSOAP 应该如何工作。

    服务器定义了一个单独的方法“echoStringArray”,它将一个数组作为名为“inputStringArray”的属性,并在没有任何修改的情况下将其回显。

    您无需修改​​即可将粘贴复制到您的 eID 脚本中,因此您将立即获得基本的 TYPO3 集成。 然后一一添加其他的东西,比如数据库层等等。 尽量不要先使用类,而是使用与我的示例相同的程序方法。

    所以这里是服务器定义soap-server.php

    <?php
    
    // Pull in the NuSOAP code
    require_once('./nusoap-0.9.5/lib/nusoap.php');
    
    function logRequest($userAgent, $methodName, $request, $response, $result) {
        $fp = fopen("./soap.log","a+");
        fputs($fp,"$userAgent\n$methodName\n$request\n$response\n$result\n=======================================\n");
        fclose($fp);
    }
    
    $log = true;
    
    // Create the server instance
    $SOAP_server = new soap_server;
    $SOAP_server->configureWSDL(
        'Test Service',
        'http://my-soap-server.local/xsd'
    );
    
    // Set schema target namespace
    $SOAP_server->wsdl->schemaTargetNamespace = 'http://my-soap-server/xsd';
    
    // Define SOAP-Types which we will need. In this case a simple array with strings
    $SOAP_server->wsdl->addComplexType(
        'ArrayOfstring',
        'complexType',
        'array',
        '',
        'SOAP-ENC:Array',
        array(),
        array(array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'string[]')),
        'xsd:string'
    );
    
    // Define SOAP endpoints (remote methods)
    
    $SOAP_server->register(
        'echoStringArray', // this is the name of the remote method and the handler identifier below at the same time
        array('inputStringArray'=>'tns:ArrayOfstring'),
        array('return'=>'tns:ArrayOfstring'),
        'http://soapinterop.org/'
    );
    
    // Define SOAP method handlers
    
    // This is the handler for the registered echoStringArray SOAP method. It just receives an array with strings and echoes it back unmodified
    function echoStringArray($inputStringArray){
        $outputData = $inputStringArray;
        return $outputData;
    }
    
    // Now let the SOAP service work on the request
    $SOAP_server->service(file_get_contents("php://input"));
    
    if(isset($log) and $log == true){
        logRequest($SOAP_server->headers['User-Agent'],$SOAP_server->methodname,$SOAP_server->request,$SOAP_server->response,$SOAP_server->result);
    }
    

    这里是合适的客户端soap-client.php

    <?php
    require_once('./nusoap-0.9.5/lib/nusoap.php');
    
    // This is your Web service server WSDL URL address
    $wsdl = "http://my-soap-server.local/soap-server.php?wsdl";
    
    // Create client object
    $client = new nusoap_client($wsdl, 'wsdl');
    $err = $client->getError();
    if ($err) {
        // Display the error
        echo '<h2>Constructor error</h2>' . $err;
        // At this point, you know the call that follows will fail
        exit();
    }
    
    // Call the hello method
    $result1 = $client->call('echoStringArray', ['inputStringArray' => ['Hello', 'World', '!']]);
    
    print_r($result1);
    

    如您所见,消息正文、XML、标头等绝对没有自定义处理。这一切都由 NuSOAP 自己负责。

    您只需在 $client->call() 中的键 inputStringArray 下提供一个数组,并在服务器端获取与名为 inputStringArray 的参数相同的数组方法处理程序的 echoStringArray

    最后但并非最不重要的一点是,您可以尝试比 nuSOAP 更新的东西,例如zend-soap。好像更简单,看看这个简短的教程https://odan.github.io/2017/11/20/implementing-a-soap-api-with-php-7.html

    【讨论】:

    • 以你的例子来说,非常感谢 Artur。我有另一个使用相应包装的 xml 的示例。在那个例子中,一切都是程序性的,它就像一个魅力。当我尝试使用 eID 和 Typo3 类时,事情变得复杂了。我必须使用一个类,因为脚本方式已被标记为已弃用。我不知道如何将它与类正确集成
    • "您必须记住,必须在每个请求上初始化 SOAP 服务器。" 我认为这是我遗漏的一点。我将编辑并重试
    【解决方案2】:

    是的!现在它可以工作了。你的最后一句话是:“SOAP 服务器必须在每个请求上初始化”。认为此服务器初始化仅用于创建 wsdl。我遇到的另一个困难是如何调用我的函数。如果该函数在同一个类中,它将不会被调用(可能是由于一些自动加载问题),我不得不使用该函数创建另一个类以使事情正常工作。 这是我的整个解决方案。 在 ext_localconf.php 中

    $GLOBALS['TYPO3_CONF_VARS']['FE']['eID_include']['update_order'] = Vendor\DocBasics\Controller\EventsController::class . '::processRequest';
    

    我的班级事件控制器

    <?php
    
    declare(strict_types=1);
    namespace Vendor\DocBasics\Controller;
    
    use Psr\Http\Message\ResponseInterface;
    use Psr\Http\Message\ServerRequestInterface;
    use Psr\Http\Server\MiddlewareInterface;
    use Psr\Http\Server\RequestHandlerInterface;
    
    use TYPO3\CMS\Extbase\Object\ObjectManager;
    use TYPO3\CMS\Core\Localization\LanguageService;
    use TYPO3\CMS\Core\Utility\GeneralUtility;
    
    require_once(PATH_site . 'typo3conf/ext/doc_basics/Classes/Libs/nusoap/nusoap.php');
    require_once(PATH_site . 'typo3conf/ext/doc_basics/Classes/Libs/Utility.php');
    
    class EventsController
    {
    
    protected $objectManager;
    
    /**
    * @var array
    */
    protected $responseArray = [
    'hasErrors' => false,
    'message' => 'Nothing to declare'
    ];
    
    /**
     * @param ServerRequestInterface $request
     * @param ResponseInterface $response
     * @return ResponseInterface
     */
    public function processRequest(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
    {
    
    $server = new \soap_server();
        $server->soap_defencoding='utf-8';
        $server->configureWSDL("updateorderservice", "https://domain.tld/updateorderservice", "https://domain.tld/index.php?eID=update_order");
        $server->register(
            "Utility.updateOrder",
            array("Vbeln" => 'xsd:string', "Zaehl" => 'xsd:integer'),
            array("return" => 'xsd:string'),
            "https://domain.tld/updateorderservice",
            "update",
            "rpc",
            "encoded",
            "Update a given order"
        );
    
    $this->prepareResponse($response);
    return $response;
    }
    
    
     /**
    * @param ResponseInterface $response
    * @param String $action
    * @return void
    */
    protected function prepareResponse(ResponseInterface &$response)
    {
        $response = $response->withHeader('Content-Type', 'text/xml; charset=utf-8'); 
        $response->getBody()->write($this->responseArray['message']);
    }
    
    }
    

    还有我的类实用程序

    class Utility
    {
    public function updateOrder($Vbeln,$Zaehl) 
    {
    //do ur stuff
     return "Order ".$Vbeln." done";
    }
    }
    

    你可以用https://domain.tld/index.php?eID=update_order&wsdl调用你的wsdl 再次感谢 Artur 帮助我解决了这个问题。 Dziekuje ;-)

    【讨论】:

    • 您好,如果我的建议对您有帮助,请接受我的回答。谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-03-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多