Skip to content
This repository was archived by the owner on Jan 21, 2020. It is now read-only.

Conversation

@rkeet
Copy link
Contributor

@rkeet rkeet commented Sep 19, 2018

Provide a narrative description of what you are trying to accomplish:

  • Are you creating a new feature?
    • Why is the new feature needed? What purpose does it serve?

Issue #59 - When not using raw data (so filtered) and having requirements on the Entities (logically), the issue can exist that null values get attempted to be hydrated.

Filtering the data (by not using raw data), causes all keys for of all InputFilter's to be added to the data array which gets passed to the DoctrineObject hydrator in the current happy flow.

This PR gives an additional option: filter out the null values.

  • How will users use the new feature?

Same as use_raw_data and allows_only_fields_in_filter -> create config key with true value.

  • Base your feature on the develop branch, and submit against that branch.
  • Add only one feature per pull request; split multiple features over multiple pull requests
  • Add tests for the new feature.
  • Add documentation for the new feature.
  • Add a CHANGELOG.md entry for the new feature.

Acceptance criteria

  • Provide config flag to filter out null values
  • Filter out null values when flag set to true
  • Do not filter out null values from request (received) data, this is intentionally send and might be intended for optional value

This may not be the greatest solution, I'm open to suggestions/requests for improvement.

However, consider that this added bit does not change the current implementation, it just adds the possibility to filter out the null/empty values of a received data array.

It does not contain a bc-break as it must be enabled with config, the same way as 2 existing options.

…ter the data, added function to determine config setting, added overwriting of data with filtered data if key set and true in config.
…out the key - adds what it does and how to set it
@coveralls
Copy link

coveralls commented Sep 19, 2018

Coverage Status

Coverage increased (+2.6%) to 81.513% when pulling c9fd599 on rkeet:feature/remove-empty-data into c36b369 on zfcampus:develop.

…ional checks for empty data on response of recursive calls to prevent possibility of returned empty array being left in final response.
if (empty($value)) {
unset($data[$key]);
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be simplified a ton:

foreach ($data as $key => $value) { if (! is_array($value) && ! empty($value)) { continue; } if (! is_array($value)) { unset($data[$key]); continue; } if (empty(array_filter($value, $removeNull))) { unset($data[$key]); continue; } $tmpValue = $this->removeEmptyData($value); if (empty(array_filter($tmpValue, $removeNull))) { unset($data[$key]); continue; } $data[$key] = $tmpValue; }

You don't need to unset $tmpValue as it gets re-assigned when the appropriate conditional occurs. By flattening the structure, we can better understand the various paths through the loop, which will make testing easier.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah thank you, will have a look at it again soon. Atm pushing deadlines, so might be a wee while.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

$this->assertEquals($params, $dataParams->getBodyParams());
}

public function testFilterEmptyEntriesFromDataByOptionWithNestedData()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are five different paths through the removeEmptyData() method, corresponding to five different conditions that can occur. You'll need five tests to fully exercise the method and verify it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will have another look. Was thinking today it wasn't enough, but as tests passed and I'm pushed for time, I was thinking of coming back to it.

@rkeet
Copy link
Contributor Author

rkeet commented Nov 1, 2018

Woke up with the realization that this PR is slightly off at the moment. Will have to modify it some more (apart from @weierophinney's comments thus far).

E.g. an address: "Farmroad 3a", consists of 2 required (street, number) and 1 optional (addition) values.

But, the address was a typo, should've been "Farmroad 3". As addition is optional, it's nullable. So a patch request might contain just:

PATCH /address/2

{ "addition":null } 

As such, I need to add in functionality to compare the data from which null's need to be removed against the data received in the request. This to ensure that data which should be hydrated as null does not get removed.


(btw, posting that here so I don't forget. I'm aiming to pick this up today or tomorrow, but it's busy at the office.)

…t compatible with PHP < 7 and added TODO lines (2) for when module is bumpted to PHP > 7. Added comparisonData variable to onRoute function, later used for removeEmptyData, but it keeps unfiltered data instead of being overwritten at a later point.
@rkeet
Copy link
Contributor Author

rkeet commented Nov 1, 2018

Must still update the tests

@rkeet rkeet force-pushed the feature/remove-empty-data branch from a57d74f to 5084634 Compare November 1, 2018 14:21
…ived data (compareTo) - current situation deleted them in next if statement - this is all in ContentValidationListener.
Copy link
Member

@weierophinney weierophinney left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rkeet I see you're still adding to this, so I did a quick review of what's here, and made a few more suggestions. In addition, I still need the tests I suggested before I can review to merge and release.

Thanks for all the great work so far!

* @return array
*/
// TODO strict types for PHP > 7 when module gets bumped
// protected function removeEmptyData(array $data, array $compareTo = []) : array
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Put this in the docblock, above the @param annotations, as an @todo annotation, please.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

protected function removeEmptyData($data, $compareTo = [])
{
// TODO when bumped to PHP > 7 and strict types above enforced this check may be removed
if (! is_array($data) || ! is_array($compareTo)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PHP 5.6 allows us to use the array typehint for arguments.; we do not need to wait for PHP 7 here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

$removeNull = function ($value, $key = null) use ($compareTo) {
// If comparison array is empty, do a straight comparison
if (empty($compareTo)) {
return ! is_null($value);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We tend to use the construct null !== $value.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

return true;
}

return ! is_null($value);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment here: null !== $value

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

$tmpValue = $this->removeEmptyData($value, $compareTo[$key]);
} else {
$tmpValue = $this->removeEmptyData($value);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could become:

$tmpValue = array_key_exists($key, $compareTo) && is_array($compareTo[$key]) ? $this->removeEmptyData($value, $compareTo[$key]) : $this->removeEmptyData($value);

Ternary assignments are nice for this kind of either/or thing, and make reading the code easier.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

…ary. Replaced '! is_null()' with 'null !== '.
@rkeet
Copy link
Contributor Author

rkeet commented Feb 3, 2019

TODO

  • Unit testing through added functionality (current tests pass, but do not cover all use cases)
rkeet added 2 commits February 3, 2019 20:36
…tionality for creatoin of listener and event into own functions, re-used for all 5 test functions
@rkeet
Copy link
Contributor Author

rkeet commented Feb 3, 2019

I think I've got it all covered now. Please do check.

@rkeet
Copy link
Contributor Author

rkeet commented Feb 25, 2019

Small ping @weierophinney

- Removed unnecessary import statement. - Simplified conditional in `shouldRemoveEmptyData()` to remove redundant `isset` check. - Removed `@todo` annotations that detail future signature changes; these will happen regardless. - Add parameter types to annotations where necessary. - Remove unnecessary parens. - Remove unnecessary whitespace.
- Extracts the `booleanProvider` for use with `testFilterEmptyEntriesFromDataByOptionWhenValueBooleanNotInComparison()` test case. - Moves annotations to the end of method docblocks. - If the only argument is an array, moves opening brace to same line as method invocation. - Ensure arrays have trailing commas.
Copy link
Member

@weierophinney weierophinney left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've pushed a few minor consistency changes, mostly around formatting; otherwise, this is ready to go!

Thanks, @rkeet !

@weierophinney weierophinney merged commit c9fd599 into zfcampus:develop Feb 26, 2019
@diego-sorribas
Copy link

Hello, I have found some problems in my api with this new PR. I have some forms that send zero value and this new PR unset me the body param. Its that ok? I need to set remove_empty_data in my config for every controller? Im using Apigility.

protected function shouldRemoveEmptyData($controllerService)
{
if (! isset($this->config[$controllerService]['remove_empty_data'])
|| $this->config[$controllerService]['remove_empty_data'] === true
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This condition is wrong, please see #104 and #105.

@michalbundyra
Copy link
Member

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

6 participants