Skip to end of metadata
Go to start of metadata

<ac:macro ac:name="unmigrated-inline-wiki-markup"><ac:plain-text-body><![CDATA[

<ac:macro ac:name="unmigrated-inline-wiki-markup"><ac:plain-text-body><![CDATA[

Zend Framework: Zend\Stdlib\Configurator Component Proposal

Proposed Component Name Zend\Stdlib\Configurator
Developer Notes http://framework.zend.com/wiki/display/ZFDEV/Zend\Stdlib\Configurator
Proposers Renan de Lima
Vincent de Lau (original)
Zend Liaison TBD
Revision 1.0 - 5 July 2010: Initial Draft. (wiki revision: 7)

Table of Contents

1. Overview

Zend\Stdlib\Configurator is intended to provide classes with an easy way to process options. It will accept a Zend\Config object or array and call the appropriate setters with the provided value. The class will accept names as both underscored lowercase and camelcaps.

This component fills the gap that comes with lack of multiple inheritance or mixins in the PHP language. Without this component, each class that accepts a Zend\Config object or array has to process the options manually, which is a repetitive task. Extracting the code should lead to less code duplication and more stable code.

2. References

3. Component Requirements, Constraints, and Acceptance Criteria

  • This component will call the setter for each provided option.
  • The component will align with coding standards and practices.
  • The component will not have any knowledge of the target object.
  • The component will allow option names to be passed as underscored words.
  • The component will treat option names case insensitive.
  • The component will require the target object to have setters for each configurable option.
  • The component will not convert or test any configuration data passed.

4. Dependencies on Other Framework Components

  • Zend_Config (optional)
  • Zend_Exception

5. Theory of Operation

Zend\Stdlib\Configurator will accept a target object and an object implementing Traversable. This includes Zend\Config objects and plain arrays.

For each option passed, the Configurator will call the appropriate setter with the value provided. Option names are stripped of underscores before resolving the setter. Since call_user_method(), is_callback() and method_exists() are case sensitive, option names are practically case insensitive.

Since no state has to be maintained, the Configurator will be implemented as a class with only static methods.

6. Milestones / Tasks

  • Milestone 1: Wait for input based on coding standards and the need for configurable objects
  • Milestone 2: Finish the proposal
  • Milestone 3: Unit tests exist, work, and are checked into SVN.
  • Milestone 4: Initial documentation exists.
  • Milestone 5: The component is applied to all appropriate framework components

7. Class Index

  • Zend\Stdlib\Configurator
  • Zend\Stdlib\ConfiguratorException

8. Use Cases

UC-01

9. Class Skeletons

]]></ac:plain-text-body></ac:macro>

]]></ac:plain-text-body></ac:macro>

Labels:
None
Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.
  1. Jul 05, 2010

    <p>Thanks for creating this proposal!</p>

    <p>My points are the following:</p>
    <ul>
    <li><strong>instance of Zend\Config</strong><br />
    The configurator simply iterates over options and uses the key to find the right setter and the value as option value.<br />
    I can't see arguments to restrict to array and Zend\Config
    <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
    public static function configure($options)
    {
    if ( !($options instanceof Traversable) && !is_array($options))

    Unknown macro: { // Exception }

    foreach ($options as $k => &$v)

    Unknown macro: { // call setter }

    }
    ]]></ac:plain-text-body></ac:macro></li>
    </ul>

    <ul>
    <li><strong>Simply stripping underscores</strong><br />
    Method names are case-insensitive! In my eyes we don't need to convert underscored options names to CamelCase because the same method will be called.<br />
    I understand matthew to convert to CamelCase because it's the real defined method name but we could save 2 of 3 string conversation calls and the user doesn't note anything of it. (Sure the defined method names should be [set]CamelCase)
    <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
    $setter = 'set' . str_replace('_', '', $name);
    // instead of
    $setter = 'set' . str_replace(' ', '', ucwords(str_replace('_', ' ', $name)));
    ]]></ac:plain-text-body></ac:macro></li>
    </ul>

    <ul>
    <li><strong>ConfiguratorException extends \Exception</strong><br />
    The exception name should extends SPL exceptions like InvalidArgumentException and therefore should be named as same as the SPL exception or something to show the user better what was wrong like UnknownOptionException extends InvalidArgumentException</li>
    </ul>

    <ul>
    <li><strong>An additional check of the magic method "__call" should be done</strong><br />
    I have a case where some options names could be handled by __call and the configurator must call these setter anyway.</li>
    </ul>

    <p>A small explain:<br />
    An adapter has some options and an adapter overlay implements the adapter interface and adds additional functionalities and options to it but can be used with different adapters. In this case the overlay object using the magic __call to forward method calls (incl. option setters & getters) to the inner adapter.<br />
    > <a class="external-link" href="http://framework.zend.com/wiki/display/ZFPROP/Zend+Cache+2.0++Marc+Bennewitz">http://framework.zend.com/wiki/display/ZFPROP/Zend+Cache+2.0+-+Marc+Bennewitz</a></p>

    <p>Greetings</p>

    1. Jul 05, 2010

      <p>Thanks for the feedback!</p>
      <ul>
      <li>instance of Zend\Config</li>
      </ul>

      <p>I was actually planning on that but hadn't really investigated yet which interface or SPL class I needed. When expanding the class prototype, I'll add traversable to the documentation.</p>
      <ul>
      <li>Simply stripping underscores</li>
      </ul>

      <p>This is exactly what I was planning to do. I will word this a bit more explicit in the Theory of Operation and the documentation.</p>
      <ul>
      <li>ConfiguratorException extends \Exception</li>
      </ul>

      <p>To be honest I have no idea what the best practice for exceptions is. I was under the impressions that exceptions should be in the namespace, but I have no objection against any other exception type. Besides the name of a class, messages can convey enough helpful information, don't they?</p>
      <ac:macro ac:name="code"><ac:default-parameter>php</ac:default-parameter><ac:plain-text-body><![CDATA[
      $message = sprintf("There is no setter method available for option '%s' on class %s",$option_name,get_class($target);
      ]]></ac:plain-text-body></ac:macro>
      <ul>
      <li>An additional check of the magic method "__call" should be done</li>
      </ul>

      <p>I've thought about this, together with trying public properties and __set, but I think the new way is to be explicit. When looking at API documentation or source code it becomes immediately apparent which options are available.</p>

      <p>However, you may have a valid use case here. I'm not sure however that we should add this to the default behavior. How about an optional third parameter $checkSetters = false, which will disable function name checking and thus try __call() if a setter is not available?</p>

    2. Feb 08, 2011

      <p>One rationale for converting to actual camelCase arises when you want to reduce the number of calls to method_exists(), which can be potentially expensive when called repeatedly. One technique I've used is to call get_class_methods() to cache the available methods, and then do in_array() calls (or an array_flip() and isset()) in order to determine if the method exists.</p>

      <p>Regarding the assertion of checking for __call(), I'd argue against that. Typically, we shouldn't be defining __call(), and specifically not for setters – the whole point of doing configuration like this is to batch a bunch of existing, exposed setters. Otherwise, we're hiding implementation from the users, which makes it harder for the code to be self-documenting, and thus harder to learn. While I understand the idea of using __call() to forward to an adapter, I'd argue that such configuration should be represented by a specific key, which is handled by an specific method, which then passes on that adapter configuration to the adapter itself.</p>

  2. Jul 06, 2010

    <p>This looks good a couple of points.</p>

    <p>How would you handle required options, in the main class or inside the Configurator?</p>

    <p>How about adding a configurable interface? Just a blank one for typing.</p>

    1. Jul 06, 2010

      <p>The Configurator has no knowledge about the target class, so I would leave that responsibility with the target class. I would check the required properties after the Configurator has done its work using isset() and empty(). Checking for type constraints should be done in the individual setters.</p>

      <p>There was some debate about a Configurable interface. The interface would potentially define a setOptions() function or something like that, for use in DI containers and factories. I intentionally left it out of Configurator but if the dust around a Configurable interface settles, it might be appropriate to add.</p>

  3. Jul 06, 2010

    <p><strong>I can't see arguments to restrict to array and Zend\Config</strong><br />
    <strong>if ( !($options instanceof Traversable) && !is_array($options)) {</strong></p>

    <p>agreed</p>

    <p><strong>$setter = 'set' . str_replace('_', '', $name);</strong><br />
    <strong>// instead of</strong><br />
    <strong>$setter = 'set' . str_replace(' ', '', ucwords(str_replace('_', ' ', $name)));</strong></p>

    <p>Though I don't have a problem with either code fragment, I wonder if taking the less readable approach is the right thing to do in a cases where the performance cost is negligible. Potential food for thought.</p>

    <p><strong>The exception name should extends SPL exceptions</strong></p>

    <p>Absolutely agree.<br />
    I would suggest something like:<br />
    Zend\Stdlib\UnknownOptionException<br />
    or<br />
    Zend\Stdlib\Configurator\UnknownOptionException</p>

    <p><strong>An additional check of the magic method "__call" should be done</strong></p>

    <p>I think an optional flag would be reasonable here (less magic). Maybe $ignoreMissingSetter = FALSE (the default). The side-effect (advantage?) of this option is that it is an optional way to gain a slight (albeit negligible) performance boost (not having to check for method names).<br class="atl-forced-newline" /></p>

    <p>As for required options. I'm thinking yet another "optional" parameter would be $requiredOptions = array(). Obviously this means that we have to be able to explicitly check for the corresponding setter method so this would override a TRUE === $ignoreMissingSetter setting. </p>

    1. Jul 06, 2010

      <p><strong>Traversable vs Zend\Config</strong></p>

      <p>It is already updated in the proposal. It adds the benefit of being completely independent of Zend_Config.</p>

      <p><strong>option to setter name conversion</strong></p>

      <p>If readability is an issue (error messages?), I'd certainly convert by convention. I'll leave that as an implementation detail.</p>

      <p><strong>The exception name should extends SPL exceptions</strong></p>

      <p>I'll change it.</p>

      <p><strong>__call and other options</strong></p>

      <p>I think 'ignore missing setters' is something different from 'check setters'. The first one could try to detect is a setter or __call is available and ignore options for which no setter is available. The other option would just try setting without checking, implicitly falling back on __call if available. Ignoring would not throw an exception on a missing setter, not checking would.</p>

      <p>Providing a list of required options is another setting. This could be done as a simple checklist which is used during the setting of the options. I don't see why this would affect the other two options.<br />
      However, such a list just covers a use case where a fixed set of options is required. More complex rules still would have to be checked by the target. For instance, a database configuration could require a 'socket' option when the 'protocol' is 'unix', or a 'hostname' if the 'protocol' is 'inet'</p>

      <p>If all these options should be made available, I'd seriously consider moving away from a purely static class. However, I think it is best to reduce the number of options. Especially the handling of missing setters should be the same across all framework components (throw an exception), although a fall-back to __call could be something to configure. Basically it would be the target telling the Configurator 'my __call function will handle setters'.</p>

      <p>Just thinking along while typing... A new signature could be</p>
      <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
      void function configure(object $target,
      Traversable $options,
      [array $required=null],
      [boolean $checkSetters=true]);
      ]]></ac:plain-text-body></ac:macro>

      <p>Where $required and $checkSetters are both optional and either can be omitted.</p>

      1. Jul 06, 2010

        <p>The updated signature looks good in my opinion.</p>

        <p><strong>The other option would just try setting without checking, implicitly falling back on __call if available. Ignoring would not throw an exception on a missing setter, not checking would.</strong><br class="atl-forced-newline" /></p>

        <p>Makes sense; however, while I believe the name $checkSetters does convey the end result, it could be improved to better clarify how it is actually used in implementation. Given that this ($checkSetters === FALSE) will "fall-back" on __call, may I suggest something like $allowOverloadFallback (or something similar).</p>

        <p> On the other hand, keeping it as $checkSetters (more vague) could be a good thing if there will later be additions to the language that allow for a different method of implementation (in addition to or instead of __call).
        <br class="atl-forced-newline" /></p>

        <p><strong>Providing a list of required options is another setting. This could be done as a simple checklist which is used during the setting of the options. I don't see why this would affect the other two options.</strong><br class="atl-forced-newline" /></p>

        <p>After thinking about it further, I see you point here. The given options have no effect on whether the corresponding setter method exists or not. The setter method existing is a detail of the target object. The options given are the responsibility of the caller. I also agree that the target object should handle further validations on its own.</p>

      2. Jul 06, 2010

        <p>I already replied to the mailing list - sry for duplicates</p>

        <ul>
        <li>fall-back to __call<br />
        Not checking setters could change the behavior of option setting on different components.<br />
        I would prefer an option argument like $allowMagicCall to only fall-back if the setter doesn't exists but the magic method "__call" exists and the magic method have to throw a defined exception if it's unknown which can be re-throw by the setter to leave behavior of failed option setting equal to other components. (I send a prototype on mailing list)</li>
        </ul>

        <ul>
        <li>required options<br />
        This should be handled within the component its self because options could be required or not dependent on others.
        <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
        __constructor($options) {
        Zend\Stdlib\Configurator::configure($this, $options);
        if ($this->_optionOne == 2 && $this->_dependentOption === null)

        Unknown macro: { // throw exception }

        }
        ]]></ac:plain-text-body></ac:macro></li>
        </ul>

        1. Jul 07, 2010

          <p>I've updated the proposal with a third option $tryCall and a basic implementation. Maybe $tryCall should be named $tryMagicCall for more clarity.</p>

          <p>Matthew suggested on the ML that non existent options should be ignored to facilitate quick object swapping without having to rework the configuration.</p>

          <p>I'm not in favor of making ignore an option. Although I think that component creators might find that useful, it doesn't help to enforce a common way to handle options. The $tryMagicCall option is different, since it is a declaration of the component creator that the __call method knows how to handle setter calls.</p>

          <p>Besides bad parameters types, I see no need to throw or re-throw exceptions. IMHO the Exceptions thrown for bad method calls, wrong parameter types and such are sufficient. Wrapping these exceptions and re-throwing them might make it harder to debug.</p>

          1. Jul 07, 2010

            <blockquote><p>Although I think that component creators might find that useful</p></blockquote>
            <p>If the configurator ignores unknown options the component get note of it. Why it should be helpful for component writers ?</p>

            <p>I'm not a favor of it, too. But it should be a point to ark ZF users (not contributors) to get your votes. It doesn't help to see that 5 users are criticize to not ignoring unknown options but for 100 users exceptions are fine and don't tell it.</p>

            <blockquote><p>Besides bad parameters types, I see no need to throw or re-throw exceptions. IMHO the Exceptions thrown for bad method calls, wrong parameter types and such are sufficient. Wrapping these exceptions and re-throwing them might make it harder to debug.</p></blockquote>
            <p>This would only be interesting if unknown exceptions have to throw.</p>

            <p>My point for it was that for the user only one exceptions should be thrown on unknown option. But if a component allows option setters by __call it should throw directly this exception because:<br />
            1. It doesn't know if this was an failed option setter of another (direct) call to it's object.<br />
            2. On component shouldn't throw exceptions of others</p>

            <p>Therefore for the component it's simply an BadMethodCallException and can be catched by the configurator which knows that this BadMethodCallException is followed of an unknown option name and re-throw it to be for the users its the same type of exception as on other components not using "__call"-setters</p>

          2. Feb 08, 2011

            <p>The reason I'm against raising exceptions on unknown options is quite simple: configuration inheritance. Consider the following:</p>

            <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
            [production]
            component.adapter.class = "Some\Adapter\Class"
            component.adapter.options.foo = "bar"

            [development : production]
            component.adapter.class = "Some\Other\Adapter\Class"
            component.adapter.options.bar = "baz"
            ]]></ac:plain-text-body></ac:macro>

            <p>Now consider that Some\Other\Adapter\Class doesn't know about option "foo", but does know and care about option "bar" – the problem we have now is that the options array now looks like this:</p>

            <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
            array(
            'foo' => 'bar',
            'bar' => 'baz',
            )
            ]]></ac:plain-text-body></ac:macro>

            <p>If we were to throw exceptions on unknown options, we simply cannot do configuration inheritance any more – and this is an incredibly powerful and useful feature of our configuration approach.</p>

            1. Feb 08, 2011

              <p>I'd be in favor of having a strict setting which does throw an exception but have it default to non-strict.</p>

              <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
              public static function configure($target, $options, $strictOptions=false) {}
              ]]></ac:plain-text-body></ac:macro>

  4. Jul 07, 2010

    <p>After some more feedback and discussion, I have the following questions for you all:</p>

    <ul>
    <li>Should the configurator function be static. Given the lack of state, I'd say it is fine. I also don't see any issue with testability, but I'm new to unit testing and TDD.</li>
    </ul>

    <ul>
    <li>What type of exception should be thrown? Should they be a SPL InvalidArgumentException or must exceptions derive from a zend\stdlib\Exception?</li>
    </ul>

    <ul>
    <li>Are we going to have a Configurable interface? Should this component only allow target objects that implement this interface? I see no requirement for this, but would not object if that is community consensus.</li>
    </ul>

    1. Jan 15, 2011

      <p><strong>Should the configurator function be static. Given the lack of state, I'd say it is fine. I also don't see any issue with testability, but I'm new to unit testing and TDD.</strong></p>

      <p>If there is no state, there is no reason for an instance. For cleanliness and clarity you might want to consider blocking __construct and __clone explicitly.</p>

      <p><strong>What type of exception should be thrown? Should they be a SPL InvalidArgumentException or must exceptions derive from a zend\stdlib\Exception?</strong></p>

      <p> Probably best if a lead answers this one.</p>

      <p><strong>Are we going to have a Configurable interface? Should this component only allow target objects that implement this interface? I see no requirement for this, but would not object if that is community consensus.</strong></p>

      <p>In this case, I think it makes sense to utilize the interface.</p>

    2. Jul 07, 2010

      <ul>
      <li><strong>Should the configurator function be static. Given the lack of state, I'd say it is fine. I also don't see any issue with testability, but I'm new to unit testing and TDD.</strong><br />
      There is no need to create an instance and would only be overflow</li>
      </ul>

      <ul>
      <li><strong>What type of exception should be thrown? Should they be a SPL InvalidArgumentException or must exceptions derive from a zend\stdlib\Exception?</strong><br />
      It should use the standard of ZF 2.0 -> extends SPL-Exception with a component marker.<br />
      Like this:
      <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
      namespace Zend\Stdlib;
      class UnknownOptionException extends \InvalidArgumentException implements Exception
      {}
      ]]></ac:plain-text-body></ac:macro>
      -> extends the base InvalidArgumentException <br />
      -> implements Zend\Stdlib\Exception</li>
      </ul>

      <ul>
      <li><strong>Are we going to have a Configurable interface? Should this component only allow target objects that implement this interface? I see no requirement for this, but would not object if that is community consensus.</strong><br />
      This should be part of another proposal of Zend\Config<br />
      -> But it shouldn't only allow target object's of this interface.</li>
      </ul>

  5. Jul 15, 2010

    <p>I get an idea for an addition to solve the following issue:</p>

    <p>Within Zend_Cache_Frontend_Page there there are the options "default_options" and "regexps" which hold a list of the options which are only affected on specific circumstances.<br />
    This means these options are part of an option to set but can't directly set and should be validated on set the option group.<br />
    (I hope it's clear what I mean)</p>

    <p>-> <a class="external-link" href="http://framework.zend.com/manual/en/zend.cache.frontends.html#zend.cache.frontends.page">http://framework.zend.com/manual/en/zend.cache.frontends.html#zend.cache.frontends.page</a></p>

    <p>How to validate options without set the option ?</p>

    <p>1. get the current option -> set the new option to check -> re-set the old option<br />
    or<br />
    2. add a method to validate an option on component side and to validate a list of options on configurator side.</p>
    <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
    class Zend_Component {
    protected $_myOption;
    protected $_specificOptions = array(); // a list of options to set only
    // on specific circumstances

    public function setMyOption($value) {
    if (!$this->validateMyOption($value))

    Unknown macro: { throw new InvalidArgumentException(...); }

    $this->_myOption = $value;
    }
    public function validateMyOption($value)

    Unknown macro: { // code to validate return true; // or false }

    public function setSpecificOptions($options) {
    if (!$this->validateSpecificOptions($options))

    $this->_specificOptions = $options;
    }
    public function validateSpecificOptions($options)

    Unknown macro: { return Configurator}

    }
    ]]></ac:plain-text-body></ac:macro>
    <p>-> For every option a method "validate

    Unknown macro: {OptionName}

    (mixed $value) : boolean" would be required.<br />
    -> The configurator would need a method to only validate a list of options.</p>

  6. Jan 08, 2011

    <p>What's up with this proposal? I'd still like to see it in ZF2, because it resolves a lot of duplicate code. Oh, by the way, I'd like to see the option to speciy "must have" options, which, if not existent, throw an exception.</p>

    1. Jan 14, 2011

      <p>This is a good proposal for zf2</p>

      <p>-1 for specify "must have", it should be implemented after configurator calling (ie: in configurable object constructor). API shouldn't require all required options every time.</p>

      <p>Configurator behavior ("try call", "must have" and future others) are tricks. We should think another way to set those configurations, methods looks dirty when it has a lot of arguments. I don't know how, but adding arguments doesn't look good for me. Those options/behavior should be defined by configurable class, not by the user.</p>

      <p>I think options could also work for static methods like \Zend\Mail::setDefaultFrom()</p>

      <p>This also could support "set" and "add" methods calling. Bellow a basic implementation.</p>

      <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
      /**

      • @param stdClass|string $target
      • @param Traversable|array $options
      • @throws InvalidArgumentException
      • @return void
        */
        public static function configure($target, $options)
        {
        if (!is_object($target) && !class_exists($target))
        Unknown macro: { throw new InvalidArgumentException( 'Target should be an object or a valid class name'); }

        if (!$options instanceof Traversable && !is_array($options))

        Unknown macro: { throw new InvalidArgumentException( 'Options should implement Traversable'); }

      foreach ($options as $name => &$value) {
      $suffix = str_replace(' ', '', ucwords(str_replace('_', ' ', $name)));
      $operations = array('set', 'add');
      foreach ($operations as $operation) {
      $method = $operation . $suffix;
      $callback = array($target, $method);
      // @todo check somewhere if is possible call __callStatic() or __call()
      if (is_callable($callback))

      Unknown macro: { call_user_func($callback ,$value); break; }

      }
      }
      }
      ]]></ac:plain-text-body></ac:macro>

    2. Jan 14, 2011

      <p>Well, to be honest I'm currently not working with Zend Framework anymore, since I changed jobs. Still trying to get this shop over to ZF though...</p>

      <p>I do think this proposal has it's benefits, but I think the community has to decide it they want it. I think there is enough stuff in here to start large flame wars... <ac:emoticon ac:name="wink" /></p>

      <p>Having said that, I think the component itself is quite trivial to implement. My implementation is actually in the class skeleton above.</p>

    3. Jan 14, 2011

      <p>I really do think this proposal is good and <strong>necessary</strong>, options in zf2 can be improved so much</p>

      <p>I dind't want to start a flame. It's just my opnion, here (and lists) is the place to talk about zf, obviously my opnion is not the best one, it's just yet another one <ac:emoticon ac:name="wink" /> don't worry</p>

      <p>I also think implementation is trivial, but this is an important component, somethings looks basic, but our choose today can generate problems in the future</p>

      1. Jan 15, 2011

        <p>+1</p>

        <p>Great proposal to zf2, I think that with this proposal should try fix some problems that already know.</p>

        <p>How order of the keys (ZF-10836, ZF-10543 between another) or skip of some keys (see ZF-8175, Zend_Form_Element between another).</p>

        <p>A code simple</p>
        <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
        interface Zend\Stdlib\Configurable
        {
        /**

        • @return name of the keys
          */
          public static function getOptionNames();

        /**

        • @return name of the keys mandatory
          */
          public static function getRequiredOptions();
          }

        class Zend\Form implements Zend\Stdlib\Configurable
        {
        public static function getOptionNames()

        Unknown macro: { // here fix keys in order also the problem of skip keys return array('key'); }

        public static function getRequiredOptions()

        Unknown macro: { // here keys required }

        }
        ]]></ac:plain-text-body></ac:macro>
        <p>With this should be done a treatment in Zend\Stdlib\Configurator if the $target <strong>implements</strong> Zend\Stdlib\Configurable to make called $target->getOptionNames() in Zend\Stdlib\Configurator::configure().</p>

        <p>Greetings,<br />
        Ramon Henrique Ornelas </p>

  7. Jan 15, 2011

    <p>+1 for creating an Configurable interface which implements basic functions to get available option names and required options. This also solves test to magic methods because its clear which options methods are available ignoring of implementation detail.</p>

    <blockquote><p>Matthew suggested on the ML that non existent options should be ignored to facilitate quick object swapping without having to rework the configuration.</p></blockquote>
    <p>This is something I really don't like because it makes debugging more difficult and generates more problems as it solves.</p>

    <p>But if this behavior is required we should create an option to disable it for debugging like "ignore_missing_options" but with that it would mean the configuration becomes a state and should instantiable.</p>

    <blockquote><p>I think options could also work for static methods like \Zend\Mail::setDefaultFrom()</p></blockquote>
    <p>In my opinion there is no need to implement this but if it's needed the interface should differ between class options and object options.</p>

    1. Feb 08, 2011

      <p>Please see my previous comments – the reason why I don't support raising exceptions/errors on unknown options is because it invalidates configuration inheritance.</p>

  8. Jan 31, 2011

    <p>I'm starting work in this proposal. Next days i'm gonna log every changes in this wiki page.</p>

    <p>----- from: Renan de Lima<br />
    ----- to: Vicent de Lau</p>

    <p>Hi Vicent,</p>

    <p>I'm Renan, php developer and zf contributor.</p>

    <p>I got your message:
    <a class="external-link" href="http://framework.zend.com/wiki/display/ZFPROP/Zend_Stdlib_Configurator+-+Vincent+de+Lau?focusedCommentId=31129771#comment-31129771">http://framework.zend.com/wiki/display/ZFPROP/Zend_Stdlib_Configurator+-+Vincent+de+Lau?focusedCommentId=31129771#comment-31129771</a></p>

    <p>This proposal is very important, I wanna start working on this<br />
    component, once you think this is possible, I would like coding it.</p>

    <p>----- from: Vicent de Lau<br />
    ----- to: Renan de Lima</p>

    <p>Hi Renan,</p>

    <p>As I said, I'm currently not actively working with Zend Framework at the moment. If you want, feel free to take up this proposal and finish it.</p>

    <p>Although it seems like a simple component, I think the community will have a lot of feedback. <ac:emoticon ac:name="wink" /></p>

  9. Feb 03, 2011

    <p>Soon i'm going to update this proposal regarding some subjects. Please, let your option.</p>

    <ul>
    <li>Magic methods</li>
    </ul>

    <p>We should avoid them. Magic methods are slow and not clear for users. Anyway __set() makes more sense than __call() in this case.</p>

    <p>In zf2, we are working to make class APIs clearer. Class definitons have getters and setters explicited defined. Every component should assist that.</p>

    <p>Magic methods may give us some problems. For example, user should implement magic methods case insensitive, otherwise the API of this component is wrong. So this component has a dependency of others.</p>

    <p>I think we should <strong>not</strong> use __call() and/or __set()</p>

    <ul>
    <li>Required options</li>
    </ul>

    <p>It's a nice feature for constructors, but it's not for other cases. stdlib\configurator must work everywhere. Required options checking would be optional, maybe a third argument for configure() method.</p>

    <p>I agree when Marc says "This should be handled within the component its self because options could be required or not dependent on others.". Anyway an interface, as Ramon suggested, works fine.</p>

    <p>I think that optional argument and Interface are better for this issue.</p>

    <ul>
    <li>Class configurator</li>
    </ul>

    <p>IMO class configuration is needed, specially because class options values handling of zf classes could be easer.</p>

    <p>Currently we have some classes and their default values. Every time users want to change them they have to send all options to the object factory. Application resources could handle user options and make configuration.ini file easer to understand and smallest. Anyway providing ways to change default values (configurable by static methods) of anything is good for the framework.</p>

    1. Feb 03, 2011

      <p>Good to hear you are working on it <ac:emoticon ac:name="smile" /></p>

      <blockquote><p>Anyway __set() makes more sense than __call() in this case.</p></blockquote>
      <p>This isn't true in all cases. For example if a component is working with such properties you can't differ these kind of properties and options.</p>

      <p>But if we have an Interface incl. a method to get all available options/names this automatic defines which getters/setters are available for options. If a component implements the Interface it also indicate that every available option has a getter and setter method. -> There is no need test it before call.</p>

      <p><strong>Required options</strong><br />
      As already noted I see no need of this argument as part of configurator.</p>

      1. Feb 07, 2011

        <blockquote><p> "about __set() and __call()" This isn't true in all cases. For example if a component is working with such properties you can't differ these kind of properties and options.</p></blockquote>

        <p>sure, properties != options</p>

        <blockquote><p>But if we have an Interface incl. a method to get all available options/names this automatic defines which getters/setters are available for options. If a component implements the Interface it also indicate that every available option has a getter and setter method. -> There is no need test it before call.</p></blockquote>

        <p>agreed, no magic calling for objects that implements this Interface, but the configurator have to work for every object, even for those that don't implement configurable interface</p>

        <blockquote><p>As already noted I see no need of this argument (required options) as part of configurator.</p></blockquote>

        <p>thinking better about this, we should have some way to find "getters" or merge current object option values with new options arguments... so, this is an object business</p>

  10. Feb 08, 2011

    <p>There are a lot of posts, I tried gather topics about this component. The main topics and its "decisions":</p>

    <ul>
    <li>no check for __call()</li>
    <li>no exceptions for required options</li>
    <li>no exceptions for missing options</li>
    <li>no class configurator</li>
    <li>optional interface for configurable objects that provide an option map
    <ul>
    <li>below it's my current improvement for this feature</li>
    <li>array(method1 => opt1) or just array(opt1, opt2) or both array(method1 => opt1, opt2)</li>
    </ul>
    </li>
    </ul>

    <p>This isn't a bigger component, so you'll see something implemented in my zf2 fork soon.</p>

  11. May 04, 2011

    <p>I've implemented days and days ago. See some files from my fork.</p>

    <p>Configurator class: <a class="external-link" href="https://github.com/renanbr/zf2/blob/master/library/Zend/Stdlib/Configurator.php">https://github.com/renanbr/zf2/blob/master/library/Zend/Stdlib/Configurator.php</a></p>

    <p>Configurable interface: <a class="external-link" href="https://github.com/renanbr/zf2/blob/master/library/Zend/Stdlib/Configurable.php">https://github.com/renanbr/zf2/blob/master/library/Zend/Stdlib/Configurable.php</a></p>

    1. May 06, 2011

      <p>Interface:<br />
      Does it make sense to have a getOptions method returning an array (or object implements ArrayAccess)</p>

      <p>Configurator:<br />
      1. It makes only sense to check if a setter exists if the target object doesn't implement Configurable interface<br />
      2. Normalizing should return a "setCamelCase" format and this method should be called<br />
      3. array_keys only works on Arrays</p>

      <p>-> It should be enough to iterates once over options<br />
      (if Configurable check if option is available within option names (case-insensitive)<br />
      or check if method exists)<br />
      and if valid normalize and call setter within this iteration (e.g. setCamelCase)</p>

      <p>Or do I have an error in reasoning ?</p>

      1. May 24, 2011

        <blockquote><p>Interface: Does it make sense to have a getOptions method returning an array (or object implements ArrayAccess)</p></blockquote>

        <p>I don't think so. This interface provides only options information for configurator class. It doesn't mean children classes must provide a kind of option access.</p>

        <blockquote><p>Configurator: 1. It makes only sense to check if a setter exists if the target object doesn't implement Configurable interface</p></blockquote>

        <p>In this implementation, configurable classes can intercept setter calls in setSomething() (or __call() when method does not exist). When configurator checks if a setter exists, this means configurable->getOptionNames() returned as a key option name in array map a specific setter to be called (in despite of default behavior). This is implemented to avoid runtime exception, this way non well-formed option configuration is just ignored.</p>

        <blockquote><p>Configurator: 2. Normalizing should return a "setCamelCase" format and this method should be called</p></blockquote>

        <p>Makes sense, there is no way to know __call() implementation. I think user expect camel case method name. I think we should change this as you propose.</p>

        <blockquote><p>Configurator: 3. array_keys only works on Arrays</p></blockquote>

        <p>Sure, i didn't tested it. This situation must be added to test cases.</p>