Organize Your Views Better With Subdirectories
There are a couple of more concepts that we should look at before we move on to the blade templating engine. This time, we’ll cover subdirectories and one simple check to see if the view that we’re calling actually exists.
Read the previous article on Passing Arguments to Views.
Subdirectories
Who cares about subdirectories? Why not just shove all of the views under one directory, views
? It’s incredibly important for organization. Most of the time, you’ll list your resource name, likes users
as a subdirectory of views, and then the 4 CRUD views:
create.blade.php
edit.blade.php
index.blade.php
show.blade.php
We’ll go over those in detail later when we cover resource controllers, but for now, let’s look at creating a basic subdirectory called cars1
and placing an index.blade.php
file in there. I added the 1
at the end since we’ll create a lot of car
subdirectories going forward for examples. I really hope you like them as much as I do. It will be a lot more enjoyable :).
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Car</title>
<!-- Fonts -->
<link href="https://fonts.bunny.net/css2?family=Nunito:wght@400;600;700&display=swap" rel="stylesheet">
<!-- Styles -->
<style>
/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}a{background-color:transparent}[hidden]{display:none}html{font-family:system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;line-height:1.5}*,:after,:before{box-sizing:border-box;border:0 solid #e2e8f0}a{color:inherit;text-decoration:inherit}svg,video{display:block;vertical-align:middle}video{max-width:100%;height:auto}.bg-white{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity))}.bg-gray-100{--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity))}.border-gray-200{--tw-border-opacity: 1;border-color:rgb(229 231 235 / var(--tw-border-opacity))}.border-t{border-top-width:1px}.flex{display:flex}.grid{display:grid}.hidden{display:none}.items-center{align-items:center}.justify-center{justify-content:center}.font-semibold{font-weight:600}.h-5{height:1.25rem}.h-8{height:2rem}.h-16{height:4rem}.text-sm{font-size:.875rem}.text-lg{font-size:1.125rem}.leading-7{line-height:1.75rem}.mx-auto{margin-left:auto;margin-right:auto}.ml-1{margin-left:.25rem}.mt-2{margin-top:.5rem}.mr-2{margin-right:.5rem}.ml-2{margin-left:.5rem}.mt-4{margin-top:1rem}.ml-4{margin-left:1rem}.mt-8{margin-top:2rem}.ml-12{margin-left:3rem}.-mt-px{margin-top:-1px}.max-w-6xl{max-width:72rem}.min-h-screen{min-height:100vh}.overflow-hidden{overflow:hidden}.p-6{padding:1.5rem}.py-4{padding-top:1rem;padding-bottom:1rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.pt-8{padding-top:2rem}.fixed{position:fixed}.relative{position:relative}.top-0{top:0}.right-0{right:0}.shadow{--tw-shadow: 0 1px 3px 0 rgb(0 0 0 / .1), 0 1px 2px -1px rgb(0 0 0 / .1);--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.text-center{text-align:center}.text-gray-200{--tw-text-opacity: 1;color:rgb(229 231 235 / var(--tw-text-opacity))}.text-gray-300{--tw-text-opacity: 1;color:rgb(209 213 219 / var(--tw-text-opacity))}.text-gray-400{--tw-text-opacity: 1;color:rgb(156 163 175 / var(--tw-text-opacity))}.text-gray-500{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity))}.text-gray-600{--tw-text-opacity: 1;color:rgb(75 85 99 / var(--tw-text-opacity))}.text-gray-700{--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity))}.text-gray-900{--tw-text-opacity: 1;color:rgb(17 24 39 / var(--tw-text-opacity))}.underline{text-decoration:underline}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.w-5{width:1.25rem}.w-8{width:2rem}.w-auto{width:auto}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}@media (min-width:640px){.sm\:rounded-lg{border-radius:.5rem}.sm\:block{display:block}.sm\:items-center{align-items:center}.sm\:justify-start{justify-content:flex-start}.sm\:justify-between{justify-content:space-between}.sm\:h-20{height:5rem}.sm\:ml-0{margin-left:0}.sm\:px-6{padding-left:1.5rem;padding-right:1.5rem}.sm\:pt-0{padding-top:0}.sm\:text-left{text-align:left}.sm\:text-right{text-align:right}}@media (min-width:768px){.md\:border-t-0{border-top-width:0}.md\:border-l{border-left-width:1px}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (min-width:1024px){.lg\:px-8{padding-left:2rem;padding-right:2rem}}@media (prefers-color-scheme:dark){.dark\:bg-gray-800{--tw-bg-opacity: 1;background-color:rgb(31 41 55 / var(--tw-bg-opacity))}.dark\:bg-gray-900{--tw-bg-opacity: 1;background-color:rgb(17 24 39 / var(--tw-bg-opacity))}.dark\:border-gray-700{--tw-border-opacity: 1;border-color:rgb(55 65 81 / var(--tw-border-opacity))}.dark\:text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity))}.dark\:text-gray-400{--tw-text-opacity: 1;color:rgb(156 163 175 / var(--tw-text-opacity))}.dark\:text-gray-500{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity))}}
</style>
</head>
<body class="p-6">
<h1>Here's a list of my favorite cars</h1>
<ul>
<li>2003 Chevy Corvette</li>
<li>2007 Chevy Corvette</li>
<li>1999 Nissan Skyline GT-R</li>
<li>2021 Nissan GT-R</li>
<li>2022 Porsche 911 GT3</li>
<li>1994 Toyota Supra 2JZGTE</li>
<li>1989 Nissan 240SX Hatchback</li>
<li>2019 Subaru WRX STi</li>
<li>1998 Dodge Viper GTS-R</li>
</ul>
</body>
</html>
To call the subdirectory from our view global helper, we use the dot notation.
<?php
// ...
Route::get('/cars', function() {
return view('cars.index');
});
<?php
// ...
Route::get('/cars', function() {
return view('cars/index');
});
Refreshing the page, we’ll see our list of favorite cars. I’m not being pushy or anything, but this is now your favorite car list as well. By the way, the list is a lot larger than this. These are just the top ones right now so that the entire article doesn’t become a list of vehicles.
Checking to see if a view exists
We haven’t covered Facades yet, and we won’t for a while. For now, just think of Facades as a static class that you can tap into and utilize some of its functionality. To check and see if a view exists, we’ll need to use the View
Facade.
The View
Facade has a method called exists
that we can pass a name of the view to. It will check within the views
directory whether that view exists or not. If it exists, it’ll return true
and false
otherwise.
To use the View
Facade, we’ll first need to add it at the top of the web.php
route file.
<?php
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\View;
Route::get('/cars', function() {
if ( View::exists('cars.index') ) {
return view('cars.index');
}
return null;
});
Pretty straightforward to implement. You just need to understand that it exists. We’ll take a detailed look into Facades much later in this series.
See you in the blade template world.
Laravel Series
Continue your Laravel Learning.
How to Pass Arguments to Views
Laravel – P6: Passing Arguments to Views
We know how to grab URL parameters and return them from our route, but how do we pass arguments to the view?
Organize Your Views Better With Subdirectories
Laravel – P7: View Subdirectories and Checks
If you want to keep your Laravel views directory organized, we’ll need to look at subdirectories. There is a standard that we should strive to follow.
Using the Blade Engine to Remove PHP
Laravel – P8: Blade Introduction
Blade is a templating engine that allows you to write some front-end friendly code. The last thing we want to see is PHP wrapped up inside of the views.