i need to ask solution of my problem
usually people make url path like mylaravelsite/products/{id}
ex. mylaravelsite/products/1
i'm build a website but i need to create url path like mylaravelsite/products/{title}
example:
mylaravelsite/products/name-of-product
after doing The Alpha solution and thats works :)
You can do it. It doesn't matter if you want to use a parameter as slug/string instead of an id/numeric. Just declare the route the same way you would have declared for a numeric id parameter. For example, you may declare a route like this:
Route::get(
'/products/{title}',
array('uses' => 'ProductController#show', 'as' => 'product.show')
);
Then, the URL for this route could be http://yourdomain.com/products/name-of-product.
The reason people use an id because, most often people use an auto-incremented numeric id a primary key in their database and it's a good idea to use something like that which would be unique. You just make sure that your products are unique as well and insert them as slug in your database using:
$product->title = Str::slug(Input::get('product_title'));
Also, you may use a where condition in your route to make sure that the product name supplied to the route is an string using something like this:
Route::get(
'/products/{title}',
array('uses' => 'ProductController#show', 'as' => 'product.show')
)->where('title', '[A-Za-z-]+');
This is a macro I've used for same reason (From Slug to Title):
Str::macro('toTitle', function($str){
return ucwords(str_replace('-', ' ', $str));
});
You may use a normal helper function as well and maybe you may use preg_replace if needed.
Related
Is it possible to create a one time link in Laravel? Once you open the link it expires?
I have created a Temporary Signed Link, but I can open it multiple times. How do I counter it?
There is this package that can help you
https://github.com/linkeys-app/signed-url/
This will generate a link valid for 24hours and for just one click .
$link = \Linkeys\UrlSigner\Facade\UrlSigner::generate('https://www.example.com/invitation', ['foo' => 'bar'], '+24 hours', 1);
The first time the link is clicked, the route will work like normal. The second time, since the link only has a single click, an exception will be thrown. Of course, passing null instead of '+24 hours' to the expiry parameter will create links of an indefinite lifetime.
There maybe a package that provides a functionality like this... always worth looking on Packagelist before building something rather generic like this from scratch. But, it's also not a hard one to build from scratch.
First you'll need database persistence, so create a model and a migration called UniqueLink. In the migration you should include a string field called "slug", a string field called path, and a timestamp field called "used_at."
Next create a controller with a single __invoke(string $slug) method. In the method look up the $link = UniqueLink::where('slug', $slug)->first(); Update the models' used_at parameter like so $link->update(['used_at' => Carbon::now()]);
Then return a redirect()->to($link->path);
Add a route to your routes file like this Route::get('/unique-link/{slug}', UniqueLinkController::class);
Now you'll just need to create a method to add these links to the db which create a slug (you could use a UUID from Str::uuid() or come up with something more custom) and a path that the link should take someone. Over all a pretty straight forward functionality.
You could track when the URL is visited at least once and mark it as such for the user if you really want to, or you could reduce the expiry down to a few mins.
URL::temporarySignedRoute( 'foobar', now()->addMinutes(2), ['user' => 100] );
Is it unconventional and therefore ill-advised to use the match() method to determine which controller method to use under 1 uniformed named route? I have this code:
Route::match(['get', 'post'], '/add/lecture/{course}', [
'as' => 'addLecture',
'uses' => Request::isMethod('post') ? 'Main#addLecture':'Main#showAddLecture'
]);
Which works as expected. But I just want to know if this is a feasible solution, or if I should stop being lazy and create two separate routes (I am not using Route::resource() for a particular reason, so please don't advise me to use that for basic CRUD). I don't mean for this question to be subjective, I presume there is an objective reason as to why this isn't employed very often?
It looks like hack. It's not readable and can stop working after random minor Laravel update. In my opinion it's better to create two explicit routes.
I have 3 domains which, on my local server, take the format:
mydomainfirst.local
mydomainsecond.local
mydomainthird.local
In my routes.php file, I have the following:
Route::group(array('domain' => '{domain}.{suffix}'), function() {
Route::get('/', 'Primary#initialize');
});
The idea is to take the $domain variable in my controller and extract the first/second/third part from it, which works fine. However, now my site is online, this routing file no longer works and throws a Http-not-found exception. After a while, I have figured that the problem is that the domains have now taken the format mydomainfirst.co.uk. Because there are now 2 parts to the domain suffix, it seems I need to do this:
Route::group(array('domain' => '{domain}.{a}.{b}'), function() {
Route::get('/', 'Primary#initialize');
});
To get it to work. Which is stupid. How can I tell it to just accept any suffix? Is there an 'anything' wildcard I can use?
I have tried a few things like this answer but it doesn't work with route groups.
EDIT: It seems the Enhanced Router package would at least enable me to add a where clause to the route group, but does it solve the problem of how to set a wildcard that will match an indeterminate number of segments? I need something like:
{domain}.{anything}
That will match both:
mydomainfirst.local AND mydomainfirst.co.uk
?
Ok let me first say that the code of this package actually looks good and should work. Even if you can't get it running by installing you could take the files and use the code with your own service provider etc.
But there's also a kind of quick and dirty solution. (Actually the package does it pretty similar, but it looks a lot nicer ;))
First, here's how you can do it for one route:
Route::group(array('domain' => '{domain}.{tld}'), function(){
Route::get('/', 'Primary#initialize')->where('tld', '.*');
});
So the where condition for the route group actually gets set on the individual route.
Of course you don't want to do this for every route inside that group so you can use a simple foreach loop:
Route::group(array('domain' => '{domain}.{tld}'), function($group){
Route::get('/', 'Primary#initialize');
foreach($group->getRoutes() as $route){
$route->where('tld', '.*');
}
});
Note: The loop needs to come after all routes. Otherwise they won't registered and therefore not returned with getRoutes()
I'm trying to implement a multilanguage routing.
The problem I'm facing lies in pointing out a route translated to more than one language, to a controller of its own. Let me give a simple example:
Let's say I have a simple route as follows
Route::get('/contacts', 'PageController#contacts');
And I want the same controller to be used for another route, but this time translated in another language, german for example.
Route::get('/kontakte', 'PageController#contacts');
For a simple webiste, with no more than 5-6 pages, writing down the routes for all languages would not be such a pain, but for more complex website, with huge amount of pages and having more than 2 available languages, a solution like this would be ugly.
I found an older topic here, where the author suggested loading a route.php file depending on the currently selected language. But still, this would require more than one file to be edited for further need.
A point of suggestion or currently working solution would be really appreciated.Thanks for your help.
Just some quick thoughts:
A solution can be to do grouping routes with a prefix like '/en/' and '/de/'.
So you will have /en/contact and /de/contact.
docs for this: http://laravel.com/docs/routing#route-prefixing
This way you can just create a loop through your available languages, and register the route.
The con here that you can't have a /de/kontake or /kontakte url, because there is 1 loop with routes, and they probably will be in English.
<?php
$languages = array('en', 'de');
foreach($langauges as $language)
{
Route::group(array('prefix' => $language), function()
{
Route::get('/', 'HomeController#index');
Route::get('contact', 'HomeController#contact');
});
}
A second solution will be to store all your routes in a database (or just an array to test it in the beginning)
You will need some Page and PageLocal models for it.
Page: id, name, controller
example: 1, contact, PageController#contact
PageLocal: id, page_id, language, slug
example: 1, 1, en, contact
example: 1, 1, de, kontakte
Loop through all Pages, lazy load the PageLocal with it, and register the routes.
You can throw out the language column if you like, but lookout for duplicate slugs. Thats why a language prefix is a good idea. (And perhaps it will help with some SEO...)
<?php
$Pages::with('Locals')->all();
foreach($Pages as $Page)
{
foreach($Page->Locals as $PageLocal)
{
Route::get($PageLocal->language.'/'.$PageLocal->slug, $Page->controller);
}
}
And after that you still have to think about url's without a language prefix, get and post routes, etc, etc, but this will get something started.
I was just wondering what the best practice approach is for deciding where to create an action/view in certain situations.
If User hasMany Video
where is the best place to create the action/view to show user videos?
So within the Users account page 'My Videos' link do you
just create a users/my_videos action and view.
create videos/my_videos action and view.
or as is most likely you would already have a Controller/Action of videos/index which would have search functionality. Simply use this passing in a user id.
Any thoughts/advice greatly appreciated
Thanks
Leo
One potential option is to do the following:
Since the videos likely have much more code around them than a simple which user has which videos lookup the video list action should be in the VideosController.
In past projects I have (in CakePHP 1.3) used prefix routing to address some of this.
In config/core.php make sure you enable routing.prefixes to include a 'user' prefix.
<?php
... in routes.php ...
Routing.prefixes = array( 'user' );
?>
In the videos controller make an action with the following signature:
<?php
...
public function user_index( $userID = null ){
...
}
?>
and in the views where you link to the list of users videos the html::link call should look similar to the following:
<?php
...
echo $this->Html->link( 'User\'s Videos', array(
'controller' => 'videos',
'action' => 'index',
'prefix' => 'user',
$this->Session->read( 'Auth.User.id' )
));
?>
Of course this assumes you are using the Auth component here to track the logged in user. The Session helper code to read the authenticated user id might need tweaking.
This lets you a) Not worry too much about routing aside from enabling prefix routing and b) will quickly let you have pretty links like so -- site.com/user/videos/index/419
Couple this with some Slug love ( this is the best link for this I have seen - no slug field required on the db layer - http://42pixels.com/blog/slugs-ugly-bugs-pretty-urls )
You could even end up with urls like so quite easily: site.com/user/videos/index/eben-roux
and with just a tiny bit of editing to app/config/routes.php you could eliminate the /index/ portion and the results would be SEO friendly and user friendly in the format:
site.com/user/videos/eben-roux
http://book.cakephp.org/view/945/Routes-Configuration
As always with code you have the two extremes of:
1) Putting everything in a single controller
2) Having every action in a separate controller
The ideal approach will nearly always be somewhere between the two so how to decide what is grouped together and what is separated?
In MVC I tend to look at the Views and see what the commonalities are: as you point out Users have a ref to a collection of Videos in the Model, but would you want both sets of Data in any single View? i.e. In this example is it likely that you would be on a page that both managed user details, and displayed the list of vids? If not then I'd suggest separate controllers.
If either controller would then be extremely simple - e.g. one method, then may be worth considering merging the two.
I like to keeps things separate.
What I'd do is an index action in videos controller, passing user's id as argument and then displaying only current users video.
public function index($id = null){
$this->paginate = array( 'conditions'=> array('Video.user_id' => $id));
$this->set('videos', $this->paginate());
}
My take is that it depends on the responsibility you assign to the controllers.
I would say that something like a User or a Video controller should be concerned with only those entities.
You may want to consider something like a UserDashboard (or something similar but appropriately named) as alluded to by Dunhamzzz in the comments. This can aggegate all the functionality from an "entry" point-of-view. The same way a banner / shortcut / action menu would work.
Your UserDashboard would use whatever data layer / repository is required to get the relevant data (such as the IVideoRepository or IVideoQuery implementation).
Usually when something doesn't feel right it isn't. Try splitting it out and see how it works. You can alsways re-arrange / refactor again later.
Just a thought.
I don't think there's a 'one-rule-fits-all' solution to this question, but I would try to take an approach in which you would determine what the main object is that you're dealing with, and adding the action/view to that object's controller.
In your example I'd say that your main object is a video and that the action you're requiring is a list of video's filtered by a specific property (in this case the user's id, but this could very well be a category, a location, etc.).
One thing I would not do is let your desired URL determine in which controller you put your functionality. URLs are trivially changed with routes.