I included the knplabs/doctrine-behaviors module in my ZF2 project to get the geocodable behavior. It adds a custom mapping type point which stores the values of lat and lng in a mysql point column.
The problem is, that the value of the entity field does not get hydrated in the result set, if I choose the array hydration mode. The result is an object and should be an array.
Is there a way to set a custom hydration strategie for a custom field type or anything else?
Current result:
array(1) {
["id"]=> int(269)
["address"]=> array(4) {
["id"]=> int(269)
["street"]=> string(14) "Rathausplatz 1"
["location"]=> object(Knp\DoctrineBehaviors\ORM\Geocodable\Type\Point)#1504 (2) {
["latitude":"Knp\DoctrineBehaviors\ORM\Geocodable\Type\Point":private]=> float(50.938212)
["longitude":"Knp\DoctrineBehaviors\ORM\Geocodable\Type\Point":private]=> float(6.959035)
}
}
}
Wanted result:
array(1) {
["id"]=> int(269)
["address"]=> array(4) {
["id"]=> int(269)
["street"]=> string(14) "Rathausplatz 1"
["location"]=> array(2) {
["latitude"]=> float(50.938212)
["longitude"] => float(6.959035)
}
}
}
Related
In our CouchDB document database, we have documents with different "status" property values like this:
doc1: {status: "available"},
doc2: {status: "reserved"},
doc3: {status: "available"},
doc4: {status: "sold"},
doc5: {status: "available"},
doc6: {status: "destroyed"},
doc7: {status: "sold"}
[...]
Now, I would like to write a map-reduce function that returns all distinct status values that exist over all documents: ["available", "reserved", "sold", "destroyed"].
My approach was to begin writing a map function that returns only the "status" property of each document:
function (doc) {
if(doc.status) {
emit(doc._id, doc.status);
}
}
And now, I would like to compare all map rows to each other such that no status duplicates will be returned.
The official CouchDB documentation seems to be very detailed and technical, but cannot really be projected to our use case, which does not have any nested structures like in blog posts but simply "flat objects" with a "status" property. Besides, our backend uses PouchDB as an adapter to connect to our remote CouchDB.
I discovered that when executing the reduce function below (which I implemented myself trying to understand what happens under the hood), some strange result will be returned.
function(keys, values, rereduce) {
var array = [];
if(rereduce) {
return values;
} else {
if(array.indexOf(values[0]) === -1) {
array.push(values[0]);
}
}
return array;
}
Result:
{
"rows": [
{
"key": null,
"value": "[reduce] [status] available,available,[status] sold,unknown,[status] available,[status] available,[status] available,reserved,available,[status] reserved,available,[status] available,[status] sold,reserved,[status] sold,sold,[status] available,available,[status] reserved,[status] reserved,[status] available,[status] reserved,available"
}
]
}
The reduce step seems to be executed exactly once, while the status loops sometimes have only a single value, then two or three values, without a recognizable logic or pattern.
Could somebody please explain to me the following:
How to retrieve an array with all distinct status values
What is the logic (or workflow) of the reduce function of CouchDB? Why do status rows have an arbitrary number of status values?
Thanks to #chrisinmtown's comment I was able to implement the distinct retrieval of status values using the following functions:
function map(doc) {
if(doc.status) {
emit(doc.status, null);
}
}
function reduce(key, values) {
return null;
}
It is important to send the query parameter group = true as well, otherwise the result will be empty:
// PouchDB request
return this.database.query('general/all-status', { group: true }).pipe(
map((response: PouchDB.Query.Response<any>) => response.rows.map((row: any) => row.key))
);
See also the official PouchDB documentation for further information how to use views and queries.
Under Symfony4.2, I have a Translate entity (id, gb_name, fr_name) and LocationCountry entity (id, ISO3166-2 name: GB,FR, DE…, translate_id)
I define a CSV file with 255 countries ("GB", "Great Britain", "Angleterre"…) and I want to push it in Translate and LocationCountry entities tables with DataFixture.
I read carefully https://symfony.com/doc/current/bundles/DoctrineFixturesBundle/index.html#sharing-objects-between-fixtures
and
php create fixtures with automatic relations
src/DataFixtures/TranslateFixtures.php:
if ($csv_handle) {
while ($item = fgetcsv($csv_handle, $csv_max_line_length, $csv_delimiter, $csv_enclosure)) {
$obj = new Translate();
$obj->setGbValue($item[1]);
$obj->setFrValue($item[2]);
$this->addReference('country'.$item[0], $obj);
$manager->persist($obj);
}
fclose($csv_handle);
}
$manager->flush();
I am not sure addReference should be before flush() ?
src/DataFixtures/LocationCountryFixtures.php:
if ($csv_handle) {
while ($item = fgetcsv($csv_handle, $csv_max_line_length, $csv_delimiter, $csv_enclosure)) {
$translate_country = $this->getReference('country'.$item[0]);
$obj = new LocationCountry();
$obj->setIso3166Name($item[0]);
$obj->setTranslate($translate_country);
$manager->persist($obj);
}
fclose($csv_handle);
}
$manager->flush();
}
public function getDependencies() {
return array(
Translate::class,
);
}
If I remove addReference Translate entity is well filled.
But with the code above, it returns error:
In SymfonyFixturesLoader.php line 76:
The "App\Entity\Translate" fixture class is trying to be loaded, but is not available. Make sure this class is defined as a service and tagged with "doctrine.fixture.orm".
I think to have the right Use:
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Common\Persistence\ObjectManager;
use Doctrine\Common\DataFixtures\DependentFixtureInterface;
use App\Entity\LocationCountry;
use App\Entity\Translate;
Thank for your help
Doctrine loads the fixture files in alphabetical order; that's why you get an error. You can consider using function getOrder in your fixtures in order to set which one will be load first.
EDIT :
You get an error because you don't provide the right class in your getDependencies method :
public function getDependencies() {
return array(
TranslateFixtures::class,
);
}
In this case, I just remove src/DataFixtures/TranslateFixtures.php
and change src/DataFixtures/LocationCountryFixtures.php to do all job:
if ($csv_handle) {
while ($item = fgetcsv($csv_handle, $csv_max_line_length, $csv_delimiter, $csv_enclosure)) {
//$translate_country = $this->getReference('country'.$item[0]);
$country = new LocationCountry();
$translate_country = new Translate();
$translate_country->setGbValue($item[1]);
$translate_country->setFrValue($item[2]);
$country->setIso3166Name($item[0]);
$country->setTranslateCountry($translate_country);
$manager->persist($translate_country);
$manager->persist($country);
}
fclose($csv_handle);
}
$manager->flush();
Here is a working Apollo subscription handler:
componentDidMount() {
const fromID = Meteor.userId();
const {toID} = this.props;
this.toID = toID;
this.props.data.subscribeToMore({
document: IM_SUBSCRIPTION_QUERY,
variables: {
fromID: fromID,
toID: toID,
},
updateQuery: (prev, {subscriptionData}) => {
if (!subscriptionData.data) {
return prev;
}
const newIM = subscriptionData.data.IMAdded;
// don't double add the message
if (isDuplicateIM(newIM, prev.instant_message)) {
return previousResult;
}
return update(prev, {
instant_message: {
$push: [newIM],
},
});
}
});
}
instant_message is an array of objects to be displayed. Each object contains a date field. I need to sort the objects in this array by date.
This approach used to work with beta versions of Apollo:
//update returns a new "immutable" list
const instant_message = update(previousResult, {instant_message: {$push: [newAppt]}});
instant_message.instant_message = instant_message.instant_message.sort(sortIMsByDateHelper);
return instant_message;
I can sort the array, but Apollo throws an error with the returned object-- e.g. it is not found in props when the render routine needs it.
What is the correct way to return the sorted array from updateQuery? Thanks in advance to all for any info.
It turns out it wasn't the sorting that was causing the anomaly. It appears that subscriptions fail if the __TYPENAME of the returned object doesn't match something else here -- either the varname used in this routine ('instant_message' in the above code), or the varname of the array of objects returned in props to the render function. Lining up all these things so that they are identical fixes it.
I'm a beginner with Doctrine ORM (v2.5.5) and Silex (v2.0.4)/Symfony (v3.1.6). I need to output my Date field to the YYYY-MM-DD format. Let's say I have this annotation and getter method on my Entity:
// src/App/Entity/Tnkb.php (simplified)
// 'expire' field
/**
* #ORM\Column(type="date")
*/
protected $expire;
// getter
public function getExpire()
{
return !is_object($this->expire) ? new \DateTime() : $this->expire->format('Y-m-d');
}
Here's my simplified controller for debugging purpose:
$app->get('/debug', function() use ($app) {
$tnkbRepo = $app['orm.em']->getRepository('\App\Entity\Tnkb');
$normalizer = new \Symfony\Component\Serializer\Normalizer\ObjectNormalizer();
$encoder = new \Symfony\Component\Serializer\Encoder\JsonEncoder();
$normalizer->setCircularReferenceHandler(function($obj){
return $obj->getId();
});
$serializer = new \Symfony\Component\Serializer\Serializer(array($normalizer), array($encoder));
$qb = $tnkbRepo->createQueryBuilder('c')
->setMaxResults(1);
//$query = $qb->getQuery(); // [1] <<-- this line produce proper YYYY-MM-DD format
//$query = $qb->select('c.expire')->getQuery(); // [2] <<-- this (manual select) line produce DateTime object.
$results = $query->getResult();
return $serializer->serialize($results, 'json');
});
With the first [1] line uncommented I got the proper output I wanted:
[more json output here]...,"expire":"1970-10-25",...
But with the second [2] line uncommented (I intendedly omitted other fields for testing) I got the following output, which wasn't what I expected:
[{"expire":{"timezone":{"name":"UTC","location":{"country_code":"??","latitude":0,"longitude":0,"comments":""}},"offset":0,"timestamp":25660800}}]
I also noticed, with the [2] line Doctrine seems to ignore my entity's getter method (I tried returning empty string). I expect the output will be the same as the [1] case, it makes me curious. My questions are:
How do I achieve the same proper YYYY-MM-DD format with the [2] version?
And why are they produce different output format?
Thank you.
UPDATE
More simplified /debug controller for testing (no serialization):
$app->get('/debug', function() use ($app) {
$tnkbRepo = $app['orm.em']->getRepository('\App\Entity\Tnkb');
$qb = $tnkbRepo->createQueryBuilder('c');
// [1a] normal query. doesn't return Entity, getExpire() isn't called.
/*$query = $qb->select('c.expire')
->setMaxResults(1)->getQuery();*/
// [2a] partial query. returns Entity, getExpire() called.
/*$query = $qb->select('partial c.{id,expire}')
->setMaxResults(1)->getQuery();*/
$results = $query->getResult();
var_dump($results);die;
});
Updated Entity method getExpire():
// src/App/Entity/Tnkb.php (simplified)
// 'expire' field
/**
* #ORM\Column(type="date")
*/
protected $expire;
protected $dateAsString = true;
protected $dateFormat = 'Y-m-d';
// getter
public function getExpire()
{
return ($this->expire instanceof \DateTime) ? $this->dateOutput($this->expire)
: $this->dateOutput(new \DateTime());
}
protected function dateOutput(\DateTime $date) {
if ($this->dateAsString) {
return $date->format($this->dateFormat);
}
return $date;
}
Controller dump results:
[1a] normal query:
// non-entity
array(1) { [0]=> array(1) { ["expire"]=> object(DateTime)#354 (3) { ["date"]=> string(26) "1970-10-25 00:00:00.000000" ["timezone_type"]=> int(3) ["timezone"]=> string(3) "UTC" } } }
[2a] partial object query:
// array of entity
array(1) { [0]=> object(App\Entity\Tnkb)#353 (23) { /* more properties */...["expire":protected]=> object(DateTime).../* more properties */
I found out this is normal behaviour with Doctrine, it has something to do with Partial Objects. See my comment below. Link: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/partial-objects.html
I don't think it's good practice to return a \DateTime sometimes but a formatted string other times. However maybe you have your reasons for doing this.
The only reason I can think of the difference in results is if Doctrine calls getters on the properties when loading an entity. I tested with a simple class which has the same expire property and getter. Returning the class still had the serialized (not formatted) \DateTime object, which would suggest that at some point your getter is being called and the property set to a new \DateTime.
My recommendation is to look at the DateTimeNormalizer provided by Symfony in 3.1. If you can't upgrade to 3.1 then you can easily build your own one. Then you can be sure you'll always have consistent \DateTime format in all your responses. You can all remove the ->format(...) from your getter then and always return a \DateTime object. I think this is a much cleaner approach.
Is there a way to retrieve the set-at-creations properties of an EmberJS object if you don't know all your keys in advance?
Via the inspector I see all the object properties which appear to be stored in the meta-object's values hash, but I can't seem to find any methods to get it back. For example object.getProperties() needs a key list, but I'm trying to create a generic object container that doesn't know what it will contain in advance, but is able to return information about itself.
I haven't used this in production code, so your mileage may vary, but reviewing the Ember source suggests two functions that might be useful to you, or at least worth reviewing the implementation:
Ember.keys: "Returns all of the keys defined on an object or hash. This is useful when inspecting objects for debugging. On browsers that support it, this uses the native Object.keys implementation." Object.keys documentation on MDN
Ember.inspect: "Convenience method to inspect an object. This method will attempt to convert the object into a useful string description." Source on Github
I believe the simple answer is: you don't find a list of props. At least I haven't been able to.
However I noticed that ember props appear to be prefixed __ember, which made me solve it like this:
for (f in App.model) {
if (App.model.hasOwnProperty(f) && f.indexOf('__ember') < 0) {
console.log(f);
}
};
And it seems to work. But I don't know whether it's 100% certain to not get any bad props.
EDIT: Adam's gist is provided from comments. https://gist.github.com/1817543
var getOwnProperties = function(model){
var props = {};
for(var prop in model){
if( model.hasOwnProperty(prop)
&& prop.indexOf('__ember') < 0
&& prop.indexOf('_super') < 0
&& Ember.typeOf(model.get(prop)) !== 'function'
){
props[prop] = model[prop];
}
}
return props;
}
Neither of these answers are reliable, unfortunately, because any keys paired with a null or undefined value will not be visible.
e.g.
MyClass = Ember.Object.extend({
name: null,
age: null,
weight: null,
height: null
});
test = MyClass.create({name: 'wmarbut'});
console.log( Ember.keys(test) );
Is only going to give you
["_super", "name"]
The solution that I came up with is:
/**
* Method to get keys out of an object into an array
* #param object obj_proto The dumb javascript object to extract keys from
* #return array an array of keys
*/
function key_array(obj_proto) {
keys = [];
for (var key in obj_proto) {
keys.push(key);
}
return keys;
}
/*
* Put the structure of the object that you want into a dumb JavaScript object
* instead of directly into an Ember.Object
*/
MyClassPrototype = {
name: null,
age: null,
weight: null,
height: null
}
/*
* Extend the Ember.Object using your dumb javascript object
*/
MyClass = Ember.Object.extend(MyClassPrototype);
/*
* Set a hidden field for the keys the object possesses
*/
MyClass.reopen({__keys: key_array(MyClassPrototype)});
Using this method, you can now access the __keys field and know which keys to iterate over. This does not, however, solve the problem of objects where the structure isn't known before hand.
I use this:
Ember.keys(Ember.meta(App.YOUR_MODEL.proto()).descs)
None of those answers worked with me. I already had a solution for Ember Data, I was just after one for Ember.Object. I found the following to work just fine. (Remove Ember.getProperties if you only want the keys, not a hash with key/value.
getPojoProperties = function (pojo) {
return Ember.getProperties(pojo, Object.keys(pojo));
},
getProxiedProperties = function (proxyObject) {
// Three levels, first the content, then the prototype, then the properties of the instance itself
var contentProperties = getPojoProperties(proxyObject.get('content')),
prototypeProperties = Ember.getProperties(proxyObject, Object.keys(proxyObject.constructor.prototype)),
objectProperties = getPojoProperties(proxyObject);
return Ember.merge(Ember.merge(contentProperties, prototypeProperties), objectProperties);
},
getEmberObjectProperties = function (emberObject) {
var prototypeProperties = Ember.getProperties(emberObject, Object.keys(emberObject.constructor.prototype)),
objectProperties = getPojoProperties(emberObject);
return Ember.merge(prototypeProperties, objectProperties);
},
getEmberDataProperties = function (emberDataObject) {
var attributes = Ember.get(emberDataObject.constructor, 'attributes'),
keys = Ember.get(attributes, 'keys.list');
return Ember.getProperties(emberDataObject, keys);
},
getProperties = function (object) {
if (object instanceof DS.Model) {
return getEmberDataProperties(object);
} else if (object instanceof Ember.ObjectProxy) {
return getProxiedProperties(object);
} else if (object instanceof Ember.Object) {
return getEmberObjectProperties(object);
} else {
return getPojoProperties(object);
}
};
In my case Ember.keys(someObject) worked, without doing someObject.toJSON().
I'm trying to do something similar, i.e. render a generic table of rows of model data to show columns for each attribute of a given model type, but let the model describe its own fields.
If you're using Ember Data, then this may help:
http://emberjs.com/api/data/classes/DS.Model.html#method_eachAttribute
You can iterate the attributes of the model type and get meta data associated with each attribute.
This worked for me (from an ArrayController):
fields: function() {
var doc = this.get('arrangedContent');
var fields = [];
var content = doc.content;
content.forEach(function(attr, value) {
var data = Ember.keys(attr._data);
data.forEach(function(v) {
if( typeof v === 'string' && $.inArray(v, fields) == -1) {
fields.push(v);
}
});
});
return fields;
}.property('arrangedContent')