How to use a different protocol with $AbsoluteLink in Silverstripe - php

In the Silverstripe templating syntax $AbsoluteLink returns the full URL of a page/object, including the protocol and host:
http://www.example.com/event/ics
I want to be able to call a full URL with a different protocol:
webcal://www.example.com/event/ics
What is the best way to achieve this?

Define a custom link method that replaces the current website protocol with your desired one. ie.
public function WebCalLink()
{
return str_replace(Director::protocol(), 'webcal://', Director::protocolAndHost()) . $this->Link();
}

Make a new getter function on your page:
public function WebcalLink() {
$absolute = $this->AbsoluteLink();
$webcal = str_replace(Director::protocol(), "webcal://", $absolute);
return $webcal;
}
You can call it from your template using $WebcalLink

Related

Phalcon\Mvc\View\Exception: Macro 'baseImagesURL' does not exist

I have defined a shared service baseImagesURL in my configuration Class but when I try to use it in volt it throws this error Phalcon\Mvc\View\Exception: Macro 'baseImagesURL' does not exist
/**
* This service helps in the setting base images folder URL
*/
$di->setShared('baseImagesURL', function() use ($di) {
/** #var Config $config */
$config = $di->get('config');
$url = new Url();
$url->setStaticBaseUri( $config->path("environment.baseImagesUri"));
return $url;
});
Volt:
<img src="{{baseImagesURL('Sale-big.jpg')}}" >
Volt, by default, has already a function called url that can be used to handle what you want. I assume you are already familiar with the url function, so I imagine that you are using a different name (baseImagesURL) because you would like to have both functions simultaneously available inside the templating engine, with different base URI configurations.
To find out how to do what you whant, we can inspect the generated compiled code of a Volt template that uses the regular url function. We will see that the line {{url('foo.bar')}} gets translated to: <?= $this->url->get('foo.bar') ?> inside the generated PHP code (you can find this compiled file inside the cache/ dir of your Phalcon app).
Knowing that, we can do the same thing and create a new function called baseImagesURL to be used. First, we have to create a new service, like you already did in your question:
$di->setShared('baseImagesURLService', function () {
$url = new UrlResolver();
$url->setBaseUri('/tmp2/');
$url->setStaticBaseUri('/tmp2/');
return $url;
});
The above is similar to what you had in your question, but I've simplified a little bit to have the base URIs hardcoded.
After creating this service, you can add a new Volt function:
$volt->getCompiler()->addFunction(
'baseImagesURL',
function ($url) {
return '$this->baseImagesURLService->get(' . $url . ');';
}
);
Now, we are ready to use the new function inside a Volt template:
{{ url('foo.bar') }}
<br/>
{{ baseImagesURL('foo.bar') }}
The above will result in:
/tmp/foo.bar
/tmp2/foo.bar
As you can see, I have used both url() and baseImagesURL() inside the same template, to show you that both are working as expected. For this demo, I've configured the url service almost identical to baseImagesURLService, except for the hardcoded path:
$di->setShared('url', function () {
$url = new UrlResolver();
$url->setBaseUri('/tmp/');
$url->setStaticBaseUri('/tmp/');
return $url;
});
PS - I have only named the service baseImagesURLService (redundant name) to make a clear distinction between the service name, and the Volt function name (baseImagesURL). Of course, you could use the same name for both.
PS2 - Make sure that you have configured Volt to always recompile your template. If not, the function baseImagesURL will not be available and will trigger the same error you have already encountered (macro not found). Example:
$volt->setOptions([
'compiledPath' => $config->application->cacheDir,
'compiledSeparator' => '_',
'compileAlways' => true
]);

Laravel5.4: How to mock the current page?

I want to test a helper function using Request::fullUrl in it.
function foo($arg)
{
// Get current full URL.
$url = Request::fullUrl();
// Return modified URL.
return $url;
}
The docs says:
You should not mock the Request facade. Instead, pass the input you desire into the HTTP helper methods such as get and post when running your test.
What are "the HTTP helper methods"?
They mean "TestCase::get" and "TestCase::post"?
Yes, my problem was solved by using $this->get().
But is this correct way?
class MyHelperTest extends TestCase
{
public function testFoo()
{
// Move to index page.
$this->get('/');
// Get a modified URL.
$url = foo('arg');
$this->assertEquals('Expected URL', $url);
}
}
It solved.
Using $this->get('/') is correct way.
https://laravel.com/docs/5.4/http-tests
The get method makes a GET request into the application

How do you get the HTTP host with Laravel 5

I'm trying to get the hostname from an HTTP request using Laravel 5, including the subdomain (e.g., dev.site.com). I can't find anything about this in the docs, but I would think that should be pretty simple. Anyone know how to do this?
Good news! It turns out this is actually pretty easy, although Laravel's Request documentation is a bit lacking (the method I wanted is inherited from Symfony's Request class). If you're in a controller method, you can inject the request object, which has a getHttpHost method. This provides exactly what I was looking for:
public function anyMyRoute(Request $request) {
$host = $request->getHttpHost(); // returns dev.site.com
}
From anywhere else in your code, you can still access the request object using the request helper function, so this would look like:
$host = request()->getHttpHost(); // returns dev.site.com
If you want to include the http/https part of the URL, you can just use the getSchemeAndHttpHost method instead:
$host = $request->getSchemeAndHttpHost(); // returns https://dev.site.com
There two ways, so be careful:
<?php
$host = request()->getHttpHost(); // With port if there is. Eg: mydomain.com:81
$host = request()->getHost(); // Only hostname Eg: mydomain.com
laravel 5.6 and above
request()->getSchemeAndHttpHost()
Example of use in blade :
{{ request()->getSchemeAndHttpHost() }}
You can use request()->url();
Also you can dump the complete request()->headers();
And see if that data is useful for you.

Symfony2 RedirectResponse message

I have problem with redirect to another website. When I redirected I see message: "Redirecting to...". Why? Really I can't redirect to site without problem?
I see:
Is it possible to change the default redirect message in Symfony?
My code:
/**
* #Route("/project/{url}/{link}/", name="page_show")
* #Template("base.html.twig")
*/
public function pageAction($link, $url) {
if ($link == '...') {
$redrect = new RedirectResponse('http://...');
return $redrect;
}
Maybe I'm Idiot and don't see solution...
I'm not sure you can combine #Template("base.html.twig") with a redirect response. Try to remove the #template annotation and do a render of base.html.twig in the end of your action :
/**
* #Route("/project/{url}/{link}/", name="page_show")
*/
public function pageAction($link, $url) {
if ($link == '...') {
$redrect = new RedirectResponse('http://...');
return $redrect;
}
// Maybe add the proper path "BundleName:DirectoryName:base.html.twig"
return $this->render('base.html.twig');
}
Read closely
First, create your template 301.html.twig into your Acme/FooBundle/Resources/views/Error/ with the content you want.
Here:
Is it possible to change the default redirect message in Symfony?
Redirect to Another web site:
public function pageAction(Request $request)
{
return $this->redirect('https://google.com');
}
If this is happening in the development environment, then you have set the intercept_redirects configuration option to true. Set it to false as explained in: http://symfony.com/doc/current/reference/configuration/web_profiler.html
If this is happening in the production environment, the reason is that RedirectResponse has some hardcoded HTML content to do the redirection. See these lines of code: https://github.com/symfony/symfony/blob/2.8/src/Symfony/Component/HttpFoundation/RedirectResponse.php#L86-L96
During 1 second, you see the Redirecting to ... message. Changing this message is possible, but it requires you a lot of effort. Everything is explained here: Is it possible to change the default redirect message in Symfony?
Update: in this discussion in the Symfony repository there is more information about this. The redirect should be instantaneous because it should use the information provided in the response headers. If something wrong happens, then the hardcoded HTML content is used. So you probably need to debug why the response is not getting the right redirect headers.
Answer to your question is in official Symfony book.
http://symfony.com/doc/current/book/controller.html#redirecting
public function pageAction()
{
return $this->redirect('http://stackoverflow.com');
}
Unless you are really keen to redirect using the Symfony' RedirectResponse class, you can always relay on the old good PHP:
function redirectUrl($url, $replace=true, $status=302){
header("Location : ".$url, $replace, $status);
exit();
}
// usage example
redirectUrl("http://www.google.com");
This not only works like a charm but is extremely fast in comparison with Symfony's internal function because there is only one call + die/exit.
Read more about the PHP's header function.
However, since this approach is totally decoupled from the framework, the Symfony profiler won't be able to intercept your redirect so the developer toolbar won't notice/show this redirect. It depends what you want.

Efficiently Map RESTful URI to API endpoint Architecture

When creating an api each valid URI is mapped to an action. This action can be a specific function call or can set some parameters passed to a generic function.
My question is how or what are the good method to map an uri such as /auth/create to the right action.
To illustrate my attempts:
I thought about naming a function the same as a the URI replacing the / with Z to directly call the function by its name. I could basically simply execute the $request_uri directly without testing.
// from $request_uri = '/auth/create' I make;
$request_uri ='ZauthZcreate';
function ZauthZcreate($email, $password) {
echo "i've been called as expected \n";
}
$request_uri($_GET[email],$_GET[password]);
but it wouldn't work with something like /user/123123. I am trying to avoid falling in an endless cascade of if-else.
EDIT
I've iterated on this concept and found another solution:
$request_uri = '/api/auth/login';
$request_path = ltrim($request_uri,'/');
$request = explode('/', $request_path);
// begin point for api
if($method = array_shift($request)) {
if ($method == 'api') {
$method($request);
}
}
function api($request) {
$method = __FUNCTION__.'_'.array_shift($request);
if(is_callable($method)) {
$method($request);
}
}
// In a dedicated file for the scope auth
function api_auth($request) {
$method = __FUNCTION__.'_'.array_shift($request);
if(is_callable($method)) {
$method($request);
}
}
function api_auth_login($request) {
// api end point implementation here
}
function api_auth_create($request) {
// api end point implementation here
}
I wouldn't use those Z's, that's going to be needlessly difficult to read. In your above example you could do the same thing with just AuthCreate. You could also do this with OO design by making a base class for your main verbs (like Auth) and then having them declare their member functions.
Ultimately you wont want to resolve this with if/else blocks, but rather parse each part of the URI and see if a function in the right namespace exists, and once it doesnt start using your slashes as inputs (for your example above with /user/123123).
It might also do you well to look at how other REST API's are structured, because this is something of a solved problem

Categories