createAbsoluteUrl generates a path-like URL, how to avoid it? - php

I create a URL like this:
$app->createAbsoluteUrl('/', array(
'param1' => 'val1',
'param2' => 'var2',
);
The generated URL is:
http://mysite.com/param1/var1/param2/var2
But I expect a url like this:
http://mysite.com/?param1=var1&param2=var2
In function manual it says:
$params array additional GET parameters (name=>value). Both the name and value will be URL-encoded.
But it doesn't seem to work like that. How I can generate the expected URL? Thanks.

You need to specify that the urlManager application component should use the "get" format for the URLs it generates; the default is to use the "path" format. The Yii guide explains how to do it inside your application configuration:
array(
......
'components'=>array(
......
'urlManager'=>array(
'urlFormat'=>'get',
),
),
);
Update: So your urlFormat is "path" and that's by design... what about alternatives?
If you don't mind extending CWebApplication and using your own derived class in its place then you have several options such as:
Define your own createUrlEx method based on the original createUrl. It could look like this:
public function createUrlEx($format,$route,$params=array(),$ampersand='&')
{
$oldFormat = $this->getUrlManager()->getUrlFormat();
$this->getUrlManager()->setUrlFormat($format);
$url = $this->getUrlManager()->createUrl($route,$params,$ampersand);
$this->getUrlManager()->setUrlFormat($oldFormat);
return $url;
}
Override registerCoreComponents so that you can have a second url manager:
protected function registerCoreComponents()
{
parent::registerCoreComponents();
$components=array(
'specialUrlManager'=>array(
'class'=>'CUrlManager',
'urlFormat'=>'get',
),
);
$this->setComponents($components);
}
You can now call Yii::app()->specialUrlManager->createUrl(...) anytime.
You can also approach the problem in other ways:
Extend CUrlManager and expose a method that allows you to select the flavor of url to create on the spot.
If you only need "get" urls in one or two places, you can always create a new CUrlManager object, configure it on the spot, call createUrl and then discard it. You could also hide this ugliness behind a free function. Essentially this (admittedly not recommended) approach is a low-tech version of the first workaround given that has the advantage that you don't need to extend CWebApplication.

You should be able to use something like Yii::app()->urlManager->createPathInfo This will generate the query string as ...&var=val&... using a custom & and = if you like. You could use this to create a query string version of a URL on demand with:
$url = $this->createAbsoluteUrl('/').'index.php?'.Yii::app()->urlManager->createPathInfo($arrayOfStuff);
Or you might even be able to do:
Yii::app()->urlManager->urlFormat = 'get';
$this->createAbsoluteUrl('My/Path');
Yii::app()->urlManager->urlFormat = 'path';
Although I haven't and don't want to test the second method.

URL route should be in the format of 'ControllerID/ActionID'. manual
Your manual link is for CController and isn't for CApplication.

Related

How To Implement "defaults()" For Multiple Params In A Route - Laravel

So I have a POST URL with two parameters and I want to assign default values for both parameters .
I know you can implement this way for a URL with a single param:
Route::post('activity-log/datatable/{tag_access?}/{page_access?}',
'SettingsController#datatable_activity_log')
->defaults('tag_access', 'activity-log');
But how do i go about it with a URL that looks like this:
Route::post('activity-log/datatable/{tag_access?}/{page_access?}',
'SettingsController#datatable_activity_log')
You can achieve it by following way:
Keep your route as you want like this:
Route::post('activity-log/datatable/{tag_access?}/{page_access?}','SettingsController#datatable_activity_log')
Now, In controller function you can take these parameters with default value like this,
public function datatable_activity_log($tag_access='activity-log', $page_access='activity-log', Request $request){
// Here write your logic
}
This may not be the best way to achieve what you want but this is one of the way.
From what I see regarding the usage of defaults you can either do one at a time:
Route::post('activity-log/datatable/{tag_access?}/{page_access?}',
'SettingsController#datatable_activity_log')
->defaults('tag_access', 'activity-log')
->defaults('page_access', 'defaultValue');
An alternative (since defaults is public) is to do:
$route = Route::post('activity-log/datatable/{tag_access?}/{page_access?}',
'SettingsController#datatable_activity_log');
$route->defaults = [ 'tag_access' => 'activity-log', 'page_access' => 'defaultValue' ];
My personal favourite is what #Sagar Gautam suggest which is to use default function parameters.

Reusable code for controller in Cakephp3

I would like to create reusable code in controller in "Cakephp way". I would like to replace always one field in few controllers before render website. For example I would like to replace string in field "body". I can do this like this in show method:
public function show($id = null) {
$site = $this->Sites->findById($id)->first();
$new_value = 'test2';
$site['body'] = str_replace('test', $new_value, $site['body']);
}
Is there any better way to do this in cakephp way for example in initalize method or beforeRender? I can't use behavior here.
EDIT:
I know about components, but how to use it to replace all $site['body] (in my code) for all controller methods (so I would like to do this automatic, like behavior for entity)?
Read about Components.
Components are packages of logic that are shared between controllers. CakePHP comes with a fantastic set of core components you can use to aid in various common tasks. You can also create your own components. If you find yourself wanting to copy and paste things between controllers, you should consider creating your own component to contain the functionality. Creating components keeps controller code clean and allows you to reuse code between different controllers.
And see Component Callbacks.
You can use component
https://book.cakephp.org/3.0/en/controllers/components.html
Don't forget to load it in appController or where your need it
After edit :
#nexequ
Maybe if you set the beforeRender in your appController
public function beforeRender()
{
debug($this->request);
}
In $this->request->data array you have your data to replace.
Exemple:
data => array(
'Reunion' => array(
'begin' => '2017-01-13 20:00:00',
'end' => '2017-01-13 20:30:00'
)
If you find the way to get the model ("Reunion" in my example.)
You can do a trick like
replace --> $this->request->data[$model]['body']
I found solution with burzum help, I can use virtual property in src/Model/Entity:
protected function _getBody() {
$new_value = 'test2';
$test = str_replace('test2', $new_value, $this->_properties['body']);
return $test;
}
It will replace for instance 'test2' with $new_value in all controller methods.

How to run no action and a single variable in the Silverstripe url_handlers?

I'm working on a project which has a special page type which checks a single 250 alphanumeric string.
Ideally I'd like the URL structure to work like this:
http://www.example.com/check/I1gdTVUsnezY9SDI8V0GS2mg7Y0IdG6MqjCZ8t1yejRdi0pKzyr7G28iF0fyxOW9Le9vg3op7NnuCE0unT7d09aN00Trn7xPYAjLRhqQ9k5aRlsThsTk0HaS966MCDb4aC23RW4Cl273e9YiWKFNm2STI75X1jnlZ684M7ejDpmWg1YfM32OpwX066bF5VTp5v0F5I42T2SWh8QhMc9GW9I2ZbuP7ykh710UHnLwQyA3BO7KitZWcCU0u9
However using allowed_actions and url_handlers the standard way I can only get it to work if I preface the alphanumeric string with "uid" - http://www.example.com/check/uid/string-goes-here
class CheckPage_Controller extends Page_Controller {
private static $allowed_actions = array(
'uid'
);
private static $url_handlers = array(
'uid/$uID' => 'uid'
);
Is it possible to have url_handlers work with just a variable and no action on a custom page?
You can define a route without a action in your _config.php:
Director::addRules(100, array(
'check/$UID' => 'CheckPage_Controller'
));
and in your CheckPage_Controller you can catch the request in the index function:
public function index() {
var_dump($this->request->allParams());die;
}
But you should be aware that the add route catches all requests to /check/whatever. So you need to define a different url for other stuff.
Assuming you have a pagetype "CheckPage" with $URLSegment "check" and some Dataobjects in a has_many relation you can use Nightjars extension for using this urlslug method, which is really elegant:
https://github.com/NightJar/silverstripe-slug/
ATM it's no ready to install module but an extension to the controller you can configure.
If you need any further help please provide some more informations about your code structure.

cakephp secure link using html helper link method

What's the best way in cakephp to extend the html->link function so that I can
tell it to output a secure(https) link?
Right now, I've added my own secure_link function to app_helpers that's basically a
copy of the link function but adding a https to the beginning.
But it seems like there should be a better way of overriding the html->link method so that I can specify a secure option.
http://groups.google.com/group/cake-php/browse_thread/thread/e801b31cd3db809a
I also started a thread on the google groups and someone suggested
doing something like
$html->link('my account', array('base' => 'https://', 'controller' => 'users'));
but I couldn't get that working.
Just to add, this is what is outputted when I have the above code.
my account
I think there's a bug in the cake/libs/router.php on line 850. There's a keyword 'bare' and I think it should be 'base' Though changing it to base doesn't seem to fix it.
From what I gather, it's telling it to exclude those keys that are passed in so that they don't get included as parameters. But I'm puzzled as to why it's a 'bare' keyword and the only reason I can come up with is that it's a type.
Simply linking to the secure version of a page doesn't fully prevent access to the non-secure version, therefore a better approach might be to implement automatic https switching for the actions needed.
<?php
class UsersController extends AppController {
var $components = array('Security');
function beforeFilter() {
$this->Security->blackHoleCallback = '_forceSecure';
$this->Security->requireSecure();
/**
* It is very common to require invocation
* of the parent beforeFilter().
* Your usage may have the invocation
* at the top instead of at the bottom.
*/
parent::beforeFilter();
}
function _forceSecure() {
$this->redirect( 'https://'.env('SERVER_NAME').env('REQUEST_URI') );
}
}
?>
Using this technique you can choose which controllers/actions need secured without having to worry about prepending https:// to every single link.
If you want to override the base you have to specify also server name not just the protocol.
If the link you want to create should be https://example.com/mysite/users/action then https://example.com/mysite/ is your base.
Try running this code:
$html->link('my account',
array('base' => 'https://example.com/mysite/', 'controller' => 'users'));
In _forceSecure(), it would be better use this line to redirect:
$this->redirect('https://'.env('SERVER_NAME').env('REQUEST_URI'));
Otherwise you will lose any parameters specified in a GET request.
The best I could come up for that is the following:
$html->link('my account', str_replace('http://', 'https://', $html->url('/users', true)));
Works perfectly.

How Can I Write Zend Framework URLs That Have Anchor Tags In The Body?

Using the standard MVC set up in Zend Framework, I want to be able to display pages that have anchors throughout. Right now I'm just adding a meaningless parameter with the '#anchor' that I want inside the .phtml file.
<?= $this->url(array(
'controller'=>'my.controller',
'action'=>'my.action',
'anchor'=>'#myanchor'
));
This sets the URL to look like /my.controller/my.action/anchor/#myanchor
Is there a better way to accomplish this? After navigation to the anchor link, the extra item parameter gets set in the user's URL which is something I would rather not happen.
one of possibilities is to override url helper, or to create a new one.
class My_View_Helper_Url extends Zend_View_Helper_Url
{
public function url(array $urlOptions = array(), $name = null, $reset = false, $encode = true)
{
if (isset($urlOptions['anchor']) && !empty($urlOptions['anchor']))
{
$anchor = $urlOptions['anchor'];
unset($urlOptions['anchor']);
}
else
{
$anchor = '';
}
return parent::url($urlOptions, $name, $reset, $encode).$anchor;
}
}
this helper override url helper, problem is, that you can't use parameter called 'anchor', because it will be changed into anchor in url.
you will call it as in your's example
<?= $this->url(array(
'controller'=>'my.controller',
'action'=>'my.action',
'anchor'=>'#myanchor'
));
I hope it helps
There are multiple ways you could go about implementing a fragment id into your URLs. Below are some options, along with some pros and cons for each.
Direct Add
You could simply add the "#$fragment_id" after your url() call. Inelegant, but simple. If you don't use page anchors much (i.e. One or two pages only), this is the way to go.
Write a custom url() helper
You could write a custom version of url() appending an optional 5th argument for the fragment id:
class My_View_Helper_Url extends Zend_View_Helper_Url
{
public function url(array $urlOptions = array(), $name = null,
$reset = false, $encode = true,
$fragment_id = null)
{
$uri = parent::url($urlOptions, $name, $reset, $encode);
if(!is_null($fragment_id)) {
$uri .= "#$fragment_id";
}
return $uri;
}
}
This way, anchor (and anchor/fragment id) information is kept strictly withing the realm of the View. This is good for general use, but can get a little unwieldy for the default route. Also, this is still a little too hard-coded for some uses.
Write a custom Route class (Extreme)
As a third option, you could write a custom version of the Zend_Controller_Router_Route class(es), specifically the assemble($data, $reset, $encode) method (the match($path) method ignores fragment ids by default).
Using this method can be quite tricky, but very useful, especially if use is only limited to specific routes (this method can be used to base the fragment id off of any variable).
Caveat
Certain considerations must be taken into account when using fragment ids. For example, query strings have to precede the fragment id in the uri, otherwise, the query string ignored by PHP. However, most ZF applications tend to avoid use of query strings, so it may not be an issue.
The url view helper accepts a 'fragment' key for the third option:
url('[route]',array([params]),array('fragment'=>'anchor'));
this will automatically end the url with #anchor.
-Thanks to Exlord
I think the Extreme method of writing a custom route class is better because other helper will have the same behavior (like the redirector action helper).

Categories