I'm wanting to be able to handle polymorphic relations with Backpack CRUD. I can't find any good explanations and I'm struggling to unpick its implementation in their other packages (e.g. PermissionManager). What I'm wanting to do is to be able to change the specialties Users & Clinicians are linked to - similar to how roles & permissions change in the Permission Manager.
I have a polymorphic n-n relationship with Users & Clinicians to Specialties. Each model CRUDTrait.
Specialty Model
public function user()
{
return $this->morphedByMany(User::class, 'model', 'model_has_specialties');
}
public function clinician()
{
return $this->morphedByMany(Clinician::class, 'model', 'model_has_specialties');
}
User Model
public function specialties()
{
return $this->morphToMany(Specialty::class, 'model', 'model_has_specialties');
}
Clinician Model
public function specialties()
{
return $this->morphMany(Specialty::class, 'model', 'model_has_specialties');
}
The pivot table is 'model_has_specialties' and contains:
$table->increments('id');
$table->timestamps();
$table->integer('model_id');
$table->string('model_type');
$table->integer('specialty_id');
$table->unique(['model_id', 'model_type', 'specialty_id']);
I have tried a number of different addField() configurations however I'm really struggling.
Example of addField() tried:
$this->crud->addField([
'label' => 'specialties',
'type' => 'select',
'morph' => true,
'name' => 'model_id',
'entity' => 'ModelHasSpecialties',
'attribute' => 'model_id',
'model' => 'App\Models\Clinician',
'pivot' => true,
]);
** Edit **
Here's the ClinicianCrudController which is the link between the clinician class & bootstrap.
class ClinicianCrudController extends CrudController
{
public function setup()
{
/*
|--------------------------------------------------------------------------
| CrudPanel Basic Information
|--------------------------------------------------------------------------
*/
$this->crud->setModel('App\Models\Clinician');
$this->crud->setRoute(config('backpack.base.route_prefix') . '/clinician');
$this->crud->setEntityNameStrings('clinician', 'clinicians');
$this->crud->setColumns(['surname', 'forename', 'title', 'specialties']);
$this->crud->addField([
'name' => 'surname',
'type' => 'text',
'label' => 'Surname'
]);
$this->crud->addField([
'name' => 'forename',
'type' => 'text',
'label' => 'Forename'
]);
$this->crud->addField([
'name' => 'title',
'type' => 'select_from_array',
'options' => [
'Dr' => 'Dr',
'Miss' => 'Miss',
'Mr' => 'Mr',
'Mrs' => 'Mrs',
'0Ms' => 'Ms',
'Prof' => 'Prof',
],
'label' => 'Title',
'allows_null' => false,
]);
$this->crud->addField([
'label' => 'specialties',
'type' => 'select',
'morph' => true,
'name' => 'model_id',
'entity' => 'ModelHasSpecialties',
'attribute' => 'model_id',
'model' => 'App\Models\Clinician',
'pivot' => true,
]);
/*
|--------------------------------------------------------------------------
| CrudPanel Configuration
|--------------------------------------------------------------------------
*/
// TODO: remove setFromDb() and manually define Fields and Columns
$this->crud->setFromDb();
// add asterisk for fields that are required in ClinicianRequest
$this->crud->setRequiredFields(StoreRequest::class, 'create');
$this->crud->setRequiredFields(UpdateRequest::class, 'edit');
}
Related
I have all my rules in the Validation config file, like the documentation suggest:
https://codeigniter4.github.io/userguide/libraries/validation.html#saving-sets-of-validation-rules-to-the-config-file
For example:
public $userCreate = [
'first_name' => [
'label' => 'First Name',
'rules' => 'required|string|max_length[60]'
],
'last_name' => [
'label' => 'Last Name',
'rules' => 'required|string|max_length[60]',
],
'email' => [
'label' => 'Auth.email',
'rules' => 'required|max_length[254]|valid_email|is_unique[users.email]',
],
];
In my controllers I can access my validation groups like this:
$validation = \Config\Services::validation();
$rules = $validation->getRuleGroup('userCreate');
As my app gets bigger, I need more and more validation rules, so the question is, is there a way to organize them in separate files and not to have all of them in a single config file? Something like the custom rules, which are loaded in the config file and stored separately.
Steps
Create a custom directory for storing your validation rules. I.e app/Validation.
Create a class under that directory for your 'User' rules. I.e: app/Validation/UserRules.php
<?php
namespace App\Validation;
class UserRules
{
public function create()
{
return [
'first_name' => [
'label' => 'First Name',
'rules' => 'required|string|max_length[60]'
],
'last_name' => [
'label' => 'Last Name',
'rules' => 'required|string|max_length[60]',
],
'email' => [
'label' => 'Auth.email',
'rules' => 'required|max_length[254]|valid_email|is_unique[users.email]',
],
];
}
public function update()
{
return [
// Add 'User' update rules here.
];
}
}
In the \Config\Validation config file, set the relevant 'User' validation rules in the constructor. I.e:
<?php
namespace Config;
use CodeIgniter\Config\BaseConfig;
// ...
class Validation extends BaseConfig
{
// --------------------------------------------------------------------
// Setup
// --------------------------------------------------------------------
public $userCreate = [];
public $userUpdate = [];
public function __construct()
{
$this->userCreate = ($userRules = new \App\Validation\UserRules())->create();
$this->userUpdate = $userRules->update();
}
// ...
}
In your Controllers, you may access validation groups as usual.
Thanks to #steven7mwesigwa I came up with a solution that suits me the most.
First I created separate classes inside the App/Validation folder. For example these 2 classes:
App\Validation\Auth.php
<?php
namespace App\Validation;
class Auth {
public $login = [
'email' => [
'label' => 'E-mail',
'rules' => 'required|max_length[254]|valid_email',
],
'password' => [
'label' => 'Password',
'rules' => 'required',
],
'remember' => [
'label' => 'Remember me',
'rules' => 'if_exist|permit_empty|integer',
]
];
}
App\Validation\User.php
<?php
namespace App\Validation;
class User {
public $userCreate = [
'first_name' => [
'label' => 'First Name',
'rules' => 'required|string|max_length[60]',
],
'last_name' => [
'label' => 'Last Name',
'rules' => 'required|string|max_length[60]',
],
'email' => [
'label' => 'E-mail',
'rules' => 'required|max_length[254]|valid_email|is_unique[users.email]',
],
];
}
The next step is to add a construct method to the existing validation config file:
App\Config\Validation.php
<?php
namespace Config;
use CodeIgniter\Config\BaseConfig;
class Validation extends BaseConfig {
...
// --------------------------------------------------------------------
// Rules
// --------------------------------------------------------------------
public function __construct() {
$ruleGroups = [
new \App\Validation\Auth(),
new \App\Validation\User(),
];
foreach ($ruleGroups as $ruleGroupClass) {
foreach ((array) $ruleGroupClass as $groupName => $rules) {
$this->{$groupName} = $rules;
}
}
}
}
Good day. My group our currently working in our final project using Laravel. I have this problem that I encounter.
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use app\database\seeders\Survey;
class SurveySeeder extends Seeder
{
/**
* Run the database seeds.
*
* #return void
*/
public function run()
{
$survey = Survey::create(['name' => 'Register Form', 'settings' => ['accept-guest-entries' => true]]);
$survey->questions()->create([
'content' => 'First Name',
]);
$survey->questions()->create([
'content' => 'Last Name',
]);
$survey->questions()->create([
'content' => 'Date of Birth (MM/DD/YYYY)',
]);
$survey->questions()->create([
'content' => 'Full Address',
]);
$survey->questions()->create([
'content' => 'Blood Group',
'type' => 'radio',
'options' => ['A', 'B', 'O', 'AB']
]);
$survey->questions()->create([
'content' => 'Phone Number',
'type' => 'number',
'rules' => ['numeric', 'min:11', 'max:11']
]);
}
}
I found some solutions but it doesn't work for me. I hope you can help me to get through this.
Where is your model Survey.php?
If in app/Models then you need to
use App\Models\Survey;
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 ...
In Laravel I have relation:
class Address extends Model
{
protected $fillable = [
'street', 'city', 'post_code', 'country', 'state',
];
public function companies() {
return $this->hasMany('App\Company');
}
}
class Company extends Model
{
protected $fillable = [
'name', 'nip', 'email', 'phone', 'address_id'
];
public function address() {
return $this->belongsTo('App\Address');
}
}
and in CompaniesController.php I want to do update tables. My code looks like this:
public function update(Request $request, $id)
{
Company::where('id', $id)->update([
'name' => $request->name,
'email' => $request->email,
'phone' => $request->phone,
'nip' => $request->nip,
]);
}
How to also update the address associated with this company?
If the ID is your primary key, you should use find instead of where, as the former will guarantee that you only retrieve one row.
You can then query the relationship of your Company model, using the following code:
$company = Company::find($id);
$company->update([
'name' => $request->name,
'email' => $request->email,
'phone' => $request->phone,
'nip' => $request->nip,
]);
$company->address()->update([
'street' => 'street value',
'city' => 'city value',
'post_code' => 'post_code value',
'country' => 'country value',
'state' => 'state value',
]);
Please refer to the laravel docs
I have created a custom extension just like a customer module and I want backend just like a customer.
My extension has two tables and two models.
My modules are:
Mage::getModel('custommod/reg') - just like Mage::getModel('customer/customer'), reg saves data of registration
Mage::getModel('custommod/personal') - just like Mage::getModel('customer/address'), //personal data of a reg records.
Please check the image below:
Now I am facing the problem to show the data and edit .
In Magento customer admin section, Customer edit position has multiple tabs: Account information, Address etc.
Here, Account information tab saves data in customer/customer
and Address information tab saves data in customer/address.
I like this type of section.
After a long time work i have done it ,Here the solution
The tabs.php show left panel
<?php
class Amit_Vendor_Block_Adminhtml_List_Edit_Tabs extends Mage_Adminhtml_Block_Widget_Tabs
{
public function __construct()
{
parent::__construct();
$this->setId('vendor_tabs');
$this->setDestElementId('edit_form');
$this->setTitle(Mage::helper('vendor')->__('Manage Vendor'));
}
protected function _beforeToHtml()
{
$this->addTab('form_section', array(
'label' => Mage::helper('vendor')->__('General Information'),
'title' => Mage::helper('vendor')->__('General Information'),
'content' => $this->getLayout()->createBlock('vendor/adminhtml_list_edit_tab_form')->toHtml(),
));
$this->addTab('vendor_details',array(
'label'=>Mage::helper('vendor')->__('Vendor Store Details'),
'title'=>Mage::helper('vendor')->__('Vendor Store Details'),
'content'=>$this->getLayout()->createBlock('vendor/adminhtml_list_edit_tab_storedetails')->toHtml(),
));
return parent::_beforeToHtml();
}
}
after the form.php
<?php
class Amit_Vendor_Block_Adminhtml_List_Edit_Tab_Form extends Mage_Adminhtml_Block_Widget_Form
{
protected function _prepareForm()
{
$vendor = Mage::registry('vendor_data');
$form = new Varien_Data_Form();
$fieldset = $form->addFieldset('vendor_form', array(
'legend' => Mage::helper('vendor')->__('Vendor Registration')
));
$fieldset->addField('name', 'text', array(
'name' => 'name',
'label' => Mage::helper('vendor')->__('Name'),
'required' => true,
));
$fieldset->addField('email', 'text', array(
'name' => 'email',
'label' => Mage::helper('vendor')->__('Email'),
'required' => true,
));
$fieldset->addField('user_name', 'text', array(
'name' => 'user_name',
'label' => Mage::helper('vendor')->__('User name'),
'required' => true,
));
$fieldset->addField('password', 'password', array(
'name' => 'password',
'class' => 'required-entry',
'label' => Mage::helper('vendor')->__('Password'),
'required' => true,
));
$this->setForm($form);
$form->setValues($vendor->getData());
return parent::_prepareForm();
}
public function filter($value)
{
return number_format($value, 2);
}
}
Second form Storedetails.php
<?php
class Amit_Vendor_Block_Adminhtml_List_Edit_Tab_Storedetails extends Mage_Adminhtml_Block_Widget_Form{
protected function _prepareForm(){
$vendorStore = Mage::registry('vendor_store_details');// new registry for different module
$form = new Varien_Data_Form();
//$form->setFieldNameSuffix('vendor_store');
$fieldset = $form->addFieldset('vendor_form', array(
'legend' => Mage::helper('vendor')->__('Vendor deatsilsn')
));
$fieldset->addField('alternative_email','text',array(
'name' =>'alternative_email',
'label' => Mage::helper('vendor')->__('Alternative Email'),
'required'=> false
));
$fieldset->addField('shopname','text',array(
'name' =>'shopname',
'label' => Mage::helper('vendor')->__('Shop Name'),
'required'=> true,
'class' => 'required-entry',
));
$fieldset->addField('company', 'text', array(
'name' => 'company',
'label' => Mage::helper('vendor')->__('Company'),
'required' => true,
'class' => 'required-entry',
));
$fieldset->addField('street','text',array(
'name' =>'vendor_details[street]',
'label' => Mage::helper('vendor')->__('Street Address'),
'required'=> false
));
$this->setForm($form);
$form->addValues($vendorStore->getData());
return parent::_prepareForm();
}
}