https://media.notthebee.com/articles/67335aafcbba967335aafcbbaa.jpg
This is almost too sad to watch, but it’s worth it for the punchline at the end of this video.
Not the Bee
Just another WordPress site
https://media.notthebee.com/articles/67335aafcbba967335aafcbbaa.jpg
This is almost too sad to watch, but it’s worth it for the punchline at the end of this video.
Not the Bee
Don’t have time to read Efficient MySQL Performance?
Here’s the book (10 chapters) in one-liners.
Planet MySQL
https://www.ammoland.com/wp-content/uploads/2024/11/313899079_675017000648466_2950238684783824927_n-500×326.jpg
“The race is on to replace JD Vance in the U.S. Senate,” WEWS statehouse reporter Morgan Trau noted Wednesday, following the Trump/Vance ticket’s presidential election victory. “[Ohio Governor Mike] DeWine has a big decision to make. Vance will need to resign from his coveted Senate seat, and the governor will appoint his replacement.”
“I’ll look for someone who wants to get things done every day and will stay focused on it,” DeWine had told Trau in July. “We also have to have someone who will be able to stay there a while.” And, according to Republican strategist Bob Clegg, he may “choose someone with more in common with his own ideology and mild-mannered personality.”
That would not be the best outcome for a number of reasons. Note the qualities of “get[ting] things done” is silent on what things, and DeWine’s on again/off again affinities for citizen disarmament edicts show a politician who views the right to arms as a political expedient rather than a keystone for freedom. In short, he’s gone from engendering headlines like “Principled Statesman Mike DeWine Endorsed by Brady Campaign” to being endorsed by NRA. After a mass shooting in Dayton, he returned to his gun-grabber roots stumping for supposedly “bipartisan” infringements, including raising the firearm purchasing age, “expanded background checks,” and so-called “safety protection orders.”
Matt Dolan: “With RINO-Republicans like Ohio’s Matt Dolan, who needs Democrats?” this correspondent asked in a 2022 AmmoLand article. In addition to being “described by CNN as a ‘non-Trump Republican’,” Dolan supports a host of gun prohibitions including raising the purchase age, red flags, and ending private sales.
Troublingly, this is the candidate DeWine endorsed in the race won by Bernie Moreno to unseat Sherrod Brown.
Dave Joyce: He was my congressman until redistricting. NRA gave him an A grade and called him “a solidly pro-gun candidate with a record of support on Second Amendment issues.” Up to a point. By supporting Democrats on the “Bipartisan Safer Communities Act,” he’s placed himself in the “can’t trust anymore” camp.
Mike Carey: “Criminals, the mentally ill, and individuals who are underage should be prevented from buying firearm. It is also important that the laws already on the books are enforced. In addition, maintaining and integrating the databases used to conduct background checks is another important tool to keep guns out of [illegal] hands,” he asserted in 2022. “The Constitution IS absolute and the right of the people to keep and bear arms, shall not be infringed. Strict gun regulations only make things harder for law abiding citizens. In Congress, Mike is working to protect our 2nd Amendment rights by co-sponsoring bills like the RIFLE Act. Mike Carey will always defend your right to bear arms and oppose any legislation that infringes on your rights.”
How he squares enforcing existing Intolerable Acts with “shall not be infringed” has been left unsaid.
Of them all, Ramaswamy is the one with the most national prominence and his relationship with Vance is an added bonus. The main problem: In the above-linked Forbes article, he opined that “background checks are ‘absolutely a legitimate part of the process,’” which disregards that they are a prior restraint infringement.
Per the National Institute of Justice, their “Effectiveness depends on the ability to reduce straw purchasing, requiring gun registration…” And per the Bureau of Justice Statistics, criminals don’t get their guns that way anyway.
The thing is, even with the Trump victory, don’t look for elimination of the National Instant Background Check System (NICS) to be on the table, and none of the other names on the list have called for its repeal, or are likely to. As always, our work to educate not just the public, but legislators receptive to listening, will be ongoing. It’s up to us to ensure they do and to expose those who don’t.
About David Codrea:
David Codrea is the winner of multiple journalist awards for investigating/defending the RKBA and a long-time gun owner rights advocate who defiantly challenges the folly of citizen disarmament. He blogs at “The War on Guns: Notes from the Resistance,” is a regularly featured contributor to Firearms News, and posts on Twitter: @dcodrea and Facebook.
AmmoLand Shooting Sports News
An anonymous reader quotes a report from 404 Media: If you voted in the U.S. presidential election yesterday in which Donald Trump won comfortably, or a previous election, a website powered by a right-wing group is probably doxing you. VoteRef makes it trivial for anyone to search the name, physical address, age, party affiliation, and whether someone voted that year for people living in most states instantly and for free. This can include ordinary citizens, celebrities, domestic abuse survivors, and many other people. Voting rolls are public records, and ways to more readily access them are not new. But during a time of intense division, political violence, or even the broader threat of data being used to dox or harass anyone, sites like VoteRef turn a vital part of the democratic process — simply voting — into a security and privacy threat. […]
The Voter Reference Foundation, which runs VoteRef, is a right wing organization helmed by a former Trump campaign official, ProPublica previously reported. The goal for that organization was to find irregularities in the number of voters and the number of ballots cast, but state election officials said their findings were "fundamentally incorrect," ProPublica added. In an interview with NPR, the ProPublica reporter said that the Voter Reference Foundation insinuated (falsely) that the 2020 election of Joe Biden was fraudulent in some way. 404 Media has found people on social media using VoteRef’s data to spread voting conspiracies too. VoteRef has steadily been adding more states’ records to the VoteRef website. At the time of writing, it has records for all states that legally allow publication. Some exceptions include California, Virginia, and Pennsylvania. ProPublica reported that VoteRef removed the Pennsylvania data after being contacted by an attorney for Pennsylvania’s Department of State. "Digitizing and aggregating data meaningfully changes the privacy context and the risks to people. Your municipal government storing your marriage certificate and voter information in some basement office filing cabinet is not even remotely the same as a private company digitizing all the data, labeling it, piling it all together, making it searchable," said Justin Sherman, a Duke professor who studies data brokers.
"Policymakers need to get with the times and recognize that data brokers digitizing, aggregating, and selling data based on public records — which are usually considered ‘publicly available information’ and exempted from privacy laws — has fueled decades of stalking and gendered violence, harassment, doxing, and even murder," Sherman said. "Protecting citizens of all political stripes, targets and survivors of gendered violence, public servants who are targets for doxing and death threats, military service members, and everyone in between depends on reframing how we think about public records privacy and the mass aggregation and sale of our data."
Read more of this story at Slashdot.
Slashdot
https://s.yimg.com/os/creatr-uploaded-images/2024-11/7d82b710-9c50-11ef-9fff-7061b6a1c803
Stardew Valley on mobile just received its latest update, and in it is a new secret multiplayer mode. Developer ConcernedApe says it’s currently secret because of its experimental nature, and mobile multiplayer can be “frustrating.”
Unlike Stardew Valley multiplayer on other platforms, players on mobile can’t discover others’ farms and can only connect via IP address. They can still join a PC-hosted farm using their mobile devices. The developers also warn that using a mobile network isn’t recommended, as it may not be stable enough. The experience works best when both devices are on the same network, but that’s not compulsory.
To unlock mobile multiplayer, you’ll have to tap the leaves in a specific order. It’s actually part of the Konami code, but without the A and B buttons because, well, smartphones and tablets don’t have them. The Stardew Valley multiplayer blog has instructions if you’re interested.
Once you see the new co-op menu on the screen, you can host or join a farm. You’ll need an IP address if you want to join someone’s farm, but that isn’t difficult to find on your mobile device. The Stardew Valley post also has instructions for that for both iOS and Android users.
This article originally appeared on Engadget at https://www.engadget.com/gaming/stardew-valley-now-has-a-secret-multiplayer-mode-on-mobile-150956438.html?src=rssEngadget
https://media.babylonbee.com/articles/672acda975db4672acda975db5.jpg
U.S. — Donald Trump has defeated Kamala Harris to become the next president of the United States, proving once and for all that Americans are ready to unburden themselves from what has been.
Sources say the unburdening could lead to unprecedented levels of imagining what can be.
"Kamala was a huge burden, but now it’s time for us to be unburdened, more unburdened than ever before," Donald Trump said as he addressed crowds at the Palm Beach Convention Center. "She was so terrible. But now she’s gone. She’s a ‘has-been.’ So sad. Maybe she can work at McDonald’s now."
His supporters roared in approval, hanging onto every word as Trump reminded them of his plans for the first 100 days in office now that the nation has been unburdened from Kamala’s glaring incompetence.
Sources within the Trump campaign say the president wasn’t nervous at all leading up to the election thanks in part to his new spiritual advisors Joe Rogan and Elon Musk. Instead of panicking, Trump reportedly spent most days working on his golf game in between campaign stops and owning libs on Twitter.
At publishing time, Trump’s new efficiency advisor Ron Paul encouraged the nation to imagine what could be if there were no Federal Reserve.
BIG NEWS: We made a movie, and you can watch the trailer NOW:
Click here to find out how you can watch the movie when it releases on October 11
Babylon Bee
https://picperf.io/https://laravelnews.s3.amazonaws.com/featured-images/laravel-pagination.png
Pagination is a common feature in web applications. Almost every Laravel application I’ve ever worked on has had some form of pagination implemented.
But what is pagination and why do we use it? How can we implement pagination in our Laravel applications? And how do we decide which pagination method to use?
In this article, we’re going to answer those very questions and explore how to use pagination in Laravel for both Blade views and API endpoints. By the end of this article, you should feel confident enough to start using pagination in your own projects.
Pagination is a technique used to divide a large dataset into smaller chunks (or pages). It allows you to display a subset of the data, rather than all the possible values at once.
For instance, imagine you had a page that outputs the names of all the users in your application. If you had thousands of users, it wouldn’t be practical to display them all on a single page. Instead, you could use pagination to display a subset of the users (say 10 users at a time) on each page, and allow users to navigate between the pages to view more users (the next 10).
By using pagination you can:
Pagination can typically be split into two different types:
Laravel provides three different methods for paginating Eloquent queries in your applications:
paginate
– Uses offset-based pagination and fetches the total number of records in the dataset.simplePaginate
– Uses offset-based pagination but doesn’t fetch the total number of records in the dataset.cursorPaginate
– Uses cursor-based pagination and doesn’t fetch the total number of records in the dataset.Let’s take a look at each of these methods in more detail.
paginate
MethodThe paginate
method allows you to fetch a subset of data from the database based on an offset and limit (we’ll take a look at these later when we look at the underlying SQL queries).
You can use the paginate
method like so:
use App\Models\User;
$users = User::query()->paginate();
Running the above code would result in the $users
being an instance of Illuminate\Contracts\Pagination\LengthAwarePaginator
, typically an Illuminate\Pagination\LengthAwarePaginator
object. This paginator instance contains all the information you need to display the paginated data in your application.
The paginate
method can automatically determine the requested page number based on the page
query parameter in the URL. For example, if you visited https://my-app.com/users?page=2
, the paginate
method would fetch the second page of data.
By default, all the pagination methods in Laravel default to fetching 15 records at a time. However, this can be changed to a different value (we’ll take a look at how to do this later).
paginate
with Blade ViewsLet’s take a look at how to use the paginate
method when rendering data in a Blade view.
Imagine we have a simple route that fetches the users from the database in a paginated format and passes them to a view:
use App\Models\User;
use Illuminate\Support\Facades\Route;
Route::get('users', function () {
$users = User::query()->paginate();
return view('users.index', [
'users' => $users,
]);
});
Our resources/views/users/index.blade.php
file might look something like this:
<html>
<head>
<title>Paginate</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body>
<div class="max-w-5xl mx-auto py-8">
<h1 class="text-5xl">Paginate</h1>
<ul class="py-4">
@foreach ($users as $user)
<li class="py-1 border-b"></li>
@endforeach
</ul>
</div>
</body>
</html>
The resulting page would look something like this:
Let’s break down what’s happening in the Blade view:
$users
field (the Illuminate\Pagination\LengthAwarePaginator
object) and outputting their name.links
method on the $users
object. This is a really handy method which returns some HTML that displays the pagination links (e.g., "Previous", "Next", and the page numbers). This means you don’t have to worry about creating the pagination links yourself, and Laravel will handle all of that for you.We can also see that the paginate
method is giving us an overview of the pagination data. We can see that we’re viewing the 16th to 30th records, out of a total of 50 records. We can also see that we’re on the second page and that there are a total of 4 pages.
It’s important to note that the links
method will return the HTML styled using Tailwind CSS. If you wish to use something other than Tailwind or you want to style the pagination links yourself, you can check out the documentation on customizing pagination views.
paginate
in API EndpointsAs well as using the paginate
method in Blade views, you can also use it in API endpoints. Laravel makes this process easy by automatically converting the paginated data into JSON.
For instance, we could build an /api/users
endpoint (by adding the following route to our routes/api.php
file) which returns the paginated users in JSON format:
use App\Models\User;
use Illuminate\Support\Facades\Route;
Route::get('paginate', function () {
return User::query()->paginate();
});
Accessing the /api/users
endpoint would return a JSON response similar to the following (please note I’ve limited the data
field to just 3 records for the sake of brevity):
{
"current_page": 1,
"data": [
{
"id": 1,
"name": "Andy Runolfsson",
"email": "teresa.wiegand@example.net",
"email_verified_at": "2024-10-15T23:19:28.000000Z",
"created_at": "2024-10-15T23:19:29.000000Z",
"updated_at": "2024-10-15T23:19:29.000000Z"
},
{
"id": 2,
"name": "Rafael Cummings",
"email": "odessa54@example.org",
"email_verified_at": "2024-10-15T23:19:28.000000Z",
"created_at": "2024-10-15T23:19:29.000000Z",
"updated_at": "2024-10-15T23:19:29.000000Z"
},
{
"id": 3,
"name": "Reynold Lindgren",
"email": "juwan.johns@example.net",
"email_verified_at": "2024-10-15T23:19:28.000000Z",
"created_at": "2024-10-15T23:19:29.000000Z",
"updated_at": "2024-10-15T23:19:29.000000Z"
}
],
"first_page_url": "http://example.com/users?page=1",
"from": 1,
"last_page": 4,
"last_page_url": "http://example.com/users?page=4",
"links": [
{
"url": null,
"label": "« Previous",
"active": false
},
{
"url": "http://example.com/users?page=1",
"label": "1",
"active": true
},
{
"url": "http://example.com/users?page=2",
"label": "2",
"active": false
},
{
"url": "http://example.com/users?page=3",
"label": "3",
"active": false
},
{
"url": "http://example.com/users?page=4",
"label": "4",
"active": false
},
{
"url": "http://example.com/users?page=5",
"label": "5",
"active": false
},
{
"url": "http://example.com/users?page=2",
"label": "Next »",
"active": false
}
],
"next_page_url": "http://example.com/users?page=2",
"path": "http://example.com/users",
"per_page": 15,
"prev_page_url": null,
"to": 15,
"total": 50
}
Let’s break down the JSON response:
current_page
– The current page we’re on. In this case, we’re on the first page.data
– The actual data itself that’s being returned. In this case, it contains the first 15 users (shortened to 3 for brevity).first_page_url
– The URL to the first page of data.from
– The starting record number of the data being returned. In this case, it’s the first record. If we were on the second page, this would be 16.last_page
– The total number of pages of data. In this case, there are 4 pages.last_page_url
– The URL to the last page of data.links
– An array of links to the different pages of data. This includes the "Previous" and "Next" links, as well as the page numbers.next_page_url
– The URL to the next page of data.path
– The base URL of the endpoint.per_page
– The number of records being returned per page. In this case, it’s 15.prev_page_url
– The URL to the previous page of data. In this case, it’s null
because we’re on the first page. If we were on the second page, this would be the URL to the first page.to
– The ending record number of the data being returned. In this case, it’s the 15th record. If we were on the second page, this would be 30.total
– The total number of records in the dataset. In this case, there are 50 records.Using the paginate
method in Laravel results in two SQL queries being run:
So if we wanted to fetch the first page of users (with 15 users per page), the following SQL queries would be run:
select count(*) as aggregate from `users`
and
select * from `users` limit 15 offset 0
In the second query, we can see that the limit
value is set to 15. This is the number of records that are returned per page.
The offset
value is calculated as follows:
Offset = Page size * (Page - 1)
So if we wanted to fetch the third page of users, the offset
value would be calculated as:
Offset = 15 * (3 - 1)
Therefore, the offset
value would be 30 and we would fetch the 31st to 45th records. The queries for the third page would look like so:
select count(*) as aggregate from `users`
and
select * from `users` limit 15 offset 30
simplePaginate
MethodThe simplePaginate
method is very similar to the paginate
method but with one key difference. The simplePaginate
method doesn’t fetch the total number of records in the dataset.
As we’ve just seen, when we use the paginate
method, we also get information about the total number of records and pages available in the dataset. We can then use this information for displaying things like the total number of pages in the UI or API response.
But if you do not intend to display these details to the user (or developer consuming the API), then we can avoid an unneeded database query (that counts the total number of records) by using the simplePaginate
method.
The simplePaginate
method can be used in the same way as the paginate
method:
use App\Models\User;
$users = User::query()->simplePaginate();
Running the above code would result in the $users
being an instance of Illuminate\Contracts\Pagination\Paginator
, typically an Illuminate\Pagination\Paginator
object.
Unlike the Illuminate\Pagination\LengthAwarePaginator
object returned by the paginate
method, the Illuminate\Pagination\Paginator
object doesn’t contain information about the total number of records in the dataset and has no idea how many pages or total records there are. It just knows about the current page of data and whether there are more records to fetch.
simplePaginate
with Blade ViewsLet’s take a look at how you can use the simplePaginate
method with a Blade view. We’ll assume we have the same route as before, but this time we’re using the simplePaginate
method:
use App\Models\User;
use Illuminate\Support\Facades\Route;
Route::get('users', function () {
$users = User::query()->simplePaginate();
return view('users.index', [
'users' => $users,
]);
});
We’ll build our Blade view in the same way as before:
<html>
<head>
<title>Simple Paginate</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body>
<div class="max-w-5xl mx-auto py-8">
<h1 class="text-5xl">Simple Paginate</h1>
<ul class="py-4">
@foreach ($users as $user)
<li class="py-1 border-b"></li>
@endforeach
</ul>
</div>
</body>
</html>
The resulting page would look something like this:
As we can see in this example, the output of $users->links()
is different to the output we saw when using the paginate
method. Since the simplePaginate
method doesn’t fetch the total number of records, it has no context of the total number of pages or records, only whether there’s a next page or not. Therefore, we only see the "Previous" and "Next" links in the pagination links.
simplePaginate
in API EndpointsYou can also use the simplePaginate
method in API endpoints. Laravel will automatically convert the paginated data into JSON for you.
Let’s build an /api/users
endpoint that returns the paginated users in JSON format:
use App\Models\User;
use Illuminate\Support\Facades\Route;
Route::get('users', function () {
return User::query()->simplePaginate();
});
When we hit this route, we’ll get a JSON response similar to the following (I’ve limited the data
field to just 3 records for brevity):
{
"current_page": 1,
"data": [
{
"id": 1,
"name": "Andy Runolfsson",
"email": "teresa.wiegand@example.net",
"email_verified_at": "2024-10-15T23:19:28.000000Z",
"created_at": "2024-10-15T23:19:29.000000Z",
"updated_at": "2024-10-15T23:19:29.000000Z"
},
{
"id": 2,
"name": "Rafael Cummings",
"email": "odessa54@example.org",
"email_verified_at": "2024-10-15T23:19:28.000000Z",
"created_at": "2024-10-15T23:19:29.000000Z",
"updated_at": "2024-10-15T23:19:29.000000Z"
},
{
"id": 3,
"name": "Reynold Lindgren",
"email": "juwan.johns@example.net",
"email_verified_at": "2024-10-15T23:19:28.000000Z",
"created_at": "2024-10-15T23:19:29.000000Z",
"updated_at": "2024-10-15T23:19:29.000000Z"
}
],
"first_page_url": "http://example.com/users?page=1",
"from": 1,
"next_page_url": "http://example.com/users?page=2",
"path": "http://example.com/users",
"per_page": 15,
"prev_page_url": null,
"to": 15
}
As we can see, the JSON response is very similar to the response we got when using the paginate
method. The key difference is that we don’t have the last_page
, last_page_url
, links
, or total
fields in the response.
Let’s take a look at the underlying SQL queries that are run when using the simplePaginate
method.
The simplePaginate
method still relies on the limit
and offset
values to fetch the subset of data from the database. However, it doesn’t run the query to fetch the total number of records in the dataset.
The offset
value is still calculated in the same way as before:
Offset = Page size * (Page - 1)
However, the limit
value is calculated slightly differently than the paginate
method. It’s calculated as:
Limit = Page size + 1
This is because the simplePaginate
method needs to fetch one more record than the perPage
value to determine if there are more records to fetch. For example, let’s say we’re fetching 15 records per page. The limit
value would be 16. So if 16 records were to be returned, we’d know there is at least one more page of data available to fetch. If any less than 16 records were returned, we’d know that we’re on the last page of data.
So if we wanted to fetch the first page of users (with 15 users per page), the following SQL queries would be run:
select * from `users` limit 16 offset 0
The query for the second page would look like so:
select * from `users` limit 16 offset 15
cursorPaginate
MethodSo far we’ve looked at the paginate
and simplePaginate
methods which both use offset-based pagination. We’re now going to take a look at the cursorPaginate
method which uses cursor-based pagination.
As a heads-up, cursor-based pagination might seem a little confusing the first time you come across it. So don’t worry if you don’t quite get it straight away. Hopefully, by the end of this article, you’ll have a better understanding of how it works. I’ll also leave an awesome video at the end of this article that explains cursor-based pagination in more detail.
With offset-based pagination, we use the limit
and offset
values to fetch a subset of data from the database. So we can say "skip the first 10 records and fetch the next 10 records". This is simple to understand and easy to implement. Whereas with cursor pagination, we use a cursor (typically a unique identifier for a specific record in the database) as a starting point to fetch the previous/next set of records.
For example, let’s say we make a query to fetch the first 15 users. We’ll assume the ID of the 15th user is 20. When we want to fetch the next 15 users, we’ll use the ID of the 15th user (20) as the cursor. We’ll say "fetch the next 15 users with an ID greater than 20".
You may sometimes see cursors referred to as "tokens", "keys", "next", "previous", and so on. They’re essentially a reference to a specific record in the database. We’ll look at the structure of the cursors later in this section when we take a look at the underlying SQL queries.
Laravel allows us to easily use cursor-based pagination with the cursorPaginate
method:
use App\Models\User;
$users = User::query()->cursorPaginate();
Running the above code would result in the $users
field being an instance of Illuminate\Contracts\Pagination\CursorPaginator
, typically an Illuminate\Pagination\CursorPaginator
object. This paginator instance contains all the information you need to display the paginated data in your application.
Similar to the simplePaginate
method, the cursorPaginate
method doesn’t fetch the total number of records in the dataset. It only knows about the current page of data and whether there are more records to fetch, so we’re not immediately aware of the total number of pages or records.
cursorPaginate
with Blade ViewsLet’s take a look at how to use the cursorPaginate
method when rendering data in a Blade view. Similar to our previous examples, we’ll assume we have a simple route that fetches the users from the database in a paginated format and passes them to a view:
use App\Models\User;
use Illuminate\Support\Facades\Route;
Route::get('users', function () {
$users = User::query()->cursorPaginate();
return view('users.index', [
'users' => $users,
]);
});
The Blade view might look something like this:
<html>
<head>
<title>Cursor Paginate</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body>
<div class="max-w-5xl mx-auto py-8">
<h1 class="text-5xl">Cursor Paginate</h1>
<ul class="py-4">
@foreach ($users as $user)
<li class="py-1 border-b"></li>
@endforeach
</ul>
</div>
</body>
</html>
This would output a page similar to the following:
As we can see, since the cursorPaginate
method doesn’t fetch the total number of records in the dataset, the output of $users->links()
is similar to the output we saw when using the simplePaginate
method. We only see the "Previous" and "Next" links in the pagination links.
cursorPaginate
in API EndpointsLaravel also allows you to use the cursorPaginate
method in API endpoints and will automatically convert the paginated data into JSON for us.
Let’s build an /api/users
endpoint that returns the paginated users in JSON format:
use App\Models\User;
use Illuminate\Support\Facades\Route;
Route::get('users', function () {
return User::query()->cursorPaginate();
});
When we hit this route, we’ll get a JSON response similar to the following (I’ve limited the data
field to just 3 records for brevity):
{
"data": [
{
"id": 1,
"name": "Andy Runolfsson",
"email": "teresa.wiegand@example.net",
"email_verified_at": "2024-10-15T23:19:28.000000Z",
"created_at": "2024-10-15T23:19:29.000000Z",
"updated_at": "2024-10-15T23:19:29.000000Z"
},
{
"id": 2,
"name": "Rafael Cummings",
"email": "odessa54@example.org",
"email_verified_at": "2024-10-15T23:19:28.000000Z",
"created_at": "2024-10-15T23:19:29.000000Z",
"updated_at": "2024-10-15T23:19:29.000000Z"
},
{
"id": 3,
"name": "Reynold Lindgren",
"email": "juwan.johns@example.net",
"email_verified_at": "2024-10-15T23:19:28.000000Z",
"created_at": "2024-10-15T23:19:29.000000Z",
"updated_at": "2024-10-15T23:19:29.000000Z"
}
],
"path": "http://example.com/users",
"per_page": 15,
"next_cursor": "eyJ1c2Vycy5pZCI6MTUsIl9wb2ludHNUb05leHRJdGVtcyI6dHJ1ZX0",
"next_page_url": "http://example.com/users?cursor=eyJ1c2Vycy5pZCI6MTUsIl9wb2ludHNUb05leHRJdGVtcyI6dHJ1ZX0",
"prev_cursor": null,
"prev_page_url": null
}
As we can see, the JSON response is similar to the previous responses we’ve seen but with some small differences. Since we aren’t fetching the total number of records, we don’t have the last_page
, last_page_url
, links
, or total
fields in the response. You may also have noticed we don’t have the from
and to
fields either.
Instead, we have the next_cursor
and prev_cursor
fields which contain the cursor for the next and previous pages of data. Since we’re on the first page, the prev_cursor
and prev_page_url
fields are both null
. However, the next_cursor
and next_page_url
fields are set.
The next_cursor
field is a base-64 encoded string that contains the cursor for the next page of data. If we decode the next_cursor
field, we’d get something like this (beautified for readability):
{
"users.id": 15,
"_pointsToNextItems": true
}
The cursor contains two separate pieces of information:
users.id
– The ID of the last record fetched in the dataset._pointsToNextItems
– A boolean value that tells us whether the cursor points to the next or previous set of items. If the value is true
it means the cursor should be used to fetch the next set of records with an ID greater than the users.id
value. If the value is false
, it means the cursor should be used to fetch the previous set of records with an ID less than the users.id
value.Let’s take a look at what the second page of data might look like (again, shortened to 3 records for brevity):
{
"data": [
{
"id": 16,
"name": "Durward Nikolaus",
"email": "xkuhic@example.com",
"email_verified_at": "2024-10-15T23:19:28.000000Z",
"created_at": "2024-10-15T23:19:29.000000Z",
"updated_at": "2024-10-15T23:19:29.000000Z"
},
{
"id": 17,
"name": "Dr. Glenda Cruickshank IV",
"email": "kristoffer.schiller@example.org",
"email_verified_at": "2024-10-15T23:19:28.000000Z",
"created_at": "2024-10-15T23:19:29.000000Z",
"updated_at": "2024-10-15T23:19:29.000000Z"
},
{
"id": 18,
"name": "Prof. Dolores Predovic",
"email": "frankie.schultz@example.net",
"email_verified_at": "2024-10-15T23:19:28.000000Z",
"created_at": "2024-10-15T23:19:29.000000Z",
"updated_at": "2024-10-15T23:19:29.000000Z"
}
],
"path": "http://example.com/users",
"per_page": 15,
"next_cursor": "eyJ1c2Vycy5pZCI6MzAsIl9wb2ludHNUb05leHRJdGVtcyI6dHJ1ZX0",
"next_page_url": "http://example.com/users?cursor=eyJ1c2Vycy5pZCI6MzAsIl9wb2ludHNUb05leHRJdGVtcyI6dHJ1ZX0",
"prev_cursor": "eyJ1c2Vycy5pZCI6MTYsIl9wb2ludHNUb05leHRJdGVtcyI6ZmFsc2V9",
"prev_page_url": "http://example.com/users?cursor=eyJ1c2Vycy5pZCI6MTYsIl9wb2ludHNUb05leHRJdGVtcyI6ZmFsc2V9"
}
We can see that the prev_cursor
and prev_page_url
fields are now set, and the next_cursor
and next_page_url
fields have been updated with the cursor for the next page of data.
To get a better understanding of how the cursor pagination works under the hood, let’s take a look at the underlying SQL queries that are run when using the cursorPaginate
method.
On the first page of data (containing 15 records), the following SQL query would be run:
select * from `users` order by `users`.`id` asc limit 16
We can see that we’re fetching the first 16 records from the users
table and ordering them by the id
column in ascending order. Similar to the simplePaginate
method, we’re fetching 16 rows because we want to determine if there are more records to fetch.
Let’s imagine we then navigate to the next page of items with the following cursor:
eyJ1c2Vycy5pZCI6MTUsIl9wb2ludHNUb05leHRJdGVtcyI6dHJ1ZX0
When this cursor is decoded, we get the following JSON object:
{
"users.id": 15,
"_pointsToNextItems": true
}
Laravel will then run the following SQL query to fetch the next set of records:
select * from `users` where (`users`.`id` > 15) order by `users`.`id` asc limit 16
As we can see, we’re fetching the next 16 records from the users
table that have an id
larger than 15 (since 15 was the last ID on the previous page).
Now let’s assume that the ID of the first user on page 2 is 16. When we navigate back to the first page of data from the second page, the following cursor would be used:
eyJ1c2Vycy5pZCI6MTYsIl9wb2ludHNUb05leHRJdGVtcyI6ZmFsc2V9
When this is decoded, we get the following JSON object:
{
"users.id": 16,
"_pointsToNextItems": false
}
When we’re moving to the next page of results, the last record fetched is used as the cursor. When we move back to the previous page of results, the first record fetched is used as the cursor. For this reason, we can see the users.id
value is set to 16 in the cursor. We can also see that the _pointsToNextItems
value is set to false
because we’re moving back to the previous set of items.
As a result, the following SQL query would be run to fetch the previous set of records:
select * from `users` where (`users`.`id` < 16) order by `users`.`id` desc limit 16
As we can see, the where
constraint is now checking for records with an id
less than 16 (since 16 was the first ID on page 2) and the results are ordered in descending order.
So far, in our API examples, we’ve just returned the paginated data directly from the controller. However, in a real-world application, you’ll likely want to process the data before returning it to the user. This could be anything from adding or removing fields, converting data types, or even transforming the data into a different format altogether. For this reason, you’ll likely want to use API Resources since they provide a way for you to consistently transform your data before returning it.
Laravel allows you to use API resources alongside pagination. Let’s look at an example of how to do this.
Imagine we have created an App\Http\Resources\UserResource
API resource class that transforms the user data before returning it. It might look something like this:
declare(strict_types=1);
namespace App\Http\Resources;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
final class UserResource extends JsonResource
{
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'name' => $this->name,
'email' => $this->email,
];
}
}
In the toArray
method, we’re defining that whenever we process a user via this resource, we only want to return the id
, name
, and email
fields.
Now let’s build a simple /api/users
API endpoint in our routes/api.php
file that returns the paginated users using the App\Http\Resources\UserResource
:
use App\Models\User;
use App\Http\Resources\UserResource;
use Illuminate\Support\Facades\Route;
Route::get('users', function () {
$users = User::query()->paginate();
return UserResource::collection(resource: $users);
});
In the code above, we’re fetching a single page of users (let’s assume it’s the first page containing 15 users) from the database. We’re then passing the $users
field (which will be an instance of Illuminate\Pagination\LengthAwarePaginator
) to the UserResource::collection
method. This method will transform the paginated data using the App\Http\Resources\UserResource
before returning it to the user.
When we hit the /api/users
endpoint, we’ll get a JSON response similar to the following (I’ve limited the data
field to just 3 records for brevity):
{
"data": [
{
"id": 1,
"name": "Andy Runolfsson",
"email": "teresa.wiegand@example.net"
},
{
"id": 2,
"name": "Rafael Cummings",
"email": "odessa54@example.org"
},
{
"id": 3,
"name": "Reynold Lindgren",
"email": "juwan.johns@example.net"
}
],
"links": {
"first": "http://example.com/users?page=1",
"last": "http://example.com/users?page=4",
"prev": null,
"next": "http://example.com/users?page=2"
},
"meta": {
"current_page": 1,
"from": 1,
"last_page": 4,
"links": [
{
"url": null,
"label": "« Previous",
"active": false
},
{
"url": "http://example.com/users?page=1",
"label": "1",
"active": true
},
{
"url": "http://example.com/users?page=2",
"label": "2",
"active": false
},
{
"url": "http://example.com/users?page=3",
"label": "3",
"active": false
},
{
"url": "http://example.com/users?page=4",
"label": "4",
"active": false
},
{
"url": "http://example.com/users?page=2",
"label": "Next »",
"active": false
}
],
"path": "http://example.com/users",
"per_page": 15,
"to": 15,
"total": 50
}
}
As we can see in the JSON above, Laravel detects that we’re working with a paginated dataset and returns the paginated data in a similar format as before. However, this time the users in the data
field only contain the id
, name
, and email
fields which we specified in our API resource class. Other fields (current_page
, from
, last_page
, links
, path
, per_page
, to
, and total
) are still returned as they’re part of the paginated data, but they’ve been placed inside a meta
field. There’s also a links
field that contains the first
, last
, prev
, and next
links to the different pages of data.
When building views with paginated data, you might want to allow the user to change the number of records displayed per page. This might be via a dropdown or number input field.
Laravel makes it easy to change the number of records displayed per page by passing a perPage
parameter to the simplePaginate
, paginate
, and cursorPaginate
methods. This parameter allows you to specify the number of records you want to display per page.
Let’s take a look at a simple example of how to read a per_page
query parameter and use this to change the number of records fetched per page:
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
Route::get('users', function (Request $request) {
$perPage = $request->integer('per_page', default: 10);
return User::query()->paginate(perPage: $perPage);
});
In the example above, we’re grabbing the per_page
query parameter’s value. If the value isn’t provided, we’ll default to 10. We then pass that value to the perPage
parameter of the paginate
method.
We could then access these different URLs:
https://my-app.com/users
– Display the first page of users with 10 records per page.https://my-app.com/users?per_page=5
– Display the first page of users with 5 records per page.https://my-app.com/users?per_page=5&page=2
– Display the second page of users with 5 records per page.Now that we’ve looked at the different types of pagination and how to use them in Laravel, we’ll discuss how to decide which of these approaches to use in your application.
If you’re building a UI or API endpoint that requires the total number of records or pages to be displayed, then the paginate
method is probably a sensible choice.
If you don’t require either of these, then the simplePaginate
or cursorPaginate
will be more efficient as they don’t perform unnecessary queries to count the total number of records.
If you need to be able to jump to a specific page of data, then offset-based pagination is more suitable. Since cursor pagination is stateful, it relies on the previous page to know where to go next. So it’s not as easy to jump to a specific page.
Whereas when using offset pagination, you can typically just pass the page number in the request (maybe as a query parameter) and jump to that page without having any context of the previous page.
Due to the way that databases handle offset
values, offset-based pagination becomes less efficient as the page number increases. This is because when you’re using an offset, the database still has to scan through all the records up to the offset value. They’re just discarded and not returned in the query results.
Here’s a great article that explains this in more detail: https://use-the-index-luke.com/no-offset.
So as the total amount of data in the database grows and the page number increases, offset-based pagination can become less efficient. In these cases, cursor-based pagination is more performant, especially if the cursor field is indexed, since the previous records aren’t read. For this reason, if you’re going to be using pagination against a large dataset, you might want to opt for cursor pagination over offset pagination.
Offset-based pagination can suffer from issues if the underlying dataset changes between requests.
Let’s take a look at an example.
Let’s say we have the following 10 users in our database:
We make a request to fetch the first page (containing 5 users) and get the following users:
When we navigate to page 2, we’d expect to get users 6 to 10. However, let’s imagine that before we load page 2 (while we’re still viewing page 1), User 1 is deleted from the database. Since the page size is 5, the query to fetch the next page would look like this:
select * from `users` limit 5 offset 5
This means we’re skipping the first 5 records and fetching the next 5.
This would result in page 2 containing the following users:
As we can see, User 6 is missing from the list. This is because User 6 is now the 5th record in the table, so they’re actually on the first page.
Cursor-based pagination doesn’t have this issue, because we’re not skipping records, we’re just fetching the next set of records based on a cursor. Let’s imagine we’d used cursor-based pagination in the example above. The cursor for page 2 would be the ID of User 5 (which we’ll assume is 5) since it was the last record on the first page. So our query for page 2 may look like this:
select * from `users` where (`users`.`id` > 5) order by `users`.`id` asc limit 6
Running the above query would return users 6 to 10 as expected.
This should hopefully highlight how offset-based pagination can become problematic when the underlying data is changed, added to, or removed while it’s being read. It becomes less predictable and can lead to unexpected results.
It’s important to remember that you’re not fixed to using a single type of pagination in your application. In some places, offset pagination might be more suitable (maybe for UI purposes) and in others, cursor pagination might be more efficient (such as when working with a large dataset). So you can mix and match pagination methods in your application depending on the use case.
However, if you’re building an API, I’d highly recommend that you’re consistent and use a single pagination approach for all your endpoints. This will make it easier for developers to understand how to use your API and avoid any confusion.
You don’t want them to have to remember which endpoints use offset-pagination and which use cursor-pagination.
Of course, this isn’t a hard and fast rule. If you really need to use a different pagination method in one particular endpoint, then go ahead. But just make sure to make it clear in the documentation to make it easier for developers to understand.
If you’re more of a visual learner, you might want to check out this awesome video by Aaron Francis that explains the difference between offset and cursor-based pagination in more detail:
<iframe width="560" height="315" src="https://www.youtube.com/embed/zwDIN04lIpc" title="Pagination in MySQL – offset vs. cursor" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
In this article, we’ve taken a look at the different types of pagination in Laravel and how to use them. We’ve also looked at their underlying SQL queries and how to decide which pagination method to use in your application.
Hopefully, you should now feel more confident in using pagination in your Laravel applications.
The post A Guide to Pagination in Laravel appeared first on Laravel News.
Join the Laravel Newsletter to get all the latest
Laravel articles like this directly in your inbox.
Laravel News
https://gizmodo.com/app/uploads/2024/11/Harrison-Ford-Captain-America-Brave-New-World-Red-Hulk.jpg
As Marvel has trucked into its fifth phase of films and TV shows, fans and actors alike have expressed growing pains with the comic book cinematic universe. While much of folks’ ire with the MCU’s oversaturation in pop culture centers on the waning quality in its post-Avengers: Endgame storytelling, another point of frustration is with how the MCU’s casting announcements—once a cause for internet frenzy—have felt like jury duty for well-established and up-and-coming actors alike. In a shocking turn of events, Harrison Ford, Hollywood’s grumpiest lovable actor, has come forward to dispel the stigma surrounding actors in Marvel films.
In a recent interview with GQ, Ford reminisced over his legendary career starring in pop culture touchstones like Star Wars, Indiana Jones, and Blade Runner. The 82-year-old actor also reflected on his debut in the MCU as Thaddeus “Thunderbolt” Ross (aka Red Hulk) in the upcoming Marvel film Captain America: Brave New World. When asked about his patently dismissive non-answers at press events—something GQ notes would be unorthodox for any other Marvel actor—was indicative of something more profound, Ford responded in kind, saying that it wasn’t that deep.
“I mean, this is the Marvel universe and I’m just there on a weekend pass. I’m a sailor new to this town. Show me the way to go home,” Ford told GQ.
Ford expanded on his comment, addressing the notion of actors steering clear of the Marvel Cinematic Universe as their next artistic venture because they think it will debase their talents. This ongoing discourse has been stoked by comments from directors like Martin Scorsese and Francis Ford Coppola, who’ve wrestled with whether the MCU is cinema or just a blockbuster rollercoaster solely meant to generate money rather than (as Coppola put it) “illuminate contemporary life.”
“I understand the appeal of other kinds of films besides the kind we made in the ’80s and ’90s. I don’t have anything general to say about it. It’s the condition our condition is in, and things change and morph and go on,” Ford said. “We’re silly if we sit around regretting the change and don’t participate. I’m participating in a new part of the business that, for me at least, I think is really producing some good experiences for an audience. I enjoy that.”
Although Ford is known for being a curmudgeon whenever fans and the press ask him for his take on theories about Star Wars and Indiana Jones, his big tent answer here does get at the reason why actors like himself perform in the first place: to create new, thrilling experiences for moviegoers. As far as Ford’s involvement in projects like the MCU goes, he says it all boils down to good old-fashioned writing.
“It’s the quality of writing. It doesn’t matter what the genre is. It doesn’t matter whether it’s on television or in movies. It’s the writing, it’s the story, it’s the character, it’s the emotional experience for an audience or for myself. It’s people that I have some feeling that I want to work with, or it’s a quality opportunity,” Ford said, adding, “I suppose I should be sitting on my ass, but I actually love working.”
Ford’s measured defense for his involvement in the MCU isn’t to say his resume will only be filled with larger-than-life comic book epics. In fact, at New York Comic Con 2024, it was announced that Ford is gearing up for the third season of the Apple+ comedy show Shrinking alongside co-star Jason Segel.
For folks solely interested in witnessing Ford making mean faces as Red Hulk, they can look forward to Captain America: Brave New World when it releases in theaters February 14.
Want more io9 news? Check out when to expect the latest Marvel, Star Wars, and Star Trek releases, what’s next for the DC Universe on film and TV, and everything you need to know about the future of Doctor Who.
Gizmodo
https://media.notthebee.com/articles/67291266dacb067291266dacb1.jpg
This goes so hard.
Not the Bee
Our bodies divest themselves of 60 billion cells every day through a natural process called "apoptosis". So Stanford medicine researchers are developing a new approach to cancer therapy that could "trick cancer cells into disposing of themselves," according to announcement from Stanford’s medical school:
Their method accomplishes this by artificially bringing together two proteins in such a way that the new compound switches on a set of cell death genes… One of these proteins, BCL6, when mutated, drives the blood cancer known as diffuse large cell B-cell lymphoma… [It] sits on DNA near apoptosis-promoting genes and keeps them switched off, helping the cancer cells retain their signature immortality. The researchers developed a molecule that tethers BCL6 to a protein known as CDK9, which acts as an enzyme that catalyzes gene activation, in this case, switching on the set of apoptosis genes that BCL6 normally keeps off. "The idea is, Can you turn a cancer dependency into a cancer-killing signal?" asked Nathanael Gray, PhD, co-senior author with Crabtree, the Krishnan-Shah Family Professor and a chemical and systems biology professor. "You take something that the cancer is addicted to for its survival and you flip the script and make that be the very thing that kills it…." When the team tested the molecule in diffuse large cell B-cell lymphoma cells in the lab, they found that it indeed killed the cancer cells with high potency. They also tested the molecule in healthy mice and found no obvious toxic side effects, even though the molecule killed off a specific category of of the animals’ healthy B cells, a kind of immune cell, which also depend on BCL6. They’re now testing the compound in mice with diffuse large B-cell lymphoma to gauge its ability to kill cancer in a living animal. Because the technique relies on the cells’ natural supply of BCL6 and CDK9 proteins, it seems to be very specific for the lymphoma cells — the BCL6 protein is found only in this kind of lymphoma cell and in one specific kind of B cell. The researchers tested the molecule in 859 different kinds of cancer cells in the lab; the chimeric compound killed only diffuse large cell B-cell lymphoma cells. Scientists have been trying to shut down cancer-driving proteins, one of the researchers says, but instead, "we’re trying to use them to turn signaling on that, we hope, will prove beneficial for treatment." The two researchers have co-founded the biotech startup Shenandoah Therapeutics, which "aims to further test this molecule and a similar, previously developed molecule," according to the article, "in hopes of gathering enough pre-clinical data to support launching clinical trials of the compounds. "They also plan to build similar molecules that could target other cancer-driving proteins…"
Read more of this story at Slashdot.
Slashdot