CodeIgniter - Call method inside a model? - codeigniter

I have the following code:
class Badge extends CI_Model
{
public function foo()
{
echo $this->bar('world');
}
public function bar($word)
{
return $word;
}
}
But it always gives me an error on the line where echo $this->bar('world'); is.
Call to undefined method (......)

Your not loading your model inside your controller:
public function test()
{
$this->load->model('badge');
$this->badge->foo();
}
Because the code works - I've just tested it by pasting using your model unedited:
class Badge extends CI_Model
{
public function foo()
{
echo $this->bar('world');
}
public function bar($word)
{
return $word;
}
}
output:
world

In order to avoid any external call dependecy you need to get the Codeigniter instance and call the method through the instance.
class Badge extends CI_Model
{
public function foo()
{
$CI =& get_instance();
echo $CI->Badge->bar('world');
}
public function bar($word)
{
return $word;
}
}

Related

How can I avoid repeating this line in all my methods?

I am working on a blogging application in Laravel 8.
I have a settings table from which I pull the directory name of the current theme.
class ArticlesController extends Controller {
public $theme_directory;
public function index() {
// Theme _directory
$this->theme_directory = Settings::all()[0]->theme_directory;
// All articles
$articles = Article::all();
return view('themes/' . $this->theme_directory . '/templates/index', ['articles' => $articles]);
}
public function show($slug) {
// Theme _directory
$this->theme_directory = Settings::all()[0]->theme_directory;
// Single article
$article = Article::where('slug', $slug)->first();
return view('themes/' . $this->theme_directory . '/templates/single', ['article' => $article]);
}
}
The problem
A you can see, the line $this->theme_directory = Settings::all()[0]->theme_directory is repeted in both methods (and would be repeted in others in the same way).
Question
How can I avoid this repetition (and make my code DRY)?
Inheritance approach
Inheritance for a controller would avoid you from repeating it.
abstract class CmsController extends Controller{
protected $themeDirectory;
public function __construct()
{
$this->themeDirectory= Settings::first()->theme_directory ?? null;
}
}
Extend it and you can access it like you have always done.
class ArticlesController extends CmsController
{
public function index() {
dd($this->themeDirectory);
}
}
Trait
Use traits which is partial classes, done by just fetching it, as it is used in different controllers the performance is similar to saving it to an property as it is never reused.
trait Themeable
{
public function getThemeDirectory()
{
return Settings::first()->theme_directory ?? null;
}
}
class ArticlesController extends CmsController
{
use Themeable;
public function index() {
dd($this->getThemeDirectory());
}
}
Static function on model
If your models does not contain to much logic, a static function on models could also be a solution.
class Setting extends model
{
public static function themeDirectory()
{
return static::first()->theme_directory ?? null;
}
}
class ArticlesController extends CmsController
{
use Themeable;
public function index() {
dd(Setting::themeDirectory());
}
}

PHPUnit test for Laravel Artisan command without calling external API in inner instance (dependency injection)

I am trying to write a phpunit test with laravel 5.2 for a console command.
Few resources seems promising, but so far I failed making it work. I am trying to follow info given here:
stackoverflow - PHPUnit test for Laravel Artisan command that calls an external API without calling that API physically?
Laravel binding
The test is calling a command that 'binds' ExternalAPI class in its constructor.
In the test, I mock the ExternalAPI.
The ExternalAPI class:
Class ExternalAPI {
protected $lang;
public function __construct($lang)
{
$this->lang = $lang;
}
public function call_api($myparam){
//do the api stuff here
}
}
The command:
class MyCommand extends Command
{
protected $signature = 'check:mycommand';
protected $externalAPI ;
public function __construct(ExternalAPI $externalAPI)
{
$this->externalAPI = $externalAPI;
parent::__construct();
}
public function handle()
{
$res = $this->externalAPI->call_api('test');
}
}
The test:
class MyCommandTest extends TestCase
{
public function setUp()
{
parent::setUp();
$methods_to_stub = ['call_api'];
$mock = $this->getMockBuilder('\ExternalAPI')
->setConstructorArgs(array('param_value'))
->setMethods($methods_to_stub)
->getMock();
$mock->method('call_api')->willReturn(44.44);
$this->app->instance(ExternalAPI::class, $mock);
}
public function test1()
{
$output = new BufferedOutput;
Artisan::call('check:mycommand', [],$output);
echo "output:$output\n\n";
}
}
The error is:
Illuminate\Contracts\Container\BindingResolutionException:
Unresolvable dependency resolving [Parameter #0 [
$myparam]] in class App\MyLibrary\ExternalAPI
I managed to get it to work using mockery
This is the corrected code that works for me:
The ExternalAPI class (I removed the param from the constructor because right now I didn't check if and how it can be done):
Class ExternalAPI {
protected $lang;
public function __construct()
{
}
public function init($lang)
{
$this->lang = $lang;
}
public function call_api($myparam){
//do the api stuff here
}
}
The command:
class MyCommand extends Command
{
protected $signature = 'check:mycommand';
protected $externalAPI ;
public function __construct()
{
$this->externalAPI = app(ExternalAPI::class);
parent::__construct();
}
public function handle()
{
$this->externalAPI->init('whatever')
$res = $this->externalAPI->call_api('test');
}
}
The AppServiceProvider:
class AppServiceProvider extends ServiceProvider{
public function boot()
{
$this->app->bind('App\MyLibrary\ExternalAPI',function(){
return new \App\MyLibrary\ExternalAPI();
});
}
}
The test:
class MyCommandTest extends TestCase
{
public function setUp()
{
parent::setUp();
$mock = Mockery::mock('ExternalAPI');
$mock->shouldReceive('call_api')->with(Mockery::any())->andReturn(44.44);
$mock->shouldReceive('init')->with(Mockery::any());
$this->app->instance(ExternalAPI::class, $mock);
}
public function test1()
{
$output = new BufferedOutput;
Artisan::call('check:mycommand', [],$output);
echo "output:$output\n\n";
}
}

Add function to laravel Notification

I have next Notification class:
class WelcomeNotification extends Notification
{
use Queueable;
public function __construct()
{
//
}
public function via($notifiable)
{
return ['database'];
}
public function toDatabase($notifiable)
{
return [
//
];
}
}
And I want add some function to this. For example:
public function myFunction()
{
return 'something';
}
But $user->notifications->first()->myFunction return nothing
When you call the notifications() relation it turns out is a polymorphic relation using the DatabaseNotification model. The proper way is to inherit DatabaseNotification and write the custom function their.
For example, create app/DatabaseNotification/WelcomeNotification.php and inherit DatabaseNotification model.
namespace App\DatabaseNotification;
use Illuminate\Notifications\DatabaseNotification;
class WelcomeNotification extends DatabaseNotification
{
public function foo() {
return 'bar';
}
}
And override the notifications() function that uses the Notifiable trait:
use App\DatabaseNotification\WelcomeNotification;
class User extends Authenticatable
{
use Notifiable;
...
public function notifications()
{
return $this->morphMany(WelcomeNotification::class, 'notifiable')
->orderBy('created_at', 'desc');
}
...
}
And now you can call the custom function as follows:
$user->notifications->first()->foo();

laravel can't retrieve session when redirect

in laravel 5.4
class AdminController extends Controller
{
public function checkLogin(Request $request)
{
Session::put('admin','yes');
return redirect('mobiles');
}
}
class MobilesController extends Controller
{
public function __construct()
{
if( ( Session::has('admin') ) )
{ dd('admin');}
else
{ dd('not admin'); }
}
}
it prints 'not admin' so what happen to the session , if i prints the admin session in class checkLogin it prints normally
Since L5.3, you cannot a access to the session in the controller's constructor. You have to use a closure :
public function __construct()
{
$this->middleware(function ($request, $next) {
echo Session::has('admin') ? 'admin' : 'not admin';
return $next($request);
});
}
https://laravel.com/docs/5.3/upgrade#5.3-session-in-constructors
you have to use laravel flashed-session-data
https://laravel.com/docs/5.4/redirects#redirecting-with-flashed-session-data
return redirect('mtest2')->with('admin','yes');
so modify your code like this
class AdminController extends Controller {
public function checkLogin(Request $request){
return redirect('mobiles')->with('admin',true);
}
}
class MobilesController extends Controller {
public function __construct() {
if( session()->has('admin') ){
dd('admin');
}else{
dd('not admin');
}
}
}
Here is updated code if you do not want to use Flashed data
class AdminController extends Controller {
public function checkLogin(Request $request){
$request->session()->put('admin',true);
return redirect('mobiles');
}
}
it should work.

magento controller action

I have created the following class on my module
class Mage_Chargeagent_PaymentupdateController extends Mage_Core_Controller_Front_Action
{
public function indexAction()
{
echo "im here";
die();
}
}
it is located under local\Company\Chargeagent\controllers\PaymentupdateController.php
when im trying to navigate to http://www.xxx.com/index.php/chargeagent/paymentupdate im not getting to the correct action , what am i doing wrong ?
The class name should be Company_Chargeagent_PaymentupdateController
class Company_Chargeagent_PaymentupdateController extends Mage_Core_Controller_Front_Action
{
public function indexAction()
{
echo "im here";
die();
}
}

Resources