CodeIgniter - Singleton pattern not allowed? - codeigniter

I'm trying to use a singleton pattern in a class I've created. I'm using CodeIgniter and it seems to require the the constructor of all model objects be public.
Is there a way around this? What's the best approach if I can't use the Singleton pattern?
My Class:
class RakebackSites extends CI_Model {
private $allSites = array();
private function __construct() {
parent::__construct();
self::initAllSites();
}
public static function getInstance() {
if(empty(self::$instance)) {
self::$instance = new CurrencyTypes();
}
return self::$instance;
}
private function initAllSites() {
$sql = "SELECT * FROM rakeback_sites";
$this->db->query($sql);
foreach ($q->result() as $row) {
$allSites[] = new RBSite($row->id, $row->name, $row->logo, $row->rakeback, $row->sign_up_bonus, $row->sign_up_bonus_currency, $row->referral_code, $row->id);
}
}
public function getAllSites() {
return $this->allSites;
}
}
And the error I get:
Fatal error: Access level to RakebackSites::__construct() must be public (as in class CI_Model) in /home/.../application/models/rakebacksites.php on line 29

If I recall correctly, CI automatically effectively creates Singletons if you load via $this->load->model('Your_model'). Obviously, it would still be possible to instantiate directly but then... just don't do it. Alternatively, don't inherit from CI_Model.

Does it let you declare the constructor as protected instead of private? Not exactly singleton but would that still work for your purposes?

Making a constructor private or protected does not have anything to do with the singleton pattern. All you are doing is defining an abstract class that cannot be directly instantiated.
To produce a singleton you need to override the new() method or implement a class factory.

Related

bind abstract class service in provider laravel

Gives an error:
Target [MyVendor\ProductList\ProductServiceInterface] is not instantiable.
ProductServiceInterface
namespace MyVendor\ProductList;
interface ProductServiceInterface
{
public function productList();
public function getProductSpeed();
}
ProductColorService
namespace MyVendor\ProductList\Service;
abstract class ProductColorService implements \MyVendor\ProductList\ProductServiceInterface
{
public function productList()
{
$color = "black";
return $color;
}
}
** ProductSpeedService **
namespace MyVendor\ProductList\Service;
abstract class ProductSpeedService implements \MyVendor\ProductList\ProductServiceInterface {
public function getProductSpeed() {
$speed = 200;
return $speed;
}
}
Provider :
namespace MyVendor\ProductList;
use Illuminate\Support\ServiceProvider;
use MyVendor\ProductList\ProductServiceInterface;
use MyVendor\ProductList\Service\ProductColorService;
class ProductColorServiceProvider extends ServiceProvider
{
public function boot()
{
$this->loadRoutesFrom(__DIR__ . '/routes/color.php');
}
public function register()
{
$this->app->bind('MyVendor\ProductList\ProductServiceInterface','MyVendor\ProductList\Service\ProductColorService');
$this->app->bind('MyVendor\ProductList\ProductServiceInterface','MyVendor\ProductList\Service\ProductSpeedService');
}
}
Whats wrong in this code? Actually I need to override some functions in interface using service. ie each service should override one method.
namespace MyVendor\ProductList\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use MyVendor\ProductList\Models\Product;
use MyVendor\ProductList\ProductServiceInterface;
class ProductListController extends Controller
{
public function index(ProductServiceInterface $product_service)
{
$color = $product_service->productList();
$speed = $product_service->getProductSpeed();
dd($color," = ",$speed);
$product = Product::get();
return view('ProductList::product',compact('product'));
}
}
here productList() in one service and productSpeed() from another service
You can't instantiate abstract classes. The whole point of them is there can never be an instance of them, so if you bind your interface to your abstract class with a method, it simply can never be abstract. Abstract is for classes in inheritance structures you do not want to have the users to create new ones.
So there is no reason for the abstract, abstract is for something like this.
abstract class Vehicle {
protected $wheels;
public function getWheels() {
return $this->wheels;
}
}
class Car extends Vehicle {
protected $wheels = 4;
}
class Bike extends Vehicle {
protected $wheels = 2;
}
You can not make a vehicle as it is not a concrete implementation, as it is a parent class to help with methods shared across two classes. So short version, just remove the abstract keyword. If you don't know why you add it, it is not needed.

How to write a custom function in a model?

There is a model data:
class Order extends Model
{
}
How to write a custom method inside the Order class so that it can be called in constructor like this:
Order::myMethod()
Order->myMethod()
Where myMethod is:
public function myMethod() {
return DB::query(<SQL QUERY>);
}
Purpose is to move SQL queries inside model's class, that don't mess this code in controllers.
Rather create a custom function in Model, You can use traits to achieve the desired output.
Please follow either steps:-
https://medium.com/#kshitij206/traits-in-laravel-5db8beffbcc3
https://www.conetix.com.au/blog/simple-guide-using-traits-laravel-5
Guess you are asking about the static functions:
class Order extends Model {
public static function myMethod() {
}
}
and you can call it anywhere like
Order::myMethod();
You can achieve the desired behavior using magic methods __call and __callStatic
if your real method is static you can use __call() to intercept all "non static" calls and use it to call the static and use __callStatic to forward the calls to a new instance to that class .
Your methods should be always static because if a non static method exists and you are calling it statically php raises an error
Non-static method Foo::myMethod() should not be called statically
No problem if your method is static
class Order extends Model {
public static function myMethod() {
return static::query()->where(...)->get(); // example
}
public function __call($name, $arguments) {
return forward_static_call_array([__CLASS__, $name], $arguments);
}
public static function __callStatic($name, $arguments) {
return call_user_func_array([app(__CLASS__), $name], $arguments);
}
}
(new Order())->myMethod();
Order::myMethod();
I can't understand your exact problem is. but if you are using laravel, then you can write custom method inside the ABC model like this
class ABC extends Model
{
//here is your fillable array;
public function abc()
{
//Here is your Eloquent statement or SQL query;
}
}
just call this abc() method inside the controller like this
use ABC;
class AbcController extends Controller
{
private $_abc; // it is private variable
// this is constructor
public function __construct(ABC $abc)
{
$this->_abc= $abc;
}
public function abcMethod()
{
$this->_abc->abc();
}
}
Thanks
I don't believe I'm understanding your intention. You've stated:
Purpose is to move SQL queries inside model's class, that don't mess this code in controllers.
Why does the Order->myMethod() need calling inside the constructor? If you're trying to design your data access layer to work efficiently, you can use data repositories.

Laravel: use extended controller or Traits or something else?

To maintain my Laravel application and save myself from a lot of duplicate code I have made the following solution:
BaseController
class BaseController extends Controller
{
public function get($id){
return $this->baseService->get($id);
}
public function getAll(){
return $this->baseService->getAll();
}
}
BaseService
class BaseService
{
protected $model;
public function __construct($model){
$this->model = $model;
}
public function get($id){
return response()->json($this->model->where('id', $id)->first());
}
public function getAll()
{
return $this->model->get();
}
}
MyController
class MyController extends BaseController
{
protected $model;
protected $baseService;
public function __construct(){
$this->model= new Model();
$this->baseService = new BaseService($this->model);
}
/**
* This controller has all the functionality from BaseController now
*/
}
What I'm wondering if this is a good method. Should I stick with this or should I use a different approach? I've heard about Traits but not sure if they are doing the same thing. It's Laravel 5.5 I'm using.
Yes, traits are used to move methods out of a controller regularly. A good example that the Laravel framework uses is the ThrottlesLogin trait. Take a look at https://github.com/laravel/framework/blob/5.5/src/Illuminate/Foundation/Auth/ThrottlesLogins.php#L20
to see how the methods are moved outside of a controller but can be still accessed by importing the trait using the use keyword.
While traits would work for your use case I wouldn't use them here for the functionality you are looking for. I would use the repository pattern. It would better separate your code and make it more reusable.
Take a look at https://bosnadev.com/2015/03/07/using-repository-pattern-in-laravel-5/ for more information on the repository pattern. Basically, you would separate your code into a separate repository and use Laravel's built in IoC to inject the repository into your controller.
MyController
class MyController extends Controller
{
protected $repo;
public function __construct(MyRepository $myRepository)
{
$this->repo = $myRepository;
}
public function index()
{
$myStuff = $this->repo->all();
}
// you can also inject the repository directly in the controller
// actions.
// look at https://laravel.com/docs/5.5/controllers#dependency-injection-and-controllers
public function other(MyRepository $repo)
{
$myStuff = $repo->all();
}
}
This is the perfect use case for a Trait. Traits are intended for reusable functions. They're super simple to implement, and won't take more than a few minutes to change what you have.
Here is a great article on them: https://www.conetix.com.au/blog/simple-guide-using-traits-laravel-5

What does the make() method do in Laravel?

In the Laravel documentation, I found the following - https://laravel.com/docs/5.4/container#the-make-method
but I am still confused as to what exactly the make() method does. I know the create() method uses the make() method and then persists them into the database, so does make() methods just temporarily save it in php tinker or something? Sorry, I'm Laravel noob. I'm trying to figure out these functions. Thank you! :)
The make method will return an instance of the class or interface you request.
Where you request to make an interface, Laravel will lookup a binding for that interface to a concrete class.
E.g.
$app->make('App\Services\MyService'); // new \App\Services\MyService.
One advantage to using the make method, is that Laravel will automatically inject any dependencies the class may define in it's constructor.
E.g. an instance of the Mailer class would be automatically injected here.
namespace App\Services;
use \Illuminate\Mail\Mailer;
class MyService
{
public function __construct(Mailer $mailer) {
$this->mailer = new Mailer;
}
}
I discovered recently that when you use make (), you are installing the class and you can access the methods of that class or model, this is a useful for the Test and validate that you are getting what you want Example:
User model
class User extends Authenticatable
{
public function getRouteKeyName ()
     {
         return 'name';
     }
}
Test user
class UserTest extends TestCase
{
public function route_key_name_is_set_to_name ()
     {
$ user = factory (User :: class) -> make ();
$ this-> assertEquals ('name', $ user-> getRouteKeyName ());
// When you access the getRouteKeyName method you get the return, that is 'name'
}
}
On the other hand if you use "create" that would give an error because you are creating a user

IoC binding to a resourceful controller method, not constructor

Is it possible to bind an instance into a method parameter of a resourceful controller in laravel 4?
Is this even a good idea? If I have an object that I need for just one method, is it worth it to include it as a constructor parameter?
app/routes.php
Route::Resource('track', 'TrackController');
app/controller/TrackController.php
class TrackController extends BaseController {
public function __construct(/Foo/Bar p1, /Foo/Baz p2)
{
// All these bindings seem to work
}
public function show($id, /Foo/Xyz $xyz)
{
// This binding doesn't work, even though the exact same binding
// in the constructor will work.
}
}
Automatic Resolution works only for constructors:
When a type is not bound in the container, it will use PHP's Reflection facilities to inspect the class and read the constructor's type-hints. Using this information, the container can automatically build an instance of the class.
The best you could do in this case might be:
class TrackController extends BaseController {
public function __construct(/Foo/Bar p1, /Foo/Baz p2, /Foo/Xyz $xyz)
{
$this->xyz = $xyz;
}
public function show($id)
{
echo $this->xyz->property;
}
}

Resources