rodrigo.pedra

rodrigo.pedra

Lead Developer at avaliadora.com.br

Member Since 5 Years Ago

São Carlos, Brazil

Experience Points
231,410
Total
Experience

3,590 experience to go until the next level!

In case you were wondering, you earn Laracasts experience when you:

  • Complete a lesson — 100pts
  • Create a forum thread — 50pts
  • Reply to a thread — 10pts
  • Leave a reply that is liked — 50pts
  • Receive a "Best Reply" award — 500pts
Lessons Completed
1062
Lessons
Completed
Best Reply Awards
184
Best Reply
Awards
  • start your engines Created with Sketch.

    Start Your Engines

    Earned once you have completed your first Laracasts lesson.

  • first-thousand Created with Sketch.

    First Thousand

    Earned once you have earned your first 1000 experience points.

  • 1-year Created with Sketch.

    One Year Member

    Earned when you have been with Laracasts for 1 year.

  • 2-years Created with Sketch.

    Two Year Member

    Earned when you have been with Laracasts for 2 years.

  • 3-years Created with Sketch.

    Three Year Member

    Earned when you have been with Laracasts for 3 years.

  • 4-years Created with Sketch.

    Four Year Member

    Earned when you have been with Laracasts for 4 years.

  • 5-years Created with Sketch.

    Five Year Member

    Earned when you have been with Laracasts for 5 years.

  • school-in-session Created with Sketch.

    School In Session

    Earned when at least one Laracasts series has been fully completed.

  • welcome-newcomer Created with Sketch.

    Welcome To The Community

    Earned after your first post on the Laracasts forum.

  • full-time-student Created with Sketch.

    Full Time Learner

    Earned once 100 Laracasts lessons have been completed.

  • pay-it-forward Created with Sketch.

    Pay It Forward

    Earned once you receive your first "Best Reply" award on the Laracasts forum.

  • subscriber Created with Sketch.

    Subscriber

    Earned if you are a paying Laracasts subscriber.

  • lifer Created with Sketch.

    Lifer

    Earned if you have a lifetime subscription to Laracasts.

  • evangelist Created with Sketch.

    Laracasts Evangelist

    Earned if you share a link to Laracasts on social media. Please email [email protected] with your username and post URL to be awarded this badge.

  • chatty-cathy Created with Sketch.

    Chatty Cathy

    Earned once you have achieved 500 forum replies.

  • lara-veteran Created with Sketch.

    Laracasts Veteran

    Earned once your experience points passes 100,000.

  • 10k-strong Created with Sketch.

    Ten Thousand Strong

    Earned once your experience points hits 10,000.

  • lara-master Created with Sketch.

    Laracasts Master

    Earned once 1000 Laracasts lessons have been completed.

  • laracasts-tutor Created with Sketch.

    Laracasts Tutor

    Earned once your "Best Reply" award count is 100 or more.

  • laracasts-sensei Created with Sketch.

    Laracasts Sensei

    Earned once your experience points passes 1 million.

  • top-50 Created with Sketch.

    Top 50

    Earned once your experience points ranks in the top 50 of all Laracasts users.

Level 47
231,410 XP
Sep
15
6 days ago
Activity icon

Replied to Guzzlehttp Error While Upgrading Laravel To 8 From 7

Laravel Telescope version 3 is not compatible with Laravel 8.

Update this in your composer.json:

"laravel/telescope": "^4.0",

For any further dependencies errors you can visit the package repository and check if it already supports Laravel 8, and if so, check if you are requesting the correct version.

By the way, the Laravel Telescope version upgrade is noted on the upgrade guide:

https://laravel.com/docs/8.x/upgrade#updating-dependencies

(look at the second list)

Sep
10
1 week ago
Activity icon

Awarded Best Reply on How To Subtract A DB Object From Another.

Hi @davidsi02 , if I understood it well you want to filter the groups in the DB level from the groups associated with an specific user.

I tried doing the two queries below, not sure if that is what you want, so I added comments to explain what is happening:

// this will return the groups which the current user (from $id above)
// is not associated to. It will use a subquery in the whereIn constraint
// 
// sould produce the following SQL:
//
// SELECT idgrupo, nome
// FROM grupo
// WHERE idgrupo NOT IN (SELECT FROM idgrupo WHERE iduser <> ?)
//
// When executing the question mark will be replaced with
// the $id variable's value
$groupsCurrentUserIsNotAssociatedTo = DB::table('grupo')
    ->select(['idgrupo', 'nome'])
    ->whereNotIn(
        'idgrupo',
        DB::table('grupoutilizador')
            ->select(['idgrupo'])
            ->where('iduser', $id)
    )
    ->get();

// This will return all the groups, with their respective
// associated users, which the current user is not associated to.
// Note that you could have duplicated group ids and names
// if users different than the current one are associated to
// the same group.
// For example, lets consider that:
//   - user "John" with id 1 (the current user) belongs to groups: A, B
//   - user "Bill" with id 2 belongs to groups: A, C, D
//   - user "Mary" with id 3 belongs to groups: B, C
//   - groups ids corresponds to theirs alphabetical order (for this example)
// So the return of this query would be:
//   - 2  |  Bill  |  3  |  C
//   - 2  |  Bill  |  4  |  D
//   - 3  |  Mary  |  3  |  C
// Note that group C will be returned twice
// 
// sould produce the following SQL:
//
// SELECT users.id, users.name, grupo.idgrupo, grupo.nome
// FROM grupo
// INNER JOIN grupoutilizador ON grupo.idgrupo = grupoutilizador.idgrupo
// INNER JOIN users ON grupoutilizador.iduser = users.id
// WHERE grupo.idgrupo NOT IN (SELECT FROM idgrupo WHERE iduser <> ?)
$groupsCurrentUserIsNotAssociatedToWithUsers = DB::table('grupo')
    ->join('grupoutilizador', 'grupo.idgrupo', '=', 'grupoutilizador.idgrupo')
    ->join('users', 'grupoutilizador.iduser', '=', 'users.id')
    ->select(['users.id', 'users.name', 'grupo.idgrupo', 'grupo.nome'])
    // you could move the where constraint below into the
    // join clause on 'grupoutilizador', but the DBMS query optimizer
    // should make the same query plan for both cases
    ->whereNotIn(
        'grupo.idgrupo',
        DB::table('grupoutilizador')
            ->select(['idgrupo'])
            ->where('iduser', $id)
    )
    ->get();
Aug
28
3 weeks ago
Activity icon

Replied to Vue - V-show And @click Event Doesn't Work

The item is from the list received as a prop.

Vue doesn't expected props to be mutated. This part of the docs explores this:

https://vuejs.org/v2/guide/components-props.html#One-Way-Data-Flow

The linked docs above states this:

There are usually two cases where it’s tempting to mutate a prop:

  1. The prop is used to pass in an initial value; the child component wants to use it as a local data property afterwards. In this case, it’s best to define a local data property that uses the prop as its initial value...

Considering this, can you try making a copy of the prop locally? I don't use the TypeScript class syntax, but in plain JavaScript syntax it would be something like this:

// DropdownMenu
export default {
    props: ['list'],

    data() {
        return {
            records: this.list.subnav.map(item => ({...item, open: false})),
        };
    },
}

Then, in your template you will need to iterate over records in the v-for directive.

v-for="(item, index) in records"

There are one caveat with this approach, if the list props changes on the parent component, those changes won't be reflected on the child component as we make a copy during the component's creation.

You can workaround this limitation by using a watcher to track props changes and rebuild the records copy,

or: skip making a copy locally, emit an event @/click (added the slash to avoid linking to a user handle) and make the open = !open changes on the parent. (events "up", props "down" approach)

Aug
27
3 weeks ago
Activity icon

Replied to User Age Verification

Code seems fine to me. Someone who was born on January 1st, 2002 completed 18 years old on January 1st, 2020.

So if you comparing against today (August 27th, 2020) this person is already 18 years old, which - by your description - is of legal age.

Try with different dates, for example try with tomorrow's date (2020-08-28) and you'll see the result would be 17.

Activity icon

Replied to How To Subtract A DB Object From Another.

Hi @davidsi02 , if I understood it well you want to filter the groups in the DB level from the groups associated with an specific user.

I tried doing the two queries below, not sure if that is what you want, so I added comments to explain what is happening:

// this will return the groups which the current user (from $id above)
// is not associated to. It will use a subquery in the whereIn constraint
// 
// sould produce the following SQL:
//
// SELECT idgrupo, nome
// FROM grupo
// WHERE idgrupo NOT IN (SELECT FROM idgrupo WHERE iduser <> ?)
//
// When executing the question mark will be replaced with
// the $id variable's value
$groupsCurrentUserIsNotAssociatedTo = DB::table('grupo')
    ->select(['idgrupo', 'nome'])
    ->whereNotIn(
        'idgrupo',
        DB::table('grupoutilizador')
            ->select(['idgrupo'])
            ->where('iduser', $id)
    )
    ->get();

// This will return all the groups, with their respective
// associated users, which the current user is not associated to.
// Note that you could have duplicated group ids and names
// if users different than the current one are associated to
// the same group.
// For example, lets consider that:
//   - user "John" with id 1 (the current user) belongs to groups: A, B
//   - user "Bill" with id 2 belongs to groups: A, C, D
//   - user "Mary" with id 3 belongs to groups: B, C
//   - groups ids corresponds to theirs alphabetical order (for this example)
// So the return of this query would be:
//   - 2  |  Bill  |  3  |  C
//   - 2  |  Bill  |  4  |  D
//   - 3  |  Mary  |  3  |  C
// Note that group C will be returned twice
// 
// sould produce the following SQL:
//
// SELECT users.id, users.name, grupo.idgrupo, grupo.nome
// FROM grupo
// INNER JOIN grupoutilizador ON grupo.idgrupo = grupoutilizador.idgrupo
// INNER JOIN users ON grupoutilizador.iduser = users.id
// WHERE grupo.idgrupo NOT IN (SELECT FROM idgrupo WHERE iduser <> ?)
$groupsCurrentUserIsNotAssociatedToWithUsers = DB::table('grupo')
    ->join('grupoutilizador', 'grupo.idgrupo', '=', 'grupoutilizador.idgrupo')
    ->join('users', 'grupoutilizador.iduser', '=', 'users.id')
    ->select(['users.id', 'users.name', 'grupo.idgrupo', 'grupo.nome'])
    // you could move the where constraint below into the
    // join clause on 'grupoutilizador', but the DBMS query optimizer
    // should make the same query plan for both cases
    ->whereNotIn(
        'grupo.idgrupo',
        DB::table('grupoutilizador')
            ->select(['idgrupo'])
            ->where('iduser', $id)
    )
    ->get();
Aug
21
1 month ago
Activity icon

Replied to Vue.prototype Not Working

No problem, glad you got it working =)

Activity icon

Awarded Best Reply on Vue.prototype Not Working

Also I think you'd need to convert to a boolean on javascript as attributes are returned as a string from the getAttribute.

Activity icon

Replied to Vue.prototype Not Working

Also I think you'd need to convert to a boolean on javascript as attributes are returned as a string from the getAttribute.

Activity icon

Replied to Vue.prototype Not Working

I don't know if it as typo on your code sample, but the attribute on the div#app is written with a Q instead of a G (isquest instead of isguest).

Activity icon

Replied to Laravel Query Builder, I Need Help In Write Query

I am assuming you are using MySQL. Add this column to the query:

DB::raw("COUNT(CASE
    WHEN CAST(created_at AS DATE) = CURRENT_DATE THEN 1
    ELSE NULL
END) AS today_count"),

Take a look at MySQL date and time functions:

https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html

Aug
20
1 month ago
Activity icon

Replied to How Do I Change The Password Verification Algorithm?

You're welcome, glad to help =)

My twitter and github handles are linked on my Laracasts' profile close to my username.

Activity icon

Awarded Best Reply on How Do I Change The Password Verification Algorithm?

Hi @roffdaniel

I wasn't with enough time yesterday, so sorry for the late response.

Recently I had to connect a Laravel project to a legacy database and had some of the issues you describe (custom users table, custom hashing, etc.)

To outline a path for you I first created a new laravel project using a SQLite database, using these commands:

# create from composer
composer create-project --prefer-dist laravel/laravel test
cd test || exit

# tweak .env configuration
sed -i 's/mysql/sqlite/' .env
sed -i 's/DB_DATABASE/# DB_DATABASE/g' .env

# create sqlite database file
touch database/database.sqlite

# require auth scaffolding
composer require laravel/ui
php artisan ui bootstrap --auth

# install frontend dependencies
npm install
npm run dev

The sed commands above only replaces the .env config to use SQLite instead of MySQL. At the end my .env file had these lines regarding the database:

DB_CONNECTION=sqlite
DB_HOST=127.0.0.1
DB_PORT=3306
# DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD=

With the project in place I took the following steps:

1. Tweaking the User Model

First I modified the users migration that comes with Laravel to mimic your scheme:

<?php

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

class CreateUsersTable extends Migration
{
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->id();
            $table->string('uLogin')->unique();
            $table->string('uEmail')->unique();
            $table->string('uPassword');
            $table->string('uSalt');

            // timestamps seemed to be saved as integers in your example
            $table->unsignedInteger('uRegDate');
            $table->unsignedInteger('uLastDate');
        });
    }

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

Then I tweaked the User model (located at ./app/User.php) to match the DB scheme:

<?php

namespace App;

use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;

class User extends Authenticatable
{
    use Notifiable;

    // if using custom table name change this
    protected $table = 'users';

    // tell laravel to use these as timestamps columns
    const CREATED_AT = 'uRegDate';
    const UPDATED_AT = 'uLastDate';

    // tell laravel to save dates unix timestamps
    protected $dateFormat = 'U';

    protected $fillable = [
        'uLogin',
        'uEmail',
        'uPassword',
        'uSalt',
    ];

    protected $hidden = ['uPassword', 'uSalt'];

    // Useful for default auth scaffolding
    public function getAuthPassword()
    {
        return $this->uPassword;
    }

    // Useful for avoiding tweaking default auth scaffolding
    public function getNameAttribute()
    {
        return $this->uLogin;
    }
}

I added some comments above to highlight some the changes.

2. Custom user provider

As I told you in my first answer one approach is to use a Custom User Provider, for reference this is again the docs section about it:

https://laravel.com/docs/7.x/authentication#adding-custom-user-providers

So I created a new User Provider under the project ./app directory:

<?php

namespace App;

use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Contracts\Auth\UserProvider;
use Illuminate\Support\Arr;

class CustomUserProvider implements UserProvider
{
    public function retrieveById($identifier)
    {
        return User::query()->find($identifier);
    }

    public function retrieveByToken($identifier, $token)
    {
        // not implementing remeber me
        return null;
    }

    public function updateRememberToken(Authenticatable $user, $token)
    {
        // not implementing remeber me
    }

    public function retrieveByCredentials(array $credentials)
    {
        if (Arr::has($credentials, 'email')) {
            return User::query()
                ->where('uEmail', $credentials['email'])
                ->first();
        }

        // allow login user either by email or name
        // default auth scaffolding will use email
        // but you can tweak the login view and LoginController
        // to login by "login" field
        if (Arr::has($credentials, 'login')) {
            return User::query()
                ->where('uLogin', $credentials['login'])
                ->first();
        }

        return null;
    }

    public function validateCredentials(Authenticatable $user, array $credentials)
    {
        $plain = $credentials['password'];

        // use custom hash mechanism
        $hash = \hash('sha256', $user->uSalt . $plain);

        // comparing with hash_equals prevents time-based attacks
        // see php docs about it
        return \hash_equals($user->getAuthPassword(), $hash);
    }
}

Then, per docs instructions, we need to register this User Provider. Let's follow the docs recommendation and change our app's AuthServiceProvider (located at ./app/Providers/AuthServiceProvider.php)

<?php

namespace App\Providers;

use App\CustomUserProvider;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Gate;

class AuthServiceProvider extends ServiceProvider
{
    protected $policies = [
        // 'App\Model' => 'App\Policies\ModelPolicy',
    ];

    public function boot()
    {
        $this->registerPolicies();

        // ADD THIS. 
        // Don't forget to import the Auth Facade and CustomUserProvider
        Auth::provider('custom', function () {
            return new CustomUserProvider();
        });
    }
}

Note that for all changed classes I removed the default comments to minimize space here.

Lastly we need to tell Laravel to use this Custom User Provider for authentication. We can do so by modifying the ./config/auth.php file. I won't paste the whole file here, but should be easy to find the place to change looking at the snippet below:

    'providers' => [
        'users' => [
            'driver' => 'custom', // CHANGE HERE
            // 'model' => App\User::class, // not needed anymore
        ],

        // 'users' => [
        //     'driver' => 'database',
        //     'table' => 'users',
        // ],
    ],

3. Default Auth scaffolding

To test it out I used Laravel default auth scaffolding (see composer require laravel/ui above).

When registering new users we need to tweak the RegisterController (located at ./app/Http/Controllers/Auth/RegisterController.php).

<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use App\User;
use Illuminate\Foundation\Auth\RegistersUsers;
use Illuminate\Support\Facades\Validator;

class RegisterController extends Controller
{
    use RegistersUsers;

    protected $redirectTo = RouteServiceProvider::HOME;

    public function __construct()
    {
        $this->middleware('guest');
    }

    protected function validator(array $data)
    {
        return Validator::make($data, [
            'name' => ['required', 'string', 'max:255'],

            // might need to change the unique:users
            // if using custom users table name
            'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],

            'password' => ['required', 'string', 'min:8', 'confirmed'],
        ]);
    }

    protected function create(array $data)
    {
        // added for reference. use your current salt function
        $salt = $this->createSalt(5);

        return User::query()->create([
            'uLogin' => $data['name'],
            'uEmail' => $data['email'],
            'uPassword' => \hash('sha256', $salt . $data['password']),
            'uSalt' => $salt,
        ]);
    }

    // added for reference. use your current salt function
    private function createSalt($length)
    {
        $text = md5(uniqid(rand(), true));
        return substr($text, 0, $length);
    }
}

Note this controller is made available after installing the laravel/ui package listed above and running the php artisan ui bootstrap --auth command (bootstrap can be swapped by vue and react).

If you already have some authentication code in place take a look at the laravel/ui repository to check out how they approach authentication.

https://github.com/laravel/ui

As we are using the Custom User Provider, after we have a user in our database, we won't need to customize the LoginController. Authentication will just work.

4. Migrating and running

Before testing out, we need first to migrate the database, this can be done with this command:

php artisan migrate

Then we can start a webserver to test in the browser, by using this command:

php artisan serve

To test it out, follow this steps:

  • Navigate to http://localhost:8000
  • Click Register on the top right
  • Fill the form and register a new user, the name field will be saved in the login column
  • Click the user's name (login) on the top right
  • Click logout
  • Click Login on the top right
  • Fill the user's credentials and login

You can check the user was created and saved to the Database with your custom scheme, custom timestamps and custom hashing.

Hope it helps!

Activity icon

Replied to How Do I Change The Password Verification Algorithm?

Hi @roffdaniel

I wasn't with enough time yesterday, so sorry for the late response.

Recently I had to connect a Laravel project to a legacy database and had some of the issues you describe (custom users table, custom hashing, etc.)

To outline a path for you I first created a new laravel project using a SQLite database, using these commands:

# create from composer
composer create-project --prefer-dist laravel/laravel test
cd test || exit

# tweak .env configuration
sed -i 's/mysql/sqlite/' .env
sed -i 's/DB_DATABASE/# DB_DATABASE/g' .env

# create sqlite database file
touch database/database.sqlite

# require auth scaffolding
composer require laravel/ui
php artisan ui bootstrap --auth

# install frontend dependencies
npm install
npm run dev

The sed commands above only replaces the .env config to use SQLite instead of MySQL. At the end my .env file had these lines regarding the database:

DB_CONNECTION=sqlite
DB_HOST=127.0.0.1
DB_PORT=3306
# DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD=

With the project in place I took the following steps:

1. Tweaking the User Model

First I modified the users migration that comes with Laravel to mimic your scheme:

<?php

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

class CreateUsersTable extends Migration
{
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->id();
            $table->string('uLogin')->unique();
            $table->string('uEmail')->unique();
            $table->string('uPassword');
            $table->string('uSalt');

            // timestamps seemed to be saved as integers in your example
            $table->unsignedInteger('uRegDate');
            $table->unsignedInteger('uLastDate');
        });
    }

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

Then I tweaked the User model (located at ./app/User.php) to match the DB scheme:

<?php

namespace App;

use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;

class User extends Authenticatable
{
    use Notifiable;

    // if using custom table name change this
    protected $table = 'users';

    // tell laravel to use these as timestamps columns
    const CREATED_AT = 'uRegDate';
    const UPDATED_AT = 'uLastDate';

    // tell laravel to save dates unix timestamps
    protected $dateFormat = 'U';

    protected $fillable = [
        'uLogin',
        'uEmail',
        'uPassword',
        'uSalt',
    ];

    protected $hidden = ['uPassword', 'uSalt'];

    // Useful for default auth scaffolding
    public function getAuthPassword()
    {
        return $this->uPassword;
    }

    // Useful for avoiding tweaking default auth scaffolding
    public function getNameAttribute()
    {
        return $this->uLogin;
    }
}

I added some comments above to highlight some the changes.

2. Custom user provider

As I told you in my first answer one approach is to use a Custom User Provider, for reference this is again the docs section about it:

https://laravel.com/docs/7.x/authentication#adding-custom-user-providers

So I created a new User Provider under the project ./app directory:

<?php

namespace App;

use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Contracts\Auth\UserProvider;
use Illuminate\Support\Arr;

class CustomUserProvider implements UserProvider
{
    public function retrieveById($identifier)
    {
        return User::query()->find($identifier);
    }

    public function retrieveByToken($identifier, $token)
    {
        // not implementing remeber me
        return null;
    }

    public function updateRememberToken(Authenticatable $user, $token)
    {
        // not implementing remeber me
    }

    public function retrieveByCredentials(array $credentials)
    {
        if (Arr::has($credentials, 'email')) {
            return User::query()
                ->where('uEmail', $credentials['email'])
                ->first();
        }

        // allow login user either by email or name
        // default auth scaffolding will use email
        // but you can tweak the login view and LoginController
        // to login by "login" field
        if (Arr::has($credentials, 'login')) {
            return User::query()
                ->where('uLogin', $credentials['login'])
                ->first();
        }

        return null;
    }

    public function validateCredentials(Authenticatable $user, array $credentials)
    {
        $plain = $credentials['password'];

        // use custom hash mechanism
        $hash = \hash('sha256', $user->uSalt . $plain);

        // comparing with hash_equals prevents time-based attacks
        // see php docs about it
        return \hash_equals($user->getAuthPassword(), $hash);
    }
}

Then, per docs instructions, we need to register this User Provider. Let's follow the docs recommendation and change our app's AuthServiceProvider (located at ./app/Providers/AuthServiceProvider.php)

<?php

namespace App\Providers;

use App\CustomUserProvider;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Gate;

class AuthServiceProvider extends ServiceProvider
{
    protected $policies = [
        // 'App\Model' => 'App\Policies\ModelPolicy',
    ];

    public function boot()
    {
        $this->registerPolicies();

        // ADD THIS. 
        // Don't forget to import the Auth Facade and CustomUserProvider
        Auth::provider('custom', function () {
            return new CustomUserProvider();
        });
    }
}

Note that for all changed classes I removed the default comments to minimize space here.

Lastly we need to tell Laravel to use this Custom User Provider for authentication. We can do so by modifying the ./config/auth.php file. I won't paste the whole file here, but should be easy to find the place to change looking at the snippet below:

    'providers' => [
        'users' => [
            'driver' => 'custom', // CHANGE HERE
            // 'model' => App\User::class, // not needed anymore
        ],

        // 'users' => [
        //     'driver' => 'database',
        //     'table' => 'users',
        // ],
    ],

3. Default Auth scaffolding

To test it out I used Laravel default auth scaffolding (see composer require laravel/ui above).

When registering new users we need to tweak the RegisterController (located at ./app/Http/Controllers/Auth/RegisterController.php).

<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use App\User;
use Illuminate\Foundation\Auth\RegistersUsers;
use Illuminate\Support\Facades\Validator;

class RegisterController extends Controller
{
    use RegistersUsers;

    protected $redirectTo = RouteServiceProvider::HOME;

    public function __construct()
    {
        $this->middleware('guest');
    }

    protected function validator(array $data)
    {
        return Validator::make($data, [
            'name' => ['required', 'string', 'max:255'],

            // might need to change the unique:users
            // if using custom users table name
            'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],

            'password' => ['required', 'string', 'min:8', 'confirmed'],
        ]);
    }

    protected function create(array $data)
    {
        // added for reference. use your current salt function
        $salt = $this->createSalt(5);

        return User::query()->create([
            'uLogin' => $data['name'],
            'uEmail' => $data['email'],
            'uPassword' => \hash('sha256', $salt . $data['password']),
            'uSalt' => $salt,
        ]);
    }

    // added for reference. use your current salt function
    private function createSalt($length)
    {
        $text = md5(uniqid(rand(), true));
        return substr($text, 0, $length);
    }
}

Note this controller is made available after installing the laravel/ui package listed above and running the php artisan ui bootstrap --auth command (bootstrap can be swapped by vue and react).

If you already have some authentication code in place take a look at the laravel/ui repository to check out how they approach authentication.

https://github.com/laravel/ui

As we are using the Custom User Provider, after we have a user in our database, we won't need to customize the LoginController. Authentication will just work.

4. Migrating and running

Before testing out, we need first to migrate the database, this can be done with this command:

php artisan migrate

Then we can start a webserver to test in the browser, by using this command:

php artisan serve

To test it out, follow this steps:

  • Navigate to http://localhost:8000
  • Click Register on the top right
  • Fill the form and register a new user, the name field will be saved in the login column
  • Click the user's name (login) on the top right
  • Click logout
  • Click Login on the top right
  • Fill the user's credentials and login

You can check the user was created and saved to the Database with your custom scheme, custom timestamps and custom hashing.

Hope it helps!

Aug
19
1 month ago
Activity icon

Awarded Best Reply on Laravel Query Builder, I Need Help In Write Query

Try this:

$records = Patient::query()
    ->select([
        'provider_id',
        DB::raw('COUNT(*) AS patients_count'),
        DB::raw("COUNT(CASE WHEN auth = 'Yes' THEN 1 ELSE NULL END) AS auth_yes_count"),
        DB::raw("COUNT(CASE WHEN auth = 'No' THEN 1 ELSE NULL END) AS auth_no_count"),
        DB::raw("COUNT(CASE WHEN auth_status = 'Approved' THEN 1 ELSE NULL END) AS status_approved_count"),
        DB::raw("COUNT(CASE WHEN auth_status = 'Denied' THEN 1 ELSE NULL END) AS status_denied_count"),
        DB::raw("COUNT(CASE WHEN auth_status = 'Pending' THEN 1 ELSE NULL END) AS status_pending_count"),
    ])
    ->groupBy('provider_id')
    ->withCasts([
        'patients_count' => 'integer',
        'auth_yes_count' => 'integer',
        'auth_no_count' => 'integer',
        'status_approved_count' => 'integer',
        'status_denied_count' => 'integer',
        'status_pending_count' => 'integer',
    ])
    ->get();

You can skip the ->withCasts(...) part if you are not using Laravel 7. That would convert your columns to integer instead of strings.

If you are not using Eloquent Models, but the query builder directly, use this:

$records = DB::table('patients')
    ->select([
        'provider_id',
        DB::raw('COUNT(*) AS patients_count'),
        DB::raw("COUNT(CASE WHEN auth = 'Yes' THEN 1 ELSE NULL END) AS auth_yes_count"),
        DB::raw("COUNT(CASE WHEN auth = 'No' THEN 1 ELSE NULL END) AS auth_no_count"),
        DB::raw("COUNT(CASE WHEN auth_status = 'Approved' THEN 1 ELSE NULL END) AS status_approved_count"),
        DB::raw("COUNT(CASE WHEN auth_status = 'Denied' THEN 1 ELSE NULL END) AS status_denied_count"),
        DB::raw("COUNT(CASE WHEN auth_status = 'Pending' THEN 1 ELSE NULL END) AS status_pending_count"),
    ])
    ->groupBy('provider_id')
    ->get();
Activity icon

Replied to Laravel Query Builder, I Need Help In Write Query

But what do you want to count? If it is random text it is hard to know what is in there.

As the field is nullable If you want to count only if the field is filled this might work:

$records = DB::table('patients')
    ->select([
        'provider_id',
        DB::raw('COUNT(*) AS patients_count'),
        DB::raw("COUNT(CASE WHEN auth = 'Yes' THEN 1 ELSE NULL END) AS auth_yes_count"),
        DB::raw("COUNT(CASE WHEN auth = 'No' THEN 1 ELSE NULL END) AS auth_no_count"),
        DB::raw("COUNT(CASE WHEN auth_status = 'Approved' THEN 1 ELSE NULL END) AS status_approved_count"),
        DB::raw("COUNT(CASE WHEN auth_status = 'Denied' THEN 1 ELSE NULL END) AS status_denied_count"),
        DB::raw("COUNT(CASE WHEN auth_status = 'Pending' THEN 1 ELSE NULL END) AS status_pending_count"),
        DB::raw("COUNT(auth_reconsideration) AS reconsiderations_count"),
    ])
    ->groupBy('provider_id')
    ->get();

As SQL's COUNT aggregate function will ignore NULL values, it would only count the rows where auth_reconsideration has some value filled in.

If you need to search for specific words you can use any SQL condition on the SQL's CASE statement:

DB::raw("COUNT(CASE
    WHEN auth_reconsideration LIKE '%foo%' THEN 1
    WHEN auth_reconsideration LIKE '%bar%' THEN 1
    ELSE NULL
END) AS reconsiderations_count"),

The example above will count all rows where the auth_reconsideration column contains the characters "foo" or "bar".

Activity icon

Awarded Best Reply on Message: "Cannot Modify Header Information - Headers Already Sent

You can try returning after the cookies were sent:

    public function addToCart($pid, $qty)
    {
        if (isset($_COOKIE["shopping_cart_panorama"])) {
            $cookie_data = stripslashes($_COOKIE["shopping_cart_panorama"]);
            $cart_data = json_decode($cookie_data, true);
        } else {
            $cart_data = array();
        }

        $item_id_list = array_column($cart_data, 'item_id');
        $wasAdded = false;

        if (in_array($pid, $item_id_list)) {
            foreach ($cart_data as $keys => $values) {
                if ($cart_data[$keys]["item_id"] == $pid) {
                    $cart_data[$keys]["item_qty"] = $cart_data[$keys]["item_qty"] + $qty;
                }
            }
        } else {
            $item_array = array(
                'item_id' => $pid,
                'item_qty' => $qty,
            );
            $cart_data[] = $item_array;

            $wasAdded = true; // replacing "echo 1;"
        }

        $item_data = json_encode($cart_data);
        setcookie('shopping_cart_panorama', $item_data, time() + (3600 * 24 * 30), "/");
        
        if ($wasAdded) {
            echo 1;
        }
    }

Is this function a controller's method? I would try using Laravel's built in methods for cookie and response manipulation:

public function addToCart($pid, $qty)
{
    // request() is a Laravel helper that wraps around super globals
    // and let you perform several request related tasks
    if (request()->hasCookie('shopping_cart_panorama')) {
        $cookie_data = stripslashes(request()->cookie('shopping_cart_panorama'));
        $cart_data = json_decode($cookie_data, true);
    } else {
        $cart_data = [];
    }

    $item_id_list = array_column($cart_data, 'item_id');
    $wasAdded = false;

    if (in_array($pid, $item_id_list)) {
        foreach ($cart_data as $keys => $values) {
            if ($cart_data[$keys]['item_id'] == $pid) {
                $cart_data[$keys]['item_qty'] = $cart_data[$keys]['item_qty'] + $qty;
            }
        }
    } else {
        $item_array = [
            'item_id' => $pid,
            'item_qty' => $qty,
        ];
        $cart_data[] = $item_array;

        $wasAdded = true;
    }

    $item_data = json_encode($cart_data);

    // cookie() is a Laravel helper to create a cookie object
    // note that we don't need to add to time() here, just tell 
    // the number of seconds when this cookie will expire in the future
    $cookie = cookie('shopping_cart_panorama', $item_data, 3600 * 24 * 30, '/');

    // response() is a Laravel helper that will create
    // a Laravel response object
    // intval will convert true -> 1 and false -> 0
    return response(intval($wasAdded))->withCookie($cookie);
}

If you try this code out, cookies will be encrypted by default. As you seem to be using this cookie client-side you will need to tell Laravel to not encrypt this cookie.

Go to your project's ./app/Http/Middleware/EncryptCookies.php file and add that cookie name to the $except array:

<?php

namespace App\Http\Middleware;

use Illuminate\Cookie\Middleware\EncryptCookies as Middleware;

class EncryptCookies extends Middleware
{
    /**
     * The names of the cookies that should not be encrypted.
     *
     * @var array
     */
    protected $except = [
        'shopping_cart_panorama',
    ];
}
Activity icon

Replied to How Do I Change The Password Verification Algorithm?

You can replace the User Provider Laravel authentication system uses.

By default it will use the EloquentUserProvider and hash the password using the bcrypt algorithm (this is the default, you can set a different hash algorithm).

But in your case I would implement a custom user provider as you need to check more than one column for password validation.

Take a read on the docs to learn how custom user providers work and how you can use them:

https://laravel.com/docs/7.x/authentication#adding-custom-user-providers

And take a look in the code for EloquentUserProvider for implementation hints:

https://github.com/laravel/framework/blob/7.x/src/Illuminate/Auth/EloquentUserProvider.php

Activity icon

Replied to Laravel Query Builder, I Need Help In Write Query

Try this:

$records = Patient::query()
    ->select([
        'provider_id',
        DB::raw('COUNT(*) AS patients_count'),
        DB::raw("COUNT(CASE WHEN auth = 'Yes' THEN 1 ELSE NULL END) AS auth_yes_count"),
        DB::raw("COUNT(CASE WHEN auth = 'No' THEN 1 ELSE NULL END) AS auth_no_count"),
        DB::raw("COUNT(CASE WHEN auth_status = 'Approved' THEN 1 ELSE NULL END) AS status_approved_count"),
        DB::raw("COUNT(CASE WHEN auth_status = 'Denied' THEN 1 ELSE NULL END) AS status_denied_count"),
        DB::raw("COUNT(CASE WHEN auth_status = 'Pending' THEN 1 ELSE NULL END) AS status_pending_count"),
    ])
    ->groupBy('provider_id')
    ->withCasts([
        'patients_count' => 'integer',
        'auth_yes_count' => 'integer',
        'auth_no_count' => 'integer',
        'status_approved_count' => 'integer',
        'status_denied_count' => 'integer',
        'status_pending_count' => 'integer',
    ])
    ->get();

You can skip the ->withCasts(...) part if you are not using Laravel 7. That would convert your columns to integer instead of strings.

If you are not using Eloquent Models, but the query builder directly, use this:

$records = DB::table('patients')
    ->select([
        'provider_id',
        DB::raw('COUNT(*) AS patients_count'),
        DB::raw("COUNT(CASE WHEN auth = 'Yes' THEN 1 ELSE NULL END) AS auth_yes_count"),
        DB::raw("COUNT(CASE WHEN auth = 'No' THEN 1 ELSE NULL END) AS auth_no_count"),
        DB::raw("COUNT(CASE WHEN auth_status = 'Approved' THEN 1 ELSE NULL END) AS status_approved_count"),
        DB::raw("COUNT(CASE WHEN auth_status = 'Denied' THEN 1 ELSE NULL END) AS status_denied_count"),
        DB::raw("COUNT(CASE WHEN auth_status = 'Pending' THEN 1 ELSE NULL END) AS status_pending_count"),
    ])
    ->groupBy('provider_id')
    ->get();
Activity icon

Replied to Message: "Cannot Modify Header Information - Headers Already Sent

Hi @yuvismahi2 , please create a new thread so more people can help you out on this.

Activity icon

Replied to Message: "Cannot Modify Header Information - Headers Already Sent

You can try returning after the cookies were sent:

    public function addToCart($pid, $qty)
    {
        if (isset($_COOKIE["shopping_cart_panorama"])) {
            $cookie_data = stripslashes($_COOKIE["shopping_cart_panorama"]);
            $cart_data = json_decode($cookie_data, true);
        } else {
            $cart_data = array();
        }

        $item_id_list = array_column($cart_data, 'item_id');
        $wasAdded = false;

        if (in_array($pid, $item_id_list)) {
            foreach ($cart_data as $keys => $values) {
                if ($cart_data[$keys]["item_id"] == $pid) {
                    $cart_data[$keys]["item_qty"] = $cart_data[$keys]["item_qty"] + $qty;
                }
            }
        } else {
            $item_array = array(
                'item_id' => $pid,
                'item_qty' => $qty,
            );
            $cart_data[] = $item_array;

            $wasAdded = true; // replacing "echo 1;"
        }

        $item_data = json_encode($cart_data);
        setcookie('shopping_cart_panorama', $item_data, time() + (3600 * 24 * 30), "/");
        
        if ($wasAdded) {
            echo 1;
        }
    }

Is this function a controller's method? I would try using Laravel's built in methods for cookie and response manipulation:

public function addToCart($pid, $qty)
{
    // request() is a Laravel helper that wraps around super globals
    // and let you perform several request related tasks
    if (request()->hasCookie('shopping_cart_panorama')) {
        $cookie_data = stripslashes(request()->cookie('shopping_cart_panorama'));
        $cart_data = json_decode($cookie_data, true);
    } else {
        $cart_data = [];
    }

    $item_id_list = array_column($cart_data, 'item_id');
    $wasAdded = false;

    if (in_array($pid, $item_id_list)) {
        foreach ($cart_data as $keys => $values) {
            if ($cart_data[$keys]['item_id'] == $pid) {
                $cart_data[$keys]['item_qty'] = $cart_data[$keys]['item_qty'] + $qty;
            }
        }
    } else {
        $item_array = [
            'item_id' => $pid,
            'item_qty' => $qty,
        ];
        $cart_data[] = $item_array;

        $wasAdded = true;
    }

    $item_data = json_encode($cart_data);

    // cookie() is a Laravel helper to create a cookie object
    // note that we don't need to add to time() here, just tell 
    // the number of seconds when this cookie will expire in the future
    $cookie = cookie('shopping_cart_panorama', $item_data, 3600 * 24 * 30, '/');

    // response() is a Laravel helper that will create
    // a Laravel response object
    // intval will convert true -> 1 and false -> 0
    return response(intval($wasAdded))->withCookie($cookie);
}

If you try this code out, cookies will be encrypted by default. As you seem to be using this cookie client-side you will need to tell Laravel to not encrypt this cookie.

Go to your project's ./app/Http/Middleware/EncryptCookies.php file and add that cookie name to the $except array:

<?php

namespace App\Http\Middleware;

use Illuminate\Cookie\Middleware\EncryptCookies as Middleware;

class EncryptCookies extends Middleware
{
    /**
     * The names of the cookies that should not be encrypted.
     *
     * @var array
     */
    protected $except = [
        'shopping_cart_panorama',
    ];
}
Activity icon

Replied to Package Phpunit/php-token-stream Is Abandoned

It is just a warning you can ignore it.

it is requested by a third-party dependency not by Laravel itself. So when this dependency gets updated by its mantainer this message will disappear.

To know which dependency requires it you can run:

$ composer why phpunit/php-token-stream

Which outputs:

phpunit/php-code-coverage  7.0.10  requires  phpunit/php-token-stream (^3.1.1)

And phpunit/php-code-coverage is required by phpunit/phpunit which is required by Laravel.

So probably on a next update to PHPUnit this message will vanish. By now no need to worry about it.

Aug
18
1 month ago
Activity icon

Replied to Message: "Cannot Modify Header Information - Headers Already Sent

The error disappears because the @ is the error suppression operator, so it will hide any errors that happened on that function call, but it won't prevent any error from happening.

Regarding the error cause, try removing (or commenting out) the echo 1; 2 lines above the setcookie call.

As stated in PHP docs:

setcookie() defines a cookie to be sent along with the rest of the HTTP headers. Like other headers, cookies must be sent before any output from your script (this is a protocol restriction). This requires that you place calls to this function prior to any output, including and tags as well as any whitespace.

reference: https://www.php.net/manual/en/function.setcookie.php

So as the echo 1; sends an output before setting the cookies, that might be the reason the setcookie call fails.

Aug
15
1 month ago
Activity icon

Awarded Best Reply on Update Prototype Outside The Instance

Didn't test with this configuration, but I sometimes reach for Vue.observable to make variables reactive.

If you can try using it in your app like this:

Vue.prototype.$user = Vue.observable(JSON.parse(document.getElementById('app').getAttribute('user')));

const app = new Vue({
    el: '#app',
});

I am betting it might work.

Reference:

https://vuejs.org/v2/api/#Vue-observable

Note: Per docs it requires Vue 2.6+

Activity icon

Replied to Load Blade File Using Jquery

I would go with @yuhliel suggestion and also since Laravel 5.5 you can map a route to a view file in your routes.php file like this:

Route::view('/admin/admins/statistics', 'admin.admins.statistics');

Docs: https://laravel.com/docs/5.5/routing#view-routes

Activity icon

Replied to Update Prototype Outside The Instance

Didn't test with this configuration, but I sometimes reach for Vue.observable to make variables reactive.

If you can try using it in your app like this:

Vue.prototype.$user = Vue.observable(JSON.parse(document.getElementById('app').getAttribute('user')));

const app = new Vue({
    el: '#app',
});

I am betting it might work.

Reference:

https://vuejs.org/v2/api/#Vue-observable

Note: Per docs it requires Vue 2.6+

Aug
05
1 month ago
Activity icon

Replied to Group By Month And Order By Something Else?

Great you have it working. The weird thing from the error message you sent is that my try was not grouping by on the DB query, it was using the collection's group by method after the database query is getting executed (after the ->get()) method.

Maybe you tried adapting my solution to your existing code. Which makes totally sense as you might have shared a simplified version of your app's code.

Essentially grouping by in the for each is similar to what I proposed, as it is grouping the collection, not the query.

I skipped grouping by in the database as it seemed to me you want to fetch all Post's records and then group by the results for UI presentation. I generally only group by in the database when I need some kind of aggregation, (such as COUNT(), AVG(), SUM(), ...).

When using one of those, for most DBMS, you need to specify the columns you are referring on the SELECT and ORDER BY clauses to not have the error message you sent.

But then again, great you got it working =)

Jul
29
1 month ago
Activity icon

Replied to Group By Month And Order By Something Else?

Laracasts has a video about something similar:

https://laracasts.com/series/laravel-explained/episodes/6

But the solution in the lesson is similar to what you already have

As you want to show the individual records, grouped by month and then sort them by rank, maybe fetching from DB ordered by date, group the collection and them sorting might do the trick:

$posts = Post::query()
    ->latest() // similar to ->orderByDesc('created_at')
    ->get() // fetch the query and returns a collection
    ->groupBy(function ($post) {
        // If Post is a regular Eloquent model, 
        // I think you can safely change this line to:
        // return $post->created_at->format('F');

        // to be safe when close to year change, 
        // I would add the year to the format:
        // return $post->created_at->format('F, Y');

        return Carbon::parse($post->created_at)->format('F');
    })
    ->transform(function ($group) { // similar to ->map()
        // as collection was grouped each item will be a collection from the grouped items
        return $group->sortByDesc('post_likes');
    });
Jul
10
2 months ago
Activity icon

Replied to How To Start

I would highly recommend starting with this series:

https://laracasts.com/series/laravel-6-from-scratch

It is a free series and covers basically all you need to know to get started with Laravel.

Although Laravel current version is v7 and the series is named after v6, the concepts covered in that series have not changed a lot and most code should work on v7 with no changes.

v7 introduced some new features worth taking a look such as the HTTP client and blade components, but after going through that series you can easily learn those from the docs itself:

https://laravel.com/docs

Those content are also covered in some other Laracasts videos, specially blade components have an on going series:

https://laracasts.com/series/blade-component-cookbook

But this one is not free to watch.

Jun
09
3 months ago
Activity icon

Replied to Laravel Mysql Select All Except An Array Of Values ?

It seems your frontend is sending mat_codes as an string with the codes concatenated by a string.

Try this:

$mat_codes = [];

if ($request->mat_codes !== null) {
    $mat_codes = explode(',', $mat_codes);
}

It doesn't seem that the mat_codes request variables can contain spaces between commas, but if that is a possibility, I would add:

$mat_codes = [];

if ($request->mat_codes !== null) {
    $mat_codes = array_map('trim', explode(',', $mat_codes));
}

Just to be sure if an element on the list contains a space, such as xxx, 123, it becomes the array ['xxx', '123']

May
02
4 months ago
Activity icon

Awarded Best Reply on Calling Validation FormRequest From Controller Is Sometimes Incorrect

Unfortunately passing arguments to class hints is not possible.

As FormRequest is a Request you don't need to use the request() helper inside of it. You could change your example as the following:

protected function prepareForValidation()
{
    if (!$this->has('enable')) return; // do nothing

    // process as above
}

Also you could have a QuickAddTasksRequest with the rules method and make TaskRequest extend that adding the prepareForValidation method.

Personally I avoid having deep class hierarchies, as they can become hard to maintain, but that is an option.

For example:

// namespace, use, etc...

class QuickAddTasksRequest extends FormRequest {
  public function rules() {
    return [
      // validation rules
    ];
  }

  // no prepareForValidation
}
// namespace, use, etc...

class TasksRequest extends QuickAddTasksRequest {
  // no need of a rules method as they are defined in the parent class

  public function prepareForValidation() {
    // pre-validation sanitizing logic
  }
}

And then on each controller you would have:

// quick add controller

public function store(QuickAddTasksRequest $request) {
  $validated = $request->validated();
  // do something with the validated data
}
// regular controller

public function store(TasksRequest $request) {
  $validated = $request->validated();
  // do something with the validated data
}

That way the prepareForValidation method would only be executed in the TasksRequest while it shares the same rules from the QuickAddTasksRequest

Activity icon

Replied to Hide Modal Box After User Login

As you are using standard bootstrap data- attributes I assume you have jQuery in your setup.

So you can manually hide the modal after the user logs in:

      submit () {
        this.signIn(this.form);
        $('#myModal1').modal('hide');
      }

Reference

https://getbootstrap.com/docs/4.4/components/modal/#modalhide

Activity icon

Replied to Calling Validation FormRequest From Controller Is Sometimes Incorrect

Unfortunately passing arguments to class hints is not possible.

As FormRequest is a Request you don't need to use the request() helper inside of it. You could change your example as the following:

protected function prepareForValidation()
{
    if (!$this->has('enable')) return; // do nothing

    // process as above
}

Also you could have a QuickAddTasksRequest with the rules method and make TaskRequest extend that adding the prepareForValidation method.

Personally I avoid having deep class hierarchies, as they can become hard to maintain, but that is an option.

For example:

// namespace, use, etc...

class QuickAddTasksRequest extends FormRequest {
  public function rules() {
    return [
      // validation rules
    ];
  }

  // no prepareForValidation
}
// namespace, use, etc...

class TasksRequest extends QuickAddTasksRequest {
  // no need of a rules method as they are defined in the parent class

  public function prepareForValidation() {
    // pre-validation sanitizing logic
  }
}

And then on each controller you would have:

// quick add controller

public function store(QuickAddTasksRequest $request) {
  $validated = $request->validated();
  // do something with the validated data
}
// regular controller

public function store(TasksRequest $request) {
  $validated = $request->validated();
  // do something with the validated data
}

That way the prepareForValidation method would only be executed in the TasksRequest while it shares the same rules from the QuickAddTasksRequest

Activity icon

Awarded Best Reply on Problem With Storing Checkbox Values In Database

If you want the checkboxes values as an array the name attribute in all of them should something like name="looking_for[]" so PHP will make them available as an array.

Also the for attribute in the <label> element binds the label to a input by its id attribute. id is the one that should be unique in a HTML document. name tells how to pack the form input fields when submitting

<div class="interestedIn">
  <input type="checkbox" id="{{ $name.'-'.$value }}" name="{{ $name }}[]" value="{{ $value }}" {{ isset($data[$fieldData['label']['id']]) ? (in_array($value, $data[$fieldData['label']['id']]) ? 'checked' : null) : '' }}>
  <label for="{{$name}}-{{ $value }}">{{ $label }}</label>
</div>

Note: Just added id and changed name, didn't assessed nor changed your checked logic

Activity icon

Replied to Problem With Storing Checkbox Values In Database

If you want the checkboxes values as an array the name attribute in all of them should something like name="looking_for[]" so PHP will make them available as an array.

Also the for attribute in the <label> element binds the label to a input by its id attribute. id is the one that should be unique in a HTML document. name tells how to pack the form input fields when submitting

<div class="interestedIn">
  <input type="checkbox" id="{{ $name.'-'.$value }}" name="{{ $name }}[]" value="{{ $value }}" {{ isset($data[$fieldData['label']['id']]) ? (in_array($value, $data[$fieldData['label']['id']]) ? 'checked' : null) : '' }}>
  <label for="{{$name}}-{{ $value }}">{{ $label }}</label>
</div>

Note: Just added id and changed name, didn't assessed nor changed your checked logic

Activity icon

Replied to Can I Use Laravel Educational Projects?

Sure. Sorry for the late response, was busy these last days.

Activity icon

Replied to Calling Validation FormRequest From Controller Is Sometimes Incorrect

Sorry for the late response, these last days were busy to me.

As the form request extends the request you have access to all the normal request's methods.

For example you could check by route name:

protected function prepareForValidation()
{
    if ($this->routeIs('my.route.name')) return; // do nothing

    // process as above
}

by path:

protected function prepareForValidation()
{
    if ($this->is('/task/*')) return; // do nothing

    // process as above
}

Or by any other request method.

May
01
4 months ago
Activity icon

Awarded Best Reply on Get Type SET Values Using Eloquent.

You mean to discover from an existing DB?

I would list them in a constant in a Model class, as querying the DB every time to check for valid values can lead to performance issues, also SET values generally don't change too much.

Anyway, I found this link that gets the value for a ENUM column, might help you somehow.

http://constituteweb.com/eloquent-laravel-enum

Apr
29
4 months ago
Activity icon

Replied to Can I Use Laravel Educational Projects?

You're welcome =) hope something helps.

Activity icon

Replied to Multi Threading In Laravel

I guess you can enable threads if you are using php-fpm (usually with nginx) but you will need to whitelist and increase timeout in your php.ini

I wouldn't go that way, as it is not usual.

But considering your description I would agree that the options are using queued jobs or optimized synchronous code.

Personally I like the flow of queuing jobs and have a record to inform the user of the progress and completion/failure. I think UI is more responsive as the request just dispatches the job and gets back to the user.

But of course your requirements might ask for a different approach.

Good luck, and please share if you come to a different strategy.

Activity icon

Replied to Calling Validation FormRequest From Controller Is Sometimes Incorrect

You can override the prepareForValidation method from the form request to merge data before the Form Request validation is triggered

https://laravel.com/docs/7.x/validation#prepare-input-for-validation

Even the example from the docs is something similar:

/**
 * Prepare the data for validation.
 *
 * @return void
 */
protected function prepareForValidation()
{
    $this->merge([
        'slug' => Str::slug($this->slug),
    ]);
}

In your case it would be something like this:

protected function prepareForValidation()
{
    // get accepts a default value when field is not present
    // also, as FormRequest extends request we can use $this here
    $id = $this->get('id', 0);

    $suggest = TasksSuggests::find( $id );

    $data = /* ... init data from suggest */

    $this->merge($data);
}

This prepareForValidation will be called before the form request validation is triggered.

Apr
28
4 months ago
Activity icon

Replied to [FormRequest Validation] Missing Inputs Marked Required Not Validating

If you add a required attribute to the <select> element the HTML form won't allow the user to submit it if a value is not chosen:

<select name="category" required>
	<option value="">Select a category</option>
</select>
Activity icon

Awarded Best Reply on Using Route Helper Links With Tabbed Nav Bar Pills

From my understanding one would use the data-toggle behavior when they already have the content rendered and only want to show a tab at a time. So it makes sense to prevent the link to do navigation.

It seems that you want to navigate between different pages but have the correct tab highlighted. If that is the case, you can change the active class to the selected link:

<nav class="navbar navbar-expand-sm fixed-top navbar-light bg-white ">
    <div class="container-fluid">
        <ul class="nav nav-pills nav-pills -primary nav-pills -icons justify -content -center" role="tablist">
            <li class="nav-item" style="padding -right:0.9em;">
                <a class="nav-link {{ request()->routeIs('user.index') ? 'active' : null }}" href="{{ route('user.index') }}" role="tablist">User </a>
            </li>
            <li class="nav-item">
                <a class="nav-link {{ request()->routeIs('page.charts') ? 'active' : null }}"  href="{{ route('page.charts') }}" role="tablist" margin="30px">Charts </a>
            </li>
        </ul>
    </div>
</nav>
Activity icon

Replied to [FormRequest Validation] Missing Inputs Marked Required Not Validating

Really weird, I just tested with a clean laravel install with this form request and route:

namespace App\Http\Requests;

use Illuminate\Contracts\Validation\Validator;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Http\Exceptions\HttpResponseException;

class DummyRequest extends FormRequest
{
    public function rules()
    {
        return [
            'name' => 'required',
            'category' => 'required',
        ];
    }

    protected function failedValidation(Validator $validator)
    {
        $response = response()->json($this->all() + ['failed' => true]);

        throw new HttpResponseException($response);
    }
}
Route::get('test', function (\App\Http\Requests\DummyRequest $request) {
    return $request->all() + ['valid' => true];
});

So if I navigate to one of these:

http://localhost:8000/test
http://localhost:8000/test?name=Mary
http://localhost:8000/test?category=Dev

It shows the 'failed' key on the output as expected, and when navigating to

http://localhost:8000/test?name=Mary&category=Dev

It shows the 'valid' key on the output as expected.

So it seems your problem might something else, but it is hard to tell with the information we have.

I would double check the data coming to the request adding a dd() to the FormRequest's validated method:


public function validated()
{
    dd(parent::validated(), $this->all());
}

Just to be sure category is missing from the request when it passes.

Activity icon

Replied to Multi Threading In Laravel

You can have an auxiliary table/model where you track your job status and save the results. So in the frontend you would show the processing status while it processes and keep refreshing (or polling with ajax) the status until it is done.

Imagine you need to perform time expensive operations on an Order model. Your job would be something like this:

class GenerateExpensiveReport implements ShouldQueue {
  use SerializesModels;

  protected $order;

  // pass any other needed variables to the job
  public function __construct(Order $order) {
    $this->order = $order;
  }

  public function handle() {
    $process = new Process();
    $process->status = 'processing';
    $process->output = null;
    $process->started_at = now();
    $process->ended_at = null;
    $this->order->process()->save($process);

    try {
      // perform some time expensive calculation

      $process->status = 'success';
      $process->output = null;
      $process->ended_at = now();
      $process->save();
    } catch(\Throwable $exception) { // use \Exception on older PHP version
      $process->status = 'error';
      $process->output = $exception->getMessage();
      $process->ended_at = now();
      $process->save();
    }
  }
}

The Process model needs a table with a status, output, started_at and ended_at and morph columns.

https://laravel.com/docs/7.x/eloquent-relationships#one-to-one-polymorphic-relations

And in your Order model you define the relation to process as this:

public function process()
{
  return $this->morphOne(Process::class, 'processable')
    ->withDefault(function () {
      return Process(['status' => 'pending']);
    });
}

Of course you can add those snippets to update a process status on the status model itself so you can reuse with other jobs

Activity icon

Awarded Best Reply on Is It Best Practice If I Store Model Data In $request?

Don't worry, having path-related parameters bound to the request object is a common practice.

Laravel even has this feature (automatically bind a model based on a route parameter) out of the box:

https://laravel.com/docs/7.x/routing#route-model-binding

It is a very useful feature.

If you are using Laravel 7 you can skip your middleware and change your routes paths to:

/{member:code}/abc

/{member:code}/def

/{member:code}/xyz

Then in your controllers/action do this:

$member = $request->route('member');

Laravel will even throw a 404 when member is not found.