Silverstripe drop down field does not show saved value as selected - silverstripe

I have created a drop down field in the CMS like so:
class ProductPage extends Page {
//.....
private static $has_one = [
'TeaserImage'=>Image::Class,
'LinkedProduct'=>'Product'
];
public function getCMSFields(){
$fields = parent::getCMSFields();
$productLinkField = DropdownField::create('LinkedProduct', 'Link a Product', Product::get()->map('ID', 'ProductName'));
$productLinkField->setEmptyString('(Select one)');
$fields->addFieldToTab('Root.Main', $productLinkField, 'Content');
return $fields;
}
}
The problem is that when I select a value and save/publish the page the drop down goes back to "Select one" instead of showing the saved selection.
I have not checked the database to see if the value is being stored but I assume it is.
EDIT: Not a duplicate.
The suggested duplicate dealt with removing a field from the CMS.
This question deals with setting the drop down value to the saved selection.
The answers are however similar. The user must always append ID to a has_one field for the CMS to interact with it.

By default SilverStripe appends an 'ID' parameter to the end of has_one relation fields when saving them in the database.
As such when you override the field for relations you will need to append 'ID' to the field identifier.
DropdownField::create('LinkedProductID', 'Link a Product', Product::get()->map('ID', 'ProductName'));

Related

Getting data from the database based on dropdown selection in Symfony forms

I have two Entities, First one is the Company Entity and the other one is Events Events Entity.
ManyToOne(targetEntity="App\Entity\Company", inversedBy="events"
On the events from I have created a drop-down doing something like following.
->add ( 'company' , EntityType::class , [
'class' => Company::class ,
'choice_label' => function ( Company $company ) {
return $company->getName ();
}
is there any way I can obtain other values from the database for the selected company. In the database, there is a column called app_client_id which I want to get on dropdown selection so I can use that to call external API'S.
By default, in the dropdown, you get the result of the __toSring() function in the entity. Consider setting there what you want to read when selecting.

WP-Members / How to update value of radio button value?

I'm using WP-Members. And I'm using wp_update_user function to update value.
When I try to update the "text" value, it is updated. Like this.
$test = array ( 'ID' => $id,'first_name' => $first_name);
But, when it comes to update the value of "radio", it didn't work.
$test = array ( 'ID' => $id,'plan' => $plan);
$plan is a string value
setting of the "plan"
How can I update the radio button value?
wp_update_user() only updates WordPress native fields. If you have a radio field in your form, then that would certainly be a custom field not native to WP. Any custom field is a user meta field and must be updated with update_user_meta():
update_user_meta( $id, 'plan', $plan );
Note that this would be true of any field that is not a native WP field (i.e. any custom fields you added in WP-Members, or using any other method).

Drupal - Importing a taxonomy with migrate module from a table and creating/updating existing terms

I need to import a list of terms into my taxonomy from a source I loaded in the database.
The problem is I allready have this taxonomy on my site (loaded wihtout migrate) with terms that are used by reference in other content, so I got to keep existing term and update them or create the new ones.
To link my taxonomy source and the existing taxonomy I have an unique code for each term, so I added a code field to my vocabulary and filled it for each existing term.
I am currently able to create and update terms with my current Migration class, but if the name of my term on the site and the name of the term in my source is different, the import will create a new term instead of updating its name even if the code is the same.
Here my Migration Class :
class TotoMigration extends Migration {
private $list_term = array();
public function __construct($arguments) {
parent::__construct();
$this->softDependencies = array('TotoParent');
// get data from the custom table containing the new terms to create or update
$query = db_select('toto', 'f')
->fields('f', array(
'CODE', // code
'LIBLONG', // name
'PARENT', // parent
)
);
$this->source = new MigrateSourceSQL($query);
$this->destination = new MigrateDestinationTerm('toto_tax');
$this->map = new MigrateSQLMap($this->machineName,
array(
'CODE' => array('type' => 'varchar',
'length' => 5,
'not null' => TRUE,
'description' => 'Code',
)
),
MigrateDestinationTerm::getKeySchema()
);
$this->addFieldMapping('name', 'LIBLONG');
$this->addFieldMapping('field_code', 'CODE');
$this->addFieldMapping('parent', 'PARENT')
->arguments(array('source_type' => 'tid'))
->sourceMigration('TotoParent');
// create a list of existing toto terms with code => tid
$list_term = db_query("select fc.field_code_value, ttd.tid
from taxonomy_term_data ttd
left join taxonomy_term_hierarchy tth on tth.tid=ttd.tid
left join field_data_field_code fc on fc.entity_id = ttd.tid
where ttd.vid=10
and tth.parent!=0;")->fetchAllKeyed();
}
public function prepareRow($row) {
// Always include this fragment at the beginning of every prepareRow()
// implementation, so parent classes can ignore rows.
if (parent::prepareRow($row) === FALSE) {
return FALSE;
}
// if the destination is not mapped in migrate we tell him where to go
if (!isset($row->migrate_map_destid1) && isset($list_term[$row->CODE])) {
$row->migrate_map_destid1 = $list_term[$row->CODE];
}
}
}
I then load the import with drush (and --update option).
I must be missing something, if anyone got a clue it will be welcome.
After many tries, the problem reside in the fact the module Migrate does not support Creating content and Updating content in the same migration class (I even read it will sometime claim to update content and just do nothing).
So the solution is pretty simple, create 2 classes :
One for Creating content
One for Updating content
Your Creating class will be the same.
Your Updating class will need to have a systemeOfRecord set to DESTINATION :
$this->systemOfRecord = Migration::DESTINATION;
So it knows to only update and not recreate the content, it will keep current fields not mapped and update fields mapped that are not part of the MigrateSQLMap :
$this->map = new MigrateSQLMap($this->machineName,array(...));
The tricky part will be to find corresponding nid/tid of your content so you can map it to your imported data and then to separate data used to update or create content.

SilverStripe GridField: too many versions of DataObject get created

TL;DR When creating/saving a versioned DataObject with relation to some page, two entries are created in the corresponding versions table (instead of one).
I'm trying to version some DataObject and have the Versioned extension applied as follows:
class Testobject extends DataObject {
static $has_one = array(
'Page' => 'Page'
);
static $extensions = array(
"Versioned('Stage', 'Live')",
);
Testobjects are being managed in a GridField on some page like so:
class PageContent extends Page {
public static $has_many = array(
"Testobjects" => "TestObject"
);
public function getCMSFields() {
$fields = parent::getCMSFields();
$config = GridFieldConfig_RelationEditor::create();
$gridField = new GridField(
'Testobjects',
'Testobject',
$this->Testobjects(),
$config);
$fields->addFieldToTab('Root.Main', $gridField);
}
Now, whenever i add or save some Testobject in the GridField's EditForm, two new entries show up in the Testobject_versions table. For comparsion, when i save a page in the SiteTree, only one entry in the corresponding versions table is created.
As there will we thousands of these DataObjects on a page, i'm worried about this duplication filling up my database. Is there a way to get around this?
Further recognitions:
On creation of a new Testobject, the first entry in the versions table has it's PageID field set to 0, the second entry has set the actual PageID of the corresponding page.
If I replace $this->Testobjects() in the GridField construction by Testobject::get(), only one entry shows up in the versions table.
onBeforeWrite is called twice when using $this->Testobjects()
So it seems setting the relation to the page happens after a first 'write()', then another 'write()' is called. But where in the code does this happen?
If you're editing your page/testobject in the main section of the CMS (# '/admin/pages'), you can try this somewhat hackish trick in your TestObject class
public function getCMSFields(){
$fields = parent::getCMSFields();
$fields->push( new HiddenField('PageID','PageID', Controller::curr()->CurrentPageID());
return $fields;
}
This is not ideal for the following reasons:
hard to test with unit test controller
awareness of the controller in the model is bad
IMHO
But it can be a reasonable fix if it works for you

One to one relationship in Silverstripe

I'll try and put this as simply as possible but basically what I am trying to achieve is this.
There are two page types with a one to one relationship, car and owner. I want to be able te be able to select an owner through a dropdown on the car page. If an owner is already linked to another car I don't want it to appear in the dropdown.
I know that I'll need an if statement but I I'm finding it hard to puzzle out how it should go. I followed this tutorial to create the dropdown and it worked quite well.
Thanks in advance.
You can modify the function that gives you the dropdown values. Your DataObject::get() call
can have a filter for the second argument. Simply select all owners that have a CarID of 0.
So, from the tutorial you provided, you can use this modified code:
new DropdownField(
'OwnerID',
'Please choose an owner',
Dataobject::get("Owner","CarID='0'")->map("ID", "Title", "Please Select")
);
2 things to note:
This assumes your DataObjects are called Car and Owner (change as necessary, but keep the ID at the end of the name as it is written above)
This may not work depending how you set up the relationships with the $has_one assignments on your DataObjects. If there is no CarID field on the Owner table, then this code won't help you (you may have it set up vice-versa). In that case, you'll have to create a function that loops through all cars, and then removes the DataObjects from that DataObjectSet that have an OwnerID of 0. Add a comment if this isn't making sense.
Benjamin Smith' answer is perfectly valid for the dropdown you were asking for, just wanted to point to another approach: instead of taking care of the one-to-one relation yourself, there's the 'HasOneComplexTableField' handling this for you.
use the following code for your Car class:
class Car extends Page {
public static $has_one = array(
'Owner' => 'Owner'
);
function getCMSFields() {
$fields = parent::getCMSFields();
$tablefield = new HasOneComplexTableField(
$this,
'Owner',
'Owner',
array(
'Title' => 'Title'
)
);
$tablefield->setParentClass('Car');
$tablefield->setOneToOne();
$tablefield->setPermissions(array());
$fields->addFieldToTab('Root.Content.Owner', $tablefield);
return $fields;
}
}
note the 'setOneToOne()' call, telling the tablefield to only let you select Owners which aren't already selected on another car.
you'll find more information on this in the silverstripe tutorial: http://doc.silverstripe.org/framework/en/tutorials/5-dataobject-relationship-management

Resources