Использование Typo3 eID для вызова nu soap - PullRequest
0 голосов
/ 29 марта 2020

Я использую следующий код для моего soap звонка.

Если я добавлю wsdl и сделаю свой клиентский вызов, я просто получу ответ без полного soap переноса.

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, неверно.

Ответы [ 2 ]

0 голосов
/ 31 марта 2020

ДА! сейчас это работает. У последнего замечания был пункт: «SOAP Сервер должен быть инициализирован при каждом запросе ». Подумал, что эта инициализация сервера использовалась только для создания wsdl. Другая сложность, с которой я столкнулся, заключалась в том, как вызвать мою функцию. Если функция находится в том же классе, она не получит вызов (возможно, из-за некоторых проблем с автозагрузкой), мне пришлось создать другой класс с функцией, чтобы все заработало. Вот мое целое решение. в ext_localconf. php

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

Мой класс EventsController

<?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']);
}

}

А мой класс Utility

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

U может вызывать ur wsdl с https://domain.tld/index.php?eID=update_order&wsdl Еще раз спасибо, Артур, за помощь в решении этой проблемы. Dziekuje; -)

0 голосов
/ 30 марта 2020

ваш случай здесь имеет гораздо больше смысла, чем на Facebook, но в ваших будущих публикациях о stackoverflow вы должны написать больше справочной информации для всех остальных разработчиков, у которых нет справочной информации, как у меня.

В общем Ты слишком усложняешь вещи. : -)

Во-первых, вы сказали мне на Facebook, что ваш soap сервер как таковой (без интеграции TYPO3 в качестве eID) работает. Это так? Я не могу видеть это из вашего кода :-) Вы обрабатываете некоторый управляющий http параметр «action» и создаете сервер SOAP, только если значение «create». Но для «действия» значения «обновление», нет инициализации сервера? Как это может работать? Вы должны помнить, что сервер SOAP должен быть инициализирован при каждом запросе. Это не демон, который запускается один раз и работает в фоновом режиме.

Нет абсолютно никакой необходимости в таком «управляющем» параметре управления на входной стороне. Вот для чего нужна регистрация SOAP удаленного метода сервера Nu SOAP - метод с характерным именем, который вы явно вызываете на стороне клиента.

Тогда ваш parseResult и parseResponse методы? Вы пытаетесь обработать протокол SOAP вручную? Nu SOAP должен справиться со всем этим для вас. Вам просто нужно зарегистрировать соответствующие типы данных (ComplexType).

Сначала вам нужно получить гораздо больше базовых знаний о самом Nu SOAP.

Вот простой рабочий Пример, который я использовал в очень старом проекте. Я сократил его, чтобы показать вам, как Nu SOAP должен работать.

Сервер определяет один единственный метод "echoStringArray", который принимает один массив в качестве атрибута с именем "inputStringArray" и возвращает его обратно без каких-либо изменений.

Вы можете взять и скопировать вставку без изменений в свой сценарий eID, и у вас будет немедленная базовая интеграция c 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 -клиент. 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, заголовки и тд. Все это заботится самим Nu SOAP.

Вы просто предоставляете массив под ключом inputStringArray в $ client-> call () и получить тот же массив на стороне сервера, что и параметр с именем inputStringArray обработчика метода echoStringArray .

И последнее, но не менее важное: вы можете попробовать что-то более новое, чем nu SOAP, например zend- soap. Кажется, проще, ознакомьтесь с этим коротким учебником https://odan.github.io/2017/11/20/implementing-a-soap-api-with-php-7.html

...