using symfony 3.0 where I want to get the ID from the URL.
/**
* #Route("/pathtocontent/{id}-{name}", defaults={"id"=null,"name"=null},
requirements={"name"="[a-zA-Z0-9\-_\/]+", "id"="\d+"}, name="routingname")
* #Route("/pathtocontent/{name}-{id}", defaults={"id"=null,"name"=null},
requirements={"name"="[a-zA-Z0-9\-_\/]+", "id"="\d+"},
name="routingname_alias")
*/
public function pathAction(Request $request, $id = null) {
}
So I have 2 rules for the same action. The URL can be:
/pathtocontent/Name-part-comes-here-1234
and also could be like that:
/pathtocontent/1234-Name-part-comes-here
The problem is the first case, where the name get all the:
Name-part-comes-here-1234 value and the Id is null
How can I force the first case to parse the Id value out too, so I need to get the Id (1234) from the :
/pathtocontent/Name-part-comes-here-1234
Use just:
#Route("/pathtocontent/{name}/{id}", defaults={"id"=null,"name"=null},
Because use have many hyphens (-)
Related
I am trying to use the google indexer api with symfony and therefore i need to generate the same URLs dynamically from my job-entity (in the database) like i am already using in the frontend.
My controller function looks (reduced) like this
/**
*
* #Route({
* "de": "/profile/{name}-{id}/career/{jobname}-{jobid}",
* }, name="somename")
*/
public function detailfunction($name, $id, $jobname, $jobid)
{ // some code
}
In my frontend i get the following url rendered by twig (path function):
https://www.mydomain.xy/profile/This+is+a+company+name-23/career/Worker+Montage+%2528mwd%2529-135
So now i need to send the exact same url to google so it updates the index whenever this page is modified.
I try to generate this url in the controller of my "google indexer" function like this:
$job = $this->getDoctrine()->getRepository(Jobs::class)->findBy(....);
$url = $this->generateUrl('somename', array('name' => $job->getCompany()->getName(),
'id' => $job->getCompany()->getid(),
'jobname" => $job->getTitle(),
'jobid' => $job->getId()));
// Debug
echo $url;
Unfortunately it outputs "ERROR : Parameter "jobname" for route "somename" must match "[^/]++" ("Worker Montage (m/w/d)" given) to generate a corresponding URL"
So it doesn´t encode the data that comes from the database for the url generator. I have been wondering how symfony (or twig as well) actually encodes internally but i am completely lost and very thankful for a hint.
Although i am still not sure of how exactly symfony / twig encodes the url, i wrote a small workaround function and call it before passing it to the generateURL function.
array('name' => $this->urlcleaner($job->getCompany()->getName()),
'id' => $job->getCompany()->getId(),
private function urlcleaner($string){
$string = preg_replace('/[^A-Za-z0-9\-ığşçöüÖÇŞİıĞ()\/]/', ' ', $string);
$string = str_replace("/","",$string);
$string = str_replace("-","",$string);
$string = urlencode($string);
return $string;
}
On laravel 4 I could generate a url with query strings using the route() helper. But on 4.1 instead of:
$url = url('admin.events', array('lang' => 'en'));
// admineventsurl/?lang=en
I get:
$url = url('admin.events', array('lang' => 'en'));
// admineventsurl/en
I did some research and all laravel methods to generate url are using the parameters like that. How can I generate the url with query strings?
Laravel's route() and action() helper methods support URL query params. The url() helper method, unfortunately does not.
Simply provide an array with key => value pairs to the route parameters. For example:
route('products.index', ['manufacturer' => 'Samsung']);
// Returns 'http://localhost/products?manufacturer=Samsung'
You can also still include your route parameters (such as ID's and models) to accompany these parameters:
route('products.show', [$product->id, 'model' => 'T9X']);
// Returns 'http://localhost/products/1?model=T9X'
Basically, any elements in the array that contain string keys will be treated as query parameter (/products?param=value). Anything with an integer array key will be treated as a URL argument (/products/{arg}).
This is also supported in action methods:
action('ProductController#index', ['manufacturer' => 'Samsung']);
You can also supply query parameters inside the link_to_route() and link_to_action() methods:
link_to_route('products.index', 'Products by Samsung', ['model' => 'Samsung');
link_to_action('ProductController#index', 'Products by Samsung', ['model' => 'Samsung']);
2019 - EDIT:
If you can't use route() or action(), you can generate a URL with query params using the Arr::query() helper:
url('/products?').\Illuminate\Support\Arr::query(['manufacturer' => 'Samsung']);
// Returns 'http://localhost/products?manufacturer=Samsung'
Or:
url('/products?').http_build_query(['manufacturer' => 'Samsung'], null, '&', PHP_QUERY_RFC3986);
// Returns 'http://localhost/products?manufacturer=Samsung'
Or create a simple helper function:
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
function url_query($to, array $params = [], array $additional = []) {
return Str::finish(url($to, $additional), '?') . Arr::query($params);
}
Then call it:
url_query('products', ['manufacturer' => 'Samsung']);
// Returns 'http://localhost/products?manufacturer=Samsung'
url_query('products', ['manufacturer' => 'Samsung'], [$product->id]);
// Returns 'http://localhost/products/1?manufacturer=Samsung'
Side note.
I disagree with #Steve Bauman's idea (in his answer) that one rarely needs querystring urls, and think that Laravel should at least consider adding querystring functionality (back) in. There are plenty of cases when you want a querystring url rather than a param based "pretty url". For example, a complex search filter...
example.com/search/red/large/rabid/female/bunny
...may potentially refer to the same exact set of rodents as...
example.com/search/bunny/rabid/large/female/red
...but any way you look at it (programming, marketing analytics, SEO, user-friendliness), it's kinda terrible. Even though...
example.com/search?critter=bunny&gender=female&temperament=rabid&size=large&color=red
...is longer and "uglier", it actually is better in this not-so-rare case. Net: Friendly URLs are great for some things, querystrings are great for others.
Answer to the original question...
I needed a "querystring" version of url() -- so I copied the function, modified it, and stuck it in /app/start/global.php:
/**
* Generate a querystring url for the application.
*
* Assumes that you want a URL with a querystring rather than route params
* (which is what the default url() helper does)
*
* #param string $path
* #param mixed $qs
* #param bool $secure
* #return string
*/
function qs_url($path = null, $qs = array(), $secure = null)
{
$url = app('url')->to($path, $secure);
if (count($qs)){
foreach($qs as $key => $value){
$qs[$key] = sprintf('%s=%s',$key, urlencode($value));
}
$url = sprintf('%s?%s', $url, implode('&', $qs));
}
return $url;
}
Example:
$url = qs_url('sign-in', array('email'=>$user->email));
//http://example.loc/sign-in?email=chris%40foobar.com
Note: It appears that the url() function is pluggable, that is, you can replace it. Look in vendor/laravel/framework/src/Illuminate/Support/helpers.php: the url function is wrapped in a if ( ! function_exists('url')) conditional. But you would probably have to jump through hoops to do it (i.e. have laravel load it before its version.)
Cheers,
Chris
The following was what I needed to do:
I handle all of my routing in a service provider, where I had defined the following function:
private function registerRestfulController($prefix, $controllerClass)
{
Route::controller($prefix, $controllerClass, $controllerClass::getRouteNames());
}
getRouteNames is a static method on my BaseController that conventionally returns routes so that RESTful controllers can have automatic named routes.
The problem I was running into was that this defined the set of wildcard matchers on the route itself - in order to avoid that, I add the following to the private function above:
foreach ($controllerClass::getRoutesNames() as $name) {
$route = Route::getRoutes()->getByName($name);
$cleanUri = preg_replace('/\/\{\w*\?\}/', '', $route->getUri());
$route->setUri($cleanUri);
}
This loads all the routes you are registering at the time and immediately removes wildcards from the URI. You could easily pass a boolean or "white-list" of route names that you want to preserve wildcards for, so that it doesn't stomp all over the Laravel default without the intention. Once you run this, it automatically starts working with query string variables, which I find far preferable to path variables in this instance.
A simple way to do this, specially to use with jQuery Autocomplete, it's modify the Controller with a condition to check if has 'term' in the $request:
(Controller file)
public function list_for_autocomplete(Request $request)
{
if ($request->has('term')) {
return YourModel::select('column_name as value')
->where('column_name', 'like', '%' . $request->input('term') . '%')
->get()
}
}
I have something like the following in a Netbeans code template:
/**
* stuff
*/
$name = '${name}';
array('${var1 default="persons_${name}"}');
How can I make the default value for var1 actually expand the name variable as input in the preceding line when using the code template?
I expect to get:
/**
* stuff
*/
$name = 'joseph';
array('person_joseph');
When I fill in joseph for the name variable.
Looks like your problem is not with expanding ${name}, but with specifying a default value. Assuming you want to get person_joseph when var1 is null or undefined it should be:
array('${var1!"persons_${name}"}');
I have a Zend_Form with a dropdown field.
When the user sets a value in the url this one should be selected as default value in this dropdown.
So what i do at the moment is this:
$parlang = $this->getRequest()->getParam('lang');
if($parlang){
$this->view->filterForm->getElement('ddLanguage')->setValue($parlang);
}
if ($this->getRequest()->isPost()) {
if($this->view->filterForm->isValid($_POST)){
...
...
...
No i want to check if the value of the variable is even a valid value for the dropdown? How can i check this in coorporation with the form validation. Yes i can check the variable against a array or so but this seems to be "fighting against the framework".
So what is the Zend way to do such a thing?
Edit:
My final solution for all who are interested, is:
$parlang = $this->getRequest()->getParam('lang');
if($parlang){
$ddLanguage = $this->view->filterForm->ddLanguage;
if($ddLanguage->isValid($parlang)){
$ddLanguage->setValue($parlang);
$language = $parlang;
}
}
I ran a quick test and it looks like one method you can use is Zend_Form_Element_Select::getMultiOption() to check if the language exists in the select values.
<?php
$parlang = $this->getRequest()->getParam('lang');
if ($parlang) {
$el = $this->view->filterForm->getElement('ddLanguage');
// attempt to get the option
// Returns null if no such option exists, otherwise returns a
// string with the display value for the option
if ($el->getMultiOption($parlang) !== null) {
$el->setValue($parlang);
}
}
If your Multiselect element contains a list of country, I would just populate a default in your element value according to the one in the URL.
In order to do so, you could create a custom Zend_Form_Element as follow:
class My_Form_Element_SelectCountry extends Zend_Form_Element_Select
{
protected $_translatorDisabled = true;
public function init()
{
$locale = Zend_Registry::get('Zend_Locale');
if (!$locale) {
throw new Exception('No locale set in registry');
}
$countries = Zend_Locale::getTranslationList('territory', $locale, 2);
unset($countries['ZZ']);
// fetch lang parameter and set US if there is no param
$request = Zend_Controller_Front::getInstance()->getRequest();
$lang = $request->getParam('lang', 'US');
// sort your country list
$oldLocale = setlocale(LC_COLLATE, '0');
setlocale(LC_COLLATE, 'en_US');
asort($countries, SORT_LOCALE_STRING);
setlocale(LC_COLLATE, $oldLocale);
// check weither the lang parameter is valid or not and add it to the list
if (isset($countries[$lang])) {
$paramLang = array($lang => $countries[$lang]);
$countries = array_merge($paramLang, $countries);
}
$this->setMultiOptions($countries);
}
}
You get the idea from this custom form.
If what you're trying to do isn't a Multiselect field filled by a country list but a list of language instead, then the logic is the same, you just need to change the call to the static method Zend_Locale::getTranslationList()and grab whatever information you need.
One more thing, if you just want a single element in your Multiselect element, then go for a Zend_Form_Element_Hidden.
It's a lot of "if" but I can't understand how looks like your Multiselect element exactly from your question.
Now let's take a look on the validation side, when you're using a Multiselect element, Zend_Framework automatically adds an InArray validator, which means that you don't have anything to do to check weither the data sent are correct or not. isValid is going to do it for you.
Weither a user let the default parameter and everything will be fine, or he modifies/deletes this parameter and the default parameter (en_US in this case, see code above) is going to be set as a default value for the Multiselect field.
To answer your last question, no it's not against the framework to check a variable set by a user and compare it with an array (from getTranslationList()for example). I would say it's even the recommended way to do things.
i have url like this :
http://quickstart.local/public/category1/product2
and in url (category1/product2) numbers are id , categorys and products fetched from database attention to the id
id is unique
i need to the sensitive url like zend framework url. for example :http://stackoverflow.com/questions/621380/seo-url-structure
how i can convert that url to the new url like this
is there any way?!!
You'll need to store a unique value in your database with a field name such as 'url' or something similar. Every time you generate a new product you will have to create this unique url and store it with the product information. A common way to do this is to take the name of the product and make it url friendly:
public function generateUrl($name)
{
$alias = str_replace(' ', '-', strtolower(trim($name)));
return preg_replace('/[^A-Za-z0-9-]/', '', $alias);
}
Calling this method:
$url = $this->generateUrl("My amazing product!");
echo $url;
will output:
my-amazing-product
You'll need to check that the output from this function does not already exist in the database as you will use this value to query on instead of the id.
If you apply this logic to the categories as well, you can have easily readable and descriptive urls like the one below. You may need to tweak your routing before this works correctly though.
http://quickstart.local/public/awesome-stuff/my-amazing-product
You could use ZF's Zend_Controller_Router_Route. For example, to make similar url to those used by SO, one could define a custom route in an application.ini as follows (assuming you have controller and action called questions and show respectively):
resources.router.routes.questions.route = '/questions/:id/:title'
resources.router.routes.questions.type = "Zend_Controller_Router_Route"
resources.router.routes.questions.defaults.module = default
resources.router.routes.questions.defaults.controller = questions
resources.router.routes.questions.defaults.action = show
resources.router.routes.questions.defaults.id =
resources.router.routes.questions.defaults.title =
resources.router.routes.questions.reqs.id = "\d+"
Having such a route, in your views you could generate an url as follows:
<?php echo $this->url(array('id'=>621380,'title' => 'seo url structure'),'questions');
// results in: /myapp/public/questions/621380/seo+url+structure
//OR if you really want to have dashes in your title:
<?php echo $this->url(array('id'=>621380,'title' => preg_replace('/\s+/','-','seo url structure'),'questions');
// results in: /myapp/public/questions/621380/seo-url-structure
Note that /myapp/public/ is in the url generated because I don't have virtual hosts setup on my localhost nor any modifications of .htaccess made. Also note that you don't need to have unique :title, because your real id is in :id variable.
As a side note, if you wanted to make it slightly more user friendly, it would be better to have your url as /question/621380/see-url-structure rather than /questions/621380/see-url-structure. This is because under this url you would have only one question, not many questions. This could be simply done by changing the route to the following resources.router.routes.questions.route = '/question/:id/:title'.
EDIT:
And what to do with categories and products that you have in your question? So, I would define a custom route, but this time using Zend_Controller_Router_Route_Regex:
resources.router.routes.questions.route = '/questions/(\d+)-(d+)/(\w*)'
resources.router.routes.questions.type = "Zend_Controller_Router_Route_Regex"
resources.router.routes.questions.defaults.module = default
resources.router.routes.questions.defaults.controller = questions
resources.router.routes.questions.defaults.action = show
resources.router.routes.questions.map.1 = category
resources.router.routes.questions.map.2 = product
resources.router.routes.questions.map.3 = title
resources.router.routes.questions.reverse = "questions/%d-%d/%s"
The url for this route would be then generated:
<?php echo $this->url(array('category' => 6213,'product' => 80,'title' => preg_replace('/\s+/', '-', 'seo url structure')),'questions' ); ?>
// results in: /myapp/public/questions/6213-80/seo-url-structure
Hope this will help or at least point you in the right direction.