Development

/branches/1.4/lib/helper/UrlHelper.php

You must first sign up to be able to contribute.

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

Revision 31396, 20.8 kB (checked in by fabien, 3 years ago)

added some @ignore phpdoc tags to avoid internal functions to be present in the API doc

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