What I'm asking here is something weird. I'm using Symfony2 with Doctrine2. To bypass a issue between FOSRestBundle and JMSBundle (who don't like composite primary key) I need to know if it's possible - and how - to call a setter from the name of the field.
Here an example: imagine my Product entity have a primary key composed by 3 fields.
The trick is to send an array this kind of JSON into my API REST:
{
"id": {
"field1": "xxx",
"field2": "...",
"field3": "..."
},
// other fields
}
Then I use json_decode() to extract the ID field. I create a table of $key => $value with the 3 primary keys. And there is my problem, with this table I want, in a foreach loop, to do something like $myEntity->set$KEY($VALUE).
I'm doing this because I want to reuse this code with all my entities.
I know that this is something really weird, to sum up with only the name of the object field/property I want to call is appropriate setter().
Thanks ;-)
PS: sorry if my English isn't perfect, this isn't my birth langage.
You can use dynamic method name in PHP :
$myEntity->{'set'.$KEY}($VALUE);
or more readable version :
$method = 'set'.$KEY;
$myEntity->$method($VALUE);
Don't forget to check if method exists anyway :
$method = 'set'.$KEY;
if (!method_exists($myEntity, $method))
throw new \Exception('Something bad');
$myEntity->$method($VALUE);
Related
I am trying to get a single record from my database using doctrine. I am unsure how to use the findBy() method.
My current code is below:
$token = $em->getRepository('APIBundle:Token')->findBy();
Any help will be appreciated
You just need to include an array of what you want the findBy() method to use. Please see the below code:
$token = $em->getRepository('APIBundle:Token')->findBy(array('string' => $string));
Just name the 'string' part of the code as whatever field you are searching, and replace the $string with the variable.
I'm building a REST API with FOSRestBundle on my Symfony2 application.
What I want to do is to allow my POST and PUT actions, let say on a Product entity who got a #OneToMany relationship with another entity called Risk, to add/delete the children I past in JSON.
Let me give to you an example of JSON:
{
"cproduct": "ASSOC000000000999",
"risks": [
{
//first risk fields
},
{
//second risk fields
}
]
}
This is a simple JSON (the real one got more fields but these aren't needed here).
So here I've my Product ID (ASSOC000000000999) and I want to update this product by adding to him 2 new risks.
I know that normally I would have to create a Risk with the product ID separately, but for the needs of my application, I need to make only one request to the database. I want my users to be able to create a product, then add one or more risks and only then persist it into the database.
In a second time I would like them to be able to delete a child (risk) if he doesn't appear in the JSON sent with PUT action.
Here an example, let say that product “ASSOC000000000999” got a risk “RISK1”.
If I send this JSON:
{
"cproduct": "ASSOC000000000999",
"risks": [
{
“id”: “RISK2”,
//other fields
},
{ “id”: “RISK3”,
//other fields
}
]
}
On persist I want RISK1 to be deleted.
How can I do that? I found nothing on the web about that, please help me. :-)
PS: Sorry for my English, this isn't my birth langage.
EDIT:
I target what my problem really is.
When I send that JSON file with HTTP PUT verb:
{
"cfam": "AUTE",
"lpronom": "My Contract",
"riss": [{
"cris": "AS",
"lris": "Organization Law of 1901",
"lrisfic": "RCAD_FICHERCA9"
}]
}
Doctrine does a SELECT on RIS (my Risk table is called RIS, so the collection is $riss in my PROduct entity) where CRIS = "AS", and that's my problem. Here I want doctrine to create a RIS if the composite PK {cpro, nprover, cris} doesn't exist, and an update if it exist.
How can I do that?
(Without using Symfony form if possible).
Here my API call :
http://localhost/web/web/app_dev.php/fos/api/pros/ASSOC000000000009_1
My putProAction():
public function putProAction($id, Request $request)
{
$detachedEntity = $this->reqDeserialize($request, 'Namespace\Bundle\ProductBundle\Entity\Pro');
// Here I need to explode my serialized PUT parameter ID
list($cpro, $nprover) = explode('_', $id);
$detachedEntity->setCPRO($cpro);
$detachedEntity->setNPROVER($nprover);
$em = $this->getDoctrine()->getManager();
// I use merge to attache the entity to perform the persist
$entity = $em->merge($detachedEntity);
$em->persist($entity);
$em->flush();
return $entity;
}
You should use Symfony's Form Collections.
The example listed on that page is very similar to your requirements.
I'm trying to make a custom request in my repository with a WHERE clause inside an array field. I tried something like that, not working, but can better show my problem :
$qb ->andWhere( "p.addresses[:index] = :address" )
->setParameter( "index" , $p_idLang )
->setParameter( "address" , $p_address );
Extracted from the documentation about array type:
Maps and converts array data based on PHP serialization. If you need
to store an exact representation of your array data, you should
consider using this type as it uses serialization to represent an
exact copy of your array as string in the database. Values retrieved
from the database are always converted to PHP’s array type using
deserialization or null if no data is present.
Your query doesn't make sense. You have a few options though:
Retrieve p.adresses and check using php if p.adresses[$index] = $address
Try something much less reliable but that could work:
$val_length = strlen($p_address);
$qb ->andWhere( "p.addresses LIKE :indexAddress" )
->setParameter( "indexAddress" , "%i:$p_idLang;s:$val_length:$p_address%" );
Create a new entity and a relation oneToMany between this entity and the new one.
I'd definetely try option 3. Option 1 isn't an option if the array is big or will become big in the future. I wouldn't go for option 2, but as an experiment could be worth trying.
fellow programmers :)
I'm having a bad case of no idea what's going on.
This concerns two entities: Ware and File.
In my repository, I have a function that returns File objects along with wares to avoid lazy loading:
The relevant part of this function ( because the exception happens even if i trigger this bit only ) is this:
public function findByWithFilesTotal($params, $page = false, $per_page = false){
$res = $this->_em->createQuery('SELECT w, f FROM ShopBundle:Ware w JOIN w.files f');
// same result occurs with LEFT JOIN
return count($res->getResult());
}
Important stuff:
1) Ware and File classes are direct descendants of class Data. Discriminators are all right.
2) Ware has OneToMany relation with File - that means File table has ware_id column.
3) This is the most important part ( IMHO ). I use this filter to separate deleted items in all Data descendants.
class UndeletedFilter extends SQLFilter
{
public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias)
{
if(!$targetEntity->hasField('deleted'))
return "";
return "( $targetTableAlias.deleted = 0 OR $targetTableAlias.deleted IS NULL)";
}
}
It works for all the other entities, but causes a HydrationException with message 'The discriminator column "discr" is missing for "Acme\CoreBundle\Entity\File" using the DQL alias "f".' for this one query.
This, however, DOES NOT happen if I either remove JOIN w.files from DQL query, and leave it to lazy loading, or return an empty string from addFilterConstraint() method even if it does have the 'deleted' field.
So, if anyone knows: What exactly causes this, and how do solve it?
Thank you in advance :)
One reason for trigger this exception in when you are working inherent classes, then for example, if your discriminator column has null values the QueryBuilder will do not know how to convert this unknown type based in type.
I want to create a form using some fields from multiple entities. I have all the distinct entites needed already created and i am not using form classes. I need to know how to do to render a form and handle its data so i can save them to the correct tables in my database.
Here is a part of my controller in charge of doing that
public function createPublicSpaceAction() {
//My entities
$Room = new Room();
$GuestList = new GuestList();
$Guest = new Guest();
//I need to know what to do from here
return $this -> render('AcmeUserBundle:Default:Forms/createPublicSpace.html.twig', array());
}
I kept trying to find a solution and i came up with the idea that one form needs one entity. So maybe the solution would be to merge those entities in one so i can build the form easily. I would then have to persist data to corresponding tables. But i can't think of how to merge entities.
I figured out a temporary solution. For those who want to know, I manually created an entity that looks like a merge of all the entity I need. This new entity has no link with Doctrine therefore it cannot create a table. Its goal is simply to allow me to build up a form and be able to manipulate data through that form. I then assign all data submitted to corresponding entities fields and persist them to the database.
Once again i know this is not the best solution. But for some reasons I won't tell, it is for me at this moment. I hope this can help some that are in the same situation than me and do not hesitate to post links that could help or better ways to do that.
It is highly recommended to use form classes http://symfony.com/doc/current/book/forms.html#creating-form-classes
They are designed to save time and make a lot of things just easier.
However to answer your question consider the following. Your action needs to handel a post request. So catch the request object with the post data:
use Symfony\Component\HttpFoundation\Request;
public function createPublicSpaceAction(Request $request)
Then get a form builder intance and create the form:
$builder = $this->createFormBuilder();
$builder->add('floor', 'text', array(
'label' => 'Room floor',
'data' => $room->getFloor()
));
add as much form fields as you need. There are several built-in field types: http://symfony.com/doc/current/book/forms.html#built-in-field-types
Create the form:
$form = $builder->getForm();
Pass the form to your template:
return $this -> render('AcmeUserBundle:Default:Forms/
createPublicSpace.html.twig', array(
'roomForm' = $form
));
To get posted data within your action:
if ('POST' == $request->getMethod()) {
$data = $request->request->get("form");
}
And in your template you can render the form by yourself or let twig do the job:
{{ form_widget(form.floor)}}
So this are the most importend things to mention. However you should go through http://symfony.com/doc/current/book/forms.html They actually tell you everything I wrote down.
Good luck ;)