Symfony2 implement PATCH method to update user fileds - json

How can I update FOS USER user details using PATCH method. So when I pass partial details in Json, only these details are updated.
User entity
/**
* #ORM\Entity
* #ORM\Table(name="user")
*/
abstract class User extends BaseUser
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var string]
* #ORM\Column(name="first_name", type="string", length=255, nullable=true)
*/
private $firstName;
/**
* #var string
* #ORM\Column(name="last_name", type="string", length=255, nullable=true)
*/
private $lastName;
// getters and setters are here
}
For example. I have user Jack Nickolson and my json is:
{"firstName": "John"}
Only first name is updated.
This is my controller. How do I set new parameters to user, without specifing which parameters?
/**
* #Route("/update", name="api_user_update")
* #Security("has_role('ROLE_USER')")
* #Method("PATCH")
*/
public function updateAction(Request $request){
$jsonContent = $request->getContent();
$params = json_decode($jsonContent);
$em = $this->getDoctrine()->getEntityManager();
$response = new JsonResponse();
$user = $this->getUser();
// do something to update user details
$this->get('fos_user.user_manager')->updateUser($user);
$em->persist($user);
$em->flush();
$response->setContent([
"status" => "user ". $user->getUsername() ." is updated"
]);
return $response;
}
UPDATE
I tried to use an answer below, so this what I have now
public function updateAction(Request $request){
$em = $this->getDoctrine()->getEntityManager();
$response = new JsonResponse();
$user = $this->getUser();
$editForm = $this->createForm('CoreBundle\Form\UserType', $user);
$requestData = $request->getContent();
$requestData = json_encode($requestData, true);
$editForm->submit($requestData, false);
$this->get('fos_user.user_manager')->updateUser($user);
$em->persist($user);
$em->flush();
$response->setContent([
"status" => "user ". $user->getUsername() ." is updated"
]);
return $response;
}
Well, my entity was not updated. What am I doing wrong?

You need to prepare and create UserType form for partial updated.
Then, when processing a submitted form, you'll need to pass a false $clearMissing option to your form's submit method call in the controller:
$form->submit($request, false);
Thanks to that option the form component will only update the fields passed from the request.
and then flush user:
$em->flush();
Also if you want send data like:
{"firstName": "John"}
your UserType form should have method:
public function getBlockPrefix()
{
return "";
}
You can also use nice and powerfull https://github.com/FriendsOfSymfony/FOSRestBundle

Related

Column 'ip' cannot be null (SQL: insert into `logins` (`ip`, `steamid`, `time`)

insert into `logins` (`ip`, `steamid`, `time`)
I use php7.0 and phpmyadmin on vmware ubuntu server 16.04.6
I tried to fix it myself but I'm not really good at those kind of things if you need any more code tell me.
any help if welcome
the site wont let me post the full code here is the full code
This is the AuthController code
<?php namespace App\Http\Controllers;
use Invisnik\LaravelSteamAuth\SteamAuth;
use Illuminate\Support\Facades\DB;
use App\User;
use Auth;
use Carbon\Carbon;
class AuthController extends Controller
{
/**
* The SteamAuth instance.
*
* #var SteamAuth
*/
protected $steam;
/**
* The redirect URL.
*
* #var string
*/
protected $redirectURL = '192.168.1.12';
/**
* AuthController constructor.
*
* #param SteamAuth $steam
*/
public function __construct(SteamAuth $steam)
{
$this->steam = $steam;
}
/**
* Redirect the user to the authentication page
*
* #return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
public function redirectToSteam()
{
return $this->steam->redirect();
}
/**
* Get user info and log in
*
* #return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
public function handle()
{
if($this->steam->validate())
{
$info = $this->steam->getUserInfo();
$findUser = DB::table('users')->where('steamid', $info->steamID64)->first();
if(is_null($findUser))
{
$hasThisIp = DB::table('users')->where('ip', $this->getIp())->count();
if(!is_null($hasThisIp)) {
$connections = json_decode(json_encode($hasThisIp), true);
if($connections > 3) return view('connections');
else {
$array = array('<','>');
$numele = $info->personaname;
$name = str_replace($array, '*', $numele);
DB::table('users')->insert(
[
'name' => $name,
'steamid' => $info->steamID64,
'avatar' => $info->avatarfull,
'token' => csrf_token(),
'ip' => $this->getIp()
]
);

CakePHP and DefaultPasswordHasher syntax error

I have no clue why but for the line
use Cake\Auth\DefaultPasswordHasher;
I'm getting an error
Error: syntax error, unexpected '?'
and full code of user.php
namespace App\Model\Entity;
use Cake\ORM\Entity;
use Cake\Auth\DefaultPasswordHasher;
/**
* User Entity
*
* #property int $id
* #property string $email
* #property string $password
* #property \Cake\I18n\Time $created
* #property \Cake\I18n\Time $modified
*
* #property \App\Model\Entity\Bookmark[] $bookmarks
*/
class User extends Entity
{
/**
* Fields that can be mass assigned using newEntity() or patchEntity().
*
* Note that when '*' is set to true, this allows all unspecified fields to
* be mass assigned. For security purposes, it is advised to set '*' to false
* (or remove it), and explicitly make individual fields accessible as needed.
*
* #var array
*/
protected $_accessible = [
'*' => true,
'id' => false
];
/**
* Fields that are excluded from JSON versions of the entity.
*
* #var array
*/
protected $_hidden = [
'password'
];
protected function _setPassword($value){
$hasher = new DefaultPasswordHasher();
return $hasher->hash($value);
}
}
Any thoughts? I'm using latest CakePHP
Please try with this one. Please update your CakePHP project with composer, it will update all dependency if you miss something.
namespace App\Model\Entity;
use Cake\Auth\DefaultPasswordHasher;
use Cake\ORM\Entity;
class User extends Entity
{
// Make all fields mass assignable except for primary key field "id".
protected $_accessible = [
'*' => true,
'id' => false
];
// ...
protected function _setPassword($password)
{
return (new DefaultPasswordHasher)->hash($password);
}
// ...
}
Also please read this doc here. Hope it should be help you to solve this issue.
use Cake\ORM\Entity;
use Cake\Auth\DefaultPasswordHasher;
/**
* User Entity
*
* #property int $id
* #property string $email
* #property string $password
* #property string $role
* #property \Cake\I18n\Time $created
* #property \Cake\I18n\Time $modified
*/
class User extends Entity
{
/**
* Fields that can be mass assigned using newEntity() or patchEntity().
*
* Note that when '*' is set to true, this allows all unspecified fields to
* be mass assigned. For security purposes, it is advised to set '*' to false
* (or remove it), and explicitly make individual fields accessible as needed.
*
* #var array
*/
protected $_accessible = [
'*' => true,
'id' => false
];
/**
* Fields that are excluded from JSON versions of the entity.
*
* #var array
*/
protected $_hidden = [
'password'
];
protected function _setPassword($password) {
return (new DefaultPasswordHasher)->hash($password);
}
}

FOSRest Symfony POST using json

I'm new with the symfony framework. I'm trying to create webservices with FOSRest bundle but I had a problems when I tried to implement the POST method for one entity with json.
Test:
public function testJsonPostNewTesteAction(){
$this->client->request(
'POST',
'/api/teste/new',
array(),
array(),
array(
'Content-Type' => 'application/json',
'Accept' => 'application/json'
),
'{"Teste":{"title":"O teu title"}}'
);
$response = $this->client->getResponse();
$this->assertJsonResponse($response, Codes::HTTP_CREATED);
}
Controller:
/**
*
* #Config\Route(
* "/teste/new",
* name="postTestNew"
* )
* #Config\Method({"POST"})
*
* #param Request $request the request object
*
* #return View|Response
*/
public function postNewTeste(Request $request){
return $this->processFormTest($request);
}
/**
* Method for create the process form to Advertisements
*
* #param Request $request
*
* #return mixed
*/
private function processFormTest(Request $request){
$form = $this->createForm(
new TesteType(),
new Teste()
);
$form->bind($request);
//$from->handleRequest($request);
if ($form->isValid()) {
$test = $form->getData();
return $test;
}
return View::create($form, Codes::HTTP_BAD_REQUEST);
}
The problem is when I use the handleRequest(), the method isValid() returns false because the form didn't submit. So I try to change the handleRequest to the bind method. In the last case, the method isValid() returns true but the method getData() returns a null object.
I don't know if the problem is the type form class bellow.
Type Form:
/**
* The constant name to that type
*/
const TYPE_NAME = "Teste";
/**
* {#inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options){
parent::buildForm($builder, $options);
$builder->add("title", ValidationType::TEXT);
}
/**
* {#inheritdoc}
*/
public function setDefaultOptions(OptionsResolverInterface $resolver){
$resolver->setDefaults(
array(
'csrf_protection' => false,
'cascade_validation' => true,
'data_class' => 'oTeuGato\DatabaseBundle\Entity\Teste'
)
);
}
/**
* Returns the name of this type.
*
* #return string The name of this type
*/
public function getName(){
return AdvertisementType::TYPE_NAME;
}
I need to POST the entity with both ways. Anyone sugest anything for my problem?
Thanks for the patience!
Got the same issue with the form binding, the only way i found to solve it was to set an empty string to the form getName function:
/**
* Returns the name of this type.
*
* #return string The name of this type
*/
public function getName(){
return '';
}
And i would suggest to use the handleRequest method when you bind your data because the bind method is deprecated:
private function processFormTest(Request $request){
$form = $this->createForm(
new TesteType(),
new Teste()
);
$from->handleRequest($request);
if ($form->isValid()) {
$test = $form->getData();
return $test;
}
return View::create($form, Codes::HTTP_BAD_REQUEST);
}
It looks more like a hack but seems like it's the only way for now:
https://github.com/FriendsOfSymfony/FOSRestBundle/issues/585
I am not entirely sure but I think it's because you're sending the data with: 'Content-Type' => 'application/json'
in stead of 'Content-Type' => 'application/x-www-form-urlencoded'
Or at least I think that's the reason why the handleRequest is not doing it's thing.

Update discriminator column Doctrine2 with Symfony2

I have an entity called User which has inheritance for Student, Professional and Business.
When a user is registered, is only a User but they must update their profile and choose which kind of user is, I have a form which handles this, a controller which gets the form data, but I can't update the discriminator field type with $userEntity->setType()
This is my mapping stuff
class User
{
const TYPE_BASIC = "Basico";
const TYPE_STUDENT = "Estudiante";
const TYPE_PROFESSIONAL = "Profesional";
const TYPE_BUSINESS = "Empresa";
protected $type = self::TYPE_BASIC;
public function getType()
{
return self::TYPE_BASIC;
}
public function setType($type)
{
$this->type = $type;
}
class Student extends User
{
protected $type = self::TYPE_STUDENT;
And then Professional and Business just like Student (changing const)
<entity name="User" table="user_base" inheritance-type="JOINED">
<discriminator-column name="type" type="string"/>
<discriminator-map>
<discriminator-mapping value="Basico" class="User"/>
<discriminator-mapping value="Estudiante" class="Student"/>
<discriminator-mapping value="Profesional" class="Professional"/>
<discriminator-mapping value="Empresa" class="Business"/>
</discriminator-map>
the child tables are named user_xxx where xxx = Student/Professional/Business
And this is my controller
if($form->isValid())
{
$em = $this->getDoctrine()->getManager();
$data = $form->all();
$type = $data['type']->getData();
$email = $data['email']->getData();
$profile = $data['profile']->all();
$name = $profile['name']->getData();
$lastName = $profile['lastName']->getData();
$birth = $profile['birth']->getData();
$profileEntity = new Profile();
$profileEntity->setBirth($birth);
$profileEntity->setName($name);
$profileEntity->setLastName($lastName);
$profileEntity->setUser($user);
$em->persist($profileEntity);
ladybug_dump($type);
$userEntity = $em->getRepository('User')->find($user);
$userEntity->setProfile($profileEntity);
$userEntity->setType($type);
if($user->getEmail() != $email)
$userEntity->setEmail($email);
$em->persist($userEntity);
$em->flush();
}
Everything is persisted but type field, which remains it's original data. I know when I change discriminator column I need to create a new row inside it's child element, but first I want to know how to change the discriminator column.
it is possible if you use this custom bit of code in the Form of a Trait which you can use inside a Repository.
The Trait:
namespace App\Doctrine\Repository;
use App\Exception\InvalidDiscriminatorClassException;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\DBALException;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Mapping\ClassMetadata;
/**
* Discriminator Trait
*/
trait DiscriminatorTrait
{
/**
* #return ClassMetadata
*/
abstract public function getClassMetadata();
/**
* #return EntityManager
*/
abstract public function getEntityManager();
/**
* Update Discriminator Column
*
* #param integer $id
* #param string $class
* #return boolean
* #throws InvalidDiscriminatorClassException
*/
private function updateDiscriminatorColumn($id, $class)
{
/* #var ClassMetadata $classMetadata */
$classMetadata = $this->getClassMetadata();
if (!in_array($class, $classMetadata->discriminatorMap)) {
throw new InvalidDiscriminatorClassException($class);
}
$identifier = $classMetadata->fieldMappings[$classMetadata->identifier[0]]["columnName"];
$column = $classMetadata->discriminatorColumn["fieldName"];
$value = array_search($class, $classMetadata->discriminatorMap);
/* #var Connection $connection */
$connection = $this->getEntityManager()->getConnection();
try {
$connection->update(
$classMetadata->table["name"],
[$column => $value],
[$identifier => $id]
);
}
catch (DBALException $e) {
return false;
}
return true;
}
}
According to the Doctrine documentation on Inheritance mapping, it is not possible to either get or set the type. You may wish take advantage of PUGXMultiUserBundle, which readily handles the mapping. This bundle also makes it possible for your users to register with the appropriate profile.

Error when trying to display page in JSON format

I have this error when trying to display page in JSON format but with the html format it works fine
An exception occurred while executing
'SELECT t0.id AS id1, t0.libProjet AS libProjet2, t0.site AS site3, t0.partceg AS partceg4, t0.datego AS datego5, t0.dateResmisOff AS dateResmisOff6, t0.dateTransfert AS dateTransfert7, t0.nompays_id AS nompays_id8, t0.libTypeProj_id AS libTypeProj_id9, t0.nomclt_id AS nomclt_id10,t0.libContrat_id AS libContrat_id11, t0.libEtatProj_id AS libEtatProj_id12, t0.libEtatOff_id AS libEtatOff_id13
FROM projet t0 WITH (NOLOCK) WHERE t0.id = ?' with params ["index.json"]:
this is the entity
class projet
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="libProjet", type="string", length=255)
*/
private $libProjet;
/**
* #var string
*
* #ORM\Column(name="site", type="string", length=255)
*/
private $site;
/**
* #var float
*
* #ORM\Column(name="partceg", type="float")
*/
private $partceg;
//....
This is the Controller
public function indexAction()
{
$em = $this->getDoctrine()->getManager();
$entities = $em->getRepository('rexBundle:projet')->findAll();
$repository = $this->getDoctrine()->getRepository('rexBundle:projet');
$query = $repository->createQueryBuilder('t')
->select('t.id','t.libProjet','t.site','t.partceg',
'IDENTITY(t.nompays) AS nompays',
'IDENTITY(t.libTypeProj) AS libTypeProj',
'IDENTITY(t.nomclt) AS nomclt',
'IDENTITY(t.libContrat) AS libContrat',
'IDENTITY(t.libEtatProj) AS libEtatProj',
'IDENTITY(t.libEtatOff) AS libEtatOff',
't.datego',
't.dateResmisOff',
't.dateTransfert')
->getQuery();
$entities = $query->getResult();
$entity = new projet();
$form = $this->createCreateForm($entity);
return array(
'entities' => $entities,
'entity' => $entity,
'form' => $form->createView(),
);
}
If you want send JSON response, read this article in documentation.
http://symfony.com/doc/current/components/http_foundation/introduction.html#creating-a-json-response
Now in your controller you don't send JSON Response, you only render form
Example how send JSON response:
use Symfony\Component\HttpFoundation\Response;
$response = new Response();
$response->setContent(json_encode(array(
'data' => 123,
)));
$response->headers->set('Content-Type', 'application/json');