Laravel Cashier Call to Undefined Method onGracePeriod() - laravel

So I recently upgraded from Laravel 5.1 -> 5.4 and Cashier from 5.0 -> 7.0. In my blade I am using this check to see if a user is in their grace period
<?php if(Auth::check() && Auth::user()->onGracePeriod()): ?>
However now this code throws an exception
Call to undefined method Illuminate\Database\Query\Builder::onGracePeriod()
As per the documentation my user model has the import
use Laravel\Cashier\Billable;
and the use statement inside of the class itself
class User extends Model implements AuthenticatableContract,
CanResetPasswordContract
{
use Authenticatable, CanResetPassword, Billable;
/**
* The database table used by the model.
*
* #var string
...
Is there anything else that could cause this error? Searching through the code it looks like the function is within the Subscription.php within cashier but I cannot seem to find a fix. I also have the included dates that is often referenced in the documentation
protected $dates = ['trial_ends_at', 'subscription_ends_at'];
But I had that and my DB using that before back on 5.1 so I doubt that is related. Any ideas? The only thing I can think of is that when moving from 5.1 -> 5.4 I had to remove the "BillableContract" since it appears that it is no longer being used, is there something I have to replace that with? Thanks!

I believe you have to reference their subscription piece directly - not directly off the user (I think it's being used wrong is what I'm saying);
Per the documentation you check for onGracePeriod like this:
if ($user->subscription('main')->onGracePeriod()) {
//
}

Related

Correct way to pass model instance from middleware to controller?

If I have a middleware that fetches a related model from an authenticated User (ie: Info model), checking stuff and throwing error if an inconsistency is found in User's Info, otherwise I want to use that same Info in my controller without making the same query again.
I know I can $request->request->add(['info' => $info]) and then call it as request('info') in my controller, but it doesn't seems to be the best way since it's giving me a huge headache when combined with Livewire resulting in weird and unexpected behavior.
So, what is the correct way to do this?
You can refer to this documentation. Laravel 8 Authentication
So what it says basically is that once you are authenticated, you can always use Auth facade anywhere from your code and get the Info model associated to it (Assuming you have setup the eloquent relationship between your User & Info models)
e.g.
use Illuminate\Support\Facades\Auth;
// MyController.php
public function index(Request $request)
{
// Let's say Info model has address column
$address = Auth::user()->info->address;
}
Your User model should have relationship with Info Model like this, well then again assuming Info class has one to one relationship with your User class
Source: Laravel 8 Eloquent
class User extends Authenticatable
{
public function info()
{
return $this->hasOne(\App\Models\Info::class);
}
}

count(): Parameter must be an array or an object that implements Countable

I'm facing strange case. I face an error in production env not while in dev it's working fine.
Development:
Laravel 5.4.28
PHP 7.0.13
MYSQL 5.7.17
Production:
Laravel 5.4.28
PHP 7.2.1
MYSQL 5.7.20
In implementation code. I used:
namespace App;
use Illuminate\Support\Facades\Storage;
use Laravel\Scout\Searchable;
use Illuminate\Database\Eloquent\Model;
class Artwork extends Model
{
use Searchable;
In development it works fine. But in production it gives me this error:
count(): Parameter must be an array or an object that implements Countable
in Builder.php (line 936)
as you can see in this pic:
Any idea what is the reason behind this? and how to fix?
Put this code at the beginning of your route file, it will work fine
if(version_compare(PHP_VERSION, '7.2.0', '>=')) {
error_reporting(E_ALL ^ E_NOTICE ^ E_WARNING);
}
This is a documented change in PHP 7.2. You need to either update Laravel to 5.6 or downgrade PHP to version 7.1.
Replace
$originalWhereCount = count($query->wheres);
by
$originalWhereCount = count((array)$query->wheres);
in
\vendor\laravel\framework\src\Illuminate\Database\Eloquent\Builder.php
I was facing similar issue in Laravel 5.6. Where I was getting error for object based array. I knew that data in that particular variable will always remain object so i used to convert the object to array. Here is code sample:
$objectData = (array)$objectData;
echo "Total Elements in array are: ".count($objectData);
My server was on PHP 7.1 when I updated to PHP 7.2 I got the same issue.
After searching I found why this occurs. (This occurs because of a PHP update.).
so in my case, the error is solved by typecasting.
I just update all code where I used to count
Before
//this is before
count($adminDetails)
After updated
//after update all i typecast all the code where i used count
count((array)$adminDetails)
Goodluck
This error occurs because you are using a higher PHP version and your Laravel application is on an older PHP version.
✅ Simple solution:
Open: app/Providers/AppServiceProvider.php
And in: public function register() { ... } function add following code:
if(version_compare(PHP_VERSION, '7.2.0', '>=')) {
error_reporting(E_ALL ^ E_NOTICE ^ E_WARNING);
}
In php 7.2+ count does not work on relation objects, you need to use:
$model->relation()->exists()
Not this (less than php 7.2):
count($model->relation)
i ran into the same problem (PHP 7.2 + Laravel 5.3) but i don't see any "good" answers here. For me, the problem occurs when i tried to start a Builder from a scope method on the model: SomeModel::forUser() calls scopeForUser(). Trying to build a new Query, it trips on a count($this->wheres) that gets no initial value (null). Because the magic static call to the scope starts the builder, no other conditions have been placed in the object so the property is still null at that point.
i thought it's worth sharing my solution first, then perspective on why i consider it better than Ben's answer. It's not personal, i just disagree.
Solution
i took a cue from this answer about overriding some of the core Illuminate\Database classes...
Extend Illuminate\Database\Eloquent\Model
Mine is App\Overrides\Database\Eloquent\Model
Extend Illuminate\Database\Eloquent\Builder
Mine is App\Overrides\Database\Eloquent\Builder
Extend Illuminate\Database\Query\Builder
Can you guess? App\Overrides\Database\Query\Builder
Tell Laravel to use YOUR Eloquent\Model:
config/app.php 'aliases' array, replace the 'Eloquent' value
with your Eloquent\Model FQN
My Model:
namespace App\Overrides\Database\Eloquent;
/*
* Notes:
* * Using replacement Query\Builder with ALIAS
* * Use of Builder in this class is MY Eloquent\Builder
*/
use App\Overrides\Database\Query\Builder as QueryBuilder;
use Illuminate\Database\Eloquent\Model as EloquentModel;
class Model extends EloquentModel
{
public function newEloquentBuilder($query)
{
return new Builder($query);
}
protected function newBaseQueryBuilder()
{
$conn = $this->getConnection();
$grammar = $conn->getQueryGrammar();
return new QueryBuilder($conn, $grammar, $conn->getPostProcessor());
}
}
My Eloquent\Builder:
namespace App\Overrides\Database\Eloquent;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
class Builder extends EloquentBuilder
{
public function __construct($query)
{
parent::__construct($query);
/*
* FIX #1: Set properties treated AS arrays
* to empty arrays on construct.
*/
$this->wheres = [];
// Any other properties treated as arrays should also be initialized.
}
}
My Query\Builder:
namespace App\Overrides\Database\Query;
use Illuminate\Database\Query\Builder as QueryBuilder;
class Builder extends QueryBuilder
{
public function __construct()
{
parent::__construct(...func_get_args());
/*
* FIX #2: Set properties treated AS arrays
* to empty arrays on construct.
*/
$this->wheres = [];
// Any other properties treated as arrays should also be initialized.
}
}
This safely preserves the framework's functionality, since the only actual change you're making is initializing properties that should have been in the first place. Everything else will pass instanceof checks used for dynamic loading and dependency injection.
Opinion
While i agree with #ben-harold about every comment he made saying "NEVER edit vendor code," i disagree with the "solution." It's an oversimplification to a much more complex problem.
Upgrade Laravel: to ensure support for PHP 7.2, jumping up several minor versions - if not major releases - is impractical for a lot of teams. As a long term objective, yes of course. As something i can do to get rid of the bug for my deadline? Nope. Upgrading takes a lot of planning and frequently a lot of rewrites as structures, names, and functionality change. It's something to prioritize, but not a need-it-now answer.
Downgrade PHP: same problem. Downgrading into PHP 5.x means A) PHP is EOL, which may be a deal breaker for a lot of customers who have security policies, and B) any usage of PHP 7.x language features have to be scrapped. As with upgrading the framework this is very likely to cause a lot of headaches. It's also an even less useful solution, since walking backward in the language just puts you farther behind and will require more long-term effort.
place the below line ob code before the class name in your controllers
if (version_compare(PHP_VERSION, '7.2.0', '>=')) {
// Ignores notices and reports all other kinds... and warnings
error_reporting(E_ALL ^ E_NOTICE ^ E_WARNING);
// error_reporting(E_ALL ^ E_WARNING); // Maybe this is enough
}
I was facing the same issue with an external created table (Not using migration or command),
After creating the model, I just assigned a table name, but the problem was in my model protected $fillable where I assign string instead of array and error occurred.
There is 2 possible solution for that.
Assign an array to your protected $fillable = ['filed1', 'filed2'];
Remove protected $fillable completely (Not Recommended)
class Abc extends Model
{
protected $table = 'cities';
protected $fillable = ['field1','field2', ...];
}
Model looking for countable parameter:
class ClassName extend Model {
protected $fillable=['column_name']; // column in DB of Model is in array
}
Before
count($collection['colors'])
Error:Expected type 'Countable|array'. Found 'string'
After
count((array)$collection['colors'])
It works for me!
'vendor\laravel\framework\src\Illuminate\Database\Eloquent\Builder.php' to:
$originalWhereCount = is_array($query->wheres) ? count($query->wheres) : 0;
I;m using laravel 6.x
for this case you can use this way:
$id = \DB::table('xxxx')->where('id', $id)->count();
I Solve this in Laravel 5.6
// in controller
public function index()
{
$todos = Todo::all();
return view('todos.index')->with(['todos' => $todos]);
}
// in view page
#if(count($todos) > 0)
#foreach($todos as $todo)
<div class="well">
<h3>{{$todo->text}}</h3>
<span class="label label-danger">{{$todo->due}}</span>
</div>
#endforeach
#endif

What causes an illegal offset in the makeAlias function of laravel 5.5 within this package implementation?

I am making packages for the first time in Laravel (v5.5). Unfortunately, the Route Model Bindings are giving me trouble. At first, I was receiving the id number raw without the model, and I realized that I had to force the package routes through the 'web' middleware grouping.
When I add the 'web' middleware grouping, I can see that laravel tries to load the model, but I receive an "Illegal offset type in isset or empty" in the first line of the Container->makeAlias method.
I have tried using custom binding loaders defined in the ServiceProvider using Route::model( $class, $closure ), but the error occurs before the loader is called. I've even tried moving this declaration from the ServiceProvider->boot method to the ServiceProvider->register method, just in case it is an order of operations issue.
I have tried adding a binding to the app by calling $this->app->bind inside the ServiceProvider, but this has had no effect.
I'm going to post the relevant code below, and I appreciate any insites that you may have! Thank you in advance!
Some Facts
The route
We are loading the url: http://127.0.0.1/profiles/1/edit for this test.
Operation without bindings
When no bindings or middleware are applied, and the url above is called, I can safely load the model from within the function manually and return the view. This indicates that the package is correctly loaded into the main application container.
The model can load in Tinker
To verify the model and database connection, we use tinker and run the command \Clemence\Profiles\Profile::find(1) to which the following is returned:
=> Clemence\Profiles\Profile {#777
id: 1,
name: "Clemence, Jared",
address: """
554 Christmas Tree Lane\n
Bakersfield, CA 93306
""",
email: "jaredclemence#gmail.com",
phone: "610-360-9558",
created_at: null,
updated_at: null,
deleted_at: null,
}
The stack trace
The Route->performBinding method is called with the following arguments:
[
Closure, /* Presumably the loader */
"1", /* the index that is passed into the route URL */
Route /* A self reference back to the containing object */
]
after this, the Closure is called with
[
"1",
Route
]
from the Closure, Application->make is called, the argument named $class is passed another Closure with the following definition:
Closure {#97 ▼
class: "Clemence\Profiles\ProfilesServiceProvider"
this: ProfilesServiceProvider {#87 …}
parameters: {▶}
}
lastly we end up in Container->makeAlias where the Exception is thrown, makeAlias is called with this Closure:
Closure {#97 ▼
class: "Clemence\Profiles\ProfilesServiceProvider"
this: ProfilesServiceProvider {#87 …}
parameters: {▶}
}
The Files
packages/clemence/profiles/src/routes.php
Route::group(['middleware' => ['web']], function() {
Route::get('/profiles/{profile}/edit', '\Clemence\Profiles\ProfileController#edit');
Route::get('/profiles/create', '\Clemence\Profiles\ProfileController#create');
Route::get('/profiles', '\Clemence\Profiles\ProfileController#showAll');
Route::get('/profiles/{profile}', '\Clemence\Profiles\ProfileController#show');
Route::post('/profiles/create', '\Clemence\Profiles\ProfileController#createWithFormData')->name('profile.create');
Route::put('/profiles/{profile}', '\Clemence\Profiles\ProfileController#updateWithFormData')->name('profile.update');
Route::delete('/profoiles/{profile}', '\Clemence\Profiles\ProfileController#destroy')->name('profile.delete');
Route::get('/roles', '\Clemence\Profiles\RoleController#showAll');
Route::get('/roles/{role_id}', '\Clemence\Profiles\RoleController#show');
Route::get('/roles/create', '\Clemence\Profiles\RoleController#create');
});
packages/clemence/profiles/src/ProfilesServiceProvider.php
namespace Clemence\Profiles;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Route;
class ProfilesServiceProvider extends ServiceProvider {
/**
* Bootstrap the application services.
*
* #return void
*/
public function boot() {
$this->loadRoutesFrom( __DIR__ . '/routes.php' );
if ($this->app->runningInConsole()) {
$this->commands([
\Clemence\Profiles\Commands\InstallProfiles::class,
\Clemence\Profiles\Commands\PrepareEnvironmentForProfiles::class
]);
}
}
/**
* Register the application services.
*
* #return void
*/
public function register() {
$this->app->make(\Clemence\Profiles\ProfileController::class);
$this->app->make(\Clemence\Profiles\RoleController::class);
$this->loadMigrationsFrom(__DIR__ . '/migrations');
$this->loadViewsFrom(__DIR__ . '/views', 'profiles');
}
}
packages/clemence/profile/src/ProfileController.php
namespace Clemence\Profiles;
use App\Http\Controllers\Controller;
use Clemence\Profiles\Profile;
use Illuminate\Http\Request;
use Clemence\Profiles\FormTemplateData;
use Illuminate\Support\Facades\URL;
class ProfileController extends Controller
{
/* ... collapsed ... */
/**
* Show the form for editing the specified resource.
*
* #param \App\Profile $profile
* #return \Illuminate\Http\Response
*/
public function edit(Profile $profile )
{
return dd( $profile );
$formData = new FormTemplateData();
$profile = Profile::find( $profile_id );
$formData->setProfile( $profile );
$formData->setFormActionMethod("POST");
$formData->setDeleteButtonText("Delete Profile");
$formData->setSubmitButtonText( "Update Profile" );
$on_cancel_route_url = $formData->getNamedUrl('profile.delete');
$on_submit_route_url = $formData->getNamedUrl('profile.update');
$formData->setFormCancelUrl($on_cancel_route_url);
$formData->setFormSubmitUrl($on_submit_route_url);
return $this->editForm($formData);
}
/* ... collapsed ... */
}
packages/clemence/profile/src/Profile.php
namespace Clemence\Profiles;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Model;
class Profile extends Model
{
use SoftDeletes;
}
RESOLVED: SOLUTION UNKNOWN
I will post the steps that I took to find the resolution here for those who may find this post in the future. I admit: I have no idea what fixed the problem.
What I did after asking the question
First and foremost, I got some sleep. When I have been coding too long, I find that sleep solves most problems.
On waking, I realized that I have a machine with XDebug installed and I can literally step through the PHP code as it executes, so I booted up that machine and did the following:
a. I moved the project to the local machine and opened it in NetBeans.
b. I placed breakpoints at several places in the middle ware so that I could verify that the system was running.
c. I changed the project config to run "as a website" and to load the url http://localhost:8000/profiles/1/edit as the start point.
d. I clicked 'Debug Program' and stepped through the bootup, the route loading, the model binding, and watched it all happen step-by-step looking for any line of code or parameter that looked out of sorts. I watched as the model was selected. I watched as it was passed the id 1 and asked to build the query. I watched as a collection of Profiles was returned (Oh! how excited I was to see the data I wanted sitting in that array and knowing that it was there but something would eventually block it, and I would find the block and release it!), and I watched as the collection was asked to return the first value. Then I watched as the parameter was set on the route. Lastly, I watched as the command $kernal->terminate() ran....
Needlessly to say, I was very disappointed and confused. How could I be getting an error, if the Kernal is running to completion?
So, I looked at the browser window, and there in the browser window was the very information that I was looking for! The Profile had loaded. I had changed nothing, and the Profile had loaded.
I moved the code back to the original machine, maybe it is an environment setting? I ran the web query without debugging, and it loaded... no error!
So, I honestly don't know what happened. I doubt that getting sleep helped the problem.
Maybe the Netbeans Debugger ran a cleanup service that fixed or patched a bad linkage? I honestly don't know, but I do know that this problem is resolved, so I post this answer in the hopes that it helps someone in the future, and that it saves other people the time of needlessly looking for an unnecessary solution.

Checking for Roles & Permissions in zizaco/entrust laravel package

I'm using zizaco/entrust package in my laravel project beside multi Auth package name Hesto/multi-auth
Our project on laravel 5.4,
i get below error when i want to get current logged in users' role and permissions with this method:
Entrust::hasRole('role-name'); OR Auth::user()->hasRole('role-name');
But I can access users' Role with this method for example :
$user = User::find($userid);
dd($user->hasRole('admin')); // Return true
i followed exactly installation instruction but i get below error :
`Non-static method Zizaco\Entrust\Entrust::hasRole() should not be called statically`
How can i solve my problem,
Thanks in advance
In this error message you have answer to your problem:
Non-static method Zizaco\Entrust\Entrust::hasRole() should not be called statically
You called this method hasRole() statically, but this method is non static. It means that you need to create object of this class, but you instead that used a class.
In the example that you gave:
$user = User::find($userid);
dd($user->hasRole('admin')); // Return true
you create an object of class User, and class User (I think) implements class Entrust:
$user = User::find($userid);
$user is an object and it`s not static, you can use hasRole().
In other words, to use method hasRole() (literally - is someone has a role?) you need this someone:
$user->hasRole('admin') // Is this user has role `admin`?
Hope, I explained it. Sorry about my English (I'm just studying).
In your User.php file add EntrustUserTrait like
<?php
namespace App;
//...
use Zizaco\Entrust\Traits\EntrustUserTrait;
class User extends Authenticatable
{
use Notifiable, EntrustUserTrait;
//...

How can I make the Laravel5 Codeception module not care if my database entities are Eloquent models?

I'm updating our codebase to use Laravel 5.2 which includes a bunch of unit tests that use codeception. Originally, the code was written using plain Doctrine2, which I updated to use LaravelDoctrine. With that change came the need to update the tests to use the codeception Laravel5 module.
Now, the tests were originally written as such
public function someTest(SomeTestObject $I) {
$I->wantTo('Some test objective');
$I->amOnPage('/some/page.php?parameter=678');
$I->waitForText('Text');
$I->click('Somelink');
$I->seeInRepository('My/Models/SomeObject', ['columnName' => 678]);
}
and they work and everything is awesome.
Once I updated to use the Laravel5 module, The $I->seeInRepository(... isn't generated by codeception in the AcceptanceTesterActions.php file, so I can't use it anymore. I tried a couple other methods that were there instead -- canSeeReord, seeInDatabase -- but they throw the exception
[RuntimeException] Class SomeObject is not an Eloquent model
I understand that because SomeObject actually isn't an Eloquent model but... who cares? The test worked before, and using the website works everywhere (LaravelDoctrine's tagline is "A drop-in Doctrine2 implementation for Laravel 5+" which it sort of is so that's cool).
We have a ton of models and some complicated structure to the current model set to which a complete rewrite simply isn't in scope...
I looked at the module code in Laravel5.php, and the exception and module looks pretty coupled to Eloquent models:
/**
* #param string $modelClass
*
* #return EloquentModel
*/
protected function getQueryBuilderFromModel($modelClass)
{
$model = new $modelClass;
if (!$model instanceof EloquentModel) {
throw new \RuntimeException("Class $modelClass is not an Eloquent model");
}
return $model->newQuery();
}
Is there a way around this?

Resources