Skip to content

[5.1] Example of recently inserted state tracking#9746

Merged
taylorotwell merged 2 commits intolaravel:5.1from
atrauzzi:add-inserted-state
Jul 30, 2015
Merged

[5.1] Example of recently inserted state tracking#9746
taylorotwell merged 2 commits intolaravel:5.1from
atrauzzi:add-inserted-state

Conversation

@atrauzzi
Copy link
Copy Markdown
Contributor

Fairly trivial, but I think this could be helpful in many scenarios.

Closes #9745.

Fairly trivial, but I think this could be helpful in many scenarios.

Closes #9745.
@Anahkiasen
Copy link
Copy Markdown
Contributor

That would be very useful

@atrauzzi
Copy link
Copy Markdown
Contributor Author

And of course, anyone is open to suggest a better name for the variable ;)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Minor indentation issue here

@brunogaspar
Copy link
Copy Markdown
Member

I like the idea.

@GrahamCampbell GrahamCampbell changed the title Example of recently inserted state tracking [5.1] Example of recently inserted state tracking Jul 24, 2015
@taylorotwell
Copy link
Copy Markdown
Member

What were the use cases for this?

@deefour
Copy link
Copy Markdown
Contributor

deefour commented Jul 24, 2015

If I understand correctly, this would help for places we don't want to hook some created event in an observer; where inlining the conditional functionality is just fine. #9745 outlines an entirely different use.

function persist(Podcast $podcast, array $attrs) {
  $podcast = $podcast ?: new Podcast;

  $podcast->forceFill(array_only($attrs, [ 'title', 'url' ]));

  $podcast->save();

  if ($podcast->recent) {
    // do something with $podcast that required it
    // already being saved to the db, but only when
    // it was just created.
  }
}

Setting a flag up front is currently necessary.

function persist(Podcast $podcast, array $attrs) {
  $podcast  = $podcast ?: new Podcast;
  $creating = ! $podcast->exists; // Need to set a flag here; this PR makes this unecessary

  $podcast->forceFill(array_only($attrs, [ 'title', 'url' ]));

  $podcast->save();

  if ($creating) {
    // ...
  }
}

@atrauzzi
Copy link
Copy Markdown
Contributor Author

Without functionality along these lines, repetitive blocks using firstOrNew are required at a very high layer. Which I feel is a lot of defensive coding for metadata that has nowhere else to live.

In our case, we need it to respond with HTTP 200 or 201. So with this feature, we could do things like this:

return new JsonResponse($model, $model->recent ? 201 : 200);

However, producing the same state without having Eloquent accumulate it (similar to exists) would force the implementation to do all data manipulation at the same level as the check -- or require an ugly sidechannel for the extra metadata, causing unfortunate design problems:

$data = Model::firstOrNew($attributes)

if($data->exists) {
    $recent = false;
}
else {
    $recent = true;
    $data->save();
}

return new JsonResponse($model, $recent ? 201 : 200);

Which is not ideal as the state has to be inferred manually at the time the store/update functionality is used. While it produces the same end result, firstOrNew and JsonResponse shouldn't be required to exist at the same layer.

As I mentioned earlier, if you want $recent anywhere outside of where this check occurs, you have to somehow bundle it with the model. Which hopefully justifies having the model track that state internally as a conveneince.

:)

@lukasgeiter
Copy link
Copy Markdown
Contributor

I think the variable could be a bit more self-explanatory. What about recentlyCreated?

@atrauzzi
Copy link
Copy Markdown
Contributor Author

@lukasgeiter - I'd like to see if there is a different name that is more specific, although it might be nice to keep it as short as possible. Let's wait for as many suggestions as we can get :)

@GrahamCampbell
Copy link
Copy Markdown
Collaborator

This feature would be really useful to me too. 👍

@GrahamCampbell
Copy link
Copy Markdown
Collaborator

My use case is working out if a user has signed up.

@dtaub
Copy link
Copy Markdown
Contributor

dtaub commented Jul 25, 2015

What about new for the variable name? It's concise and (imo) better conveys the fact that the record was newly created. recent almost sounds like it's checking for some arbitrary age, whereas new implies it was created just now on the current request.

@Anahkiasen
Copy link
Copy Markdown
Contributor

Isn't new a reserved keyword though?

@GrahamCampbell
Copy link
Copy Markdown
Collaborator

Isn't new a reserved keyword though?

No, not for properties. I tried it out too just to be sure.

@Anahkiasen
Copy link
Copy Markdown
Contributor

Then in that case I'd prefer new too I think, better conveys the intent than recent

@lukasgeiter
Copy link
Copy Markdown
Contributor

👍 for new. But what would its initial value be when you create a fresh model instance?

@GrahamCampbell
Copy link
Copy Markdown
Collaborator

Yeh.

@dtaub
Copy link
Copy Markdown
Contributor

dtaub commented Jul 25, 2015

@Anahkiasen Yeah, I was thinking it might be reserved, too, but double checked before posting. The only issue that crossed my mind was that to someone used to Ruby, it might kinda look like it's creating a new instance, but that's kind of a stretch.

@arrilot
Copy link
Copy Markdown
Contributor

arrilot commented Jul 25, 2015

I would have gone even further - isNew because we already have a verb exists

if ($model->exists) {
...
}

if ($model->isNew) {
...
}

@dan-har
Copy link
Copy Markdown
Contributor

dan-har commented Jul 25, 2015

I think it is bad to add more public properties to the model, it can make conflicts with the dynamic properties, for example if i have a column 'new' or 'recent' inside a table. It should be a protected property that is accessed by a public method.

@dtaub
Copy link
Copy Markdown
Contributor

dtaub commented Jul 25, 2015

Yeah, it would be pretty standard to have a protected property new and access it using isNew(). No point in making it public.

@atrauzzi
Copy link
Copy Markdown
Contributor Author

@GrahamCampbell @taylorotwell -- Let me know what you guys would prefer to see and I'll amend my MR.

@GrahamCampbell
Copy link
Copy Markdown
Collaborator

@atrauzzi It's totally up to @taylorotwell. :)

@atrauzzi
Copy link
Copy Markdown
Contributor Author

For sure, @taylorotwell - Whatcha think? :)

@taylorotwell taylorotwell merged commit a3ff186 into laravel:5.1 Jul 30, 2015
@taylorotwell
Copy link
Copy Markdown
Member

Renamed it to wasRecentlyCreated to make it a little longer and less likely to collide.

@atrauzzi
Copy link
Copy Markdown
Contributor Author

👍 Awesome!

@hauthorn
Copy link
Copy Markdown

I'm not sure to write this here.
This addition does make some testing using Laravels "assertViewHas" fail tests.

See my gist here for an explanation: https://gist.github.com/hauthorn/fb1494c3ba5238283acc

This didn't fail before. Now it does.

Do I use the "assertViewHas" in some inappropriate way, or is this an unintended consequence of the change?

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.