Get serialization context groups in controller - symfony

I have the problem that depending on user rights, there are different context groups used, and I can't find the place where the context groups are set.
For debugging issues I'm searching an possibility to find out which serialization context group an api call is using. This is my code:
<?php
namespace AppBundle\Controller\Api\Upload;
use AppBundle\Entity\Upload\UploadRepository;
use AppBundle\Entity\Upload\UploadType;
use AppBundle\Entity\Upload\UploadTypeRepository;
use Doctrine\ORM\ORMException;
use GuzzleHttp\Psr7\UploadedFile;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Nelmio\ApiDocBundle\Annotation\ApiDoc;
use ApiPlatform\Core\Annotation\ApiResource;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use AppBundle\General\Registry;
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
use Symfony\Component\Serializer\Normalizer\DataUriNormalizer;
use AppBundle\Entity\Upload\Upload;
use AppBundle\Entity\Application\ApplicationData;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\Serializer\Serializer;
/**
* Class UploadController
*
* #package AppBundle\Controller\Api\Upload
*
* #ApiDoc()
* #ApiResource(attributes={"pagination_enabled"=true})
*/
class UploadController extends Controller
/**
* Get an upload.
*
* #ApiDoc(
* resource=true,
* description="gets an upload",
* )
* #Route(
* name="getUploadSpecial",
* path="/fileuploads/{id}",
* defaults={"_api_resource_class"=Upload::class, "_api_item_operation_name"="getUpload"}
* )
* #Method("GET")
*
* #param Upload $data
*
* #return null|string
*
*/
public function getUploadAction($data)
{
// here I'd like to return the serialization context group
return $data;
}
Is there the possibility to get the serialization context group in the controller?

Well, it seems, the controller isn't the right place to find it.
It is better to dump in
src/Serializer/JsonEncoder.php in function encode, right before the return like this:
/**
* {#inheritdoc}
*/
public function encode($data, $format, array $context = [])
{
dump($data, $context);die;
return $this->jsonEncoder->encode($data, $format, $context);
}

Related

Resources are not supported in serialized data

Hello everyone m working on a project there is a bundle CustomerBundle when i call a function following errors are display can anyone tell me why this error coccured..
message": "Resources are not supported in serialized data. Path:
Monolog\Handler\StreamHandler -> Symfony\Bridge\Monolog\Logger ->
Symfony\Component\Cache\Adapter\FilesystemAdapter ->
Symfony\Component\Cache\Adapter\TraceableAdapter ->
Symfony\Component\Cache\DoctrineProvider ->
Doctrine\Common\Annotations\CachedReader ->
Doctrine\ORM\Mapping\Driver\AnnotationDriver ->
Doctrine\Common\Persistence\Mapping\Driver\MappingDriverChain ->
Doctrine\ORM\Configuration -> Doctrine\ORM\EntityManager ->
CustomerBundle\Repository\CustomerRepository",
"class": "JMS\Serializer\Exception\RuntimeException",
this is my Customer entity page
/**
* #ORM\ManyToOne(targetEntity="CompanyBundle\Entity\Company", inversedBy="company_customer")
* #ORM\JoinColumn(name="company_id", referencedColumnName="id")
*/
private $companyId;
/**
* #var \DateTime
*
* #ORM\Column(name="created_time", type="datetimetz")
*/
private $createdTime;
/**
* #var \DateTime
*
* #ORM\Column(name="modified_time", type="datetime")
*/
private $modifiedTime;
/**
* #ORM\OneToMany(targetEntity="SalesBundle\Entity\SalesAccount", mappedBy="customerId" )
*/
private $sales_customer_id;
CustomerApiController controller
namespace CustomerBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\HttpFoundation\Request;
use FOS\RestBundle\Controller\Annotations as Rest;
use FOS\RestBundle\Controller\FOSRestController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use FOS\RestBundle\View\View;
use CustomerBundle\Entity\Customer;
class CustomerapiController extends FOSRestController
{
/**
* #Rest\Post("/api/customer")
*/
public function customerAction(Request $request)
{
$data = $this->getDoctrine()->getRepository(Customer::class);
$data->find(1);
return $data;
}
}
I think you should have a look at this post. Similar problem can be solved in the same way.
Write a custom repository function and do the following instead of your "find(1)" :
public function findFirstElement()
{
$qb = $this->createQueryBuilder('e');
$qb->where('e.id = 1');
return $qb->getQuery()->getArrayResult();
}

swagger-ui How do you hide rest methods not implemented

Maybe im just missing it, I would like to hide some rest methods from controllers that do not implement them like options , delete, head
Is there an annotation for this? I could not find it in the documentation
using https://github.com/nelmio/NelmioApiDocBundle v3
currently when i view /api/doc any controllers I add list all rest methods even if I only have a GET method implemented.
<?php
namespace ApiBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\HttpFoundation\JsonResponse;
use Swagger\Annotations as SWG;
class UserController extends Controller
{
/**
* #Security("is_granted('IS_AUTHENTICATED_FULLY')")
* #Route("/api/users", name="get_users", methods={"GET"})
*
* #SWG\Response(
* response=200,
* description="Returns all users"
* )
* #SWG\Tag(name="users")
*
*
* #return \Symfony\Component\HttpFoundation\JsonResponse
*/
public function getUsersAction()
{
$repo = $this->getDoctrine()
->getRepository('AccountBundle:User');
$users = $repo->createQueryBuilder('q')
->getQuery()
->getArrayResult();
return new JsonResponse($users);
}
}
Just figured it out if you do not specify the methods in the controller in the #Route() annotation then it will show all of them but if you add methods={} to the Route annotation then it will only list the defined methods
* #Route("/api/users", name="get_users", methods={"GET"})
Specify #Value and #method type in the #RequestMapping
#RequestMapping(value="/instances/all",method=RequestMethod.GET)
#JsonFormat
public String showInstances(){
return "instances";
}

Symfony using NotEqualTo validator with an object

According to Symfony docs it should be possible to use a NotEqualTo constraint with objects
value
type: mixed [default option]
This option is required. It defines the value to compare to. It can be a string, number or object.
I have the following entity:
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\ORM\Mapping\UniqueConstraint;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Constraints\NotEqualTo;
/**
* Class Template
* #ORM\Entity(repositoryClass="NoteRepository")
* #ORM\Table(uniqueConstraints={#UniqueConstraint(name="note_unique",columns={"from_id", "to_id"})})
*/
class Note
{
/**
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\Column(type="integer")
* #var $id int
*/
protected $id;
/**
* #ORM\ManyToOne(targetEntity="Template")
* #var $from Template
* #NotBlank()
* #NotEqualTo(value="$to")
*/
protected $from;
/**
* #ORM\ManyToOne(targetEntity="Template")
* #NotBlank()
* #var $to Template
*/
protected $to;
/**
* #ORM\Column(type="text")
* #var $notes string
*/
protected $notes;
}
I want to avoid getting $from == $to, how can I configure the constraint to use an instance of the class Template at validation time or more generrally how can I configure the constraint to use an object
Right now if a dump the values that the validator is receiving
class NotEqualToValidator extends AbstractComparisonValidator
{
/**
* {#inheritdoc}
*/
protected function compareValues($value1, $value2)
{
var_dump($value1);
var_dump($value2);
return $value1 != $value2;
}
}
I get
object(AppBundle\Entity\Template)
string '$to' (length=3)
Okay, despite Symfony docs states to be possible pass object to NotEqualTo Constraint it isn't true when using YML or Annotations.
So in order to dynamically unsure Note::$to is equals (or not equals) to Note::$from you could to use either Getters Constraint Targets or Callback Constraint.
However, there is a third option much easier (IMO): Expression Constraint
Expression Constraint approach
This constraint allows you to use an expression for more complex,
dynamic validation. See Basic Usage for an example. See Callback for a
different constraint that gives you similar flexibility.
Here is an example based on your question:
use Symfony\Component\Validator\Constraints as Assert;
/*
* Entity class...
*/
class Note
{
//...
/**
* #ORM\ManyToOne(targetEntity="Template")
* #var $from Template
* #Assert\NotBlank()
* #Assert\Expression('not (value == this.getTo())')
*/
protected $from;
//...
}
That is, just add #Assert\Expression('not (value == this.getTo())') to $from property.
Constraints Targets: Getters approach
use Symfony\Component\Validator\Constraints as Assert;
/*
* Entity class...
*/
class Note
{
//...
/**
* #Assert\isFalse(message='"from" cannot be equals to "to"')
* #return bool True if self::$from is not equals to self::$to
*/
function isFromAndToNotEqual()
{
return !($this->getFrom() != $this->getTo());
}
//...
}
Setting the property path validation:
Be aware taking this approach (Getters As Constraints Targets) and using validation with forms, it'll not show error messages next/closer to form field.
However, you always can set/config the error_mapping option (in Form type) in order to show the custom errors display next to a specific field, thus the solution would be something like this:
<?php
namespace AppBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class MyType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('from')
->add('to')
// more fields...
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
//...
# it cause error message display next to
# "from" field (or whaterver field you which).
'error_mapping' => array(
'fromAndToNotEqual' => 'from',
),
));
}
}
Please note the current solutions is based on Symfony 2.7, but it
should be work nicely on other older versions (except some details for
Form class, etc).

Symfony 2.3.6 generate CRUD panel from FOSuserbundle

I trying to create CRUD panel from FOSUserBundle but i have some troubles. I mean that i created User entity for FOS and made crud panel for this entity. Now when i trying to add new user i have error like below
Neither the property "expiresAt" nor one of the methods "getExpiresAt()", "isExpiresAt()", "hasExpiresAt()", "_get()" or "_call()" exist and have public access in class "Bn\UserBundle\Entity\User".
It's my first project so please understand when i will ask for simple function, some suggestion ? What is wrong ?
<?php
namespace Bn\UserBundle\Entity;
use FOS\UserBundle\Model\User as BaseUser;
use Doctrine\ORM\Mapping as ORM;
/**
* User
*
* #ORM\Table(name="fos_user")
* #ORM\Entity
*/
class User extends BaseUser
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* Get expiresAt
*
* #return \DateTime
*/
public function getExpiresAt()
{
return $this->expiresAt;
}
/**
* Get credentials_expire_at
*
* #return \DateTime
*/
public function getCredentialsExpireAt()
{
return $this->credentialsExpireAt;
}
public function __construct()
{
parent::__construct();
// your own logic
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
}
Now is working but i don't know why i must declare again function for getter.
I believe this means you need to add public accessors setExpiresAt() and getExpiresAt() to your User entity.
You need only add getExpiresAt to your User.php class. FOSUserBundle\User doesn't have getter for this field, but Sensio generator creates views for all fields.
public function getExpiresAt()
{
return $this->expiresAt;
}

JMS Serializer Deserialize with abstract parent class

I have an abstract parent (mapped super-)class which has several children with different properties which I'd like to deserialize.
I'm storing the data using MongoDB and Doctrine ODM, so I also have a discriminator field which tells doctrine which subclass is used (and also have a custom "type" property ontop which is used elsewhere to determine which class is currently processed).
When deserializing my model, I get an exception telling me that its impossible to create an instance of an abstract class (ofcourse) - now I'm wondering how I can tell the JMS Deserializer which inherited class it should use (that is why I use a custom type instance variable for example - because I have no access to doctrine's discriminator field mapping).
I can successfully hook into the preDeserializeEvent- so maybe it is possible to make some switch/cases there (or using the )?
My Model in short (abstract class):
<?php
namespace VBCMS\Bundle\AdminBundle\Document;
use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB;
use JMS\Serializer\Annotation as Serializer;
/**
* abstract Class Module
* #Serializer\AccessType("public_method")
* #MongoDB\MappedSuperclass
* #MongoDB\InheritanceType("SINGLE_COLLECTION")
* #MongoDB\DiscriminatorField(fieldName="_discriminator_field")
* #MongoDB\DiscriminatorMap({
* "module"="Module",
* "text_module"="TextModule",
* "menu_module"="MenuModule",
* "image_module"="ImageModule"
* })
*/
abstract class Module {
const TYPE_MODULE_TEXT = 'module.text';
const TYPE_MODULE_MENU = 'module.menu';
const TYPE_MODULE_MEDIA_ITEM = 'module.media.item';
/**
* #Serializer\Type("string")
* #MongoDB\Field(type="string")
* #var String
*/
protected $type;
/**
* #Serializer\Type("boolean")
* #MongoDB\Field(type="boolean")
* #var boolean
*/
protected $visible;
// getter/setter methods etc..
}
?>
One of the subclasses
<?php
namespace VBCMS\Bundle\AdminBundle\Document;
use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB;
use JMS\Serializer\Annotation as Serializer;
/**
* Class TextModule
* #package VBCMS\Bundle\AdminBundle\Document
* #Serializer\AccessType("public_method")
* #MongoDB\EmbeddedDocument
*/
class TextModule extends Module {
const TEXT_TYPE_SPLASH_HEADLINE = 'splashscreen.headline';
const TEXT_TYPE_SPLASH_SUBLINE = 'splashscreen.subline';
/**
* the actual text
*
* #var string
* #Serializer\Type("string")
* #MongoDB\Field(type="string")
*/
protected $text;
/**
* how it is called in the admin interface
*
* #var string
* #Serializer\Type("string")
* #MongoDB\Field(type="string")
*/
protected $label;
/**
* #var string
* #Serializer\Type("string")
* #MongoDB\Field(type="string")
*/
protected $textType;
// getter/setter methods etc..
?>
Another test was to not make the Module class abstract and to create a custom static method
/**
*
* #Serializer\HandlerCallback("json", direction="deserialization")
* #param JsonDeserializationVisitor $visitor
*/
public static function deserializeToObject(JsonDeserializationVisitor $visitor)
{
// modify visitor somehow to return an instance of the desired inherited module class??
}
any ideas?
I found a discriminator mapping in the Tests directory of the plugin, unfortunately, this is not yet documented: https://github.com/schmittjoh/serializer/blob/master/tests/JMS/Serializer/Tests/Fixtures/Discriminator/Vehicle.php
Documentation is updated http://jmsyst.com/libs/serializer/master/reference/annotations#discriminator
namespace JMS\Serializer\Tests\Fixtures\Discriminator;
use JMS\Serializer\Annotation as Serializer;
/**
* #Serializer\Discriminator(field = "type", map = {
* "car": "JMS\Serializer\Tests\Fixtures\Discriminator\Car",
* "moped": "JMS\Serializer\Tests\Fixtures\Discriminator\Moped",
* })
*/
abstract class Vehicle
{
/** #Serializer\Type("integer") */
public $km;
public function __construct($km)
{
$this->km = (integer) $km;
}
}

Resources