Pulling Data from the Database and passing to View - Laravel Basics - php

Pretty new to Laravel and looking to get a project off the ground, so I'll cut to the chase. I'm coming over from codeigniter and was hoping for more documentation/examples.
I'm having an issue where my view is coming up blank white. I turned debug to true but I am not seeing any errors being reported.
Controller:
public function clientHome()
{
$data = Contact::orderAsc()->get();
$data->toarray();
return View::make('clientes.clientes', $data);
}
Model:
class Contact extends Eloquent {
protected $table = 'contact';
public function scopeOrderAsc()
{
return $query->orderBy('sort_order', 'asc');
}
}
I have rows in my db table called 'contact'. I have to be missing something small. I went through the code step by step and it is getting caught at the return $query->orderBy('sort_order', 'asc'); line. Thoughts? Also I'm new here so looking forward to contributing in other areas!

You should pass $query into your scope method:
class Contact extends Eloquent {
protected $table = 'contact';
public function scopeOrderAsc($query)
{ // ^^^^^^
$query->orderBy('sort_order', 'asc');
}
}

Related

Laravel Eloquent delete() not working

Documentation says:
$user = User::find($user_id);
$user->delete();
This doesnt work, however ProductColor::find($color_id) working. $color->delete() Doest return anything, DELETE FROM query doesn't even execute (as seen in debug bar).
But I can delete record with:
ProductColor::destroy($color_id);
Must be something I overlooked earlier, I'm new to Laravel.
I'm using store also, and it working as expected
public function store(Request $request)
{
$color = new ProductColor();
$color->name = $request->color_name;
$color->order = $request->color_order;
$saved = $color->save();
if ($saved) {
return back()->with('message:success', 'Ok');
} else {
return back()->with('message:error', 'Error');
}
}
To sum up
This WORKS
public function destroy($color_id)
{
$deleted = ProductColor::destroy($color_id);
if ($deleted) {
return back()->with('message:success', 'Deleted');
} else {
return back()->with('message:error', 'Error');
}
}
This NOT
public function destroy($color_id)
{
$color = ProductColor::find($color_id);
$color->delete();
}
My Model
<?php
namespace Modules\Shop\Entities;
use Illuminate\Database\Eloquent\Model;
use Modules\Languages\Entities\Language;
class ProductColor extends Model
{
protected $fillable = [];
protected $table = 'product_colors';
}
Sorry, I've figured out the problem. My mistake to post this question.
What I tried to do:
$color = new ProductColor();
$color->find($color_id);
$color->delete();
Should be:
$color = ProductColor::find( $color_id );
$color->delete();
My problem was that I was scared about the IDE complaining about using non-static method 'find'
Please check your model class if you have added soft delete option in that case your record will not be deleted from the database.
Your code is fine - the docs show exactly what you are doing.
If there is no error, and the color is not deleted as expected, then $color_id is not being passed as expected. Try using findOrFail, or add some other check that you found the expected model.
DB::table('pykcodes')
->where('user_id', $user_id)
->delete();
This works directly without using the model.
Just make sure you call use DB; from the top.
My problem was, the name of the property inside the uri on the routes file was incorrect:
Route::delete('/foo/{fo3o}', [DollyController::class, 'delete']);
-----^
I don't know why the controller method was working:
public function delete(Foo $foo)
{
$foo->delete();
return ['message' => 'success'];
}
After correcting it, the problem was solve and the delete method started working again:
Route::delete('/foo/{foo}', [DollyController::class, 'delete']);
------^
You have to add SoftDeletes in User Model:
...
use Illuminate\Database\Eloquent\SoftDeletes;
class User extends Authenticatable
{
use SoftDeletes;
protected $dates = ['deleted_at'];
...

Laravel retrieving eloquent nested eager loading

In my application i have 4 models that relate to each other.
Forms->categories->fields->triggers
What I am trying to do is get the Triggers that refer to the current Form.
Upon researching i found nested eager loading, which would require my code to look like this
Form::with('categories.fields.triggers')->get();
Looking through the response of this i can clearly see the relations all the way down to my desired triggers.
Now the part I'm struggling with is only getting the triggers, without looping through each model.
The code i know works:
$form = Form::findOrFail($id);
$categories = $form->categories;
foreach ($categories as $category) {
$fields = $category->fields;
foreach ($fields as $field) {
$triggers[] = $field->triggers;
}
}
I know this works, but can it be simplified? Is it possible to write:
$form = Form::with('categories.fields.triggers')->get()
$triggers = $form->categories->fields->triggers;
To get the triggers related? Doing this as of right now results in:
Undefined property: Illuminate\Database\Eloquent\Collection::$categories
Since it is trying to run the $form->categories on a collection.
How would i go about doing this? Do i need to use the HasManyThrough relation on my models?
My models
class Form extends Model
{
public function categories()
{
return $this->hasMany('App\Category');
}
}
class Category extends Model
{
public function form()
{
return $this->belongsTo('App\Form');
}
public function fields()
{
return $this->hasMany('App\Field');
}
}
class Field extends Model
{
public function category()
{
return $this->belongsTo('App\Category');
}
public function triggers()
{
return $this->belongsToMany('App\Trigger');
}
}
class Trigger extends Model
{
public function fields()
{
return $this->belongsToMany('App\Field');
}
}
The triggers run through a pivot table, but should be reachable with the same method?
I created a HasManyThrough relationship with unlimited levels and support for BelongsToMany:
Repository on GitHub
After the installation, you can use it like this:
class Form extends Model {
use \Staudenmeir\EloquentHasManyDeep\HasRelationships;
public function triggers() {
return $this->hasManyDeep(Trigger::class, [Category::class, Field::class, 'field_trigger']);
}
}
Form::with('triggers')->get();
Form::findOrFail($id)->triggers;

Laravel get data from pivot table

I have a pivot table of users_operators.
I want to grab the operator_id of the user.
This is how i do this now, but its seems like verbose way.
if (Auth::user()->type === 'operator') {
$user = Auth::user();
// There is a better way to do this?
$operator_id = $user->operator[0]['pivot']['operator_id'];
Session::put('operatorId', $operator_id);
}
class Operator extends \Eloquent
{
public function users() {
return $this->belongsToMany('User');
}
}
class User extends \Eloquent
{
public function operator() {
return $this->belongsToMany('Operator');
}
}
I'm, battling insomnia and not functioning at 100%, but you should be able to get away with $user->operator->id based on what I'm interpreting your models to be (it looks like you had a typo when you copied them into the question).
If that doesn't work, you might want to check out the "Dynamic Properties" section in the Eloquent docs for more info, if you haven't already.

In my view, why does Laravel overwrite variables I declare in my controller with those from my model?

Am I understanding the MVC design pattern incorrectly? Why does Laravel seemingly overwrite variables I declare in my controller and pass to my view with those from my model? Say I'm passing the variable $journey from my controller to my view like so:
class JourneyController extends BaseController {
public function journey($id) {
$journey = Journey::find($id);
// I overwrite one of the attributes from the database here.
$journey->name = "Overwritten by the Controller";
return View::make('journey', array(
'journey' => $journey,
'bodyClass' => 'article'
));
}
}
But, I'm using an accessor to also modify the $journey->name attribute in my Journey model:
class Journey extends Eloquent {
protected $table = 'journeys';
protected $primaryKey = 'id';
public $timestamps = false;
public function getNameAttribute($value) {
return 'Overwritten by the Model';
}
}
So when my view is created, and I display $journey->name like so:
{{ $journey->name }}
I'm left with:
"Overwritten by the Model";
Why does this occur? Doesn't the controller handle a request, fetch information from my model, manipulate it, and then pass it to the view where it can be outputted? If this is the case, why, and also how, is the model seemingly 'jumping' in between to overwrite my controller-written variable with its own?
I know this is old, but I just found a solution on Laravel 4.2 today.
class Journey extends Eloquent {
protected $table = 'journeys';
protected $primaryKey = 'id';
public $timestamps = false;
public function getNameAttribute($value = null) {
if($value)
return $value;
return 'Overwritten by the Model';
}
}
You should update your getNameAttribute function as above to return the set value (if there is one) instead of always returning the string. Previously, calling this value would always run the function and ignore the set value, but now the function takes checks first for the value that you have set.
Hopefully 2 years isn't too late to still help some people!
Have a look at using Presenters, Take Jeffery Way's Presenter Package. Install it normally and then you can add the $presenter variable to your model.
For instance:
use Laracasts\Presenter\PresentableTrait;
class Journey extends Eloquent {
use PresentableTrait;
protected $presenter = "JourneyPresenter";
}
Then you can create your JourneyPresenter Class:
class JourneyPresenter {
public function journeyName()
{
return "Some Presentation Name";
}
}
In your view you can call this, like so:
<h1>Hello, {{ $journey->present()->journeyName }}</h1>
It really helps keep this sort of "presentation" logic out of your view and controller. You should try hard to keep your controller solely for its intended purpose, handling routes and basic guards and keep your views logic-less.
As for your problem, you may just be experiencing the natural order of Laravel operations.

testing php laravel controller shouldReceive arguments

I have a laravel model which uses ardent/eloquent. I am trying to set up tests for the controller in particular, storing a new model that uses the ardent model.
The method works in the app but I'm having trouble with my tests
I'm having problems working out how to mock the calls this method makes.
My controllers set up and the method in question is this one:
use golfmanager\service\creator\TicketCreatorInterface;
//controller manages the ticket books
class BooksController extends BaseController {
/**
* Book Repository
*
* #var Book
*/
protected $book;
protected $ticket;
public function __construct(Book $book, TicketCreatorInterface $ticket)
{
$this->book = $book;
$this->ticket = $ticket;
}
public function store()
{
$input = Input::all();
$result = $this->book->save();
if ($result) {
//if book created then create tickets
$this->ticket->createTicket($input, $this->book);
return Redirect::route('books.index');
}
return Redirect::route('books.create')
->withInput()
->withArdentErrors()
->with('message', 'There were validation errors.');
}
And the methods used by the interface (TicketCreator):
public function createTicket($input, $book) {
//dd($input);
$counter = $input['start_number'];
while($counter <= $input['end_number']) {
$ticketDetails = array(
'ticketnumber'=>$counter,
'status'=>'unused',
'active'=>1
);
$this->ticket->create($ticketDetails)->save();
$this->ticket->book()->associate($book)->save();
$counter = $counter+1;
}
return $counter;
}
My test is as follows:
use Mockery as m;
use Way\Tests\Factory;
class BooksTest extends TestCase {
public function __construct()
{
$this->mock = m::mock('Ardent', 'Book');
$this->collection = m::mock('Illuminate\Database\Eloquent\Collection')->shouldDeferMissing();
}
public function setUp()
{
parent::setUp();
$this->attributes = Factory::book(['id' => 1, 'assigned_date'=> '20/11/2013']);
$this->app->instance('Book', $this->mock);
}
public function testStore()
{
Input::replace($input = ['start_number'=>1000, 'end_number'=>1010, 'assigned_date'=>'20/11/2013']);
$this->mock->shouldReceive('save')->once()->andReturn(true);
$this->ticket->shouldReceive('createTicket')->once()->with($input, $this->mock)->andReturn(true);
//with($input);
//$this->validate(true);
$this->call('POST', 'books');
$this->assertRedirectedToRoute('books.index');
}
Currently I get an error:
No matching handler found for Book::save()
Is this being thrown because the book model doesnt contain a save method? If it is how do I mock the model correctly. I don't want it to touch the database (although it could if it has to).
Is it the multiple saves in the createTicket method?
Still learning how to set up tests correctly - slowly getting there but not enough knowledge yet.
If I change the name of the method in shouldReceive to say 'store' it still comes up with the save() error message.
Update:
I have isolated part of the problem to the createTicket call. I've changed my testStore test and updated as above.
My error with this current test is: Undefined index: start_number.
If I remove the call to createTicket in the controller method I don't get an error. I tried using Input::replace to replace the input from a form but appears not getting through to my function
How can I simulate a form input in the mocked objects?
Thanks

Categories