PHP ORM "Spot" throws exception for an easy use case - php

I just tyed out the ORM "Spot" and created a simple entity with only 1 field, created the correspoding table and followed the documentation to insert a row for an instance of that entity. I keep getting an ArgumentCountError in the set function of the Entity class of Spot, but the Entity gets saved anyway. This is the Code im using.
$data = [
'firstName' => $this->request->getParameter('fname'),
'lastName' => $this->request->getParameter('lname'),
];
$cfg = new \Spot\Config();
// MySQL
$cfg->addConnection('mysql', 'mysql://TestUser:1234#localhost/bookstore');
$spot = new \Spot\Locator($cfg);
$userMapper = $spot->mapper('Example\Models\User');
$entity = $userMapper->build([
'firstName' => $data['firstName']
]);
$result = $userMapper->insert($entity);
and the Entity:
class User extends Entity
{
protected static $table = 'user';
public static function fields()
{
return [
'firstName'=> ['type' => 'string']
];
}
}

Related

CREATE operation with Eloquent ORM shows 500 internal server error

I am trying to make a POST request to add a showroom in the Laravel application. When I try to do it with Showroom model using Eloquent ORM , it shows 500 internal server error. But if I do it with DB query, then it successfully CREATE the showroom. I commented out the db query lines and apply dd debugging and found out table for Showroom Model is null.
This is my controller code -
public function store(ShowroomRequest $request)
{
$showroom = new Showroom([
"name" => $request->get('name'),
"address" => $request->get('address'),
"description" => $request->get('description'),
]);
dd($showroom);
$ret = $showroom->save();
// $name = $request->input('name');
// $address = $request->input('address');
// $description = $request->input('description');
// DB::table('showroom')->insert(
// ['name' => $name, 'address' => $address, 'description' => $description]
// );
return redirect()->route('back.showroom.index')->withSuccess(__('Showroom Added Successfully.'));
}
And this is my model -
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Showroom extends Model
{
protected $fillable = ['name', 'description', 'address'];
protected static $ordersModel = 'App\Models\Order';
protected static $reviewsModel = 'App\Models\Review';
public function Orders()
{
return $this->hasMany(static::$ordersModel, 'showroom_id');
}
public function Reviews()
{
return $this->hasMany(static::$reviewsModel, 'showroom_id');
}
}
Finally this is my db structure -
Can anyone help me to find out what went wrong here? Thanks in advance.
in controller can you assign static values instead of request->get, and see if it saves.
please let me what happens afterwards.
also assign name of table in model like this,
protected $table = 'tablename';

How to get methods properties values - PHP

I have this code and wonder get the methods properties values.
<?php
class framework{
// users table
function users(){
$username="VARCHAR (255)";
$email="VARCHAR (255)";
$password="VARCHAR (255)";
}
// product table
function produts(){
$title="VARCHAR (255)";
$price="INT ()";
$author="VARCHAR (255)";
}
//categories table
function categories(){
$category_name="VARCHAR (255)";
}
}
?>
I'm trying to create my own framework and in this particular code I'm trying to simplify database creation. The idea is to get the class name as the database name and the methods as tables names, and the last get the methods properties as cols.
I use get_class() to get the class name and add as table name;
get_class_methods to get the class methods and create the table.
So I have no idea of how to create the respective cols.
I am not recommending this approach because you are reinventing the wheel here, but you could expose your DDL info via public properties. Of course, you can make these private/protected and expose them via getters.
I also created a base model which your child models can inherit. This allows for IDE autocompletion in the DatabaseBuilder below.
<?php
namespace Bartolomeu;
// Base model
abstract class Model {
public $table;
public $columns;
}
class User extends Model
{
public $table = 'users';
public $columns = [
'username' => 'VARCHAR (255)',
'email' => 'VARCHAR (255)',
'password' => 'VARCHAR (255)',
];
}
class Product extends Model
{
public $table = 'products';
public $columns = [
'title' => 'VARCHAR (255)',
'price' => 'INT ()',
'author' => 'VARCHAR (255)',
];
}
class Category extends Model
{
public $table = 'categories';
public $columns = [
'category_name' => 'VARCHAR (255)',
];
}
Finally, you can create a class that will actually "read" the models and do the necessary work to create the tables themselves.
<?php
class DatabaseBuilder
{
public function createTables()
{
$models = [
new User(),
new Product(),
new Category(),
];
foreach ($models as $model) {
/* #var Model $model */
$table = $model->table;
$columns = $model->columns;
//...
}
}
}

Saving application/json with SLIM 3 and Eloquent

So, when getting an Object from the database i do something like this in the Object Controller:
public function show(Request $request, Response $response, array $args)
{
$id = (int)$args['oid'];
$object = $this->object->getObjectById($id);
$data = $this->fractal->createData(new Item($object, new ObjectTransformer()))->toArray();
return $response->withJson($data);
}
I'm using fractal to transform the database structure to the needed JSON format and Eloquent for the Database access.
Then i'm getting something like this:
{
"propertyId": 12345,
"created": "2017-12-29T19:25:23+01:00",
"modified": "2018-06-07T17:28:04+02:00",
"published": true,
"market": [
"buy"
],
"text": {
"title": "Object Title"
}
}
I'm sending the exact same JSON string (without the ID) via Postman as application/json.
When trying to save a new object i'm doing this in the Controller:
public function store(Request $request, Response $response, array $args)
{
$object = new Object($request->getParsedBody());
//dd($request->getParsedBody());
$object->save(); // nothing happens, just an empty entry
}
The Object Class
class Object extends \Comp\Models\Mapper
{
protected $database;
protected $hidden = array('created_by', 'checked_out', 'checked_out_time', 'modified_by', 'access', 'params', 'oid', 'video');
protected $casts = [
'published' => 'boolean',
'featured' => 'boolean',
'rating' => 'float',
];
protected $dates = ['created','modified'];
public $timestamps = false;
/*protected $fillable = [
'shop_id','vendor_id','name','address','pincode','phone','shop_type'
];*/
public function __construct( $database)
{
$this->setTable('objects');
$this->database = $database;
}
}
The "Mapper" Class
<?php
namespace Comp\Models;
use Interop\Container\ContainerInterface;
use Illuminate\Database\Eloquent\Model;
abstract class Mapper extends Model {
protected $db;
public function __construct(ContainerInterface $container) {
}
public function removeEmptyElements(array $array)
{
}
}
I don't know if and how to do a transformation again, to map the structure for the Eloquent ORM.
Update 1:
I just spotted this:
https://github.com/tuupola/slim-todo-backend/blob/master/app.php
So do i need something like Spot and Fractal together? I wanted to have a central Transformer and not multiple places for output and input. And also i use Eloquent and cant use another ORM...
Update 2:
Added Object Model and Mapper Class
Any ideas are very appreciated.
We can insert it very easily.I did this .I use slim 3.0 frame work and laravel Eloquent
Here i explain detailed structure of my project
First you need to install Eloquent data base driver and create models
<?php
require 'vendor/autoload.php';
include 'dbboot.php';
use User\Models\User;
$app = new \Slim\App([
'settings' => [
'displayErrorDetails' => true,
'debug' => true,
'whoops.editor' => 'sublime',
]
]);
$app->get('/user', function ($request, $response, $args) {
$_user = new User();
$users = $_user->all();
$payload = [];
$payload['user']=$users;
return $response->withStatus(200)->withJson($payload);
});
$app->post('/user', function($request,$response,$args) {
$_user = new User();
$user = $request->getParsedBodyParam('userinfo', '');
$user_id=$_user :: insertGetId($user);
$payload = [];
$payload['user_id']=$user_id;
$payload['message']="Insertion success";
return $response->withStatus(200)->withJson($payload);
});
// Run app
$app->run();
For source code please clone my Github repository:
https://github.com/sherinmac/slim3-with-eloquent.git

Only User Model is saving with empty Values to database

In Laravel 5.4 when I try to save User model to the database the values are not saved. I've set the fillable property as well.
It was working in Laravel 5.3. This issue is coming after upgrading the application into Laravel 5.4.
Below is a User model.
class User extends BaseModel implements AuthenticatableContract, CanResetPasswordContract, JWTSubject
{
use SoftDeletes,
UserAccess,
UserAttribute,
UserRelationship,
Authenticatable,
CanResetPassword,
Notifiable;
/**
* Database Table
*
* #var string
*/
protected $table = "users";
/**
* The attributes that are not mass assignable.
*
* #var array
*/
protected $guarded = ['id'];
/**
* Fillable Form Fields
*
* #var array
*/
protected $fillable = [
'name',
'first_name',
'last_name',
'email',
'password',
'status',
'confirmed',
'api_user',
'confirmation_code',
'account_id',
'role_id',
'cw_contact_id',
'all',
'all_locations',
'username',
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = ['password', 'remember_token'];
/**
* Select HTML Preference
*
* #var string
*/
protected static $selectHTMLFormat = "[email]";
/**
* #var array
*/
protected $dates = ['deleted_at', 'last_login'];
}
Please note the issue is with User Model only.
I'm saving User as below.
// Create User
$user = $this->model->create([
'first_name' => $input['first_name'],
'last_name' => $input['last_name'],
'username' => $input['username'],
'email' => $input['email'],
'password' => bcrypt($input['password']),
'confirmation_code' => md5(uniqid(mt_rand(), true)),
'confirmed' => 1,
'api_user' => (isset($input['api_user']) ? $input['api_user'] : 0),
'account_id' => $input['account_id'],
'role_id' => (isset($input['role_id']) ? $input['role_id'] : 0),
'all' => (!isset($input['associated-permissions']) || $input['associated-permissions'] == 'all') ? 1 : 0,
'status' => (!isset($input['status']) || $input['status'] ? 1 : 0),
'all_locations' => $input['all_locations']
]);
Then the create method of BaseModel will be called and below is the code of it.
public static function create(array $attributes = Array())
{
$user = access()->user();
if($user)
{
$attributes['account_id'] = (!isset($attributes['account_id']) ? $user->account->id : $attributes['account_id'] );
}
$childClass = get_called_class();
$model = new $childClass;
$model->runActionLogger(false, 'create');
return parent::query()->create($attributes);
}
The reason is most probably the new middleware in Laravel 5.4 called "Request Sanitization Middleware" as explained in https://laravel.com/docs/5.4/releases.
Disable \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class, in app/Http/kernel.php and see what you get.
You can also check in /config/database.php and your mysql connection settings: 'strict' => true, if so, set to false.
A good practice is using the model for user input. In this case, instead of $user = $this->model->create(...) populate you model with
$user = new \App\User($input) and update your values from there, f.ex.
$user->confirmation_code = md5(uniqid(mt_rand(), true)); and
$user->password = bcrypt($user->password);
If fields are nullable, indicate as such in your migration file, f.ex. $table->string('all')->nullable();
If done just run $user->save();
From 5.4 the create() function is not more defined in Illuminate\Database\Eloquent\Model:
Is handled as dinamic method call, that is by calling one of these functions (dependig on if it's called statically or not):
public static function __callStatic($method, $parameters)
// or
public function __call($method, $parameters)
In the Illuminate\Database\Eloquent\Model class.
Now I dont have all your code but, IMHO, I will try to change this line in your BaseModel class:
return parent::query()->create($attributes);
to this:
return $model->create($attributes);
or, even better for me, to this:
return (new static)->newQuery()->create($attributes);
In the
documentation
it says:
$post = App\Post::find(1);
$comment = $post->comments()->create([
'message' => 'A new comment.',
]);
So
$user = $this->users()->create([
'first_name' => $input['first_name'],
'last_name' => $input['last_name'],
'username' => $input['username'],
'email' => $input['email'],
'password' => bcrypt($input['password']),
'confirmation_code' => md5(uniqid(mt_rand(), true)),
'confirmed' => 1,
'api_user' => (isset($input['api_user']) ? $input['api_user'] : 0),
'account_id' => $input['account_id'],
'role_id' => (isset($input['role_id']) ? $input['role_id'] : 0),
'all' => (!isset($input['associated-permissions']) || $input['associated-permissions'] == 'all') ? 1 : 0,
'status' => (!isset($input['status']) || $input['status'] ? 1 : 0),
'all_locations' => $input['all_locations']
]);
where users() is your public function but I don't know what is $this in your case but should be the model as in the example from documentation.
Why you're not using resource controllers? Or if you need to populate the db use a seeder
I think It will be more easy to manage.
So 2 things i can think off
1st there is no need to use
protected $guarded = [];
and
protected $fillable = [];
Guarded will assume everything is fillable if its not in here and fillable will assume everything is guarded unless in here.
To quote the docs
While $fillable serves as a "white list" of attributes that should be mass assignable, you may also choose to use $guarded. The $guarded property should contain an array of attributes that you do not want to be mass assignable. All other attributes not in the array will be mass assignable. So, $guarded functions like a "black list". Of course, you should use either $fillable or $guarded - not both.
2nd to rule out any of the $this->model stuff try instantiate the class first and save them
use App\Path\To\Model as user;
$user = new user();
$user->first_name = $input['first_name'];
$user->last_name = $input['last_name'];
$user->username = $input['username'];
$user->email = $input['email'];
$user->password = bcrypt($input['password']);
$user->confirmation_code = md5(uniqid(mt_rand(); true));
$user->confirmed = 1;
$user->api_user = (isset($input['api_user']) ? $input['api_user'] : 0);
$user->account_id = $input['account_id'];
$user->role_id = (isset($input['role_id']) ? $input['role_id'] : 0);
$user->all = (!isset($input['associated-permissions']) || $input['associated-permissions'] == 'all') ? 1 : 0;
$user->status = (!isset($input['status']) || $input['status'] ? 1 : 0);
$user->all_locations = $input['all_locations'];
$user->save();
Guys I'm able to resolve issue by using Fill() method.
public static function create(array $attributes = Array())
{
$user = access()->user();
if($user)
{
$attributes['account_id'] = (!isset($attributes['account_id']) ? $user->account->id : $attributes['account_id'] );
}
$childClass = get_called_class();
$model = new $childClass;
$model->fill($attributes);
$model->save();
$model->runActionLogger($model, 'create');
return $model;
}
Also By mistake I've added Construction on CanResetPassword Trait which causing issue as well. So If i remove that everything will work as before as well.
Yes, you can't use __construct method in Traits.
Please Refer PHP.net for more details about trait, they said "Using AS on a __construct method (and maybe other magic methods) is really, really bad."
You can use trait like following way.
class User extends BaseModel
{
use userRelation
}
Trait userRelation
{
public function getUserName()
{
return "Jhon Doe";
}
}
I have created "userRelation" Trait which contains few useful code to re-use.
Please refer following link for more details - http://php.net/manual/en/language.oop5.traits.php
Please try it and let me know if it won't work.
Thanks

Laravel 3 - Eloquent query returns rules

I'm trying to send use models for the first time and running into a confusion. When I run a query, the rules are linked with it, is it supposed to be like that?
Model:
class User extends Elegant
{
public static $table = 'users';
protected $rules = array(
'email' => 'required|email',
'firstname' => 'required',
'lastname' => 'required',
'initials' => 'required|alpha|match:/[A-Z]+/',
'role' => 'required|in:writer_fr,writer_en,reader',
'password' => 'min:6,max:32|same:password2'
);
public static function has_role($role)
{
//$u = new User;
$users = User::where($role, '=', 1)->get(array('firstname', 'lastname'));
return $users;
}
}
Controller
$u = array();
$u['writer_en'] = User::has_role('writer_en');
dd($u['writer_en']);
Which prints out the entire model rules, messages, relationship etc logic. Am I doing something wrong or is this normal?
In your has_role method you are returning User model
public static function has_role($role)
{
//$u = new User;
$users = User::where($role, '=', 1)->get(array('firstname', 'lastname'));
return $users; // <-- User model
}
So, it's dumping the User model and it's doing the right thing as it suppose to do by following code
$u = array();
$u['writer_en'] = User::has_role('writer_en');
dd($u['writer_en']);
Instead of dumping the model, you can use
$user = User::has_role('writer_en');
echo $user->firstname;
echo $user->lastname;

Categories