Not sure if it's exactly the reason, but
->increment() works on a single model object, in your case ->get() result is a collection
Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.
Currently trying to update an order logic, where you have a list with points in it:
A: order: 0
B: order: 1
C: order: 2
If I now place a point D above C, D gets the order value of 2.
How do I increment the order value of C to 3 now?
Current solution (not working):
$update = $point->update([
'order' => $request->order, // 2
]);
$points_equal = $list->points()->where('order', '==', $request->order)->get();
$test = $points_equal->increment('order'); // should be 3
Basically, if I place a point in the list, I need to update the order of the remaining points to be correct based on the change. $request->order equals the newly put point.
Not sure if it's exactly the reason, but
->increment() works on a single model object, in your case ->get() result is a collection
Could be part of the problem. But when I think about it - $points_equal would contain two records the newly placed in D, as well as C. So incrementing both wouldn't make sense in the order as they both would resolve to 3, instead of 2.
Any idea on how I could create a logic where I place D in the order, and update the other points accordingly?
@splendidkeen you might benefit from looking at this without the db side to understand what your expectation is first, and also using a larger data set:
in your example you are returning a single result and hoping to increment it, but if your list contained more data, what would your code look like for the following?
A: order: 0
B: order: 1
C: order: 2
D: order: 3
E: order: 4
and you wanted to add another point: F
You'd have
A: order: 0
B: order: 1
F: order: 2
C: order: 3
D: order: 4
E: order: 5
How in your front end are you ordering the points before you send to the back end. if its by some drag/ drop you may be best serialising the whole list and starting your ordering from zero again.
or converting it to a collection, reorder using splice and saving it back to the join table again.
see https://laravel.com/docs/7.x/collections#method-splice
BTW this kind of problem is the perfect excuse to write a unit test, especially as you know what your inputs and expectations are.
@automica - That is exactly what I am currently thinking about.
I am ordering them through creating them. If I add a new point to a list: let order = this.lists[id].points.length
Currently I am doing it this way, which basically is missing the adjustment of the other points, resolving in duplicate key errors:
changeOrder(data) {
let toPoint = data.to
let fromPoint = data.from
let order = data.newIndex == data.oldIndex ? false : data.newIndex
}
If your records are already sequentially ordered, and the new entry has an index of 2 then you need to get all records with index of 2 or more and then increment each of them.
So, new record is stored as 2, 2 becomes 3, 3 becomes 4 etc
@snapey - Increment them before updating the new record, right? I had problems with incrementing them being a collection, how would I do that foreach equal to/ or larger than $request->order ?
It works - thanks.
Correction: This is not the best solution, as I end up with orders like:
$list->points()->where('order', '>=', $request->order)->get()->each(function ($point) {
$point->increment('order');
}):
A: order: 2
B: order: 4
D: order: 1
C: order: 6
which then won't work anymore in terms of $this->points()->orderBy('order')->get()
How could I serialize every points in a list, after dragging a point into it?
This ends up in the same behavior: See this order:
A: order: 0
B: order: 1
C: order: 2
D: order: 3
If I now place C above B, I end up with:
A: order: 0
C: order: 1
B: order: 2
D: order: 4
If I now place C above A, I end up with:
C: order: 0
A: order: 1
B: order: 3
D: order: 5
If I now place D above B, I end up with:
C: order: 0
A: order: 1
D: order: 2
B: order: 4
But if I place e.g. A below D now, this won't work - because the multiple increments before are greater than the change.
I see now. Can you try this..
$order_increment = $request->order;
$list->points()->where('order', '>', $request->order)->get()->each(function ($point) use (&$order_increment) {
$point->order = $order_increment++;
$point->save();
}):
Unfortunately, this won't work. Even with '>=' it doesn't work.
Did you get this part right?
use (&$order_increment)
What were your results?
Yes - D will remain 2, just like C, when putting it above C.
I do have to work now, and will think about a way of serializing the whole list, after every change. Will continue later.
Because if you change multiple lines in one list, it ends up being incremented to a scale where it will be always bigger than another points order.
Thank you for the help @davidifranco - maybe we can catch up later
why does it matter if there are gaps, as long as they are numerically sortable?
ref
But if I place e.g. A below D now, this won't work - because the multiple increments before are greater than the change.
it depends what value you give A. Are you putting A below D (give it the order of D +1) ordoes your view give it the same order as the one after D, ie, the slot you are taking.
I think you need to consider how your view works
That is not the problem - the problem is if the gap is too large.
But if I place e.g. A below D now, this won't work - because the multiple increments before are greater than the change.
I guess I will retry this one later:
use (&$order_increment)
you miss the point. The size of the gaps should be irrelevant
If in the view, you simply sequentially order the items then yes you will have a problem, but if you give the view elements the actual order value then there should be no range problem
@splendidkeen when I've used ordering before, its often been helpful to make them increments of 10 rather than 1.
that would allow you to place something between
A: 10
B: 20
C could easily be added as 15 and you'll still retain your order.
once ordering is complete, reorder the whole group and then you can set your increments to multiples of 10.
@automica - Interesting, how would I reorder the whole group and why?
@splendidkeen another thing to consider is why not treat the line as an object in itself. i'm not sure of your usage of this, but if you had many lines, you could save the points and their order as json and have one row per line.
@automica - On your second idea: I already treat a line as an object itself. Because there are two lines per row. C is coming basically from the second line, which is working fine. Just looking for a solution for the order trait.
What you are doing in the view is critical to this discussion....
@splendidkeen what I mean by 1 line per row is the row in the db table. Would love to see what your front end is doing as that will inform the best way to deal with storing the data,
@automica - Thanks for coming back. What you mean exactly by front end in this case?
List 1: List 2:
A: order: 0 E: order: 0
B: order: 1 F: order: 1
C: order: 2 G: order: 2
D: order: 3 H: order: 3
Seeing the structure above, if I was to put F in line 1, how would I restructure the order of every point in line 1, according to the new point?
Put it where, and what order value are you presenting with it?
@splendidkeen front end as in the bit that the user interacts with (in your browser) and where you are posting from.
regarding your points, I assume you are plotting points on an x,y axis? If they are, surely you can treat these lines separately as (theoretically) line A and line B could have exactly the same points.
What relationship is there between line 1 and line 2?
@automica - Line 1 and line 2 are on the same page. List 1 and 2 actually. Had a typo there.
Again, when changing points, they will always take the order of the place they are put in, starting from 0. Problem occurs when there has been incremental order changes within one list, and the order amount is too great, to put it e.g. above the newly put in point. It will then just remain in the same place, after a refresh, logically.
Currently using:
$list->points()->where('order', '>=', $request->order)->get()->each(function ($point) {
$point->increment('order');
});
I can help but you are ignoring my questions. This is trivial to fix and requires that you pass back the position you want the item to be in relative to the others, and using their current order and not just a sequential count.
@snapey - Haven't seen this one:
Put it where, and what order value are you presenting with it?
Put it in list 1, and as mentioned the order value will be the place you put the point to:
let order = data.newIndex == data.oldIndex ? false : data.newIndex
You would rather take on the order amount of the point you replace?
Say you have these values in the model
So if you list these in ascending order then all is fine, they are listed correctly.
But in the view, if you number them 0,1,2,3 and then swap 2 and 3 then you won't get the result you want because entries of 2 and 3 in the database are actually order values of 3 and 5
My point was, if you number them in the view, 0,2,3 and 5 and you move C above D then you give C the value of D (3, the one it replaces) and D then gets the order value 4.
@snapey - That would be good.
Plus I would also need to change the logic, when I create a point - which currently just counts the length of a list for the order amount. Here, I would probably get the highest order within the list and increment it.
Please or to participate in this conversation.