I have the following Entities, with the main attributes:
Location
id
name
address
type
Station
location_id
trigram
altitude
Institute
location_id
abreviation
departement
Station and Institute are "inheriting" from Location: any location_id of those 2 tables refers to an id in the Location table.
As you can guess, the idea is that the different types of locations share common characteristics (gathered in Location) but also have independant ones (gathered in the Station and Institute tables).
I also have a entity "Item", and an Item can be placed and move in a location, no matter if it is a Station or an Institute.
So in my "move Item" form, I need to display all the locations in a dropdown list to select the required one. For that, I use GenemuFormBundle - select2.
My problem: I would like to display:
"location.name - station.trigam" if location.type is Station
"location.name - intitute.abreviation" if location.type is Institute
I know that what is displayed in the "select" dropdown list is determined by the "property" option:
$builder->add('location', 'genemu_jqueryselect2_entity', array(
'class' => 'MyBundle:Location',
'property' => 'labelSelect2',
'query_builder' => function(LocationRepository $lr) {
return $lr->createQueryBuilder('l')
->orderBy('l.name', 'ASC');}
))
"labelSelect2" refers to the function getLabelSelect2() of my entity Location.
But unfortunately, even though I can know the location.type, I don't know how to access station.trigram or institute.abreviation from the function Location::getLabelSelect2().
Any idea how to do that?
Related
I'm facing the following problem, where I need to design a filter engine with nested conditional logic.
I'm representing the logic as a tree where each branch first value is "OR" or "AND"; the second value can either be
a name of a function
another branch with further conditional structure
For example:
$tree = [
'nodetype' => 'ruleset',
'conditional' => 'OR',
'children' => [
[
'nodetype' => 'method',
'methodName' => 'startsWith'
'arguments' => [
'startsWithThis' => 'john',
'subject' => 'john doe'
]
],
[
'nodetype' => 'ruleset'
'conditional' => 'AND',
'children' => [
...more nesting
]
]
]
];
This tree is then recursively evaluated using Symfony's Expression language component (I've registered custom expressions for methods like startsWith etc).
The issue is that methods will differ from one another in their number of arguments they accept and the order of those arguments. I'm not sure how to store this in a relational database, without serialising the whole tree to a json string; which I'd like to avoid.
What I came up with so far is the following database structure:
filters:
id
name
filter_arguments:
id
filter_id
name
filter_usecases:
id
filter_id
filter_usecase_values
id
filter_usecase_id
filter_argument_id
value
However this table design does not address the issue of storing the "OR" / "AND" nature of a branch; and it also cannot represent nested filters (e.g. parent-child relation of branches).
How do I go about this? Is there a specific term that describes what I'm trying to achieve here? I'd gladly read more about this but I don't even know what to google.
To take a quick stab at it, going just from the data:
node
id
nodetype
conditional
method_name
children
id
parent_node_id
child_node_id
arguments
id
node_id
key
value
Note that the relationships (children) and argument data are not in the node table, but rather are specified by cross reference tables you will have to join with when you retrieve nodes. I would expect that it is the "children" table which will become the central actor in your recursing the tree, while "node" and "arguments" will be the joined tables.
Please let us know the solution you end up using successfully.
From the code snippet below :
modelBuilder.Entity<Product>()
.HasMany(e => e.ProductPictures)
.WithRequired(e => e.Product)
.WillCascadeOnDelete(false);
Which is WillCascadeOnDelete referring to?
Product has
-ProductID
-ProductNumber
-ProductDescription
-Cost
-UnitPrice
-OnHandQty
-StartDate
-CreateDate
ProductPicture has
-ProductPictureId
-ProductId
-IsThumb
-SortOrder
-ProductPictureNote
which means that ProductPicture is the dependent one. Is WillCascadeOnDelete referring to Product? meaning that if Product is deleted then the ProductId property of the ProductPicture will be set to null.
"Cascading delete" is a configuration of a relationship, not of an entity/table. Hence WillCascadeOnDelete is a method of ascadableNavigationPropertyConfiguration.
It means that if a Product deleted from the database, it's ProductPictures should not be deleted together with the Product. That's a property of this specific relationship, not of the Product table.
In WooCommerce you can add attributes to a product in two ways.
method #1
a. Create an attribute in Product->Attributes, set a name for it (i.e color), define it wether to be a select-field or a text-field. Save.
b. Edit product switch to attributes-tab, select "color" from the dropdown, fill in some values. Save.
method #2
Edit product, switch to attributes-tab, select "add custom attribute", set a name, fill in some values. Save.
Well, in method #1, the attributes are saved and connected over three tables. wp_terms, wp_term_taxonomies and wp_term_relationship
In method #2, the attributes are serialized and saved in wp_postmeta with '_product_attributes' as meta_key.
my problem
What I would like to do now is to move all attributes that are stored in the wp_postmeta table, to the wp_meta table and connect them correctly via wp_term_taxonomies and wp_term_relationship.
Is there any solution or plugin for that?
Moving them manually is not an option since there are over 500 of them.
Cheers,
There is a WooCommerce-REST-API that allows me to do that.
http://woothemes.github.io/woocommerce-rest-api-docs/
First I had to get the slugs and names of all attributes (not their values) that are stored in the wp_term_relathionship. Since there are just a few, I wrote them down.
Get a JSON list of all products
Iterate through the attributes of the product
Compare it's name and slug to the one written down
If slug doesn't match, write the values to an attribute with the correct slug.
Example:
Product has two attributes called "Color". The one attribute is stored in wp_term_relationships and has name "Color" and slug "pa_attr_color". The other color is stored in wp_postmeta as pa_attributes, and has name "Color" and slug "wrong_color". Now I want to move that values to the pa_attr_color.
$product = [product =>
[
id => 123,
attributes => [
[name => 'Color', 'slug' => 'pa_attr_color', options => ['red', 'blue']],
[name => 'color', 'slug' => 'wrong_color', options => ['yellow', 'green']]
]]
All I have to do now is to move the options from wrong_color to pa_attr_color.
If there's no pa_attr_color, than I simply had to create one.
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
My question is about: "adding field data to referenced node without replacing existing data".
For example, I have a project node with team members referencing the project. Each team member has on its node a location, ie, 'United Kingdom', 'United States', 'Australia'.
On the project node I have those exact same fields. I need to create a rule so that when a 'team member' node is created, its location is added to the project node without replacing existing content.
So for instance, a project node with a team member from the United Kingdom would also have on its location field, 'United Kingdom'. When a team member from 'United States' is added, the project's location field would have 'United Kingdom' and 'United States'. When a team member who's location is both Canada AND France is added, the project's location becomes United Kingdom, United States, Canada, and France.
Thanks!
Doing something like:
return array(
0 => array('value' => 'United Kingdom')
);
Just wouldn't work! It would replace the existing values. How do I make it so that it adds on to the existing values. Thanks!
Is it important to actually have the reference on the node or just to display the location.
If you are just worried about displaying the location then I think you can do this quite easily with a view.
There is a node reference reverse option I believe, but this would only display the team members and not the location.
If it is important to actually have the location information in the project node, then you will have to use hook_nodeapi op = save with code similar to Matts' answer.
Will something like this work? Basically we capture the current nodes cck location field (change the field names below to fit), load the reference node, and add the location data to it, and save it away. I've not added the code to check to see if the location already exists, but that's something for another day. - Hope it helps.
#some debug data below
#krumo ($node);
#print "<pre>". print_r($node,true) . "</pre>";
#$node is our current data set
# save the current $node nid into a variable
$nid = $node->nid;
#get the reference nid
$refnid = $node->field_refnid[0][nid];
#get the location
$currentlocation = $node->field_team_location[0][value];
# nowload the reference node
$refnode = node_load ($refnid);
# some debug data below
#krumo ($refnode);
#print "<pre>". print_r($refnode,true) . "</pre>";
$newlocation = array ("value"=>$currentlocation);
$refnode->field_loacations[] = $newlocation;
#now save the reference node
node_save ($refnode);
#drupal_goto ("node/$nid");
Have you tried:
return array(
array('value' => 'United Kingdom'),
array('value' => 'United States'),
);