How I Use a Free App to Build My Personal News Feed

https://static1.makeuseofimages.com/wordpress/wp-content/uploads/2024/08/what_is_rss_and_what_can_you_do_with_it.jpg

Key Takeaways

  • Inoreader is a free RSS feed reader app that consolidates articles from multiple sources for easy access.
  • Customize your feed with up to 150 sources and monitor it through a customizable dashboard.
  • Pro users gain access to advanced features such as rules, filters, article translation, and monitoring feeds, which enhance control.

If you want to read up on your favorite online news site or any other source of information, you can either take the time to look up what you want on a specific website or go through the newsletters that clog your inbox. A more efficient way is to use an RSS (Really Simple Syndication) feed reader.

RSS readers collect articles from multiple sources into one app, making it extremely easy to find what you need without fighting search algorithms and the general mess that the internet is. And the best part? You don’t need to pay for this feature—Inoreader lets you create a personalized news feed for free.

What Is Inoreader?

Inoreader is one of the best and most well-reviewed RSS feed-reading apps you can find online. If you don’t know what RSS is and what you can do with it, we’ve got you covered, but in a nutshell, RSS is a simple format that allows websites to share updates directly with you. RSS is a great alternative to newsletters and social media, as it puts you in control of what appears in your feed, free from the influence of algorithms.

There are a lot of ways you can find popular content on the internet, but RSS readers like Inoreader allow you to build your own feeds. It’s a little bit of work setting it up, but once you’re done, you’ll have all your news sources coming up in one feed and in one app, exactly how you prefer.

Inoreader’s free version is rather limited in terms of the features you get, but you can still get your news feed and a personalized dashboard up and running in no time. However, more advanced features like filters, automation, and translation are reserved for paying users.

1. Setting Up a Feed

The first thing you’ll see when you log into Inoreader is your dashboard with three options to get you started. You can search for your preferred sources like news websites, explore Inoreader’s featured feed collections, or import feeds from another RSS reader.

Inoreader’s featured collections are a good starting point for beginners, but to create a truly personalized feed, it’s best to search for the websites and sources you frequently read. This approach helps you avoid clutter and focus on what matters most to you.

Inoreader offers extensive control over what you can add to your feed. You can follow websites, Facebook pages, Twitter accounts, Google News, Reddit, Telegram channels, and even other Inoreader users. You can also track keywords, brands, names, subreddits, or specific phrases.

While Facebook Pages are restricted to Pro users, all other sources are accessible on the free tier.

The free version of Inoreader lets you select up to 150 feeds (or sources), so you can look up all your sources and add them to Inoreader. As you add sources, Inoreader will suggest similar ones to expand your feed further.

2. Monitoring Your Feed

Once you’ve added your desired feeds, you’ll likely return to the app frequently to stay updated. This is where Inoreader’s dashboard comes in handy.

When you first load the reader, it defaults to a basic yet functional dashboard. However, if you want more control, you can create a totally custom dashboard. Just click the Create custom dashboard in the top bar, select the widgets you want, and you’re off to the races.

These dashboard widgets show everything from the latest articles coming in across your feeds to the total number of unread articles you have, article reading statistics, trending articles on Inoreader, and even recommended sources.

There’s not a lot you can customize here, though. It would’ve been nice if Inoreader had let me resize the widgets so I could truly make the dashboard look how I wanted it, but the fact that I can deck it out with the information I want to see is valuable.

Once you’ve set up everything to your liking, chances are you’ll find what you need on the dashboard itself, without having to scroll through your sources. And if you do need to take a deeper look, you can create folders to group similar feeds together for another layer of organization.

Another powerful feature is Monitoring Feeds. This feature allows you to search for a specific term and create a feed for it. As articles containing the search terms appear, they’ll populate this monitoring feed, ensuring you catch what you’re looking for as soon as it arrives. Unfortunately, this feature is behind a paywall and is only accessible to Pro subscribers.

Another feature you can use to spot words and phrases in articles quickly is Highlighters. Add your term, select a color, and you’ll see the word or phrase highlighted in that color as you read articles in your feed. This is by far one of the best features I’ve come across in an RSS feed app, and it makes it incredibly easy to find what you’re looking for without reading entire articles.

3. Using Filters and Automation

Two of the coolest Inoreader features, Rules and Filters, are only available to Pro users, which is a bit of a bummer. As the name suggests, rules allow you to act based on article properties. For example, you can send push notifications if an article from a specific site, author, or keyword gets published.

Filters enable you to exclude articles from your feed or connected apps based on keywords in their title or body. Since filtered feeds only cover the last 30 days, filters help ensure you see only the content that interests you, while irrelevant content is filtered out.

4. Translating Articles

Inoreader also offers translation features for those reading articles in different languages. This feature, available only to Pro subscribers, eliminates the need to rely on browser-based or third-party translation tools, saving you time and effort when accessing foreign-language content.

While Inoreader’s Pro version offers many additional features, the free version is sufficient for building a simple, clutter-free news feed that delivers what you want, when you want it.

MakeUseOf

How to Separate First and Last Names to Columns in Excel

https://static1.makeuseofimages.com/wordpress/wp-content/uploads/2024/08/a-laptop-with-an-excel-spreadsheet-displaying-a-list-of-names-separated-into-first-names-and-last-names.jpg

Separating first and last names in an Excel spreadsheet is a common task that can be time-consuming if done manually. Thankfully, Excel offers several efficient methods to automate this process, saving you valuable time and effort.

Use Delimiters in Excel

One of the most straightforward ways to separate first and last names is by using delimiters in Excel. A delimiter is a character that separates different parts of text data. In the case of names, the space between the first and last names often serves as the delimiter.

To separate first and last names using delimiters:

  1. Select the column in your Excel spreadsheet containing the full names you want to split.
  2. Go to the Data tab and click Text to Columns in the Data Tools group.
  3. Select Delimited and click Next.
  4. Tick the Space checkbox. If a different delimiter, such as a comma or hyphen, separates the first and last names, select the appropriate option. Then, click Next.
  5. Excel will overwrite the original data in the same column by default. To keep the original data intact, specify a different column in the Destination field.
  6. Click Finish to confirm.

Excel will split the first and last names into two columns. You can also use this to separate first, middle, and last names.

Use the TEXTSPLIT Formula

Another easy way to separate first and last names is using the TEXTSPLIT Excel function. This formula allows you to split text into multiple columns or rows based on a specified delimiter. Here’s how to use it.

  1. In the column that contains the full names you want to split, note down the cell address of the full name. Let’s say it’s in cell A3.
  2. Go to the cell where you want the first name to appear.
  3. Type =TEXTSPLIT(A3, " ") and press Enter.
  4. This formula will split the text in cell A3 wherever there is a space, placing the first name in the selected cell and the last name in the adjacent cell.
  5. To apply the formula to the entire column, drag the fill handle (the small square at the bottom-right corner of the selected cell) down to cover all the needed rows.

Use a Keyboard Shortcut

If you’re not keen on using Excel functions or formulas to separate first and last names, there’s a quicker way to get the job done. Excel’s Flash Fill feature, triggered with the Ctrl + E keyboard shortcut, can also help you separate first and last names into columns.

Flash Fill is a powerful tool that automatically fills in data when it detects a pattern in your input, making it perfect for separating names. Here’s how to use it:

  1. Ensure that your data is in a single column with full names.
  2. In the cell where you want to extract the first name, manually type the first name from the first full name in column A. If A3 contains John Doe, type John in B3.
  3. Select the cell where you entered the first name and press Ctrl + E.
  4. Excel will automatically detect the pattern and fill down the first names for the entire column.
  5. Similarly, in the next column, type the last name corresponding to the first full name in column A. If A3 is John Doe, you would type Doe in C3.
  6. With C3 selected, press Ctrl + E again.

Excel will automatically populate the last names for all the rows based on the detected pattern. Knowing how to separate first and last names in Excel can help you better organize your spreadsheet. With methods such as Text to Columns, Flash Fill, and Excel formulas, you can select the approach that best suits your needs.

MakeUseOf

We can now watch Grace Hopper’s famed 1982 lecture on YouTube

https://cdn.arstechnica.net/wp-content/uploads/2024/08/hopper1-760×380.jpg

Rear Admiral Grace Hopper on Future Possibilities: Data, Hardware, Software, and People (Part One, 1982).

The late Rear Admiral Grace Hopper was a gifted mathematician and undisputed pioneer in computer programming, honored posthumously in 2016 with the Presidential Medal of Freedom. She was also very much in demand as a speaker in her later career. Hopper’s famous 1982 lecture on "Future Possibilities: Data, Hardware, Software, and People," has long been publicly unavailable because of the obsolete media on which it was recorded. The National Archives and Records Administration (NARA) finally managed to retrieve the footage for the National Security Agency (NSA), which posted the lecture in two parts on YouTube (Part One embedded above, Part Two embedded below).

Hopper earned undergraduate degrees in math and physics from Vassar College and a PhD in math from Yale in 1930. She returned to Vassar as a professor, but when World War II broke out, she sought to enlist in the US Naval Reserve. She was initially denied on the basis of her age (34) and low weight-to-height ratio, and also because her expertise made her particularly valuable to the war effort. Hopper got an exemption, and after graduating first in her class, she joined the Bureau of Ships Computation Project at Harvard University, where she served on the Mark I computer programming staff under Howard H. Aiken.

She stayed with the lab until 1949 and was next hired as a senior mathematician by Eckert-Mauchly Computer Corporation to develop the Universal Automatic Computer, or UNIVAC, the first computer. Hopper championed the development of a new programming language based on English words. "It’s much easier for most people to write an English statement than it is to use symbols," she reasoned. "So I decided data processors ought to be able to write their programs in English and the computers would translate them into machine code."

Her superiors were skeptical, but Hopper persisted, publishing papers on what became known as compilers. When Remington Rand took over the company, she created her first A-0 compiler. This early achievement would one day lead to the development of COBOL for data processors, which is still the major programming language used today.

“Grandma COBOL”

In November 1952, the UNIVAC was introduced to America by CBS news anchor Walter Cronkite as the presidential election results rolled in. Hopper and the rest of her team had worked tirelessly to input voting statistics from earlier elections and write the code that would allow the calculator to extrapolate the election results based on previous races. National pollsters predicted Adlai Stevenson II would win, while the UNIVAC group predicted a landslide for Dwight D. Eisenhower. UNIVAC’s prediction proved to be correct: Eisenhower won over 55 percent of the popular vote with an electoral margin of 442 to 89.  

Hopper retired at age 60 from the Naval Reserve in 1966 with the rank of commander but was subsequently recalled to active duty for many more years, thanks to congressional special approval allowing her to remain beyond the mandatory retirement age. She was promoted to commodore in 1983, a rank that was renamed "rear admiral" two years later, and Rear Admiral Grace Hopper finally retired permanently in 1986. But she didn’t stop working: she became a senior consultant to Digital Equipment Corporation and "goodwill ambassador," giving public lectures at various computer-related events.

One of Hopper’s best-known lectures was delivered to NSA employees in August 1982. According to an NSA press release, the footage had been preserved in a defunct media format—specifically, two 1-inch AMPEX tapes. The agency asked NARA to retrieve that footage and digitize it for public release, and NARA did so. The NSA described it as "one of the more unique public proactive transparency record releases… to date."

Hopper was a very popular speaker not just because of her pioneering contributions to computing, but because she was a natural raconteur, telling entertaining and often irreverent war stories from her early days. And she spoke plainly, as evidenced in the 1982 lecture when she drew an analogy between using pairs of oxen to move large logs in the days before large tractors, and pairing computers to get more computer power rather than just getting a bigger computer—"which of course is what common sense would have told us to begin with." For those who love the history of computers and computation, the full lecture is very much worth the time.

Grace Hopper on Future Possibilities: Data, Hardware, Software, and People (Part Two, 1982).

Listing image by Lynn Gilbert/CC BY-SA 4.0

Ars Technica – All content

Bizarre Product Design: These Snowflake-Shaped Charging Port Cleaning Tools

https://s3files.core77.com/blog/images/1568509_81_133459_MHgzGlF9n.jpg

This strange-looking object, by a company whose name has four consonants in a row, is a tool for cleaning out charging ports on smartphones and tablets.

It features a variety of picks, brushes and scrapers, as well as a kind of scrubber port that you load with (included) "detergent" to clean the male connector. It can also be used to clean wireless earbuds and their cases.

The tool has the same challenge as countless EDC multi-bit tools, but rather than going with a cylindrical form factor, they’ve opted for a snowflake shape. I can’t fathom why. The only other tool I’ve seen that uses this shape is a spark plug gap gauge, but it was coin-sized; this thing here is 3.5" across.

They also offer this more organic-looking variant.

I don’t deny that there’s a need for this tool, particularly if you do a lot of outdoor stuff. (I actually have to keep a little plug in my phone’s charging port, otherwise it becomes so clogged I can’t charge it.) I’m just taken aback at the form, and the tool’s overall popularity; it’s got 2,000 reviews and 4.5 stars on Amazon.

These run $20.

Core77

Federal Judge Rules Machineguns are Protected Under the Second Amendment

https://www.ammoland.com/wp-content/uploads/2021/12/Daniel-Defense-HERO-01-500×333.jpg

Federal Judge Rules Machineguns are Protected Under the Second Amendment. img. Jim Grant
Federal Judge Rules Machineguns are Protected Under the Second Amendment. img. Jim Grant

A United States Federal District Court Judge for the District of Kansas dismissed a case against a man accused of having two machine guns, claiming that these firearms are protected as bearable arms under the Second Amendment.

Prosecutors claim that on Oct. 17, 2022, Tamori Morgan possessed two machine guns. The first firearm was an Anderson Manufacturing AM-15 chambered in .300 blk that the man converted from semi-automatic to fully automatic. The second machine gun was a Glock 33 equipped with a Glock switch. A Glock switch converts a semi-automatic handgun to a machine gun. These switches are readily available on Chinese websites, and their numbers in the country have risen over the past few years.

In April 2023, a grand jury in the U.S. District Court in Wichita, Kansas, indicted Morgan for possession of the two machine guns. Mr. Morgan would be assigned federal public defender David Freund. Public defenders get a bad rap, but these are some of the most experienced trial lawyers in the country. Mr. Freund filed for a motion to dismiss in November of 2023, claiming that machine guns were protected arms under the Second Amendment.

Under the Bruen test, a law on guns is only constitutional if it is consistent with the text, tradition, and history of the Second Amendment. The first step is the original text of the Second Amendment. There is nothing in the Second Amendment that gives the government the right to ban machine guns. Once it is determined that a law isn’t consistent with the text, the burden falls to the government to provide historical analogues to show that the law is consistent with the history and tradition of the Second Amendment from the founding era.

“When the Second Amendment’s plain text covers an individual’s conduct, the Constitution presumptively protects that conduct,” Associate Justice Clarence Thomas wrote in Bruen. “The government must then justify its regulation by demonstrating that it is consistent with the Nation’s historical tradition of firearm regulation. Only then may a court conclude that the individual’s conduct falls outside the Second Amendment’s unqualified command.”

The government tried to argue that the Second Amendment only applies to arms that were around during the ratification of the Second Amendment. U.S. District Judge John Broomes rejected Assistant U.S. Attorney Aaron Smith’s arguments. The prosecutor also tried to use English common law. Prosecution also mentioned a case from North Carolina in 1829 that recognized an offense to arm oneself “with dangerous and unusual weapons, in such a manner as will naturally cause a terror to the people.” The judge dismissed both laws because they were not similar to the charges against Morgan. The Supreme Court’s Rahimi opinion said that an analogue doesn’t have to be a “historical twin.” SCOTUS went on to say it does have to resemble the law being defended.

The judge also called out the prosecutor for trying to use dicta from the Heller decision. Mr. Smith attempted to say that Heller allowed for banning machine guns because they are “dangerous and unusual.” The judge was quick to reject the argument because the Heller case had nothing to do with machine guns. He also pointed out that not all machine guns are illegal; only ones produced after May 1986 are forbidden for public transfer. Judge Broomes highlighted that there are 740,000 transferable machine guns in public circulation.

“Machineguns have been in existence for well over a century,” the judge wrote. “While the federal government has regulated transfer and possession of such weapons since passage of the National Firearms Act in 1934, it did not outright prohibit possession of machineguns until passage of the Firearms Owners Protection Act in 1986. Even then, the law did not prohibit the possession of all machineguns; rather, § 922(o) merely prohibits possession of machineguns that were not lawfully possessed as of the date that prohibition went into effect in 1986. § 922(o)(2)(B). Thus, even today, it is perfectly legal for a person who has not been divested of his firearm rights under some other provision of law to acquire and possess a machinegun, so long as it was lawfully possessed by someone before the relevant date in 1986, and so long as he complies with the National Firearms Act’s requirements to obtain and possess the weapon. In that sense, machineguns are not unusual.”

The government then tried to say the law was justified because machine guns were “military weapons.” To counter this point, the judge used United States v. Miller. In the 1939 Miller case, the Supreme Court rejected the idea that sawed-off shotguns were protected arms and couldn’t be regulated. The Supreme Court reasoned that sawed-off shotguns were not used on the battlefield and, therefore, not protected. The Supreme Court believed that the Second Amendment applied to military arms. The judge also highlighted laws from the founding era that required civilians to keep personal military arms in case the need arose for a militia to be formed.

The judge dismissed the case, but the prosecutor can appeal the judge’s decision. Most legal experts expect this appeal. The decision doesn’t knock down the National Firearms Act of 1934 (NFA) and doesn’t apply to anyone outside the case. Post-1986 machine guns remain illegal to own for private citizens. Mr. Morgan faced ten years in prison and a $250,000 fine for each offense if convicted.


About John Crump

Mr. Crump is an NRA instructor and a constitutional activist. John has written about firearms, interviewed people from all walks of life, and on the Constitution. John lives in Northern Virginia with his wife and sons, follow him on X at @crumpyss, or at www.crumpy.com.

John Crump

AmmoLand Shooting Sports News

Make Your Excel Spreadsheets Smarter With Dropdown Lists

https://static1.makeuseofimages.com/wordpress/wp-content/uploads/2024/08/a-computer-screen-showing-dropdown-lists-in-excel-alongisde-the-excel-logo.jpg

Dropdown lists are the secret weapon against data inconsistency and typos, making data entry easier and more accurate. Despite their power, they’re often overlooked in Excel’s UI, leaving many users missing out on their benefits. Ready to make your spreadsheets smarter? Here’s how you can use dropdown lists in Excel

How to Create Dropdown Lists in Excel

Excel’s dropdown lists are rightly categorized under the Data Validation tab, as they not only streamline data entry but also enhance the reliability of your formulas.

For this example, we’ll use a task tracker with a Status column that provides dropdown lists for each task. The list items will include Not Started, In Progress, Completed, and Blocked.

Unlike Google Sheets, Excel requires the list values to exist somewhere in your workbook. To avoid cluttering your task tracker, it’s best to create a separate sheet to store these values. Once the dropdown lists are created, you can hide the cells or the entire sheet to keep your tracker tidy.

Here’s how to set up the dropdown list:

  1. Prepare your list values by entering the list items (e.g., Not Started, In Progress, Completed, Blocked) in a column on a separate sheet.
  2. Highlight the cells where you want the dropdown lists to appear (e.g., B2:B5).
  3. Go to the Data tab on the ribbon, then click Data Validation in the Data Tools section.
  4. In the Data Validation window, select List under the Allow dropdown.
  5. Click the upward arrow in the Source field, and select the range containing your list items.
  6. Click OK to apply the dropdown list to the selected cells.

The selected cells should now display a dropdown arrow, allowing you to choose from the predefined items.

How to Customize Excel Dropdown Lists

While your dropdown list is functional, it may not look as visually appealing as you’d like, especially if you’re used to the colorful dropdowns in Google Sheets. Fortunately, with a touch of Excel’s conditional formatting, you can enhance the appearance of your dropdown list in Excel.

To apply conditional formatting to your dropdown list, follow these steps:

  1. Highlight the cells with dropdown lists (e.g., B2:B5).
  2. Go to the Home tab, click Conditional Formatting, and select New Rule.
  3. In the New Formatting Rule window, choose Format only cells that contain.
  4. In the rule description, set the first dropdown to Specific Text and leave the second field as is.
  5. Enter the text you want to format (e.g., Completed).
  6. Click Format next to the preview. In the Format Cells window, set the Font color to white, go to the Fill tab, and choose a deep green color for the background.
  7. Click OK twice to apply the rule.

Now, any task marked as Completed will have a green background, making it easy to identify at a glance. Repeat these steps for the other list items and assign each a unique color. This will significantly improve visual clarity.

Dropdown lists eliminate the risk of typos and variations—no more Complete vs. Finished vs. Done. This consistency is crucial when analyzing data with formulas; for instance, if a formula tracks Completed tasks, it will miss tasks marked as Finished.

Now with your dropdown lists in place, your Excel sheet is not only easier to use but also primed for advanced data analysis. You can filter tasks by status, such as showing only In Progress tasks, or use the COUNTIF function to count how many tasks are Blocked.

MakeUseOf

Laravel Model Tips

https://picperf.io/https://laravelnews.s3.amazonaws.com/featured-images/laravel-model-tips.png

Laravel Model Tips

Laravel provides a huge amount of cool features that help improve our development experience (DX). But with the regular releases, stresses of day-to-day work, and the vast amount of features available, it’s easy to miss some of the lesser-known features that can help improve our code.

In this article, I’m going to cover some of my favourite tips for working with Laravel models. Hopefully, these tips will help you write cleaner, more efficient code and help you avoid common pitfalls.

Spotting and Preventing N+1 Issues

The first tip we’ll look at is how to spot and prevent N+1 queries.

N+1 queries are a common issue that can occur when lazy loading relationships, where N is the number of queries that are run to fetch the related models.

But what does this mean? Let’s take a look at an example. Imagine we want to fetch every post from the database, loop through them, and access the user that created the post. Our code might look something like this:

$posts = Post::all();

foreach ($posts as $post) {
    // Do something with the post...

    // Try and access the post's user
    echo $post->user->name;
}

Although the code above looks fine, it’s actually going to cause an N+1 issue. Say there are 100 posts in the database. On the first line, we’ll run a single query to fetch all the posts. Then inside the foreach loop when we’re accessing $post->user, this will trigger a new query to fetch the user for that post; resulting in an additional 100 queries. This means we’d run 101 queries in total. As you can imagine, this isn’t great! It can slow down your application and put unnecessary strain on your database.

As your code becomes more complex and features grow, it can be hard to spot these issues unless you’re actively looking out for them.

Thankfully, Laravel provides a handy Model::preventLazyLoading() method that you can use to help spot and prevent these N+1 issues. This method will instruct Laravel to throw an exception whenever a relationship is lazy-loaded, so you can be sure that you’re always eager loading your relationships.

To use this method, you can add the Model::preventLazyLoading() method call to your App\Providers\AppServiceProvider class:

namespace App\Providers;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        Model::preventLazyLoading();
    }
}

Now, if we were to run our code from above to fetch every post and access the user that created the post, we’d see an Illuminate\Database\LazyLoadingViolationException exception thrown with the following message:

Attempted to lazy load [user] on model [App\Models\Post] but lazy loading is disabled.

To fix this issue, we can update our code to eager load the user relationship when fetching the posts. We can do this by using the with method:

$posts = Post::with('user')->get();

foreach ($posts as $post) {
    // Do something with the post...

    // Try and access the post's user
    echo $post->user->name;
}

The code above will now successfully run and will only trigger two queries: one to fetch all the posts and one to fetch all the users for those posts.

Prevent Accessing Missing Attributes

How often have you tried to access a field that you thought existed on a model but didn’t? You might have made a typo, or maybe you thought there was a full_name field when it was actually called name.

Imagine we have an App\Models\User model with the following fields:

  • id
  • name
  • email
  • password
  • created_at
  • updated_at

What would happen if we ran the following code?:

$user = User::query()->first();
    
$name = $user->full_name;

Assuming we don’t have a full_name accessor on the model, the $name variable would be null. But we wouldn’t know whether this is because the full_name field actually is null, because we haven’t fetched the field from the database, or because the field doesn’t exist on the model. As you can imagine, this can cause unexpected behaviour that can sometimes be difficult to spot.

Laravel provides a Model::preventAccessingMissingAttributes() method that you can use to help prevent this issue. This method will instruct Laravel to throw an exception whenever you try to access a field that doesn’t exist on the current instance of the model.

To enable this, you can add the Model::preventAccessingMissingAttributes() method call to your App\Providers\AppServiceProvider class:

namespace App\Providers;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        Model::preventAccessingMissingAttributes();
    }
}

Now if we were to run our example code and attempt to access the full_name field on the App\Models\User model, we’d see an Illuminate\Database\Eloquent\MissingAttributeException exception thrown with the following message:

The attribute [full_name] either does not exist or was not retrieved for model [App\Models\User].

An additional benefit of using preventAccessingMissingAttributes is that it can highlight when we’re trying to read a field that exists on the model but that we might not have loaded. For example, let’s imagine we have the following code:

$user = User::query()
    ->select(['id', 'name'])
    ->first();

$user->email;

If we have prevented missing attributes from being accessed, the following exception would be thrown:

The attribute [email] either does not exist or was not retrieved for model [App\Models\User].

This can be incredibly useful when updating existing queries. For example, in the past, you may have only needed a few fields from a model. But maybe you’re now updating the feature in your application and need access to another field. Without having this method enabled, you might not realise that you’re trying to access a field that hasn’t been loaded.

It’s worth noting that the preventAccessingMissingAttributes method has been removed from the Laravel documentation (commit), but it still works. I’m not sure of the reason for its removal, but it’s something to be aware of. It might be an indication that it will be removed in the future.

Prevent Silently Discarding Attributes

Similar to preventAccessingMissingAttributes, Laravel provides a preventSilentlyDiscardingAttributes method that can help prevent unexpected behaviour when updating models.

Imagine you have an App\Models\User model class like so:

namespace App\Models;

use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    protected $fillable = [
        'name',
        'email',
        'password',
    ];
    
    // ...
}

As we can see, the name, email, and password fields are all fillable fields. But what would happen if we tried to update a non-existent field on the model (such as full_name) or a field that exists but isn’t fillable (such as email_verified_at)?:

$user = User::query()->first();

$user->update([
    'full_name' => 'Ash', // Field does not exist
    'email_verified_at' => now(), // Field exists but isn't fillable
    // Update other fields here too...
]);

If we were to run the code above, both the full_name and email_verified_at fields would be ignored because they haven’t been defined as fillable fields. But no errors would be thrown, so we would be unaware that the fields have been silently discarded.

As you’d expect, this could lead to hard-to-spot bugs in your application, especially if any other in your "update" statement were in fact updated. So we can use the preventSilentlyDiscardingAttributes method which will throw an exception whenever you try to update a field that doesn’t exist on the model or isn’t fillable.

To use this method, you can add the Model::preventSilentlyDiscardingAttributes() method call to your App\Providers\AppServiceProvider class:

namespace App\Providers;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        Model::preventSilentlyDiscardingAttributes();
    }
}

The above would force an error to be thrown.

Now if we were to try and run our example code from above and update the user’s first_name and email_verified_at fields, an Illuminate\Database\Eloquent\MassAssignmentException exception would be thrown with the following message:

Add fillable property [full_name, email_verified_at] to allow mass assignment on [App\Models\User].

It’s worth noting that the preventSilentlyDiscardingAttributes method will only highlight unfillable fields when you’re using a method such as fill or update. If you’re manually setting each property, it won’t catch these errors. For example, let’s take the following code:

$user = User::query()->first();

$user->full_name = 'Ash';
$user->email_verified_at = now();

$user->save();

In the code above, the full_name field doesn’t exist in the database, so rather than Laravel catching it for us, it would be caught at the database level. If you were using a MySQL database, you’d see an error like this:

SQLSTATE[42S22]: Column not found: 1054 Unknown column 'full_name' in 'field list' (Connection: mysql, SQL: update `users` set `email_verified_at` = 2024-08-02 16:04:08, `full_name` = Ash, `users`.`updated_at` = 2024-08-02 16:04:08 where `id` = 1)

Enable Strict Mode for Models

If you’d like to use the three methods that we’ve mentioned so far, you can enable them all at once using the Model::shouldBeStrict() method. This method will enable the preventLazyLoading, preventAccessingMissingAttributes, and preventSilentlyDiscardingAttributes settings.

To use this method, you can add the Model::shouldBeStrict() method call to your App\Providers\AppServiceProvider class:

namespace App\Providers;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        Model::shouldBeStrict();
    }
}

This is the equivalent of:

namespace App\Providers;

use Illuminate\Database\Eloquent\Model;

class AppServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        Model::preventLazyLoading();
        Model::preventSilentlyDiscardingAttributes();
        Model::preventAccessingMissingAttributes();
    }
}

Similar to the preventAccessingMissingAttributes method, the shouldBeStrict method has been removed from the Laravel documentation (commit) but still works. This might be an indication that it will be removed in the future.

Using UUIDs

By default, Laravel models use auto-incrementing IDs as their primary key. But there may be times when you’d prefer to use universally unique identifiers (UUIDs).

UUIDs are 128-bit (or 36-character) alphanumeric strings that can be used to uniquely identify resources. Due to how they’re generated, it’s highly unlikely that they’ll collide with another UUID. An example UUID is: 1fa24c18-39fd-4ff2-8f23-74ccd08462b0.

You may want to use a UUID as the primary key for a model. Or, you might want to keep your auto-incrementing IDs for defining relationships within your application and database, but use UUIDs for public-facings IDs. Using this approach can add an extra layer of security by making it harder for attackers to guess the IDs of other resources.

For example, say we are using auto-incrementing IDs in a route. We might have a route for accessing a user like so:

use App\Models\User;
use Illuminate\Support\Facades\Route;

Route::get('/users/{user}', function (User $user) {
    dd($user->toArray());
});

An attacker could loop through the IDs (e.g. – /users/1, /users/2, /users/3, etc.) in an attempt to try and access other users’ information if the routes aren’t secure. Whereas if we used UUIDs, the URLs might look more like /users/1fa24c18-39fd-4ff2-8f23-74ccd08462b0, /users/b807d48d-0d01-47ae-8bbc-59b2acea6ed3, and /users/ec1dde93-c67a-4f14-8464-c0d29c95425f. As you can imagine, these are much harder to guess.

Of course, just using UUIDs isn’t enough to protect your applications, they’re just an additional step you can take to improve the security. You need to make sure you’re also using other security measures like rate limiting, authentication, and authorization checks.

Use UUIDs as the Primary Key

We’ll first start by looking at how to change the primary key to UUIDs.

To do this, we’ll need to make sure our table has a column that’s capable of storing UUIDs. Laravel provides a handy $table->uuid method that we can use in our migrations.

Imagine we have this basic migration that creates a comments table:

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('comments', function (Blueprint $table) {
            $table->uuid();
            $table->foreignId('user_id');
            $table->foreignId('post_id');
            $table->string('content');
            $table->timestamps();
        });
    }

    // ...
}

As we can see in the migration, we’ve defined a UUID field. By default, this field will be called uuid, but you can change this by passing a column name to the uuid method if you’d like.

We then need to instruct Laravel to use the new uuid field as the primary key for our App\Models\Comment model. We also need to add a trait that will allow Laravel to generate UUIDs automatically for us. We can do this by overriding the $primaryKey property on our model and using the Illuminate\Database\Eloquent\Concerns\HasUuids trait:

namespace App\Models;

use Illuminate\Database\Eloquent\Concerns\HasUuids;
use Illuminate\Database\Eloquent\Model;

class Comment extends Model
{
    use HasUuids;

    protected $primaryKey = 'uuid';
}

The model should now be configured and ready to use UUIDs as the primary key. Take this example code:

use App\Models\Comment;
use App\Models\Post;
use App\Models\User;

$user = User::first();
$post = Post::first();

$comment = new Comment();
$comment->content = 'The comment content goes here.';
$comment->user_id = $user->id;
$comment->post_id = $post->id;
$comment->save();

dd($comment->toArray());

// [
//     "content" => "The comment content goes here."
//     "user_id" => 1
//     "post_id" => 1
//     "uuid" => "9cb16a60-8c56-46f9-89d9-d5d118108bc5"
//     "updated_at" => "2024-08-05T11:40:16.000000Z"
//     "created_at" => "2024-08-05T11:40:16.000000Z"
// ]

We can see in the dumped model that the uuid field has been populated with a UUID.

Add a UUID Field to a Model

If you’d prefer to keep your auto-incrementing IDs for internal relationships but use UUIDs for public-facing IDs, you can add a UUID field to your model.

We’ll assume your table has id and uuid fields. Since we’ll be using the id field as the primary key, we won’t need to define the $primaryKey property on our model.

We can override the uniqueIds method that’s made available via the Illuminate\Database\Eloquent\Concerns\HasUuids trait. This method should return an array of the fields that should have UUIDs generated for them.

Let’s update our App\Models\Comment model to include the field that we’ve called uuid:

namespace App\Models;

use Illuminate\Database\Eloquent\Concerns\HasUuids;
use Illuminate\Database\Eloquent\Model;

class Comment extends Model
{
    use HasUuids;

    public function uniqueIds(): array
    {
        return ['uuid'];
    }
}

Now if we were to dump a new App\Models\Comment model, we’d see that the uuid field has been populated with a UUID:

// [
//     "id" => 1
//     "content" => "The comment content goes here."
//     "user_id" => 1
//     "post_id" => 1
//     "uuid" => "9cb16a60-8c56-46f9-89d9-d5d118108bc5"
//     "updated_at" => "2024-08-05T11:40:16.000000Z"
//     "created_at" => "2024-08-05T11:40:16.000000Z"
// ]

We’ll take a look later in this article at how you can update your models and routes to use these UUIDs as your public-facing IDs in your routes.

Using ULIDs

Similar to using UUIDs in your Laravel models, you may sometimes want to use universally unique lexicographically sortable identifiers (ULIDs).

ULIDs are 128-bit (or 26-character) alphanumeric strings that can be used to uniquely identify resources. An example ULID is: 01J4HEAEYYVH4N2AKZ8Y1736GD.

You can define ULID fields in the exact same as you would UUID fields. The only difference is that instead of updating your model to use the Illuminate\Database\Eloquent\Concerns\HasUuids trait, you should use the Illuminate\Database\Eloquent\Concerns\HasUlids trait.

For example, if we wanted to update our App\Models\Comment model to use ULIDs as the primary key, we could do so like this:

namespace App\Models;

use Illuminate\Database\Eloquent\Concerns\HasUlids;
use Illuminate\Database\Eloquent\Model;

class Comment extends Model
{
    use HasUlids;
}

Changing the Field Used for Route Model Binding

You’ll likely already know what route model binding is. But just in case you don’t, let’s quickly go over it.

Route model binding allows you to automatically fetch instances of models based on data passed to your Laravel app’s routes.

By default, Laravel will use your model’s primary key field (typically an id field) for route model binding. For example, you might have a route for displaying the information for a single user:

use App\Models\User;
use Illuminate\Support\Facades\Route;

Route::get('/users/{user}', function (User $user) {
    dd($user->toArray());
});

The route defined in the example above will attempt to find a user that exists in the database with the provided ID. For example, let’s say a user with an ID of 1 exists in the database. When you visit the URL /users/1, Laravel will automatically fetch the user with an ID of 1 from the database and pass it to the closure function (or controller) for acting on. But if a model doesn’t exist with the provided ID, Laravel will automatically return a 404 Not Found response.

But there may be times when you’d like to use a different field (other than your primary key) to define how a model is retrieved from the database.

For example, as we’ve previously mentioned, you may want to use auto-incrementing IDs as your model’s primary keys for internal relationships. But you might want to use UUIDs for public-facing IDs. In this case, you might want to use the uuid field for route model binding instead of the id field.

Similarly, if you’re building a blog, you may want to fetch your posts based on a slug field instead of the id field. This is because a slug field is more human-readable and SEO-friendly than an auto-incrementing ID.

Changing the Field for All Routes

If you’d like to define the field that should be used for all routes, you can do so by defining a getRouteKeyName method on your model. This method should return the name of the field you’d like to use for route model binding.

For example, imagine we want to change all route model binding for an App\Models\Post model to use the slug field instead of the id field. We can do this by adding a getRouteKeyName method to our Post model:

namespace App\Models;

use Illuminate\Contracts\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    use HasFactory;

    public function getRouteKeyName()
    {
        return 'slug';
    }

    // ...
}

This means we could now define our routes like so:

use App\Models\Post;
use Illuminate\Support\Facades\Route;

Route::get('/posts/{post}', function (Post $post) {
    dd($post->toArray());
});

And when we visit the URL /posts/my-first-post, Laravel will automatically fetch the post with a slug of my-first-post from the database and pass it to the closure function (or controller) for acting on.

Changing the Field for Single Routes

However, there may be times when you only want to change the field used in a single route. For example, you might want to use the slug field for route model binding in one route, but the id field in all other routes.

We can do this by using the :field syntax in our route definition. For example, let’s say we want to use the slug field for route model binding in a single route. We can define our route like so:

Route::get('/posts/{post:slug}', function (Post $post) {
    dd($post->toArray());
});

This now means in this specific route, Laravel will attempt to fetch the post with the provided slug field from the database.

Use Custom Model Collections

When you fetch multiple models from the database using a method such as App\Models\User::all(), Laravel will typically put them inside an instance of the Illuminate\Database\Eloquent\Collection class. This class provides a lot of useful methods for working with the returned models. However, there may be times when you want to return a custom collection class instead of the default one.

You might want to create a custom collection for a few reasons. For instance, you might want to add some helper methods that are specific to dealing with that type of model. Or, maybe you want to use it for improved type safety and be sure that the collection will only contain models of a specific type.

Laravel makes it really easy to override the type of collection that should be returned.

Let’s take a look at an example. Let’s imagine we have an App\Models\Post model and when we fetch them from the database, we want to return them inside an instance of a custom App\Collections\PostCollection class.

We can create a new app/Collections/PostCollection.php file and define our custom collection class like so:

declare(strict_types=1);

namespace App\Collections;

use App\Models\Post;
use Illuminate\Support\Collection;

/**
 * @extends Collection<int, Post>
 */
class PostCollection extends Collection
{
    // ...
}

In the example above, we’ve created a new App\Collections\PostCollection class that extends Laravel’s Illuminate\Support\Collection class. We’ve also specified that this collection will only contain instances of the App\Models\Post class using the docblock. This is great for helping your IDE understand the type of data that will be inside the collection.

We can then update our App\Models\Post model to return an instance of our custom collection class by overriding the newCollection method like so:

namespace App\Models;

use App\Collections\PostCollection;
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    // ...

    public function newCollection(array $models = []): PostCollection
    {
        return new PostCollection($models);
    }
}

In the example, we’ve taken the array of App\Models\Post models that are passed to the newCollection method and returned a new instance of our custom App\Collections\PostCollection class.

Now we can fetch our posts from the database using our custom collection class like so:

use App\Models\Post;

$posts = Post::all();

// $posts is an instance of App\Collections\PostCollection

Comparing Models

A common issue that I see when working on projects is how models are compared. This is usually within authorization checks when you want to check whether a user can access a resource.

Let’s look at some of the common gotchas and why you should probably avoid using them.

You should avoid using === when checking if two models are the same. This is because the === check, when comparing objects, will check if they are the same instance of the object. This means that even if two models have the same data, they won’t be considered the same if they are different instances. So you should avoid doing this, as it will likely return false.

Assuming a post relationship exists on an App\Models\Comment model and that the first comment in the database belongs to the first post, let’s look at an example:

// ⚠️ Avoid using `===` to compare models

$comment = \App\Models\Comment::first();
$post = \App\Models\Post::first();

$postsAreTheSame = $comment->post === $post;

// $postsAreTheSame will be false.

You should also avoid using == when checking if two models are the same. This is because the == check, when comparing objects, will check if they are an instance of the same class and if they have the same attributes and values. However, this can lead to unexpected behaviour.

Take this example:

// ⚠️ Avoid using `==` to compare models

$comment = \App\Models\Comment::first();
$post = \App\Models\Post::first();

$postsAreTheSame = $comment->post == $post;

// $postsAreTheSame will be true.

In the example above, the == check will return true because $comment->post and $post are the same class and have the same attributes and values. But what would happen if we changed the attributes in the $post model so they were different?

Let’s use the select method so we only grab the id and content fields from the posts table:

// ⚠️ Avoid using `==` to compare models

$comment = \App\Models\Comment::first();
$post = \App\Models\Post::query()->select(['id', 'content'])->first();

$postsAreTheSame = $comment->post == $post;

// $postsAreTheSame will be false.

Even though $comment->post is the same model as $post, the == check will return false because the models have different attributes loaded. As you can imagine, this can lead to some unexpected behaviour that can be pretty difficult to track down, especially if you’ve retrospectively added the select method to a query and your tests start failing.

Instead, I like to use the is and isNot methods that Laravel provides. These methods will compare two models and check they belong to the same class, have the same primary key value, and have the same database connection. This is a much safer way to compare models and will help to reduce the likelihood of unexpected behaviour.

You can use the is method to check if two models are the same:

$comment = \App\Models\Comment::first();
$post = \App\Models\Post::query()->select(['id', 'content'])->first();

$postsAreTheSame = $comment->post->is($post);

// $postsAreTheSame will be true.

Similarly, you can use the isNot method to check if two models are not the same:

$comment = \App\Models\Comment::first();
$post = \App\Models\Post::query()->select(['id', 'content'])->first();

$postsAreNotTheSame = $comment->post->isNot($post);

// $postsAreNotTheSame will be false.

Use whereBelongsTo When Building Queries

This last tip is more of a personal preference, but I find that it makes my queries easier to read and understand.

When attempting to fetch models from the database, you might find yourself writing queries that filter based on relationships. For example, you might want to fetch all comments that belong to a specific user and post:

$user = User::first();
$post = Post::first();

$comments = Comment::query()
    ->where('user_id', $user->id)
    ->where('post_id', $post->id)
    ->get();

Laravel provides a whereBelongsTo method that you can use to make your queries more readable (in my opinion). Using this method, we could rewrite the query above like so:

$user = User::first();
$post = Post::first();

$comments = Comment::query()
    ->whereBelongsTo($user)
    ->whereBelongsTo($post)
    ->get();

I like this syntactic sugar and feel like it makes the query more human-readable. It’s also a great way to ensure that you’re filtering based on the correct relationship and field.

You, or your team, may prefer to use the more explicit approach of writing out the where clauses. So this tip might not be for everyone. But I think as long as you’re consistent with your approach, either way is perfectly fine.

Conclusion

Hopefully, this article should have shown you some new tips for working with Laravel models. You should now be able to spot and prevent N+1 issues, prevent accessing missing attributes, prevent silently discarding attributes, and change the primary key type to UUIDs or ULIDs. You should also know how to change the field used for route model binding, specify the type of collection returned, compare models, and use whereBelongsTo when building queries.


The post Laravel Model Tips appeared first on Laravel News.

Join the Laravel Newsletter to get all the latest
Laravel articles like this directly in your inbox.

Laravel News

New Ryobi Cordless Butt Warmer!

https://i0.wp.com/toolguyd.com/blog/wp-content/uploads/2024/08/Ryobi-USB-Lithium-Heated-Cushion-Used-by-Construction-Worker.jpg?resize=600%2C450&ssl=1

Ryobi USB Lithium Heated Cushion Used by Construction Worker

Ryobi is about to launch a new battery-powered cordless butt warmer!

Officially called a Heated Cushion Kit, the new tush heater (model FVT51K) will be part of their USB lithium line of cordless tools and accessories.

The Ryobi heated seat warmer features 3 temperature settings and up to 5 hours or charge on 2x 2Ah batteries set to low.

Ryobi USB Lithium Heated Cushion Used at Stadium

It measures 3″ thick, for padded comfort in different environments, from jobsites to bleacher seats.

Ryobi USB Lithium Heated Cushion X-Ray View

Ryobi says that the cordless heated cushion can a temperature of up to 150°.

Ryobi USB Lithium Heated Cushion Power Pack

The included power pack works with 2x Ryobi Lithium USB batteries and has a built-in fuel gauge. It looks like there’s also a hole for a lanyard strap.

Ryobi USB Lithium Heated Cushion Power Pack Battery Configuration

Here are expected runtimes for the 3 temperature settings when the cushion is powered by 2x 2Ah batteries:

  • High (150°) – 2 hours
  • Medium (130°) – 3.5 hours
  • Low (110°) – 5 hours
Ryobi USB Lithium Heated Cushion and Power Pack Charging Phone

The power adapter has a USB-C output and doubles as a mobile device charger.

Ryobi USB Lithium Heated Cushion Kit FVT51K

The kit comes with the heated cushion, power pack, 2x 2Ah batteries, and a charging cable.

Price: $89
ETA: October 2024

The heated seat warmer will be available exclusively at Home Depot.

Discussion

A heated butt warmer…??

Makita Cordless Heated Jacket DCB200A Worn Over Pants

It’s not exactly unprecedented. Makita was first to tackle this type of product, with their heated blanket.

Ryobi’s new heated cushion makes sense. I wonder if it’s suitable for use in other environments, outside of broad jobsites, tailgating, and stadiums, such as outdoors for camping.

Will its 2-5 hrs runtime be a downside?

This looks to be Ryobi’s first dual battery USB Lithium product, and one big question comes to mind – what else might the new mobile-charging-capable power back be used for?

ToolGuyd

Receive inbound email with Laravel

https://opengraph.githubassets.com/2305774d1659683786b6e15037504edf7c06cfafa867d39ae79ad7ef401b55f1/proxied-mail/laravel-receive-email

ProxiedMail Client | Receive email via webhook Laravel

ProxiedMail 👷‍♀️ is a simple package for the base library to create proxy emails and receive webhooks or simply browse email list.
You can find the base PHP library at https://github.com/proxied-mail/proxiedmail-php-client

You’re welcome to visit the docs.

ProxiedMail is a tool that brings the email experience to a new level because it was built around the privacy first concept that enhances using a unique email each time which makes it a second password, but also allows you more control over your correspondence.
Additionally, it gives you the advantage of moving to another email provider just in a few seconds.
Because we have this kind of system we also aim to bring more into the experience of development using emails.

🛠 Creating endless proxy emails with one of ProxiedMail domains (i.e abc@proxiedmail.com, abcd@pxdmail.com, abcde@pxdmail.net)

🛠 Setting up forwarding email or disabling forwarding

🛠 Setting up a callback to your URL

🛠 Browsing received emails on the received emails endpoint

🛠 Setting up custom domains. You can do everything using your domain as well.

🛠 Domain-to-domain forwarding. Just in case you need it we can forward emails by mask, like *@domainhostedatproxiedmail.com -> *someotherdomain.com. In this case, the MX of the first domain should be pointed to ProxiedMail and the second domain should be verified by TXT record.

Via composer

$ composer require proxiedmail/laravel-receive-email

This package provide auto-discovery for service provider

If Laravel package auto-discovery is disabled, add service providers manually to /config/app.php. There are service provider you must add:

\ProxiedMail\Client\Providers\ProxiedMailServiceProvider::class

Publish client configuration:

php artisan vendor:publish --tag=proxiedmail

Configure ProxiedMail client:

Put your ProxiedMail API token in /config/proxiedmail.php. You can find this token in ProxiedMail API Settings.

return [
    'apiToken' => 'YOUR API TOKEN',
    'host' => 'https://proxiedmail.com',
];

This example demonstrates create proxy emails, browse received emails and receive emails via webhook.

use ProxiedMail\Client\Bridge\ProxiedMailClient;
use ProxiedMail\Client\Facades\ApiFacade;

class ExampleController
{
    public function browseReceivedEmails(ProxiedMailClient $proxiedMailClient)
    {
        /**
 * @var ApiFacade $api
 */
        $api = $proxiedMailClient->getClient();

        $proxyEmail = $api->createProxyEmail(
            [],
            null,
            null,
            null,
            true
        );


        // while (true) with 100 seconds limit
        foreach (range(0, 180) as $non) {
            echo "PROXY-EMAIL: " . $proxyEmail->getProxyAddress() . "\n";
            echo "Time limit is 3 mins \n";
            echo "Send the email to this proxy-email to get email payload printed here \n";

            //checking webhook receiver

            $receivedEmails = $api->getReceivedEmailsLinksByProxyEmailId($proxyEmail->getId())->getReceivedEmailLinks();
            echo "Amount of received emails: " . count($receivedEmails) . "\n";
            foreach ($receivedEmails as $receivedEmail) {
                echo "Have received email: \n";
                var_dump($receivedEmail);

                echo "\n";
            }

            echo "\n";

            sleep(1);
        }
    }


    public function receiveEmailViaWebhook(ProxiedMailClient $proxiedMailClient)
    {
        /**
 * @var ApiFacade $api
 */
        $api = $proxiedMailClient->getClient();

        $wh = $api->createWebhook(); //creating webhook-receiver
        $proxyEmail = $api->createProxyEmail(
            [],
            null,
            $wh->getCallUrl() //specifying webhook url
        );


        // while (true) with 100 seconds limit
        foreach (range(0, 100) as $non) {
            echo "PROXY-EMAIL: " . $proxyEmail->getProxyAddress() . "\n";
            echo "Send the email to this proxy-email to get email payload printed here";

            //checking webhook receiver
            $whStatus = $api->statusWebhook($wh->getId());

            echo "Webhook STATUS: \n";
            echo "Received: " . ($whStatus->isReceived() ? 'yes' : 'no') . "\n"; //printing webhook status

            //printing payload if received
            if ($whStatus->isReceived()) {
                echo "WEBHOOK PAYLOAD: \n";
                echo json_encode($whStatus->getPayload());
                break;
            }


            echo "\n";

            sleep(1);
        }
    }
}

You can create find the UI on ProxiedMail to manage your domains, emails, and webhooks.

Please feel free to fork and sending Pull Requests. This project follows Semantic Versioning 2 and PSR-2.

GPL3. Please see License File for more information.

For any questions please contact laraclient@pxdmail.com

Also please check out the article how to receive emails in Laravel in our blog.
If you’re interested in receiving emails in PHP use the library for pure PHP.

Article: how to receive emails in PHP

Laravel News Links