title: ZF2 + Doctrine 2 - Entity created when requirements not met and values empty
body: <p>Extending on 2 previous questions about <a href="https://stackoverflow.com/questions/44265665/zf2-doctrine2-fieldsets-not-validated-data-is-always-valid">form structure</a> and <a href="https://stackoverflow.com/questions/45057551/zf2-doctrine2-fieldset-in-fieldset-of-a-collection-in-fieldset-does-not-vali">validating collections</a> I've run into the next issue. </p>
  
  <p>My form validates properly. Including included collections by way of Fieldsets. But the innermost Fieldset should not result in an Entity and a FK association to the parent if its values are not set. </p>
  
  <p>An <code>Address</code> may or may not have linked <code>Coordinates</code>. It's possible to create all of these in the same Form. </p>
  
  <p>However, the <code>Coordinates</code> should not be created and should not be linked from the <code>Address</code> if no coordinates have been given in the Form. They're not required in the Form and the Entity <code>Coordinates</code> itself requires both properties of Latitude and Longitude to be set. </p>
  
  <p>Below, first the Entities. Following are the Fieldsets used for the <code>AddressForm</code>. I've removed stuff from both unrelated to the chain of <code>Address</code> -> <code>Coordinates</code>. </p>
  
  <p><strong><code>Address.php</code></strong></p>
  
  <pre><code>class Address extends AbstractEntity
  {
      // Properties
  
      /**
       * @var Coordinates
       * @ORM\OneToOne(targetEntity="Country\Entity\Coordinates", cascade={"persist"}, fetch="EAGER", orphanRemoval=true)
       * @ORM\JoinColumn(name="coordinates_id", referencedColumnName="id", nullable=true)
       */
      protected $coordinates;
  
      // Getters/Setters
  }
  </code></pre>
  
  <p><strong><code>Coordinates.php</code></strong></p>
  
  <pre><code>class Coordinates extends AbstractEntity
  {
      /**
       * @var string
       * @ORM\Column(name="latitude", type="string", nullable=false)
       */
      protected $latitude;
  
      /**
       * @var string
       * @ORM\Column(name="longitude", type="string", nullable=false)
       */
      protected $longitude;
  
      // Getters/Setters
  }
  </code></pre>
  
  <p>As is seen in the Entities above. An <code>Address</code> has a <code>OneToOne</code> uni-directional relationship to <code>Coordinates</code>. The <code>Coordinates</code> entity requires both <code>latitude</code> and <code>longitude</code> properties, as seen with the <code>nullable=false</code>.</p>
  
  <p>It's there that it goes wrong. If an <code>Address</code> is created, but no <code>Coordinates</code>'s properties are set in the form, it still creates a <code>Coordinates</code> Entity, but leaves the <code>latitude</code> and <code>longitude</code> properties empty, even though they're required. </p>
  
  <p>So, in short:</p>
  
  <ul>
  <li>A <code>Coordinates</code> Entity is created where non should exist</li>
  <li>A link to <code>Coordinates</code> is created from <code>Address</code> where non should exist</li>
  </ul>
  
  <p>Below the Fieldsets and InputFilters to clarify things further.</p>
  
  <p><strong><code>AddressFieldset.php</code></strong></p>
  
  <pre><code>class AddressFieldset extends AbstractFieldset
  {
      public function init()
      {
          parent::init();
  
          // Other properties
  
          $this-&gt;add([
              'type' =&gt; CoordinatesFieldset::class,
              'required' =&gt; false,
              'name' =&gt; 'coordinates',
              'options' =&gt; [
                  'use_as_base_fieldset' =&gt; false,
              ],
          ]);
      }
  }
  </code></pre>
  
  <p><strong><code>CoordinatesFieldset.php</code></strong></p>
  
  <pre><code>class CoordinatesFieldset extends AbstractFieldset
  {
      public function init()
      {
          parent::init();
  
          $this-&gt;add([
              'name' =&gt; 'latitude',
              'required' =&gt; true,
              'type' =&gt; Text::class,
              'options' =&gt; [
                  'label' =&gt; _('Latitude'),
              ],
          ]);
  
          $this-&gt;add([
              'name' =&gt; 'longitude',
              'required' =&gt; true,
              'type' =&gt; Text::class,
              'options' =&gt; [
                  'label' =&gt; _('Longitude'),
              ],
          ]);
      }
  }
  </code></pre>
  
  <p><strong><code>AddressFieldsetInputFilter.php</code></strong></p>
  
  <pre><code>class AddressFieldsetInputFilter extends AbstractFieldsetInputFilter
  {
      /** @var CoordinatesFieldsetInputFilter $coordinatesFieldsetInputFilter */
      protected $coordinatesFieldsetInputFilter;
  
      public function __construct(
          CoordinatesFieldsetInputFilter $filter,
          EntityManager $objectManager,
          Translator $translator
      ) {
          $this-&gt;coordinatesFieldsetInputFilter = $filter;
  
          parent::__construct([
              'object_manager' =&gt; $objectManager,
              'object_repository' =&gt; $objectManager-&gt;getRepository(Address::class),
              'translator' =&gt; $translator,
          ]);
      }
  
      /**
       * Sets AddressFieldset Element validation
       */
      public function init()
      {
          parent::init();
  
          $this-&gt;add($this-&gt;coordinatesFieldsetInputFilter, 'coordinates');
  
          // Other filters/validators
      }
  }
  </code></pre>
  
  <p><strong><code>CoordinatesFieldsetInputFilter.php</code></strong></p>
  
  <pre><code>class CoordinatesFieldsetInputFilter extends AbstractFieldsetInputFilter
  {
      public function init()
      {
          parent::init();
  
          $this-&gt;add([
              'name' =&gt; 'latitude',
              'required' =&gt; true,
              'allow_empty' =&gt; true,
              'filters' =&gt; [
                  ['name' =&gt; StringTrim::class],
                  ['name' =&gt; StripTags::class],
              ],
              'validators' =&gt; [
                  [
                      'name' =&gt; StringLength::class,
                      'options' =&gt; [
                          'min' =&gt; 2,
                          'max' =&gt; 255,
                      ],
                  ],
                  [
                      'name' =&gt; Callback::class,
                      'options' =&gt; [
                          'callback' =&gt; function($value, $context) {
                              //If longitude has a value, mark required
                              if(empty($context['longitude']) &amp;&amp; strlen($value) &gt; 0) {
                                  $validatorChain = $this-&gt;getInputs()['longitude']-&gt;getValidatorChain();
  
                                  $validatorChain-&gt;attach(new NotEmpty(['type' =&gt; NotEmpty::NULL]));
                                  $this-&gt;getInputs()['longitude']-&gt;setValidatorChain($validatorChain);
  
                                  return false;
                              }
  
                              return true;
                          },
                          'messages' =&gt; [
                              'callbackValue' =&gt; _('Longitude is required when setting Latitude. Give both or neither.'),
                          ],
                      ],
                  ],
              ],
          ]);
  
          // Another, pretty much identical function for longitude (reverse some params and you're there...)
      }
  }
  </code></pre>
  
  <p><strong>EDIT:</strong> Adding a DB Dump image. Shows empty latitude, longitude.</p>
  
  <p><a href="https://i.stack.imgur.com/492st.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/492st.png" alt="Empty latitude/longitude"></a></p>
  
  <p><strong>EDIT2:</strong> When I remove <code>'allow_empty' =&gt; true,</code> from the <code>AddressFieldsetInputFilter</code> inputs and fill a single input (latitude or longitude), then it validates correctly, unless you leave both inputs empty, then it breaks off immediately to return that the input is required. (<code>Value is required and can't be empty</code>).</p>