because my component, controller and model has the same name:
<?php
namespace Plug\Controller;
use Plug\Controller\AppController;
class SettingController extends AppController
{
public function initialize(){
parent::initialize();
$this->loadModel('Setting');
$this->loadComponent('Plug.Setting');
}
How do I know how to refer to component or model ?
Check the manual, almost everything is there. Please consider checking the documentation, it's there to be read.
Aliasing Components
One common setting to use is the className option, which allows you to alias components. This feature is useful when you want to replace $this->Auth or another common Component reference with a custom implementation:
// src/Controller/PostsController.php
class PostsController extends AppController
{
public function initialize()
{
$this->loadComponent('Auth', [
'className' => 'MyAuth'
]);
}
}
// src/Controller/Component/MyAuthComponent.php
use Cake\Controller\Component\AuthComponent;
class MyAuthComponent extends AuthComponent
{
// Add your code to override the core AuthComponent
}
Related
In my LoginController under Auth, I have used the following codes:
namespace App\Http\Controllers\Auth;
use App\Model\Admin;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Input;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Redirect;
use Hash;
use Auth;
use DB;
use App\Model\UserAdmin;
class LoginController extends Controller {
use AuthenticatesUsers;
public function __construct() {
$this->middleware('guest')->except('logout');
}
public function doLogin(Request $request) {
$userdata = array(
'email' => Input::get('email'),
'password' => Input::get('password'),
'status' => '1',
);
if (Auth::guard('admin')->attempt($userdata)) {
return Redirect::intended('/administrator/dashboard')->with('successMessage', 'You have successfully logged in.');
}
}
}
And in UserAdmin (model) under app/Model is as follows:
namespace App\Model;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Config;
class UserAdmin extends Authenticatable {
protected $table = 'adminusers';
public $timestamps = false;
protected $fillable = ['firstName', 'lastName', 'email', 'company', 'website'];
public function __construct() {
parent::__construct(); // Don't forget this, you'll never know what's being done in the constructor of the parent class you extended
}
}
After submitting the login details, it shows me the error:
Type error: Argument 1 passed to Illuminate\Auth\EloquentUserProvider::validateCredentials() must be an instance of Illuminate\Contracts\Auth\Authenticatable, instance of App\Model\UserAdmin given, called in /var/www/html/XXXXXX/vendor/laravel/framework/src/Illuminate/Auth/SessionGuard.php on line 379
I suppose that you required to add implements \Illuminate\Contracts\Auth\Authenticatable to your UserAdmin model class definition.
class UserAdmin extends Model implements
\Illuminate\Contracts\Auth\Authenticatable
You must use Authenticatable in User model
for example:
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
//your code
}
You must declared use AuthenticableTrait for Authenticatable interface.
For example :
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Auth\Authenticatable as AuthenticableTrait;
use Illuminate\Database\Eloquent\Model;
class Company extends Model implements Authenticatable
{
use AuthenticableTrait;
Try and run 'composer dump-autoload' to check for "ambiguous User class resolution". It is likely you have two classes Defined as User Class.
use Illuminate\Foundation\Auth\AuthenticatesUsers;
Then in your model class, extends AuthenticatesUsers instead of Model.
You must extends Authenticatable class and implements JWTSubject in User model
For example :
class User extends Authenticatable implements JWTSubject {
Go to your Model and instead of extending Model, extend User
<?php
namespace App;
class Staff extends \Illuminate\Foundation\Auth\User
{
}
In cakephp 3 (3.3.5, that is) I want to extend my entity classes with custom functions (business logic). For example:
namespace App\Model\Entity;
use Cake\ORM\Entity;
class Something extends Entity {
public function isFoo() {
return true;
}
}
The corresponding table object looks like this:
namespace App\Model\Table;
use Cake\ORM\RulesChecker;
use Cake\ORM\Table;
use Cake\Validation\Validator;
use Cake\ORM\TableRegistry;
use App\Model\Entity\Something; // produces an `unused import' warning
class SomethingsTable extends Table
{
public function initialize(array $config)
{
parent::initialize($config);
...
}
...
}
In the controller, I use this code to retrieve the entity from the database and call the custom function:
class SomeOtherController extends AppController {
...
$this->loadModel('Somethings');
$thing = $this->SomethingsTable->get($id);
if ($thing->isFoo()) { ... }
...
}
However, this fails with a fatal error:
Error: Call to undefined method Cake\ORM\Entity::isFoo()
Note, when I do a
<?= var_dump($thing,true); ?>
in the corresponding view, $thing is shown as of type Cake\ORM\Entity.
How can I change the table's get() function to return entities with the correct type "Something" ?
It should be:
$thing = $this->Somethings->get($id);
// not
$thing = $this->SomethingsTable->get($id);
Thats why the Something entity is not used, but the default Entity class.
CakePHP autotables, since it can not find the SomethingsTableTable the default table class is used. Therefore also the default entity class is loaded.
If your test method would contain a query to the db, there would have been an error thrown, saying that somethings_table does not exist.
The problem is probably here:
class SomeOtherController extends AppController {
$this->loadModel('Somethings');
$thing = $this->SomethingsTable->get($id); // <-- Here
if ($thing->isFoo()) { ... }
}
Controller::loadModel does not set $this->SomethingsTable (which was probably set somewhere else in your code... ), but $this->Somethings, so this should be:
$this->loadModel('Somethings');
$thing = $this->Somethings->get($id);
if ($thing->isFoo()) { }
This code works, you do not need use App\Model\Entity\Something in SomethingsTable.php.
When trying to debug such thing, use debug() instead of var_dump:
Configure::write('debug', true); // If you are not already in debug mode
$this->loadModel('Somethings');
debug($this->Somethings);
Output:
object(App\Model\Table\SomethingsTable) {
'registryAlias' => 'Somethings',
'table' => 'somethings',
'alias' => 'Somethings',
'entityClass' => 'App\Model\Entity\Something', // Good!
'associations' => [],
'behaviors' => [],
'defaultConnection' => 'default',
'connectionName' => 'default'
}
This is an old post but I faced this issue today and the solution for me was slightly different. I was loading the model the right way, but my class name was not following naming conventions.
My Table: JobProfitsTable.php
My Entity: JobProfits.php (plural)
CakePhp is automatically looking for class named JobProfit.php (singular), and seems to fallback on Cake\ORM\Entity
So I had 2 options:
Rename my entity into JobProfit.php
Update my Table class with $this->setEntityClass('JobProfits')
I just started reading cakephp 3 docs (I have been developing with cake 2.x for some time) and want to migrate some website from 2.x to 3. In cake 2 in my AppModel I have some callbacks, particularly beforeFind and beforeSave, that contain some logic concerning almost all tables in a database.
Now in cake 3 there is no AppModel, how do I get the same thing done ? The best I can think of is to put that code in some behavior's callbacks, but I have like 30 models, should I load the behavior in all models one by one ?
Thanks
You can also create an AppTable in your src/Model/Table Folder:
namespace App\Model\Table;
use Cake\ORM\Table;
class AppTable extends Table
{
public function initialize(array $config)
{
parent::initialize($config);
$this->addBehavior('myBehavior');
$this->addBehavior('myBehavior2');
$this->addBehavior('myBehavior3');
}
}
And then extends your Table class by AppTable:
namespace App\Model\Table;
use App\Model\Table\AppTable;
class ArticlesTable extends AppTable
{
}
Use an event listener that listens to the events Model.beforeSave, Model.beforeFind and Model.initialize and apply whatever you want to do there. Read the chapter about events and the documentation for table callbacks.
use Cake\Event\EventListenerInterface;
use Cake\Event\Event;
class SomeListener implements EventListenerInterface
{
public function implementedEvents()
{
return [
'Model.beforeFind' => 'beforeFind',
];
}
public function beforeFind(Event $event, Query $query, ArrayObject $options, boolean $primary)
{
// Your code here
}
}
And attach it to the global event manager. It will now listen to the callbacks of all table object.
My Code tries to fetch all Main categories of the posts into Appcontroller to show on the homepage:
namespace App\Controller;
use Cake\Core\App;
use Cake\Controller\Controller;
class AppController extends Controller
{
public $helpers = ['Html', 'Form', 'Session','Time','Tree'];
public function initialize()
{
parent::initialize();
$this->loadComponent('Flash');
$this->maincategories();
}
function maincategories(){
App::import('Controller','Postcategories');
$postcates = new PostcategoriesController;
$postcates = $postcategory->find('threaded');
}
}
Your maincategories() method is wrong. You need the model, not the controller to retrieve the data from. You need to use TableRegistry::get('Postcategories') to get the Postcategories model and then call the find on that:-
public function maincategories()
{
$Postcategories = TableRegistry::get('Postcategories');
$this->set('postcategories', $Postcategories->find('threaded'));
}
$this->set() is setting the categories as a view variable ($postcategories). You will need to make sure you include use Cake\ORM\TableRegistry; at the top of your AppController file.
Make sure you've fully read the docs on retrieving data.
I need to know in a helper in a CakePHP application if the device is mobile, I would love to use $this->RequestHandler->isMobile(), but the request handler component is not available in helpers. Any ideas?
Thanks!
You can import the class and use it anywhere in the framework like so:
App::import('Component', 'RequestHandler'); // import class
$requestHandler = new RequestHandlerComponent(); // instantiate class
$isMobile = $requestHandler->isMobile(); // call method
var_dump($isMobile); // output: bool(true) or bool(false)
(Tested from helper and gives correct results for Firefox and iPhone)
Also, any options you set in the Controller::helpers property will be passed to the helper:
class AppController extends Controller {
public $components = array(/*...*/, 'RequestHandler');
public $helpers = array(/*...*/, 'MyHelper');
public function beforeFilter() {
$this->helpers['MyHelper']['mobile'] = $this->RequestHandler->isMobile();
}
}
You can catch the options array in your helper's constructor:
class MyHelper extends AppHelper {
protected $_defaultOptions = array('mobile' => false);
public function __construct($options) {
$this->options = array_merge($this->_defaultOptions, $options);
}
}
The accepted answer suggests using a component inside a helper which should be avoided as components are for use solely in controllers and will result in errors as mentioned by Anupal.
The simple solution is to use the CakeRequest class that RequestHandlerComponent uses. So in your helper you can do:-
App::uses('CakeRequest', 'Utility');
$isMobile = (new CakeRequest())->is('mobile');