Skip to content

Latest commit

 

History

History
382 lines (291 loc) · 12.3 KB

options_resolver.rst

File metadata and controls

382 lines (291 loc) · 12.3 KB
.. index::
    single: Options Resolver
    single: Componenti; OptionsResolver

Il componente OptionsResolver

Il Componente OptionsResolver aiuta a configurare gli oggetti con un array di opzioni. Esso supporta valori predefiniti, opzioni con vincoli e opzioni pigre.

Installazione

È possibile installare il componente in due modi differenti:

Utilizzo

Si immagini di avere una classe Mailer che ha 2 opzioni: host e password. Queste opzioni stanno per essere gestite dal Componente OptionsResolver.

Innanzitutto, creare la classe Mailer:

class Mailer
{
    protected $options;

    public function __construct(array $options = array())
    {
    }
}

Si potrebbe impostare il valore di $options direttamente nella proprietà. Invece, utilizzare la classe :class:`Symfony\\Component\\OptionsResolver\\OptionsResolver` e lasciare che essa risolva le opzioni tramite la chiamata al metodo :method:`Symfony\\Component\\OptionsResolver\\OptionsResolver::resolve`. I vantaggi di operare in questo modo saranno più ovvi andando avanti:

use Symfony\Component\OptionsResolver\OptionsResolver;

// ...
public function __construct(array $options = array())
{
    $resolver = new OptionsResolver();

    $this->options = $resolver->resolve($options);
}

La proprietà $options è ora un array ben definito, con tutte le opzioni risolte rese disponibili:

// ...
public function getHost()
{
    return $this->options['host'];
}

public function getPassword()
{
    return $this->options['password'];
}

Configurare OptionsResolver

Adesso, si provi a utilizzare effettivamente la classe:

$mailer = new Mailer(array(
    'host'     => 'smtp.example.org',
    'password' => 'pa$$word',
));

In questo momento, si riceverà una :class:`Symfony\\Component\\OptionsResolver\\Exception\\InvalidOptionsException`, la quale informa che le opzioni host e password non esistono. Questo perché è necessario configurare prima l'OptionsResolver, in modo che sappia quali opzioni devono essere risolte.

Tip

Per controllare se un'opzione esiste, si può utilizzare la funzione :method:`Symfony\\Component\\OptionsResolver\\OptionsResolver::isKnown`.

Una buona pratica è porre la configurazione in un metodo (per esempio setDefaultOptions). Il metodo viene invocato nel costruttore per configurare la classe OptionsResolver:

use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;

class Mailer
{
    protected $options;

    public function __construct(array $options = array())
    {
        $resolver = new OptionsResolver();
        $this->setDefaultOptions($resolver);

        $this->options = $resolver->resolve($options);
    }

    protected function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        // ... configura il resolver, come si apprendererà nelle sezioni successive
    }
}

Opzioni Obbligatorie

Supponiamo che l'opzione firstName sia obbligatoria: la classe non può funzionare senza di essa. Si possono settare le opzioni obbligatorie invocando :method:`Symfony\\Component\\OptionsResolver\\OptionsResolver::setRequired`:

// ...
protected function setDefaultOptions(OptionsResolverInterface $resolver)
{
    $resolver->setRequired(array('host'));
}

A questo punto è possible usare la classe senza errori:

$mailer = new Mailer(array(
    'host' => 'smtp.example.org',
));

echo $mailer->getHost(); // 'smtp.example.org'

Se un'opzione obbligatoria non viene passata, una :class:`Symfony\\Component\\OptionsResolver\\Exception\\MissingOptionsException` sarà lanciata.

Per determinare se un'opzione è obbligatoria, si può usare il metodo :method:`Symfony\\Component\\OptionsResolver\\OptionsResolver::isRequired`.

Opzioni Facoltative

Qualche volta, un'opzione può essere facoltativa (per esempio l'opzione lastName nella classe Person). È possibile configurare queste opzioni invocando :method:`Symfony\\Component\\OptionsResolver\\OptionsResolver::setOptional`:

// ...
protected function setDefaultOptions(OptionsResolverInterface $resolver)
{
    // ...

    $resolver->setOptional(array('password'));
}

Settare Valori Predefiniti

La maggior parte delle opzioni facoltative hanno un valore predefinito. È possibile configurare queste opzioni invocando :method:`Symfony\\Component\\OptionsResolver\\OptionsResolver::setDefaults`:

// ...
protected function setDefaultOptions(OptionsResolverInterface $resolver)
{
    // ...

    $resolver->setDefaults(array(
        'username' => 'root',
    ));
}

È stata aggiunta una terza opzione, username, con un valore predefinito di root. Se l'utente passerà un'opzione username, tale valore sarà sovrascritto. Non è necessario configurare username come una opzione facoltativa. OptionsResolver sa già che le opzioni con un valore predefinito sono facoltative.

Valori predefiniti che dipendono da altre Opzioni

Supponiamo di aggiungere un'opzione port alla classe Mailer, il cui valore predefinito è indovinato sulla base dell'host. Lo si può fare facilmente, usando una Closure come valore predefinito:

use Symfony\Component\OptionsResolver\Options;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;

// ...
protected function setDefaultOptions(OptionsResolverInterface $resolver)
{
    // ...

    $resolver->setDefaults(array(
        'port' => function (Options $options) {
            if (in_array($options['host'], array('127.0.0.1', 'localhost'))) {
                return 80;
            }

            return 25;
        },
    ));
}

Caution!

Il primo parametro della Closure deve essere di tipo Options, altrimenti sarà considerata come il valore.

Sovrascrivere i valori predefiniti

Un valore predefinito, impostato in precedenza, può essere sovrascritto invocando di nuovo :method:`Symfony\\Component\\OptionsResolver\\OptionsResolver::setDefaults`. Se si usa una closure come nuovo valore, riceverà due parametri:

use Symfony\Component\OptionsResolver\Options;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;

// ...
protected function setDefaultOptions(OptionsResolverInterface $resolver)
{
    // ...
    $resolver->setDefaults(array(
        'encryption' => 'ssl',
        'host' => 'localhost',
    ));

    // ...
    $resolver->setDefaults(array(
        'encryption' => 'tls', // sovrascrittura semplice
        'host' => function (Options $options, $previousValue) {
            return 'localhost' == $previousValue ? '127.0.0.1' : $previousValue;
        },
    ));
}

Tip

Se il precedente valore predefinito è calcolato da una closure impegnativa e non si ha bisogno di accedervi, si può usare invece il metodo :method:`Symfony\\Component\\OptionsResolver\\OptionsResolver::replaceDefaults`. Questo metodo agisce come setDefaults, ma cancella semplicemente il valore precedente, per migliorare le prestazioni. Questo vuol dire che il precedente valore predefinito non è disponibile se si sovrascrive con un'altra closure:

use Symfony\Component\OptionsResolver\Options;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;

// ...
protected function setDefaultOptions(OptionsResolverInterface $resolver)
{
    // ...
    $resolver->setDefaults(array(
        'encryption' => 'ssl',
        'heavy' => function (Options $options) {
            // dei calcoli pesanti per creare $result

            return $result;
        },
    ));

    $resolver->replaceDefaults(array(
        'encryption' => 'tls', // sovrascrittura semplice
        'heavy' => function (Options $options) {
            // $previousValue non disponibile
            // ...

            return $someOtherResult;
        },
    ));
}

Note

Le chiavi di opzioni esistenti non menzionate durante la sovrascrittura saranno preseervate.

Configurare i Valori consentiti

Non tutti i valori sono validi per le opzioni. Supponiamo che la classe Mailer abbia un'opzione transport, che può valere solo sendmail, mail o smtp. È possibile configurare questi valori consentiti, invocando :method:`Symfony\\Component\\OptionsResolver\\OptionsResolver::setAllowedValues`:

// ...
protected function setDefaultOptions(OptionsResolverInterface $resolver)
{
    // ...

    $resolver->setAllowedValues(array(
        'transport' => array('sendmail', 'mail', 'smtp'),
    ));
}

Esiste anche un metodo :method:`Symfony\\Component\\OptionsResolver\\OptionsResolver::addAllowedValues`, che è possibile utilizzare se si vuole aggiungere un valore consentito al precedente set di valori consentiti.

Configurare i Tipi consentiti

È possibile anche specificare i valori consentiti. Per esempio, l'opzione firstName può essere qualsiasi cosa, ma deve essere una stringa. È possibile configurare questi tipi invocando :method:`Symfony\\Component\\OptionsResolver\\OptionsResolver::setAllowedTypes`:

// ...
protected function setDefaultOptions(OptionsResolverInterface $resolver)
{
    // ...

    $resolver->setAllowedTypes(array(
        'port' => 'integer',
    ));
}

I possibili tipi sono quelli associati alle funzioni php is_* o al nome della classe. È possibile passare anche un array di tipi come valore. Per esempio, array('null', 'string') consente a port di essere nullo o una stringa.

Esiste anche un metodo :method:`Symfony\\Component\\OptionsResolver\\OptionsResolver::addAllowedTypes`, che può essere utilizzato per aggiungere un tipo consentito a quelli precedentemente indicati.

Normalizzare le Opzioni

Alcuni valori devono essere normalizzati prima che possano essere usati. Per esempio, firstName dovrebbe sempre iniziare con una lettera maiuscola. Per fare ciò, si posso scrivere dei normalizzatori. Queste Closure saranno eseguite dopo che tutte le opzioni sono state passate e ritornano il valore normalizzato. I normalizzatori possono essere configurati invocando :method:`Symfony\\Components\\OptionsResolver\\OptionsResolver::setNormalizers`:

// ...
protected function setDefaultOptions(OptionsResolverInterface $resolver)
{
    // ...

    $resolver->setNormalizers(array(
        'host' => function (Options $options, $value) {
            if ('http://' !== substr($value, 0, 7)) {
                $value = 'http://'.$value;
            }

            return $value;
        },
    ));
}

Si può notare che la closure riceve un parametetro $options. Qualche volta, è necessario utilizzare altre opzioni per normalizzare:

// ...
protected function setDefaultOptions(OptionsResolverInterface $resolver)
{
    // ...

    $resolver->setNormalizers(array(
        'host' => function (Options $options, $value) {
            if (!in_array(substr($value, 0, 7), array('http://', 'https://'))) {
                if ($options['ssl']) {
                    $value = 'https://'.$value;
                } else {
                    $value = 'http://'.$value;
                }
            }

            return $value;
        },
    ));
}