TuffRivers's avatar

Query Builder and Models

Hi All,

I am electing not ot use eloquent for this project and im new to OOP so im having a hard time understanding when i should be working with an object and when with arrays.

I am testing my web api service to create a new user but having some difficulty saving to my database. I know that if i use PDO i can create an insert statement and write my Request $request fields to an array and easily bind it and insert it in my model function insert($userOptions), but why would i then create a new model in my controller just to convert it to an array after? Can i write objects to my databse without eloquent?

Sorry for the confusion, im a noob!

Model

<?PHP

namespace App\Models;
use Illuminate\Notifications\Notifiable;
use Laravel\Passport\HasApiTokens;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Support\Facades\DB;

class User extends Authenticatable

{

    use HasApiTokens, Notifiable;

    public $id;
    public $first_name;
    public $last_name;
    public $email;
    public $alerts;
    public $status;
    public $client_id;
    public $password;

    public function insert($user){

       DB::table('users')->insert($user); //this will not work because $user is an object
        return $user;
    }

}

Controller

<?php
   
namespace App\Http\Controllers\API;
   
use Illuminate\Http\Request;
use App\Http\Controllers\API\BaseController as BaseController;
use App\Models\User;
use Validator;
   
class UserController extends BaseController
{
    /**
     * Register api
     *
     * @return \Illuminate\Http\Response
     */
    public function register(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'first_name' => 'string|required',
            'last_name' => 'string|required',
            'client_id' => '',
            'email' => 'required|email',
            'password' => 'required',
            'c_password' => 'required|same:password',
        ]);
   
        if($validator->fails()){
            return $this->sendError('Validation Error.', $validator->errors());       
        }

    
        $data = $request->only('first_name','last_name','client_id','email','password');
        
        $user = new User; //create a user model, whats the point if i just build it as an array and pass to my insert function ?
        $user->first_name = $data['first_name'];
        $user->last_name = $data['last_name'];
        $user->client_id = $data['client_id'];
        $user->email = $data['email'];
        $user->password = bcrypt($data['password']);
      

        $user->insert($user); //call insert function in my model passing the user 
       
   
        return $this->sendResponse($user, 'User created.');
    }
}
0 likes
20 replies
Snapey's avatar

why not follow some tutorials and use eloquent. You will quickly get to grips with it and have less problems as a result.

You don't need to copy the variables to a temporary data array, and just need to add save() rather than insert

        $user = new User;
        $user->first_name = $request->first_name;
        $user->last_name = $request->last_name;
        $user->client_id = $request->client_id;
        $user->email = $request->email;
        $user->password = bcrypt($request->password);
      
        $user->save();
TuffRivers's avatar

@snapey i unsertand the benefits of an ORM and i also know for my use case 95% of what i need CAN be satisfied by eloquent, but i want to take a rougher approach and do things a bit dirtier with SQL (i actually really like working with SQL haha) and less abastraction

also $user->save() returns this error:

Illuminate\Database\QueryException: SQLSTATE[HY000]: General error: 1364 Field 'first_name' doesn't have a default value (SQL: insert into `users` (`updated_at`, `created_at`) values (2020-03-21 19:28:27, 2020-03-21 19:28:27)) in file 

my object:

App\Models\User Object
(
[fillable:protected] => Array
(
[0] => client_id
[1] => first_name
[2] => last_name
[3] => email
[4] => password
)

[id] =>
[first_name] => Enza
[last_name] => B 
[email] => [email protected]
[alerts] =>
[status] =>
[client_id] =>
[password] => y$czzIoE81YoMsBZRQRzW1RekVRutruuN0LQ0Twe9USNd3ChX3Gyw.m
[connection:protected] =>
[table:protected] =>
[primaryKey:protected] => id
[keyType:protected] => int
[incrementing] => 1
[with:protected] => Array
(
)

[withCount:protected] => Array
(
)

[perPage:protected] => 15
[exists] =>
[wasRecentlyCreated] =>
[attributes:protected] => Array
(
)

[original:protected] => Array
(
)

[changes:protected] => Array
(
)

[casts:protected] => Array
(
)

[classCastCache:protected] => Array
(
)

[dates:protected] => Array
(
)

[dateFormat:protected] =>
[appends:protected] => Array
(
)

[dispatchesEvents:protected] => Array
(
)

[observables:protected] => Array
(
)

[relations:protected] => Array
(
)

[touches:protected] => Array
(
)

[timestamps] => 1
[hidden:protected] => Array
(
)

[visible:protected] => Array
(
)

[guarded:protected] => Array
(
[0] => *
)

[rememberTokenName:protected] => remember_token
[accessToken:protected] =>
)

I want to move all databse stuff outside of my controller as well from what tutorials ive seen this is the best practice?

Snapey's avatar

if using the code I posted, this should not be the case, unless your $request has null values.

Snapey's avatar

but if you just want to use query builder its easy enough, and identical syntax in most cases

TuffRivers's avatar

Thats what i thought. But this is what my $usre object looks like before in $user>save() - first_name isnt null ?

[id] => //AI in the database
[first_name] => Enza //not null
[last_name] => B //not null
[email] => [email protected] //not null
[alerts] => //null allowed - auto set in database to 1
[status] => //null allowed - auto set in databsae to 1
[client_id] => //null allowed
[password] => y$czzIoE81YoMsBZRQRzW1RekVRutruuN0LQ0Twe9USNd3ChX3Gyw.m //nn
TuffRivers's avatar

This is my code doing the save within the controller and not calling the model function

<?php
   
namespace App\Http\Controllers\API;
   
use Illuminate\Http\Request;
use App\Http\Controllers\API\BaseController as BaseController;
use App\Models\User;

use Validator;
   
class UserController extends BaseController
{
    /**
     * Register api
     *
     * @return \Illuminate\Http\Response
     */
    public function register(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'first_name' => 'string|required',
            'last_name' => 'string|required',
            'client_id' => '',
            'email' => 'required|email',
            'password' => 'required',
            'c_password' => 'required|same:password',
        ]);
   
        if($validator->fails()){
            return $this->sendError('Validation Error.', $validator->errors());       
        }

    
        $user = new User;
        $user->first_name = $request->first_name;
        $user->last_name = $request->last_name;
        $user->client_id = $request->client_id;
        $user->email = $request->email;
        $user->password = bcrypt($request->password);
      
        $user->save();
       
   
        return $this->sendResponse($user, 'User created.');
    }
}
burimb's avatar
burimb
Best Answer
Level 4
A tip: Validatore::make()->validate() returns all validated attributes

>>> Validator::make(['name'=>'burim'], ['name'=>'required'])->validate()
=> [
     "name" => "burim",
   ]

I think this is better way to do the work

<?php
   
namespace App\Http\Controllers\API;
   
use Illuminate\Http\Request;
use App\Http\Controllers\API\BaseController as BaseController;
use App\Models\User;
use Validator;
   
class UserController extends BaseController
{
    /**
     * Register api
     *
     * @return \Illuminate\Http\Response
     */
    public function register(Request $request, UserRepository $userRepo)
    {
        $validated = Validator::make($request->all(), [
            'first_name' => 'string|required',
            'last_name' => 'string|required',
            'client_id' => '',
            'email' => 'required|email',
            'password' => 'required',
            'c_password' => 'required|same:password',
        ])->validate();
    
   
        $validated['password'] = bcrypt($request['password']);
      

        $userRepo->insert($validated); //call insert function in user repository passing the user as array 
       
   
        return $this->sendResponse($user, 'User created.');
    }
}

Add new UserRepository

<?php

namespace App\Repositories;

use App\User;

class UserRepository implements UserRepositoryInterface
{
    /**
     * Create new public function
     */
    public function insert($attributes)
    {
        \DB::table('users')->insert($attributes);
    }
}
TuffRivers's avatar

this makes sense, would my UserRepositoryInterface look like?

interface UserRepositoryInterface
{
    public function insert($attributes);
 
}
1 like
burimb's avatar

Yess,

<?php

namespace App\Repositories;

interface UserRepositoryInterface
{
	public function insert($attributes);
}
Snapey's avatar

its not saving because you have added those public attributes in your user model.

These stop the eloquent model attributes from being updated so when you save, the public attributes you have set are not saved.

Snapey's avatar

personal opinion ... repositories == big waste of time and duplication of existing and proven functionality

TuffRivers's avatar

So you suggest i just skip reposotiry and put the insert code either in controller or directly in model?

Snapey's avatar

I can only say what I do. Use a FormRequest class and give it the responsibility of saving form data.

TuffRivers's avatar

care to share an example and how your set it up? Like are you executing this in the controller or in the model (i assume you call the formrequest class from either of them)

jlrdw's avatar

@tuffrivers if yor are not using eloquent, I'd suggest still using the query builder at least, an insert is just this easy:

Validation not shown.

            $dogpic = $newname;
            $dogname = ucfirst(Request::input('dogname'));
            $sex = ucfirst(Request::input('sex'));
            $comments = Request::input('comments');
            $adopted = !empty(Request::input('adopted')) ? '1' : '0';
            $lastedit = date("Y-m-d H:i:s");

            $postdata = array(
                'dogpic' => $dogpic,
                'dogname' => $dogname,
                'sex' => $sex,
                'comments' => $comments,
                'adopted' => $adopted,
                'lastedit' => $lastedit
            );

            DB::table('dc_dogs')->insert($postdata);

But you can use request direct, like just example here:

'comments' => Request::input('comments'),

For me just habit of putting in an array first. Sometimes I have the insert statement in model, and easy to pass an array.

But really, this stuff is easy. Just look over and work examples from query builder docs.

Remember validate.

1 like
TuffRivers's avatar

@jlrdw

Thanks i guess i was just confused because im used to only working with arrays and never objects and now that im trying OOP i was confused that i would convert my data to array before inserting into database.

TuffRivers's avatar

@jlrdw

So i elected to use the repository pattern and i am able to insert my data by turning it into an array. I now want to get that user information as an object and send that object back to my controller so i can trigger an event (send welcome email).

Would i just search for the user based on the email, or is this a hack way of doing it?

<?php

namespace App\Repositories;
use Illuminate\Support\Facades\DB;
use App\RepositoryInterface\UserRepositoryInterface;
use App\Models\User;

class UserRepository implements UserRepositoryInterface
{



 
    /**
     * Create new public function
     */
    public function insert($request)
    {

        $newUser = array(
            "client_id" => $request->client_id,
            "first_name" => $request->first_name,
            "last_name" => $request->last_name,
            "email" => $request->email,
            "password" => bcrypt($request->password),
            "created_at" => now(),
            "updated_at" => now()
        );
         
        DB::table('users')->insert($newUser); 
  	// $userData = select from users where email = newUser['email'] ?
	//create user object
// $userObj = new User;
//$userObj->first_name = $user['first_name'].. etc
        // return user;
       
    }
}

Thanks

Please or to participate in this conversation.