I'm just learning some Laravel 9 and i'm doing a simple one to one relationship on two tables. I've created the relationships and the foreign keys which are working fine.
I am trying to create a new Hotel which saves info into the Hotels model and the facilities into the facilities model and are joined by the hotel_id as the foreign key.
I can't quite get my transaction right, where I have the hotel but need to pick up the id for it to pass and also have it as my foreign key on the facilities table.
DB::transaction(function () use ($request) {
$hotel = Hotel::create([
'name' => $request->input('name'),
'address' => $request->input('address'),
'postcode' => $request->input('postcode'),
'state' => $request->input('state'),
'star_rating' => $request->input('star_rating'),
]);
$facility = HotelFacility::create([
'hotel_id' => 39,
'fitness_centre' => true,
'bar' => false,
'bar' => true,
'parking' => true,
'free_wifi' => true,
]);
Hotel::find($hotel->id)->facility()->save($facility);
});
You're doing a few things you don't need to here.
When you call create(), it persists to the Database, so calling ->save() later is redundant.
The last line is completely unnecessary as well.
There's ways to do this code by using relationship methods:
DB::beginTransaction();
try {
$hotel = Hotel::create([
'name' => $request->input('name'),
'address' => $request->input('address'),
'postcode' => $request->input('postcode'),
'state' => $request->input('state'),
'star_rating' => $request->input('star_rating'),
]);
$hotel->facility()->create([
'fitness_centre' => true,
'bar' => false,
'parking' => true,
'free_wifi' => true,
]);
DB::commit();
} catch (Exception $ex) {
DB::rollBack();
}
Related
SearchLogic for select_multiple isn't working, I can't change the type of the column so, I have to make it searchable. any workaround?
thanks in advance
I tried to make it to different type as well but getting datatables popup error there.
$this->crud->setColumns([
[
'name' => 'item',
'label' => trans('admin.item_number'),
'type' => "select_multiple",
'entity' => 'item',
'attribute' => "item_number",
'model' => "App\Item",
'searchLogic' => function ($query, $column, $searchTerm)
{
$query->orWhereHas('item', function ($q) use ($column, $searchTerm,$value) {
$q->join('download_item','download_item.download_id', '=' , 'downloads.id')
->join('items','download_item.item_id', '=' , 'items.id')
->where('items.item_number', 'like', '%'.$searchTerm.'%');
});
}
],
]);
I have three tables and the relations are like
downloads table have items from items table but the relationship store in different table named as download_item which contains download_id and item_id.
Why not use a filter? That's much more useful for the user, IMHO.
Here's an example:
$this->crud->addFilter([
'name' => 'provider_state',
'type' => 'select2_multiple',
'label' => 'State',
], function () {
return [
'draft' => 'Draft',
'paid' => 'Paid',
'open' => 'Open',
'late' => 'Late',
'uncollectible' => 'Uncollectible',
'reminded' => 'Reminded',
'pending_payment' => 'Pending Payment',
];
}, function ($values) {
$this->crud->addClause('whereIn', 'provider_state', json_decode($values));
});
I got in trouble with Codeigniter 3 using the form validation library; I have to check that the email address submitted by a user into aregistration form is unique into the users database.
I use two databases in my project, the users one is not the default.
To perform the email check I use the following code:
$this->form_validation->set_rules('email','Email','trim|required|valid_email|is_unique[users.email]');
I got an error about the missing users table into the default database, so I've realized that CI 3 looks the email to check into a default database ... not the correct users database, even if in the construct I load the correct model/database.
Is there a way to perform the check into a different database using the form validation above?
Thanks for any feedback
UPDATE
Below the code I use to load the model in the controller
function __construct()
{
parent::__construct();
$this->load->model("admin/user_model","user");
}
Below the code of the User_model
// Database
private $auth_db;
// Tables
private $table_users = 'users';
public function __construct()
{
parent::__construct();
$this->auth_db = $this->load->database('auth', true);
}
and...finally...in the config file the database configuration
$active_group = 'default';
$query_builder = TRUE;
$db['default'] = array(
'dsn' => '',
'hostname' => 'localhost',
'username' => 'xxxxxxxxx',
'password' => 'xxxxxxxxx',
'database' => 'vfr_main',
'dbdriver' => 'mysqli',
'dbprefix' => '',
'pconnect' => FALSE,
'db_debug' => TRUE,
'cache_on' => FALSE,
'cachedir' => '',
'char_set' => 'utf8',
'dbcollat' => 'utf8_unicode_ci',
'swap_pre' => '',
'encrypt' => FALSE,
'compress' => FALSE,
'stricton' => FALSE,
'failover' => array(),
'save_queries' => TRUE
);
$db['auth'] = array(
'dsn' => '',
'hostname' => 'localhost',
'username' => 'xxxxxxxxxxx',
'password' => 'xxxxxxxxxxx',
'database' => 'vfr_auth',
'dbdriver' => 'mysqli',
'dbprefix' => '',
'pconnect' => FALSE,
'db_debug' => TRUE,
'cache_on' => FALSE,
'cachedir' => '',
'char_set' => 'utf8',
'dbcollat' => 'utf8_unicode_ci',
'swap_pre' => '',
'encrypt' => FALSE,
'compress' => FALSE,
'stricton' => FALSE,
'failover' => array(),
'save_queries' => TRUE
);
In CodeIgniter 3, models do not have a direct way to control which database group they connect to. In this case I do not think we can simply write a custom validation rule, because is_unique is the only rule that makes a db call, and there is no built in way to change db.
In this case I think the most direct approach would be to extend the form validation class, and then add a new is_unique_authdb method in this extended library for checking with the second db. Then you would use this new method in place of the call you have shown above.
In the 3.x repo on git hub I see this is the existing method.
public function is_unique($str, $field)
{
sscanf($field, '%[^.].%[^.]', $table, $field);
return isset($this->CI->db)
? ($this->CI->db->limit(1)->get_where($table, array($field => $str))->num_rows() === 0)
: FALSE;
}
And your extra method could be something like:
public function is_unique_authdb($str, $field)
{
$db = $this->CI->load->database('auth', true);
sscanf($field, '%[^.].%[^.]', $table, $field);
return isset($db)
? ($db->limit(1)->get_where($table, array($field => $str))->num_rows() === 0)
: FALSE;
}
Extending a native library is very simple. For example, to extend the native Form_validation class you’ll create a file named application/libraries/MY_Form_validation.php, and declare your class with:
class MY_Form_validation extends CI_Form_validation {
public function is_unique_authdb($str, $field)
{
$db = $this->CI->load->database('auth', true);
sscanf($field, '%[^.].%[^.]', $table, $field);
return isset($db)
? ($db->limit(1)->get_where($table, array($field => $str))->num_rows() === 0)
: FALSE;
}
}
Then you would load the library as normal but it will load your extended library and you can use the authdb method for this validation.
$this->form_validation->set_rules('email','Email','trim|required|valid_email|is_unique_authdb[users.email]');
CI3 docs for extending a native library.
Note: With CodeIgniter 4 I think this would be more simple because CI4 has a built in property for models that specifically allows you to manage which db a model will connect to.
I'm using Laravel 7 + Backpack CRUD 4.1.
I have two models Payment and PaymentMethods and field in PaymentCrudController
$this->crud->addField([
'label' => 'Payment Method',
'type' => 'select2',
'name' => 'payment_method_id',
'entity' => 'paymentMethod',
'attribute' => 'name',
'model' => 'App\Models\PaymentMethod',
'wrapperAttributes' => [
'class' => 'form-group col-md-3',
],
]);
Relation in Payment model:
public function paymentMethod()
{
return $this->hasOne(PaymentMethod::class, 'id', 'payment_method_id');
}
Actually, this works as expected - I see all records from the PaymentMethod model in the options field. But I need to filter some values. I trying to modify model relation:
public function paymentMethod()
{
return $this->hasOne(PaymentMethod::class, 'id', 'payment_method_id')->where('name', '!=', 'Online');
}
But I still see all records in select options. How can I filter select values?
putting 'where' in relation make no sense, in my opinion, relation should be as it is, reflect tables 's relations ....
for your suituation you could use 'options' for 'select2' field:
$this->crud->addField([
'label' => 'Payment Method',
'type' => 'select2',
'name' => 'payment_method_id',
'entity' => 'paymentMethod',
'attribute' => 'name',
'model' => 'App\Models\PaymentMethod',
'options' => (function ($query) {
return $query->where('name', '!=', 'Online')->get();}),
'wrapperAttributes' => [
'class' => 'form-group col-md-3',
],
]);
something else ... for your one to many relation: it should be:
public function paymentMethod()
{
return $this->hasOne(PaymentMethod::class,'payment_method_id');
}
second parameter should be the foreign key ...
Let me show you my code, and place comments for you guys to better understand:
$homework = new Homework([ // I create Homework (And I indeed want to get the ID of the one that was just created).
'subject_id' => $request->subject_id,
'user_id' => auth()->user()->id,
'title' => $request->name,
'image' => $path,
'progress' => $request->progress,
'description' => $request->description,
'duedate' => $request->date
]);
$homework->save(); // I save it
$homeworkid = Homework::where('id', $id)->first(); // I try to retrieve it, but I'm not sure how to get it as I need to define `$id`.
$progress = newProgress([
'user_id' => auth()->user()->id,
'homework_id' => $homeworkid, // I need this for the relationship to work.
'title' => 'Initial Progress',
'description' => 'This progress is auto-generated when you create an assignment',
'username' => auth()->user()->name,
'progress' => $homeworkid->progress
]);
$progress->save(); // I save the progress
Well, as you saw, I'm trying to retrieve the ID of Homework right after it was created, but I'm not sure how to define $id in order to get it.
There is no need to instantiate a new model and saving it if your are not doing anything between instantiating and saving, you can use the create method instead:
$homework = Homework::create([
'subject_id' => $request->subject_id,
'user_id' => auth()->user()->id,
'title' => $request->name,
'image' => $path,
'progress' => $request->progress,
'description' => $request->description,
'duedate' => $request->date
]);
$homework->id; // get the id
After saving / creating the model you can access the id like you normally would:
$homework->id
What you then could do is setup the relationships between your models so you can do the following after creating a new homework:
$homework->newProgress()->create([
'user_id' => auth()->user()->id,
'title' => 'Initial Progress',
'description' => 'This progress is auto-generated when you create an assignment',
'username' => auth()->user()->name,
'progress' => $homework->progress
]);
This way you don't have to pass the homework id when creating a new newProgress, laravel will pass it automatically for you.
This is very simple for you. No need to complex it.
$homework->save(); // I save it
After this line just use only
$progress = newProgress([
'user_id' => auth()->user()->id,
'homework_id' => $homework->id, // I need this for the relationship to work.
'title' => 'Initial Progress',
'description' => 'This progress is auto-generated when you create an assignment',
'username' => auth()->user()->name,
'progress' => $homework->progress
]);
You don't no need this line of code
$homeworkid = Homework::where('id', $id)->first(); // I try to retrieve it, but I'm not sure how to get it as I need to define `$id`.
$data = $homework->save();
Get the ID this way: $data->id
I am able to import for 'users' table but I also need to import to pivot tables. Here's my code from my UsersController for importing to 'users' table, but is it possible to supply data to pivot tables like "user_company", "user_department" by importing? Can you show me a sample of importing to pivot tables? Anyways this is my code in importing.
if( Input::file('file_import') ) {
$path = Input::file('file_import')->getRealPath();
$inserts = [];
Excel::load($path,function($reader) use (&$inserts)
{
foreach ($reader->toArray() as $row){
$inserts[] = ['email' => $row['email'], 'username' => $row
['username'], 'password' => $row['password'], 'first_name' => $row['first_name'],'middle_name' => $row['middle_name'], 'last_name' => $row['last_name'], 'gender' => $row['gender'],
'civil_status' => $row['civil_status'], 'spouse' => $row['spouse'], 'religion' => $row['religion'],'emergency_no' => $row['emergency_no'],'previous_work' => $row['previous_work'],
'remarks' => $row['remarks'],'course' => $row['course'],'biometrics' => $row['biometrics'],'immediate_head' => $row['immediate_head'],'designation' => $row['designation'],'level' => $row['level'],
'emp_status' => $row['emp_status'],'dependents' => $row['dependents'],'date_hired' => $row['date_hired'],'regularization_date' => $row['regularization_date'],'remmitance_date' => $row['remmitance_date'],
'tin' => $row['tin'],'philhealth' => $row['philhealth'],'pagibig' => $row['pagibig'],'sss' => $row['sss'],'umid' => $row['umid'],'phone' => $row['phone'],'avatar' => $row['avatar'],
'address' => $row['address'],'country_id' => $row['country_id'],'role_id' => $row['role_id'],'birthday' => $row['birthday'],'status' => $row['status']];
}
});
}
}
if (!empty($inserts)) {
DB::table('users')->insert($inserts);
return back()->with('success','Inserted Record successfully');
}
There is a better way for this case, using Laravel Eloquent Relationships, but when using Laravel Database Query Builder you should get the last inserted id and to use it in next insert in "user_company", "user_department".
$userinsert = DB::table('users')->insert($inserts);
$insertedId = $userinsert->id;
$insertsusercompany = [
'user_id' => $insertedId,
'value1' => 'somedata1',
'value2' => 'somedata2'
]
$usercompany = DB::table('user_company')->insert($insertsusercompany);
... and the same for others tables, but you should use Eloquent Relationships, because it is much more easier.