I have a model called Report that has one-many relationship to another model called ReportAttachments.
In my ReportCrudController class, I have a the following field to add or manage attachments.
$this->crud->addField([ // Browse multiple
'name' => 'attachments',
'label' => 'Image Attachments',
'type' => 'browse_multiple',
'multiple' => true, // enable/disable the multiple selection functionality
'mime_types' => ['image'], // visible mime prefixes; ex. ['image'] or ['application/pdf']
'model' => 'App\Models\ReportAttachment',
'attribute' => 'id',
'entity' => 'attachments'
]);
However, I cant seem to make it work as I get this error during edit:
"Property [attachments] does not exist on this collection instance."
Also, when creating a new report, empty insert query is generated for the attachments which throws an exception:
"SQLSTATE[HY000]: General error: 1364 Field 'file' doesn't have a default value (SQL: insert into report_attachments () values ())"
This is the code for Report Model:
class Report extends Model
{
use CrudTrait;
protected $table = 'reports';
protected $fillable = ['name', 'slug', 'description', 'impression'];
protected $casts = [
'attachments' => 'array',
];
public function attachments()
{
return $this->hasMany('App\Models\ReportAttachment');
}
}
Code for Attachment Model
class ReportAttachment extends Model
{
protected $table = 'report_attachments';
protected $primaryKey = 'id';
protected $fillable = ['file', 'title', 'file_type'];
public $timestamps = false;
public function report()
{
return $this->belongsTo('App\Models\Report');
}
}
Am I missing something or doing something wrong here? Thanks in advance!
Update:
added table definition and updated namespace for model ReportAttachment
CREATE TABLE `reports` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL,
`slug` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL,
`description` longtext COLLATE utf8mb4_unicode_ci,
`impression` enum('0','1','2') COLLATE utf8mb4_unicode_ci NOT NULL,
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `reports_name_unique` (`name`),
UNIQUE KEY `reports_slug_unique` (`slug`)
) ENGINE=InnoDB AUTO_INCREMENT=37 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
report_attachments table:
CREATE TABLE `report_attachments` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`title` varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT '',
`file` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL,
`file_type` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL,
`report_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`),
KEY `report_attachments_report_id_foreign` (`report_id`),
CONSTRAINT `report_attachments_report_id_foreign` FOREIGN KEY (`report_id`) REFERENCES `reports` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
I have a category table with parent category Id in the same tables. And add the association to join the same table for classified child category. Below are my table structure, table association code and delete function.But delete not working :(.
Table Structure :-
CREATE TABLE IF NOT EXISTS `category` (
`Cat_Id` int(11) NOT NULL,
`Cat_Code` varchar(255) NOT NULL,
`Cat_Desc` text NOT NULL,
`CreatedBy` varchar(255) NOT NULL,
`ParentId` int(11) NOT NULL DEFAULT '0',
`GstPercentage` double NOT NULL DEFAULT '0',
`CreatedDate` datetime NOT NULL,
`UpdateDate` datetime NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
--
-- Indexes for dumped tables
--
--
-- Indexes for table `category`
--
ALTER TABLE `category`
ADD PRIMARY KEY (`Cat_Id`),
ADD UNIQUE KEY `Cat_id` (`Cat_Id`);
--
-- AUTO_INCREMENT for dumped tables
--
--
-- AUTO_INCREMENT for table `category`
--
ALTER TABLE `category`
MODIFY `Cat_Id` int(11) NOT NULL AUTO_INCREMENT;
Model Association :-
public function initialize(array $config)
{
parent::initialize($config);
$this->table('category');
$this->displayField('Cat_Id');
$this->primaryKey('Cat_Id');
// association for the same table join
$this->belongsToMany('Parents', [
'className' => 'Category',
'joinTable' => 'category',
'foreignKey' => 'Cat_Id',
'targetForeignKey' => 'ParentId',
]);
// used to associate the table with user table (join)
$this->belongsTo('Users', [
'className' => 'Users',
'foreignKey' => 'CreatedBy',
'propertyName' => 'user'
]);
}
Delete Function :-
public function delete($id = null)
{
$this->request->allowMethod(['post', 'delete']);
$category = $this->Category->get(base64_decode($id));
if ($this->Category->delete($category)) {
$this->Flash->success(__('The category has been deleted.'));
} else {
$this->Flash->error(__('The category could not be deleted. Please, try again.'));
}
return $this->redirect(['action' => 'index']);
}
I am using Laravel 5 and have amended the default registrar a bit to use first_name and last_name instead of just name. For some reason though when the user is created the first_name and last_name fields are blank in the database. This is the code I am using:
public function validator(array $data)
{
return Validator::make($data, [
'first_name' => 'required|max:255',
'last_name' => 'required|max:255',
'discount_code' => 'max:255',
'register_email' => 'required|email|confirmed|max:255|unique:users,email',
'register_password' => 'required|confirmed|min:6|max:60'
]);
}
public function create(array $data)
{
return User::create([
'first_name' => $data['first_name'],
'last_name' => $data['last_name'],
'email' => $data['register_email'],
'password' => bcrypt($data['register_password'])
]);
}
In the create method if I do a print_r($data) before User::create is called first_name and last_name are there but when the entry is stored to my users table in the database only the email and password get stored. Here is my table definition also:
CREATE TABLE IF NOT EXISTS `users` (
`id` int(10) unsigned NOT NULL,
`first_name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`last_name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`email` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`password` varchar(60) COLLATE utf8_unicode_ci NOT NULL,
`discount_code` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`remember_token` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00'
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
The first_name and last_name fields need to be mass assignable in the model through the $fillable/$guarded arrays.
I must be missing something important but I can't sort this thing out
I would like to associate many addresses to a person so ... here we go with my settlement:
Is there anyone to help?
CREATE TABLE `testpersons` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(20) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=6 ;
CREATE TABLE `testaddresses` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(20) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=3 ;
CREATE TABLE `testassociate` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`testuser_id` int(11) NOT NULL,
`testgroup_id` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=6 ;
Then I create my objects:
class Testperson extends ActiveRecord\Model {
static $table_name = 'testpersons';
static $has_many = array(
array('testaddress',
'through'=>'test_associate',
'foreign_key'=>'testgroup_id',
'primary_key'=>'testuser_id',
'class_name'=>'Testaddress')
);
}
class Testaddress extends ActiveRecord\Model {
static $table_name = 'addresses';
static $belongs_to = array(
array('testperson',
'through'=>'test_associate',
'foreign_key'=>'testuser_id',
'primary_key'=>'testgroup_id')
);
}
Then trying to get my result:
$person = Testperson::find(2);
echo var_dump ( $person);
Gives that:
object(Testperson)[16]
public 'errors' => null
private 'attributes' (ActiveRecord\Model) =>
array (size=2)
'id' => int 2
'name' => string 'tata' (length=4)
private '__dirty' (ActiveRecord\Model) =>
array (size=0)
empty
private '__readonly' (ActiveRecord\Model) => boolean false
private '__relationships' (ActiveRecord\Model) =>
array (size=0)
empty
private '__new_record' (ActiveRecord\Model) => boolean false
Could someone tell me what's wrong with my association?
Many thx
If all you want to do is associate many Address to one Person, than your db structure is wrong and unnecessarily complex.
What you want is this:
CREATE TABLE `testpeople` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(20) NOT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE `testaddresses` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`testperson_id` int(11) NOT NULL,
`name` varchar(20) NOT NULL,
PRIMARY KEY (`id`)
);
Now your model would be like this:
class Testaddress extends ActiveRecord\Model {
static $belongs_to = array(
array('testperson')
);
}
class Testperson extends ActiveRecord\Model {
static $table_name = 'testpeople';
static $has_many = array(
array('testaddress')
);
}
That should be enough.
However, when you want to use through, you should have also a model for the intermediate table with the respective relationship.
For example sake, I'll use your db structure.
class Testperson extends ActiveRecord\Model {
static $table_name = 'testpeople';
static $has_many = array(
array('testassociate', 'foreign_key' => 'testuser_id'),
array('testaddress', 'through' => 'testassociate', 'foreign_key' => 'testgroup_id')
);
}
class Testassociate extends ActiveRecord\Model {
static $belongs_to = array(
array('testperson', 'foreign_key' => 'testuser_id'),
array('testaddress', 'foreign_key' => 'testgroup_id'),
);
}
class Testaddress extends ActiveRecord\Model {
static $has_one = array(
array('testassociate', 'foreign_key' => 'testgroup_id'),
array('testaddress', 'through' => 'testassociate', 'foreign_key' => 'testuser_id'),
);
}
Regarding the empty __relathionships, it's because that's a cache variable that will be populated when you request some relation, such as $person->testaddresses.
My database:
CREATE TABLE IF NOT EXISTS `ws_accounts` (
`account_id` int(11) NOT NULL AUTO_INCREMENT,
`account_username` varchar(255) DEFAULT NULL COMMENT 'username',
`account_email` varchar(255) DEFAULT NULL COMMENT 'email',
`account_salt` varchar(255) DEFAULT NULL COMMENT 'store salt for use when hashing password',
`account_password` tinytext COMMENT 'password',
`account_display_name` varchar(255) DEFAULT NULL COMMENT 'name for display on web to prevent show username.',
`account_firstname` varchar(255) DEFAULT NULL COMMENT 'first name',
`account_middlename` varchar(255) DEFAULT NULL COMMENT 'middle name',
`account_lastname` varchar(255) DEFAULT NULL COMMENT 'last name',
`account_birthdate` date DEFAULT NULL COMMENT 'birthdate store in date format (YYYY-mm-dd)',
`account_avatar` varchar(255) DEFAULT NULL COMMENT 'avatar file. refer from root web without http or domain',
`account_signature` text COMMENT 'signature. very useful in forum',
`account_timezone` varchar(30) NOT NULL DEFAULT 'Asia/Bangkok' COMMENT 'see timezone list here http://www.php.net/manual/en/timezones.php',
`account_language` varchar(10) DEFAULT NULL COMMENT 'framework language shortcode eg: en, th',
`account_create` bigint(20) DEFAULT NULL COMMENT 'timestamp of account create date',
`account_create_gmt` bigint(20) DEFAULT NULL COMMENT 'timestamp of account create date in gmt0',
`account_last_login` bigint(20) DEFAULT NULL COMMENT 'timestamp of last login date',
`account_last_login_gmt` bigint(20) DEFAULT NULL COMMENT 'timestamp of last login date in gmt0',
`account_status` int(1) NOT NULL DEFAULT '0' COMMENT '0=disable, 1=enable',
`account_status_text` varchar(255) DEFAULT NULL COMMENT 'status text for describe why disable.',
`account_new_email` varchar(255) DEFAULT NULL COMMENT 'store new email waiting for confirmation',
`account_new_password` varchar(255) DEFAULT NULL COMMENT 'store new password in reset password progress',
`account_confirm_code` varchar(255) DEFAULT NULL COMMENT 'confirmation code. use for confirm register, change email, reset password',
`account_confirm_code_since` bigint(20) DEFAULT NULL COMMENT 'confirm code generated since',
PRIMARY KEY (`account_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='contain user account' AUTO_INCREMENT=2 ;
--
-- Dumping data for table `ws_accounts`
--
INSERT INTO `ws_accounts` (`account_id`, `account_username`, `account_email`, `account_salt`, `account_password`, `account_display_name`, `account_firstname`, `account_middlename`, `account_lastname`, `account_birthdate`, `account_avatar`, `account_signature`, `account_timezone`, `account_language`, `account_create`, `account_create_gmt`, `account_last_login`, `account_last_login_gmt`, `account_status`, `account_status_text`, `account_new_email`, `account_new_password`, `account_confirm_code`, `account_confirm_code_since`) VALUES
(0, 'Guest', 'none#localhost', NULL, NULL, 'Guest', NULL, NULL, NULL, NULL, NULL, NULL, 'Asia/Bangkok', NULL, 1387121127, 1387095927, NULL, NULL, 0, 'This account is for guest actions.', NULL, NULL, NULL, NULL),
(1, 'admin', 'admin#localhost.com', NULL, '$P$FPnwJAQzX498tYCbbIfYTbdYiOCShE0', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Asia/Bangkok', NULL, 1387121127, 1387095927, NULL, NULL, 1, NULL, NULL, NULL, NULL, NULL);
CREATE TABLE IF NOT EXISTS `ws_account_level` (
`level_id` int(11) NOT NULL AUTO_INCREMENT,
`level_group_id` int(11) NOT NULL,
`account_id` int(11) NOT NULL,
PRIMARY KEY (`level_id`),
KEY `level_group_id` (`level_group_id`),
KEY `account_id` (`account_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
CREATE TABLE IF NOT EXISTS `ws_account_level_group` (
`level_group_id` int(11) NOT NULL AUTO_INCREMENT,
`level_name` varchar(255) DEFAULT NULL,
`level_description` text,
`level_priority` int(5) NOT NULL DEFAULT '1' COMMENT 'lower is more higher priority',
PRIMARY KEY (`level_group_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='contain user role or level' AUTO_INCREMENT=5 ;
--
-- Dumping data for table `ws_account_level_group`
--
INSERT INTO `ws_account_level_group` (`level_group_id`, `level_name`, `level_description`, `level_priority`) VALUES
(1, 'Super administrator', 'For site owner or super administrator.', 1),
(2, 'Administrator', NULL, 2),
(3, 'Member', 'For registered user.', 999),
(4, 'Guest', 'For non register user.', 1000);
Models
class Model_Accounts extends \Orm\Model
{
protected static $_table_name = 'accounts';
protected static $_primary_key = array('account_id');
// relations
protected static $_has_many = array(
'account_level' => array(
'model_to' => 'Model_AccountLevel',
'key_from' => 'account_id',
'key_to' => 'account_id',
'cascade_delete' => true,
),
'account_fields' => array(
'model_to' => 'Model_AccountFields',
'key_from' => 'account_id',
'key_to' => 'account_id',
'cascade_delete' => true,
),
);
}
model/accounts.php
class Model_AccountLevelGroup extends \Orm\Model
{
protected static $_table_name = 'account_level_group';
protected static $_primary_key = array('level_group_id');
// relations
protected static $_has_many = array(
'account_level' => array(
'model_to' => 'Model_AccountLevel',
'key_from' => 'level_group_id',
'key_to' => 'level_group_id',
'cascade_delete' => true,
)
);
}
model/accountlevelgroup.php
class Model_AccountLevel extends \Orm\Model
{
protected static $_table_name = 'account_level';
protected static $_primary_key = array('level_id');
// relations
protected static $_belongs_to = array(
'account_level_group' => array(
'model_to' => 'Model_AccountLevelGroup',
'key_from' => 'level_group_id',
'key_to' => 'level_group_id',
),
'accounts' => array(
'model_to' => 'Model_Accounts',
'key_from' => 'account_id',
'key_to' => 'account_id',
)
);
}
model/accountlevel.php
Create user.
I use register method in accounts model to create user.
$data['account_username'] = 'unique_username';
$data['account_password'] = 'pass';
$data['account_email'] = 'no#email.tld';
$account = self::forge($data);
$account->account_level = new Model_AccountLevel();
$account->account_level->level_group_id = 3;
$account->save();
$account_id = $account->account_id;
and i got this error.
Assigned relationships must be an array or null, given relationship
value for account_level is invalid.
How to insert related table? What wrong with my code?
Your account_level relation is a has_many, this means that when accessing it you need to access it like an array. The ORM expects the value of this to be an array so assigning the model directly to it is invalid.
What you want to do is:
$account->account_level[] = new Model_AccountLevel(['level_group_id' => 3]);
(Using the array in the constructor because personally I find it's neater, but it's not required)