in cakephp4 how to access a model within a model - cakephp

How do i access another model within a model in cakephp4.2? The docs on this issue isnt clear to me and i can then run a query on this ? TableRegistry is deprecated now.
error Unknown method "getTableLocator" called on App\Model\Table\LessonsTable
//none of these no longer work
in model {
use Cake\ORM\Locator\LocatorAwareTrait;
class LessonsTable extends Table
{
..
private function getlessonRevenue(){
//$clients = $this->getTableLocator()->get('Clients');
// $cleints = TableRegistry::get('Clients');
// $this->Table = TableRegistry::get('Clients');
$clients = $this->getTableLocator()->get('Clients');
https://api.cakephp.org/4.0/class-Cake.ORM.TableRegistry.html

Try:
<?php
use Cake\ORM\Locator\LocatorAwareTrait; //<------------ add here
class ArchivesTable extends Table
{
use LocatorAwareTrait; // <--------------------------- and add here
public function myMethod()
{
$clients = $this->getTableLocator()->get('Clients');
}
and read https://book.cakephp.org/4/en/orm/table-objects.html#using-the-tablelocator
and learn how to use php trait https://www.phptutorial.net/php-tutorial/php-traits/

Related

How to test CakeEmail is called from a model

In CakePHP 2.1 I'm trying to test that the CakeEmail::to() method is called from my model test case with the correct "to" email (In this example: cat#gmail.com).
I want the following test to pass but I get:
Expectation failed for method name is equal to <string:to> when invoked 1 time(s).
Method was expected to be called 1 times, actually called 0 times.
Here's the code in the Model and the test case:
<?php
// Model/Job.php
App::uses('AppModel', 'Model');
App::uses('CakeEmail', 'Network/Email');
class Job extends AppModel {
public function emailCat() {
$CakeEmail = new CakeEmail();
$CakeEmail->to('cat#gmail.com');
$CakeEmail->subject('hello!');
$CakeEmail->emailFormat('text');
$CakeEmail->config('default');
$CakeEmail->send('hi');
}
}
// Test/Model/JobTest.php
class JobTestCase extends CakeTestCase {
public function setUp() {
parent::setUp();
$this->Job = ClassRegistry::init('Job');
}
public function testEmailCat() {
// I want to assert CakeEmail::to() is called with correct email
$CakeEmail = $this->getMock('CakeEmail' , array('to'));
$CakeEmail->expects($this->once())
->method('to')
->with($this->equalTo('cat#gmail.com'));
$result = $this->Job->emailCat();
}
}
The problem is that you're mocking a completely different class then the one that is actually used on the model. On your model function, you instantiate a brand new email class which will be mocked. Instead, you need to make sure that the CakeEmail object that the model uses is the one mocked.
class Job extends AppModel {
public $CakeEmail = null;
public function emailCat() {
if (!$CakeEmail) {
$this->CakeEmail = new CakeEmail();
}
$this->CakeEmail = new CakeEmail();
$this->CakeEmail->to('cat#gmail.com');
$this->CakeEmail->subject('hello!');
$this->CakeEmail->emailFormat('text');
$this->CakeEmail->config('default');
$this->CakeEmail->send('hi');
}
}
Then update your test case to set the mock object on your Job model.
class JobTestCase extends CakeTestCase {
public function setUp() {
parent::setUp();
$this->Job = ClassRegistry::init('Job');
}
public function testEmailCat() {
// I want to assert CakeEmail::to() is called with correct email
$CakeEmail = $this->getMock('CakeEmail' , array('to'));
$CakeEmail->expects($this->once())
->method('to')
->with($this->equalTo('cat#gmail.com'));
// use mock object instead of creating a brand new one
$this->Job->CakeEmail = $CakeEmail;
$result = $this->Job->emailCat();
}
}

How should I use Component in Helper?

I used AkismetComponent in AkisHelper and my AkisHelper code is:
<?php
App::uses('AppHelper', 'View/Helper');
class AkisHelper extends AppHelper {
public $helpers = array('Html');
public $components = array('Akismet');
function isValid() {
if ($this->Akismet->isKeyValid()) {
echo 'OK';
} else {
echo 'Error';
}
}
}
But this error occured:
Error: Call to a member function isKeyValid() on a non-object
File: /var/www/cakeblog/app/View/Helper/AkisHelper.php
Line: 10
Please help me to solve my problem.
Thanks
Your not supposed to be able to n_n.. It's not MVC, it's like trying to call a controller method inside the view.
However you could always pass a variable to the view in your Akismet component, something like:
class AkismetComponent extends Component {
private $controller;
public function initialize($controller) {
$this->controller = $controller;
//here I pass a variable to the view
$this->controller->set('isKeyValid',$this->isKeyValid());
}
and in your view use it like any other variable:
if(isset($isKeyValid) && $isKeyValid){
}
Anyway, if you don't want to change the component, you could still pass the variable from the controller.
The view should be used only to display the information. Helpers should be only functions to help you with that, but they are not supposed to do business logic.
Hope this helps

CakePHP: Find if is mobile browser in a helper (no access to request handler)

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');

Override model validate errors

I am new to CakePHP.
I would like to use the model validate mechanism, but I'm having trouble overriding the errors that are displayed. I am building an API where all the views need to be rendered in JSON and I have a JSON format that all errors need to output as. I've defined a custom AppError class and I have successfully be able to define custom errors in this format there.
Is there a way to use the AppError class to override the output of the error messages coming from validation?
Thanks.
I came up with a solution by adding these methods to my AppModel class:
function validates($options = array()) {
$result = parent::validates($options);
if (!$result) {
$this->_validateErrors();
}
return $result;
}
function _validateErrors() {
foreach ($this->validationErrors as $code) {
$this->cakeError('apiError', array('code' => $code)); // Custom JSON error.
return;
}
}
I then manually call $this->Model->validates() before a Model::save() call in my controller. This seems to be working well.
As far as I know, there's no direct way to get validation errors from within your AppError class. The way around it would be to create an AppModel class in app/app_model.php and use the onError() callback method to pass the error to your AppError class.
// app/app_model.php
class AppModel extends Model {
public function onError() {
// Pass the errors to your AppError class
AppError::someErrorMethod($this->getErrors());
}
}

Cakephp getting session variable in model without using Auth component

I want to get my session variables in my model. Im not using Auth component. Is there any alternate way ?
Thanks
Binoy
You would need to use the Session helper to do,
$this->Session->write('key','value');
But as the comment states, you'll be wanting to set a variable in your model and then use the session to write the same value into that variable in the model, rather than accessing the session actually in the model.
Class MyModel Extends AppModel{
var $username;
var $password;
}
Then in your controller you could use something along the lines of,
$this->MyModel->username = $this->Session->read('User.id');
$this->MyModel->password = $this->Session->read('User.password');
Controller File : use Session helper
class AppController extends Controller {
var $helpers = array('Session');
function index()
{
$this->Session->write('answer', '10'); //$this->Session->write('key','value');
}
....
}
Now you can access this varibale in your model :
class AppModel extends Model {
function validateanswer(){
CakeSession::read('answer');/*Here u can get value of varibale answer which you set through controller*/
}
}

Resources