Symfony API : test if the content has the keys - symfony

With Symfony, I can get the content of request (POST and application/json) with :
$content = json_decode($request->getContent());
dd($content) return :
[
"subject" => "test"
"content" => "content"
]
I just want to hydrate an object with the subject, this works good :
$subject = new SubjectEntity();
$subject->setSubject($content['subject]);
But I don't want to do a setSubject() if the subject key doesn't exist.
I know I can do an if for each variable (Or $subject->setSubject($content['subject] ?? null)), but I think it will be a bit tedious in more complex cases.
Is there a way to "validate" the content sent to verify that all the desired keys are present ?

The cleanest solution would be a request param validator using symfony validator
Example:
public function validateRequest(array $params): array
{
$validator = Validation::createValidator();
$constraints = new Assert\Collection([
'subject' => new Assert\Type('string'),
'content' => new Assert\Type('string'),
]);
$group = new Assert\GroupSequence(['Default', 'custom']);
return $validator->validate($params, $constraints, );
}
If the keys can be optional, then you must use Assert\Optional(). Either way, you will need the null coalescing operator to cast to null if the key isn't set.
You can put these in a different class and with a small refactor you can make it work much nicer than doing a bunch of ifs, and it can be re-used to validate all of your api requests.

Related

Drupal \Drupal\user\Entity\User how retrieve property

i come from ES6 and need to do something in one Drupal 8 site.
Basically I try to get some value from the current logged user object.
...i try any possible method but nothing good.
by this snippet of code i can dump($userx) variable, i need to parse
$userCurrent = \Drupal::currentUser();
$uid = $userCurrent->id();
$userx = \Drupal::entityTypeManager()->getStorage('user')->loadByProperties([
'uid' => '13465'
]);
dump($userx);
outpup see picture
$cf = $userx->get('field_codice_fiscale_user')->getvalue()[0]['value'];
dump($cf);
otput NULL
Results output
i need the value of
protected values
field_cv_codice_fiscale
x-default => array (1)
0 => array (1)
value => string (16) "DSSSLV83D67B35QV"
i tried:
$cf = $userx->get('field_codice_fiscale_user')->getvalue()[0]['value'];
again NULL
my goal is to have variable valorized by :
'field_codice_fiscale_user' -> value;
after struglling two days i need to give up to drupal folly.
Thank you in advance
I found the solution.
as reported in the Drupal specification, entityTypeManager return objects array.
so the corect snippet is:
$userx = \Drupal::entityTypeManager()->getStorage('user')->loadByProperties([
'uid' => $uid2 ]);
dpm($userx);
$cfx = $userx[$uid2];
now the variable $cfx contain objects (inpictures = '3465' objects).
we can access the object property by this way
if(isset($cfx->get('field_codice_fiscale_user')->getvalue()[0]['value'])) {
$cf = $cfx->get('field_codice_fiscale_user')->getvalue()[0]['value'];
} else { $cf = '';}
dmp($cf)
output
$scf = 'DSLL....'

Getting An Error when trying to create a subcollection in Firestore

I am trying to create a node in Google Firebase, and use its unique id to create a Document in Google Firestore of the same name.
I'm using Google's PHP Firestore Client: https://github.com/GoogleCloudPlatform/google-cloud-php-firestore
And I've read through their documentation: http://googlecloudplatform.github.io/google-cloud-php/#/docs/cloud-firestore/v0.5.1/firestore/writebatch
Here is my code:
<?php
use \Google\Cloud\Firestore\FirestoreClient;
use \Google\Cloud\Core\Timestamp;
use \Google\Cloud\Firestore\Transaction as FirestoreTransaction;
use \grptx\Firebase as FirebaseClient;
class FirestoreTest
{
public function create()
{
$client = new FirebaseClient();
$database = $client->getDatabase();
$org = array(
"acl" => array(),
"people" => array()
);
$ref = $database->getReference("/clients/")->push($org);
$key = $ref->getKey();
$config = array(
"projectId" => "xxx",
"keyFile" => json_decode(file_get_contents("/xxx/firebase_auth.json"), true)
);
$firestore = new FirestoreClient($config);
$batch = $firestore->batch();
$collection = $firestore->collection("clients")->document("-LXXXXXX")->collection("trips");
}
}
And I get this error:
Exception 'Google\Cloud\Core\Exception\BadRequestException' with message '{
"message": "Document name \"projects\/xxx-test\/databases\/(default)\/documents\/clients\/\" has invalid trailing \"\/\".",
"code": 3,
"status": "INVALID_ARGUMENT",
"details": []
}'
Any help is appreciated.
Basically this will happen if you try to put blank as document name.
This is the error that occurs if you try to get a collection as a document. It's kind of tricky because this can also happen if you try to get a document with the name of empty string in a collection.
I don't know PHP, but I would guess that either in your $database->getReference("/clients/")->push($org); call, you were supposed to name a document to push your information to, or in your $firestore->collection("clients")->document("-LXXXXXX")->collection("trips"); call that the document you are trying to get ("-LXXXXXX") has the name empty string. (Of course, this is assuming your document isn't actually named "-LXXXXXX", and you are using that as a substitute for some variable that happens to be equal to "").
For instance, in python this call randomly failed me earlier:
db.collection(u'data').document(current_id)
with the same error: 'Document name ".../documents/data/" has invalid trailing "/". and will exit.' I scratched my head for a while but that's because the variable current_id is the empty string.
Basically, internally Firebase converts it into a long pathname and then tries to get a document or a collection at that pathname depending on what your last call was. This causes an issue if you try to get a document that is named "".

Symfony - findAll() returns ok if render, empty if response

I created a custom Bundle in my Symfony 2.7 website.
One of the entity works perfectly :
Entity class is Version.php
Custom repository is VersionRepository
The MainController.php of my bundle is :
$repository = $this->getDoctrine()->getManager()->getRepository('MyBundle:Version');
$versions = $repository->findAll();
return $this->render('IpadUpdaterBundle:Version:index.html.twig', array(
'versions' => $versions
));
Output in Twig is perfect :
My first version row
My second version row
BUT ... if I want to change the ouput and render a JSON response with the same datas, I make this change in the controller :
$repository = $this->getDoctrine()->getManager()->getRepository('MyBundle:Version');
$versions = $repository->findAll();
$versions = json_encode($versions);
$rep_finale = new Response($versions);
$rep_finale->headers->set('Content-Type', 'application/json');
return $rep_finale;
or :
$repository = $this->getDoctrine()->getManager()->getRepository('MyBundle:Version');
$versions = $repository->findAll();
return new JsonResponse($versions);
.. and the ouput becomes an empty array with 2 children :
[{},{}]
!I can not understand what's wrong and what changes I would implement to solve this issue. I already use "use Symfony\Component\HttpFoundation\Response" and "use Symfony\Component\HttpFoundation\JsonResponse" in the header of my controller.php.
Thanks for your help !
json_encode and JSONResponse don't do well with complex entities, especially with links to other complex entities. Mostly, those are for encoding strings or arrays as JSON.
If you only need some of the information from your entities you can make an array and pass that.
$repository = $this->getDoctrine()->getManager()->getRepository('MyBundle:Version');
$versionInformation = $repository->getIdNameOfVersionsAsArray();
$versionInformation = array_column($versionInformation, 'id', 'name');
return new JSONResponse($versionInformation);
You'll have to implement the getIdNameOfVersionsAsArray function in your repository to just return an array of values.
If you need every field of your version entity it may be easier to use a serializer. JMSSerializer Bundle is the most popular and well-supported.
$serializer = $this->container->get('serializer');
$versionJSON = $serializer->serialize($versions, 'json');
return new Response($versionJSON);
And you'll have to implement annotations in your entities to tell the serializer what to do. See the link above for that.

symfony2 get all validation constraints on an entity (yml, xml, annotations)

Im trying to get all validation constraints on an entity and translate theses constraints to Jquery validation rules, right now im able to get annotation defined constraints (thanks to : Symfony2 get validation constraints on an entity), but im having some trouble getting xml and yml ones.
$xml_file_loader = new XmlFileLoader("path_to_my_project/vendor/friendsofsymfony/user-bundle\FOS\UserBundle\Resources\config\validation.xml");
Using a similar code means that i need to know beforehand where the xml/yml file is located, i m trying to write somehow a generic code that can do this automatically.
Isn't there a way to get all constraints at once? if not how can i know the location of xml/yml files, and also in cases of inheritance i need to check for parent constraints... Is this doable?
private function getValidations()
{
$validations=[];
$validator=$this->get("validator");
$metadata=$validator->getMetadataFor(new your_entity());
$constrainedProperties=$metadata->getConstrainedProperties();
foreach($constrainedProperties as $constrainedProperty)
{
$propertyMetadata=$metadata->getPropertyMetadata($constrainedProperty);
$constraints=$propertyMetadata[0]->constraints;
$outputConstraintsCollection=[];
foreach($constraints as $constraint)
{
$class = new \ReflectionObject($constraint);
$constraintName=$class->getShortName();
$constraintParameter=null;
switch ($constraintName)
{
case "NotBlank":
$param="notBlank";
break;
case "Type":
$param=$constraint->type;
break;
case "Length":
$param=$constraint->max;
break;
}
$outputConstraintsCollection[$constraintName]=$param;
}
$validations[$constrainedProperty]=$outputConstraintsCollection;
}
return $validations;
}
Returns:
array(13) (
[property1] => array(4) (
[NotBlank] => (string) notBlank
[NotNull] => (string) notBlank
[Type] => (string) string
[Length] => (int) 11
)
[property2] => array(4) (
[NotBlank] => (string) notBlank
[NotNull] => (string) notBlank
[Type] => (string) string
[Length] => (int) 40
)
..........
)
The returned array can be configured or used to define client side validation rules depending on the client-side validation library/code that you are using
$validator=$this->get("validator");
$metadata=$validator->getMetadataFor(new yourentity());
The object $metadata now contains all the metadata about validations that concerns your specific entity.

Symfony2 Functional test: Passing form data directly

I am using phpunit to run functional tests but I am having a problem with a few of the forms. The problem is that phpunit is not aware of JS, and I have a form with a dynamically populated select box that needs jQuery.
So I need to pass the form data directly. The 'book' gives the following example:
// Directly submit a form (but using the Crawler is easier!)
$client->request('POST', '/submit', array('name' => 'Fabien'));
When I used this example the controller didn't receive any of the form data. Intially I saw that passing the array key 'name' wasn't correct in my situation as I needed the form name which was 'timesheet' in my code. So I tried something like:
$client->request('POST', '/timesheet/create', array('timesheet[project]' => '100'));
But this still didn't work. In the controller I tried to understand what was happening and what if anything was being received:
$postData = $request->request->get('timesheet');
$project = $postData['project'];
This didn't work and $project remained empty. However if I used the following code I got the value:
$project = $request->request->get('timesheet[project]');
But clearly that's not what I want. Atleast though I can see that there is some POST data. My last attempt was to try the following in the test method:
$this->crawler = $this->client->request('POST', '/timesheet/create/', array('timesheet' => array(project => '100'));
So I am trying to pass a 'timesheet' array as the first element of the request parameter array. But with this I get the error:
Symfony\Component\Form\Exception\UnexpectedTypeException: Expected argument of type "array", "string" given (uncaught exception) at /mnt/hgfs/pmt/src/vendor/symfony/src/Symfony/Component/Form/Form.php line 489
I would be very happy if someone can expand on what's in the 'book' about how I am supposed to get this working.
Form bind in controller:
if ($request->getMethod() == 'POST') {
$form->bindRequest($request);
if ($form->isValid()) {
$postData = $request->request->get('timesheet');
$project = $postData['project'];
$timesheetmanager = $this->get('wlp_pmt.timesheet_db_access');
$timesheetmanager->editTimesheet($timesheet);
return $this->redirect($this->generateUrl('timesheet_list'));
}
}
If you are wanting to know how to inject arrays of POST data using the test client...
In your test method, do something like
$crawler = $client->request('POST', '/foo', array(
'animal_sounds' => array(
'cow' => 'moo',
'duck' => 'quack'
)
); // This would encode to '/foo?animal_sounds%5Bcow%5D=moo&animal_sounds%5Bduck%5D=quack'
$this->assertTrue( ... );
In the controller, you would access your params like this:
$data = $request->request->get('animal_sounds');
$cowNoise = $data['cow'];
$duckNoise = $data['duck'];
Or you could just use the forms API if the test method was injecting valid form data...
do you have a $request parameter in your action?
that was the reason why my request->get() was empty:
//WRONG
public function projectAction()
{
$request = Request::createFromGlobals();
$project = $request->request->get('timesheet[project]');
//$project will be empty
}
//CORRECT
public function projectAction(Request $request)
{
$project = $request->request->get('timesheet[project]');
//$project is not empty
}
see
How do I create a functional test which includes a POST to a page with parameters?
Try to use $form->bind($clientData) instead of $form->bindRequest($request).

Resources