I am using the MultiForm module to submit a long form with SilverStripe. The logic for this form is in 'CampaignBriefForm.php' whereas the gridfield CMS field is being added in 'CampaignBriefPage.php'. I have a Data Object for a CampaignBriefLead which is what the form creates.
Campaign Brief Page
private static $has_many = array(
'CampaignBriefLeads' => 'CampaignBriefLead'
);
public function CampaignBriefForm() {
return new CampaignBriefForm($this, 'CampaignBriefForm');
}
Campaign Brief Lead (DO)
private static $has_one = array( "Page" => "CampaignBriefPage" );
As you can see the Campaign Brief page has the correct relationship with the Data Object and also you can see the the form itself (done in a sepearate file) is correctly returning (as it's being saved in the DB). For some reason however, the gridfield will not show me what is in the database for that Data Object. The grid field code is as follows.
$fields = parent::getCMSFields();
$contactConfig = GridFieldConfig_RelationEditor::create();
$contactConfig->getComponentByType('GridFieldDataColumns')->setDisplayFields(
array(
'CompanyName' => 'Company Name',
'StartDate' => 'Start Date',
'Duration' => 'Duration',
'WebsiteURL' => 'Website',
'Budget' => 'Budget'
));
$contactGrid = new GridField(
'CampaignBrief',
'Campaign Enquiries',
$this->CampaignBriefLeads(),
$contactConfig
);
$fields->addFieldToTab("Root.Enquiries", $contactGrid);
To me this all looks correct and should work but for some reason it is not working.
Note
The link existing option on the gridfield allows me to link one of the entries from the DO with the gridfield weirdly?? So it saves one entry but I have to do it manually, this tells me it can see the DB but won't pull for some reason.
For reviewing reasons, here is the code for the multiform where the campaign brief lead is actually saved to the DB after the form is submitted.
public function finish($data, $form) {
parent::finish($data, $form);
$steps = DataObject::get(
'MultiFormStep',
"SessionID = {$this->session->ID}"
);
$enquiry = new CampaignBriefLead();
foreach($steps as $step) {
$data = $step->loadData();
foreach($data as $key => $value) {
if($key == 'url' || $key == 'MultiFormSessionID' || $key == 'action_finish') {
continue;
}
if(isset($data[$key])) {
$enquiry->$key = $data[$key];
error_log($data[$key]);
}
}
}
$enquiry->write();
$this->controller->redirect('/campaign-brief/');
}
If you need anything more let me know. Thanks.
I would take a guess that the CampaignBriefLead PageID is not being set on your form submission.
Check the CampaignBriefLead table in your database and check the PageID column. If it is blank, null or 0 for each row then it is not being set.
One way to fix this problem for any new submission is to set the PageID for the $enquiry:
public function finish($data, $form) {
// ...
$enquiry = new CampaignBriefLead();
if ($campaignBriefPage = CampaignBriefPage::get()->first()) {
$enquiry->PageID = $campaignBriefPage->ID;
}
// ...
}
For the existing entries you will need to update the entries to have the correct PageID.
Related
I am on a component where I want the user add their own fields as options for another record.
For example I have a view Product (administrator/components/com_myproducts/views/product/...). This view will get their title, alias and description of its form (administrator/components/com_myproducts/models/forms/product.xml). The form xml is static but I want users to add product attributes by themselves.
So I am adding another view Attributes where users can add records with a name and a field type.
Now I want these attributes to be added to the Product form. So it is basically fetching the Attributes from the database, loading the form XML, appending the attributes to the XML and feeding the modified XML to a JForm object to return it in the Product models getForm().
In the Product model this would look something like this:
public function getForm($data = array(), $loadData = true)
{
// Get the form.
$form = $this->loadForm(
'com_myproducts.product',
'product',
array(
'control' => 'jform',
'load_data' => $loadData
)
);
$xml = $form->getXML();
$attributes = $this->getAttributes();
$newForm = Helper::manipulateFormXML($xml, $attributes);
/*
* load manipulated xml into form
* don't know what to do here
*/
...
if (empty($form)) {
return false;
}
return $form;
}
How can I update the form with the modified xml or should I approach this another way?
I kind of found a workaround for the problem by creating a new instance of the form.
public function getForm($data = array(), $loadData = true)
{
// Get the form.
$tmp = $this->loadForm(
'com_myproducts.tmp',
'product',
array(
'control' => 'jform',
'load_data' => $loadData
)
);
$xml = $tmp->getXML();
$attributes = $this->getAttributes();
$newXml = Helper::manipulateFormXML($xml, $attributes);
// Get the form.
$form = $this->loadForm(
'com_myproducts.product',
$newXml->asXML(),
array(
'control' => 'jform',
'load_data' => $loadData
)
);
if (empty($form)) {
return false;
}
return $form;
}
I am not satisfied with this solution but it does what I want.
So I just want to insert the data if the typed data does not exist and/or remove them if users decides to remove them; the problem is that it checks for more > 1 value.
This should be my last question of three in total(see my last two question on profile) regarding the same topic, relationships.
So I have three tables like the ones given below:
AI = auto increment.
ci_users: user_id(AI), username, slug, email, biography.
ci_terms: term_id(AI), title, slug, body.
ci_relationship: id(AI), term_id, user_id, type.
I'm actually trying to do this in a edit view in which I get all the terms from ci_terms and and the already(added directly in databse) ci_terms attached to the user with the following controller:
public function edit($id){
// Verify user ID before updating/editing info
if($this->session->userdata('user_id') != $id) {
// Redirect to dashboard
redirect('users/dashboard');
}
// Field Rules
$this->form_validation->set_rules('email', 'Email', 'trim|required|min_length[7]|valid_email');
if ($this->form_validation->run() == FALSE) {
// Get user
$data['item'] = $this->User_model->get($id);
// Meta
$data['title'] = $this->settings->title.' | Edit '. ucfirst($data['item']->username);
// Get attached skills
$skills = array();
$skills[0] = 'Select Skills';
$skills_attached = $this->User_model->the_skills($id);
foreach($skills_attached as $skill){
$skills[$skill->term_id] = $skill->term_id;
}
$data['skills'] = $skills;
// Select Skills
$skill_options = array();
$skill_options[0] = 'Select Skills';
$skill_list = $this->Terms_model->get_list();
foreach($skill_list as $cat){
$skill_options[$cat->term_id] = $cat->title;
}
$data['skill_options'] = $skill_options;
//Load View Into Template
$this->template->load('public', 'default', 'users/edit', $data);
} else {
// Create User Data Array
$data = array(
'email' => strip_tags($this->input->post('email')),
'biography' => strip_tags($this->input->post('biography')),
);
// Update User
$this->User_model->update($id, $data);
// BEGINNING OF HERE IS WHERE I NEED HELP
// Here I try to check the selected ci_terms(term_id) in the database
$existent_skill = $this->User_model->existent_skill($this->input->post('term_id'));
// If the selected ci_terms(term_id) already exists, display an error
if (!empty($existent_skill)) {
// Create Message
$this->session->set_flashdata('error', 'You already have that one or more of those selected skills');
// Redirect to pages
redirect('users/edit/'.$id.'/'.$id->username);
} else {
// Display the data from ci_terms table
$skills = $this->Terms_model->get_list();
// Expect data to be array
$data = array();
foreach ($skills as $skill){
$data[] = array(
// The main problem how do I add the correct IDs to the array?
'term_id' => $skill->id,
'user_id' => $this->session->userdata('user_id'),
'type' => 'skill',
);
}
// If terms selected, add them
$this->db->insert_batch('ci_relationship', $data);
// I'm also trying to figure out a way to remove the terms that are already attached to the user if he/she decides not to want those skill anymore, any suggestion will be taken into practice.
// else if terms unselected, remove them
$this->User_model->delete_skills($id, $terms_id, $data);
// END OF HERE IS WHERE I NEED HELP
}
// Create Message
$this->session->set_flashdata('success', "You're account has been updated");
// Redirect to profile
redirect('users/dashboard');
}
}
Here is how I get to display the attached(to user) terms from the ci_terms table into the view:
public function the_skills($id){
$this->db->select('*');
$this->db->from($this->relationship);
$this->db->where('user_id', $id);
$this->db->where('type', 'skill');
$query = $this->db->get();
if($query->num_rows() >= 1){
return $query->result();
} else {
return false;
}
}
This is the method which I'm still trying to create that checks for all the selected terms before adding them if they don't exist:
// Verify if relationship already exists
public function existent_skill($term_id) {
$query = $this->db->get_where($this->relationship, array(
'user_id' => $this->session->userdata('user_id'),
'term_id' => $term_id,
'type' => 'skill',
));
return $query->row_array();
}
to continue, here is the function which is supposed(not tested) to delete them if they're unselected from the input:
// Delete un-selected skills
public function delete_skills($id, $terms_id, $data){
$this->db->from($this->relationship);
$this->db->where('user_id', $id);
$this->db->where_in('term_id', $terms_id);
$this->db->where('type', 'skill');
$this->db->delete($this->relationship, $data);
}
Finally here is the view in which I'm using a dropdown with select2:
<!-- Skills -->
<div class="form-group">
<?php echo form_label('Skills', 'skills'); ?>
<div class="input-group date"><div class="input-group-addon"><i class="fa fa-star" aria-hidden="true"></i></div>
<?php
$data = array(
'id' => 'term_id[]',
'name' => 'term_id[]',
);
$class = array(
'class' => 'form-control js-example-basic-multiple',
'multiple' => TRUE,
);
?>
<!-- $data is to provide the dropdown with the id and name -->
<!-- $skill_options is to get the terms from ci_terms in case the user wants to add them as their skill -->
<!-- $skills is to get the current term_id attached to the user which were added in the db -->
<!-- $class is to give the class of js-example-basic-multiple to enable select2 -->
<?= form_dropdown($data, $skill_options, $skills, $class); ?>
<script type="text/javascript">
// Select2 Input
$(document).ready(function () {
$('.js-example-basic-multiple').select2({
tags: true,
tokenSeparators: [',', ' '],
allowClear: true,
selectOnClose: false,
selectOnBlur: false,
});
});
</script>
</div>
</div>
BELOW ARE JUST IMAGES
So what I'm trying to achieve is this:
As you can see there HTML5(term_id, 1) and CSS(term_id, 2) are the attached term_id's and if I deselect them, they should be deleted from ci_relationship after clicking the update button and the same(not really) goes when selecting new terms that are not attached, they should be added.
Is pretty much a relationship system like the one WordPress uses.
Thanks in advance.
I guess you are overthinking here to much - you should just delete all items related to that user and after that insert the new ones which are selected...
an example for your model function could be
public function updateSkills(array $arrSkills)
{
//in case if the array is empty you can stop the process here
if (empty($arrSkills)) return false;
//kill all associated items
$this->db
->where('user_id', $this->session->userdata('user_id'))
->where('type', 'skill');
->delete('ci_relationship');
//insert all items
$arrInsertData = [];
foreach($arrSkills AS $strSkill)
{
$arrInsertData[] = [
'term_id' => $strSkill,
'user_id' => $this->session->userdata('user_id'),
'type' => 'skill'
]
}
$this->db->insert_batch('ci_relationship', $arrInsertData);
return true;
}
and the part in your controller could look like
$data = array(
'email' => strip_tags($this->input->post('email')),
'biography' => strip_tags($this->input->post('biography')),
);
// Update User
$this->User_model->update($id, $data);
// BEGINNING OF HERE IS WHERE I NEED HELP
$blnSuccess = $this->User_model->updateSkills($this->input->post('term_id[]'));
of course you can also add a rule, in case if term_id is required
$this->form_validation->set_rules('term_id[]', 'Term', 'trim|required');
I am very much new to laravel framework.
I have one form , which i need to update on submit button click.
when submit button clicks control goes to controller.php 's update() function .
But I am unable to edit any field's value.
here is my code.
public function update($id)
{
//echo "<pre>";print_r(Input::all());exit;
$product = $this->product->find($id);
$input = Input::only('designer', 'sku', 'name', 'display_name', 'description', 'price', 'main_category', 'sub_category', 'lead_time', 'sizing', 'woven', 'body_fabric', 'lining_fabric', 'fit', 'primary_color', 'secondary_color', 'care_label', 'neck_type', 'closure', 'trims', 'special_finishings', 'image1', 'image2', 'image3', 'image4', 'image5','top', 'combo_products', 'keywords', 'visibility', 'featured');
//echo "<pre>";print_r($input);exit;
try
{
$this->adminNewProductForm->validate($input);
} catch(\Laracasts\Validation\FormValidationException $e)
{
return Redirect::back()->withInput()->withErrors($e->getErrors());
}
$slug = Str::slug(Input::get('name'));
$slug = $this->product->getSlug($slug);
$input = array_add($input, 'slug', $slug);
DB::transaction(function() use($product, $input)
{
$product->fill($input)->save();
$stock_count = 0;
if(!empty(Input::get('xsmall_size')))
{
$rows = DB::table('products_variants')->where('product_id', $product->id)->where('variant_name', 'XS')->get();
$stock_count += Input::get('xsmall_stock');
if(!empty($rows))
{
DB::table('products_variants')->where('product_id', $product->id)->where('variant_name', 'XS')->update(array('variant_specs' => Input::get('xsmall_size'), 'price_change' => Input::get('xsmall_price'), 'total_stock' => Input::get('xsmall_stock'), 'stock_used' => 0));
} else {
DB::table('products_variants')->insert(array('product_id' => $product->id, 'variant_name' => 'XS', 'variant_specs' => Input::get('xsmall_size'), 'price_change' => Input::get('xsmall_price'), 'total_stock' => Input::get('xsmall_stock'), 'stock_used' => 0));
}
}
$input = array();
$input['flagship_status'] = Input::get('flagship_status');
if(Input::get('flagship_status'))
{
$input['stock_count'] = Input::get('small_stock');
}else {
$input['stock_count'] = $stock_count;
}
$product->fill($input)->save();
});
//echo "<pre>";print_r(Input::all());exit;
return Redirect::back()->withFlashMessage('Product Updated Successfully!');
}
Also I cant understand , what is going on by this line ? because i did not find validate function anywhere in my code.
$this->adminNewProductForm->validate($input);
I need to update table products not products_variants.
validate is inherited from the FormRequst class.
https://laravel.com/api/5.0/Illuminate/Foundation/Http/FormRequest.html#method_validate
You've provided too much code and too little information. You said you need to update a specific table, but yet there are two lines where you are very intentionally manually updating a database entry.
This is one of them:
DB::table('products_variants')->where('product_id', $product->id)->where('variant_name', 'XS')->update(array('variant_specs' => Input::get('xsmall_size'), 'price_change' => Input::get('xsmall_price'), 'total_stock' => Input::get('xsmall_stock'), 'stock_used' => 0));
When you call this:
$product->fill($input)->save();
It also saves 'dirty' (modified) models that also belong to it, which can include products_variants relationships. From the sound of it, you are incorrectly applying changes directly through SQL, and then the model's save method is overwriting it.
You seem unclear about what your code is actually doing, and I would strongly suggest simplifying it down and adding in code as you begin to understand what each line does. I think your question is the byproduct of copying an example and adding your own work without understanding how Laravel handles relationships and models. There is almost never a good reason to use raw SQL or DB statements.
I am working on my first project using Laravel 5.1. Uses a selectbox in a form.
{!!Form::select('animal_parent[]', array('1' => 'opt1', '2' => 'opt2', '3' => 'opt3', '4' => 'opt4',), null, ['id' => 'animal_parent', 'disabled' => 'disabled', 'multiple' => 'multiple', 'class' => 'form-control'])!!}
Selection limited to two options which need to saved in two columns, male_parent and female_ parent of the animal table.
There are no male_parent and female_ parent element names in the form. Similarly no animal_parent field in animal table.
Values are set as expected in the code given below. However, the insert command does not reflect the newly set values and throws an error.
"ErrorException in helpers.php line 671: preg_replace(): Parameter mismatch, pattern is a string while replacement is an array."
Any help would be much appreciated.
First attempt using mutators
public function setMaleParentAttribute()
{
$parent = Input::get('animal_parent');
$this->attributes['male_parent'] = intval($parent[0]);
}
public function setFemaleParentAttribute(AddAnimalRequest $request)
{
$parent = Input::get('animal_parent);
if (isset($parent[1])) {
$this->attributes['female_parent'] = intval($parent[1]);
} else {
$this->attributes['female_parent'] = intval($parent[0]);
}
unset($request->animal_parent);
}
Second attempt using the store() method in the controller.
$animal = new Animal($request->all());
$parent = Input::get('animal_parent');
$animal['male_parent'] = intval($parent[0]);
if (isset($parent[1])) {
$animal['female_parent'] = intval($parent[1]);
} else {
$animal['female_parent'] = intval($parent[0]);
}
unset($request->animal_parent);
Auth::user()->animals()->save($animal);
return redirect('animals');
The problem was then solved with a change in UI. I feel the problem could have been solved using the below method. Hope that helps someone.
$input = $request->all();
$parent = $input['animal_parent'];
$input['male_parent'] = intval($parent[0]);
if (isset($parent[1])) {
$input['female_parent'] = intval($parent[1]);
} else {
$input['female_parent'] = intval($parent[0]);
}
unset($input['animal_parent']);
$animal = new Animal($input);
$animal->save();`
I want to perform strip_tags on a field called description before data is saved in the database during form submission. I thought of creating a custom rule and doing it over there:
'description' => array(
'stripTags' =>array(
'rule' => array('StripTags'),
'message' => ''
),
),
public function StripTags($user = array()) {
return !empty($user['description'])?strip_tags($user['description']):"";
}
However this doesn't work since cakephp expects true/false to be returned instead of an updated value. How should I do this?
Use the Model::beforeSave() callback, that's were all automatic pre-save data modification logic should go. It is invoked before save, but after validation.
Untested example:
public function beforeSave($options = array())
{
if(!parent::beforeSave($options))
{
return false;
}
if(!empty($this->data[$this->alias]['description']))
{
$this->data[$this->alias]['description'] = strip_tags($this->data[$this->alias]['description']);
}
return true;
}