Passing Object between Models - laravel

I have a a couple of Models like so (some code removed for simplicity)
class Poll extends Model
{
public function poll()
{
return $this->hasOne('App\PollQuestion', 'pollId');
}
}
class PollQuestion extends Model
{
public function poll()
{
return $this->belongsTo('App\Poll');
}
}
I then have all my routes set up, for the PollQuestion they currently look like this
Route::model('polls.questions', 'PollQuestion');
Route::get('/admin/polls/{id}/addquestions', [
'as' => 'polls.questions.create',
'uses' => 'PollQuestionController#addQuestions'
]);
Route::post('/admin/polls/{id}/storequestions', [
'as' => 'polls.questions.store',
'uses' => 'PollQuestionController#storeQuestion'
]);
In my PollQuestionController, to see the questions view I have
public function addQuestions(Request $request)
{
$poll = Poll::where('id', '=', $request->id)->first();
return view('poll.admin.questions', compact('poll'));
}
Inside this view if I dump the poll e.g.
{{ dd($poll) }}
I can see what I expect to see. For the question form, I am doing
{!! Form::model(new App\PollQuestion, [
'route' => ['polls.questions.store', $poll]
]) !!}
So I presume that should pass my store function the Poll Object I previously dumped. However, in the store function, I do
public function storeQuestion(Request $request, Poll $poll) {
dd($poll);
}
And it shows Null. Why would this happen seeing that I am passing it the Poll Object I had previously dumped?
Thanks

You need use Route Model Binding correctly. According to Laravel Documentation
Route::model('poll-question', App\PollQuestion::class);
Route::get('/admin/polls/{poll-question}/addquestions', [
'as' => 'polls.questions.create',
'uses' => 'PollQuestionController#addQuestions'
]);
Route::post('/admin/polls/{poll-question}/storequestions', [
'as' => 'polls.questions.store',
'uses' => 'PollQuestionController#storeQuestion'
]);
Route::model define a variable in the route like a Model. This method searches the primary key passed in the route and retrieve the Model.

Related

How to show Order count of logged in user across the views?

I want to show the order count on top of the navbar across views. I know about Shared Views but the problem I am having that Auth::check() is always false here even I am logged in. How can I make the following happen in boot method of AppServiceProvider? Is there some other way to do it or I have to rely on Session vars?
if(Auth::check()) {
$orders = Order::where( [ 'user_id' => Auth::user()->id, 'status' => 0 ] )->get();
dd($orders);
}
In your App\Providers\AppServiceProvider, in the boot method:
public function boot()
{
view()->composer('*', function ($view) {
if(Auth::check()) {
$order_count = Order::where( [ 'user_id' => Auth::user()->id, 'status' => 0 ] )->count();
$view->with('order_count', $order_count);
}
});
}

Laravel Resource API CURL | store/delete don't work [duplicate]

This question already has an answer here:
Laravel HttpException - No error message
(1 answer)
Closed 4 years ago.
I'm trying to create my own resource API in Laravel, I test the api via Postman program, index() and show() functions (with GET requests) work well, but unfortunatelly store()/delete() functions dont't work (POST, PUT, DELETE requests).
I've tried a lot of tutorials, and result the same, I can't use POST, PUT, DELETE requests (or can't test them properly via Postman)
More details:
I have DB with tables (with relations): Categories, Startups, Contacts, Countries
1.1 One Category can have many Startups
1.2 One Contact can have many Startups
1.3 One Country can have many Contacts
I defined Api Routes in web.php (not in api.php), (I'm trying to make api for Startups Table):
// get list startups
Route::get('api/startups', 'Admin\StartupController#index');
// get single startup
Route::get('api/startup/{id}', 'Admin\StartupController#show');
// create new startup
Route::post('api/startup', 'Admin\StartupController#store');
// update startup
Route::put('api/startup', 'Admin\StartupController#store');
// delete startup
Route::delete('api/startup/{id}', 'Admin\StartupController#destroy');
Controller code (StartupController), I'm showing only one method - store()
(I think it's enough for identifying the issue)
public function store(Request $request) {
$startup = Startup::create([
'category_id' => $request->category()->id,
'contact_id' => $request->contact()->id,
'name' => $request->name,
'description' => $request->description,
'url' => $request->url,
'logo' => $request->logo,
]);
return new StartupResource($startup);
Also second option of the function (which doesn't work too):
public function store(Request $request) {
$startup = $request->isMethod('put') ? Startup::findOrFail($request->startup_id) : new Startup;
$startup->id = $request->input('startup_id');
$startup->name = $request->input('startup_name');
$startup->description = $request->input('startup_description');
$startup->url = $request->input('startup_url');
$startup->logo = $request->input('startup_logo');
if ($startup->save()) {
return new StartupResource($startup);
}
}
My migration
Schema::create('startups', function (Blueprint $table) {
$table->increments('id');
$table->integer('category_id');
$table->integer('contact_id')->nullable();
$table->string('name');
$table->mediumText('description');
$table->string('url');
$table->boolean('public')->default(false);
$table->string('logo');
$table->timestamps();
});
toArray() function in resources
public function toArray($request) {
return [
'id' => $this->id,
'name' => $this->name,
'description' => $this->description,
'url' => $this->url,
'public' => $this->public,
'logo' => $this->logo,
'created_at' => (string) $this->created_at,
'updated_at' => (string) $this->updated_at,
'category' => $this->category,
'contact' => $this->contact
];
}
(Additional) may be it will help - how I test it in Postman
row (submitting json)
form-data
I think it's a CSRF protection.
https://laravel.com/docs/5.7/csrf
api.php routes don't have this protection(only web.php).
So, you should decide - use api routes, or just use VerifyCsrfToken::$except property to avoid this protection for some routes.

nested resources in laravel not worked

I want to have nested resources like that:
Route::group(['prefix' => 'manage', 'middleware' => ['role:boss']], function ()
{
Route::resource('/articles', 'ArticleController');
Route::group(['prefix' => '/articles', 'as' => 'articles.'], function () {
Route::resource('/types', 'ArticleTypeController');
});
});
But nested route for "article/type" doesn't work, I check my ArticleTypeController outside the "article" route and work.
I really confused, Everybody can help me?
and here is my controller:
class ArticleTypeController extends Controller
{
public function index()
{
$types = ArticleType::all();
return view('manage.articles.types.index')->withtypes($types);
}
}
Route::group(['prefix' => 'manage', 'middleware' => ['role:boss']], function ()
{
Route::get('articles/types', 'ArticleTypeController#articleTypeMethod');
Route::resource('articles', 'ArticleController');
Route::resource('articles.types', 'ArticleTypeController');
});
for nested resources use articles.types. plural naming is good.
now that manage/articles and manage/articles/1/types will work.
If you want to put a custom route, put it above the resource route if the controller has been used as a resource. see the articles/types [GET] route which maps to ArticleTypeController's articleTypeMethod. now this way http://localhost.com/manage/articles/types should work
here is the 5.1 documentation and it has been removed from documentation of 5.5. but have a look at what Taylor said about it here
it's not recommended on REST to use index function for articles/types, a nested resources index method is used like articles/{id}/types.
for articles/types you need to create a new method.
but if you still want to do it like that. just make it like this
Route::group(['prefix' => 'manage', 'middleware' => ['role:boss']], function ()
{
Route::get('articles/types', 'ArticleTypeController#index');
Route::resource('articles', 'ArticleController');
Route::resource('articles.types', 'ArticleTypeController', ['except' => ['index']]);
});

Get a parameter from a route?

I have the following route:
Route::get('news', [
'as' => 'news',
'uses' => 'ArticleController#getIndex',
]);
There are also other routes that use the same resource controller, e.g:
Route::get('travel', [
'as' => 'travel',
'uses' => 'ArticleController#getIndex',
]);
In the article controller, how can I get the category of the articles. e.g. travel or news?
I can't turn it into a route param e.g.
Route::get('{travel}', [
'as' => 'travel',
'uses' => 'ArticleController#getIndex',
]);
As there are other sections such as contact, faqs, etc that do not use the article controller.
I know I could put it all on one route:
Route::get('/article/{category}', [
'as' => 'travel',
'uses' => 'ArticleController#getIndex',
]);
But I want pretty URLS like:
mydomain.com/category-slug/article-slug
Ideally if I could use a resource controller:
Route::resource('news', ArticleController');
With some sort of array:
Route::resource(['news', 'travel'], ArticleController');
So my questions:
How can I get the name of the resource. e.g. news, travel in my controller?
Is there an easy way to specify varying routes to the same resource?
For Example Keep your routes like this as your static routes will be limited and need to be unique so they will not get conflict between routes
demo routes :
Route::get('contact', [
'as' => 'contact',
'uses' => 'contactController#getIndex',
]);
Route::get('{travel}', [
'as' => 'travel',
'uses' => 'ArticleController#getIndex',
]);
In order to achieve a route like that:
mydomain.com/category-slug/article-slug
Use the following:
Route::get('/{category}/{article}', 'ArticleController#getArticle');
Then in your controller, you will have 2 parameters in your getArticle method.
public function getArticle($category, $article)
{
//Your code here
}
In order to have pretty urls you need to make a few steps:
1)
First of all you need to add a column to your articles table called for example 'slug'.
2) Then you need to specify your route key in your article model. Like this:
Article model
public function getRouteKeyName()
{
return 'slug';
}
3) When you add an article you should create the slug by your own in order to be unique. so in your controller that you create the article add this code.
$slug = str_slug($article['title'], '-');
$slugs_count = DB::table('articles')->where('name',$article['title'])- >count();
if($slugs_count>1){
$slug = $slug.'-'.($slugs_count-1);
}
$article->slug = $slug;
$article->update();
4) Now we have to set the route
Route::get('/article/{slug}', [
'as' => 'travel',
'uses' => 'ArticleController#getIndex'
])->where(['slug','[\w\d\-\_]+']);
5) Finally in order to get the article you need
$article = Article::where('slug','=',$slug)->first();
If you want to use categories etc you could pass more parameters in your route and manipulate it in your controller. like this
Route::get('/article/{category}/{slug}', [
'as' => 'travel',
'uses' => 'ArticleController#getIndex'
])->where(['slug','[\w\d\-\_]+','category','[\w\d\-\_]+']);
The where clause is to restrict the parameter with some regular expressions(its optional).
I forgot to mention that the routekeyname in your model works in laravel 5.2.

Laravel 5, can't insert via request method doesn't exist

That's what i'm trying to do without any success:
In welcome.blade I have a foreach with some boards and subboards(random generated by user) where you can click on subboard and go something like this /subboardOne. I got this on my routes.php
Route::get('/{subboaName}', 'ThreadController#index');
Route::post('/{subboaName}', 'ThreadController#store');
then you can post a thread on this subboard via form but since i really don't know how laravel knows where he is, the form is something like this:
<form class="form col-md-12 center-block" role="form" method="POST" action="/{{$subboardcoll->id}}">
this $subboardcoll->id comes from the controller, where it sends via the index function the collection:
public function index($subboard)
{
$subboardcoll = Subboard::where('subboaName', $subboard)->first();
$threads = Thread::where('subboaId', $subboardcoll->id)
->orderBy('created_at', 'desc')
->get();
return view('threads.thread', compact('threads', 'subboardcoll'));
}
then i'm trying to send my form and store the thread autoinserting the subboardId but laravel doesn't recognize subboards method:
public function store(Request $request)
{
$this->validate($request, [
'comentario' => 'required|max:2000',
//'g-recaptcha-response' => 'required|recaptcha',
//'imagen' => 'required',
]);
$request->subboards()->threads()->create([
'thrName' => $request->nombre,
'thrComment' => $request->comentario,
'thrImg' => $request->imagen,
'thrSubject' => $request->tema,
]);
return redirect()->back();
}
And gives me this erorr:
BadMethodCallException in Macroable.php line 81: Method subboards does not exist.
Can you guys helpme to know why? also is there better form to do what i'm trying? im newbie on laravel, thanks
EDIT:
Thread.php
public function subboard()
{
return $this->belongsTo(Subboard::class, 'subboaId');
}
Subboard.php
public function thread()
{
return $this->hasMany(Thread::class);
}
The method subboards do not exist in a request object. Consider doing this
public function store($id, Request $request)
{
$this->validate($request, [
'comentario' => 'required|max:2000',
//'g-recaptcha-response' => 'required|recaptcha',
//'imagen' => 'required',
]);
Subboard::find($id)->threads()->create([
'thrName' => $request->nombre,
'thrComment' => $request->comentario,
'thrImg' => $request->imagen,
'thrSubject' => $request->tema,
]);
//Alternative query statement
Subboard::where('id', $id)->first()->threads()->create([.....
return redirect()->back();
}

Resources