Skip to content
This repository has been archived by the owner on Dec 10, 2018. It is now read-only.

Adding dynamic accessors and mutators from $uuidAttributes and customising uuid text attribute suffix #49

Merged
merged 22 commits into from
Aug 8, 2018

Conversation

isocroft
Copy link
Contributor

@isocroft isocroft commented Aug 6, 2018

This PR references this PR by @westphalen and also this issue #45 and #33 . It also makes the default uuid text attribute suffix customizable with support for composite keys without breaking original code. Details are on README.md file on this PR branch.

Thanks in anticipation.

Copy link
Contributor

@brendt brendt left a comment

Choose a reason for hiding this comment

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

Great, thanks for the PR! There are a few naming issues I'd like to be solved, and I also had some implementation questions. Overall, it seems like a good way forward!

One major remark though: you should also add tests for this new feature!

Can you confirm that all the old code will keep working the way it did? Otherwise we're looking at a major version bump. Nothing wrong with that, but if it's the case, I'm also going to add another breaking change, and than this PR should target the v2 branch.


$array = parent::toArray();

// if (! $this->exists) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's clean this up :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Alright

// return $array;
// }

if (is_array($uuidAttributes)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd prefer an early return here. if (! is_array()) { return ... }

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes, you're right and i will do this... very good refactor suggestion


if (is_array($uuidAttributes)) {
foreach ($uuidAttributes as $attributeKey) {
if (array_key_exists($attributeKey, $array)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Also here, an early return allows for better readability:

if (! array_key_exists()) {
    continue;
}

return $array;
}

public function getRelatedBinaryKeyName($attrib)
Copy link
Contributor

Choose a reason for hiding this comment

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

Use the full name $attribute, no need to use shortened names, they make things more confusing for people reading the code.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Exactly... totally agree


public function getAttribute($key)
{
if (($uuidKey = $this->uuidTextAttribute($key)) && $this->{$uuidKey} !== null) {
Copy link
Contributor

Choose a reason for hiding this comment

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

To make this more readable, you should avoid assignment in an if statement:

$uuidKey = $this->uuidTextAttribute($key);

if ($uuidKey && $this->{$uuidKey} !== null)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes true

README.md Outdated
*
* @var
*/
protected $uuidTextAttribSuffix = '_str';
Copy link
Contributor

Choose a reason for hiding this comment

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

This can be a more clear name. Possibly uuidSuffix ? Also see further down for more feedback on this name.

Copy link
Collaborator

Choose a reason for hiding this comment

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

uuidSuffix is not clear to me. uuidTextAttribSuffix sounds clumsy. I would suggest textUuidSuffix or textualUuidSuffix.

Additionally, would this belong to configuration or model? Recently in a PR for laravel-status, @freekmurze made me use a configuration option for attribute names. You may want to look at your other packages to get something consistent in the whole Spatie ecosystem :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I was actually stuck between trying to make the property name meaningful while keeping it shortest. You're totally right. This is better


$key = $this->getKeyName(); // ! composite primary keys will return an array

if (is_string($key)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this check can be removed by simply casting $key to an array:

$key = (array) $this->getKeyName();

$uuidAttributes = array_merge($uuidAttributes, $key);

$uuidAttributes = [];

if (property_exists($this, 'uuidAttributes')) {
$uuidAttributes = $this->uuidAttributes === null ? [] : $this->uuidAttributes;
Copy link
Contributor

Choose a reason for hiding this comment

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

$uuidAttributes = $this->uuidAttributes ?? [];

should work

Copy link
Contributor Author

Choose a reason for hiding this comment

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

okay

$uuidAttributes = $this->uuidAttributes === null ? [] : $this->uuidAttributes;
}

$key = $this->getKeyName(); // ! composite primary keys will return an array
Copy link
Contributor

Choose a reason for hiding this comment

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

What if the user also specified the primary key name in $uuidAttributes, shouldn't doubles be filtered out?

Copy link
Contributor Author

@isocroft isocroft Aug 7, 2018

Choose a reason for hiding this comment

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

The array_unique(array_merge($uuidAttributes, $key)); call will be used to filter out the duplicate(s) going by the way array_unique works

return (property_exists($this, 'uuidTextAttribSuffix')) ? $this->uuidTextAttribSuffix : '_text';
}

protected function uuidTextAttribute($key)
Copy link
Contributor

Choose a reason for hiding this comment

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

Do I understand this code correctly that when calling $model->uuid_text, the actual property's name is calculated, so the return value would actually be the textual version value of the primary key? You're adding this as a shortcut, I suppose?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not a shortcut per say. What i'm doing here is to avoid hard coding ->uuid_text to the property name for textual UUIDs and to also make it customizable to that developers can choose another property name suffix apart from '_text'

Copy link
Contributor

Choose a reason for hiding this comment

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

yeah, that's fine.

@vpratfr
Copy link
Collaborator

vpratfr commented Aug 7, 2018

To take this closer to Eloquent way of naming stuff, instead of protected $uuidAttributes, I would simply have protected $uuids

Just like we already have : protected $casts or protected $dates

@brendt
Copy link
Contributor

brendt commented Aug 7, 2018

Good point, though the correct name would be binaryUuids, no?

@vpratfr
Copy link
Collaborator

vpratfr commented Aug 7, 2018

It is unlikely that you store binary and string UUIDs at the same time in the model. So I would go with the shortest option for simplicity.

@isocroft
Copy link
Contributor Author

isocroft commented Aug 7, 2018

@brendt The only previously existing method in the HasBinaryUuid trait that was modified by this PR is toArray() and the modification was done transparently. The main aim of this modification was to provide for 3 things without changing the way toArray() originally worked before.

  • Add support for other uuid columns in the table for any Model using HasBinaryUuid besides the primary key uuid to be decoded to their UUID textual representation.
  • Add support for composite primary keys on any Model which happen to be uuids.
  • Add support for custom suffix for textual UUID property name(s) or attributes.

All other code modifications are additions/insertions that do not interact with previously existing methods in a stateful way. In the event that a developer duplicates related or primary keys in the $uuids array or in a composite primary key, all duplicates are removed before decoding commences.

I have adapted my code to the reviews given by @brendt and have included tests for the all features i have added. Also, this PR does not introduce any breaking changes. Therefore, the changes can still be released under the 1.x.x versioning line.

@vpratfr
Copy link
Collaborator

vpratfr commented Aug 7, 2018

Are there any tests to check that it still works as expected with custom suffix, toArray serialization of attributes, etc. ?

@isocroft
Copy link
Contributor Author

isocroft commented Aug 7, 2018

Yes there are tests to check the custom suffix @vpratfr .

@isocroft
Copy link
Contributor Author

isocroft commented Aug 8, 2018

Any merge for this PR coming soon ?

@brendt
Copy link
Contributor

brendt commented Aug 8, 2018

Yes.

@brendt brendt merged commit b4e6802 into spatie:master Aug 8, 2018
@brendt
Copy link
Contributor

brendt commented Aug 8, 2018

@isocroft
Copy link
Contributor Author

isocroft commented Aug 8, 2018

Super!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants