Restful Controller in Zendframework 2 - how does its parameter work? - zend-framework2

This is my unit test for create function :
public function testCreate() {
$this->routeMatch->setMatchedRouteName('restful');
$this->request->setMethod('POST')
->setContent('name=A');
$result = $this->controller->dispatch($this->request);
$response = $this->controller->getResponse();
$this->assertEquals(403, $response->getStatusCode());
$this->assertArrayHasKey('id', $result);
}
And this is my function :
public function create($data) {
if (empty($data)) {
$this->response->setStatusCode(400);
return;
}
for ($i = 0; $i < count(self::$ideas); $i++) {
if (self::$ideas[$i]['name'] == $data['name']) {
$this->response->setStatusCode(404);
return;
}
}
//#todo: secure the API
self::$index++;
$tmpArray = array('id'=>self::$index, 'name'=>$data['name']);
$this->response->setStatusCode(403);
}
But it seems that the $data is always blank. Am I wrong at the part writing unit test ?
When I try to use curl POST with -d, the $data has value as what I post through curl. I'm a quite confused what is wrong here ?
Thanks for reading and looking forward to your answer :)
Answer
I've came up with my successful unit test http://pastebin.com/fwFe0Mi3
For more information, I use this module to implement restful controller

If you take a look at \Zend\Mvc\Controller\AbstractRestfulController method processPostData you will notice that the method create in your controller is given an array of the post params from the request object.
If you look at \Zend\Http\Request the $postParams property is populated by the setPost method.
Now the child class \Zend\Http\PhpEnvironment\Request (used by ZF2 when you are requesting something) that extends \Zend\Http\Request (above) on instantiation (__contruct method) calls the setPost method (above) giving it the $_POST array.
This means that eventually ZF2 internally feeds your controller's create method with the $_POST contents and not by parsing the request body.
Now to your code.
I don't think dispatch will do anything without you having set up the event framework first. Instead you can call the controllers execute method providing it with an MvcEvent. The MvcEvent needs to have the request you instantiated set.
Secondly, as described above you need to call the request's setPost and give it an array for the create method to work properly. (On the other hand PUT reads the data from the request body)
Try doing that and if you are still having trouble I will try and give you an example soon.

Related

Load service in functional test (Symfony4)

I'm trying to test a controller made with Symfony 4 with PHPUnit.
I'm using https://github.com/lexik/LexikJWTAuthenticationBundle to manage JWT.
This controllers should return a 200 if a valid JWT is given, a 401/403 otherwise.
The first part with the 401 response is easy: I just don't send any token
<?php
namespace App\Tests\Controller;
Class GraphQLControllerTest extends \Symfony\Bundle\FrameworkBundle\Test\WebTestCase {
function test_token(){
$client = static::createClient();
$client->request('GET', '/graphql');
// Check 401 response
$response = $client->getResponse();
$this->assertSame(401, $response->getStatusCode());
$this->assertSame('"Not authenticated"', $response->getContent());
}
}
The next part is tricky: how do I get my JWT encoder service in my test_token method in order to generate some tokens to test 200 and 403 responses?
If I were in a controller I could use Symfony autowiring or make a public alias of lexik_jwt_authentication.encoder to be used like this:
$this->container->get('lexik_jwt_authentication.encoder')
Loading manually the service in my test like this bellow seems inefficient as some of the arguments of the constructor are some objects, and some arguments of their own constructor are objects, and ...
new Lexik\Bundle\JWTAuthenticationBundle\Encoder\DefaultEncoder([some objects here])
This is what is nice with autowiring: you just get the service you want ready to be used.
=> What's the best way to get this service in my test?
Thanks!
It's now possible with Symfony 4.1 to load a private service within a test using the KernelTestCase

get the url in the middleware laravel

I have my middleware and inside it I am trying to reach the current url of the page. so I did something like that:
$url = Request::url();
and I used:
use App\Http\Requests;
use Illuminate\Http\Request;
but I keep getting the following error:
Non-static method Illuminate\Http\Request::url() should not be called statically, assuming $this from incompatible context
any ideas?
You can access the url from the Request Object:
public function handle($request, Closure $next)
{
$url = $request->url();
...
}
Request object has also fullUrl() and path() methods. Choose the one that fit your needs
In Laravel 5 the request is already passed into the handle() function
class MyMiddleware {
public function handle($request, Closure $next)
{
$url = $request->url();
// Do stuff here
return $next($request);
}
}
Laravel 5 tries to move away from facades (e.g: Calls such as Request::url()) in favour of using dependency injection, so you may notice some functions and such cannot be accessed the same as you did in 4.
Heres quite a nice explanation of dependency injection in Laravel 5 https://mattstauffer.co/blog/laravel-5.0-method-injection

ASP.NET MVC 4 Unit Test - Is there a way to mock HttpClientCertificate with Moq

My web app is using PKI authentication via a piv card. I grab the user's unique identifier information via HttpClientCertificate.Subject. The problem is that when I am unit testing, mock will not mock this class since it doesn't have a constructor. I tried following the advice on this thread:
How to mock HttpClientCertificate?
but it looks like the way he sets it up is to inject the client certificate through the controller's constructor which I dont' want to do since the controller already has access to the client certificate. I'm assuming thats what he is implying since he is using some type of adapter pattern. Anyone got any better sugguestions?
Why don't you wrap it into your own object?
class MyHttpClientCertificate
{
public MyHttpClientCertificate(HttpClientCertificate foo) { ... }
internal MyHttpClientCertificate() { ... }
}
Your issue is that the code is using the Request object to get the certificate, but that's not easily unit testable.
What I would do is add a function delegate that, by default, will use the Request object to return the HttpClientCertificate, but will allow overriding the implementation.
For the controller, add this:
internal Func<HttpClientCertificate> HttpClientCertificateGetter = () => {
return Request.ClientCertificate;
}
And in your Controller instead of using Request use HttpClientCertificateGetter.
Then in your unit test you mock the certificate and assign it to the getter function, like this:
var certMock = new Mock<HttpClientCertificate>();
HttpClientCertificate clientCertificate = certMock.Object;
requestMock.Setup(b => b.ClientCertificate).Returns(clientCertificate);
certMock.Setup(b => b.Certificate).Returns(new Byte[] { });
controller.HttpClientCertificateGetter = () => {certMock.Object};

Symfony: trying to retrieve a variable saved using sfContext::getInstance()

i have these methods in module1/actions/actions.class.php:
public function executeMethod1(sfWebRequest $request){
$a = 10;
sfContext::getInstance()->set('a', $a);
return $this->redirect('module1/method2');
}
public function executeMethod2(sfWebRequest $request){
echo sfContext::getInstance()->get('a');
}
When i execute module1/method1 i get this error:
"The "a" object does not exist in the current context."
Any idea?
Javi
The redirect is telling the browser to load another page which terminates the current action and results in a new request that has a new context.
There are three options here:
You could use a forward if you want module1/method2 to be executed as the result of the first request.
You could use a flash attribute to pass $a to the next request.
You could use a session attribute if $a has to live beyond the next request.
EDIT: You don't need the return statement before the redirect either.

Is it possible to implement X-HTTP-Method-Override in ASP.NET MVC?

I'm implementing a prototype of a RESTful API using ASP.NET MVC and apart from the odd bug here and there I've achieve all the requirements I set out at the start, apart from callers being able to use the X-HTTP-Method-Override custom header to override the HTTP method.
What I'd like is that the following request...
GET /someresource/123 HTTP/1.1
X-HTTP-Method-Override: DELETE
...would be dispatched to my controller method that implements the DELETE functionality rather than the GET functionality for that action (assuming that there are multiple methods implementing the action, and that they are marked with different [AcceptVerbs] attributes). So, given the following two methods, I would like the above request to be dispatched to the second one:
[ActionName("someresource")]
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult GetSomeResource(int id) { /* ... */ }
[ActionName("someresource")]
[AcceptVerbs(HttpVerbs.Delete)]
public ActionResult DeleteSomeResource(int id) { /* ... */ }
Does anybody know if this is possible? And how much work would it be to do so...?
You won't be able to use the [AcceptVerbs] attribute as-is since it's tied to the request's actual HTTP verb. Fortunately the [AcceptVerbs] attribute is very simple; you can see the source for yourself at http://www.codeplex.com/aspnet/SourceControl/changeset/view/21528#266431.
In short, subclass AcceptsVerbsAttribute and override the IsValidForRequest() method. The implementation would be something like the following:
string incomingVerb = controllerContext.HttpContext.Request.Headers["X-HTTP-Method-Override"] ?? controllerContext.HttpContext.Request.Method;
return Verbs.Contains(incomingVerb, StringComparer.OrdinalIgnoreCase);
Levi's answer is great. Additionally, I added a check in the custom AcceptsVerbsAttribute that also examines the FORM collection, so you can simply put a hidden input to trigger the DELETE (similar to MVC 2's Html.HttpMethodOverride(HttpVerbs.Delete)).
<input name="X-HTTP-Method-Override" type="hidden" value="DELETE" />
Change the incomingVerb assignment to:
string incomingVerb = controllerContext.HttpContext.Request.Headers["X-HTTP-Method-Override"] ?? controllerContext.HttpContext.Request.Form["X-HTTP-Method-Override"] ??controllerContext.HttpContext.Request.HttpMethod;
Be careful with this approach! See a related post by Stephen Walther.
Hopefully this helps someone.
Insert to Form:
<%= Html.HttpMethodOverride(HttpVerbs.Delete) %>
This conversation is a bit old, but I wanted to share what I have found using mvc 2:
Browsers support two HTTP verbs: GET and POST, but ASP.NET MVC 2 allows you to simulate Put, Get, and Delete using Html.HttpMethodOverride helper method. Internally, this works by sending the verb in an X-HTTP-Method-Override form field. The behavior of HttpMethodOverride is used by the [AcceptVerbs] attribute as well as the new shorter verb attributes:
For example, the action declaration:
[ActionName("someresource")]
[HttpDelete]
public ActionResult DeleteSomeResource()
should take responsibility for your get request that has the X-HTTP-Method-Override set to Delete.
I'm surprised that this hasn't been mentioned yet, but ASP.NET MVC natively supports X-HTTP-Method-Override and has been doing so from at least version 2. There's no need to write custom code to handle this.
It work in the following way:
Inside AcceptVerbsAttribute (also proxied by [HttpPut], [HttpPost], etc), there's an IsValidForRequest method. Inside that method, it checks with Request.GetHttpMethodOverride(), which returns the proper overriden HTTP method with the following conditions:
Overriding is only supported in POST requests. All others are ignored.
If the X-HTTP-Method-Override value is GET or POST, it's ignored. This makes sense, as you'd never need to override with these values.
It looks for X-HTTP-Method-Override in the following places in this priority:
1) HTTP Header
2) Form Body
3) Query String
If you're really curious, here's how GetHttpMethodOverride() looks (from MVC 3's source code):
public static class HttpRequestExtensions {
internal const string XHttpMethodOverrideKey = "X-HTTP-Method-Override";
public static string GetHttpMethodOverride(this HttpRequestBase request) {
if (request == null) {
throw new ArgumentNullException("request");
}
string incomingVerb = request.HttpMethod;
if (!String.Equals(incomingVerb, "POST", StringComparison.OrdinalIgnoreCase)) {
return incomingVerb;
}
string verbOverride = null;
string headerOverrideValue = request.Headers[XHttpMethodOverrideKey];
if (!String.IsNullOrEmpty(headerOverrideValue)) {
verbOverride = headerOverrideValue;
}
else {
string formOverrideValue = request.Form[XHttpMethodOverrideKey];
if (!String.IsNullOrEmpty(formOverrideValue)) {
verbOverride = formOverrideValue;
}
else {
string queryStringOverrideValue = request.QueryString[XHttpMethodOverrideKey];
if (!String.IsNullOrEmpty(queryStringOverrideValue)) {
verbOverride = queryStringOverrideValue;
}
}
}
if (verbOverride != null) {
if (!String.Equals(verbOverride, "GET", StringComparison.OrdinalIgnoreCase) &&
!String.Equals(verbOverride, "POST", StringComparison.OrdinalIgnoreCase)) {
incomingVerb = verbOverride;
}
}
return incomingVerb;
}
}
Have you looked at Simply Restful Routing? It already does this.
Edited Feb 2010 to add: Method overrides are built into MVC 2.
The X-HTTP-Method-Override is a custom header and most likely isn't supported by your web container.
Are you calling this from a web page? If so, you should probably use XmlHttpRequest with DELETE (or whatever verb you want). Better yet, use a JS framework to do the heavy lifting for you.
You could create an ActionFilter that implements OnActionExecuting, which fires before the controller action is invoked. You could then interrogate the request headers, and redirect based on the value of the X-HTTP-Method-Override header, when present.

Resources