ZendFramework Zend Soap - как научить Autodiscovery понимать простые типы (конкретно - date)?

Фанат

oncle terrible
Команда форума
Трахаюсь тут с мылом.
Есть готовый сервак, я его периодически допиливаю.
До исх пор все получалось, а тут застрял.

Если определяю переменную как строку,
PHP:
<?php
namespace Soap;
class Data_Object_Period
{
    /** @var string */
    public $EndDate;
}
то всё нормально канает, в выходном wsdl получается
Код:
<xsd:element name="EndDate" type="xsd:string" nillable="true"/>
а как только пишу date - тут всё встаёт колом,
Cannot add a complex type date that is not an object or where class could not be found in "DefaultComplexType" strategy.
Вопросы классические - кто виноват и что делать?
 

Фанат

oncle terrible
Команда форума
Правда. Тупо добавил
PHP:
            case 'date':
                return self::XSD_NS . ':date';

            case 'datetime':
                return self::XSD_NS . ':datetime';
Только не в AutoDiscover а в Wsdl.
Нашел поиском эту функцию, а там тупой кейс с типами.

А ты наугад что ли писал? :)
 

флоппик

promotor fidei
Команда форума
Партнер клуба
Я? Это когда?
В каком контексте?
В теме про ларавел, чувак спрашивал, как изучать, нужно ли смотреть из индекса и дальше по инклудам, а ты сказал, мол, фреймворки надо изучать по документации, а не по инклудам ) что-то типа такого ) Не помню дословно.
 

Фанат

oncle terrible
Команда форума
Вот честно - я не знаю, куда и как там наследовать. Этот зендяра висит как дополнение к фуелу.
Я через эти дебри еле пробираюсь, чтобы ничего не сломать и не потерять.
По-хорошему - ты, конечно, прав.
Но вот как это дело реализовать на практике, я не очень понимаю.
 

Вурдалак

Продвинутый новичок

Фанат

oncle terrible
Команда форума
В теме про ларавел, чувак спрашивал, как изучать, нужно ли смотреть из индекса и дальше по инклудам, а ты сказал, мол, фреймворки надо изучать по документации, а не по инклудам ) что-то типа такого ) Не помню дословно.
А. Ну, я имел в виду, что фреймфорки, по сути, предназначены для изучения по документации.
Ведть в этом весь смысл инкапсюляции - тебе дают готовый метод, про который ты должен узнать из документации.
А что там у него внутри - это знать не обязательно.

Сам-то я тоже, не любитель читать документацию, и больше по контрол-клику.
Но основная идея, имхо - это скрыть внутреннюю реализацию и предоставить интерфейс. То есть ,получить программный продукт.
Не получается, короче сформулировать, голова уже ватная. потом попробую )
 

флоппик

promotor fidei
Команда форума
Партнер клуба
Я, как и флоппик, с ZF никогда не работал, но есть погуглить «zend soap custom type», то первая ссылка: http://www.king-foo.be/2011/09/using-complex-types-with-zend_soap/
Я за вариант Фаната голосую после прочтения статьи)
Ну и это не совсем тот случай - date и datetime - не кастомные типы для соапа, а вполне себе базовые, просто не реализованные (скорее всего, ноги опять из обратной совместимости, когда не было нормальных типов/обьектов для даты)
 

Фанат

oncle terrible
Команда форума
Я, как и флоппик, с ZF никогда не работал, но есть погуглить «zend soap custom type», то первая ссылка: http://www.king-foo.be/2011/09/using-complex-types-with-zend_soap/
нене, кастом - это другое. Этих у меня 20 штук уже налеплено. Эта ерунда спецом в wsdl-ке описывается (вообще, я через эти типы как раз и понял смысл мыла - сначала адски матерился!).
Но сам этот кастом строится из базовых типов, которых в спецификации мыла - тыща, а у зенда - три с половиной штуки.
и вот мне нужен был именно базовый
 

Фанат

oncle terrible
Команда форума
Там вообще остроумная система, с этим автодискавери.
Пишешь в папочку data описание класса, типа такого
PHP:
class Data_Object_Translate
{
    /** @var string */
    public $prefix;

    /** @var string */
    public $name = '';

    /** @var string */
    public $description;
}
И в WSDL-ке (XML с описанием всех запросов) появляется автоматом такая структура:
Код:
<xsd:all>
<xsd:element name="prefix" type="xsd:string" nillable="true"/>
<xsd:element name="name" type="xsd:string"/>
<xsd:element name="description" type="xsd:string" nillable="true"/>
</xsd:all>
Тип берет из пхпдока, нулябельность - из инициализации переменной.

Таким же макаром описываются и методы - то есть ты тупо пишешь пхп код, а зендяра по нему тебе генерит XML.
 

Фанат

oncle terrible
Команда форума
В теме про ларавел, чувак спрашивал, как изучать, нужно ли смотреть из индекса и дальше по инклудам, а ты сказал, мол, фреймворки надо изучать по документации, а не по инклудам ) что-то типа такого ) Не помню дословно.
Короче, чо я имел в виду.

Речь не про то, каким образом получать информацию о программе. Это может быть как чтение документации, так и реверс-инжиниринг, ради бога.
Речь о том, что у нас получается некий программный продукт, отдельный от пхп. Совсем отдельный. Знание пхп никак не поможет тебе начать им сразу пользоваться - ты должен сначала изучить практически новый язык. Как ты его будешь изучать - повторюсь - дело десятое.

Вот в фуйле например у моделей есть статик методы динамические, тудыть их в качель, типа User::find_by_name($name);
И вот иди догадайся, что унутре оно разбивается на find_by и name, а потом применяется женерик квере с вхере. Ну, я догадался, да. Когда имя метода попалось так же неграмотно прописанное, как и имя поля в бд. Но вообще всю эту статическую магию ненавижу.

И таких вещей в каждом фреймворке - масса. И вот чтобы не писать по незнанию руками в модели какое-нибудь find_by_article() и нужна документация. То есть, чтобы заранее знать, что есть такая фича.

О опять же, как всегда, учебник и референс мануал - это РАЗНЫЕ вещи.
Посмотреть - как вот моя текущая задача - как делается какая-то одна отдельная операция - это одно.
Изучать, как чувак собирался - это другое. Совсем другое. Чтобы научиться пользоваться, понять идеологию - эффективнее будет всё-таки читать доку или смотреть примеры.
А какой вариант пацанский, а какой для лохов - это я не различаю, и не считаю эту разницу вообще важной.
 

Absinthe

жожо
В теме про ларавел, чувак спрашивал, как изучать, нужно ли смотреть из индекса и дальше по инклудам, а ты сказал, мол, фреймворки надо изучать по документации, а не по инклудам ) что-то типа такого ) Не помню дословно.
Это была неправильная точка зрения.
Фреймворки сначала надо изучать по документации, а потом - через отладчик.
Если изучать только по документации, то изучить хорошо не выйдет.
 

WMix

герр M:)ller
Партнер клуба
если вернуться назад к вопросу, то мне нравится решение фаната, нахрен эти closed principle, я поковырял гуглов, но так и не решил красиво эту задачку на класс из пространства "\". сама нехватка toString у обьекта типа datetime, и невозможность его засунуть, делает решение слишком сложным и не рентабельным. но да, нужно отдавать себе отчет, что за этим придется следить.

другой вопрос, а нужно ли datetime передавать, может плюнуть на все и отдать обычный стринг?
 

Denis.tlt

Новичок
Переопределяем метод getType

PHP:
<?php
namespace App\Model\Zend\Soap;

class Wsdl extends \Zend\Soap\Wsdl {

    /**
     * Returns an XSD Type for the given PHP type
     *
     * @param  string $type PHP Type to get the XSD type for
     * @return string
     */
    public function getType($type) {
        if (strtolower($this->trimNamespace($type)) === 'datetime') {
            return self::XSD_NS . ':dateTime';
        }

        return parent::getType($type);
    }

    /**
     * @param string $type
     * @return string
     */
    private function trimNamespace($type) {
        $nameParts = explode('\\', $type);
        return array_pop($nameParts);
    }

}
Подменяем класс WSDL (setWsdlClass)

PHP:
<?php
namespace App\Model;

use App\Model\Zend\Soap\Wsdl;
use Zend\Soap\AutoDiscover;
use Zend\Soap\Wsdl\ComplexTypeStrategy\ArrayOfTypeComplex;

class WsdlGenerator {

    /** @var string  */
    private $path;

    /** @var string  */
    private $uri;

    /**
     * WsdlGenerator constructor.
     * @param string $path
     * @param string $uri
     */
    public function __construct(string $path, string $uri) {
        $this->path = $path;
        $this->uri = $uri;
    }

    /**
     * @param string $class
     * @return \Zend\Soap\Wsdl
     */
    public function generate($class): \Zend\Soap\Wsdl {
        $autoDiscover = new AutoDiscover(new ArrayOfTypeComplex());
        $autoDiscover
            ->setClass($class)
            ->setUri($this->uri)
            ->setServiceName('TestTask')
            ->setBindingStyle(['style' => 'document'])
            ->setOperationBodyStyle(['use' => 'literal'])
            ->setWsdlClass(Wsdl::class);

        return $autoDiscover->generate();
    }

}
Последний штрих - указываем способ преобразования даты в xml и обратно:

PHP:
<?php

$server = new Server('http://soap-task-server' . $this->generateUrl('app_wsdl'), [
    'typemap' => [
        [
            'type_name' => 'dateTime',
            'type_ns' => 'http://www.w3.org/2001/XMLSchema',
            'from_xml' => 'App\Model\Soap\DateTimeMapper::fromXML',
            'to_xml' => 'App\Model\Soap\DateTimeMapper::toXML'
        ],
    ],
    'options' => [
        'cache_wsdl' => WSDL_CACHE_DISK
    ]
]);
PHP:
<?php
namespace App\Model\Soap;

class DateTimeMapper {

    /**
     * @param \DateTime $date
     * @return string
     */
    public static function toXml(\DateTime $date): string {
        return '<dateTime>' . $date->format('c') . '</dateTime>';
    }

    /**
     * @param string $date
     * @return \DateTime|null
     */
    public static function fromXml(string $date): ?\DateTime {
        try {
            return new \DateTime(strip_tags($date));
        } catch (\Exception $e) {
            return null;
        }

    }

}
 
Последнее редактирование:
Сверху