Propel toArray Mechanics in Doctrine? - json

I was using Propel for a long time and now I want to try Doctrine.
In My Propel days I used PropelObjectCollection::toArray (for a collection) or PropelObject::toArray() for a single record to convert the PropelObject via array to json.
In my company we override the toArray method to store virtual columns in the array and then the json string.
For example:
public function toArray() {
$arr = parent::toArray();
$arr['full_name'] = $this->getFullName(); // full_name isnt part of the table, it's just a getter
return $arr;
}
When I turn this into json i have my full_name property in my json and then in my Extjs store Object (we use extjs).
Now I wanna try doctrine, but doctrine doesn't seem to allow this.
Can i override a function or property in my doctrine class, or can I do this by annotations, is it possible to generate a json with propertys ('first_name', 'last_name', 'full_name') if my Doctrine class only has the properties $first_name, $last_name and no $full_name
or is there a work around to achieve the same?
Thanks for your help
Edit:
I found something in JMSSerializerBundle if you use Annotations:
#VirtualProperty
use JMS\Serializer\Annotation\VirtualProperty;
at the top of my Doctrine Entity File and an example method
/**
*
* #VirtualProperty
* #return string
*/
public function getFullName() {
return $this->getName(). " mylastname";
}
my json then contains the virtual property full_name

Related

Yii2 field accessed only via magic method

/**
* This is the model class for table "hashtag".
*
* #property string $text
*
* #property TweetHashtag[] $tweetHashtags
* #property Tweet[] $tweets
*/
class Hashtag extends ActiveRecord
{
.........
public function getTweetHashtags()
{
return $this->hasMany(TweetHashtag::className(), ['hashtag_text' => 'text']);
}
/**
* #return \yii\db\ActiveQuery
*/
public function getTweets()
{
return $this->hasMany(Tweet::className(), ['id' => 'tweet_id'])->viaTable('tweet_hashtag', ['hashtag_text' => 'text']);
}
}
When I do in some component
$hashtags = Hashtag::find()
->with('tweets')
->where(['text' => $hashtagText])
->all();
foreach($hashtags as $hashtag)
{
print_r($hashtag->tweets);
}
It`s working but why tweets - field accessed only via magic method and how can i fix it? And tweetHashtags working well.
Class Tweet have same relationship but public function getHashtags() working without this problem.
Your question is not clear. Each method on a Component class that start with get (like getName) can be accessed with property form (e.g. name). On special case, relations of Yii's ActiveRecord, if you access to relation by property form, you get results. In fact $this->tweets is a shorthand for $this->getTweets()->all().
P.S: On Yii2 Document http://www.yiiframework.com/doc-2.0/guide-db-active-record.html#accessing-relational-data:
Note: While this concept looks similar to the object property feature,
there is an important difference. For normal object properties the
property value is of the same type as the defining getter method. A
relation method however returns an yii\db\ActiveQuery instance, while
accessing a relation property will either return a yii\db\ActiveRecord
instance or an array of these.
$customer->orders; // is an array of `Order` objects
$customer->getOrders(); // returns an ActiveQuery instance
This is useful for creating customized queries, which is described in the next section.

Laravel: decode JSON within Eloquent

I need to JSON decode a certain column in my Eloquent query. Is there a way to do this without breaking all apart?
So far I have this.
public function index()
{
return Offer::all();
}
Use an accessor on the model:
public function getColumnNameAttribute($value) {
return json_decode($value);
}
or use attribute casting to tell Laravel to do it automatically:
protected $casts = [
'column_name' => 'array',
];
The array cast type is particularly useful when working with columns that are stored as serialized JSON.
Note that you may have to stop json_encodeing your data if you use casts, as Laravel will now do that step automatically as well.

Doctrine 2 and MongoDB: How can I declare a field that will store a json document?

I would like to use MongoDB to store the logs of my json api. I am using the Doctrine 2 ODM.
Reading through the manual I understand that to store my json api response, I should use the #Field annotation with some well chosen data type. However, I do not find the one that would fit the BSON data type.
Is there any data type that will allow me to get things working with something like
$myRecord->setResponse($json_response);
and later on perform MongoDB queries like
db.Logs.find({"response.user": "foo"});
? What is the correct way to deal with this ?
After a few tries, here I am: the correct type to do this is the Hash type. Our document has a response field that looks like this:
/**
* #MongoDB\Hash
*/
protected $response;
And the call to set the value is as follow:
$myRecord->setResponse(json_decode($result, true));
This is it!
Edit: As I had some issues to retrieve the stored values, I came to use mongodb callbacks :/
/**
* (...)
* #MongoDB\HasLifecycleCallbacks
*/
class Log
{
(...)
/** #MongoDB\PreLoad */
public function preLoad(array &$data)
{
$data["response"] = json_encode($data["response"]);
}
/** #MongoDB\PrePersist */
public function prePersist()
{
$a_json = json_decode($this->getResponse(), true);
$this->setResponse($a_json);
}
Which makes the set call straight, by the way:
$myRecord->setResponse($result);

Doctrine 2 namespace issue

I'm using Zend Framework 1 with the Bisna library to integrate Doctrine 2. I generated my Entities from my database model with the Doctrine 2 CLI. This is all working fine, except for the setter methods for associated records. The argument they accept must be of a specific namespace (\Category here).
class Article
{
public function setCategory(\Category $category = null) {
$this->category = $category;
return $this;
}
}
However, when I do this:
$article = $this->em->getRepository('\Application\Entity\Article')->find(1);
$category = new \Application\Entity\Category();
$category->SetName('New Category');
$article->setCategory($category);
I get the following fatal error: Argument 1 passed to Application\Entity\CategoryField::setCategory() must be an instance of Category, instance of Application\Entity\Category given.
When I change the setter method to accept \Application\Entity\Category objects, it's working of course. Should I do this for every generated method, or are there other options? This is the first time I'm using namespaces, so it might be something simple.
You can always add this to the top of your class file: use \Application\Entity\Category; and then simply reference it later like so: public function setCategory(Category $category = null)
Check out: http://php.net/manual/en/language.namespaces.importing.php for more info about use
Otherwise you would have to reference the full namespace otherwise your application does not know that \Category is a reference to \Application\Entity\Category

Map JSON array of objects to #RequestBody List<T> using jackson

I'm having issues using Jackson to map a Javascript posted JSON array of hashes (Tag).
Here is the data received by the controller #RequestBody (It is send with correct json requestheader):
[{name=tag1}, {name=tag2}, {name=tag3}]
Here is the controller:
#RequestMapping(value = "purchases/{purchaseId}/tags", method = RequestMethod.POST, params = "manyTags")
#ResponseStatus(HttpStatus.CREATED)
public void createAll(#PathVariable("purchaseId") final Long purchaseId, #RequestBody final List<Tag> entities)
{
Purchase purchase = purchaseService.getById(purchaseId);
Set<Tag> tags = purchase.getTags();
purchaseService.updatePurchase(purchase);
}
When I debug and view the 'entities' value it shows as an ArrayList of generic objects, not as a list of objects of type 'Tag' as I would expect.
How can I get jackson to map a passed array of objects to a list of obejcts of type 'Tag'?
Thanks
It sounds like Spring is not passing full type information for some reason, but rather a type-erased version, as if declaration was something like List<?> tag. I don't know what can be done to fully resolve this (may need something from Spring integration team), but one work-around is to define your own type like:
static class TagList extends ArrayList<Tag> { }
and use that instead. This will retain generic parameterization through super-type declarations so that even if Spring only passes equivalent of TagList.class, Jackson can figure out the Tag parameter.
Another way to do this is to rather obtain an array than a List, as follows:
#RequestBody Tag[] entities
Jackson requires a default constructor with no parameters on custom Objects, so you'll need to simply add a default constructor to your Tag class.
In your case simply add to your Tag class:
public Tag(){}