Unexpected doctrine validation error about length when setting the field null - doctrine

I have a field that is defined as follows:
class Subcategory extends BaseSubcategory {}
abstract class BaseSubcategory extends Doctrine_Record
{
public function setTableDefinition()
{
// ...
$this->hasColumn('meta_description', 'string', 255);
// ...
}
// ...
}
Here's what the table looks like:
mysql> DESCRIBE subcategory;
+----------------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------------------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
[...]
| meta_description | varchar(255) | YES | | NULL | |
[...]
+----------------------+------------------+------+-----+---------+----------------+
10 rows in set (0.00 sec)
Here's my code to save a record
$m = new Subcategory;
// ...
$m->meta_description = null;
$m->save();
I'm getting the following validation error
* 1 validator failed on meta_description (length)
Why is this happening?

The code samples above do not tell the whole story. I was being misled by an earlier save, in which the meta_description field was being overloaded with over 255 characters. False alarm!

Related

accessing inverse hasmany in controller laravel

I have three tables topics, category(HowtoCategory::class), sections(Howto::class).
Multiple categories belong to one topic and multiple sections belong to one category.
Topic Has Many Category
Category Has Many Sections
Category Belongs to Topic
Sections Belongs To Category
Topic Has Many Sections Through Category
I want to search through the sections(Howto::class) but display the related topics. How can I access topics in the controller from my query search of sections? I dont want to access it in the view but in the controller.
Controller
public function index(Request $request)
{
if (request()->filled('search')) {
request()->fullUrlWithQuery(['search ' => null]);
$sections = Howto::search($request->search)->get();
$request = $request->input('search');
} else {
$sections = null;
}
return view('howto-pages.howto-main', [
'sections' => $sections,
]);
}
Models
class Topic extends Model
{
public function categories()
{
return $this->hasMany(HowtoCategory::class);
}
public function sections()
{
return $this->hasManyThrough(Howto::class, HowtoCategory::class);
}
}
class HowtoCategory extends Model
{
public function sections()
{
return $this->hasMany(Howto::class);
}
public function topic()
{
return $this->belongsTo(Topic::class);
}
}
class Howto extends Model
{
public function category()
{
return $this->belongsTo(HowtoCategory::class);
}
}
Tables
mysql> desc howto;
+-------------------+-----------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------------+-----------------+------+-----+---------+----------------+
| id | bigint unsigned | NO | PRI | NULL | auto_increment |
| title | varchar(255) | NO | | NULL | |
| body | mediumtext | YES | | NULL | |
| description | mediumtext | YES | | NULL | |
| created_at | timestamp | YES | | NULL | |
| updated_at | timestamp | YES | | NULL | |
| section_id | int | YES | | NULL | |
| howto_category_id | bigint unsigned | YES | MUL | NULL | |
+-------------------+-----------------+------+-----+---------+----------------+
mysql> desc howto_category;
+----------------------+-----------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------------------+-----------------+------+-----+---------+----------------+
| id | bigint unsigned | NO | PRI | NULL | auto_increment |
| howto_category_title | varchar(255) | NO | | NULL | |
| icon | varchar(255) | YES | | NULL | |
| description | mediumtext | YES | | NULL | |
| intro | text | YES | | NULL | |
| category_id | int | YES | | NULL | |
| created_at | timestamp | YES | | NULL | |
| updated_at | timestamp | YES | | NULL | |
| topic_id | bigint unsigned | YES | MUL | NULL | |
+----------------------+-----------------+------+-----+---------+----------------+
mysql> desc topics;
+-------------+-----------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+-----------------+------+-----+---------+----------------+
| id | bigint unsigned | NO | PRI | NULL | auto_increment |
| topic_title | varchar(255) | NO | | NULL | |
| description | mediumtext | YES | | NULL | |
| created_at | timestamp | YES | | NULL | |
| updated_at | timestamp | YES | | NULL | |
+-------------+-----------------+------+-----+---------+----------------+
First and foremost i'd define the foreignIDS in the relations just to make sure that are working as expected.
class Topic extends Model
{
public function categories()
{
return $this->hasMany(HowtoCategory::class);
}
public function sections()
{
return $this->hasManyThrough(
Howto::class, HowtoCategory::class,
"topic_id", "howto_category_id"
);
}
}
then you can get the Topics by searching the sections like so
use Illuminate\Database\Eloquent\Builder;
$topics = Topic::whereHas("sections", function(Builder $query) {
$query->where("howto.description", "something to search")
})->get();

laravel eloquent error , I can not get created_at use groupBy method

I am trying to get max value and create at date with groupBy method.
But when I put the created_at column, I got an error.
$rankings = Ranking
::select(DB::raw('MAX(rankings.percentage_correct_answer) as percentage_correct_answer, rankings.user_id,rankings.created_at'))
->groupBy('rankings.user_id')
->get();
errors:
SQLSTATE[42000]: Syntax error or access violation: 1055 'app.rankings.created_at' isn't in GROUP BY (SQL: select MAX(rankings.percentage_correct_answer) as percentage_correct_answer, rankings.user_id,rankings.created_at from rankings where rankings.deleted_at is null group by rankings.user_id)
However, I did fine by pulling out the created_at column. Why?
And I want to get the created_at column, what should I do?
No error this code.
$rankings = Ranking
::select(DB::raw('MAX(rankings.percentage_correct_answer) as percentage_correct_answer, rankings.user_id'))
->groupBy('rankings.user_id')
->get();
Model code:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Ranking extends Model
{
use SoftDeletes;
protected $table = 'rankings';
protected $fillable = [
'user_id','percentage_correct_answer'
];
}
rankings table description:
+---------------------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------------------+---------------------+------+-----+---------+----------------+
| id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| user_id | bigint(20) unsigned | NO | | NULL | |
| percentage_correct_answer | int(11) | NO | | NULL | |
| created_at | timestamp | YES | | NULL | |
| updated_at | timestamp | YES | | NULL | |
| deleted_at | timestamp | YES | | NULL | |
+---------------------------+---------------------+------+-----+---------+----------------+
Thanks Tharaka!
I tried add database config in config/database.php:
'mysql' => [
....
'strict' => false,
//'strict' => true,
],
Then it works.
I referred to this question.
GroupBy Error in Laravel Eloquent Builder
But I don't really understand the cause of the error.

hasOneThrough with pivot table laravel eloquent

I have the following tables
mysql> describe records;
+-----------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+---------------------+------+-----+---------+----------------+
| id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| event_school_id | bigint(20) unsigned | NO | MUL | NULL | |
| athlete_id | bigint(20) unsigned | NO | MUL | NULL | |
| year | int(10) unsigned | NO | | NULL | |
| place | int(10) unsigned | NO | | NULL | |
| created_at | timestamp | YES | | NULL | |
| updated_at | timestamp | YES | | NULL | |
| deleted_at | timestamp | YES | | NULL | |
+-----------------+---------------------+------+-----+---------+----------------+
8 rows in set (0.01 sec)
mysql> describe event_school;
+------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+---------------------+------+-----+---------+----------------+
| id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| event_id | bigint(20) unsigned | NO | MUL | NULL | |
| school_id | bigint(20) unsigned | NO | MUL | NULL | |
| notes | text | NO | | NULL | |
| created_at | timestamp | YES | | NULL | |
| updated_at | timestamp | YES | | NULL | |
| deleted_at | timestamp | YES | | NULL | |
+------------+---------------------+------+-----+---------+----------------+
7 rows in set (0.00 sec)
mysql> describe events;
+-------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+---------------------+------+-----+---------+----------------+
| id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(191) | NO | | NULL | |
| category_id | bigint(20) unsigned | NO | MUL | NULL | |
| created_at | timestamp | YES | | NULL | |
| updated_at | timestamp | YES | | NULL | |
| deleted_at | timestamp | YES | | NULL | |
+-------------+---------------------+------+-----+---------+----------------+
6 rows in set (0.00 sec)
From my Record Eloquent model, how can I get an event from a record. It needs to go though event_school pivot table; but I don't have a model for EventSchool. Do I need to make one? Is there a way to do that without EventSchool model?
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class EventSchool extends Model
{
use SoftDeletes;
protected $guarded = ['id'];
protected $table = 'event_school';
public function event()
{
return $this->belongsTo('App\Event');
}
public function school()
{
return $this->belongsTo('App\School');
}
}
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Record extends Model
{
use SoftDeletes;
protected $guarded = ['id'];
public function athlete()
{
return $this->belongsTo('App\Athlete');
}
function event_school()
{
return $this->belongsTo('App\EventSchool','event_school_id');
}
function event()
{
//What can I put here to complete method
//right now have to do \App\Record::find(1)->event_school->event
//Want to do \App\Record::find(1)->event
}
}
EDIT:
Here is output from one of the answers
>>> \App\Record::find(3)->event_school->event
=> App\Event {#3035
id: 1,
name: "100 Meter",
category_id: 1,
created_at: null,
updated_at: null,
deleted_at: null,
}
>>> \App\Record::find(3)->event
=> null
Every time I got into this situation I end up creating a model for the pivot table. An additional benefit of doing this, is that you can access directly to that table without bringing the other end of the relationship.
You already have additional information to the foreign keys (notes). If you have a School and need the notes from an Event, but you DON'T need the Event, you can do that if the pivot table has a model.
Of course you could do it with a join without the need of a model.
The key here is to extend from Pivot instead of Model. One of the things it does is to get the table name as singular. But you can't use SoftDeletes (do you really need it? It doesn't makes much sense)
Note: Pivot models may not use the SoftDeletes trait. If you need to soft delete pivot records consider converting your pivot model to an actual Eloquent model.
namespace App;
use Illuminate\Database\Eloquent\Relations\Pivot;
class EventSchool extends Pivot
{
protected $guarded = ['id'];
public function event()
{
return $this->belongsTo(Event::class);
}
public function school()
{
return $this->belongsTo(School::class);
}
}
Now, hasOneThrough is the inverse of what you need. You need something like belongsToThrough, but it doesn't exists. What you could use is an accessor:
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Record extends Model
{
use SoftDeletes;
protected $guarded = ['id'];
public function athlete()
{
return $this->belongsTo(Athlete::class);
}
function eventSchool()
{
return $this->belongsTo(EventSchool::class);
}
function getEventAttribute()
{
return $this->eventSchool->event;
}
}
Doing \App\Record::find(1)->event will do exactly what you expect it to do.
I create a fresh install of laravel on my computer, set up the models and relations according to the information that you provide, and the simplest solution i came up with is this one:
public function event()
{
return $this->hasOneThrough(Event::class, EventSchool::class,
'event_id', 'id', 'id', 'event_id'
);
}
This is the test that i made:
// Within some controller:
$record = Record::find(2);
dd($record->event);
And this is the result, which i think is the result you are looking for:
Event {#303 ▼
#connection: "pgsql"
#table: "events"
#primaryKey: "id"
#keyType: "int"
+incrementing: true
#with: []
#withCount: []
#perPage: 15
+exists: true
+wasRecentlyCreated: false
#attributes: array:6 [▼
"id" => 2
"name" => "Event 2"
"category_id" => 2
"created_at" => "2019-09-16 03:15:07"
"updated_at" => "2019-09-16 03:15:07"
"laravel_through_key" => 2
]
#original: array:6 [▶]
#changes: []
#casts: []
#dates: []
#dateFormat: null
#appends: []
#dispatchesEvents: []
#observables: []
#relations: []
#touches: []
+timestamps: true
#hidden: []
#visible: []
#fillable: []
#guarded: array:1 [▶]
}
Hope it helps.

How to add dependency between attribute validation in Yii CActiveRecord?

I have a model that represents key-value settings by using CActiveRecord.
The database table has the following structure:
| Field | Type |
| key | varchar(255) |
| category | varchar(255) |
| default | varchar(255) |
| is_editable | tinyint(1) |
| is_required | tinyint(1) |
| name | varchar(255) |
| description | text |
| value | varchar(255) |
| create_at | datetime |
| update_at | datetime |
What needs to be done is to have the value parameter required only when the is_required attribute is true.
The is_required attribute is added the first time, when the scenario is create.
The process should proceed with custom validation method I guess.
Here's the solution to the problem:
The rules() method should look something like:
public function rules()
{
return array(
array('key', 'required'),
array('name, is_required, default', 'required', 'on'=>'create'),
array('key, category, default, type, name, value', 'length', 'max'=>255),
array('category, value, name, is_required', 'safe'),
);
}
We can override the isAttributeRequired function so it has in mind the additional check.
public function isAttributeRequired($attribute)
{
if($attribute == 'value' && $this->is_required)
return true;
return parent::isAttributeRequired($attribute);
}

Laravel 4 BelongsToMany sync() method doesn't work properly

I have problem when using sync() method. Please help me out here.
I have three tables as below.
Table: tbl_roles
+----------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------------+------------------+------+-----+---------+----------------+
| id_role | int(10) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(60) | NO | UNI | NULL | |
| description | text | YES | | NULL | |
+----------------+------------------+------+-----+---------+----------------+
Table: tbl_permissions
+----------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------------+------------------+------+-----+---------+----------------+
| id_permission | int(10) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(255) | NO | | NULL | |
| description | text | YES | | NULL | |
+----------------+------------------+------+-----+---------+----------------+
Table: tbl_link_roles_permissions
+---------------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------------+------------------+------+-----+---------+-------+
| id_role | int(10) unsigned | NO | MUL | NULL | |
| id_permission | int(10) unsigned | NO | MUL | NULL | |
+---------------+------------------+------+-----+---------+-------+
I have created many to many relationship between roles and permissions models.
Role model:
class Role extends Eloquent
{
/**
* Permissions
*/
public function permissions()
{
return $this->belongsToMany('Permission', 'tbl_link_roles_permissions', 'id_role', 'id_role');
}
}
Permission model:
class Permission extends Eloquent
{
/**
* Roles
*/
public function roles()
{
return $this->belongsToMany('Role', 'tbl_link_roles_permissions', 'id_permission', 'id_permission');
}
}
When I run the following code to sync roles' permissions. It give me an Integrity constraint violation error.
The Code:
$role = Role::find($id_role);
$permissions = Input::get('role_permissions');
/*
* Permissions array is like array('1','2','3')
* So I convert the value to integer.
*/
$parameters = array();
foreach($permissions as $permission) {
$parameters[] = intval($permission);
}
$role->permissions()->sync($parameters);
According to the error message, I found the SQL query is not correct.
Error meesage:
SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row:
a foreign key constraint fails (`quidz_host_laravel`.`tbl_link_roles_permissions`,
CONSTRAINT `tbl_link_roles_permissions_id_permission_foreign` FOREIGN KEY
(`id_permission`) REFERENCES `tbl_permissions` (`id_permission`)) (SQL: insert into
`tbl_link_roles_permissions` (`id_role`) values (?)) (Bindings: array ( 0 => 1, ))
It only inserts id_role. This is not what I want. Can anyone tell me what I did wrong?
Thanks a lot.
I have solved my problem. It's caused by passing wrong parameters when building the relationships.
The relationship should be like the code below:
class Role extends Eloquent
{
/**
* Permissions
*/
public function permissions()
{
return $this->belongsToMany('Permission', 'tbl_link_roles_permissions', 'id_role', 'id_permission');
}
}
class Permission extends Eloquent
{
/**
* Roles
*/
public function roles()
{
return $this->belongsToMany('Role', 'tbl_link_roles_permissions', 'id_permission', 'id_role');
}
}

Resources