Getting Symfony \ Component \ HttpKernel \ Exception \ MethodNotAllowedHttpException - symfony

I'm sending a PUT request that handles input data and updates a record, but I get the above response. The problem doesn't seem to be the route, however, because if I do dd($user) after the $user = User::whereId($id)->firstOrFail(); line, I get the object returned correctly.
Yet, when it comes time to validate it, it throws this error.
# routes
Route::resource('users', 'UsersController', ['only' => ['index', 'show', 'update']]);
# api call
PUT /users/2
# controller
public function update($id)
{
$user = User::whereId($id)->firstOrFail();
$input = Input::all();
$this->userForm->validate($input);
$user->fill($input)->save();
return $user->toJson();
}
# userForm class
<?php namespace Olp\Forms;
use Laracasts\Validation\FormValidator;
class UserForm extends FormValidator {
protected $rules = [
'email' => 'required|email|unique:users',
'password' => 'required',
'password_confirmation' => 'required|same:password',
'firstname' => 'required',
'lastname' => 'required',
'schoolname' => 'required',
'address1' => 'required',
'address2' => 'required',
'postcode' => 'required',
'city' => 'required'
];
}
and in my UserController:
use Olp\Forms\UserForm;
class UsersController extends \BaseController {
function __construct(UserForm $userForm)
{
$this->userForm = $userForm;
}

I'm not a Laravel guy, but a quick check on their documentation indicates that Resource Controllers support PUT in addition to other HTTP verbs.
I was not able to figure out how to add HTTP verb support to an arbitrary action, but this indicates that you can name a controller action prefixed with the verb it responds to
public function putUpdate($id)

Related

How to Update Order custom field in Shopware 6 during order process?

I want to add a selector for date during order process in checkout. In which step should the custom field of an order be updated? And how is the custom field update done for order or other entity?
I want to add the fields as it is shown in official docs.
$this->customFieldSetRepository->create([
[
'name' => 'swag_example',
'customFields' => [
['name' => 'swag_example_size', 'type' => CustomFieldTypes::INT],
['name' => 'swag_example_color', 'type' => CustomFieldTypes::TEXT]
]
]
], $context);
Where exactly do you want to add that data during the order process?
One example would be from confirm to finish -> the cart is converted to an order.
You just need to create a Subscriber for that:
<?php
class OrderProcessSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return [
CartConvertedEvent::class => 'addCustomFieldsToConvertedCart',
];
}
public function addCustomFieldsToConvertedCart(CartConvertedEvent $event)
{
$convertedCart['customFields']['my_custom_field'] = 'test';
$event->setConvertedCart($convertedCart);
}
}
?>

ZF3 development of RestAPI: handling Post request for

I am new to Zf3, and developing Email Restful API.
having difficulties in handling request. I can't get POST parameters.i think there is some problem in module.config.php > 'router'
Questions
1 How can I get POST variables from request.
2 I found it when I request page (using Postman)
- if I passes ID, controller call get($id) method
- if I POST variables controller calls Create($data) function.
--is this always the case ? and is it good to write zendEmail code inside create($data) method
.
bwsmail controller
(create function)
public function create($data)
{
echo $this->getRequest()->getPost('id', "no value");
// Output
// this returns no value
echo $this->getRequest();
// Output
//POST http://localhost:8080/bwsmail/mail?id=123456789 HTTP/1.1
//Cookie: PHPSESSID=p5i7o8lm2ed0iocdhkc8jvos01
//Cache-Control: no-cache
//Postman-Token: ccaf5b37-02a2-4537-bf3f-c1dc419d8ceb
//User-Agent: PostmanRuntime/7.6.1
//Accept: */*
//Host: localhost:8080
//Accept-Encoding: gzip, deflate
//Content-Length: 0
//Connection: keep-alive
$response = $this->getResponseWithHeader()->setContent( __METHOD__.' create new item of data :<b>'.'</b>');
return $response;
}
module.config.php (route)
'bwsmail' => [
'type' => Literal::class,
'options' => [
'route' => '/bwsmail',
'defaults' => [
'controller' => Controller\BwsMailController::class,
]
],
'may_terminate' => true,
'child_routes' => [
'mail' => [
'type' => 'segment',
'options' => [
'route' => '/mail[/:id]',
'constraints'=>
[
'id' => '[0-9a-zA-Z]+',
],
'defaults' => [
'controller' => Controller\BwsMailController::class,
]
],
],
],
],
if BwsMailController extends AbstractController or AbstractRestfulController you can simply: $this->params()->fromRoute() or ->fromQuery() if you're using a get string. For example:
$routeParamId = $this->params()->fromRoute('id', null);
This gets the parameter id as it is defined in the route configuration. If it's not set, it will default to null.
If you have a GET url, something like: site.com/mail?id=123, then you do:
$getParamId = $this->params()->fromQuery('id', null); // sets '123' in var
More options are available, have a good read of the routing documentation.

Symfony2.7 : Twig render controller() ignore my parameters

I have a trouble with a symfony exeption and some parameter i try to get. I have absolutely no idea why i get this exception after thousands checks of my code and on the internet.
The exception is :
An exception has been thrown during the rendering of a template ("Some mandatory parameters are missing ("slug") to generate a URL for route "blogcomment_create".") in #Blog\Default\Blog\singlePost.html.twig at line 29.
The route configuration :
blogcomment_create:
path: /{slug}/comment/create/
defaults: { _controller: "BlogBundle:Comment:create" }
requirements: { methods: post }
My code in my twig template to import my controller:
<footer>
{{ render(controller('BlogBundle:Comment:create', {
'slug': Post.slugname
})) }}
</footer>
My Action declaration :
public function createAction(Request $request, $slug = null)
{
//...
}
I starting to get mad with this exception, i have no clues why i get her and i realy need a good pair of eyes.
i try tons of exemples :
How to insert a Controller in Twig with "render" in Symfony 2.2?
symfony2 - twig - how to render a twig template from inside a twig template
Change template via parameter when render a controller action?
...
Here a dump of the fonction :
object(Symfony\Component\HttpKernel\Controller\ControllerReference)[992]
public 'controller' =>
string 'BlogBundle:Comment:create' (length=31)
public 'attributes' =>
array (size=1)
'slug' => string 'article-de-test-yolowowo' (length=24)
public 'query' =>
array (size=0)
empty
Ok i finaly get it !
The problem was not at all in my twig template but in my controller. I have a fonction to generate my form in this controller. I call her in my action :
private function createCreateForm(Comment $entity, $slug)
{
$form = $this->createForm(new CommentType(), $entity, array(
'action' => $this->generateUrl('blogcomment_create', array('slug' => $slug)),
'method' => 'POST',
));
$form->add('submit', 'submit', array('label' => 'Create'));
return $form;
}
In this function i forgot to pass parameters in this fonction :
$this->generateUrl()
I really need to sleep sooner when i get that kind of problems >.>
I hope my problem will help other peoples in the future.

Can a Symfony 2 Action be made initially accessible only from another Action?

I struggled to express what I mean in the title of the question! I'll do my best to make more sense here...
Symfony 2.7
I have a Form, which when it is submitted and successfully validated I would like to feed into a second, independent Form, for further user activity. I would like initial values in the second form to be provided by the first, but that second form then to be independent, e.g. it can go through its own separate submission/validation steps.
I do not want:
it to be possible for a user to go straight to the second form
to have to pass values for the second form as querystring parameters
to use Javascript to achieve this
to persist data to a DB in the first form and pick it up in the second
Conceptually, I would like to be able to validate the first form, and then in the Controller to pass the data received to a different Action, which would show the new Form to the user. Further user submissions would then be handled by the new Action. I feel like this should be possible, I'm just not sure how to make it happen! In a way I'd like the second Action to be private, but it does need to be public so that the second form can be submitted. I'd like to be able to pass data to the second Action directly using an object, but I don't want to expose that entry point as a standard Route.
Thanks in advance.
Sorry for any lack of clarity in the question. Here's how I solved it (I'd still be interested in any different/better solutions):
I created a separate FormType (ReportConfirmType) and Action (ConfirmAction) for the second step. ReportConfirmType has the type of Data Class, and essentially all the same fields as the original FormType (ReportType), but with them all marked readonly. The route is very similar. I also created a private method to act as the "glue" between the first and second steps.
When I'm finished with my first step, I then call the private method, passing it the validated data from the first step (which can be used unchanged). This method sets up the second form and returns the second view. The action of the form needs to be changed to that of the second route.
All subsequent submissions will go to the new route, and when the second form validates I can carry out the final activities of the process.
Here's some example code to illustrate further:
ReportType
class ReportType extends AbstractType{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', 'text')
->add('completedBy', 'text')
->add('comments', 'textarea', ['required' => false])
->add('format', 'choice', ['choices' => ['pdf' => 'PDF', 'word' => 'MS Word'] ])
->add('save', 'submit', ['label' => 'Submit', 'attr' => ['class' => 'btn btn-primary']])
->getForm();
}
...
ReportConfirmType
class ReportConfirmType extends AbstractType{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', 'text', ['attr' => ['readonly' => 'readonly']])
->add('completedBy', 'text', ['attr' => ['readonly' => 'readonly']])
->add('comments', 'textarea', ['required' => false, 'attr' => ['readonly' => 'readonly']])
->add('format', 'choice', ['choices' => ['pdf' => 'PDF', 'word' => 'MS Word'], 'attr' => ['readonly' => 'readonly'] ])
->add('agree', 'checkbox', ['mapped' => false, 'label' => 'I agree', 'constraints' => [new IsTrue()]])
->add('save', 'submit', ['label' => 'Submit', 'attr' => ['class' => 'btn btn-primary']])
->getForm();
}
...
ReportController
class ReportController extends Controller
{
public function indexAction(Request $request, $id)
{
$form = $this->createForm(new ReportType(), new ReportDetails() );
$form->handleRequest($request);
if ($form->isValid()) {
return $this->confirmPseudoAction($id, $form);
}
return $this->render('Bundle:Report:index.html.twig', ['form'=> $form->createView()]);
}
private function confirmPseudoAction($id, \Symfony\Component\Form\Form $form)
{
$action = $this->generateUrl('form_confirm_report', ['id' => $id]);
$confirmForm = $this->createForm(new ReportConfirmType(), $form->getData(), ['action' => $action]);
return $this->render('Bundle:Report:confirm.html.twig', ['form'=> $confirmForm->createView()]);
}
public function confirmAction(Request $request, $id)
{
$form = $this->createForm(new ReportConfirmType(), new ReportDetails() );
$form->handleRequest($request);
if ($form->isValid()) {
return $this->generateReport($id, $form->getData());
}
return $this->render('Bundle:Report:confirm.html.twig', ['form'=> $form->createView()]);
}
...
routing.yml
form_report:
path: /form/{id}/report
defaults: { _controller: Bundle:Report:index }
requirements:
id: \d+
form_confirm_report:
path: /form/{id}/reportConfirm
defaults: { _controller: Bundle:Report:confirm }
requirements:
id: \d+
And this does what I want! There may be an easier way, but I've done it now...
I believe you can use dynamic generation for submitted forms.
It allows you to customize the form specific to the data that was submitted by the user

Dynamically map manyToOne relations

I'm trying to create Symfony Bundle in which entities are defined which can be used in a one-to-many/many-to-one relationship without the needing to rewrite the mapping manually.
I do this by subscribing to the loadClassMetadata event and adding the mapping based on the Interfaces they implement. It is not as simple as using the ResolveTargetEntityListener because that will simply substitute an interface with the concrete class.
An example. I have a Address and a Customer entity. A Customer has many Addresses.
But another bundle may redefine the Customer (or a totally different Entity which can have multiple Addresses). For this reason the Customer implements the AddressableInterface. For ease of use I've implemented this interface in a trait.
In the subscriber I check if the class implements the AddressableInterface. If so it adds an OneToMany to the Address and an ManyToOne to the class which implements the AddressableInterface. (In this example the Customer class)
However this leaves the following error:
The association Entity\Customer#addresses refers to the owning side field Entity\Address#subject which does not exist.
But I setup to association both ways in my subscriber.
Below is the essence of my code.
namespace Entity;
class Address
{
public $subject;
}
namespace Entity;
class Customer implements AddressableInterface
{
use Traits/Addressable;
}
namespace Traits;
trait Addressable //Implements all methods from AddressableInterface
{
protected $addresses;
public function getAddresses()
{
return $this->addresses;
}
public function addAddress(AddressInterface $address)
{
$this->addresses->add($address);
}
public function removeAddress(AddressInterface $address)
{
$this->addresses->removeElement($address);
}
}
And the event subscriber
class DynamicAddressBindingSubscriber implements EventSubscriber
{
public function getSubscribedEvents()
{
return [Events::loadClassMetadata];
}
public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs)
{
$metadata = $eventArgs->getClassMetadata();
$class = $metadata->getReflectionClass();
if (!in_array(AddressableInterface::class, $class->getInterfaceNames())) {
return;
}
$factory = new \Doctrine\ORM\Mapping\ClassMetadataFactory;
$factory->setEntityManager($eventArgs->getEntityManager());
$addressMetadata = $factory->getMetadataFor(Address::class);
$addressMetadata->mapManyToOne(
[
"targetEntity" => $class->getName(),
"fieldName" => "subject",
"inversedBy" => "addresses"
]
);
$metadata->mapOneToMany(
[
'targetEntity' => Address::class,
'fieldName' => 'addresses',
'mappedBy' => 'subject'
]
);
}
}
I've looked at multiple examples and based most of my code on this article and the Doctrine Bundle source. But I'm stuck at this point because I have no idea why the association can't find the owing side.
Your address class doesn't have getter/setter for the subject field.
Another thing is that if you want to bind addresses to any class, you might prefer to make it a manyToMany relations. I do so with attachments like this:
$metadata->mapManyToMany([
'targetEntity' => '...\FilesBundle\Entity\Attachment',
'fieldName' => 'attachments',
'cascade' => array('persist'),
'joinTable' => array(
'name' => strtolower($namingStrategy->classToTableName($metadata->getName())) . '_attachment',
'joinColumns' => array(
array(
'name' => $namingStrategy->joinKeyColumnName($metadata->getName()),
'referencedColumnName' => $namingStrategy->referenceColumnName(),
'onDelete' => 'CASCADE',
'onUpdate' => 'CASCADE',
),
),
'inverseJoinColumns' => array(
array(
'name' => 'file_id',
'referencedColumnName' => $namingStrategy->referenceColumnName(),
'onDelete' => 'CASCADE',
'onUpdate' => 'CASCADE',
),
)
)
]);
where namingStrategy comes from the event:
$namingStrategy = $eventArgs
->getEntityManager()
->getConfiguration()
->getNamingStrategy()
;

Resources