symfony: how to loop through fields of Doctrine object - symfony1

I need to loop through a list of fields in a custom validator to compare the value against a value already stored in the database.
My code here:
$healthUser = PersonTable::getInstance->getHealthUser(trim($values['nhi']));
if ($healthUser->getNHI() == trim($values['nhi']) &&
$healthUser->getName() != trim($values['name'])){
//Also loop through all fields and show differences
foreach (array('suite','hnr_street','suburb','city','postcode','postal_address')
as $field){
if ($value[$field] != $healthUser->getFieldName()){
//How do I get the field name from $field?--^^^^^^^^^^
$errorSchemaLocal->addError(new sfValidatorError($this,
'fieldIsDifferent', $healthUser->getFieldName()),
$field);
}
}
SO basically i need to create the getter function from the field name in $field.
Any idea how to do this?

Doctrine record implements ArrayAccess interface. You can simply access the record as an array:
if ($value[$field] != $healthUser[$field]) {
// ...
}
You can also use sfInflector to construct a getter name:
$getField = sprintf('get%s'), ucfirst(sfInflector::cammelize($field)));
if ($value[$field] != $healthUser->$getField()) {
// ...
}

Related

BeanItemContainer unique property values

I am using BeanItemContainer for my Grid. I want to get a unique list of one of the properties. For instance, let's say my beans are as follows:
class Fun {
String game;
String rules;
String winner;
}
This would display as 3 columns in my Grid. I want to get a list of all the unique values for the game property. How would I do this? I have the same property id in multiple different bean classes, so it would be nice to get the values directly from the BeanItemContainer. I am trying to avoid building this unique list before loading the data into the Grid, since doing it that way would require me to handle it on a case by case basis.
My ultimate goal is to create a dropdown in a filter based on those unique values.
There isn't any helper for directly doing what you ask for. Instead, you'd have to do it "manually" by iterating through all items and collecting the property values to a Set which would then at the end contain all unique values.
Alternatively, if the data originates from a database, then you could maybe retrieve the unique values from there by using e.g. the DISTINCT keyword in SQL.
In case anyone is curious, this is how I applied Leif's suggestion. When they enter the dropdown, I cycle through all the item ids for the property id of the column I care about, and then fill values based on that property id. Since the same Grid can be loaded with new data, I also have to "clear" this list of item ids.
filterField.addFocusListener(focus->{
if(!(filterField.getItemIds() instanceof Collection) ||
filterField.getItemIds().isEmpty())
{
BeanItemContainer<T> container = getGridContainer();
if( container instanceof BeanItemContainer && getFilterPropertyId() instanceof Object )
{
List<T> itemIds = container.getItemIds();
Set<String> distinctValues = new HashSet<String>();
for(T itemId : itemIds)
{
Property<?> prop = container.getContainerProperty(itemId, getFilterPropertyId());
String value = null;
if( prop.getValue() instanceof String )
{
value = (String) prop.getValue();
}
if(value instanceof String && !value.trim().isEmpty())
distinctValues.add(value);
}
filterField.addItems(distinctValues);
}
}
});
Minor point: the filterField variable is using the ComboBoxMultiselect add-on for Vaadin 7. Hopefully, when I finally have time to convert to Vaadin 14+, I can do something similar there.

adding objects to list if it doesn't contain it

I'm trying to add object to a list only if it wasn't added already .. like this:
for (var interest in poll.poll.interests) {
InterestDrop n = new InterestDrop(interest, false);
print(interest);
print(dropInterestsList);
print(dropInterestsList.contains(n));
if (!(dropInterestsList.contains(n))){
dropInterestsList.add(n);
}
}
but this always return false and add the object even when its already there ... how to solve this?
ANSWER:
class InterestDrop {
String name;
bool isClicked;
InterestDrop(this.name, this.isClicked);
bool operator == (o) => o is InterestDrop && name == o.name && isClicked == o.isClicked;
int get hashCode => hash2(name.hashCode, isClicked.hashCode);
}
You need to override the equality operator in your custom class.
From the docs:
The default behavior for all Objects is to return true if and only if
this and other are the same object.
So your contains method will only return true if your array contains the exact object you are comparing against.
You need to do something like this:
class InterestDrop {
operator ==(InterestDrop other) => identifier == other.identifier;
}

groovy&grails- How to go over array of object?

I have an array of Person object (person.first person.last).
To find out if the person have first name I have to "run" on the array.
I try the following but I got error:
person.eachWithIndex { String persons, i ->
if(persons.first=='')
println(''error)
}
How should I manipulate the object array?
Are you looking for something like:
class Person {
def first
def last
}
def persons = [ new Person(first:'',last:'last'), new Person(first:'john',last:'anon')]
persons.eachWithIndex { person, i ->
if(person.first==''){
println("error at person in position $i")
}
}
Since you doesn't add more details, I don't know what you're looking for when you say manipulate object array so there is some samples:
To manipulate the array objects you can add the statements in the each itself, for example to add a notDefined as a first for person where first=='' you can use:
persons.eachWithIndex { person, i ->
if(person.first==''){
person.first = 'notDefined'
println("first as notDefined for person in position $i")
}
}
To remove the elements where first =='' you can use removeAll method to remove the undesired elements from the array:
persons.removeAll { person ->
!person.first
}
EDIT BASED ON COMMENT:
If you want to remove null elements from your list, you can do it with the expression you use in your comment:
def persons = [ new Person(first:'pepe',last:'last'), null]
persons.removeAll([null])
println persons.size() // prints 1 since null element is removed
However seems that you're not trying to remove null elements instead you're trying to remove elements where all the properties are null, in your case you want to remove: new Person(first:null,last:null). To do so you can try with the follow code:
def persons = [ new Person(first:'pepe',last:'last'), new Person(first:null,last:null)]
persons.removeAll{ person ->
// get all Person properties wich value is not null
// without considering class propertie wich is implicit in all classes
def propsNotNull = person.properties.findAll { k,v -> v != null && k != 'class' }
// if list is empty... means that all properties are null
return propsNotNull.isEmpty()
}
println persons.size() // prints 1
Hope this helps,

How to cache aggregate column values on Doctrine_Record instance?

Lets say i have a record class that often gets queried with dyanmic colums that are MySQL aggregate values:
$results = Doctrine_Core::getTable('MyRecord')->creatQuery('m')
->select('m.*, AVG(m.rating) as avg_rating, SUM(m.id) as nb_related')
->innerJoin('m.AnotherRecords a')
->where('m.id = ?')
->fetchOne();
Now lets say i want a method on that record to check if the aggregate columns exist from when the record was queried, and if not then i want to go ahead an issue a separate query to get these values:
// this doesnt actually work because of filterSet and filterGet
// but its general idea
public function getAverageRating($wtihNbRelated = false)
{
if(!isset($this->avg_rating) || ($withNbRelated && !isset($this->nb_related))
{
$rating = $this->getTable()->getAverageRating($this, $withNbRelated);
$this->avg_rating = $rating['avg_rating'];
if($withNbRealted)
{
$this->nb_related = $rating['nb_related'];
}
}
return $withNbRelated
? array('avg_rating' => $this->avg_rating, 'nb_related' => $this->nb_related)
: array('avg_rating' => $this->avg_rating);
}
Is there an easy way (ie. not writing a custom hydrator) to do this?
Simple answer really. I forgot that Doctrine prefixes all its direct protected members with _. So, even though i initially tried manipulating the data member i was forgot the prefix giving me the same result as if i tried $this->avg_rating or its accessor method. The solution was:
public function getAverageRating($wtihNbRelated = false)
{
if(!isset($this->_data['avg_rating']) || ($withNbRelated && !isset($this->_data['nb_related']))
{
$rating = $this->getTable()->getAverageRating($this, $withNbRelated);
$this->_data['avg_rating'] = $rating['avg_rating'];
if($withNbRealted)
{
$this->_data['nb_related'] = $rating['nb_related'];
}
}
return $withNbRelated
? array('avg_rating' => $this->_data['avg_rating'], 'nb_related' => $this->_data['nb_related'])
: array('avg_rating' => $this->_data['avg_rating']);
}

Disable automatic index on related object id from yml

Doctrine Automatically creates indexes on columns that are used to define object relations,
For example
user: id, name
message: id, sender_id, receiver_id, message
if I define relationship between message and user in a way that message has one Sender and has one Receiver, doctrine will automatically index sender_id and receiver_id fields when I generate sql from model. I would like to disable index on sender, because I manually create index with sender_id and receiver id together. How can I disable auto generated index?
Hello I assumed you were using MySQL, and took a look in Doctrine/Export/Mysql.php
I found this :
// build indexes for all foreign key fields (needed in MySQL!!)
if (isset($options['foreignKeys'])) {
foreach ($options['foreignKeys'] as $fk) {
$local = $fk['local'];
$found = false;
if (isset($options['indexes'])) {
foreach ($options['indexes'] as $definition) {
if (is_string($definition['fields'])) {
// Check if index already exists on the column
$found = $found || ($local == $definition['fields']);
} else if (in_array($local, $definition['fields']) && count($definition['fields']) === 1) {
// Index already exists on the column
$found = true;
}
}
}
if (isset($options['primary']) && !empty($options['primary']) &&
in_array($local, $options['primary'])) {
// field is part of the PK and therefore already indexed
$found = true;
}
if ( ! $found) {
if (is_array($local)) {
foreach($local as $localidx) {
$options['indexes'][$localidx] = array('fields' => array($localidx => array()));
}
} else {
$options['indexes'][$local] = array('fields' => array($local => array()));
}
}
}
}
If I understand correctly, to disable the index should be part of the primary key.

Resources