Model Binding in Symfony - php

From few days I'm struggling with implementation of model binding mechanism known from ASP MVC into world of Symfony REST, but with no luck.
I encountered something similar - #ParamConverter, but from tries I made it looks like its not what I'm looking for.
My attempts ended at Body Converter. When I POSTed my form-data to desired route : /api/posts I received error about not existing route. debug:router gave me route different that i expected : /api/posts/{post}.{_format}. It seems to me that Body converters want me to send data in json or xml, but i want to send form-data because of files. Solution what im looking for should work like this :
/**
* #ParamConverter("Post", class="BlogBundle:Post")
*/
public function postPostAction(Post $post)
{
if($post->isValid())
{
$em->persist($post);
}
}
Do anyone can give some clues, or implementation how to make it work? Because i belive I'm not only one who want to achive such elegant way

Related

Why is Yii2 framework showing a 404 error when creating custom view page?

I'm attempting to create a custom display in yii2 framework using this code in my site controller:
/******/
public function actionChartDisplay()
{
return $this->render('chartDisplay');
}
for testing purposes I pasted the form name in my actionAbout function as a parameter to the render function in it. It worked with this:
public function actionAbout()
{
return $this->render('chartDisplay');
}
But I need to create many custom views in yii2 and this won't be a solution.
This is the error I get
I'm curious as to why it is. Since I was following this tutorial and came across this weird behaviour.
My 'chartDisplay.php' file is merely a "hello world" that does work with the action about function.
in yii2, the controllers and actions with multiple words, that are marked by capital letters are divided by - in your request, so in your case the route would be some/chart-display
Apparently as #SmartCoder pointed out it was an error on how Yii2 Handles the action functions in its controller however I didn't mark his answer as the solution right away because implementing it resulted in an error. So aside from that I'm posting the way I solved it.
So instead of using chart-display I simply changed it for "charts" like this:
public function actionCharts(){
return $this->render('charts');
}
Changed the name of my file so it fits to charts.php and it worked.

DynamicRoute Plugin for CakePHP giving 404 errors

I'm using this plugin to create slug-based URL's on a CakePHP 2 web application: https://github.com/josegonzalez/cakephp-dynamic-route
The documentation suggests that you would call a Cake controller like so:
posts/view?id=45
My URL's currently work as Cake's default behaviour. So using the example above posts/view/45 works but posts/view?id=45 does not.
When I call URL's as per the example I get a 404 error.
My functions are written like so (e.g. in PostsController.php):
public function view($id) {
// logic to load post by ID
// ...
}
There is almost no documentaiton for the above plugin. Has anyone used it or know where I'm going wrong? It seems you cannot pass a GET variable such as 'id' to the 'view' function, without re-factoring the code inside it to accept passed parameters?
The solution appears to be that some of the controller functions needed to be re-written to accept GET style parameters.
In the documentation a "spec" field looks like this:
posts/view?id=45
In a regular CakePHP application the route for that would be like this: posts/view/45
The plugin simply doesn't work if you put the second style of route (posts/view/45) into the "spec" field.
So the answer is the "spec" fields must be like so:
posts/view?id=45 and then your controller functions have to be re-written, e.g.
public function view($id) {
if (isset($this->request->params['id'])) {
$id = $this->request->params['id'];
}
}
Doing this means that it will work with a parameter (view?id=45) or a standard Cake call (view/45).
Please note this has nothing to do with the "slug" aspect of the plugin - the "slug" can be anything, as per the documentation examples: /why-isnt-this-pup-asleep or /manchester/cakephp-developers-dance-to-beyonce. The original question was asking if there was a way to map a "spec" given in the documentation to a Cake controller function without having to modify it like I have above. The answer seems to be no, you have to modify them!

Controller as Service - How to pass and return values in an advanced case?

Using Symfony, I am displaying a table with some entries the user is able to select from. There is a little more complexity as this might include calling some further actions e. g. for filtering the table entries, sorting by different criteria, etc.
I have implemented the whole thing in an own bundle, let's say ChoiceTableBundle (with ChoiceTableController). Now I would like to be able to use this bundle from other bundles, sometimes with some more parametrization.
My desired workflow would then look like this:
User is currently working with Bundle OtherBundle and triggers chooseAction.
chooseAction forwards to ChoiceTableController (resp. its default entry action).
Within ChoiceTableBundle, the user is able to navigate, filter, sort, ... using the actions and routing supplied by this bundle.
When the user has made his choice, he triggers another action (like choiceFinishedAction) and the control flow returns to OtherBundle, handing over the results of the users choice.
Based on these results, OtherBundle can then continue working.
Additionally, OtherOtherBundle (and some more...) should also be able to use this workflow, possibly passing some configuration values to ChoiceTableBundle to make it behave a little different.
I have read about the "Controller as Service" pattern of Symfony 2 and IMHO it's the right approach here (if not, please tell me ;)). So I would make a service out of ChoiceTableController and use it from the other bundles. Anyway, with the workflow above in mind, I don't see a "good" way to achieve this:
How can I pass over configuration parameters to ChoiceTableBundle (resp. ChoiceTableController), if neccessary?
How can ChoiceTableBundle know from where it was called?
How can I return the results to this calling bundle?
Basic approaches could be to store the values in the session or to create an intermediate object being passed. Both do not seem particularly elegant to me. Can you please give me a shove in the right direction? Many thanks in advance!
The main question is if you really need to call your filtering / searching logic as a controller action. Do you really need to make a request?
I would say it could be also doable just by passing all the required data to a service you define.
This service you should create from the guts of your ChoiceTableBundleand let both you ChoiceTableBundle and your OtherBundle to use the extracted service.
service / library way
// register it in your service container
class FilteredDataProvider
{
/**
* #return customObjectInterface or scallar or whatever you like
*/
public function doFiltering($searchString, $order)
{
return $this->filterAndReturnData($searchString, $order)
}
}
...
class OtherBundleController extends Controller {
public function showStuffAction() {
$result = $this->container->get('filter_data_provider')
->doFiltering('text', 'ascending')
}
}
controller way
The whole thing can be accomplished with the same approach as lipp/imagine bundle uses.
Have a controller as service and call/send all the required information to that controller when you need some results, you can also send whole request.
class MyController extends Controller
{
public function indexAction()
{
// RedirectResponse object
$responeFromYourSearchFilterAction = $this->container
->get('my_search_filter_controller')
->filterSearchAction(
$this->request, // http request
'parameter1' // like search string
'parameterX' // like sorting direction
);
// do something with the response
// ..
}
}
A separate service class would be much more flexible. Also if you need other parameters or Request object you can always provide it.
Info how to declare controller as service is here:
http://symfony.com/doc/current/cookbook/controller/service.html
How liip uses it:
https://github.com/liip/LiipImagineBundle#using-the-controller-as-a-service

filters are not being executed

I'm writing a PHP 5.6 application using apigility 1.0.4 and zend framework 2.3.3
with apigility I created a new reset service called drink
and created a filed called "drink_flavor".
I used the following filters:
Zend\Filter\StringToLower
Zend\Filter\StringTrim
now I use postman to test it.
so i configured the url to http://url/drink
I'm sending post data with raw json with the following text:
{"drink_flavor" : " AAA"}
as you can see i have a space at the beginning and the letters are capital.
now if my controller code i have the following:
public function create($data)
{
die(var_export($data,1));
}
so i'm just printing the data.
if I understood everything correctly instead of getting ' AAA' i should have gotten 'aaa'
because of my filters but I still got the unmodified data which is " AAA".
any ideas what's missing?
You have to pull the data from you InputFilter to get the filtered data.
So inside your listener:
// Get filtered data
$inputFilter = $this->getInputFilter();
$data = $inputFilter->getValues();
And continue to use that $data array instead.
The $data param in your create method is the raw/unfiltered POST data.
You should be careful using that $data as a source for your methods since anything sent by the client will be in there.
I think this is not so clearly explained in the Apigility documentation and I think that a lot of users make this mistake. I wrote about this in an issue on GitHub.

PHP REST API Routing

I have been looking at APIs and developing a REST API for a project that we are working on.
The API only accepts connections from one source in JSON format, I understand that bit fine.
If understand the majority of what is being said, however I don't understand the 3rd code example down and where the routing information would go.
The example they have provided is:
$data = RestUtils::processRequest();
switch($data->getMethod)
{
case 'get':
// retrieve a list of users
break;
case 'post':
$user = new User();
$user->setFirstName($data->getData()->first_name); // just for example, this should be done cleaner
// and so on...
$user->save();
break;
// etc, etc, etc...
}
The part I am unsure on is how to accept the original request i.e. /get/user/1 - how do you route that to the correct part of the script.
If there has been another SO question (I have searched for quite some time) or any further educational examples please do point me in the right direction.
Update
I have found a few routing PHP classes out there, but nothing thats just small and does what it says on the tin, everything seems to do routing + 2000 other things on top.
I now have all the classes I need for this project named as I wish to access them from the URI i.e.:
/data/users
/data/users/1
/hash/users
/hash/users/1
/put/users/1?json={data}
So all of these should use the users class, then one of the data, hash or put methods passing anything additional after that into the method as arguments.
If anyone could just explain how that bit works that would be a huge help!
Thanks :)
From the outset it looks like the website you've pointed out does not include a router or a dispatcher. There are plenty of PHP5 frameworks around which include a route and/or a dispatch or some description. (http://en.wikipedia.org/wiki/Comparison_of_Web_application_frameworks#PHP)
A router would be a class which have a list of predefined routes these could be really basic or quite complex, all depends on want you want to do. A good REST router IMO would look something like this:
:module/:controller/:params
And then the router would then router to the correct action based on the HTTP request (GET, POST, PUT, DELETE, OPTIONS)
public function getAction($id) {
// Load item $id
}
In your case, you will need a redirect rule that will send the request to something like this
index.php?user=id. Then you can process the get request.
The best solution I found for php REST architecture (including routing) is:
http://peej.github.com/tonic/

Categories