Call to undefined method App\Charts\SampleChart::labels(), chartjs - php

I'm currently doing the dashboard in our project and can't progress because of this error. Call to undefined method App\Charts\SampleChart::labels(). I suspect that I missed some installation and configurations but I've done it several times now.
SampleChart.php
<?php
declare(strict_types = 1);
namespace App\Charts;
use Chartisan\PHP\Chartisan;
use ConsoleTVs\Charts\BaseChart;
use Illuminate\Http\Request;
class SampleChart extends BaseChart
{
/**
* Handles the HTTP request for the given chart.
* It must always return an instance of Chartisan
* and never a string or an array.
*/
public function handler(Request $request): Chartisan
{
return Chartisan::build()
->labels(['First', 'Second', 'Third'])
->dataset('Sample', [1, 2, 3])
->dataset('Sample 2', [3, 2, 1]);
}
}
dashboardcontroller
<?php
namespace App\Http\Controllers;
use App\Charts\SampleChart;
use Illuminate\Http\Request;
use App\Models\ratings;
class DashboardController extends Controller
{
public function dashboard() {
$rating = ratings::all();
$chart = new SampleChart;
$chart->labels(['One', 'Two', 'Three']);
$chart->dataset('My Dataset 1', 'line', [1,2,4]);
return view('user/admin/dashboard', compact('rating'));
}
}
charts.php
<?php
declare(strict_types=1);
return [
/*
|--------------------------------------------------------------------------
| Global Route Prefix
|--------------------------------------------------------------------------
|
| This option allows to modify the prefix used by all the chart routes.
| It will be applied to each and every chart created by the library. This
| option comes with the default value of: 'api/chart'. You can still define
| a specific route prefix to each individual chart that will be applied after this.
|
*/
'global_route_prefix' => 'api/chart',
/*
|--------------------------------------------------------------------------
| Global Middlewares.
|--------------------------------------------------------------------------
|
| This option allows to apply a list of middlewares to each and every
| chart created. This is commonly used if all your charts share some
| logic. For example, you might have all your charts under authentication
| middleware. If that's the case, applying a global middleware is a good
| choice rather than applying it individually to each chart.
|
*/
'global_middlewares' => ['web'],
/*
|--------------------------------------------------------------------------
| Global Route Name Prefix
|--------------------------------------------------------------------------
|
| This option allows to modify the prefix used by all the chart route names.
| This is mostly used if there's the need to modify the route names that are
| binded to the charts.
|
*/
'global_route_name_prefix' => 'charts',
];
i followed this site just like what creators on youtube tells: https://charts.erik.cat/guide/installation.html
what could be the problem? please help

It looks like you are trying to call ->labels() on an instance of SampleChart based on the principle of multi-inheritance in php. The problem with that here is that ->labels() is a method of Chartisan class not SampleChart or BaseChart which it extends, hence the error you get (basically just saying hey, I cannot find labels()).
See this answer for an explanation of multi-level inheritance in PHP.
More info: https://www.php.net/manual/en/language.oop5.inheritance.php
I'm curious what your use case for doing this in your controller is though. If it is for rendering, the docs you provided has this: https://charts.erik.cat/guide/render_charts.html

Related

Laravel Route Model Binding - Resource Controller [duplicate]

I have been using RESTful controllers in my Laravel project. By including:
Route::controller('things', 'ThingController')
in my routes.php, I can define functions in the ThingController like:
public function getDisplay($id) {
$thing = Thing::find($id)
...
}
so that GETting the URL "...things/display/1" would automatically be directed to the controller function. This seems pretty handy and has been working great for me so far.
I noticed many of my controller functions start with getting a model by id from the url, and I thought it would be nice to be able to use route model binding to do this for me instead. So I updated my routes.php to
Route::model('thing', 'Thing');
Route::controller('things', 'ThingController')
and changed the ThingController functions to
public function getDisplay($thing) {
...
}
I assumed this would magically work the way I wanted it to (like everything else I've tried so far in Laravel has) but unfortunately I get "Trying to get property of non-object" when I attempt to use $thing in the function. Is this something that should be able to work and I have just done it wrong, or can route model binding only work with routes explicitly named in routes.php?
If you don't mind with URI path, method name and just work only show, edit and update method, you can use Resource Controller to generate URI string which can define model binding.
In routes.php change to
Route::model('things', 'Thing');
Route::resource('things', 'ThingController');
You can use php artisan routes command to see all URIs
$ artisan routes | grep ThingController
GET|HEAD things | things.index | ThingController#index
GET|HEAD things/create | things.create | ThingController#create
POST things | things.store | ThingController#store
GET|HEAD things/{things} | things.show | ThingController#show
GET|HEAD things/{things}/edit | things.edit | ThingController#edit
PUT things/{things} | things.update | ThingController#update
PATCH things/{things} | | ThingController#update
After that you can threat parameter as Thing object without explicitly name route.
/**
* Display the specified thing.
*
* #param Thing $thing
* #return mixed
*/
public function show(Thing $thing)
{
return $thing->toJson();
}
If you want to access ThingController#show, pass your model ID and Laravel will retrieve it automatically.
http://example.com/things/1
{"id":1,"type":"Yo!"}
You can use Route:resource and still provide other methods. Place the route you need just before that particular Route::resource line.
Eg:
Route::model('things', 'Thing');
Route::get('things/{things}/owner', 'ThingController#getOwner');
Route::resource('things', 'ThingController');
Then create the corresponding method in your controller.
public function getOwner($things) {
return Response::json($things->owner()->get());
}
Here is the official documentation from the Laravel 4.2 docs:
Source: http://laravel.com/docs/controllers#resource-controllers
Adding Additional Routes To Resource Controllers
If it becomes necessary for you to add additional routes to a resource controller beyond the default resource routes, you should define those routes before your call to Route::resource:
Route::get('photos/popular');
Route::resource('photos', 'PhotoController');

Laravel Route resource named functions

I currently have routes like this
//Settings
Route::prefix('settings')->group(function(){
//Get all users settings
Route::resource('user', 'SettingsController');
});
Which will produce a list of routes like so
| POST | settings/user |user.store | App\Http\Controllers\SettingsController#store | web,auth,GlobalAdmin |
| GET|HEAD | settings/user |user.index | App\Http\Controllers\SettingsController#index | web,auth,GlobalAdmin |
| GET|HEAD | settings/user/create |user.create | App\Http\Controllers\SettingsController#create | web,auth,GlobalAdmin |
And so on.
My issue is that I want the settings controller to be able to control a list of different settings in 1 controller, not just 'users'.
How would I name the resource so that it names the functions at the end?
For example, the above code generates function names like SettingsController#store, how would i get it so that it auto builds the function name with a prefix like SettingsController#userstore?
You can't. Unless you go behind the scenes and actually hack into how Laravel handles the generation. What you can do however is use except on the resource route or use partial resource routes.
Once you have done one of the above, you can just add your routes manually such as
POST settings/user
POST settings/other
POST settings/general
And point them that way.
If you really want to have such behavior you can have it. You can extend the Illuminate\Routing\ResourceRegistrar class and bind your extended version to the container.
There is only one method that needs to be adjusted, which is the method that sets up the action for each of the routes of the resource, getResourceAction. This can be adjusted to check for a key passed in the options array the the ResourceRegistrar already uses. If a key is present you can enable the behavior you need, prefixing the method name with the resource name and uppercasing the first letter of the actual method.
class YourRegistrar extends \Illuminate\Routing\ResourceRegistrar
{
protected function getResourceAction($resource, $controller, $method, $options)
{
$name = $this->getResourceRouteName($resource, $method, $options);
// check if 'pre' option was set
$method = isset($options['pre']) ? $resource . ucfirst($method) : $method;
$action = ['as' => $name, 'uses' => $controller.'#'.$method];
if (isset($options['middleware'])) {
$action['middleware'] = $options['middleware'];
}
return $action;
}
}
In a Service Provider #register (binding your new class to the current ResourceRegistrar):
$this->app->bind(
\Illuminate\Routing\ResourceRegistrar::class,
\Where\Ever\YourResourceRegistrar::class
);
In a routes file:
Route::resource('user', 'SettingsController', ['pre' => true]);
// SettingsController#userIndex
// SettingsController#userShow
// ...
Route::resource('user', 'SettingsController');
// SettingsController#index
// SettingsController#show
// ... normal
The router checks to see if there is something bound to the name of the ResourceRegistrar on the container before newing up one. If there is a binding it asks the container to resolve one. This is how you can extend the ResourceRegistrar and the router uses your version.
In our version we are checking if the options key pre was set or not. If it was we adjust the method names for the routes accordingly. ($method = isset($options['pre']) ? $resource . ucfirst($method) : $method;)
You can read more on the ResourceRegistrar and more detail of what happened above in my blog article on the subject:
asklagbox blog - Resource Registrar - lets extend

Where to locate database logic in laravel?

I am currently new to laravel and I am trying to wrap my head around code structure with laravel. The reason for learning laravel is to grow my knowledge on creating good code in addition to creating an easily to manage application. For this reason, It is important to me that I am building my application to an accepted standard.
I have read several articles but am still not exactly sure where to organize things.
As of now, my application structure looks as so:
app/
Console
Exceptions
Http
Controllers
Auth
Message
Settings
Middleware
Providers
Traits
Message
Settings
One of my controller looks like something like this:
<?php
namespace App\Http\Controllers\Message;
use DB;
use Auth;
use Request;
use App\Http\Controllers\Controller;
class TypeController extends Controller
{
public function __construct () {
$this->middleware('auth');
$this->middleware('access');
}
public function type () {
$this->adjustTypingStatus(1);
}
public function untype () {
$this->adjustTypingStatus(0);
}
protected function adjustTypingStatus ($level) {
DB::table('user_lobby_info')
->where('userid', Auth::User()->id)
->where('lobby', Request::get('lobbyid'))
->update([ 'typing' => $level ]);
}
}
?>
The Question
What is a better way to separate controllers into smaller, more manageable pieces? Should I put the database logic into the model and just call the model's method?
This is how I break down controller logic and use the Model for small to medium size projects.
1. Create your table and model
This command will create your Model and the --migration will create a migration file that references the BluePrint class that you can use to create your Model's table.
php artisan make:model UserLobbyInfo --migration
You seem to have a database already created, so you may want to remove the --migration, unless you want to use it to create schemas using BluePrint. I personally like using the migrations. Your Model will be created directly under the App folder in Laravel 5.
2. Modify your Model file
You find your Model file in the App folder. In your model you should add the fields you'll insert or update (mass fillable items) and the name of your table if it doesn't follow the Laravel convention (Laravel assumes that the camel casing indicates different words and that your table ends with an 's', so it thinks your table will be user_lobby_infos, in your case, your table name is user_lobby_info). This is how I'd update it based in your data in your query above:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class UserLobbyInfo extends Model
{
// Define mass fillable items
protected $fillable = array('userid','lobby','typing');
//Define table
protected $table = 'user_lobby_info';
}
How you can Use your Model
This model now has all the methods provided to it from it's extended Illuminate\Database\Eloquent\Model class, so you can do the following and more:
//To query all content:
$index = UserLobbyInfo::all();
//To query specific content:
$userLobby = UserLobbyInfo::where('id', '=', 1)->first();
//Save things:
$userLobbyInfo = UserLobbyInfo::where('id', '=', 1)->first();
$userLobbyInfo->lobby = Request::get('lobbyid')
$userLobbyInfo->save();
//Using the model for your query above this is how you can send an update:
UserLobbyInfo::where('userid', '=', Auth::User()->id)
->where('lobby', '=', Request::get('lobbyid'))
->update([ 'typing' => $level ]);
3. Creating Controller pre-canned with CRUD related methods
This command will create a controller with all the methods you'd typically use in a CRUD app (Index, show, create, save, edit, update, delete)
php artisan make:controller UserLobbyController --resource
in each of these functions you'd add the respective model with the method you need.
4. Add all the routes traditionally used in a CRUD App and linked to the --resource methods
If you use the --resource you will be able to use a resource function that will provide you with all the routes required for those respective resources.
Route::resource('userlobby', 'UserLobbyController');
that one line in your route file will create the following routes typical in a CRUD app run "php artisan route:list |grep userlobby" and youll see these routes:
| | GET|HEAD | userlobby | userlobby.index | App\Http\Controllers\UserLobbyController#index | web |
| | POST | userlobby | userlobby.store | App\Http\Controllers\UserLobbyController#store | web |
| | GET|HEAD | userlobby/create | userlobby.create | App\Http\Controllers\UserLobbyController#create | web |
| | GET|HEAD | userlobby/{userlobby} | userlobby.show | App\Http\Controllers\UserLobbyController#show | web |
| | PUT|PATCH | userlobby/{userlobby} | userlobby.update | App\Http\Controllers\UserLobbyController#update | web |
| | DELETE | userlobby/{userlobby} | userlobby.destroy | App\Http\Controllers\UserLobbyController#destroy | web |
| | GET|HEAD | userlobby/{userlobby}/edit | userlobby.edit | App\Http\Controllers\UserLobbyController#edit | web |
5. Condense your Controller to CRUD methods
I will just an edit and update method below as this can get quite lengthy. Hopefully this gives you an idea on how to breakdown a controller:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\UserLobbyInfo; // Add this to access your new model
use App\Http\Requests;
class UserLobbyController extends Controller
{
/**
* Show the form for editing the specified resource.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function edit($id)
{
$updateLobby = UserLobbyInfo::where('id', '=', $id)->first(); //This queries the table specifically for the id, just for demo purposes.
return view('lobbies.edit', compact('updateLobby')); //This will send the above defined array to your view to pre-populate.
}
/**
* Update the specified resource in storage.
*
* #param \Illuminate\Http\Request $request
* #param int $id
* #return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
{
$userLobby = UserLobbyInfo::where('userid', '=', Auth::User()->id)
->where('lobby', '=', $request->lobbyid)->first();
//Grab the UserLobby row you want to update.
$updateLobby->typing = $level; //update the typing value
$updateLobby->save(); // save it.
}
For more complex applications, I typically will migrate the heavier controller logic out to a class, and reference the class in the controller using it. I also only use DB:: class when I'm writing a complex query with multiple table joins (especially a join with multiple where clauses required in that join).
Hopefully that helps highlight how to properly use the Model in Laravel.
A lot of this info is available in the laravel documentation. I also like this cheat sheet: laravel cheat sheet
Any more questions, or if I didn't fully answer your question, just let me know.
Use Eloquent instead of raw SQL queries or Query Builder queries. Put all data related logic into Model classes:
public function getApprovedUsersWithPosts()
{
return $this->where('approved', true)->with('posts')->get();
}
Your controllers should be really small. Never put queries or other logic into controllers. Also, use DI instead of facades:
protected $user;
public function __construct(User $user)
{
$this->user = $user;
}
public function index()
{
return view('users.approved', [
'users' => $this->user->getApprovedUsers()
]);
}

Laravel 5 custom module routes not working

I'm creating my custom modules for my projects to be able to add some features to a project or another depending of the requeriments.
My issue is with the routes, I load the routes in a ModuleServiceProvider loaded in app.php:
include __DIR__.'/../../modules/canae/Http/routes.php';
I checked that this works with an echo inside that file. The routes.php file contains the following code:
Route::group(['prefix' => 'admin', 'middleware' => 'auth'], function() {
Route::controller('dogs', 'Canae\Http\Controllers\Admin\DogController');
});
I also checked that Laravel can find the Controller, the problem is that it's unable to execute the code inside it.
Here's the code I have inside DogController:
<?php namespace Canae\Http\Controllers\Admin;
class DogController extends \Origin\Http\Controllers\Controller {
public function getIndex() {
echo "Hello!";die();
}
}
And the error is Controller method not found.
If I modify the extends below to Origin\Http\Controllers\Controller (removing the first \) I get the following error: Class 'Canae\Http\Controllers\Admin\Origin\Http\Controllers\Controller' not found so my conclusion is that the code inside this controller is executing, at least reading from Laravel.
Also I'm trying to achieve the Index function with this route http://localhost/canae/public/admin/dogs/index.
This is the tail result of executing php artisan route:list:
| | GET|HEAD | admin/dogs/index/{one?}/{two?}/{three?}/{four?}/{five?} | | Canae\Http\Controllers\Admin\DogController#getIndex | auth |
| | GET|HEAD | admin/dogs | | Canae\Http\Controllers\Admin\DogController#getIndex | auth |
| | GET|HEAD|POST|PUT|PATCH|DELETE | admin/dogs/{_missing} | | Canae\Http\Controllers\Admin\DogController#missingMethod | auth |
+--------+--------------------------------+-------------------------------------------------------------------------------+--------+--------------------------------------------------------------------+------------+
Tell me if you need more information. And thanks for your time.
I solved it moving the line inside providers that loads this routes to the first item of the providers array, even before the application ones. Don't know why, but now it's working.
In light of the docs at: http://laravel.com/docs/master/controllers
Have you tried using the "use" statement? Your code would then look like:
<?php
namespace Canae\Http\Controllers\Admin;
use Canae\Http\Controllers\Controller;
class DogController extends Controller {
public function getIndex() {
echo "Hello!";die();
}
}
I'm also not sure why your namespace is "Canae\Http\Controllers\Admin" as the example shows "App\Http\Controllers" only. I'm not familiar with the specific structure of your project, but removing the "\Admin" might also help.

Can route model binding be used with RESTful controllers?

I have been using RESTful controllers in my Laravel project. By including:
Route::controller('things', 'ThingController')
in my routes.php, I can define functions in the ThingController like:
public function getDisplay($id) {
$thing = Thing::find($id)
...
}
so that GETting the URL "...things/display/1" would automatically be directed to the controller function. This seems pretty handy and has been working great for me so far.
I noticed many of my controller functions start with getting a model by id from the url, and I thought it would be nice to be able to use route model binding to do this for me instead. So I updated my routes.php to
Route::model('thing', 'Thing');
Route::controller('things', 'ThingController')
and changed the ThingController functions to
public function getDisplay($thing) {
...
}
I assumed this would magically work the way I wanted it to (like everything else I've tried so far in Laravel has) but unfortunately I get "Trying to get property of non-object" when I attempt to use $thing in the function. Is this something that should be able to work and I have just done it wrong, or can route model binding only work with routes explicitly named in routes.php?
If you don't mind with URI path, method name and just work only show, edit and update method, you can use Resource Controller to generate URI string which can define model binding.
In routes.php change to
Route::model('things', 'Thing');
Route::resource('things', 'ThingController');
You can use php artisan routes command to see all URIs
$ artisan routes | grep ThingController
GET|HEAD things | things.index | ThingController#index
GET|HEAD things/create | things.create | ThingController#create
POST things | things.store | ThingController#store
GET|HEAD things/{things} | things.show | ThingController#show
GET|HEAD things/{things}/edit | things.edit | ThingController#edit
PUT things/{things} | things.update | ThingController#update
PATCH things/{things} | | ThingController#update
After that you can threat parameter as Thing object without explicitly name route.
/**
* Display the specified thing.
*
* #param Thing $thing
* #return mixed
*/
public function show(Thing $thing)
{
return $thing->toJson();
}
If you want to access ThingController#show, pass your model ID and Laravel will retrieve it automatically.
http://example.com/things/1
{"id":1,"type":"Yo!"}
You can use Route:resource and still provide other methods. Place the route you need just before that particular Route::resource line.
Eg:
Route::model('things', 'Thing');
Route::get('things/{things}/owner', 'ThingController#getOwner');
Route::resource('things', 'ThingController');
Then create the corresponding method in your controller.
public function getOwner($things) {
return Response::json($things->owner()->get());
}
Here is the official documentation from the Laravel 4.2 docs:
Source: http://laravel.com/docs/controllers#resource-controllers
Adding Additional Routes To Resource Controllers
If it becomes necessary for you to add additional routes to a resource controller beyond the default resource routes, you should define those routes before your call to Route::resource:
Route::get('photos/popular');
Route::resource('photos', 'PhotoController');

Categories