default() is not working in laravel migration - php

I am creating a to do list using laravel, and I have a table with the columns below:
'title', 'description', 'completed', 'id'
The 'completed' column is set automatically whenever I add a new task to my table, its default value is 0 and it's being coded like this:
$table->boolean('completed')->default(0);
This column works perfectly fine, but when I try to give 'description' a default value (by leaving an empty input for description), it gives me a 'Integrity constraint violation: 1048 Column 'description' cannot be null' error.
The code I have written for 'description' column is the code below:
$table->string('description')->default('-');
I tried the text() data type, but it gives me the same error.
I also tried using nullable() for this column, but the default value, '-' , doesn't get added to the column and it returns a emtpy value.
The form I'm using to add the values looks like this:
<form action="/create" class="panel" method="post">
#csrf
<input name="title" type="text" class="title">
<textarea name="description" class="title"></textarea>
<input type="submit" class="submit">
</form>
My controller store method:
public function createTask(validation $request){
$userId = auth()->id();
$request['user_id'] = $userId;
Task::create($request->all());
return redirect()->route('showList');
}
and the table create statement:
CREATE TABLE `tasks` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`title` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
`completed` tinyint(1) NOT NULL DEFAULT 0,
`user_id` bigint(20) unsigned NOT NULL,
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL,
`description` text COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT ' ',
PRIMARY KEY (`id`),
KEY `tasks_user_id_foreign` (`user_id`),
CONSTRAINT `tasks_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci

After seeing the create table statement and your store function. It looks like it is more likely that your store function is the problem here. Try this:
use Illuminate\Support\Facades\Auth;
public function createTask(Request $request){
$user = Auth::user();//get the user model
$request->validate([//validate that the data is according to limitations
'title' => 'required|max:255',
'description' => 'max:1000',
]);
$task = new Task; //create a new instance of Task
//fill in the data
$task->title = $request->input('title');
if(!empty($request->input('description')){
$task->description = $request->input('description');
}
$task->user_id = $user->id;
$task->save();//save it
return redirect()->route('showList');
}
In your code you use mass assignment described in detail here
For mass assignment you should define your database fields to be mass assignable in your Model with protected $fillable = ['title','description','user_id'];
Your problem in specific tho is that laravel sets empty inputs to null according to answer in this question: Mass assignment won't handle Null input even when default is set on migration.Any solution to this?
You should always validate the user input and laravel provides robust tools for doing just that: https://laravel.com/docs/7.x/validation
You also might wanna consider using laravels built-in default values or at least check if they are intervening with the data :How to set the default value of an attribute on a Laravel model

Related

Yii2 rbac Role assignment is throwing error on signup

I am trying to assign a role named 'admin' (already present in auth_item table in database) during signup in yii2. signup() is present inside SignupForm model in common models.
$auth = Yii::$app->authManager;
$authorRole = $auth->getRole('admin');
$auth->assign($authorRole, $user->getId());
but it is throwing an error at vendor\yiisoft\yii2\rbac\DbManager.php as Trying to get property 'name' of non-object .
public function assign($role, $userId)
{
$assignment = new Assignment([
'userId' => $userId,
'roleName' => $role->name,
'createdAt' => time(),
]);
.....
}
this is the function where the error is getting triggered
Implementing a role based access control is a very easy process and you can even load your roles from the database if you want.
Step1: Creating necessary tables in the database [ You can also apply
migrations with console command yii migrate instead of step 1 ]
The first step is to create necessary tables in the database.Below is the sql you need to run in the database.
drop table if exists `auth_assignment`;
drop table if exists `auth_item_child`;
drop table if exists `auth_item`;
drop table if exists `auth_rule`;
create table `auth_rule`
(
`name` varchar(64) not null,
`data` text,
`created_at` integer,
`updated_at` integer,
primary key (`name`)
) engine InnoDB;
create table `auth_item`
(
`name` varchar(64) not null,
`type` integer not null,
`description` text,
`rule_name` varchar(64),
`data` text,
`created_at` integer,
`updated_at` integer,
primary key (`name`),
foreign key (`rule_name`) references `auth_rule` (`name`) on delete set null on update cascade,
key `type` (`type`)
) engine InnoDB;
create table `auth_item_child`
(
`parent` varchar(64) not null,
`child` varchar(64) not null,
primary key (`parent`, `child`),
foreign key (`parent`) references `auth_item` (`name`) on delete cascade on update cascade,
foreign key (`child`) references `auth_item` (`name`) on delete cascade on update cascade
) engine InnoDB;
create table `auth_assignment`
(
`item_name` varchar(64) not null,
`user_id` varchar(64) not null,
`created_at` integer,
primary key (`item_name`, `user_id`),
foreign key (`item_name`) references `auth_item` (`name`) on delete cascade on update cascade
) engine InnoDB;
Step2: Setting up the config file
Now you can set up the config file to use the authmanager as DbManager. This is done by adding the following lines to the components section of your config file
'authManager' => [
'class' => 'yii\rbac\DbManager',
'defaultRoles' => ['guest'],
],
Step3: Adding and assigning roles.
Now you can add roles by simply writing the following code to your corresponding controller.
use yii\rbac\DbManager;
$r=new DbManager;
$r->init();
$test = $r->createRole('test');
$r->add($test);
And you can assign it to the users by
$r->assign($test, 2);
http://www.yiiframework.com/doc-2.0/guide-security-authorization.html
Same answer has been provided here: Yii2 role management with rbac and database storage
I faced the same problem, the reason is because getRole() method returns null as you can see in your app.log file yii\rbac\DbManager->assign(NULL, 1222049)
SOLUTION
Use $auth->getPermission('admin') instead of $auth->getRole('admin')

laravel-tagging creates double entries in database

I am trying to set up laravel-tagging system and get it to store tags in the database. However, it creates double entries every time I submit an article with tags:
id taggable_id taggable_type tag_name tag_slug
'72', '128',
'73', '72', 'App\Article', 'Newtag1', 'newtag1'
The first entry (id=72) has a correct taggable_id and the second entry (id=73) is created automatically by laravel-tagging and automatically sets another taggable_id to 72, which has been counting up since zero and behaves like an auto-increment. But it has no auto-increment setting in the database schema.
Here is how I set it up:
1) I create a new model instance:
$article = new Article;
2) Then I assign a taggable_id, which is the id of a post that is created with the tag:
$article->taggable_id = $postid;
3) I save the $article into the database:
$article->save();
4) I find the saved row in the database by the taggable_id and put it into a fresh $article:
$article = Article::where('taggable_id', $postid)->first();
5) I run laravel-tagging's tag method to get the tag into the database:
$article->tag($request->taggone);
6) I save the row again
$article->save();
And this gives me the double entry shown in the beginning. Why is that happening? What am I doing wrong? I just want it to use the original entry to store those tags, not create a new one.
EDIT: I tried skipping step 4, the outcome is the same.
EDIT2 My Article model looks like this:
namespace App;
use Conner\Tagging\Taggable;
use Illuminate\Database\Eloquent\Model;
class Article extends Model
{
use Taggable;
protected $table = 'tagging_tagged';
public $timestamps = false;
}
It looks like the issue is because you set the $table property on your Article model to the tags table when it should remain the articles table.
The general idea of this is everything stays the same for the most part with laravel-tagging. The only difference is if you want a certain model, such as Article to support tagging, all you'd need to do is add the use Conner\Tagging\Taggable; statement to your model.
Then you create articles just like you always would. For example
$article = new Article();
$article->title 'Test Article';
$article->body = 'Some article body';
$article->save(); // Should save it first before trying to tag
Then if you wanted to add a tag to the article
$article->tag('Gardening'); // This will tag this article
You shouldn't need to worry about setting any of the columns on the tagging_tagged table, the extension will handle that for you when you use tag().
I suggest you to make laravel-tagging with this method:
First create News model
class News extends Model {
public function tags()
{
return $this->hasMany('App\Tag', 'news');
}
}
Then create Tag model
class Tag extends Model {
public function getNews()
{
return $this->belongsTo('App\News', 'news');
}
}
Afterwards you should create a controller to insert the news with tags.
public function postCreate(Request $request)
{
//here you will insert your own datas
$news = new News();
$news -> description = $request->description;
$news -> title = $request->title;
$news -> save();
foreach ($request->tags as $t)
{
$tags = new Tag();
$tags->tag = $t;
$tags->lang = $request->lang;
$news->tags()->save($tags);
}
}
This is your html
<form>
<input type="text" name="title"> <br>
<input type="text" name="description"> <br>
<input type="text" name="tags[]">
<input type="submit">
</form>
And this is your sql data
CREATE TABLE IF NOT EXISTS `news` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`title` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`description` text COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`),
KEY `title` (`title`),
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE IF NOT EXISTS `tags` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`tag` varchar(255) NOT NULL DEFAULT '0',
`news` int(11) NOT NULL DEFAULT '0',
`lang` tinyint(1) NOT NULL DEFAULT '1',
PRIMARY KEY (`id`),
KEY `tag` (`tag`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

Laravel 5 firstOrCreate keep create even set unique to the field

Below is my app\Cart.php
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Cart extends Model {
use SoftDeletes;
protected $table = 'cart';
protected $fillable = ['sess','uid'];
}
Below is my app\Http\Controllers\CartController.php
public function cart($id=0, $act, Request $request)
{
$sessId = Session::getId();
switch($act){
case 'Add':
$quantity = $request->only('p_quantity');
$data = $request->except('p_quantity');
$cartId = Cart::firstOrCreate(['sess' => $sessId,'status' => 1]);
break;
case 'Delete':
break;
}
return response()->json(['success' => true,'message' => 'Success', 'act' => $act, 'id' => $id ,'data' => $data, 'quantity'=> $quantity, 'cart'=>$cartId->id]);
}
What i want is check database if the session key exist in table cart.sess, else create new one and get the id.
Question is , when it keep create new duplicate session to database.
may i know where i did wrong?
Thanks
UPDATE [2015-05-27 16:02]:
After i TRUNCATE table and set the sess field to Unique , first submit it look ok, when second submit it show error below:
UPDATE [2015-05-27 16:16]
Code that i use to create database:
CREATE TABLE IF NOT EXISTS `cart` (
`id` int(11) NOT NULL,
`uid` int(11) DEFAULT NULL,
`sess` varchar(40) NOT NULL,
`status` int(11) DEFAULT '1',
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`deleted_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00'
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
In your database schema, where you created this cart table, the sess column should be unique, but it is not. You should alter it, to be unique:
$table->unique('sess');
Don't forget to delete all records before that, otherwise you will get an error.
EDIT After you posted your table schema I found the problem
sess varchar(40) NOT NULL
You must set the length of sess to at elast 255 characters or the size of your session id, because your session id is longer than 40 symbols. Laravel tries to find a string with 64 characters (or with the length of your session id) for example:
8a9f119eaea027def7268d12e4e4d680
but did not, so it tries to insert new one. Since your column is with length 40, the sess id got truncated to 40 symbols:
8a9f119eaea
and in the next check it would not match, because it is searching for 8a9f119eaea027def7268d12e4e4d680 but in your database you got 8a9f119eaea.
I Solved the problem.
Where
Because in my modal i using SoftDeletes;
How To Solved
it cant has default value inside this field,
but i set it to Default 0000-00-00 00:00:00 , just put it as null by default.
CREATE TABLE IF NOT EXISTS `cart` (
`id` int(11) NOT NULL,
`uid` int(11) DEFAULT NULL,
`sess` varchar(40) NOT NULL,
`status` int(11) DEFAULT '1',
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
deleted_at timestamp NOT NULL DEFAULT '0000-00-00 00:00:00'
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
to
deleted_at timestamp
Why
firstOrCreate did this query (Check Image Below)
Plugin Above is : https://github.com/barryvdh/laravel-debugbar for who need it.
Thanks

Creating a lookup field in a CakePHP form

I have a view created using Bake that has the following:
<fieldset>
<legend><?php echo __('Edit Device'); ?></legend>
<?php
echo $this->Form->input('DeviceID');
echo $this->Form->input('DeviceTypeID');
echo $this->Form->input('UserID');
echo $this->Form->input('Type');
echo $this->Form->input('KeyPadID');
echo $this->Form->input('Version');
echo $this->Form->input('Description');
echo $this->Form->input('UpdateID');
?>
</fieldset>
Which saves to the table:
CREATE TABLE `device` (
`DeviceID` VARCHAR(255) NOT NULL ,
`DeviceTypeID` INT(11) NOT NULL ,
`UserID` INT(10) NOT NULL ,
`Type` VARCHAR(10) NULL DEFAULT NULL ,
`KeyPadID` INT(10) NULL DEFAULT NULL ,
`Version` VARCHAR(255) NULL DEFAULT NULL ,
`Description` TINYBLOB NULL ,
`UpdateID` INT(11) NULL DEFAULT NULL ,
PRIMARY KEY (`DeviceID`),
INDEX `FK_USER` (`UserID`),
INDEX `FK_devices_updates` (`UpdateID`),
INDEX `FK_device_devicetype` (`DeviceTypeID`),
CONSTRAINT `FK_device_devicetype` FOREIGN KEY (`DeviceTypeID`) REFERENCES `devicetype` (`DeviceTypeID`),
CONSTRAINT `FK_devices_updates` FOREIGN KEY (`UpdateID`) REFERENCES `update` (`ID`) ON UPDATE CASCADE ON DELETE CASCADE,
CONSTRAINT `FK_USER` FOREIGN KEY (`UserID`) REFERENCES `user` (`UserID`) ON UPDATE CASCADE ON DELETE CASCADE
)
My problem is that when the form is displayed, it shows DeviceTypeID and UserID as well as UpdateID as the foreign key value instead of a drop down with the caption being the text and the value being the ID column. How would I go about setting a field from the foreign table to be the display field and the id as being the value?
Update 11-02-2013
First of all I strongly suggest to convert your primary and foreign keys accordingly
so that they meet the CakePHP naming conventions.
This means that:
DeviceID should be id.
DeviceTypeID should be device_type_id
UserID should be user_id
Also all primary keys in your tables should be named as id.
This way you will never have to worry about anything, concerning your models etc.
After that, all your tables must be in plural form. This means that device table should be devices, so you should rename it also.
I assume that you also have the following tables: devices_types and users.
At this point, I should notice that I would prefer to have a table named devicetype. I avoid underscored names, because it's very easy to make mistakes using the correct form for each object, class etc. So I don't have to worry whether I should use the CamelCase or not.
Anyway
Your Device model should be something like that:
<?php
/** Device.php **/
class Device extends AppModel {
public $name = 'Device';
public $belongsTo = array(
'DeviceType' => array(
'className' => 'DeviceType',
'foreignKey' => 'device_type_id'
/** Specify other keys that meet your needs **/
),
'User' => array(
'className' => 'User',
'foreignKey' => 'user_id'
)
);
};
?>
Also your DeviceType model should be similar to
<?php
/** DeviceType.php **/
class DeviceType extends AppModel {
public $name = 'DeviceType';
};
In your edit() method, you should query your DeviceType in something like this:
...
$devicetypes = $this->Device->DeviceType->find('list', array('id', 'caption'));
$this->set(compact('devicetypes'));
...
This way in your view the respective form element sets the <select> menu correctly.
PS: You should follow the CakePHP conventions about model-naming etc... Mine was just an example.

Complex reference maps in Zend_Db_Table to account for multi-column keys

I am going to attempt to keep this as simple as possible, but the use case is outside the original intention of Zend_Db I fear. It concerns a set of tables I have for tagging pages (or anything else eg. documents) in a CMS.
I have three tables:
Pages (pages)
Tags (tags)
TagLink (tags_link) which is a many-to-many linking table between Pages and Tags
Pages is a simple table (I have removed the inconsequential columns from the code below):
CREATE TABLE `pages` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
FULLTEXT KEY `search` (`name`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
Tags is quite simple as well although there is a self-referential column (parent_tag_id):
CREATE TABLE `tags` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`tag` varchar(255) NOT NULL,
`parent_tag_id` int(11) NOT NULL DEFAULT '0',
`updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `GetByParentTagId` (`parent_tag_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
TagLink is again fairly simple:
CREATE TABLE `tags_link` (
`tag_id` int(11) NOT NULL,
`module_type` varchar(50) NOT NULL,
`foreign_key` int(11) NOT NULL,
UNIQUE KEY `Unique` (`tag_id`,`module_type`,`foreign_key`),
KEY `Search` (`module_type`,`foreign_key`),
KEY `AllByTagId` (`tag_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
The complicating factor is that TagLink is able to link against any other table in the database and not just Pages. So if for example I had a documents upload section then that could also be tagged. To facilitate this way of working there is effectively a multi-column key.
To make this clearer I will demonstrate a couple of insert queries that might be run when tags are added to a table (eg. Pages):
INSERT INTO `tags_link`
SET `tag_id` = '1',
`module_type` = 'Pages',
`foreign_key` = '2'
INSERT INTO `tags_link`
SET `tag_id` = '1',
`module_type` = 'Documents',
`foreign_key` = '3'
So as you can see the module_type column is simply an arbitrary string that describes where the foreign key can be found. This is not the name of the table however as anything with an ID can have tags linked to it even if it is not necessarily in the MySQL database.
Now to the Zend_Db_Table $_referenceMap in PageTable:
protected $_referenceMap = array(
'TagLink' => array(
'columns' => 'id',
'refTableClass' => 'Models_Tag_TagLinkTable',
'refColumns' => 'foreign_key'
),
);
But this does not take into account my arbitrary module_type column and will return any TagLink with the same foreign key. Obviously this is bad because you get TagLinks for documents mixed in with those for pages for instance.
So my question is how can I take into account this additional column when setting up this reference? The aim is to avoid having a TagLink class for each module_type as I have now.
I would imagine something like the following could explain my requirements although obviously this is not how it would be done:
protected $_referenceMap = array(
'TagLink' => array(
'columns' => 'id',
'refTableClass' => 'Models_Tag_TagLinkTable',
'refColumns' => 'foreign_key',
'where' => 'module_type = "Pages"'
),
);
My current implementation overrides the _fetch method in the Documents_TagLinkTable in the following way:
protected function _fetch(Zend_Db_Table_Select $select) {
$select->where("module_type = 'Documents_Secondary_Tags' OR module_type = 'Documents_Primary_Tags' OR module_type = 'Documents'");
return parent::_fetch($select);
}
As you can see there maybe more than one set of tags added to any object as well.
Example 3 in "Fetching Dependent Rowsets" in the Zend Framework reference demonstrates a technique you could use:
http://framework.zend.com/manual/en/zend.db.table.relationships.html
Whilst it doesnt show a "where" clause being included in the select, it should work.
Duncan

Categories