Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The generated class does not correspond to reality #496

Closed
h4kuna opened this issue Jan 15, 2024 · 8 comments
Closed

The generated class does not correspond to reality #496

h4kuna opened this issue Jan 15, 2024 · 8 comments

Comments

@h4kuna
Copy link
Contributor

h4kuna commented Jan 15, 2024

Bug Report

Q A
BC Break no
Version 3.1.1

Summary

Hello, I use WSDL. I try to call method getImmobili. Where is getImmobiliResponse->immobili->immobile described. The gerated class looks like:

<?php

namespace App\ChannelManager\ImmobiNet\Soap\Agenzia\Type;

class Immobile
{
    private ?string $id;

    private ?int $idAgenzia;

    public function getId(): ?string
    {
        return $this->id;
    }

    public function withId(?string $id): static
    {
        $new = clone $this;
        $new->id = $id;

        return $new;
    }

    public function getIdAgenzia(): ?int
    {
        return $this->idAgenzia;
    }

    public function withIdAgenzia(?int $idAgenzia): static
    {
        $new = clone $this;
        $new->idAgenzia = $idAgenzia;

        return $new;
    }
}

And returned object looks like
Snímek obrazovky z 2024-01-15 10-01-42

The result is, I can't access to properties. The previous version 2.4.2 was generate all methods and has bug with property name #477.

Generated class with version 2.4.2

<?php

namespace App\ChannelManager\ImmobiNet\Soap\Agenzia\Type;

class Immobile
{
    /**
     * @var \App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\Categoria
     */
    private $categoria;

    /**
     * @var \App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\Citta
     */
    private $citta;

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

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

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

    /**
     * @var \App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\GeoCoordinates
     */
    private $coords;

    /**
     * @var \App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\ArrayOfDescrizione
     */
    private $descrizione;

    /**
     * @var \App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\ArrayOfAllegato
     */
    private $allegati;

    /**
     * @var \App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\ImmobileAbitabile
     */
    private $composizione;

    /**
     * @var \App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\ImmobileAppartamento
     */
    private $appartamento;

    /**
     * @var \App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\ImmobileSuperficie
     */
    private $superficie;

    /**
     * @var \App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\ImmobileTerreno
     */
    private $terreno;

    /**
     * @var \App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\ImmobileCasa
     */
    private $casa;

    /**
     * @var \App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\ImmobileVilla
     */
    private $villa;

    /**
     * @var \App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\ImmobileCapannone
     */
    private $capannone;

    /**
     * @var \App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\ImmobileAce
     */
    private $ace;

    /**
     * @var \App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\ArrayOfAttributo
     */
    private $attributi;

    /**
     * @var \App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\TipoCucina
     */
    private $cucina;

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

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

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

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

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

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

    /**
     * @var \App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\ImmobileTuristico
     */
    private $immobileTuristico;

    /**
     * @var \App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\ArrayOfDistanzaPoi
     */
    private $distanze;

    /**
     * @var \App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\CodiceIdentificativo
     */
    private $codiceIdentificativo;

    /**
     * @var \App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\ArrayOfInformazioniExtra
     */
    private $informazioniExtra;

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

    /**
     * @var int
     */
    private $idAgenzia;

    /**
     * @return \App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\Categoria
     */
    public function getCategoria()
    {
        return $this->categoria;
    }

    /**
     * @param \App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\Categoria $categoria
     *
     * @return Immobile
     */
    public function withCategoria($categoria)
    {
        $new = clone $this;
        $new->categoria = $categoria;

        return $new;
    }

    /**
     * @return \App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\Citta
     */
    public function getCitta()
    {
        return $this->citta;
    }

    /**
     * @param \App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\Citta $citta
     *
     * @return Immobile
     */
    public function withCitta($citta)
    {
        $new = clone $this;
        $new->citta = $citta;

        return $new;
    }

    /**
     * @return string
     */
    public function getIndirizzo()
    {
        return $this->indirizzo;
    }

    /**
     * @param string $indirizzo
     *
     * @return Immobile
     */
    public function withIndirizzo($indirizzo)
    {
        $new = clone $this;
        $new->indirizzo = $indirizzo;

        return $new;
    }

    /**
     * @return string
     */
    public function getNumero()
    {
        return $this->numero;
    }

    /**
     * @param string $numero
     *
     * @return Immobile
     */
    public function withNumero($numero)
    {
        $new = clone $this;
        $new->numero = $numero;

        return $new;
    }

    /**
     * @return string
     */
    public function getZona()
    {
        return $this->zona;
    }

    /**
     * @param string $zona
     *
     * @return Immobile
     */
    public function withZona($zona)
    {
        $new = clone $this;
        $new->zona = $zona;

        return $new;
    }

    /**
     * @return \App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\GeoCoordinates
     */
    public function getCoords()
    {
        return $this->coords;
    }

    /**
     * @param \App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\GeoCoordinates $coords
     *
     * @return Immobile
     */
    public function withCoords($coords)
    {
        $new = clone $this;
        $new->coords = $coords;

        return $new;
    }

    /**
     * @return \App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\ArrayOfDescrizione
     */
    public function getDescrizione()
    {
        return $this->descrizione;
    }

    /**
     * @param \App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\ArrayOfDescrizione $descrizione
     *
     * @return Immobile
     */
    public function withDescrizione($descrizione)
    {
        $new = clone $this;
        $new->descrizione = $descrizione;

        return $new;
    }

    /**
     * @return \App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\ArrayOfAllegato
     */
    public function getAllegati()
    {
        return $this->allegati;
    }

    /**
     * @param \App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\ArrayOfAllegato $allegati
     *
     * @return Immobile
     */
    public function withAllegati($allegati)
    {
        $new = clone $this;
        $new->allegati = $allegati;

        return $new;
    }

    /**
     * @return \App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\ImmobileAbitabile
     */
    public function getComposizione()
    {
        return $this->composizione;
    }

    /**
     * @param \App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\ImmobileAbitabile $composizione
     *
     * @return Immobile
     */
    public function withComposizione($composizione)
    {
        $new = clone $this;
        $new->composizione = $composizione;

        return $new;
    }

    /**
     * @return \App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\ImmobileAppartamento
     */
    public function getAppartamento()
    {
        return $this->appartamento;
    }

    /**
     * @param \App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\ImmobileAppartamento $appartamento
     *
     * @return Immobile
     */
    public function withAppartamento($appartamento)
    {
        $new = clone $this;
        $new->appartamento = $appartamento;

        return $new;
    }

    /**
     * @return \App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\ImmobileSuperficie
     */
    public function getSuperficie()
    {
        return $this->superficie;
    }

    /**
     * @param \App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\ImmobileSuperficie $superficie
     *
     * @return Immobile
     */
    public function withSuperficie($superficie)
    {
        $new = clone $this;
        $new->superficie = $superficie;

        return $new;
    }

    /**
     * @return \App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\ImmobileTerreno
     */
    public function getTerreno()
    {
        return $this->terreno;
    }

    /**
     * @param \App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\ImmobileTerreno $terreno
     *
     * @return Immobile
     */
    public function withTerreno($terreno)
    {
        $new = clone $this;
        $new->terreno = $terreno;

        return $new;
    }

    /**
     * @return \App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\ImmobileCasa
     */
    public function getCasa()
    {
        return $this->casa;
    }

    /**
     * @param \App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\ImmobileCasa $casa
     *
     * @return Immobile
     */
    public function withCasa($casa)
    {
        $new = clone $this;
        $new->casa = $casa;

        return $new;
    }

    /**
     * @return \App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\ImmobileVilla
     */
    public function getVilla()
    {
        return $this->villa;
    }

    /**
     * @param \App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\ImmobileVilla $villa
     *
     * @return Immobile
     */
    public function withVilla($villa)
    {
        $new = clone $this;
        $new->villa = $villa;

        return $new;
    }

    /**
     * @return \App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\ImmobileCapannone
     */
    public function getCapannone()
    {
        return $this->capannone;
    }

    /**
     * @param \App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\ImmobileCapannone $capannone
     *
     * @return Immobile
     */
    public function withCapannone($capannone)
    {
        $new = clone $this;
        $new->capannone = $capannone;

        return $new;
    }

    /**
     * @return \App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\ImmobileAce
     */
    public function getAce()
    {
        return $this->ace;
    }

    /**
     * @param \App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\ImmobileAce $ace
     *
     * @return Immobile
     */
    public function withAce($ace)
    {
        $new = clone $this;
        $new->ace = $ace;

        return $new;
    }

    /**
     * @return \App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\ArrayOfAttributo
     */
    public function getAttributi()
    {
        return $this->attributi;
    }

    /**
     * @param \App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\ArrayOfAttributo $attributi
     *
     * @return Immobile
     */
    public function withAttributi($attributi)
    {
        $new = clone $this;
        $new->attributi = $attributi;

        return $new;
    }

    /**
     * @return \App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\TipoCucina
     */
    public function getCucina()
    {
        return $this->cucina;
    }

    /**
     * @param \App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\TipoCucina $cucina
     *
     * @return Immobile
     */
    public function withCucina($cucina)
    {
        $new = clone $this;
        $new->cucina = $cucina;

        return $new;
    }

    /**
     * @return string
     */
    public function getGiardino()
    {
        return $this->giardino;
    }

    /**
     * @param string $giardino
     *
     * @return Immobile
     */
    public function withGiardino($giardino)
    {
        $new = clone $this;
        $new->giardino = $giardino;

        return $new;
    }

    /**
     * @return string
     */
    public function getParcheggio()
    {
        return $this->parcheggio;
    }

    /**
     * @param string $parcheggio
     *
     * @return Immobile
     */
    public function withParcheggio($parcheggio)
    {
        $new = clone $this;
        $new->parcheggio = $parcheggio;

        return $new;
    }

    /**
     * @return string
     */
    public function getRiscaldamento()
    {
        return $this->riscaldamento;
    }

    /**
     * @param string $riscaldamento
     *
     * @return Immobile
     */
    public function withRiscaldamento($riscaldamento)
    {
        $new = clone $this;
        $new->riscaldamento = $riscaldamento;

        return $new;
    }

    /**
     * @return string
     */
    public function getBoxAuto()
    {
        return $this->boxAuto;
    }

    /**
     * @param string $boxAuto
     *
     * @return Immobile
     */
    public function withBoxAuto($boxAuto)
    {
        $new = clone $this;
        $new->boxAuto = $boxAuto;

        return $new;
    }

    /**
     * @return string
     */
    public function getPostoAuto()
    {
        return $this->postoAuto;
    }

    /**
     * @param string $postoAuto
     *
     * @return Immobile
     */
    public function withPostoAuto($postoAuto)
    {
        $new = clone $this;
        $new->postoAuto = $postoAuto;

        return $new;
    }

    /**
     * @return string
     */
    public function getImpiantoTv()
    {
        return $this->impiantoTv;
    }

    /**
     * @param string $impiantoTv
     *
     * @return Immobile
     */
    public function withImpiantoTv($impiantoTv)
    {
        $new = clone $this;
        $new->impiantoTv = $impiantoTv;

        return $new;
    }

    /**
     * @return \App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\ImmobileTuristico
     */
    public function getImmobileTuristico()
    {
        return $this->immobileTuristico;
    }

    /**
     * @param \App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\ImmobileTuristico $immobileTuristico
     *
     * @return Immobile
     */
    public function withImmobileTuristico($immobileTuristico)
    {
        $new = clone $this;
        $new->immobileTuristico = $immobileTuristico;

        return $new;
    }

    /**
     * @return \App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\ArrayOfDistanzaPoi
     */
    public function getDistanze()
    {
        return $this->distanze;
    }

    /**
     * @param \App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\ArrayOfDistanzaPoi $distanze
     *
     * @return Immobile
     */
    public function withDistanze($distanze)
    {
        $new = clone $this;
        $new->distanze = $distanze;

        return $new;
    }

    /**
     * @return \App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\CodiceIdentificativo
     */
    public function getCodiceIdentificativo()
    {
        return $this->codiceIdentificativo;
    }

    /**
     * @param \App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\CodiceIdentificativo $codiceIdentificativo
     *
     * @return Immobile
     */
    public function withCodiceIdentificativo($codiceIdentificativo)
    {
        $new = clone $this;
        $new->codiceIdentificativo = $codiceIdentificativo;

        return $new;
    }

    /**
     * @return \App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\ArrayOfInformazioniExtra
     */
    public function getInformazioniExtra()
    {
        return $this->informazioniExtra;
    }

    /**
     * @param \App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\ArrayOfInformazioniExtra $informazioniExtra
     *
     * @return Immobile
     */
    public function withInformazioniExtra($informazioniExtra)
    {
        $new = clone $this;
        $new->informazioniExtra = $informazioniExtra;

        return $new;
    }

    /**
     * @return string
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * @param string $id
     *
     * @return Immobile
     */
    public function withId($id)
    {
        $new = clone $this;
        $new->id = $id;

        return $new;
    }

    /**
     * @return int
     */
    public function getIdAgenzia()
    {
        return $this->idAgenzia;
    }

    /**
     * @param int $idAgenzia
     *
     * @return Immobile
     */
    public function withIdAgenzia($idAgenzia)
    {
        $new = clone $this;
        $new->idAgenzia = $idAgenzia;

        return $new;
    }
}
@veewee
Copy link
Contributor

veewee commented Jan 15, 2024

Thanks for reporting! It's nice to get some real-world feedback from you, pointing out some of the pitfalls of the new wsdl-based type system.

This seems to be a bug in the new WSDL reader package:
php-soap/wsdl-reader#19

I'll try to get to it soon.

@veewee
Copy link
Contributor

veewee commented Jan 15, 2024

@h4kuna

Can you retry with the latest version of wsdl-reader?
https://github.com/php-soap/wsdl-reader/releases/tag/0.8.0

It should now generate code following the structure below.
The - dash separation is still not supported by the encoder, so that will still remain an issue 'til we figure out a way to do encoding from our end (instead of inside PHP's SoapClient)

immobile
========

> http://www.immobinet.it/schema/WebserviceImmobileBundle:immobile {
    categoria $categoria
    citta $citta
    ?string $indirizzo
    ?string $numero
    ?string $zona
    ?geo-coordinates $coords
    ?ArrayOfDescrizione $descrizione
    ?ArrayOfAllegato $allegati
    ?immobile-abitabile $composizione
    ?immobile-appartamento $appartamento
    ?immobile-superficie $superficie
    ?immobile-terreno $terreno
    ?immobile-casa $casa
    ?immobile-villa $villa
    ?immobile-capannone $capannone
    ?immobile-ace $ace
    ?ArrayOfAttributo $attributi
    ?tipo-cucina $cucina
    ?string $giardino
    ?string $parcheggio
    ?string $riscaldamento
    ?string $box-auto
    ?string $posto-auto
    ?string $impianto-tv
    ?immobile-turistico $immobile-turistico
    ?ArrayOfDistanzaPoi $distanze
    ?codice-identificativo $codice-identificativo
    ?ArrayOfInformazioniExtra $informazioni-extra
    @?string $id
    @?int $id-agenzia
  }

@h4kuna
Copy link
Contributor Author

h4kuna commented Jan 15, 2024

The generated classes looks like better. Could you set up nullable property by default null value, because property is defined like

private ?\App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\ImmobileVilla $villa;

but API return nothing and i get exception with

Typed property App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\Immobile::$villa must not be accessed before initialization.

I haven't a choice, how check property before access.

I image like

private ?\App\ChannelManager\ImmobiNet\Soap\Agenzia\Type\ImmobileVilla $villa = null;

@veewee
Copy link
Contributor

veewee commented Jan 15, 2024

Yes, that's possible:

        $assembler = new PropertyAssembler(
            PropertyAssemblerOptions::create()->withOptionalValue()
        );

Example:

function it_assembles_property_with_default_value()
{
$assembler = new PropertyAssembler(
PropertyAssemblerOptions::create()->withOptionalValue()
);
$context = $this->createContext();
$assembler->assemble($context);
$code = $context->getClass()->generate();
$expected = <<<CODE
namespace MyNamespace;
class MyType
{
/**
* Type specific docs
*
* @var null | string
*/
private ?string \$prop1 = null;
}
CODE;
$this->assertEquals($expected, $code);
}

Note: You probably want to combine this with the optional getter as well for type-safety:

$assembler = new GetterAssembler(GetterAssemblerOptions::create()->withOptionalValue());

Example:

function it_assembles_an_optional_value()
{
$assembler = new GetterAssembler(GetterAssemblerOptions::create()->withOptionalValue());
$context = $this->createContext();
$assembler->assemble($context);
$code = $context->getClass()->generate();
$expected = <<<CODE
namespace MyNamespace;
class MyType
{
/**
* @return null | string
*/
public function getProp1() : ?string
{
return \$this->prop1;
}
}

@h4kuna
Copy link
Contributor Author

h4kuna commented Jan 16, 2024

Thank you, very much, it works.

I think, this behavior could be enabled by default.

@h4kuna h4kuna closed this as completed Jan 16, 2024
@veewee
Copy link
Contributor

veewee commented Jan 16, 2024

No prob :)

I think, this behavior could be enabled by default.

I've considered it when implementing and don't think this is a good idea for several reasons:

This library follows the provided schema in the WSDL, so if it says it's a string we shouldn't annotate it as string|null cause that's confusing and not correct in every generated code scenario.

For example: it could make sense for wither-based requests but not for constructor based requests. Also for models that are being used as response DTOs it would be incorrect.

Instead, I've given to option for you to generate the code in the way you want. Just not by default.

@RiseAndCry
Copy link

@veewee
Hi, a related question:
when i make a request and try to parse the response (let's say BaseReturnType) - it contains all the necessary property values set (dump shows them as expected). But when trying to access any of them via getters i get ... must not be accessed before initialization.
How can i fix this ? i'm guessing it's because there's no constructor and thus it's hydrated using reflection (or the cloning breaks it?).
Setting the properties as nullable or giving default values makes no sense - as you said, if the schema says it's a string then it should be a string.

@veewee
Copy link
Contributor

veewee commented May 7, 2024

The case you mention should just work.
Maybe best to open up a new issue and provide it with some more details so that I can take a look at it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants