generating dynamic form to display in the admin view - php

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.

Related

Grid Field not showing entries [SilverStripe]

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.

Drupal Form API : How to pass additional data back to the form after it is been submitted

I have created a form in Drupal using its API. The theme is overridden by a template. In the template, I want to show errors where the form exists, I do not want to show the error using drupal's form_set_error() because it shows the error in a fixed default area of the page.
This is my implementation of hook_form()
function newsletter_box($form, &$form_state)
{
$form = array();
$form["newsletter-email"] = array(
"#type" => "textfield",
"#maxlength" => 32,
"#title" => "Your Email"
);
$form['send-email'] = array(
"#type" => "submit",
"#value" => t("Join Our Newsletter!")
);
return $form;
}
And this is my implementation of hook_submit()
function newsletter_box_submit($form, &$form_state)
{
if( !filter_var($form_state['values']["newsletter-email"], FILTER_VALIDATE_EMAIL) )
{
$form_state['build_info']['args'] = ['form-error' => t("Email not formatted correctly.") ];
// NOTE: here is the place where the error is set, rather I use to set a new variable, but this variable is not available in my template. Why?
}
$form_state['rebuild'] = TRUE;
drupal_form_submit("newsletter_box", $form_state);
}
Suggest adding the variable by implementing a hook_preprocess, and add the error message into form rather than form_state.
Example:
// Set in newsletter_box_submit or newsletter_box_validate
$form['#form_error'] = t("Email not formatted correctly.");
/**
* Implements hook_preprocess_HOOK().
*/
function [module_name]_preprocess_newsletter_box(&$vars) {
$form = $vars['form'];
$error_message = $form['#form_error'];
// Use $error_message in template.
}
It feels like a hack though, strongly recommend theming the form the Drupal way.

Add Button on Custom Plugin in WordPress

I am working on custom plugin in WP.I have showed the data in table format.Now i am trying to add functionality to plugin.But my table missing header and footer just like normal data listing in WP like Pages and Posts etc.Also i added the new button link.Either this is the right way ? I want to load my page on button clickMy code is :
function extra_tablenav( $which ) {
if ( $which == "top" ){
//The code that goes before the table is here
echo '<h2>Letter Templates Add New</h2>';
}
}
function get_columns() {
return $columns= array(
'col_id'=>__('ID'),
'col_name'=>__('Name'),
'col_url'=>__('Url'),
'col_description'=>__('Description')
);
}
public function get_sortable_columns() {
return $sortable = array(
'col_id'=>'id',
'col_name'=>'name'
);
}
You can use the $_column_headers extended Property
this property is assigned automatically, must manually define it in their prepare_items() or __construct() methods.
like,
function prepare_items(){
$columns = array(
'cb' => '<input type="checkbox" />', //Render a checkbox instead of text
'col_id' => 'ID',
'col_name' => 'Name',
'col_url' => 'URL',
'col_description' => 'Description',
);
$sortable_columns = array(
'col_id' => 'ID',
'col_name' => 'Name',
);
$hidden = array();
$this->_column_headers = array($columns, $hidden, $sortable);
}
function extra_tablenav( $which ) {
if ( $which == "top" ){
echo '<h2>Letter Templates Add New</h2>';
}
}
The Wordpress natively supports URLs like wp-admin/admin.php?page= you acess plugin pages like wp-admin/admin.php?page=mypage&tab=add-letter
And then in your code you just look at the GET and pull up the main page or a sub-page as needed.
like
if(isset($_GET['type']) && $_GET['type']=='new'){
include('add-letter.php');
}
check

Custom Widget doesn't display the same amount of choices

I try to create a customWidget with a special tablemethod to only display the pre selected choices of the user, this is the form :
$this->widgetSchema['Books_list'] = new MyWidgetFormThematicSelector(array(
'multiple' => true,
'model' => 'Books',
'table_method' => array('method' => 'getOnlySelected', 'parameters' => array($this->getObject()->getId())),
'expanded' => true,
));
this is the method getOnlySelected:
$q = Doctrine::getTable('BooksAuthors')
->createQuery('ba')
->select('ba.position,ba.name')
->leftJoin('ba.Books b')
->where('ba.BooksAuthors_id = ?', $id);
echo count($q); //return 4
return $q;
this method return 4 elements which is normal then if i try to echo the values of the getChoices method from the widget I get only 1 in return !?
class MyWidgetFormThematicSelector extends sfWidgetFormDoctrineChoiceWithParams {
public function configure($options = array(), $attributes = array())
{
parent::configure($options, $attributes);
}
public function getChoices() {
$choices = parent::getChoices();
echo count($choices); // return 1
return $choices;
}
public function render($name, $value = null, $attributes = array(), $errors = array()) {
return parent::render($name, $value, $attributes, $errors);
}
}
What's going on here ?
I create a similar widget in the same form where the probleme does not occurs, and it s quite the same code...
thx
I solve this problem by setting the attribute 'key_method' => 'myUniqueId', in the form where the widget is called...
Cause Ive got two primary keys in my table and the sfWidgetFormDoctrineChoiceWithParams widget use the one which was identic for all the results as the key for the array choices, so the size of the array was always one...By setting the other primary key as the main key of the getChoices method I get the correct result.

How to get Silverstripe TableField to save records

I'm trying to use TableField to manage a list of related links to a page. I have the control working, except it isn't saving the id to the db (a hidden field), just the title and url
Is this the right way to be using it? think so. I've been using this: http://doc.silverstripe.org/sapphire/en/reference/tablefield as a guide
some code:
static $has_many = array (
'Linketys' => 'Linkety',
);
$myTableField = new TableField(
'MyTableField', // fieldName
'Linkety', // sourceType
array(
'Title'=>'Title',
'URL'=>'URL'
), // fieldList
array(
'Title'=>'TextField',
'URL'=>'TextField'
), // fieldTypes
null, // filterField (legacy)
"Linkety.PageID",
$this->ID
);
// add some HiddenFields thats saved with each new row
$myTableField->setExtraData(array(
'PageID' => $this->ID ? $this->ID : '$RecordID'
));
$fields->addFieldToTab("Root.Content.Options", $myTableField);
Hmm, the documentation seems to be a bit off.
This is how I use table fields, not using extraData
Linkety.php
class Linkety extends DataObject {
public static $db = array(
'Title'=>'Varchar',
'URLSegment'=>'Varchar',
);
public static $has_one = array(
'Page' => 'Page'
);
}
In Page.php
$myTableField = new TableField(
'Linkety',
'Linkety',
array('Title'=>'Link title', 'URLSegment'=>'URL'),
array('Title'=>'TextField','URLSegment'=>'TextField'),
'PageID',
$this->ID,
$editExisting=true
);
$fields->addFieldToTab("Root.Content.Options", $myTableField);

Categories