How to automatically prepend namespace to tags when bulding XML from object? - xml2js

Let's say I have this object:
{
myRoot: {
$: {
'xmlns:abc': 'blahblah',
}
one: 'a',
two: 'b',
three: 'c'
}
}
How can I have the builder build the tags with the abc: prefix so that I don't have to change the names of the attributes in my object? In other words, I want the XML to look like:
<abc:myRoot xmlns:abc='blahblah'>
<abc:one>a</abc:one>
<abc:two>b</abc:two>
<abc:three>c</abc:three>
</abc:myRoot>
I honestly don't understand why it doesn't just do that since I did provide a namespace in the root tag. I tried passing a tagNameProcessor function to the Builder() constructor and that didn't work.
So now I have to manually specify attributes in my object like 'abc:one' instead of one:.

The answer is simply that you do use tagNameProcessor, but not with the Builder(). That functionality does not exist as of this writing. You do it in Parser(). That means if you use build to turn an Object into an XML string, once you have that string, additionally have Parser process the string.
Honestly, I just end up switching to xmlbuilder. Since this is not about xmlbuilder I won't post the answer here but let me know if you need an example.

Related

How to access values from list of maps in Apache camel message body

Perhaps this is easy, but I am somehow not able to crack it yet. Message body for an exchange is basically a list of maps with both key & value being string. As example,
[{'key'='val1'}, {'key'='val2'},...]
I am using simple expression to set this as a property which I would be using in subsequent routes. This is how I am setting it:
.setProperty("myProperty", simple("${body}"))
But this sets the complete body. I just want to (somehow) set only the values part to avoid setting the entire list of maps. What I have tried and not working so far:
.setProperty("myProperty", simple("${body}['key']"))
.setProperty("myProperty", simple("${body}[*]['key']"))
.setProperty("myProperty", simple("${body}[0]['key']")) // this returns only the first value, I want all
Any idea/suggestion how can I achieve this ?
You can access every level of your body with Simple expressions:
${body} // get whole list of maps
${body[0]} // get first map in the list (index 0)
${body[0][key]} // get value of key "key" from the first map in the list
What you cannot do in a Simple expression is a conversion of your data structure in another one.
However, you can simply plug a Java bean into your route
from("direct:start")
...
.bean(MyConversionBean.class)
...;
And do the conversion with Java
public class MyConversionBean {
public List<String> convertBody() {
// extract all values (or whatever) with Java;
return listOfValues;
}
}

Laravel Query Builder : Where pivot not in

wherePivotIn is mentionend here (under Filtering Relationships Via Intermediate Table Columns) but I can't find anything about the opposite function.
As the wherePivotIn already exists but not the wherePivotNOTIn, I edited this file : vendor/laravel/framework/src/Illuminate/Database/Eloquant/Relations/BelongsToMany.php
And added this function
public function wherePivotNotIn($column, $values, $boolean = 'and', $not = false)
{
$this->pivotWhereIns[] = func_get_args();
return $this->whereNotIn($this->table.'.'.$column, $values, $boolean, $not);
}
Now the wherePivotNotIn exist and is working. But my question is:
Is it safe to update this file?
In case of update, I guess I will lose this...
After dinging a bit, I found out that the whereIn method accept more than 2 arguments.
We juste have to use it like that to use a "wherePivotNotIn"
->wherePivotIn($column,$value,'and','NotIn')
No need to declare a new class or using scope!
Yeah don't update vendor files that's a no no. Instead , create a class that extends BelongsToMany and put your implementation in there. You'll lose your changes as soon as the file updates.
Never edit what is inside the vendor directory. Create your own method to meet your need, in case it does not exist.
In your case, you can define a Local Query Scope
It will look like:
class Task extends Model
{
public function scopeWherePivotNotIn($query)
{
/**/
}
}
$tasks = Task::wherePivotNotIn()->get();

How to get all FAL File Objects which are referenced?

I'm trying to make a extbase extension for TYPO3 to get alle file objects with mimetype image/... which referenced by any content, plugin or fluid in typo3.
But i don't know which is the best way to get these data. How should i create a model in my extension and how should i create the correct repository?
If i create a custom query i'm not sure how to return a complete FAL Object which contains any data (like metadata) etc.
hope someone could help me to find the right way, and maybe has a example or something.
thanks a lot
You could do it like this, details are at the bottom:
Get all file references.
Go through them, retrieve the referenced file for each of them and retain only the ones where the field mime_type starts with image/.
There are two things you probably need to watch out for:
The field mime_type needs to be up to date. Check the FAL scheduler indexing task for that.
Performance. Depending on the number of files you have, it could be much faster to do this with a custom SQL statement which makes use of a JOIN. But you should only do that if performance is a problem.
How to get all file references:
First, build your own empty file reference class:
namespace Vendor/Extkey/Domain/Model;
class FileReference extends \TYPO3\CMS\Extbase\Domain\Model\FileReference {}
Make sure to configure it in your TypoScript to be serialized to the table sys_file_reference:
config.tx_extbase.persistence {
classes {
Vendor\Extkey\Domain\Model\FileReference {
mapping {
tableName = sys_file_reference
}
}
}
}
Add a repository for the references:
namespace Vendor/Extkey/Domain/Repository;
class FileReferenceRepository extends \TYPO3\CMS\Extbase\Persistence\Repository {
public function initializeObject() {
/** #var \TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface */
$defaultQuerySettings = $this->objectManager->get('TYPO3\\CMS\\Extbase\\Persistence\\Generic\\QuerySettingsInterface');
$defaultQuerySettings->setRespectStoragePage(FALSE);
$this->setDefaultQuerySettings($defaultQuerySettings);
}
}
The reference class can be empty, but the repository needs it to be there in order to work correctly. Make sure you add the default query settings to ignore the page id, so you get all non-hidden and non-deleted file references by calling $fileReferenceRepository->findAll().
How to check the MIME-type of each referenced file:
You can get the MIME-type of each reference by calling
$fileReference->getOriginalResource()->getMimeType()
This should automatically fetch the original file from storage and read its MIME-type.

RavenDB Index created incorrectly

I have a document in RavenDB that looks looks like:
{
"ItemId": 1,
"Title": "Villa
}
With the following metadata:
Raven-Clr-Type: MyNamespace.Item, MyNamespace
Raven-Entity-Name: Doelkaarten
So I serialized with a type MyNamespace.Item, but gave it my own Raven-Entity-Name, so it get its own collection.
In my code I define an index:
public class DoelkaartenIndex : AbstractIndexCreationTask<Item>
{
public DoelkaartenIndex()
{
// MetadataFor(doc)["Raven-Entity-Name"].ToString() == "Doelkaarten"
Map = items => from item in items
where MetadataFor(item)["Raven-Entity-Name"].ToString() == "Doelkaarten"
select new {Id = item.ItemId, Name = item.Title};
}
}
In the Index it is translated in the "Maps" field to:
docs.Items
.Where(item => item["#metadata"]["Raven-Entity-Name"].ToString() == "Doelkaarten")
.Select(item => new {Id = item.ItemId, Name = item.Title})
A query on the index never gives results.
If the Maps field is manually changed to the code below it works...
from doc in docs
where doc["#metadata"]["Raven-Entity-Name"] == "Doelkaarten"
select new { Id = doc.ItemId, Name=doc.Title };
How is it possible to define in code the index that gives the required result?
RavenDB used: RavenHQ, Build #961
UPDATE:
What I'm doing is the following: I want to use SharePoint as a CMS, and use RavenDB as a ready-only replication of the SharePoint list data. I created a tool to sync from SharePoint lists to RavenDB. I have a generic type Item that I create from a SharePoint list item and that I serialize into RavenDB. So all my docs are of type Item. But they come from different lists with different properties, so I want to be able to differentiate. You propose to differentiate on an additional property, this would perfectly work. But then I will see all list items from all lists in one big Items collection... What would you think to be the best approach to this problem? Or just live with it? I want to use the indexes to create projections from all data in an Item to the actual data that I need.
You can't easily change the name of a collection this way. The server-side will use the Raven-Entity-Name metadata, but the client side will determine the collection name via the conventions registered with the document store. The default convention being to use the type name of the entity.
You can provide your own custom convention by assigning a new function to DocumentStore.Conventions.FindTypeTagName - but it would probably be cumbersome to do that for every entity. You could create a custom attribute to apply to your entities and then write the function to look for and understand that attribute.
Really the simplest way is just to call your entity Doelkaarten instead of Item.
Regarding why the change in indexing works - it's not because of the switch in linq syntax. It's because you said from doc in docs instead of from doc in docs.Items. You probably could have done from doc in docs.Doelkaartens instead of using the where clause. They are equivalent. See this page in the docs for further examples.

Document serialization with Doctrine MongoDB ODM

I'm trying to code a class handling serialization of documents by reading their metadata. I got inspired by this implementation for entities with Doctrine ORM and modified it to match how Doctrine ODM handles documents. Unfortunatly something is not working correctly as one document is never serialized more than once even if it is refered a 2nd time thus resulting on incomplete serialization.
For example, it outputs this (in json) for a user1 (see User document) that belongs to some place1 (see Place document). Then it outputs the place and the users belonging to it where we should see the user1 again but we don't :
{
id: "505cac0d6803fa1e15000004",
login: "user1",
places: [
{
id: "505cac0d6803fa1e15000005",
code: "place1",
users: [
{
id: "505c862c6803fa6812000000",
login: "user2"
}
]
}
]
}
I guess it could be related to something preventing circular references but is there a way around it ?
Also, i'm using this in a ZF2 application, would there be a better way to implement this using the ZF2 Serializer ?
Thanks for your help.
I have a serializer already written for DoctrineODM. You can find it in http://github.com/superdweebie/DoctrineExtensions - look in lib/Sds/DoctrineExtensions/Serializer.
If you are are using zf2, then you might also like http://github.com/superdweebie/DoctrineExtensionsModule, which configures DoctrineExtensions for use in zf2.
To use the Module, install it with composer, as you would any other module. Then add the following to your zf2 config:
'sds' => [
'doctrineExtensions' => [
'extensionConfigs' => [
'Sds\DoctrineExtensions\Serializer' => null,
),
),
),
To get the serializer use:
$serializer = $serivceLocator->get('Sds\DoctrineExtensions\Serializer');
To use the serializer:
$array = $serializer->toArray($document)
$json = $serializer->toJson($document)
$document = $serializer->fromArray($array)
$document = $serializer->fromJson($json)
There are also some extra annotations available to control serialization, if you want to use them:
#Sds\Setter - specify a non standard setter for a property
#Sds\Getter - specify a non standard getter fora property
#Sds\Serializer(#Sds\Ignore) - ignore a property when serializing
It's all still a work in progress, so any comments/improvements would be much appreciated. As you come across issues with these libs, just log them on github and they will get addressed promptly.
Finally a note on serializing embedded documents and referenced documents - embedded documents should be serialized with their parent, while referenced documents should not. This reflects the way data is saved in the db. It also means circular references are not a problem.
Update
I've pushed updates to Sds/DoctrineExtensions/Serializer so that it can now handle references properly. The following three (five) methods have been updated:
toArray/toJson
fromArray/fromJson
applySerializeMetadataToArray
The first two are self explainitory - the last is to allow serialization rules to be applied without having to hydrate db results into documents.
By default references will be serialized to an array like this:
[$ref: 'CollectionName/DocumentId']
The $ref style of referencing is what Mongo uses internally, so it seemed appropriate. The format of the reference is given with the expectation it could be used as a URL to a REST API.
The default behaviour can be overridden by defineing an alternative ReferenceSerializer like this:
/**
* #ODM\ReferenceMany(targetDocument="MyTargetDocument")
* #Sds\Serializer(#Sds\ReferenceSerializer('MyAlternativeSerializer'))
*/
protected $myDocumentProperty;
One alternate ReferenceSerializer is already included with the lib. It is the eager serializer - it will serialize references as if they were embedded documents. It can be used like this:
/**
* #ODM\ReferenceMany(targetDocument="MyTargetDocument")
* #Sds\Serializer(#Sds\ReferenceSerializer('Sds\DoctrineExtensions\Serializer\Reference\Eager'))
*/
protected $myDocumentProperty;
Or an alternate shorthand annotation is provided:
/**
* #ODM\ReferenceMany(targetDocument="MyTargetDocument")
* #Sds\Serializer(#Sds\Eager))
*/
protected $myDocumentProperty;
Alternate ReferenceSerializers must implement Sds\DoctrineExtensions\Serializer\Reference\ReferenceSerializerInterface
Also, I cleaned up the ignore annotation, so the following annotations can be added to properties to give more fine grained control of serialization:
#Sds\Serializer(#Sds\Ignore('ignore_when_serializing'))
#Sds\Serializer(#Sds\Ignore('ignore_when_unserializing'))
#Sds\Serializer(#Sds\Ignore('ignore_always'))
#Sds\Serializer(#Sds\Ignore('ignore_never'))
For example, put #Sds\Serializer(#Sds\Ignore('ignore_when_serializing')) on an email property - it means that the email can be sent upto the server for update, but can never be serialized down to the client for security.
And lastly, if you hadn't noticed, sds annotations support inheritance and overriding, so they play nice with complex document structures.
Another very simple, framework independent way to transforming Doctrine ODM Document to Array or JSON - http://ajaxray.com/blog/converting-doctrine-mongodb-document-tojson-or-toarray
This solution gives you a Trait that provides toArray() and toJSON() functions for your ODM Documents. After useing the trait in your Document, you can do -
<?php
// Assuming in a Symfony2 Controller
// If you're not, then make your DocmentManager as you want
$dm = $this->get('doctrine_mongodb')->getManager();
$report = $dm->getRepository('YourCoreBundle:Report')->find($id);
// Will return simple PHP array
$docArray = $report->toArray();
// Will return JSON string
$docJSON = $report->toJSON();
BTW, it will work only on PHP 5.4 and above.