Laravel - Model::create() works, but is missing attributes - php

So, I have the following Models:
class Recursive extends Model {
public function __construct() {
parent::__construct();
}
// ...
}
class Place extends Recursive {
protected $table = 'places';
protected $fillable = ['name', 'parent_id'];
// ...
}
The following code is used to create a new Place:
$place = Place::create([
'name' = 'Second',
'parent_id' => 1
]);
This results in the following record in the database:
| Actual | Expected |
---------------------------------------------------------
| id | name | parent_id | id | name | parent_id |
| 1 | 'Top' | NULL | 1 | 'Top' | NULL |
| 2 | NULL | NULL | 2 | 'Second' | 1 |
As you can see, the only value being set is the Auto-incrementing id column. The 2 columns I'm trying to create are in the fillable array, and the model is created, but it's not associated correctly.
Has anyone come across this issue before? I know I can use another method, such as
$place = new Place();
$place->name = 'Second';
$place->parent_id = 1;
$place->save();
But this isn't the only spot I'm using this code, and I'd prefer to not lose functionality like this.
Edit: Enabling the query log shows the following for the create() call:
array (
'query' => 'insert into `places` () values ()',
'bindings' =>
array (
),
'time' => 1.26,
),
Further edit: Enable MySQL log has the same output as above. Following Miken32's suggestion of reverting the extends to Model works as expected:
array (
'query' => 'insert into `places` (`name`, `parent_id`) values (?, ?)',
'bindings' =>
array (
0 => 'Second',
1 => '1'
),
'time' => 1.21,
),

Checking the Illuminate\Database\Eloquent\Model class, the constructor looks like this:
public function __construct(array $attributes = [])
{
$this->bootIfNotBooted();
$this->initializeTraits();
$this->syncOriginal();
$this->fill($attributes);
}
However, you overrode this in your Recursive class:
public function __construct()
{
parent::__construct();
}
The attributes were not being passed to the constructor, so it was not able to successfully build the query. You could remove the constructor since it's not doing anything, or use this instead:
public function __construct(array $attributes = [])
{
parent::__construct($attributes);
}

Related

Codeigniter 4 query builder join display only 1 time from first table

I have done up a query builder using join. I would like to show table 2, 3, 4, 5, 6 and so on based on the user id on table 1. I tried to query the result, it is showing like this :
My Tables
Table users
user_id | username | email
1 | userA | userA#email.com
2 | userB | userB#gmail.com
Table add_game
game_id | user_id | ign | acc_id
1 | 1 | ignA | accA
2 | 1 | ignB | accB
1 | 2 | ignB | accB
3 | 2 | ignD | accD
I will be using foreach loop and I believe it will display out multiple times based on the records in the database. What should I do if I only want to display the information highlighted in the red box (which is from users table) just 1 time and all the records associated with user id in add_game table?
This is my current code :
Controller
public function login()
{
$data = [];
helper(['form']);
$validation = \Config\Services::validation();
$db = db_connect();
$model = new LoginModel($db);
$user = $model->login($this->request->getVar('userlogin'));
$this->setUserSession($user[0]);
echo view('templates/header', $data, $user);
echo view('account/login', $data, $user);
echo view('templates/footer', $data, $user);
}
private function setUserSession($user){
$data = [
'user_id' => $user['user_id'],
'username' => $user['username'],
'email' => $user['email'],
'firstname' => $user['firstname'],
'lastname' => $user['lastname'],
'dob' => $user['dob'],
'country' => $user['country'],
'country_code' => $user['c_code'],
'contact' => $user['contact'],
'game_id' => $user['game_id'],
'ign' => $user['ign'],
'acc_id' => $user['acc_id'],
'isLoggedIn' => true
];
session()->set($data);
return true;
}
Model:
return $this->db->table('users')
->groupStart()
->where('username', $str)
->orWhere('email', $str)
->groupEnd()
->join('add_game', 'add_game.user_id = users.user_id')
->get()
->getResultArray();
I have a few more tables but not yet created for now so I have only joined 1 table for the time being. What am I missing? Or do I have to loop twice? Is there a way that I just need to loop 1 time? Hope someone can help me out here. Thanks in advance guys!
the easiest way to achieve this (display 2 records from add_game table and 1 record from users table) you need to create a foreach loop in your view, and exclude duplicated data from users table to be shown.
controller:
$data['my_data']=$this->Your_model->your_method(); // your query example
$this->load->view('your_view',$data)
view:
<?php $my_id=0;foreach($my_data as $row):?>
<?php if($my_id!=$row->user_id):?>
<div><?=$row->username?></div> <!--data from table user-->
<div><?=$row->created_at?></div> <!--data from table add_game-->
<?php else:?>
<div><?=$row->created_at?></div> <!--only data from table add_game-->
<?php endif;?>
<?php $my_id=$row->user_id;endforeach;?>

Get related item many to many

I have model post and tags. And relationship many-to-many.
Post:
public function getTags()
{
return $this->hasMany(Tag::className(), ['id' => 'tag_id'])
->viaTable('post_tag', ['post_id' => 'id']);
}
Tags:
public function getPosts()
{
return $this->hasMany(Post::className(), ['id' => 'post_id'])
->viaTable('post_tag', ['post_id' => 'id']);
}
And table post-tags:
But when I try tags for post:
$tags = $post->tags;
I get an empty variable;
-------------------------
| Post-tag table: |
-------------------------
| id | post_id | tag_id |
-------------------------
| 8 | 2 | 1 |
-------------------------
Make sure you have the relevant tags saved in the post_tag table against the post you are calling the relation.
Also you have to correct the relation inside the Tags Model, you need to specify the 'tag_id'=>'id' rather than 'post_id'=>'id' when calling viaTable().
public function getPosts()
{
return $this->hasMany(Post::className(), ['id' => 'post_id'])
->viaTable('post_tag',['tag_id'=>'id']);
}
Posts:
public function getTags() {
return $this->hasMany ( Tag::className (), [
'post_id' => 'post_id'
] )
}
Tags:
no need actually;
public function getPosts() {
return $this->hasMany ( Post::className (), [
'post_id' => 'post_id'
] )
}
$tags = $post->tags; will give u an object now!

Having problems getting values from foreach

trying to get id from each person
$person = $request->input('person');
//values for person: Murdock,Wayne
$values = explode(',' , $person);
if(count($values) > 1) {
//count($values) = 2
foreach($values as $val) {
$get_id = Tag::where('name', $val)->get();
foreach($get_id as $get) {
echo "id=".$get->id;
$result= FileTags::with('file')->where('tag_id', $get->id)->get();
}
}
}
when i do echo $get->id just getting id=1, when is supossed to be id=1 and id=2
Murdock -- id:1
Wayne -- id:2
|table filetags|
| id | tag_id | file_id |
| 1 | 1 | 2 |
| 2 | 1 | 3 |
| 3 | 2 | 4 |
| 4 | 3 | 1 |
$result = FileTags::with('file')->where('tag_id', $id->id)->get();
I should get files with id 2,3 and 4
Model TAG
public function fileTag() {
return $this->hasMany('App\FileTags');
}
Model Archive
protected $table = 'files';
public function fileTag() {
return $this->hasMany('App\FileTags');
}
Model FileTags
public function tag() {
return $this->belongsTo('App\Tag' , 'tag_id');
}
public function file() {
return $this->belongsTo('App\Archive', 'file_id');
}
Thanks for the help.
EDIT:
|table tag|
| id | name |
| 1 | Murdock |
| 2 | Wayne |
Result from echo $obt_id;
[{"id":1,"name":"Murdock","description":"Description","type":"0","status":"1","created_at":"2016-07-20 18:01:14","updated_at":"2016-07-20 18:01:14"}][]
from var_dump($obt_id)
array (size=1)
0 =>
object(App\Tag)[267]
protected 'table' => string 'tags' (length=4)
protected 'fillable' =>
array (size=4)
...
protected 'connection' => null
protected 'primaryKey' => string 'id' (length=2)
protected 'keyType' => string 'int' (length=3)
protected 'perPage' => int 15
public 'incrementing' => boolean true
public 'timestamps' => boolean true
protected 'attributes' =>
array (size=7)
...
...
...
C:\wamp64\www\Petro\app\Http\Controllers\CatalogedController.php:53:
object(Illuminate\Database\Eloquent\Collection)[272]
protected 'items' =>
array (size=0)
You could create a Variable, $result; initialize it as an Empty Arrayand then simply push all the Results of evaluating the code: FileTags::with('file')->where('tag_id', $get->id)->get() into that the $result Array. And, in the end, Check if the $result Array is not empty. If it's not, you may simply implode it using comma (Assuming it is a String) and echo your Results...
<?php
$person = $request->input('person');
//values for person: Murdock,Wayne
$values = explode(',' , $person);
$result = array(); // <== INITIALIZE TO AN EMPTY ARRAY...
if(count($values) > 1) { //<== $values NOT values...
//count(values) = 2
foreach($values as trim($val)) { //<== TRY TRIMMING OFF WHITE SPACES.
$get_id = Tag::where('name', $val)->get();
foreach($get_id as $get) {
echo "id=".$get->id;
// PUSH THE DATA INTO THE ARRAY...
$result[] = FileTags::with('file')->where('tag_id', $get->id)->get();
}
}
}
// CHECK IF $result IS NOT EMPTY
if(!empty($result)){
// CONVERT THE ARRAY TO A STRING (ASSUMING ITS CONTENT ARE NOT OBJECTS OR ARRAYS)
$result = implode(", ", $result);
// ECHO OUR YOUR RESULT...
echo $result;
}

Laravel: Eager loading with local scope

I have a Coupon model in a Many to Many relation with a Product model (with pivot table and so on...). I created some local scope to get only available coupons, and to get only coupons of determined category:
public function scopeAvailable($query)
{
return $query->where('available', '>', 0);
}
public function scopeOfCategory($query, $category)
{
return $query->join('categories', 'categories.id', '=', 'coupons.category_id')
->where('categories.slug', $category);
}
I want to eager load all available coupons of some category with their respective products. So I'm doing:
$coupons = Coupon::with('products')->available()->ofCategory($category)->paginate(20);
If I call $coupons->first(), I can see the information about the coupon. But if I call $coupons->first()->products I get an empty array.
If I comment the ->ofCategory($category) part, it works as expected.
Here is my Models:
class Coupon extends Model
{
public function products()
{
return $this->belongsToMany('App\Product');
}
...
}
class Product extends Model
{
public function coupons()
{
return $this->belongsToMany('App\Coupon');
}
...
}
I'm using Laravel 5.2. What am I doing wrong?
Edit:
It looks like a problem with my Category. If I try to get coupons on "other" category, I got my coupon as expected. If I try to get coupons on "electronics" category, I got a coupon with no products. I'm pretty sure I have coupons with products both on "electronics" and "other" categories.
If I dump Category::where('slug', '=', 'electronics')->first():
...
protected 'attributes' =>
array (size=3)
'id' => int 1
'name' => string 'Electronics' (length=11)
'slug' => string 'electronics' (length=11)
...
If I dump Category::where('slug', '=', 'other')->first():
...
protected 'attributes' =>
array (size=3)
'id' => int 2
'name' => string 'Other' (length=5)
'slug' => string 'other' (length=5)
...
Edit 2:
I created another coupons with "other" category, so I have two coupons with this category. When I print the coupons, it shows the first coupon twice.
Table coupons:
| id | name | available | category_id |
|----|------------|-----------|-------------|
| 1 | Coupon #1 | 1 | 1 |
| 2 | Coupon #2 | 1 | 1 |
| 3 | Coupon #3 | 1 | 1 |
Table products:
| id | name |
|----|-------------|
| 1 | Product #1 |
| 2 | Product #2 |
| 3 | Product #3 |
Table coupon_product:
| id |product_id| coupon_id |
|----|----------|-----------|
| 1 | 1 | 1 |
| 2 | 2 | 1 |
Table categories:
| id | slug |
|----|-------------|
| 1 | category-1 |
| 2 | category-2 |
| 3 | category-3 |
Product.php:
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
public function coupons()
{
return $this->belongsToMany('App\Coupon');
}
}
Coupon.php:
class Coupon extends Model
{
public function products()
{
return $this->belongsToMany('App\Product');
}
public function scopeAvailable($query)
{
return $query->where('available', '>', 0);
}
public function scopeOfCategory($query, $category)
{
return $query->join('categories', 'categories.id', '=', 'coupons.category_id')
->where('categories.slug', $category);
}
}
And finally when I run:
$coupons = App\Coupon::with('products')->available()->ofCategory('funny')->first();
dd($coupons->products);
I get this:
Which is correct. Can you post more detailed info about your current state of the project?

Sorting and storing array returned by a method as parent and child data for displaying nested/multi level comments in codeigniter 2.0

Hey guys I'm trying to learn codeigniter, but once again I'm STUCK and I seek help (as usual :P )
What I need to do?
-> I need to get the data related to a article from the database along with other stuff like the tags for the article and all the comments. I'm thinking of keeping single level nested comments for the article.
Well I'm done with the tag part [link to the answer which helped me with the same : Returning and using multidimensional array of records from database in CodeIgniter 2.0 ] but the comment part is driving me nuts.
Well to get started here is my comments table
Comments
+---------------+-------------+
| Field | Type |
+---------------+-------------+
| commentId | int(10) |
| PostId | int(10) |
| author | varchar(30) |
| email | varchar(30) |
| url | varchar(50) |
| date | datetime |
| comment | text |
| parent | int(10) |
+---------------+-------------+
I'm using the parent field to keep a track of the parent for a nested child comment. By default the value is 0 which means it the parent. Child comment will have the commentid of its parent comment
public function getPost($postName = NULL , $year = NULL, $month = NULL ){
if($postName != NULL && $year != NULL && $month != NULL){
//single post
$this->load->model('comment_model');
$this->db->where('postName',$postName);
$this->db->where('year(date)',$year);
$this->db->where('month(date)',$month);
$q = $this->db->get('mstack_Post');
if($q->num_rows()>0){
$post = $q->result();
foreach ($post as &$p) {
$p->tags = $this->getAllTags($p->postId);
/* getting the comments */
$com = $this->comment_model->getComments($p->postId);
/*echo count($com).' is the total count'; output= 4 */
foreach ($com as &$c) {
/* trying to filter the comment. but all I get is 1 comment as the output*/
if($c->parent==0){
$p->comments->parentComment = $c;
}elseif($c->commentId==$c->parent){
$p->comments->childComment = $c;
}
}
}
return $post;
}else{
return array();
}
}
}
Any help will surely be appreciated.
If you have any other technique /idea to display multi level comments then do let me know. :)
Here is the solution that might be helpfull:
First you need 2 helper recursive function:
// Building comments.
function buildComments($list, $parent = 0)
{
// Creating result array.
$result = array();
//looping...
foreach ($list as $item)
{
//iteration starts with 0 as default.
if ($item->parent == $parent)
{
// add to the result
$result[$item->commentId] = array(
'author' => $item->author,
// ... other definitions
'child' => buildComments($list, $item->commentId) //execute this function for child.
);
}
}
return $result;
}
function printComments($arg, $depth = 1)
{
foreach ($arg as $item)
{
// Printing comment...
echo str_repeat(' ', $depth) . $item['author'] . "<br />\r\n";
// extra echoes...
// if it has a child comment...
if (count($item['child'] > 0))
{
printComments($item['child'], $depth + 1);
}
}
}
A little explaining:
The buildComments() function will starts with rows that parents has 0. Then it will execute itself for child. if child as a child, it will add it. In the end, result will be like this:
$result = array(
1 => array(
'author' => 'John',
'child' => array(
8 => array(
'author' => 'Jane',
'child' => array(
3 => array(
'author' => 'Jamie',
'child => array()
)
)
),
6 => array(
'author' => 'Jackie',
'child => array()
),
9 => array(
'author' => 'Harry',
'child => array()
)
)
),
4 => array(
'author' => 'Jack',
'child' => array()
),
10 => array(
'author' => 'Clark',
'child' => array(
11 => array(
'author => 'Lois',
'child' => array()
)
)
),
12 => array(
'author' => 'Luthor',
'child' => array()
)
);
In the printComments() function we are printing results recursive. for each child, function repeats itself. You will get result like this:
John
Jane
Jamie
Jackie
Harry
Jack
Clark
Lois
Luthor
For more information about recursive functions Look this answer
USAGE
$this->db->where('postName',$postName);
$this->db->where('year(date)',$year);
$this->db->where('month(date)',$month);
$this->db->order_by('parent', 'asc');
$query = $this->db->get('comments');
$comments = buildComments($query->result());
printComments($comments);
that'is that simple...

Categories