How to Upload Images With Spatie Media Library in Laravel

https://laracoding.com/wp-content/uploads/2024/02/upload-image-spatie-media-library1.png

The Spatie Media Library simplifies the process of handling media files, such as images, in Laravel. It provides features for storage, manipulation, and retrieval of media files. One of the strengths of the package is that you can easily associate uploaded files with your Eloquent Models.

In this guide, you will learn how to integrate the Media Library package into an application. We’ll use it to associate uploaded images with an Eloquent Model, specifically the Product model.

We’ll cover all the required steps like the package installation process, model setup, defining a migration, creating the controller, views and routes to show products, show a product form with upload and storing new products.

Let’s get started!

Step 1: Install Laravel

Begin by creating a new Laravel project using Composer by running:

composer create-project --prefer-dist laravel/laravel product-media-demo

Step 2: Install Spatie Media Library

Next, install the Spatie Media Library package via Composer. Run the following command in your terminal:

composer require "spatie/laravel-medialibrary:^11.0.0"

After this has finished, we need to run following command to publish a migration the media library requires to work properly:

php artisan vendor:publish --provider="Spatie\MediaLibrary\MediaLibraryServiceProvider" --tag="medialibrary-migrations"

What this publishing does is it creates a file like, for example database/migrations/2024_02_26_203939_create_media_table.php . This migration serves to define a table ‘media’ with all the columns predefined as they are required by media library.

Afterwards we need to execute this migration by running:

The Spatie Media Library has now been successfully installed.

Step 3: Create Model and Migration

Now, let’s create a “Product” model along with its migration by running:

php artisan make:model Product -m

Step 4: Add Migration Code

Open the generated migration file (database/migrations/YYYY_MM_DD_create_products_table.php) and add additional columns that could be encountered in a real-world product application, such as “name,” “description,” “price,” and “image”:

database/migrations/2024_02_25_184519_create_products_table.php

<?php

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

return new class extends Migration
{
 public function up()
 {
 Schema::create('products', function (Blueprint $table) {
 $table->id();
 $table->string('name');
 $table->text('description')->nullable();
 $table->decimal('price', 8, 2);
 $table->string('image')->nullable(); // Added for image path
 $table->timestamps();
 });
 }

 public function down()
 {
 Schema::dropIfExists('products');
 }
};

Step 5: Run Migration

Now, run the migration to create the products table in the database:

Step 6: Add Model Code

Open the “Product” model (app\Models\Product.php) and configure it to use the Spatie Media Library trait and implement the HasMedia interface.

app\Models\Product.php

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia;

class Product extends Model implements HasMedia
{
 use InteractsWithMedia;

 protected $fillable = ['name', 'description', 'price', 'image'];
}

Defining our Model this way allows us to associate media, like an uploaded image, with each instance of a Product. We’ll see exactly how this is used, when we add our controller code in step 9.

Step 7: Create Controller

Generate a controller named “ProductController” by running the following Artisan command:

php artisan make:controller ProductController

Step 8: Add Controller Code

Now open the generated “ProductController” (app\Http\Controllers\ProductController.php) and implement the methods below to list an index page with products, show a create product form and finally storing a new product along with its uploaded image:

app/Http/Controllers/ProductController.php

<?php

namespace App\Http\Controllers;

use App\Models\Product;
use Illuminate\Http\Request;

class ProductController extends Controller
{
 // Display a list of created products along with their images
 public function index()
 {
 $products = Product::latest()->paginate(10);
 return view('products.index', compact('products'));
 }

 // Display the form to create a new product
 public function create()
 {
 return view('products.create');
 }

 // Store a new product along with its uploaded image file
 public function store(Request $request)
 {
 $request->validate([
 // Sets a max image upload file size of 2048 kilobytes or 2MB, adjust as needed:
 'image' => 'required|image|max:2048',
 // Validate that other fields contain proper values too:
 'name' => 'required|string|max:255',
 'description' => 'nullable|string|max:255',
 'price' => 'required|numeric|min:0|max:999999.99',
 ]);

 // First create the product in the database using the Eloquent model
 $product = Product::create($request->validated());

 // Then associate the uploaded image file with the product
 $product->addMediaFromRequest('image')->toMediaCollection('product-images');

 // Send the user back to the product list page
 return redirect(route('products.index'))->with('success', 'Product created successfully.');
 }
}

Step 9: Add a View to Create a Product

In this step we’ll create a view that contains the form to add a new product along with an uploaded image.

I made sure the blade code offers a nicely layouted form that shows error messages for missing or invalid values. This way we can guarantee the user is prompted to always upload an actual image file and fill the required fields name and price.

Create a file at resources/views/products/create.blade.php and add the following code:

resources/views/products/create.blade.php

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <title>Excel Import</title>
 <!-- Bootstrap CSS -->
 <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container mt-5">
 <h1 class="my-4">Create Product</h1>
 <form action="" method="POST" enctype="multipart/form-data">
 @csrf
 <div class="mb-3">
 <label for="name" class="form-label">Name</label>
 @error('name')
 <div class="text-danger">
 <small></small>
 </div>
 @enderror
 <input type="text" class="form-control" id="name" name="name">
 </div>
 <div class="mb-3">
 <label for="description" class="form-label">Description</label>
 @error('description')
 <div class="text-danger">
 <small></small>
 </div>
 @enderror
 <textarea class="form-control" id="description" name="description"></textarea>
 </div>
 <div class="mb-3">
 <label for="price" class="form-label">Price</label>
 @error('price')
 <div class="text-danger">
 <small></small>
 </div>
 @enderror
 <input type="number" step="0.01" class="form-control" id="price" name="price">
 </div>
 <div class="mb-3">
 <label for="image" class="form-label">Product Image</label>
 @error('image')
 <div class="text-danger">
 <small></small>
 </div>
 @enderror
 <input type="file" class="form-control" id="image" name="image">
 </div>
 <button type="submit" class="btn btn-primary">Create Product</button>
 </form>
</div>

</body>
</html>

Step 10: Create a View to Show Products

In this step we’ll create a view that allows us to show all products. We will use Spatie Media Library to render a thumbnail of the uploaded product image.

Create a file at resources/views/products/index.blade.php and add the following code:

resources/views/products/index.blade.php

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <title>Excel Import</title>
 <!-- Bootstrap CSS -->
 <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container mt-5">

 <!-- Display success message if it was set-->
 @if(session('success'))
 <div class="alert alert-success"></div>
 @endif

 <h1 class="my-4">Product Listing</h1>
 <table class="table">
 <thead>
 <tr>
 <th colspan="3"></th>
 <th class="text-end">
 <a href="" class="btn btn-primary">Create Product</a>
 </th>
 </tr>
 <tr>
 <th>Name</th>
 <th>Description</th>
 <th>Price</th>
 <th>Image</th>
 </tr>
 </thead>
 <tbody>
 @foreach($products as $product)
 <tr>
 <td></td>
 <td></td>
 <td></td>
 <!-- Fetch a thumbnail image based on the product's associated media -->
 <td><img src="" alt="Product Image" width="140px"></td>
 </tr>
 @endforeach
 </tbody>
 </table>
 
</div>

</body>
</html>

Step 11: Define Routes

Finally, before we can test the application, we need to define the routes to list products, show the create form, and store a product.

Open routes/web.php and add:

routes/web.php

<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\ProductController;

Route::get('/products', [ProductController::class, 'index'])->name('products.index');
Route::get('/products/create', [ProductController::class, 'create'])->name('products.create');
Route::post('/products', [ProductController::class, 'store'])->name('products.store');

Step 12: Test the Application

You can now test the application by running the development server:

Now you can navigate to http://127.0.0.1:8000/products in your browser to view the product listing. Proceed to http://127.0.0.1:8000/products/create to access the create product form.

Screenshot of the Create Product Form with Image Upload

Select an image to upload and fill in the other product details and submit the form. Verify that the product and its associated image are successfully stored in the database.

After storing the form your database contents should look somewhat like this:

Screenshot Showing the Records Stored in products and Associated media Table

Now if you continue and upload a few more you’ll see it nicely displays all the thumbnail images on the product page:

That’s it! You’ve successfully built your first application that uses Spatie Media Library to manage its uploaded media files.

Conclusion

In this tutorial, we’ve explored how to upload images using the Spatie Media Library package in a Laravel application. By following the steps outlined above, you can easily handle image uploads and storage in your Laravel projects.

Using third party packages like this can greatly speed up your development process. Before you use a package in your production application, check that the package is well maintained, supports your Laravel version, is properly documented and does not have lots of unresolved issues posted on their git page.

Spatie is a well-known company that has been developing and maintaining numerous packages for years and provides them for free as open source. The Media Library is one of their most widely used packages and is likely to meet most quality requirements.

I hope this helped you get started in using this handy third party package. Let me know in the comments what you’re using it for, how it went and what issues you may have had with it.

Happy Coding!

References

Laravel News Links

How to Upload Images With Spatie Media Library in Laravel

https://laracoding.com/wp-content/uploads/2024/02/upload-image-spatie-media-library1.png

The Spatie Media Library simplifies the process of handling media files, such as images, in Laravel. It provides features for storage, manipulation, and retrieval of media files. One of the strengths of the package is that you can easily associate uploaded files with your Eloquent Models.

In this guide, you will learn how to integrate the Media Library package into an application. We’ll use it to associate uploaded images with an Eloquent Model, specifically the Product model.

We’ll cover all the required steps like the package installation process, model setup, defining a migration, creating the controller, views and routes to show products, show a product form with upload and storing new products.

Let’s get started!

Step 1: Install Laravel

Begin by creating a new Laravel project using Composer by running:

composer create-project --prefer-dist laravel/laravel product-media-demo

Step 2: Install Spatie Media Library

Next, install the Spatie Media Library package via Composer. Run the following command in your terminal:

composer require "spatie/laravel-medialibrary:^11.0.0"

After this has finished, we need to run following command to publish a migration the media library requires to work properly:

php artisan vendor:publish --provider="Spatie\MediaLibrary\MediaLibraryServiceProvider" --tag="medialibrary-migrations"

What this publishing does is it creates a file like, for example database/migrations/2024_02_26_203939_create_media_table.php . This migration serves to define a table ‘media’ with all the columns predefined as they are required by media library.

Afterwards we need to execute this migration by running:

The Spatie Media Library has now been successfully installed.

Step 3: Create Model and Migration

Now, let’s create a “Product” model along with its migration by running:

php artisan make:model Product -m

Step 4: Add Migration Code

Open the generated migration file (database/migrations/YYYY_MM_DD_create_products_table.php) and add additional columns that could be encountered in a real-world product application, such as “name,” “description,” “price,” and “image”:

database/migrations/2024_02_25_184519_create_products_table.php

<?php

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

return new class extends Migration
{
 public function up()
 {
 Schema::create('products', function (Blueprint $table) {
 $table->id();
 $table->string('name');
 $table->text('description')->nullable();
 $table->decimal('price', 8, 2);
 $table->string('image')->nullable(); // Added for image path
 $table->timestamps();
 });
 }

 public function down()
 {
 Schema::dropIfExists('products');
 }
};

Step 5: Run Migration

Now, run the migration to create the products table in the database:

Step 6: Add Model Code

Open the “Product” model (app\Models\Product.php) and configure it to use the Spatie Media Library trait and implement the HasMedia interface.

app\Models\Product.php

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia;

class Product extends Model implements HasMedia
{
 use InteractsWithMedia;

 protected $fillable = ['name', 'description', 'price', 'image'];
}

Defining our Model this way allows us to associate media, like an uploaded image, with each instance of a Product. We’ll see exactly how this is used, when we add our controller code in step 9.

Step 7: Create Controller

Generate a controller named “ProductController” by running the following Artisan command:

php artisan make:controller ProductController

Step 8: Add Controller Code

Now open the generated “ProductController” (app\Http\Controllers\ProductController.php) and implement the methods below to list an index page with products, show a create product form and finally storing a new product along with its uploaded image:

app/Http/Controllers/ProductController.php

<?php

namespace App\Http\Controllers;

use App\Models\Product;
use Illuminate\Http\Request;

class ProductController extends Controller
{
 // Display a list of created products along with their images
 public function index()
 {
 $products = Product::latest()->paginate(10);
 return view('products.index', compact('products'));
 }

 // Display the form to create a new product
 public function create()
 {
 return view('products.create');
 }

 // Store a new product along with its uploaded image file
 public function store(Request $request)
 {
 $request->validate([
 // Sets a max image upload file size of 2048 kilobytes or 2MB, adjust as needed:
 'image' => 'required|image|max:2048',
 // Validate that other fields contain proper values too:
 'name' => 'required|string|max:255',
 'description' => 'nullable|string|max:255',
 'price' => 'required|numeric|min:0|max:999999.99',
 ]);

 // First create the product in the database using the Eloquent model
 $product = Product::create($request->validated());

 // Then associate the uploaded image file with the product
 $product->addMediaFromRequest('image')->toMediaCollection('product-images');

 // Send the user back to the product list page
 return redirect(route('products.index'))->with('success', 'Product created successfully.');
 }
}

Step 9: Add a View to Create a Product

In this step we’ll create a view that contains the form to add a new product along with an uploaded image.

I made sure the blade code offers a nicely layouted form that shows error messages for missing or invalid values. This way we can guarantee the user is prompted to always upload an actual image file and fill the required fields name and price.

Create a file at resources/views/products/create.blade.php and add the following code:

resources/views/products/create.blade.php

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <title>Excel Import</title>
 <!-- Bootstrap CSS -->
 <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container mt-5">
 <h1 class="my-4">Create Product</h1>
 <form action="" method="POST" enctype="multipart/form-data">
 @csrf
 <div class="mb-3">
 <label for="name" class="form-label">Name</label>
 @error('name')
 <div class="text-danger">
 <small></small>
 </div>
 @enderror
 <input type="text" class="form-control" id="name" name="name">
 </div>
 <div class="mb-3">
 <label for="description" class="form-label">Description</label>
 @error('description')
 <div class="text-danger">
 <small></small>
 </div>
 @enderror
 <textarea class="form-control" id="description" name="description"></textarea>
 </div>
 <div class="mb-3">
 <label for="price" class="form-label">Price</label>
 @error('price')
 <div class="text-danger">
 <small></small>
 </div>
 @enderror
 <input type="number" step="0.01" class="form-control" id="price" name="price">
 </div>
 <div class="mb-3">
 <label for="image" class="form-label">Product Image</label>
 @error('image')
 <div class="text-danger">
 <small></small>
 </div>
 @enderror
 <input type="file" class="form-control" id="image" name="image">
 </div>
 <button type="submit" class="btn btn-primary">Create Product</button>
 </form>
</div>

</body>
</html>

Step 10: Create a View to Show Products

In this step we’ll create a view that allows us to show all products. We will use Spatie Media Library to render a thumbnail of the uploaded product image.

Create a file at resources/views/products/index.blade.php and add the following code:

resources/views/products/index.blade.php

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <title>Excel Import</title>
 <!-- Bootstrap CSS -->
 <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container mt-5">

 <!-- Display success message if it was set-->
 @if(session('success'))
 <div class="alert alert-success"></div>
 @endif

 <h1 class="my-4">Product Listing</h1>
 <table class="table">
 <thead>
 <tr>
 <th colspan="3"></th>
 <th class="text-end">
 <a href="" class="btn btn-primary">Create Product</a>
 </th>
 </tr>
 <tr>
 <th>Name</th>
 <th>Description</th>
 <th>Price</th>
 <th>Image</th>
 </tr>
 </thead>
 <tbody>
 @foreach($products as $product)
 <tr>
 <td></td>
 <td></td>
 <td></td>
 <!-- Fetch a thumbnail image based on the product's associated media -->
 <td><img src="" alt="Product Image" width="140px"></td>
 </tr>
 @endforeach
 </tbody>
 </table>
 
</div>

</body>
</html>

Step 11: Define Routes

Finally, before we can test the application, we need to define the routes to list products, show the create form, and store a product.

Open routes/web.php and add:

routes/web.php

<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\ProductController;

Route::get('/products', [ProductController::class, 'index'])->name('products.index');
Route::get('/products/create', [ProductController::class, 'create'])->name('products.create');
Route::post('/products', [ProductController::class, 'store'])->name('products.store');

Step 12: Test the Application

You can now test the application by running the development server:

Now you can navigate to http://127.0.0.1:8000/products in your browser to view the product listing. Proceed to http://127.0.0.1:8000/products/create to access the create product form.

Screenshot of the Create Product Form with Image Upload

Select an image to upload and fill in the other product details and submit the form. Verify that the product and its associated image are successfully stored in the database.

After storing the form your database contents should look somewhat like this:

Screenshot Showing the Records Stored in products and Associated media Table

Now if you continue and upload a few more you’ll see it nicely displays all the thumbnail images on the product page:

That’s it! You’ve successfully built your first application that uses Spatie Media Library to manage its uploaded media files.

Conclusion

In this tutorial, we’ve explored how to upload images using the Spatie Media Library package in a Laravel application. By following the steps outlined above, you can easily handle image uploads and storage in your Laravel projects.

Using third party packages like this can greatly speed up your development process. Before you use a package in your production application, check that the package is well maintained, supports your Laravel version, is properly documented and does not have lots of unresolved issues posted on their git page.

Spatie is a well-known company that has been developing and maintaining numerous packages for years and provides them for free as open source. The Media Library is one of their most widely used packages and is likely to meet most quality requirements.

I hope this helped you get started in using this handy third party package. Let me know in the comments what you’re using it for, how it went and what issues you may have had with it.

Happy Coding!

References

Laravel News Links

Ludicrous Speed Panel

https://theawesomer.com/photos/2024/03/ludicrous_speed_switch_t.jpg

Ludicrous Speed Panel

 | Buy

Level up your transportation with the Spaceballs-inspired Ludicrous Speed Panel from Concord Aerospace. Turn its dial to increase your speed from Light to Ridiculous to Ludicrous, then go to Plaid. The Apollo-era control panel has a working main switch hidden under a “GO” cover, and its knob can be equipped with a potentiometer for controlling devices.

The Awesomer

Laravel SNS-SQS Queue

https://repository-images.githubusercontent.com/735853054/5a90530f-a552-4b85-8eb9-85bd918bc981

'connections' => [
   ...
   'sns-sqs' => [
      'driver' => 'sns-sqs',
      'key' => env('AWS_ACCESS_KEY_ID'),
      'secret' => env('AWS_SECRET_ACCESS_KEY'),
      'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
      'prefix' => env('SQS_PREFIX', 'https://sqs.us-east-1.amazonaws.com/your-account-id'),
      'queue' => env('SQS_QUEUE', 'default'),
      'suffix' => env('SQS_SUFFIX'),
      'after_commit' => false,
      'endpoint' => env('AWS_ENDPOINT'),
      'sns_topic_arn' => env('SNS_TOPIC_ARN', 'arn:aws:sns:us-east-1:your-account-id:topic'),
  ],
]

Laravel News Links

Dark Forces Remastered makes a classic Star Wars shooter feel fast and fluid

https://cdn.arstechnica.net/wp-content/uploads/2024/02/Screenshot-2024-02-26-160712-760×380.png

Player holding a gun inside an Alliance base in Dark Forces.

Enlarge / Do you ever wonder why no contractor has been able to deliver to the Empire a standardized blaster rifle that shoots right where the crosshairs are aiming? Is this covered in the "Legends" extended universe?

Nightdive Studios/LucasFilm

I remember Dark Forces, or Star Wars: Doom, as a slog. Running a demo of the 1995 game on a Gateway system with an Intel 486DX at 33 MHz, I trudged through seemingly endless gray hallways. I shot at a steady trickle of Stormtroopers with one their own (intentionally) semi-accurate blaster rifles. After a while, I would ask myself a pertinent, era-specific question: Why was I playing this low-energy nostalgia trip instead of actual Doom?

Dark Forces moved first-person shooters forward in a number of ways. It could lean on Star Wars for familiar sounds and enemies and tech, and a plot with a bit more complexity than "They’re demons, they gotta go." It let the player look up and down, jump, and crouch, which were big steps for the time. And its level design went beyond "find the blue key for the blue door," with some clever environmental puzzles and challenges.

Not that key cards don’t show up. This game is from 1995, so there are key cards, there are hidden wall-doors, and there are auto-spawning enemies. It’s not like the Dark Forces designers could entirely ignore Doom. Nobody could.

Having played through some enjoyable hours of Dark Forces Remaster, I’ve come around quite a bit on this Doom-era game’s worthiness. In 2024, I can joyfully rip through research facilities, foundries, sewers, and space stations at a breakneck clip, stuffing bad guys full of laser blasts from every angle and distance. The grenades (err, thermal detonators) actually feel viable and fun to use. The levels, and the game as a whole, are higher resolution and easier to appreciate at this faster, more frenetic pace.

  • Now you’re all in big, big trouble (because this gun shoots relatively straight).


    Nightdive Studios/LucasFilm

  • A close-up of a gray rock, gray walls, and a gray blaster in Dark Forces.


    Nightdive Studios/LucasFilm

  • You forget that Star Wars has an infinite number of worlds it can put its characters into, besides Tatooine.


    Nightdive Studios/LucasFilm

  • Alright, that does it—we’re heading to Florida.


    Nightdive Studios/LucasFilm

  • Okay, he doesn’t live in Florida, but it’s still pretty swampy.


    Nightdive Studios/LucasFilm

Nightdive Studios continues its streak of providing spiffed-up but eminently faithful remasters of classic titles with Dark Forces Remastered. The studio’s leaders told Ars last year that their goal was games that "play the way you remember them playing. Not the way they actually did on your 486 [computer], but in an evocative manner." For me, Dark Forces Remastered feels far, far better than I remember, and so I’ve gotten a chance to absorb a lot more of the world it’s trying to evoke.

Nightdive Studios/LucasFilm

An elegant shooter full of clumsy blasters

A quick primer on Dark Forces: You are mercenary Kyle Katarn, working for the Rebellion around the time of Episode IV (the first Death Star one), helping the rebels investigate and halt the development of Dark Troopers. Dark Troopers are essentially Stormtroopers with big shoulder pauldrons and the ability to deflect blaster fire. You can use all kinds of found weapons, including blasters, land mines, and rocket launchers. But you will not become a Jedi, because that happens in the next game.

Due either to thematic or technical restrictions of the time, you’re not typically fighting huge arenas of baddies. You are meant to sneak through hallways and turn corners, popping a few at a time. Unless you’re me, that is, liberated by playing at 4K at 120 frames per second (and, sometimes, cheat codes), wantonly wrecking dudes who didn’t get the memo about my arrival.

The little voice stings—"Stop!" "You’re not authorized!"—were a delight, if often cut short by the quick dispatching of their speaker. For the first few levels, I felt like the Rebellion could have destroyed five Death Stars in just two movies if they had a few more Kyles like me. But Dark Forces does ramp up as you go on.

All the same cheat codes from the original game work—Nightdive even gives you places to type them in and then activate them in menus—and I had to lean on a couple level skips and resupplies to get through the first seven levels. The objectives get far twistier and "What did flipping that switch do?" as you roll on. Some of the battery-powered devices, like infrared goggles and gas masks, are all but essential at times, and the long levels with their repeating wall textures can have you wasting them. It’s never quite unfair, but you realize how tough this must have been at a far lower frame rate and walking speed. And without such easy access to online walk-throughs, of course.

There are new lighting effects, much nicer menus and options, gamepad support (including rumble), and polished cutscenes, in addition to the gameplay that now tilts a bit more toward Motörhead than Rush in speed and feel. But, really, what sells Dark Forces Remastered is the game beneath the upgrades. If you have any interest in hopping on Jabba the Hutt’s barge again, this is the way to do it.

Listing image by Nightdive/LucasFilm

Ars Technica – All content

Six Essential Plugins for Visual Studio Code

https://picperf.io/https://laravelnews.s3.amazonaws.com/featured-images/future-ide-featured-vscode.jpg

Six Essential Plugins for Visual Studio Code

We’ve created a collection of essential plugins for Visual Studio Code that will supercharge your coding experience. I’ve gathered my favorite extensions to make you a more productive PHP developer and even threw in my favorite theme for VS Code.

Let’s dive in!

Laravel Blade Formatter

The Laravel Blade formatter is an opinionated Blade file formatter for VS Code. This extension uses the shufo/blade-formatter NPM package that you can use to format Blade template files programmatically.

Another alternative is the shufo/prettier-plugin-blade if you’d rather use the Prettier formatter instead. VS Code has a Prettier plugin that you can use to incorporate this workflow on save. The VSCode section of the readme has setup instructions if you want to go this route.

Codeium: AI Autocomplete and Chat

Codeium is a free AI Code Completion and Chat tool comparable to GitHub copilot. It offers autocomplete and is available for several editors, including Visual Studio Code. It supports 70+ programming languages, including JavaScript, TypeScript, PHP, and more. You can also use the IDE-integrated chat to avoid leaving VS Code to ask questions or explain things.

You can grab this plugin for VS Code on the Visual Studio Code Marketplace.

Monokai Pro Theme

The Monokai Pro theme is my favorite theme for Visual Studio code. While you can freely evaluate it (with occasional popups), it requires a paid license for €12.5 ($13.53 USD at the time of writing), which is well worth the effort that went into designing these themes.

Monokai Pro includes six theme variations (Octagon is my favorite), has stylish file icons, contains various configuration options, and should fit almost any style you prefer in a dark theme.

You can grab a license on the Monokai Pro website, and the extension is available on the Visual Studio Marketplace.

PHP Intelephense

The PHP Intelephense extension gives you code intelligence for PHP in Visual Studio Code. If you are a newcomer to PHP or Laravel or a seasoned PHP developer jumping into VS Code for the first time, I recommend installing this extension. It includes code intelligence, symbol searching, go-to definition, documentation help, and a host of other features.

Intelephense offers a premium license that you can grab on intelephense.com that unlocks features like code renaming, code folding, "find all" implementations, "go to type definitions," and more.

Better PHPUnit

Better PHPUnit is a test runner for Visual Studio Code that supports running tests from your editor in the embedded terminal. This extension also supports Running Pest Tests, which gives you one test runner to support any PHP testing workflow.

You can install this extension within VS Code or grab it from the Visual Studio Marketplace.

Tailwind CSS IntelliSense

The Tailwind CSS IntelliSense extension gives you intelligent Tailwind CSS tooling for VS Code. This extension makes you more productive with Tailwind by providing advanced features such as autocomplete, syntax highlighting, and linting. You can also quickly see the complete CSS for a Tailwind class name by hovering over it:

You can find this extension by searching for “Tailwind CSS IntelliSense” or getting it directly from the Visual Studio Marketplace.

That’s a wrap on our essential plugins for VS Code users. I hope you’ve found something useful to improve your VS Code development! We can’t share every single extension, so let us know your favorite VS Code extension or theme!


The post Six Essential Plugins for Visual Studio Code appeared first on Laravel News.

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

Laravel News

Good Guys with Guns Stop Crime in Ohio

https://www.ammoland.com/wp-content/uploads/2024/02/LM_147_OHIO_TN-500×282.jpg

We always hear the gun-grabbers say, “More gun restrictions will reduce crime.” We remind them that the exact opposite is true. The truth is when more good people are prevented from defending themselves due to restrictive and unconstitutional gun laws; it puts them in a vulnerable position.

Not only are good people put in a vulnerable position because they can’t defend themselves and their families, but criminals are also given the upper hand. Bad guys who want to do harm are emboldened by the fact that their potential victims can no longer defend themselves. This is why gun-free zones are the most popular spot for violent attacks.

A new study by the Center for Justice Research determined that in the year following Ohio’s constitutional carry going into effect, crime involving firearms dropped by as much as 22%. How could that be? The anti-gunners are always telling us that we need more gun laws to reduce violent crime.

The study focused on firearms-related crimes from June 2021 to June 2023. This included the year before and after the constitutional carry law went into effect. As it turns out, Cleveland, Akron, Columbus, Parma, Canton, and Toledo became much safer when residents were not restricted from protecting themselves in public with guns. This study corresponds with the Kleck / Gertz: Armed Resistance to Crime study that showed us there are up to 2.5m defensive gun uses (DGU) per year in America. It also reminds us that just because there are guns in the hands of good people and crime is stopped, as a result, it does not mean bad guys are getting killed. Because of the extensive work John Lott and others have done in this area, we now know that in approximately 95% of DGUs, a trigger is never pulled; Just the mere presence of a good gun is enough to stop a bad guy.

The rise in public safety due to responsible citizens carrying firearms led to such a notable improvement in Ohio that the State’s Attorney General officially announced this positive development on X.

Despite this study and many others like it, groups like Mom’s Demand Action, Everytown for Gun Safety, and the Gifford’s group continue to spread, anti-gun propaganda in support of more gun restrictions. It would seem they are much more interested in gun control for political purposes than actually saving lives.


About Dan Wos, Author – Good Gun Bad Guy

Dan Wos is available for Press Commentary. For more information contact PR HERE

Dan Wos is a nationally recognized 2nd Amendment advocate, Host of The Loaded Mic and Author of the “GOOD GUN BAD GUY” book series. He speaks at events, is a contributing writer for many publications, and can be found on radio stations across the country. Dan has been a guest on Newsmax, the Sean Hannity Show, Real America’s Voice, and several others. Speaking on behalf of gun-rights, Dan exposes the strategies of the anti-gun crowd and explains their mission to disarm law-abiding American gun-owners.

Dan Wos
Dan Wos

AmmoLand Shooting Sports News

Ever Wonder Why Your Car’s Shifter Goes P-R-N-D? Here’s the Reason

https://www.gearpatrol.com/wp-content/uploads/sites/2/2020/08/FD-PRND-Gear-Patrol-Lead-Full-jpg.webp

For starters, the US government says so.

fd prnd gear patrol lead fullAudi

If your car has an automatic transmission, the different positions you can shift into follow a specific pattern: P-R-N-D, usually followed by either a couple of lower gear options or the chance to shift it into a manual control mode. In case you’ve never driven (or, somehow, only driven cars with manual transmissions, in which place, god bless you), those four letters stand for Park, Reverse, Neutral and Drive — or, in layman’s terms, Stopped, Backwards, Free-Rolling and Forwards.

You’ve probably shifted from Park to Drive a hundred thousand times, and from Drive to Reverse nearly as many. But in all those times, have you ever stopped to wonder: Gee, why is it that every car’s shifter seems to go from Reverse to Neutral to Drive?

Well, there’s actually a very good reason: the United States government says so.

Editor’s Note: This story is part of “Further Details,” a series dedicated to ubiquitous but overlooked elements hidden on your favorite products.

Older shifters used a P-N-D-L-R arraingement

When the automatic transmission was young, carmakers would often set up their own shifters however they damn well felt like it. One common layout, found in General Motors and Chrysler models, among others, placed Reverse at the far end of the shifter, past Neutral, Drive and the lower gears. In one sense, it made sense; after all, you want Reverse to be easy to find, so why not put it at the very end of the shifter?

The problem that arose, however, was one of user error: people attempting to shift into a low forward gear would wind up overshooting into Reverse without realizing it, or vice versa. Given the mass of, say, a ’59 Eldorado, traveling suddenly in the wrong direction could result in very unpleasant consequences for any persons, animals or objects that happened to be in the way.

Ralph Nader noted that the old P-N-D-L-R arrangement was unsafe

It took none other than noted safety advocate Ralph Nader to help bring the problems with this arrangement to light. In the second chapter of his seminal book Unsafe at Any Speed, Nader raised five ripped-from-the-headlines examples of death, injury and destruction caused by the poor design of this P-N-D-L-R shift arrangement.

“It takes no science and little foresight to accurately condemn a particularly dangerous transmission shift pattern — the P N D L R quadrant common to Cadillacs, Buicks, Oldsmobiles, Pontiacs, Studebakers and Ramblers over the past ten years,” he wrote. “The driver is forced to look at the shift lever for confirmation of the gear in use. The driver has to lift the lever to go into reverse. Should he not lift it enough, the car will remain in forward low while the driver is looking backwards and expecting the car to move in that direction.”

FD-PRND-Gear-Patrol-Navigator
Some modern push-button automatics, like the Lincoln Navigator pictured here, have done away with the selection lever — but if anything, it’s even harder to accidentally mis-select a mode.

Placing Neutral between Drive and Reverse was safer

Sticking neutral between forward and reverse, Nader said, was a commonly-accepted trait of mechanical design in things like mechanical tools. But the design of the Hydra-matic transmission used in these models made it cheaper to put reverse next to the forward cogs, according to an automotive transmission engineer Nader cited; while that obstacle was gone by 1956, GM reportedly stood by it — using the rather circular reasoning that, in effect, there were already too many cars on the road using the P-N-D-L-R setup to stop using it now.

As with encouraging the adoption of safety belts, Nader’s outspoken advocacy wound up getting results. While America’s domestic carmakers all came around to the superior design of putting neutral between Reverse and Drive by 1966, by 1971, it had become part of federal law in the form of U.S. Department of Transportation Standard No. 102: “Location of transmission shift positions on passenger cars. A neutral position shall be located between forward drive and reverse drive positions.”

P-R-N-D has lingered even as mechanical gear shifters are going away

The recent return of pushbutton transmission selectors and the arrival of electronic gearshifts means that carmakers have a tad more flexibility than they once did, in terms of control layouts. Honda and Lincoln’s pushbutton shifters arranges its choices vertically; GMC’s stretches them out horizontally; Mercedes-Benz, BMW, Hyundai and Ford, among others, make Park a separate button to seek out. But the heart of the rule remains in effect: if you want to shift from Drive to Reverse or vice versa, you have to make a stop in Neutral.

Now, some exotic cars with single-clutch and dual-clutch automated manual transmissions, like Ferrari, Lamborghini and McLaren, arrange things even more differently — but that seems to be because they do without a “Park” or, in some cases, even a “Drive.” (Ferraris, for example, only offer buttons for reverse and manual modes; neutral is obtained by pulling both paddle shifters at once, and Park occurs automatically when the car is turned off.) But again, the spirit of the law remains in play: it’s very hard to accidentally shift into Reverse when you mean to go forward.

Gear Patrol

Jantz Knife Supply: Providing Everything Required To Make Knives

http://blademag.com/wp-content/uploads/Jantz-9.jpg

Jantz Knife Supply: Providing Everything Required To Make Knives
Based in Davis, Oklahoma, Jantz has been in the knifemaking supply business for 58 years.

Jantz is a crucial source for many who fashion knives.

For 58 years Jantz Knife Supply has met the needs of cutlery craftsmen of all stripes, from green behind the ears to on up in years, with everything needed to make knives. This includes specialty steels, handle components, sheath materials, hand tools and sanding supplies, as well as the heavy equipment for knifemaking.

What started as a small mom-and-pop gun supply outfit founded by Ken and Venice Jantz in 1966 is no less than a U.S.-based juggernaut in today’s cutlery industry. The Jantzes haven’t left their humble beginnings behind, though, so no customer job is too small for the venerable knifemaking supply company in the heartland of America, Davis, Oklahoma.

Ken Jantz
Company co-founder Ken Jantz works on a prototype for a new hollow-grinding fixture at the company facility.

Shanna Kemp oversees the marketing, financial and human resources for Jantz. She probably knows as well as anyone about the many specialty and other items available to the company’s legion of customers.
“Our goal is to provide everything knifemakers could need for their project,” she begins, “whether you’re a beginner looking for a new hobby or a custom knifemaker stocking your shop to get ready for the BLADE Show. One thing we really love is creating fixtures and tools to make knifemaking more accessible for every skill level.”

One of the company’s most popular new fixtures is the PDJ Knife Vise. “It’s handy for all levels of knifemakers as it allows you to drill perfectly perpendicular holes through your handle material” regardless of the material’s texture or unevenness, Shanna explains.
Jantz stocks an abundance of parts for assembling and enhancing knives of all types. “Our most popular products are our Corby rivets, Loveless bolts and metal round and bar stock,” Shanna enumerates. “Our customers love the quality of our materials as we source directly from reputable mills with consistent quality and do our cutting and machining in house. One of our other popular products is our handcrafted mosaic pins. Each pin design is meticulously hand assembled right here in Davis, Oklahoma.”

Jantz Steel Stock

JS750 perpendicular vise with drill press
Jantz offers a range of knifemaking equipment. An example is the JS750 perpendicular vise with drill press.

An outstanding blade is the heart of any knife and Jantz offers all kinds of stainless and high carbon steels. “We carry a variety of knifemaking steels to suit both forging and stock removal,” she states. “1095 and 80CrV2 are very popular carbon steels and CPM 154 is our most popular stainless steel.” She added that the damascus forged by Brad Vice’s Alabama Damascus is very popular because of the quality and solid price point for the company’s patterned-welded steel.

“For Jantz, steel and other metals have always had a long lead time since we source from a variety of mills in the U.S., Germany, Sweden, Brazil and others,” Shanna observes. “We have strong relationships with our suppliers, and they have worked with us to keep material moving forward even when lead times began to exceed a year.”

Jantz Knife Supply warehouse
No matter the material, component or tool for knifemaking, Jantz probably has it somewhere in one of its well-stocked aisles.

Fixed blades will never go out of style, Shanna opines, and the Jantz business model caters to the mindset that drives the knives’ popularity. “We find that fixed-blade makers tend to use both stock removal and forging in their blade design and development,” she states. “The television series Forged in Fire certainly increased the popularity of forging, but we still see about the same divide between stock removal and forging. Fixed blades designed for hunting and survival are top sellers for our custom knifemakers as well as our hobbyists. There’s something special about using a knife in the field during hunting season that you made yourself that really resonates with the knifemaking crowd.”

When it comes to heat-treating ovens, Jantz recommends Paragon kilns above all others. “Not only do they make a quality oven,” Shanna assesses, “but they have a variety of ovens designed for beginners to pros. Their customer service is top notch and Burt Flanagan, who represents Paragon’s knifemaking ovens, is a custom knifemaker, so he truly understands what knifemakers need.”

Jantz-Made Blades

Knife assembly kit
Knife assembly kits such as the Caballero are a great way to learn the ins-and-outs of folding knives. Jantz offers over a dozen knife genres, from traditional slip joints to modern tactical fare.

For those wanting to get their feet wet in the cutlery world, Jantz offers a cornucopia of pre-made blades for virtually any niche of the market, including household cutlery. According to Shanna, many custom makers order beautiful stainless damascus in various patterns from Damasteel for their kitchen knives. “Our Jantz-made line of household cutlery is especially popular with customers,” she adds. “Our santoku, cook’s and paring blades are favorites of makers using pre-shaped blades for project knifemaking. All the Jantz-made blades are manufactured in our facility.”

Jantz offers an abundance of both knife blades and knife kits. These are designed not only for the novice and hobbyist, but for those who want to tailor special knives for sale. The Jantz website offers links aplenty to a wide range of genres in both folders and fixed blades. Need a fixed-blade hunter in damascus? No problem. Like a kit to learn the ins-and-outs of folding knives? There are over a dozen styles available, from traditional slip joints to modern tactical fare.

JS500 for slip joints
Providing fixtures such as the JS500 for slip joints that make knifemaking more accessible to hobbyists and makers of all levels is a specialty at Jantz Supply.

If there is an innovation on the horizon, Jantz Supply will be on top of it. “One of the many things we love about the knifemaking community is how open and sharing makers are with each other,” Shanna observes. “Want to learn something [another knifemaker] is doing? Just ask. You will rarely find someone not willing to share.”

That spirit and willingness to help is what has made Jantz an important part of the cutlery industry for going on six decades now.

More On Knifemaking:


Download BLADE's Knife Guide Issue!NEXT STEP: Download Your Free KNIFE GUIDE Issue of BLADE Magazine

BLADE’s annual Knife Guide Issue features the newest knives and sharpeners, plus knife and axe reviews, knife sheaths, kit knives and a Knife Industry Directory.

Get your FREE digital PDF instant download of the annual Knife Guide. No, really!

We will email it to you right now when you subscribe to the BLADE email newsletter.

BLADE Magazine

Doing DNS and DHCP for your LAN the old way—the way that works

https://cdn.arstechnica.net/wp-content/uploads/2024/02/lee-dns-robot-stomp-760×380.jpg

All shall tremble before your fully functional forward and reverse lookups!

Enlarge / All shall tremble before your fully functional forward and reverse lookups!

Aurich Lawson | Getty Images

Here’s a short summary of the next 7,000-ish words for folks who hate the thing recipe sites do where the authors babble about their personal lives for pages and pages before getting to the cooking: This article is about how to install bind and dhcpd and tie them together into a functional dynamic DNS setup for your LAN so that DHCP clients self-register with DNS, and you always have working forward and reverse DNS lookups. This article is intended to be part one of a two-part series, and in part two, we’ll combine our bind DNS instance with an ACME-enabled LAN certificate authority and set up LetsEncrypt-style auto-renewing certificates for LAN services.

If that sounds like a fun couple of weekend projects, you’re in the right place! If you want to fast-forward to where we start installing stuff, skip down a couple of subheds to the tutorial-y bits. Now, excuse me while I babble about my personal life.

My name is Lee, and I have a problem

(Hi, Lee.)

I am a tinkering homelab sysadmin forever chasing the enterprise dragon. My understanding of what "normal" means, in terms of the things I should be able to do in any minimally functioning networking environment, was formed in the days just before and just after 9/11, when I was a fledgling admin fresh out of college, working at an enormous company that made planes starting with the number "7." I tutored at the knees of a whole bunch of different mentor sysadmins, who ranged on the graybeard scale from "fairly normal, just writes his own custom GURPS campaigns" to "lives in a Unabomber cabin in the woods and will only communicate via GPG." If there was one consistent refrain throughout my formative years marinating in that enterprise IT soup, it was that forward and reverse DNS should always work. Why? Because just like a clean bathroom is generally a sign of a nice restaurant, having good, functional DNS (forward and reverse) is a sign that your IT team knows what it’s doing.

Just look at what the masses have to contend with outside of the datacenter, where madness reigns. Look at the state of the average user’s LAN—is there even a search domain configured? Do reverse queries on dynamic hosts work? Do forward queries on dynamic hosts even work? How can anyone live like this?!

I decided long ago that I didn’t have to, so I’ve maintained a linked bind and dhcpd setup on my LAN for more than ten years. Also, I have control issues, and I like my home LAN to function like the well-run enterprise LANs I used to spend my days administering. It’s kind of like how car people think: If you’re not driving a stick shift, you’re not really driving. I have the same kind of dumb hang-up, but for network services.

Honestly, though, running your LAN with bind and dhcpd isn’t even that much work—those two applications underpin a huge part of the modern Internet. The packaged versions that come with most modern Linux distros are ready to go out of the box. They certainly beat the pants off of the minimal DNS/DHCP services offered by most SOHO NAT routers. Once you have bind and dhcpd configured, they’re bulletproof. The only time I interact with my setup is if I need to add a new static DHCP mapping for a host I want to always grab the same IP address.

So, hey, if the idea of having perfect forward and reverse DNS lookups on your LAN sounds exciting—and, come on, who doesn’t want that?!—then pull up your terminal and strap in because we’re going make it happen.

(Note that I’m relying a bit on Past Lee and this old blog entry for some of the explanations in this piece, so if any of the three people who read my blog notice any similarities in some of the text, it’s because Past Lee wrote it first and I am absolutely stealing from him.)

But wait, there’s more!

This piece is intended to be part one of two. If the idea of having one’s own bind and dhcpd servers sounds a little silly (and it’s not—it’s awesome), it’s actually a prerequisite for an additional future project with serious practical implications: our own fully functioning local ACME-enabled certificate authority capable of answering DNS-01 challenges so we can issue our own certificates to LAN services and not have to deal with TLS warnings like plebes.

("But Lee," you say, "why not just use actual-for-real LetsEncrypt with a real domain on my LAN?" Because that’s considerably more complicated to implement if one does it the right way, and it means potentially dealing with split-horizon DNS and hairpinning if you also need to use that domain for any Internet-accessible stuff. Split-horizon DNS is handy and useful if you have requirements that demand it, but if you’re a home user, you probably don’t. We’ll keep this as simple as possible and use LAN-specific DNS zones rather than real public domain names.)

We’ll tackle all the certificate stuff in part two—because we have a ways to go before we can get there.

Ars Technica – All content