1
\$\begingroup\$

I am working on a blogging application in Laravel 8 .

The application supports themes. In a nutshell, theme support works like this:

In the views directory, I have the directory containing the views of every theme.

screenshot of views directory

In public\themes I keep the assets (CSS, Javascript) of every theme.

screenshot of themes directory

In the SettingsController controller I have, among others, a variable named $theme_directory, which contains the name of the directory of the current theme. I use this variable in the theme view, like this, for instance:

<link href="{{ asset('themes/' . $theme_directory . '/css/clean-blog.min.css') }}" rel="stylesheet"> 

From the "Settings" section I can set the current theme.

screenshot of form

I have added a "theme picker": a select-box containing all the available themes to pick from.

In the controller, I have a themes() method that reads the names of the themes directories in the views and displays them:

namespace App\Http\Controllers\Dashboard;
use App\Http\Controllers\Controller;
use App\Models\Settings;
use Illuminate\Support\Facades\Validator;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\File;
class SettingsController extends Controller {
 
 private $rules = [
 'site_name' => 'required|string|max:190',
 'tagline' => 'required|string|max:190',
 'owner_name' => 'required|string|max:190',
 'owner_email' => 'required|email|max:190',
 'twitter' => 'required|string|max:190',
 'facebook' => 'required|string|max:190',
 'instagram' => 'required|string|max:190',
 'theme_directory' => 'required',
 ];
 private $messages = [
 'site_name.required' => 'A site title is required',
 'tagline.required' => 'A site tag line is required',
 'owner_name.required' => 'Please provide a site owner/company name',
 'owner_email.required' => 'A valid email is required',
 'owner_email.email' => 'The email you provided is not valid',
 'twitter.required' => 'Please provide a Twitter account',
 'facebook.required' => 'Please provide a Facebook account',
 'instagram.required' => 'Please provide an Instagram account',
 'theme_directory.required' => 'Please pick a theme',
 ];
 public function themes() {
 $themes = [];
 $themes_path = Config::get('view.paths')[0] . '\themes';
 foreach(File::directories($themes_path) as $theme) {
 $slug = array_reverse(explode('\\', $theme))[0];
 $name = ucwords(str_replace('-', ' ', $slug));
 $themes[] = (object)compact('slug', 'name');
 }
 return $themes;
 }
 
 public function index() {
 $settings = Settings::first();
 return view('dashboard/settings', [
 'settings' => $settings, 
 'themes' => $this->themes()
 ]);
 }
 public function update(Request $request) {
 $validator = Validator::make($request->all(), $this->rules, $this->messages);
 if ($validator->fails()) {
 return redirect()->back()->withErrors($validator->errors())->withInput();
 } else {
 $settings = Settings::first();
 $settings->site_name = $request->get('site_name');
 $settings->tagline = $request->get('tagline');
 $settings->owner_name = $request->get('owner_name');
 $settings->owner_email = $request->get('owner_email');
 $settings->twitter = $request->get('twitter');
 $settings->facebook = $request->get('facebook');
 $settings->instagram = $request->get('instagram');
 $settings->theme_directory = $request->get('theme_directory');
 $settings->is_cookieconsent = $request->get('is_cookieconsent') == 'on' ? 1 : 0;
 $settings->is_infinitescroll = $request->get('is_infinitescroll') == 'on' ? 1 : 0;
 
 $settings->save();
 return redirect()->route('dashboard.settings')->with('success', 'The settings were updated!');
 }
 }
}

In the view (form), I have:

<div class="row mb-2">
 <label for="theme" class="col-md-12">{{ __('Theme directory') }}</label>
 <div class="col-md-12 @error('theme_directory') has-error @enderror">
 <select name="theme_directory" id="theme" class="form-control @error('theme_directory') is-invalid @enderror">
 <option value="">Pick a theme</option>
 @foreach($themes as $theme)
 <option value="{{ $theme->slug }}" {{ $theme->slug == $settings->theme_directory ? 'selected' : '' }}>{{ $theme->name }}</option>
 @endforeach
 </select>
 @error('theme_directory')
 <span class="invalid-feedback" role="alert">
 <strong>{{ $message }}</strong>
 </span>
 @enderror
 </div>
</div>

Questions:

  1. Is there any redundancy in my code?
  2. Do you see any security issues?
Sᴀᴍ Onᴇᴌᴀ
29.5k16 gold badges45 silver badges201 bronze badges
asked Jan 8, 2023 at 21:08
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

Is there any redundancy in my code?

There is some redundancy between $rules and $messages

This may not be an orthodox idea by many Laravel programmers but $rules could be generated on the fly by iterating over the keys of $messages - Something like:

$rules = array_reduce(array_keys($messages), function($carry, $messageKey) {
 [$field] = explode('.', $messageKey);
 if (str_contains($field, 'theme')) {
 return $carry + [$field => 'required'];
 }
 $type = str_contains($field, 'email') ? 'email' : 'string';
 return $carry + [$field => "required|$type|max:190"];
}, []);

The update method repeatedly calls $request->get()

That method calls $request->get() ten times. Many of those could be called in a loop - e.g. which iterates over the fields from $messages.

As I explained in this answer a subclass of form request could be created to encapsulate all of the validation logic and simplify the setting of validated fields in the model.

If such a form request was made, then most all of those lines calling $request()->get() could be replaced with a single call to $request->validated() using the update() method.


Do you see any security issues?

Can any user update update the settings? If not, then perhaps a role should be checked on the user.

Another benefit of form requests is that they can help with authorization - e.g. the authorize() method can be defined and have it return false for any user that should not be able to submit such a request.

answered Jan 29, 2023 at 9:08
\$\endgroup\$
0

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.