Development

/branches/1.2/lib/helper/UrlHelper.php

You must first sign up to be able to contribute.

root/branches/1.2/lib/helper/UrlHelper.php

Revision 27597, 18.8 kB (checked in by FabianLange, 4 years ago)

[1.2, 1.3, 1.4] fixed minor incompatibility of new link_to() behaviour with 1.0 behaviour (fixes #7933, #8231)

  • Property svn:mime-type set to text/x-php
  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Rev Date
Line 
1 <?php
2
3 /*
4  * This file is part of the symfony package.
5  * (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
6  *
7  * For the full copyright and license information, please view the LICENSE
8  * file that was distributed with this source code.
9  */
10
11 /**
12  * UrlHelper.
13  *
14  * @package    symfony
15  * @subpackage helper
16  * @author     Fabien Potencier <fabien.potencier@symfony-project.com>
17  * @version    SVN: $Id$
18  */
19
20 function link_to2($name, $routeName, $params, $options = array())
21 {
22   $params = array_merge(array('sf_route' => $routeName), is_object($params) ? array('sf_subject' => $params) : $params);
23
24   return link_to1($name, $params, $options);
25 }
26
27 function link_to1($name, $internal_uri, $options = array())
28 {
29   $html_options = _parse_attributes($options);
30
31   $html_options = _convert_options_to_javascript($html_options);
32
33   $absolute = false;
34   if (isset($html_options['absolute_url']))
35   {
36     $html_options['absolute'] = $html_options['absolute_url'];
37     unset($html_options['absolute_url']);
38   }
39   if (isset($html_options['absolute']))
40   {
41     $absolute = (boolean) $html_options['absolute'];
42     unset($html_options['absolute']);
43   }
44
45   $html_options['href'] = url_for($internal_uri, $absolute);
46
47   if (isset($html_options['query_string']))
48   {
49     $html_options['href'] .= '?'.$html_options['query_string'];
50     unset($html_options['query_string']);
51   }
52
53   if (isset($html_options['anchor']))
54   {
55     $html_options['href'] .= '#'.$html_options['anchor'];
56     unset($html_options['anchor']);
57   }
58
59   if (is_object($name))
60   {
61     if (method_exists($name, '__toString'))
62     {
63       $name = $name->__toString();
64     }
65     else
66     {
67       throw new sfException(sprintf('Object of class "%s" cannot be converted to string (Please create a __toString() method).', get_class($name)));
68     }
69   }
70
71   if (!strlen($name))
72   {
73     $name = $html_options['href'];
74   }
75
76   return content_tag('a', $name, $html_options);
77 }
78
79 function url_for2($routeName, $params = array(), $absolute = false)
80 {
81   $params = array_merge(array('sf_route' => $routeName), is_object($params) ? array('sf_subject' => $params) : $params);
82
83   return url_for1($params, $absolute);
84 }
85
86 function url_for1($internal_uri, $absolute = false)
87 {
88   return sfContext::getInstance()->getController()->genUrl($internal_uri, $absolute);
89 }
90
91 /**
92  * Returns a routed URL based on the module/action passed as argument
93  * and the routing configuration.
94  *
95  * <b>Examples:</b>
96  * <code>
97  *  echo url_for('my_module/my_action');
98  *    => /path/to/my/action
99  *  echo url_for('@my_rule');
100  *    => /path/to/my/action
101  *  echo url_for('@my_rule', true);
102  *    => http://myapp.example.com/path/to/my/action
103  * </code>
104  *
105  * @param  string $internal_uri  'module/action' or '@rule' of the action
106  * @param  bool   $absolute      return absolute path?
107  * @return string routed URL
108  */
109 function url_for()
110 {
111   // for BC with 1.1
112   $arguments = func_get_args();
113   if (is_array($arguments[0]) || '@' == substr($arguments[0], 0, 1) || false !== strpos($arguments[0], '/'))
114   {
115     return call_user_func_array('url_for1', $arguments);
116   }
117   else
118   {
119     return call_user_func_array('url_for2', $arguments);
120   }
121 }
122
123 /**
124  * Creates a <a> link tag of the given name using a routed URL
125  * based on the module/action passed as argument and the routing configuration.
126  * It's also possible to pass a string instead of a module/action pair to
127  * get a link tag that just points without consideration.
128  * If null is passed as a name, the link itself will become the name.
129  * If an object is passed as a name, the object string representation is used.
130  * One of the options serves for for creating javascript confirm alerts where
131  * if you pass 'confirm' => 'Are you sure?', the link will be guarded
132  * with a JS popup asking that question. If the user accepts, the link is processed,
133  * otherwise not.
134  *
135  * <b>Options:</b>
136  * - 'absolute' - if set to true, the helper outputs an absolute URL
137  * - 'query_string' - to append a query string (starting by ?) to the routed url
138  * - 'anchor' - to append an anchor (starting by #) to the routed url
139  * - 'confirm' - displays a javascript confirmation alert when the link is clicked
140  * - 'popup' - if set to true, the link opens a new browser window
141  * - 'post' - if set to true, the link submits a POST request instead of GET (caution: do not use inside a form)
142  * - 'method' - if set to post, delete, or put, the link submits a request with the given HTTP method instead of GET (caution: do not use inside a form)
143  *
144  * <b>Note:</b> The 'popup', 'post', and 'method' options are not compatible with each other.
145  *
146  * <b>Examples:</b>
147  * <code>
148  *  echo link_to('Delete this page', 'my_module/my_action');
149  *    => <a href="/path/to/my/action">Delete this page</a>
150  *  echo link_to('Visit Hoogle', 'http://www.hoogle.com');
151  *    => <a href="http://www.hoogle.com">Visit Hoogle</a>
152  *  echo link_to('Delete this page', 'my_module/my_action', array('id' => 'myid', 'confirm' => 'Are you sure?', 'absolute' => true));
153  *    => <a href="http://myapp.example.com/path/to/my/action" id="myid" onclick="return confirm('Are you sure?');">Delete this page</a>
154  * </code>
155  *
156  * @param  string $name          name of the link, i.e. string to appear between the <a> tags
157  * @param  string $internal_uri  'module/action' or '@rule' of the action
158  * @param  array  $options       additional HTML compliant <a> tag parameters
159  * @return string XHTML compliant <a href> tag
160  * @see    url_for
161  */
162 function link_to()
163 {
164   // for BC with 1.1
165   $arguments = func_get_args();
166   if (empty($arguments[1]) || is_array($arguments[1]) || '@' == substr($arguments[1], 0, 1) || false !== strpos($arguments[1], '/'))
167   {
168     return call_user_func_array('link_to1', $arguments);
169   }
170   else
171   {
172     if (!array_key_exists(2, $arguments))
173     {
174       $arguments[2] = array();
175     }
176     return call_user_func_array('link_to2', $arguments);
177   }
178 }
179
180 function url_for_form(sfForm $form, $routePrefix)
181 {
182   $format = '%s/%s';
183   if ('@' == $routePrefix[0])
184   {
185     $format = '%s_%s';
186     $routePrefix = substr($routePrefix, 1);
187   }
188
189   $uri = sprintf($format, $routePrefix, $form->getObject()->isNew() ? 'create' : 'update');
190
191   return url_for($uri, $form->getObject());
192 }
193
194 function form_tag_for(sfForm $form, $routePrefix, $attributes = array())
195 {
196   return $form->renderFormTag(url_for_form($form, $routePrefix), $attributes);
197 }
198
199 /**
200  * If the condition passed as first argument is true,
201  * creates a <a> link tag of the given name using a routed URL
202  * based on the module/action passed as argument and the routing configuration.
203  * If the condition is false, the given name is returned between <span> tags
204  *
205  * <b>Options:</b>
206  * - 'tag' - the HTML tag that must enclose the name if the condition is false, defaults to <span>
207  * - 'absolute' - if set to true, the helper outputs an absolute URL
208  * - 'query_string' - to append a query string (starting by ?) to the routed url
209  * - 'anchor' - to append an anchor (starting by #) to the routed url
210  * - 'confirm' - displays a javascript confirmation alert when the link is clicked
211  * - 'popup' - if set to true, the link opens a new browser window
212  * - 'post' - if set to true, the link submits a POST request instead of GET (caution: do not use inside a form)
213  *
214  * <b>Examples:</b>
215  * <code>
216  *  echo link_to_if($user->isAdministrator(), 'Delete this page', 'my_module/my_action');
217  *    => <a href="/path/to/my/action">Delete this page</a>
218  *  echo link_to_if(!$user->isAdministrator(), 'Delete this page', 'my_module/my_action');
219  *    => <span>Delete this page</span>
220  * </code>
221  *
222  * @param  bool   $condition     condition
223  * @param  string $name          name of the link, i.e. string to appear between the <a> tags
224  * @param  string $internal_uri  'module/action' or '@rule' of the action
225  * @param  array  $options       additional HTML compliant <a> tag parameters
226  * @return string XHTML compliant <a href> tag or name
227  * @see    link_to
228  */
229 function link_to_if($condition, $name = '', $internal_uri = '', $options = array())
230 {
231   $html_options = _parse_attributes($options);
232   if ($condition)
233   {
234     unset($html_options['tag']);
235     return link_to($name, $internal_uri, $html_options);
236   }
237   else
238   {
239     unset($html_options['query_string']);
240     unset($html_options['absolute_url']);
241     unset($html_options['absolute']);
242
243     $tag = _get_option($html_options, 'tag', 'span');
244
245     return content_tag($tag, $name, $html_options);
246   }
247 }
248
249 /**
250  * If the condition passed as first argument is false,
251  * creates a <a> link tag of the given name using a routed URL
252  * based on the module/action passed as argument and the routing configuration.
253  * If the condition is true, the given name is returned between <span> tags
254  *
255  * <b>Options:</b>
256  * - 'tag' - the HTML tag that must enclose the name if the condition is true, defaults to <span>
257  * - 'absolute' - if set to true, the helper outputs an absolute URL
258  * - 'query_string' - to append a query string (starting by ?) to the routed url
259  * - 'anchor' - to append an anchor (starting by #) to the routed url
260  * - 'confirm' - displays a javascript confirmation alert when the link is clicked
261  * - 'popup' - if set to true, the link opens a new browser window
262  * - 'post' - if set to true, the link submits a POST request instead of GET (caution: do not use inside a form)
263  *
264  * <b>Examples:</b>
265  * <code>
266  *  echo link_to_unless($user->isAdministrator(), 'Delete this page', 'my_module/my_action');
267  *    => <span>Delete this page</span>
268  *  echo link_to_unless(!$user->isAdministrator(), 'Delete this page', 'my_module/my_action');
269  *    => <a href="/path/to/my/action">Delete this page</a>
270  * </code>
271  *
272  * @param  bool   $condition     condition
273  * @param  string $name          name of the link, i.e. string to appear between the <a> tags
274  * @param  string $internal_uri  'module/action' or '@rule' of the action
275  * @param  array  $options       additional HTML compliant <a> tag parameters
276  * @return string XHTML compliant <a href> tag or name
277  * @see    link_to
278  */
279 function link_to_unless($condition, $name = '', $internal_uri = '', $options = array())
280 {
281   return link_to_if(!$condition, $name, $internal_uri, $options);
282 }
283
284 /**
285  * Returns a URL rooted at the web root
286  *
287  * @param   string  $path     The route to append
288  * @param   bool    $absolute If true, an absolute path is returned (optional)
289  * @return  The web URL root
290  */
291 function public_path($path, $absolute = false)
292 {
293   $request = sfContext::getInstance()->getRequest();
294   $root = $request->getRelativeUrlRoot();
295
296   if ($absolute)
297   {
298     $source = 'http';
299     if ($request->isSecure())
300     {
301       $source .= 's';
302     }
303     $source .='://'.$request->getHost().$root;
304   }
305   else
306   {
307     $source = $root;
308   }
309  
310   if (substr($path, 0, 1) != '/')
311   {
312     $path = '/'.$path;
313   }
314
315   return $source.$path;
316 }
317
318 /**
319  * Creates an <input> button tag of the given name pointing to a routed URL
320  * based on the module/action passed as argument and the routing configuration.
321  * The syntax is similar to the one of link_to.
322  *
323  * <b>Options:</b>
324  * - 'absolute' - if set to true, the helper outputs an absolute URL
325  * - 'query_string' - to append a query string (starting by ?) to the routed url
326  * - 'anchor' - to append an anchor (starting by #) to the routed url
327  * - 'confirm' - displays a javascript confirmation alert when the button is clicked
328  * - 'popup' - if set to true, the button opens a new browser window
329  * - 'post' - if set to true, the button submits a POST request instead of GET (caution: do not use inside a form)
330  *
331  * <b>Examples:</b>
332  * <code>
333  *  echo button_to('Delete this page', 'my_module/my_action');
334  *    => <input value="Delete this page" type="button" onclick="document.location.href='/path/to/my/action';" />
335  * </code>
336  *
337  * @param  string $name          name of the button
338  * @param  string $internal_uri  'module/action' or '@rule' of the action
339  * @param  array  $options       additional HTML compliant <input> tag parameters
340  * @return string XHTML compliant <input> tag
341  * @see    url_for, link_to
342  */
343 function button_to($name, $internal_uri, $options = array())
344 {
345   $html_options = _parse_attributes($options);
346   $html_options['value'] = $name;
347
348   if (isset($html_options['post']) && $html_options['post'])
349   {
350     if (isset($html_options['popup']))
351     {
352       throw new sfConfigurationException('You can\'t use "popup" and "post" together.');
353     }
354     $html_options['type'] = 'submit';
355     unset($html_options['post']);
356     $html_options = _convert_options_to_javascript($html_options);
357
358     return form_tag($internal_uri, array('method' => 'post', 'class' => 'button_to')).content_tag('div', tag('input', $html_options)).'</form>';
359   }
360
361   $url = url_for($internal_uri);
362   if (isset($html_options['query_string']))
363   {
364     $url = $url.'?'.$html_options['query_string'];
365     unset($html_options['query_string']);
366   }
367   if (isset($html_options['anchor']))
368   {
369     $url = $url.'#'.$html_options['anchor'];
370     unset($html_options['anchor']);
371   }
372   $url = "'".$url."'";
373   $html_options['type'] = 'button';
374
375   if (isset($html_options['popup']))
376   {
377     $html_options = _convert_options_to_javascript($html_options, $url);
378     unset($html_options['popup']);
379   }
380   else
381   {
382     $html_options['onclick'] = "document.location.href=".$url.";";
383     $html_options = _convert_options_to_javascript($html_options);
384   }
385
386   return tag('input', $html_options);
387 }
388
389 /**
390  * Creates a <a> link tag to the given email (with href="mailto:...").
391  * If null is passed as a name, the email itself will become the name.
392  *
393  * <b>Options:</b>
394  * - 'encode' - if set to true, the email address appears with various random encoding for each letter.
395  * The mail link still works when encoded, but the address doesn't appear in clear
396  * in the source. Use it to prevent spam (efficiency not guaranteed).
397  *
398  * <b>Examples:</b>
399  * <code>
400  *  echo mail_to('webmaster@example.com');
401  *    => <a href="mailto:webmaster@example.com">webmaster@example.com</a>
402  *  echo mail_to('webmaster@example.com', 'send us an email');
403  *    => <a href="mailto:webmaster@example.com">send us an email</a>
404  *  echo mail_to('webmaster@example.com', 'send us an email', array('encode' => true));
405  *    => <a href="
406             &#x6d;a&#x69;&#x6c;&#x74;&#111;&#58;&#x77;&#x65;b&#x6d;as&#116;&#x65;&#114;
407             &#64;&#101;&#x78;&#x61;&#x6d;&#x70;&#108;&#x65;&#46;&#99;&#x6f;&#109;
408           ">send us an email</a>
409  * </code>
410  *
411  * @param  string $email          target email
412  * @param  string $name           name of the link, i.e. string to appear between the <a> tags
413  * @param  array  $options        additional HTML compliant <a> tag parameters
414  * @param  array  $default_value
415  * @return string XHTML compliant <a href> tag
416  * @see    link_to
417  */
418 function mail_to($email, $name = '', $options = array(), $default_value = array())
419 {
420   $html_options = _parse_attributes($options);
421
422   $html_options = _convert_options_to_javascript($html_options);
423
424   $default_tmp = _parse_attributes($default_value);
425   $default = array();
426   foreach ($default_tmp as $key => $value)
427   {
428     $default[] = urlencode($key).'='.urlencode($value);
429   }
430   $options = count($default) ? '?'.implode('&', $default) : '';
431
432   if (isset($html_options['encode']) && $html_options['encode'])
433   {
434     unset($html_options['encode']);
435     $html_options['href'] = _encodeText('mailto:'.$email.$options);
436     if (!$name)
437     {
438       $name = _encodeText($email);
439     }
440   }
441   else
442   {
443     $html_options['href'] = 'mailto:'.$email.$options;
444     if (!$name)
445     {
446       $name = $email;
447     }
448   }
449
450   return content_tag('a', $name, $html_options);
451 }
452
453 function _convert_options_to_javascript($html_options, $url = 'this.href')
454 {
455   // confirm
456   $confirm = isset($html_options['confirm']) ? $html_options['confirm'] : '';
457   unset($html_options['confirm']);
458
459   // popup
460   $popup = isset($html_options['popup']) ? $html_options['popup'] : '';
461   unset($html_options['popup']);
462
463   // method
464   $method = isset($html_options['method']) ? $html_options['method'] : (isset($html_options['post']) && $html_options['post'] ? 'post' : false);
465   unset($html_options['post'], $html_options['method']);
466
467   $onclick = isset($html_options['onclick']) ? $html_options['onclick'] : '';
468
469   if ($popup && $method)
470   {
471     throw new sfConfigurationException('You can\'t use "popup", "method" and "post" in the same link.');
472   }
473   else if ($confirm && $popup)
474   {
475     $html_options['onclick'] = $onclick.'if ('._confirm_javascript_function($confirm).') { '._popup_javascript_function($popup, $url).' };return false;';
476   }
477   else if ($confirm && $method)
478   {
479     $html_options['onclick'] = $onclick.'if ('._confirm_javascript_function($confirm).') { '._method_javascript_function($method).' };return false;';
480   }
481   else if ($confirm)
482   {
483     if ($onclick)
484     {
485       $html_options['onclick'] = 'if ('._confirm_javascript_function($confirm).') { return '.$onclick.'} else return false;';
486     }
487     else
488     {
489       $html_options['onclick'] = 'return '._confirm_javascript_function($confirm).';';
490     }
491   }
492   else if ($method)
493   {
494     $html_options['onclick'] = $onclick._method_javascript_function($method).'return false;';
495   }
496   else if ($popup)
497   {
498     $html_options['onclick'] = $onclick._popup_javascript_function($popup, $url).'return false;';
499   }
500
501   return $html_options;
502 }
503
504 function _confirm_javascript_function($confirm)
505 {
506   return "confirm('".escape_javascript($confirm)."')";
507 }
508
509 function _popup_javascript_function($popup, $url = '')
510 {
511   if (is_array($popup))
512   {
513     if (isset($popup[1]))
514     {
515       return "var w=window.open(".$url.",'".$popup[0]."','".$popup[1]."');w.focus();";
516     }
517     else
518     {
519       return "var w=window.open(".$url.",'".$popup[0]."');w.focus();";
520     }
521   }
522   else
523   {
524     return "var w=window.open(".$url.");w.focus();";
525   }
526 }
527
528 function _post_javascript_function()
529 {
530   return _method_javascript_function('POST');
531 }
532
533 function _method_javascript_function($method)
534 {
535   $function = "var f = document.createElement('form'); f.style.display = 'none'; this.parentNode.appendChild(f); f.method = 'post'; f.action = this.href;";
536
537   if ('post' != strtolower($method))
538   {
539     $function .= "var m = document.createElement('input'); m.setAttribute('type', 'hidden'); ";
540     $function .= sprintf("m.setAttribute('name', 'sf_method'); m.setAttribute('value', '%s'); f.appendChild(m);", strtolower($method));
541   }
542
543   // CSRF protection
544   $form = new sfForm();
545   if ($form->isCSRFProtected())
546   {
547     $function .= "var m = document.createElement('input'); m.setAttribute('type', 'hidden'); ";
548     $function .= sprintf("m.setAttribute('name', '%s'); m.setAttribute('value', '%s'); f.appendChild(m);", $form->getCSRFFieldName(), $form->getCSRFToken());
549   }
550
551   $function .= "f.submit();";
552
553   return $function;
554 }
555
556 function _encodeText($text)
557 {
558   $encoded_text = '';
559
560   for ($i = 0; $i < strlen($text); $i++)
561   {
562     $char = $text{$i};
563     $r = rand(0, 100);
564
565     # roughly 10% raw, 45% hex, 45% dec
566     # '@' *must* be encoded. I insist.
567     if ($r > 90 && $char != '@')
568     {
569       $encoded_text .= $char;
570     }
571     else if ($r < 45)
572     {
573       $encoded_text .= '&#x'.dechex(ord($char)).';';
574     }
575     else
576     {
577       $encoded_text .= '&#'.ord($char).';';
578     }
579   }
580
581   return $encoded_text;
582 }
583
Note: See TracBrowser for help on using the browser.