I want to return in my RandomController::indexAction() an XML Response:
return new Response($this->renderView(
'AcmeRandomBundle:Random:index.xml.twig',
array(
'randomParameter' => $randomParameter
)
));
where index.xml.twig is like that:
<?xml version="1.0" encoding="UTF-8"?>
<randomTag>
{{ randomParameter }}
</randomTag>
When I want to open this action in firefox, I get in firebug:
<html>
<body>
<randomTag>
randomValue
</randomTag>
</body>
</html>
How to return correct XML response?
Try adding correct header on the Response Object like:
$response->headers->set('Content-Type', 'text/xml');
Otherwise add the correct annotation (defaults) on your Controller method like this example:
/**
* #Route("/hello/{name}", defaults={"_format"="xml"}, name="_demo_hello")
* #Template()
*/
public function helloAction($name)
{
return array('name' => $name);
}
Look at the guide for further explaination
If you have many XmlResponse to return, consider creating your own Response object:
<?php
namespace App\Component\HttpFoundation;
use Symfony\Component\HttpFoundation\Response;
class XmlResponse extends Response
{
public function __construct(?string $content = '', int $status = 200, array $headers = [])
{
parent::__construct($content, $status, array_merge($headers, [
'Content-Type' => 'text/xml',
]));
}
}
You can then return new XmlResponse($xmlBody); in your controllers.
Related
I am trying to test a route that does something different in the controller whether or not the request is ajax or not.
public function someAction(Request $request)
{
if($request->ajax()){
// do something for ajax request
return response()->json(['message'=>'Request is ajax']);
}else{
// do something else for normal requests
return response()->json(['message'=>'Not ajax']);
}
}
My test:
public function testAjaxRoute()
{
$url = '/the-route-to-controller-action';
$response = $this->json('GET', $url);
dd($response->dump());
}
When I run the test and just dump the response I get back 'Not ajax' - which makes sense I guess cause $this->json() is just expecting back a json response, not necessarily making an ajax request. But how can I correctly test this? I have been commenting the...
// if($request->ajax(){
...need to test this code
// }else{
// ...
// }
every time I need to run the test on that portion of code. I'm looking for how to make an ajax request in my test case I guess...
In Laravel 5.4 tests this->post() and this->get() methods accept headers as the third parameter.
Set HTTP_X-Requested-With to XMLHttpRequest
$this->post($url, $data, array('HTTP_X-Requested-With' => 'XMLHttpRequest'));
I added two methods to tests/TestCase.php to make easier.
<?php
namespace Tests;
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
abstract class TestCase extends BaseTestCase
{
use CreatesApplication;
/**
* Make ajax POST request
*/
protected function ajaxPost($uri, array $data = [])
{
return $this->post($uri, $data, array('HTTP_X-Requested-With' => 'XMLHttpRequest'));
}
/**
* Make ajax GET request
*/
protected function ajaxGet($uri, array $data = [])
{
return $this->get($uri, array('HTTP_X-Requested-With' => 'XMLHttpRequest'));
}
}
Then from within any test, let's say tests/Feature/HomePageTest.php, I can just do:
public function testAjaxRoute()
{
$url = '/ajax-route';
$response = $this->ajaxGet($url)
->assertSuccessful()
->assertJson([
'error' => FALSE,
'message' => 'Some data'
]);
}
Try $response = \Request::create($url, 'GET', ["X-Requested-With" => "XMLHttpRequest"])->json();
This is what worked for me
$result = $this->actingAs($user)->json('delete', '/order/' . $order->id, ['id' => $order->id, "_method" => "DELETE"], ['X-Requested-With' => 'XMLHttpRequest']);
$this->assertEquals(403, $result->response->status());
I'm quite new to Yii 2 but here goes:
What I'm trying to accomplish is to set up a controller that simply reads in any json data posted to it.
I'm slightly confused as to how this works in Yii.
What I've tried so far is set up a controller called ftest to see if I could get it returning some json which seems to work:
public function actionFTest(){
$request = Yii::$app->request;
Yii::$app->response->format = \yii\web\Response::FORMAT_RAW;
$headers = Yii::$app->response->headers;
$headers->add('Content-Type', 'text/json');
$response = Yii::$app->response;
$response->format = \yii\web\Response::FORMAT_JSON;
$response->data = ['message' => 'Evan .. WHERE ARE YOU?'];
//$notificationData = json_decode(file_get_contents("php://input"), true);
//echo var_dump($notificationData);
}
Its a bit messy since I've been throwing in code back and forth. I know I should usually return something like $this->render(etc), but I'm not sure what I need to return as a view.
Thanks for any help you can provide
This might be helpful
use Yii;
use yii\web\Response;
public function actionFTest()
{
Yii::$app->response->format = Response::FORMAT_JSON;
}
Then after that just return a simple array like that:
return ['param' => $value];
Read this
http://www.yiiframework.com/doc-2.0/yii-web-response.html#$format-detail
I recommend you using behavior and contentNegotiator
public function behaviors()
{
return array_merge(
parent::behaviors(),
[
'contentNegotiator' => [
'class' => 'yii\filters\ContentNegotiator',
'formats' => [
'application/json' => \yii\web\Response::FORMAT_JSON,
]
]
],
);
}
So I'm making an API that produces a json response instead of doing View::make('foo', compact('bar')).
With blade templating
My controller simply returns the Eloquent model for Users:
public function index()
{
return User::all();
}
protected function getFooAttribute()
{
return 'bar';
}
And my view will be able to use it, along with the foo attribute (which isn't a field in the user's table).
#foreach($users as $user)
<p>{{$user->name}} {{$user->foo}}</p>
#endforeach
With Angular JS + json response
However, now that I'm not using blade but rather grabbing the json and displaying it with Angular JS I'm not able to do this:
<p ng-repeat="user in users">{{user.name}} {{user.foo}}</p>
Is there a way to cleanly pack the json response such that I have:
[{"name": "John", "foo": "bar"}, ...]
Warning: I've never built an API before and I've only started programming/web dev last December. This is my attempt:
public function index()
{
$response = User::all();
foreach($response as $r)
{
$r->foo = $r->foo;
}
return $response;
}
Yeah there is, example:
return Response::json([User:all()], 200);
Usually you want more than that though..
return Response::json([
'error' => false,
'data' => User:all()
], 200);
200 is the HTTP Status Code.
To include the attributes you need to specify these attributes to automatically append onto the response in your model.
protected $appends = array('foo');
public function getFooAttribute()
{
return 'bar';
}
In an implementation of PdfBundle, adding a stylesheet to the Pdf() annotation neither throws an error or is used. The page rendered is a default 8.5 x 11, not the expected 5 x 8. Replacing the stylesheet file name with random characters does not elicit an error. Is other configuration required to take advantage of a stylesheet?
Controller:
/**
* #Pdf(stylesheet="ManaClientBundle:Test:pdfstyle.xml.twig",
* #Route("/card")
*/
public function cardAction() {
$em = $this->getDoctrine()->getManager();
$household = $em->getRepository('ManaClientBundle:Household')->find(8607);
$facade = $this->get('ps_pdf.facade');
$response = new Response();
$this->render('ManaClientBundle:Test:card.pdf.twig', array(
'household' => $household,
'date' => date_create(),
), $response);
$xml = $response->getContent();
$content = $facade->render($xml);
return new Response($content, 200, array('content-type' => 'application/pdf'));
}
Template (in .../Resources/views/Test/)
<pdf>
<page id="card">
...
</page>
</pdf>
Stylesheet in .../Resources/views/Test/pdfstyle.xml.twig
<stylesheet>
<page id="card" page-size="8in:5in" margin=".5in" font-size="12">
</page>
</stylesheet>
From the author of the bundle:
If you use $facade object directly, Pdf annotation is unnecessary. You should use Pdf annotation when you want to use pdf rendering in implicit way. In you code you should pass stylesheet xml as second argument of $facade->render(...) method.
Controller now reads:
/**
* #Route("/card")
*/
public function cardAction() {
$em = $this->getDoctrine()->getManager();
$household = $em->getRepository('ManaClientBundle:Household')->find(8607);
$stylesheetXml = $this->renderView('ManaClientBundle:Test:pdfstyle.xml.twig', array());
$facade = $this->get('ps_pdf.facade');
$response = new Response();
$this->render('ManaClientBundle:Test:card.pdf.twig', array(
'household' => $household,
'date' => date_create(),
), $response);
$xml = $response->getContent();
$content = $facade->render($xml, $stylesheetXml);
return new Response($content, 200, array('content-type' => 'application/pdf'));
}
So far, I have figured out how to return a typical JSON response in Zend Framework 2. First, I added the ViewJsonStrategy to the strategies section of the view_manager configuration. Then, instead of returning a ViewModel instance from the controller action, I return a JsonModel instance with all my variables set.
Now that I've figured that piece out, I need to understand how to render a view and return it within that JSON response. In ZF1, I was able to use $this->view->render($scriptName), which returned the HTML as a string. In ZF2, the Zend\View\View::render(...) method returns void.
So... how can I render an HTML view script and return it in a JSON response in one request?
This is what I have right now:
if ($this->getRequest()->isXmlHttpRequest()) {
$jsonModel = new JsonModel(...);
/* #todo Render HTML script into `$html` variable, and add to `JsonModel` */
return $jsonModel;
} else {
return new ViewModel(...);
}
OK, i think i finally understood what you're doing. I've found a solution that i think matches your criteria. Though i am sure that there is room for improvement, as there's some nasty handwork to be done...
public function indexAction()
{
if (!$this->getRequest()->isXmlHttpRequest()) {
return array();
}
$htmlViewPart = new ViewModel();
$htmlViewPart->setTerminal(true)
->setTemplate('module/controller/action')
->setVariables(array(
'key' => 'value'
));
$htmlOutput = $this->getServiceLocator()
->get('viewrenderer')
->render($htmlViewPart);
$jsonModel = new JsonModel();
$jsonModel->setVariables(array(
'html' => $htmlOutput,
'jsonVar1' => 'jsonVal2',
'jsonArray' => array(1,2,3,4,5,6)
));
return $jsonModel;
}
As you can see, the templateMap i create is ... nasty ... it's annoying and i'm sure it can be improved by quite a bit. It's a working solution but just not a clean one. Maybe somehow one would be able to grab the, probably already instantiated, default PhpRenderer from the ServiceLocator with it's template- and path-mapping and then it should be cleaner.
Thanks to the comment ot #DrBeza the work needed to be done could be reduced by a fair amount. Now, as I'd initially wanted, we will grab the viewrenderer with all the template mapping intact and simply render the ViewModel directly. The only important factor is that you need to specify the fully qualified template to render (e.g.: "$module/$controller/$action")
I hope this will get you started though ;)
PS: Response looks like this:
Object:
html: "<h1>Hello World</h1>"
jsonArray: Array[6]
jsonVar1: "jsonVal2"
You can use more easy way to render view for your JSON response.
public function indexAction() {
$partial = $this->getServiceLocator()->get('viewhelpermanager')->get('partial');
$data = array(
'html' => $partial('MyModule/MyPartView.phtml', array("key" => "value")),
'jsonVar1' => 'jsonVal2',
'jsonArray' => array(1, 2, 3, 4, 5, 6));
$isAjax = $this->getRequest()->isXmlHttpRequest());
return isAjax?new JsonModel($data):new ViewModel($data);
}
Please note before use JsonModel class you need to config View Manager in module.config.php file of your module.
'view_manager' => array(
.................
'strategies' => array(
'ViewJsonStrategy',
),
.................
),
it is work for me and hope it help you.
In ZF 3 you can achieve the same result with this code
MyControllerFactory.php
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
$renderer = $container->get('ViewRenderer');
return new MyController(
$renderer
);
}
MyController.php
private $renderer;
public function __construct($renderer) {
$this->renderer = $renderer;
}
public function indexAction() {
$htmlViewPart = new ViewModel();
$htmlViewPart
->setTerminal(true)
->setTemplate('module/controller/action')
->setVariables(array('key' => 'value'));
$htmlOutput = $this->renderer->render($htmlViewPart);
$json = \Zend\Json\Json::encode(
array(
'html' => $htmlOutput,
'jsonVar1' => 'jsonVal2',
'jsonArray' => array(1, 2, 3, 4, 5, 6)
)
);
$response = $this->getResponse();
$response->setContent($json);
$response->getHeaders()->addHeaders(array(
'Content-Type' => 'application/json',
));
return $this->response;
}
As usual framework developer mess thing about AJAX following the rule why simple if might be complex Here is simple solution
in controller script
public function checkloginAction()
{
// some hosts need to this some not
//header ("Content-type: application/json"); // this work
// prepare json aray ....
$arr = $array("some" => .....);
echo json_encode($arr); // this works
exit;
}
This works in ZF1 and ZF2 as well
No need of view scrpt at all
If you use advise of ZF2 creator
use Zend\View\Model\JsonModel;
....
$result = new JsonModel($arr);
return $result;
AJAX got null as response at least in zf 2.0.0