title: How do I access the originally submitted data of a Symfony form?
body: <p>I'm working with some Symfony forms and need to access the originally submitted (untouched) data. The data accessor methods <code>$form-&gt;getData()</code>, <code>$form-&gt;getViewData()</code> and <code>$form-&gt;getModelData()</code> all give me the already transformed values, but I need the data as in the <code>PRE_SUBMIT</code> event.</p>
  
  <p>I could write a listener and extract them on <code>PRE_SUBMIT</code>, but then I have to store this information anywhere and access it in my service working with the form. For now, my service sees only the passed form object and does its work with no other dependencies.</p>
  
  <p>Other workarounds involve reading from the request object. Doesn't look like a smart option, because the form may be filled from other sources (like the session, it is a filter form).</p>
  
  <p>Is there an "official" way to access the originally submitted data directly from the form object? If not, would it be worth a feature request? Any opinions on that?</p>
  
  <p>(My usecase is a filter form, where the state is stored in and retrieved from the session. Since the form may be submitted without data coming from the request involving modes for HTML-POST, HTML-GET and JSON-POST, I don't want to just store the request data.)</p>
  
  <p>Edit 2018-06-07: As requested in the comments, I provide a code example:</p>
  
  <pre><code>/**
   * handles the filterForm request reading POST-data or namespaced JSON payload with POST method or any standard form request
   *
   * @param FormInterface $filterForm
   * @return void
   * @throws ResponseException
   */
  public function handleRequest(FormInterface $filterForm): void
  {
      // reset the filter state in the session, if a reset_filter query parameter was set
      if (true === $this-&gt;request-&gt;query-&gt;getBoolean('reset_filter', false)) {
          $this-&gt;setFilterState(null, $this-&gt;request-&gt;attributes-&gt;get('_route'));
          $this-&gt;filterIsActive = true;
      }
  
      // handle filter submission in json context
      if ($this-&gt;request-&gt;isMethod('POST') &amp;&amp; $this-&gt;request-&gt;attributes-&gt;get('_format') === 'json') {
          if ($this-&gt;request-&gt;get($filterForm-&gt;getName())) {
              $submitData = $this-&gt;request-&gt;get($filterForm-&gt;getName());
          }
          else {
              $postData = JsonHelper::parseAndCheckJsonPostData($this-&gt;request);
              if ($postData instanceof Response) {
                  throw new ResponseException($postData);
              }
              $submitData = $postData[$filterForm-&gt;getName()] ?? null;
          }
          if (null !== $submitData) {
              dump($submitData);
              $filterForm-&gt;submit($submitData, true);
              dump($filterForm-&gt;getData());
          }
      }
      else {
          // @todo find a smooth way to get the original submitted data of a form, when it is handled by the default handleRequest()-menthod
          $submitData = null;
          $filterForm-&gt;handleRequest($this-&gt;request);
      }
  
      // load the filter state from the session and submit it, if it is not yet set and we are in HTML context
      if (!$filterForm-&gt;isSubmitted()
          &amp;&amp; $this-&gt;request-&gt;attributes-&gt;get('_format') === 'html'
          &amp;&amp; null !== $this-&gt;getFilterState($this-&gt;request-&gt;attributes-&gt;get('_route'))
      ) {
          $filterForm-&gt;submit($this-&gt;getFilterState($this-&gt;request-&gt;attributes-&gt;get('_route')));
      }
  
      if ($filterForm-&gt;isSubmitted()) {
          $this-&gt;filterIsActive = true;
  
          // return an JSON error-document, if the filter form is not valid
          if (!$filterForm-&gt;isValid() &amp;&amp; $this-&gt;request-&gt;attributes-&gt;get('_format') === 'json') {
              throw new ResponseException(
                  new JsonResponse([
                      'type' =&gt; 'error',
                      'message' =&gt; $this-&gt;translator-&gt;trans('Form.Filter.errorMessage'),
                      'filterForm' =&gt; $this-&gt;serializer-&gt;normalize($filterForm-&gt;createView()),
                  ], Response::HTTP_BAD_REQUEST)
              );
          }
  
          // store the new filter state, if filter is active and and valid
          if ($filterForm-&gt;isValid() &amp;&amp; null !== $submitData) {
              $this-&gt;setFilterState($submitData, $this-&gt;request-&gt;attributes-&gt;get('_route'));
          }
      }
  }
  </code></pre>
  
  <p>Outputs this:</p>
  
  <pre><code>array:4 [▼
      "singleEntity" =&gt; "1"
      "multipleEntities" =&gt; array:1 [▼
          0 =&gt; "1"
      ]
      "dateRange" =&gt; array:2 [▼
          "left_date" =&gt; "06.06.2018"
          "right_date" =&gt; "07.06.2018"
      ]
      "submit" =&gt; true
  ]
  
  array:11 [▼
      "singleEntity" =&gt; MySingleEntity {#3739 ▶}
      "facilities" =&gt; ArrayCollection {#3419 ▼
          -elements: array:1 [▼
              0 =&gt; MyMultiEntity {#3799 ▶}
          ]
      }
      "createdOrUpdatedBetween" =&gt; array:2 [▼
          "left_date" =&gt; DateTime @1528236000 {#3408 ▼
              date: 2018-06-06 00:00:00.0 Europe/Berlin (+02:00)
          }
          "right_date" =&gt; DateTime @1528322400 {#3397 ▼
              date: 2018-06-07 00:00:00.0 Europe/Berlin (+02:00)
          }
      ]
  ]
  </code></pre>