laravel BadMethodCall() error while caliing for index in api - php

the Ptag controller
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Validator;
use App\Ptag;
use App\Http\Resources\PtagResource;
use Illuminate\Support\Facades\Auth;
use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Validation\Rule;
class PtagController extends Controller
{
public function index(Request $request){
$query=Ptag::query();
return PtagResource::collection($query);
}
}
ptag resource
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class PtagResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function toArray($request)
{
return [
'id'=>$this->id,
'title'=>$this->title
// 'product'=>$this->product()
];
}
}
ptag model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Ptag extends Model
{
protected $guarded=[];
public function product(){
return $this->belongsToMany('App\Product');
}
}
error is shown as such
ErrorException: array_key_exists(): Using array_key_exists() on objects is deprecated. Use isset() or property_exists() instead in file /home/rajesh/project/handicom/vendor/laravel/framework/src/Illuminate/Http/Resources/DelegatesToResource.php on line 53

Problem:
In DelegatesToResource.php file of vendor folder, we have the following code:
public function offsetExists($offset)
{
return array_key_exists($offset, $this->resource);
}
https://github.com/laravel/framework/blob/5.7/src/Illuminate/Http/Resources/DelegatesToResource.php
array_key_exists function is deprecated on PHP 7.4.x. So, the error you met is related to PHP, not Laravel.
Solution:
Method 1: The easiest way is to downgrade your PHP version. Naturally, you still have to ensure the requirements of Laravel 5.7 (PHP >=7.1.3)
Method 2: You upgrade your project to higher version. To limit too many changes in your project, you could use version 5.8. In this version, the library no longer uses array_key_exists function.
public function offsetExists($offset)
{
return isset($this->resource[$offset]);
}
https://github.com/laravel/framework/blob/5.8/src/Illuminate/Http/Resources/DelegatesToResource.php

Related

cant fill properties at __construct in laravel test unit

I have created a simple test like this :
namespace Tests\Feature;
use Tests\TestCase;
use App\Models\User;
use Illuminate\Support\Facades\Config;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Foundation\Testing\RefreshDatabase;
class simpleTest extends TestCase
{
public $form_array = ['forms_data'];
/**
* A basic feature test example.
*
* #return void
*/
public function test_example()
{
$response = $this->get('/');
$response->assertStatus(200);
}
}
The test above runs without a problem .
I have a public property $form_array which in the example above has a static value, but when I'm trying to fill $form_array with __construct() in test, I get this error :
array_merge(): Argument #1 must be of type array, null given
at vendor/phpunit/phpunit/phpunit:98
94▕ unset($options);
95▕
96▕ require PHPUNIT_COMPOSER_INSTALL;
97▕
➜ 98▕ PHPUnit\TextUI\Command::main();
99▕
code :
namespace Tests\Feature;
use Tests\TestCase;
use App\Models\User;
use Illuminate\Support\Facades\Config;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Foundation\Testing\RefreshDatabase;
class simpleTest extends TestCase
{
public $form_array;
public function __construct(){
$this->form_array = ['forms_data'];
}
/**
* A basic feature test example.
*
* #return void
*/
public function test_example()
{
$response = $this->get('/');
$response->assertStatus(200);
}
}
My goal is fill the $form_data with values from config files in laravel which i found this way :
public function __construct(){
parent::setUp();
$this->form_array = Config::get('ravandro.form_array');
}
but even a simple $this->form_data = 'value' doesnt work , and im really confused !
btw , Im using Laravel Octane to serve my application but I dont think it has any effect to tests.
Php version : 8.1
Laravel : 9
php-unit: "phpunit/phpunit": "^9.3.3"
In tests the correct constructor method is called setUp(), which runs before every test on that class.
You can check an example of this on https://phpunit.readthedocs.io/en/9.5/fixtures.html#fixtures

Share data with all views in Laravel?

I'm trying to share a collection of notifications to all views under the auth middleware. I thought I might be able to just call Auth::check() but it seems to always return false?
<?php
namespace App\Providers;
use Illuminate\Http\Request;
use Illuminate\Support\ServiceProvider;
use Auth;
class ViewServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application services.
* #return void
*/
public function boot()
{
view()->composer('*', function ($view)
{
$view->with('userNotifications', Auth::user()->notifications);
});
}
}

Laravel 5.7: target is not instantiable while building

I know there are so many answer, but I cannot really solve this.
I did follow this answer (How to make a REST API first web application in Laravel) to create a Repository/Gateway Pattern on Laravel 5.7
I have also the "project" on github, if someone really kindly want test/clone/see : https://github.com/sineverba/domotic-panel/tree/development (development branch)
App\Interfaces\LanInterface
<?php
/**
* Interface for LAN models operation.
*/
namespace App\Interfaces;
interface LanInterface
{
public function getAll();
}
App\Providers\ServiceProvider
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Schema;
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
/**
* Solve the "Key too long" issue
*
* #see https://laravel-news.com/laravel-5-4-key-too-long-error
*/
Schema::defaultStringLength(191);
}
/**
* Register any application services.
*
* #return void
*/
public function register()
{
$this->app->register(RepositoryServiceProvider::class);
}
}
App\Providers\RepositoryServiceProvider
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class RepositoryServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->bind(
'app\Interfaces\LanInterface', // Interface
'app\Repositories\LanRepository' // Eloquent
);
}
}
App\Gateways\LanGateway
<?php
/**
* The gateway talks with Repository
*/
namespace App\Gateways;
use App\Interfaces\LanInterface;
class LanGateway
{
protected $lan_interface;
public function __construct(LanInterface $lan_interface) {
$this->lan_interface = $lan_interface;
}
public function getAll()
{
return $this->lan_interface->getAll();
}
}
App\Repositories\LanRepository
<?php
/**
* Repository for LAN object.
* PRG paradigma, instead of "User"-like class Model
*/
namespace App\Repositories;
use App\Interfaces\LanInterface;
use Illuminate\Database\Eloquent\Model;
class LanRepository extends Model implements LanInterface
{
protected $table = "lans";
public function getAll()
{
return 'bla';
}
}
I did add also App\Providers\RepositoryServiceProvider::class, in providers section of config\app.php
This is finally the controller (I know that it is not complete):
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Gateways\LanGateway;
class LanController extends Controller
{
private $lan_gateway;
/**
* Use the middleware
*
* #return void
*/
public function __construct(LanGateway $lan_gateway)
{
$this->middleware('auth');
$this->lan_gateway = $lan_gateway;
}
/**
* Display a listing of the resource.
*
* #return \Illuminate\Contracts\Support\Renderable
*/
public function index()
{
$this->lan_gateway->getAll();
return view('v110.pages.lan');
}
}
And the error that I get is
Target [App\Interfaces\LanInterface] is not instantiable while building [App\Http\Controllers\LanController, App\Gateways\LanGateway].
I did try:
php artisan config:clear
php artisan clear-compiled
I think #nakov might be right about it being case-sensitive. I don't believe PHP itself cares about upper/lowercase namespaces, but the composer autoloader and the Laravel container use key->value array keys, which do have case-sensitive keys, to bind and retrieve classes from the container.
To ensure the names always match, try using the special ::class constant instead, like this:
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\Repositories\LanRepository;
use App\Interfaces\LanInterface;
class RepositoryServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->bind(
LanInterface::class,
LanRepository::class
);
}
}
In my case i forgot to enlist the provider to confit/app.php that's why the error.
Clear the old boostrap/cache/compiled.php:
php artisan clear-compiled
Recreate boostrap/cache/compiled.php:
php artisan optimize

Laravel 5.3 auth check in constructor returning false

I'm using Laravel 5.3 and I'm trying to get the authenticated user's id in the constructor method so I can filter the user by assigned company as follows:
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;
use Illuminate\Support\Facades\View;
use App\Models\User;
use App\Models\Company;
use Illuminate\Support\Facades\Auth;
class Controller extends BaseController
{
use AuthorizesRequests, DispatchesJobs, ValidatesRequests ;
public $user;
public $company;
public function __construct()
{
$companies = Company::pluck('name', 'id');
$companies->prepend('Please select');
view()->share('companies', $companies);
$this->user = User::with('profile')->where('id', \Auth::id())->first();
if(isset($this->user->company_id)){
$this->company = Company::find($this->user->company_id);
if (!isset($this->company)) {
$this->company = new Company();
}
view()->share('company', $this->company);
view()->share('user', $this->user);
}
}
However this doesn't return the user id. I've even tried Auth::check() and it doesn't work.
If I move the Auth::check() out of the __construct() method then this works as follows:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class HomeController extends Controller
{
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
$this->middleware('auth');
}
/**
* Show the application dashboard.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
dd(\Auth::check());
return view('home');
}
}
However this fails if I put this in the construct method in the HomeController too!
Any ideas why this is failing?
docs
you can't access the session or authenticated user in your
controller's constructor because the middleware has not run yet.
As an alternative, you may define a Closure based middleware directly
in your controller's constructor. Before using this feature, make sure
that your application is running Laravel 5.3.4 or above:
class ProjectController extends Controller
{
/**
* All of the current user's projects.
*/
protected $projects;
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware(function ($request, $next) {
$this->projects = Auth::user()->projects;
return $next($request);
});
}
}
Since 5.3 Auth::check will not work in a controller's construtor, it's one of undocumented changes. So, you need to move it to middleware or do check in controller methods instead or move project to 5.2.x.
It fails because you call $this->middleware('auth'); after parent::__construct();. It means that you auth middleware is not loaded properly.

Laravel Service provider not working

I've bind my interface called CustomerRepository to EloquentCustomerRepository. This is my CustomerServiceProvider:
public function register()
{
$this->app->bind(CustomerRepository::class,EloquentCustomerRepository::class);
$this->app->bind(PackageRepository::class,EloquentPackageRepository::class);
}
When I try to instantiate it in my controller like this:
<?php
namespace App\Http\Controllers\api\v1;
use Lsupport\repositories\api\v1\customer\CustomerRepository;
use App\Http\Controllers\Controller;
use Lsupport\customer\Customer;
use App\Http\Requests;
class CustomerController extends Controller
{
protected $CustomerRepository;
public function __construct(CustomerRepository $CustomerRepository)
{
$this->CustomerRepository = $CustomerRepository;
}
It throws the following error:
Target [Lsupport\repositories\api\v1\Customer\CustomerRepository] is not instantiable while building [App\Http\Controllers\api\v1\CustomerController].
I also registered it in app.config:
App\Providers\CustomerServiceProvider::class,
What am I doing wrong?
CustomerServiceProvider
<?php
namespace App\Providers;
use Lsupport\repositories\api\v1\customer\EloquentCustomerRepository;
use Lsupport\repositories\api\v1\customer\EloquentPackageRepository;
use Lsupport\repositories\api\v1\customer\CustomerRepository;
use Lsupport\repositories\api\v1\customer\PackageRepository;
use Illuminate\Support\ServiceProvider;
class CustomerServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application services.
*
* #return void
*/
public function boot()
{
//
}
/**
* Register the application services.
*
* #return void
*/
public function register()
{
$this->app->bind(CustomerRepository::class,EloquentCustomerRepository::class);
$this->app->bind(PackageRepository::class,EloquentPackageRepository::class);
}
}
CustomerRepository
<?php
namespace Lsupport\repositories\api\v1\Customer;
interface CustomerRepository
{
public function create($request);
}
**EloquentCustomerRepository**
<?php
namespace Lsupport\repositories\api\v1\customer;
use Lsupport\repositories\api\v1\customer\CusteromRepositoryTrait;
use Lsupport\repositories\api\v1\remain\RightTrait;
use Lsupport\repositories\api\v1\remain\JsonTrait;
use Lsupport\customer\Customer;
class EloquentCustomerRepository implements CustomerRepository
{
use JsonTrait;
use RightTrait;
use CustomerRepositoryTrait;
code.....
Ok, the first thing I notice is that you probably want the same namespaces on the interface and on the class. So, the namespace of EloquentCustomerRepository should be
namespace Lsupport\repositories\api\v1\Customer;
and not
namespace Lsupport\repositories\api\v1\customer;
(with lower customer).
Now, on your CustomerServiceProvider, you should use:
public function register()
{
$this->app->bind('Lsupport\repositories\api\v1\Customer\CustomerRepository', 'Lsupport\repositories\api\v1\Customer\EloquentCustomerRepository');
}
Make sure you run composer dumpautoload -o on the command line.

Categories