I don't understand the semantics of the Symfony Routing Component's API.
From the first code example on the Routing Component documentation page:
$context = new RequestContext('/');
$matcher = new UrlMatcher($routes, $context);
$parameters = $matcher->match('/foo');
Why is the hostname and HTTP method passed in via $context and the path via a parameter to match()? Or is it? There is also a path parameter in the RequestContext constructor.
One gets the impression match() is supposed to be called multiple times with different paths within one request, which I can't imagine would ever happen.
After integrating the Routing Component into my application, I now have a hunch why
it was done like that.
Most of the properties of the RequestContext - method, request body, get parameters - can be used without modification, but depending on the desired path structure and server configuration (rewrite rules, etc.) there are multiple ways in which the path needs to be preprocessed.
This doesn't explain why the path is passed to the match() function and the request object is passed to the constructor, but it does explain why they are passed in separately.
Related
I have a controller has an action that looks something like this:
/**
* #Route("/my_route_path", name="my_route_name")
*/
public function doSomethingAction(Request $request)
{
$myPath = $request->getScheme().'://'.$request->getHttpHost().''.$request->getBasePath();
$data = file_get_contents($myPath. '/data_folder/data.json');
return $this->render('#Entry/my_template.html.twig', array(
'data' => json_decode($data, true)
));
}
And I create a functional test for this controller like this:
/** #test */
public function doSomething_should_success()
{
$client = static::createClient();
$crawler = $client->request('GET', '/my_route_path');
$this->assertEquals(200, $client->getResponse()->getStatusCode());
}
But I can't run the functional test I still get : Failed asserting that 500 is identical to 200
So, after I checked the test.log file I find this error : file_get_contents(http://localhost/data_folder/data.json) : failed to open stream
As now the problem is comming from $request->getBasePath() because always contain empty string but the expected behaviour is return PATH_TO_MY_PROJECT_FOLDER\web in my case must return projects\web_apps\MY_PROJECT_FOLDER_NAME\web
So, the simplified question: why the request object always contain an empty basePath string in the unit test but it works very well on the browser.
The Request object helps you handle the request of a client, that is something like GET /my_route_path plus lots of headers and a server that is directed at.
The web server passes those information on to php and symfony, and symfony will turn this into a Request object. Symfony has usually one entry point, which is public/index.php (symfony 4) or web/app.php (symfony 3) which is assumed to be / or possibly /basePath/ (the basepath will be communicated by the web server and handled by Symfony).
Symfony will generate a Request object, where the basepath is essentially abstracted away, and whenever you generate a url (via Controller::generateUrl) the base path is taken into account. that's why the basepath is important for Requests.
This is actually described pretty well in the comments of the Request's functions:
getBasePath vs getPathInfo.
However, this only concerns the public facing URLs and doesn't have anything to do with how you structure your project and where that project is located, because that's completely irrelevant to the Request (separation of concerns and stuff).
So I guess, you are actually looking for the root directory of your project.
To find the location of your project dir, there is the very base version, where you directly use the PHP magic var __DIR__ which contains the directory the current script file is in, and you can navigate from there. since controllers are usually located such that their path is projectdir/src/Controller/TheController.php a __DIR__.'/../.. would give you the projectdir. However, that's not really clean. The better version:
Depending on the symfony version you're using, you should retrieve the project dir via the ParameterBagInterface (symfony 4)
function doSomethingAction(ParameterBagInterface $params) {
$projectDir = $params->get('kernel.project_dir');
}
or via the container (symfony 3) see also: new in symfony 3.3: A simpler way to get the project root directory
function doSomethingAction() {
$projectDir = $this->getParameter('kernel.project_dir');
}
In my case I had to inyect RequestStack $stackand access the main request, after that my "BasePath" has value. This is because I where in a subrequest and I had to access to the top level of the request.
This post helped me to understood: Symfony2 - get main request's current route in twig partial/subrequest
/**
* #Route("/myroute", name="myroute")
*/
public function myroute(RequestStack $stack)
{
$request = $stack->getMainRequest();
$route = $request->getPathInfo();
}
I want to upgrade from ZF2 to ZF3 right now and has the following problem with using URL parameter in my PhpRenderer.
In ZF2 I use the HelperPluginManager to get Application, then the MvcEvent and finally the routeMatch:
$routeMatch = $this
->getHelperPluginManager()
->getServiceLocator()
->get('Application')
->getMvcEvent()
->getRouteMatch();
$parameterAction = $routeMatch->getParam('action');
In ZF3 there is a deprecation warning with using the getServiceLocator() (which makes sense, because it only returns the creationContext from the ServiceManager). I want to find a way not trigger the warning.
Configure the Application as a factory-using class (using \Zend\Mvc\Service\ApplicationFactory::class) also not works, because:
Zend\View\HelperPluginManager can only create instances of Zend\View\Helper\HelperInterface and/or callables.
Is there any way to get the Application context in my template (or better even the parameters of the URL)?
Your question title is "ZF3: Read out url parameter in PhpRenderer" while inside your question you asked another one.
You can get this in any controller (get URL parameters in ZF3):
$URLparam = (string)$this->params()->fromQuery('parameter', '');
For routeMatch, if you have a MvcEvent just use;
$event->getRouteMatch()
If you have container;
$container->getApplication()->getMvcEvent()->getRouteMatch();
If you want to access routeMatch in view there's no way except view helper like tasmaniski/zend-current-route
I have an odd app set up, multiple sub domains all pointing to the same Symfony2 install.
The subdomain simply changes a single parameter within the application so that different content is loaded.
This parameter is being cached however, so visiting a.site.com and then b.site.com makes A's content appear rather than B's.
Is there another approach I can use?
Is there a way I can add this parameter the cache's hash or something similar so that when the parameter changes within the app the content can change.
I am using this method to pass the constant from the sub domain into the Symfony2 application
How to pass a PHP constant as service argument in Symfony 2?
You can use Symfony's Request Object to get the URL and parse that for the subdomain. Use that to create your configuration parameter because it won't be cached.
Like this:
echo $request->getUri();
Symfony's API can be a great resource, but a bit hard to read. http://api.symfony.com/2.6/Symfony/Component/HttpFoundation/Request.html
I ended up writing a service to parse the host name, that service was then available within my Controllers.
class GameSystem {
public function getGameSystemName()
{
$ar = explode(".", $_SERVER['HTTP_HOST']);
$first = reset($ar);
$game_system_short_name = strtolower($first);
return $game_system_short_name;
}
}
Initially I had tried to use the constant value set in each subdomain's index file. But this was failing and having some really odd effects.
I'm trying to delete a resource using ZF1 rest client
$this->restClient = new Zend_Rest_Client('https://myurl.com');
$response = $this->restClient->delete('/service/'.$this->uuid.'.json?api_key='.$this->apikey);
but I get an error:
Path "/service/v-2149d050-c64b-0131-33b0-1231390c0c78.json?api_key=a-9a136a00-b340-0131-2662-1231390c0c78" is not a valid HTTP path
the web service documentation simply says to use
DELETE https://myurl.com/service/YOUR_UUID.json?api_key=YOUR_API_KEY
any idea on how to use this class?
thanks
DELETE https://myurl.com/service/YOUR_UUID.json?api_key=YOUR_API_KEY
That is not the path only, but a full URI. It breaks down to:
Path: service/YOUR_UUID.json
Query-Info: api_key=YOUR_API_KEY
For Zend rest client, you need to call one function per each parameter, and a parameter can not be named as a standard HTTP verb:
$client = new Zend_Rest_Client('https://exeample.com');
$client->api_key(YOUR_API_KEY);
$response = $client->restClient->delete('/service/'.$this->uuid.'.json);
For more information please see the Request Arguments section in the vendor documentation on how to pass arguments with your request.
I've been working on a project (which I'll keep specific details out of this post with randomized data) that involves integrating our system (PHP 5.3.x+) with an API (they provided a SDK) of a major company. They provided a WSDL and claimed ours needed to match their methods and they provided examples of how output (XML generated by the Soap Server) should look.
Right now, everything has been working as expected. When I send a XML request from SoapUI (an app I'm using to test) it all processes properly and such, but the XML output isn't matching closely with their examples and we believe they said we must be close to their examples.
Basically, we created an agnostic class we initialize with a service name and it initializes into a non-agnostic class which is used via the following:
/**
* The following is used to process Soap Server based on config and any optional settings.
*
* #param string $className
* #param array $options
* #param object $config
* #return Zend_Soap_Server
*/
public static function init($className, Array $options = null, $config = null)
{
// Used to define the class and return object.
$soap_server = new Zend_Soap_Server(null, $options);
$soap_server->setClass($className, null, (isset($config) ? $config : null));
$soap_server->handle();
exit;
}
The problem itself lies within the outputted response. How would you guys suggest we build the XML output if they're very specific about everything?
1.) One of our methods is moneyTransferRequest. When I send the XML over for this, it does find the method and processes it. However, they want it to show the method name, in the response, as moneyTransferResponse but it outputs moneyTransferRequestResponse.
2.) Our output (for variables and such sent back as an object) has multiple variables, we'll say $money for example. The field for this would return as:
<money xsi:type="xsd:string">10.0</money>
They would like it to be:
<ns1:money xsi:type="xsd:string">10.0</money>
in the return.
I appreciate any help and input on the subject.
The key feature of SOAP is that it uses XML, and XML can come in a bunch of different styles but still mean the same.
I think (but I can only guess because you didn't provide details) that your two issues might be non-existing.
1.) The name of the response XML structure should align with the name mentioned in the WSDL. YOU are publishing the WSDL, so you should check if these two match. Note that the important entry point is the SOAP method - everything thereafter is defined in the WSDL itself, any consuming client should be able to figure it out as long as the names mentioned are correctly used.
2.) This is basically the same, but even easier: XML allows to use namespaces, and these can be defined in several locations, with the result being not literally the same, but every XML parser will understand that they are the same. So you should check whether the namespace that is required as "ns1" is mentioned in the XML header of your response. Every XML document has a base namespace, which does not need to be repeated on every element that belongs to it.
This is the case with the <money> element. Your style of writing uses that base namespace, their style of writing uses a namespace shortcut ns1 also introduced in the XML header, but not declared as the base namespace. So as long as there are traces of the correct XML namespace in both responses, I'd assume they are equivalent.
And the bad news would be that you cannot change how the PHP SoapServer generates the XML. You'd need to create your own implementation of a SOAP server, which I'd say is a complete waste of resources.