Laravel Get Slug from Database - php

I'm attempting to build a blog like application with the latest version of laravel. I'm trying to figure out how to pull a slug from the database for each article and then route it to all work correctly.
I've got it kind of working but the content wont display on the article if you use the slug to view it.
localhost/articles/1 - works fine, content shows on the page (title etc)
localhost/articles/installing-example - this works but the content errors
This happens when you try to navigate to the page using the slug from the database: Trying to get property 'title' of non-object (View: C:\xampp\htdocs\blogtest\resources\views\articles\show.blade.php)
Error with this line: <h1><?php echo e($articles->title); ?></h1>
app/http/controllers/ArticlesController:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Article;
class ArticlesController extends Controller
{
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
$articles = Article::all();
return view('articles.index')->with('articles', $articles);
}
/**
* Show the form for creating a new resource.
*
* #return \Illuminate\Http\Response
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function store(Request $request)
{
}
/**
* Display the specified resource.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function show($id)
{
$articles = Article::find($id);
return view('articles.show')->with('articles', $articles);
}
/**
* Show the form for editing the specified resource.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function edit($id)
{
//
}
/**
* Update the specified resource in storage.
*
* #param \Illuminate\Http\Request $request
* #param int $id
* #return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
{
//
}
/**
* Remove the specified resource from storage.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function destroy($id)
{
//
}
}
app/Article.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Article extends Model
{
protected $table = 'articles';
public $primaryKey = 'id';
public $timestamps = true;
}
routes/web.php
<?php
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::get('/', function () {
return view('welcome');
});
Route::resource('articles', 'ArticlesController');
resources\views\articles\show.blade.php
#extends('layouts.master')
#section('content')
<h1>{{$articles->title}}</h1>
#endsection
database
Any help and suggestions will be appreciated thanks.

Trying to get property 'title' of non-object (View: C:\xampp\htdocs\blogtest\resources\views\articles\show.blade.php)
Implies that that the $articles is not an object, if you dump it, it should be outputting null - quite rightly so.
The find function is to be used to find a row using your primary key and your primary key is not your slug column, therefore it cannot find a record.
You need to setup a route to accept a {slug} and then based on the slug you need to make the following change:
$articles = Article::find($id);
To,
$articles = Article::where('slug', $slug)->first();
and ensure that $slug is the actual slug and not the id column value.

You need to set route key in your model
// Article model
public function getRouteKeyName(){
return 'slug';
}

Try this
Without slug
Route
Route::resource('articles', 'ArticlesController');
/article/{id}
Controller
public function show($id)
{
$articles = Article::first($id);
return view('articles.show', compact('articles'));
}
Blade
#extends('layouts.master')
#section('content')
#if(!is_null($articles))
<h1>{{$articles->title}}</h1>
#endif
#endsection
With Slug
Route
Route::get('/articles/{slug}', ['as'=>'articles.by.slug', 'uses'=> 'ArticlesController#showArticles']);
or
Route::get('/articles/{slug}', 'ArticlesController#showArticles')->name('articles.by.slug');
/article/{slug}
Controller
public function showArticles($slug)
{
$articles = Article::where('slug', $slug)->first();
return view('articles.show', compact('articles'));
}
Blade
#extends('layouts.master')
#section('content')
#if(!is_null($articles)) //or #if($articles)
<h1>{{$articles->title}}</h1>
#endif
#endsection

This Is because you getting null data from database.
Reason is, you passing slug in the id field so
localhost/articles/installing-example
you passing id = installing-example, hence no id is found so no data you get.
so for this
convert your slud into original form and search not with id, search with your slug field.
let suppose from the title you make slug.
title is installing example
so when you get slug, make it into original form
then search with original like
$articles = Article::where('titile',$original)->first();

Related

Laravel scoping route params to final model query

I'm working inside a Laravel 9 project and am switching over my controller methods to scope the resources. For example, I have an Affiliate model where I'm grabbing the company ID and affiliate ID from the function, and then querying these.
I'm now trying to switch it over to defining the model in the function argument, but aren't sure how to parse company_id through to Affiliate?
This is the previous controller method:
/**
* Display the specified resource.
*
* #return \Illuminate\Http\Response
*/
public function show($company_id, $id)
{
$this->authorize('view', Affiliate::class);
$affiliate = Affiliate::where('company_id', $company_id)
->where('id', $id)
->first();
if (!$affiliate) {
return new ApiSuccessResponse(null, [
'message' => 'Affiliate not found or invalid affiliate ID.'
], 404);
}
return new ApiSuccessResponse($affiliate);
}
And here's my progress so far, how do I add the company_id check to the affiliate?
/**
* Display the specified resource.
*
* #return \Illuminate\Http\Response
*/
public function show($company_id, Affiliate $affiliate)
{
$this->authorize('view', $affiliate);
return new ApiSuccessResponse($affiliate);
}
My route looks like:
/api/company/1000/affiliates/2
And my api.php file:
Route::apiResource('company.affiliates', AffiliateController::class);

laravel how to handle profile pages?

I am playing around with Laravel 5. I am trying to build a site where a user can add some information about himself and it shows up in the frontend.
I am struggling to understand how to save the profile information only once.
Everytime the user call /profile/create a new DB entry is created. But I only need one profile entry per user!
If I don't provide a /profile/create route how can a user save his profile info to the DB? As the user can't call profile/edit because no entry exists.
This is my Controller:
namespace App\Http\Controllers;
use App\User;
use App\Profile;
use App\Http\Requests\ProfileRequest;
use App\Http\Requests;
use Illuminate\Http\Request;
use Auth;
class ProfilesController extends Controller
{
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
return view('backend.profile.index');
}
/**
* Show the form for creating a new resource.
*
* #return \Illuminate\Http\Response
*/
public function create()
{
return view('backend.profile.create');
}
/**
* Store a newly created resource in storage.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function store(ProfileRequest $request)
{
$profile = new Profile($request->all());
Auth::user()->profiles()->save($profile);
return 'saved';
}
/**
* Display the specified resource.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function show($id)
{
//
}
/**
* Show the form for editing the specified resource.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function edit($id)
{
//
}
/**
* Update the specified resource in storage.
*
* #param \Illuminate\Http\Request $request
* #param int $id
* #return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
{
//
}
/**
* Remove the specified resource from storage.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function destroy($id)
{
//
}
}
My Profile Model:
namespace App;
use Illuminate\Database\Eloquent\Model;
class Profile extends Model
{
protected $fillable = [
'name',
];
public function user() {
$this->belongsTo('App\User');
}
}
My User Model:
/**
* A User can have one Preference
* #return \Illuminate\Database\Eloquent\Relations\HasOne
*/
public function profiles() {
return $this->hasOne('App\Profile');
}
There are numerous ways, one is simply throw an exception if the user already has a profile:
public function store(ProfileRequest $request)
{
$user = Auth::user();
if($user->profiles){
abort(500);
}
$profile = new Profile($request->all());
$user()->profiles()->save($profile);
return 'saved';
}
In your template, you can show a link to either create profile or edit profile depending if the user has one yet.
You could do this check in middleware if you prefer, or make a guard.
Another nice method, as mentioned by #Maraboc in comments, is to create a blank profile on signup, so you only need an edit route.
Worth mentioning, if the user only has one profile, you should name the property 'profile' not 'profiles'
You may create empty profiles when creating new users. Another way is checkout if profile exists in your edit/update actions, like this:
public function edit()
{
//if profile will be edited at first time, then dummy profile will be used
$profile = Auth::user()->profile ?: new Profile();
return view('backend.profile.edit', compact('profile'));
}
public function update(Request $request)
{
//validate your data
//use $fillable in Profile model to whitelist acceptable attributes
if(Auth::user()->profile) {
Auth::user()->profile->update($request->all());
} else {
$profile = new Profile($request->all());
Auth::user()->profile()->save($profile);
}
//redirect to another page
}

delete method not allowed and returning MethodNotAllowedHttpException in Laravel 5

So I can create a new record on my database with form, but somehow i fail to delete my database using form And right now, I'm using laravel 5.
So this is my code looks like
routes.php
Route::get('/', [
'as' => '/',
'uses' => 'PagesController#getIndex'
]);
Route::resource('product', 'ProductController');
ProductController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use DB;
use App\Product;
use resources\views\products;
class ProductController extends Controller
{
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
$product = DB::select('select * from feedback');
return view('products.index')
->with('product',$product);
}
/**
* Show the form for creating a new resource.
*
* #return \Illuminate\Http\Response
*/
public function create()
{
return view('products.create');
}
/**
* Store a newly created resource in storage.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function store(Request $request)
{
/*$rating = new Product;
$rating->Name= $request->name;
$rating->avg=$request->price;
$rating->save();*/
$inputs= $request->all();
$product= Product::create($inputs);
//return redirect()->route('product.index');
return redirect()->action('ProductController#index');
}
/**
* Display the specified resource.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function show($id)
{
$product= Product::where('idoveralRating',$id)->first();
//return $product;
return view('products.show')
->with('product',$product);
}
/**
* Show the form for editing the specified resource.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function edit($id)
{
//
}
/**
* Update the specified resource in storage.
*
* #param \Illuminate\Http\Request $request
* #param int $id
* #return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
{
//
}
/**
* Remove the specified resource from storage.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function destroy($id)
{
//echo '<script>console.log("bitch")</script>';
//Product::destroy($id);
$product= Product::where('idoveralRating',$id)
->delete();
return redirect()->route('product.show');
}
}
show.blade.php
#extends('layouts.layout')
#section('Head')
<h1>{{$product}}</h1>
#stop
#section('Body')
<h1>{{$product->Name}}</h1>
{!!Form::open([
'method' => 'delete',
'route'=> array('product.destroy',$product->id),
])!!}
{!!Form::submit('Delete')!!}
{!!Form::close()!!}
#stop
index.blade.php
#extends('layouts.layout')
#section('Head')
ALL Product
#stop
#section('Body')
#foreach($product as $col)
<h1>{{$col->Name}}</h1>
#endforeach
#stop
layout.blade.php
<!DOCTYPE html>
<html>
<head>
#yield('Head')
</head>
<body>
#yield('Body')
</body>
</html>
Ok, So im trying to delete my database based on my database id that i typed onmy browser link(so let say i type product/1),it means i want to delete my my database with id of 1.
What I've achieve so far is that I'm able to show my database based on id i typed but somehow when i want to route the id to my destroy method in ProductController class, it shows that method=>'delete' not allowed,what am i do wrong?
Try to use 'laravel data binding'.
Add to your RouteServiceProvied.php in boot method following code:
$router->model('Product', Product::class);
And change destroy method at your controller to this:
public function destroy(Product $product)
{
$product->delete();
return back();
}
And your route at show.blade.php file must be like this:
'route'=> array('product.destroy', $product),
FORM dont have DELETE method.
You have to use it like this:
In your show.blade.php
{!!Form::open([
'method' => 'post',
'route'=> array('product.destroy',$product->id),])!!}
{{ method_field('DELETE') }}
...
I think problem in your case not in delete route. After you delete record in destroy method, you return redirect to product.show route which is required parameter id.
So try
public function destroy($id)
{
$product= Product::where('idoveralRating',$id)
->delete();
return redirect()->route('product.index');
}
Ok i want to answer my own question, the problem in my code is that I'm using a default primary key of which is equal to id(in other word, $primaryKey = 'id'), that's why when i pass my $id to destroy it seems wrong because I pass primary key that doesnt belong to the table, that's why the delete method seems not recognized because of you can't delete something that not exist.
so the problem is solved with simple step
change the primary key,protected $primaryKey='idOveralRating'(for my case, and it works!)

Laravel Undefined Offset: 1 - cause by routing

I get the error when trying to make a post call to /api/subject/search
I assume it's a simple syntax error I'm missing
I have my api routes defined below
Route::group(array('prefix' => 'api'), function()
{
Route::post('resource/search', 'ResourceController');
Route::resource('resource', 'ResourceController');
Route::post('subject/search', 'SubjectController');
Route::resource('subject', 'SubjectController');
Route::resource('user', 'UserController');
Route::controller('/session', 'SessionController');
Route::post('/login', array('as' => 'session', 'uses' => 'SessionController#Store'));
});
And my controller is mostly empty
class SubjectController extends \BaseController
{
public function search()
{
$subjects = [];
if((int)Input::get('grade_id') < 13 && (int)Input::get('grade_id') > 8)
$subjects = Subject::where('name', 'like', '%HS%')->get();
else
$subjects = Subject::where('name', 'not like', '%HS%')->get();
return Response::json([
'success' => true,
'subjects' => $subjects->toArray()
]);
}
/**
* Display a listing of the resource.
*
* #return Response
*/
public function index()
{
//
}
/**
* Show the form for creating a new resource.
*
* #return Response
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*
* #return Response
*/
public function store()
{
//
}
/**
* Display the specified resource.
*
* #param int $id
* #return Response
*/
public function show($id)
{
//
}
/**
* Show the form for editing the specified resource.
*
* #param int $id
* #return Response
*/
public function edit($id)
{
//
}
/**
* Update the specified resource in storage.
*
* #param int $id
* #return Response
*/
public function update($id)
{
//
}
/**
* Remove the specified resource from storage.
*
* #param int $id
* #return Response
*/
public function destroy($id)
{
//
}
}
You need to specify the method.
try
Route::post('subject/search', 'SubjectController#search');
See the named route example:
Laravel Docs
In your case I think search is not resolved by the controller to load the search() method. You are also sending a POST for search functionality and I guess it's better to do a GET request since POST and PUT are for storing data.
Conventions
When creating API's it's a good thing to stick to naming conventions and patterns.
http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api
Solution
Your route could be simpler like this: api.yourdomain.com/api/subject?search=term1,term2. Doing this with a GET query makes it going to the index() method. There you can check the GET params and do your search stuff and return.
Check this for the cleanest and truely RESTful way to make an API in Laravel:
How do I create a RESTful API in Laravel to use in my BackboneJS app
I got same error when accessing object at index of an empty array in view blade php file.

Laravel 4. default controller route wont accept arguments

I have a RESTful controller for my users to handle the viewing of a users profile.
The problem is this:
I want the url to look like this www.example.com/user/1
This would show the user with the id of 1. The problem is that when i define the getIndex method in the UserController it wont accept the id as an argument.
Here is my routes.php portion:
Route::controller('user', 'UserController');
Now, it is my understanding that getIndex is sort of the default route if nothing else is supplied in the url, and so this:
public function getIndex() {
}
within the UserController will accept routes,
"www.example.com/user/index"
and
"www.example.com/user"
and it does!
However, if I include an argument that it should take from the url, it no longer works:
public function getIndex($id) {
//retrieve user info for user with $id
}
This will only respond to
"www.example.com/user/index/1"
and not
"www.example.com/user/1"
How can i make the latter work? I really do not want to clutter up the url with the word "index" if it is not necessary.
If you are planning to do this, the best way is to use RESTful controllers.
Change your route to this one,
Route::resource('user', 'UserController');
Then generate a controller using php artisan command,
php artisan controller:make UserController
This will generate your controller with all RESTful functions,
<?php
class UserController extends \BaseController {
/**
* Display a listing of the resource.
*
* #return Response
*/
public function index() // url - GET /user (see all users)
{
//
}
/**
* Show the form for creating a new resource.
*
* #return Response
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*
* #return Response
*/
public function store() // url - POST /user (save new user)
{
//
}
/**
* Display the specified resource.
*
* #param int $id
* #return Response
*/
public function show($id) // url - GET /user/1 (edit the specific user)
{
//
}
/**
* Show the form for editing the specified resource.
*
* #param int $id
* #return Response
*/
public function edit($id)
{
//
}
/**
* Update the specified resource in storage.
*
* #param int $id
* #return Response
*/
public function update($id) // url - PUT /user/1 (update specific user)
{
//
}
/**
* Remove the specified resource from storage.
*
* #param int $id
* #return Response
*/
public function destroy($id) // url - DELETE /user/1 (delete specific user)
{
//
}
}
For more info, see this one Laravel RESTful controller parameters
To display www.example.com/user/1 on address bar you should use show method. In Laravel, restful controller by default create 7 routes. Show is one of them.
in your controller create a method like the following:
public function show($id)
{
// do something with id
$user = User::find($id);
dd($user);
}
Now, Browse http://example.com/user/1.

Categories