Laravel: Error when trying to use Str::limit in views - laravel

I am getting this error when trying to use the Str::limit in views
ErrorException
Undefined property: Illuminate\Pagination\LengthAwarePaginator::$body (View: C:\Users\USER\Desktop\laravels\qna\resources\views\questions\index.blade.php)
here is the code
<div class="media-body">
<h3 class="mt-0">{{ $question->title }}</h3>
{{ Str::limit($questions->body, 250) }}
</div>
Here is the controller
namespace App\Http\Controllers;
use App\Models\Question;
use Illuminate\Http\Request;
// use Illuminate\Support\Str;
class QuestionsController extends Controller
{
// use Str;
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
$questions = Question::latest()->paginate(5);
return view('questions.index', compact('questions'));
}
...
}
I get his error when "Str" is un-commented
Symfony\Component\ErrorHandler\Error\FatalError
App\Http\Controllers\QuestionsController cannot use Illuminate\Support\Str - it is not a trait
What is the proper method to use Str:: in a view

Write $question->body instead of $questions->body in your view in order to use the object of question not the paginator.
Actually you don't have to use Illuminate\Support\Str in your controller at all , because you use Str class only in your view and it's one of the aliases in laravel , take a look at config/app.php.
By the way … The (use statement) above class only shorten the namespace you must use in your code like so :
use Illuminate\Support\Str;
class QuestionsController extends Controller
{
public function index()
{
Str::limit("Some String");
}
}
But if you don't put this use , your code would be :
class QuestionsController extends Controller
{
public function index()
{
\Illuminate\Support\Str::limit("Some String");
}
}
whereas when we put use statement inside class , it means we are trying to use trait in our class
https://www.php.net/manual/en/language.oop5.traits.php

I don't think you need to add it in your controller, so just add
use Illuminate\Support\Str;
to your model and that should allow you to use it anywhere. And then in your blade you can use
\Illuminate\Support\Str::limit($questions->body, 250)
This is a Laravel solution but I do recommend looking at this thread for a pure PHP answer Limit String Length

string limit with the end of three dots
\Illuminate\Support\Str::limit($clientName,16,'...');

Related

Return value must be of type Laravel 10

I am working on a Laravel 10 project and trying to create a controller that displays records. However, I have run into a problem while attempting to do so :
App\Http\Controllers\StudentController::index(): Return value must be of type Illuminate\Http\Response, Illuminate\View\View returned
I have attached below what I have tried so far:
Student Controller
namespace App\Http\Controllers;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use App\Models\Student;
class StudentController extends Controller
{
public function index(): Response
{
$students = Student::all();
return view ('students.index')->with('students', $students);
}
If I remove the Response class, the code works, but I need to implement the Laravel 10 standard. I am unsure how to solve this issue. Can you please provide a solution?
Routes
Route::resource("/student", StudentController::class);
Laravel utilized all of the type-hinting features available in PHP at the time. However, many new features have been added to PHP in the subsequent years, including additional primitive type-hints, return types, and union types.
Release notes.
If you are using view function, you need to use the Illuminate\View\View class for type-hinting.
namespace App\Http\Controllers;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\View\View;
use App\Models\Student;
class StudentController extends Controller
{
public function index(): View
{
$students = Student::all();
return view('students.index')
->with('students', $students);
}
}
<?php
namespace App\Http\Controllers;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use App\Models\CatalogueModel;
use Illuminate\Contracts\View\View;
class StudentController extends Controller
{
public function index(): View
{
$data['students'] = Student::all();
return view('students.index')->with($data);
}
}

How to mock laravel model relathipship?

I have a model that has a relationship with a View, that is complicate to popolate for make the feature test, but in the same time this is called from some component that are inside the controller called.
The following code is an example:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use App\Models\TemperatureView;
class Town extends Model
{
function temperature()
{
return $this->hasOne(TemperatureView::class);
}
}
This is an example of the controller:
<?php
namespace App\Http\Controllers;
use App\Models\Town;
class TownController extends Controller
{
public function update($id)
{
// Here is the validation and update of Town model
$UpdatedTown = Town::where('id',$id);
$UpdatedTown->update($data);
$this->someOperation($UpdatedTown);
}
private function someOperation($Town)
{
//Here there is some operation that use the temperature Relationship
/*
Example:
$Town->temperature->value;
*/
}
}
The test is like is like this:
<?php
namespace Tests\Feature;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Tests\TestCase;
use App\Models\TownModel;
use Mockery;
use Mockery\MockInterface;
class TownTest extends TestCase
{
/**
* A basic test example.
*
* #return void
*/
public function test_get_town_temperature()
{
$payload = ['someTownInformation' => 'Value'];
$response = $this->post('/Town/'.$idTown,$payload);
$response->assertStatus(200);
//This test failed
}
public function test_get_town_temperature_with_mocking()
{
$this->instance(
TownModel::class,
Mockery::mock(TownModel::class, function (MockInterface $mock) {
$MockDataTemperature = (object) array('value'=>2);
$mock->shouldReceive('temperature')->andReturn($MockDataTemperature);
})
);
$payload = ['someTownInformation' => 'Value'];
$response = $this->post('/Town/'.$idTown,$payload);
$response->assertStatus(200);
//This test also failed
}
}
The first test failed because the Controller has some check on the relationship temperature, that is empty because the view on database is empty.
The second test failed also for the same reason. I tried to follow some others questions with the official guide of Laravel Mocking. I know this is mocking object and not specially Eloquent.
Is something I'm not setting well?
If it's not possible to mock only the function, is possible to mock all the relationship of view, bypassing the DB access to that?
Edit
I undestand that the mocking work only when the class is injected from laravel, so what I wrote above it's not pratical.
I don't know if it's possible to mock only it, I saw a different option, that to create the interface of the model and change for the test, but I didn't want to make it.

Which namespace do i use for laravel view()?

My ide typhints a few different namespaces for rendering a view in my controller and i'm not sure which one i'm supposed to use:
class PostsController extends Controller
{
public function index() : View
{
return view('posts.index');
}
}
The "view" function returns multiple types:
#return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
So which one am i supposed to use? \Illuminate\Contracts\View\View or \Illuminate\Contracts\View\Factory
What is the difference?
Why is it returning two different types instead of one? I code php in a strict way because i prefer it for readable and less error prone code, in my opinion this is a bad way of doing it and as you can see is causing confusion; a method should only be allowed one return type, create multiple methods if need be.
EDIT
Thank you for your input everyone, i have come up with the following that allows me to use the facade and the contract without producing typhint errors in my ide:
<?php
namespace App\Http\Controllers;
use Illuminate\Contracts\View\View as ViewContract;
use Illuminate\Support\Facades\View as ViewFacade;
/**
* Class PostsController
* #package App\Http\Controllers
*/
class PostsController extends Controller
{
/**
* #return ViewContract
*/
public function index() : ViewContract
{
return ViewFacade::make('posts.index');
}
}
So i can call View:make() and return the contract that View:make() returns.
EDIT 2
Using the view() helper i can condense further, i am aliasing with ViewContract just for my benefit of knowing which namespace i'm using:
<?php
namespace App\Http\Controllers;
use Illuminate\Contracts\View\View as ViewContract;
/**
* Class PostsController
* #package App\Http\Controllers
*/
class PostsController extends Controller
{
/**
* #return ViewContract
*/
public function index() : ViewContract
{
return view('posts.index');
}
}
I’ll try and address each of your questions.
In your instance, type-hint Illuminate\Contracts\View\View or the concrete implementation (Illuminate\View\View).
I’ll cover this in 3.
You’re using the view global helper function. It can return different types because, well, it can. If you don’t pass a parameter to view() then it will return a view factory instance. If you do pass a parameter (like you have in your usage), then it will return an instance of the view named by the first parameter (if such a view exists). So that’s why the view() helper function is typed to return multiple different types. Because depending on how you use it, it can return a different type.
You mean: \Illuminate\View\View.
public function index(): \Illuminate\View\View
{
return view('posts.index');
}
view() is a helper of Illuminate\Support\Facades\View facade.
return view('posts.index');
Same as :
use Illuminate\Support\Facades\View;
return View::make('posts.index');
See the documentation of Creating & Rendering Views

Laravel Models/function, how to make a main "function"

So guy's, I've created a Laravel project.
I have a master. Layout which always contains the user data.
So I have a navbar with $user->name for example.
In every controller I needed to add the User model and also the where function.
$user = User::find(auth()->user()->id)
Maybe this example is bad, but I've also included the company in the master, so it shows in the Navbar.
Is there a way, that I don't need to repeat that process? So I don't need it always in the controller.
Thanks for reading.
In laravel you are extending each class from a main controller so its better to create a method in main class like this
child controller
class testController extends Controller
{
// as you can see its extending so go into Controller class
}
parent class, So here i have creatd a getName method here. If you want get the value through mode
<?php
namespace App\Http\Controllers;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
class Controller extends BaseController
{
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
private $current_user_name = 'test';
public function getName()
{
return ($this->current_user_name);
}
}
Now go back to child controller and pass this method in view
class testController extends Controller
{
public function index()
{
return view('', $data = ['name' => $this->getName()]);
}
}
Hope this cover your query. In this way you don't need to repeat your code in every controller.
You can get data in your blade template too, like user information, but if you need more complex data and you don't want to put logic in blade, you can use this method (AppServiceProvider.php):
public function boot()
{
view()->composer('your_mast_layout', function($view)
{
$data = ...
$view->with('variable_name', $data);
});
}

Laravel: a simple MVC example

I'm new to Laravel and the documentation's basic task list returns Views from the Route(web.php) but I want to use a Controller to return an image file.
So I have for my route:
Route::get('/products', 'ProductController#index');
Then my ProductController action (please ignore comments as I'm using index to simplify things):
<?php
namespace App\Http\Controllers;
use App\Product;
use Illuminate\Http\Request;
class ProductController extends Controller
{
/**
* Display a listing of the resource.
*
#return \Illuminate\Http\Response
Fetch and return all product records.
*/
public function index()
{
//
//return response()->json(Product::all(), 200);
return view('/pages/product', compact('product'));
}
And my product.blade.php (nested in views/pages/product):
<img src="/images/product/Frozen_Ophelia_800x.png">
I keep getting a ReflectionException Class App\Product does not exist.
I got this working when I just returned a view from the route. I'm getting a ReflectionException
Class App\Product does not exist so I think it's something at the top, ie. use App\Product; that is wrong.
Edit (below is my App\Product nested in app/Providers):
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Product extends Model
{
//
use SoftDeletes
protected $fillable = [
'name', 'price', 'units', 'description', 'image'
];
public function orders(){
return $this->hasMany(Order::class);
}
}
Assuming App\Product model exists, correct code should be:
public function index() {
$product = Product::all();
return view('pages.product', compact('product'));
}
Check the docs.
PS did you call a $ composer dumpautoload? ReflectionException Class error is often related to new class autoloading (eg. new classes in a packages)
view function should have any view template not any url or route. Of you have file views/pages/product.blade.php then use
view('pages.product',compact('product'));

Resources