SEO friendly URLs with category/subcategories/article slug? [Laravel] - laravel

First of all, I have Article model and articles table in the database. Each article can be shown using Laravel's standard URI structure: www.example.com/articles/5 (where 5 the article id.). Each article has a slug field (slug column in the articles table) , so with Route Model Binding it is easy to change this and have a slug instead of id in the URI:
In RouteServiceProvider.php I just added:
public function boot(Router $router)
{
parent::boot($router);
\Route::bind('articles', function($slug) {
return \App\Article::where('slug', $slug)->firstOrFail();
});
}
... and now I can open articles with: www.example.com/articles/this-is-some-slug .
On the other hand, each article belongs to one category. For example, let's say that there are the following categories:
Politics
Sport
Football
Tennis
ATP
WTA
Culture
I created these categories by using Baum (an implementation of the Nested Set pattern for Laravel 5's Eloquent ORM). So there is a Category model and categories table in the database:
$table->increments('id');
$table->string('name');
$table->integer('parent_id')->nullable();
$table->integer('lft')->nullable();
$table->integer('rgt')->nullable();
$table->integer('depth')->nullable();
$table->timestamps();
Of course, in articles table there is a column category_id because of One-to-Many relationship (one Article belongs to one Category, one Category can have many Articles).
All articles belonging to some category can be displayed via the following URL: www.example.com/articles/category/1 (where 1 is the id). If we add slug column to the categories table & set Route Model Binding :
\Route::bind('category', function($slug) {
return \App\Category::where('slug', $slug)->firstOrFail();
});
then we will use a slug instead of id: www.example.com/articles/category/politics (this will display all the articles belonging to the category politics).
But I would like to have URIs with the following structure:
www.example.com/sport/tennis/wta/article_slug (/category/subcategory/subcategory/article_slug)
www.example.com/politics/article_slug (/category/article_slug )
and so on...
The problem is that I have no idea how to do this with Laravel. Is it even possible? How would you solve this problem?
Thanks in advance and sorry for my bad English.
SEO friendly URLs with category/subcategories/article slug?

To produce a url that's example.com/category/subcategory/article is pretty simple, but you're obviously looking to add the complexity of multiple subcategories. For that we'll need to look at route parameter regex constraints.
Using regex in your route parameter constraints you can get the subcategories as a string eg. subcategory1/subcategory2 and then pass it via another custom binding or directly to your controller.
Here's an example of the route you need with the route parameter constraint added:
// Route to closure
Route::get('/{category}/{subcategories}/{article}', function($category, $subcategories, $article)
{
return $subcategories;
})->where('subcategories', '(.*)');
// Route to controller method
Route::get('/{category}/{subcategories}/{article}', 'ArticlesController#show')->where('subcategories', '(.*)');
And an example of a custom binding for your subcategories parameter that returns the subcategories as an array:
$router->bind('subcategories', function ($value) {
return explode('/', $value);
});
Caveat: The only problem you will run into using the route parameter bindings in the way you've described, is that the article loaded here is only dependant on the slug being correct. It will still load if the categories in the url are unrelated, which you'll need to take care of in your controller logic.

Related

Laravel Relationships, don't know how to display

I have two models. Business and City.
Business:
id
title
-some columns--
city_id
City:
id
name
How to display the city name, when I get business data to view
I was able to display cities using the laravel voyager lessons
When I want to get it like $business->city_id
If you are using models, you can create a relationship by adding hasOne or hasMany to your model codes.
When you call it from your controller, you can call the relationship you wrote in your model with the 'with' query.
Model
public function city()
{
return $this->hasOne(City::class,'id','cityid');
}
Controller
$business=Business::with('city')->first();
$cityname=$business->city->name;
If you don't use model, you can connect with 'join'
You have 2 options. First, you can get city details on the controller:
Business::with('city')...;
On the blade
$business->city->name;
Other option fetching it on the blade directly. I don't recommend this because of extra database queries.
$business->city()->name;

Eloquent with diferent relationships for same table

i need some hints and what is the best way and pratice with laravel to solve this problem!
I have a main table called colors with the fields category_id and type and i have in my models 2 relationships for the category_id, the bluecategory and redcategory.
In some cases i use the id from bluecategory and in other exemples i use the redcategory id.
Now in one page i want to shows all the results from colors, but i can't do this $data->bluecategory or $data->redcategory because i dont'no what record is using what relationship.
My ideia was using a function to send parameters category_id and type and inside the function discover what is the correspondente relashion and return the correct result.
But how i can handle this?
Sorry its a bit confuse!
You could add a scope to your modal and than chain it to your existing query.
Example
public function scopeName($query, $catID, $type)
{
return $query->where('category_id, $catID)
->where('type', $type);
}

Laravel Nova Override BelongsTo Language field based on already translated resources

Imagine the following 3 models with fields:
Listing:
id
ListingTranslation:
id
listing_id
language_id
title
Language:
name
iso
Inside my ListingTranslation create/update form how can I filter the language selector to NOT SHOW the languages that have been already translated?
(i.e. If I have 2 languages ES (id 1) and EN (id 2) and if I have a listing with id 1 and this listing already has a listing_translation with id 1, listing_id 1 and language_id 1, the language selector should only show EN as an option).
Language selector:
BelongsTo::make('Language')
Laravel Nova documentation provides the following method to filter the queries that are used to populate relationship model selection menus:
public static function relatableQuery(NovaRequest $request, $query)
{
return $query->where('user_id', $request->user()->id);
}
However, I do not know how to access something like listing_id from this method.
Instead of creating Nova resource for pivot table ListingTranslation, you can make use of BelongsToMany relation.
Under Listing Nova resource fields add BelongsToMany::make('Languages'). Assuming you have already defined the relationship in Listing model.
At this point when you attach a language which is already attached, you will see an error message The language is already attached
But if you still want to stop listing the already attached languages you can add relatableQuery given below under Listing nova resource.
public static function relatableLanguages(NovaRequest $request, $query)
{
$listing = $request->findResourceOrFail();
return $query->whereNotIn('id', $listing->languages->pluck('id'));
}
Hope this will help you.

Laravel nova overriding/setting custom value for the Fields or Has Through relationship

I am developing a Web application using Laravel. For the admin panel, I am using Laravel Nova. What I am trying to do now is that I need to use data from the table which has relationship through another table. To be, clear, see my database structure below.
items
=====
id
name
price
sub_category_id
sub_categories
==============
id
name
parent_category_id
parent_categories
=================
id
name
What I am trying to achieve inside the Nova is that I want to display the parent category name of the item on the item index/list page. The first thing is that I do not want to create custom attribute something like this in the model
protected $appends = [
'parent_category_name'
];
function getParentCategoryNameAttribute()
{
//code here
}
Therefore, there are two solutions I can think of. The first solution is using the HasThrough relationship. But I cannot find it in Nova. So, I cannot use it. The second solution is that overriding the field value on render. Something like this.
Text::make("fieldname")->fillUsing(function($request, $model, $attribute, $requestAttribute) {
//$model->sub_category->parent_category - then I can return a value
return "Parent category name";
})->onlyOnIndex()
But the above code is not working. So, what would be the best approach to handle the has-through relationship in Nova?
Assuming you have defined the relationship sub_category & parent_category properly.
Define the relationship in Item model as below
public function parent_category()
{
return $this->sub_category->parent_category();
}
Then use it in Item resource as below.
BelongsTo::make('Parent Category')
->hideWhenCreating()
->hideWhenUpdating(),

Laravel Datatables display data from related tables

I'm using Datatables for displaying data. It works good, but when I want to display data from related tables (models), they do not appear.
Model Keyword.php
public function website() {
return $this->belongsToMany('App\Website');
}
Model Website.php
public function keywords() {
return $this->hasMany('App\Keyword');
}
'websites' database table: id, siteName, siteUrl
'keywords' database table: id, website_id, kwName
Url that should display data: projects/'.$website->id.'/edit (example: projects/2/edit - (edit is a blade))
So, at this Url I want to show a datatable that display all kwName for certain website_id(in this example /2/).
Please, help me what should I use and how to do this.
Your Eloquent relationships are the wrong way around.
keywords has a reference to website via website_id, this is a belongsTo relationship.
website is referenced by many keywords, so this is a hasMany relationship.
Laravel 5.4 Eloquent Relationships

Resources