model inheritance error in codeigniter - codeigniter-2

I am trying the following code but keep getting the this error:
PHP Fatal error: Call to undefined method
news_model::get_db_message()
in my application/core/My_Model.php
class MY_Model extends CI_Model {
public function __construct() {
parent::__construct();
}
public function get_db_meesage() {
echo "bla";
}
}
this is my news_model.php
class news_model extends MY_Model {
public function __construct()
{
parent::__construct();
}
public function delete_news($news_id) {
$this->get_db_message();
}
}
I felt it is probably a very subtle error but I just can't figure this out..

Correct answer taken from comments.
Codeigniter expects classes to start with a capital letter. This is stated in their General Style and Syntax document.
To quote:
Class and Method Naming
Class names should always start with an
uppercase letter. Multiple words should be separated with an
underscore, and not CamelCased. All other class methods should be
entirely lowercased and named to clearly indicate their function,
preferably including a verb. Try to avoid overly long and verbose
names.
INCORRECT: class superclass , class SuperClass
CORRECT: class Super_class

public function get_db_meesage() {
echo "bla";
}
PHP Fatal error: Call to undefined method news_model::get_db_message()
get_db_message()
get_db_meesage()

Related

Laravel: When call function from another controller, the relationship query not work

I have two controllers (FirstController, SecondController) that use the same functions, to avoid rewriting them I thought of creating another controller (ThirdController) and subsequently calling the functions through it.
the problem is that if in ThirdController there are relationship query they give me the error that "they don't exist".
example:
User Model
class User extends Authenticatable implements AuthenticatableUserContract
{
use HasFactory, Notifiable;
public function comments(){
return $this->hasMany('App\Models\Comment');
}
ThirdController
class ThirdController extends Controller
{
public static function example($id){
$comments = Comment::find($id)->comments();
return $comments;
}
}
FirstController/SecondController
public function example2(Request $request){
return ThirdController::example($request->id);
When call the route it give me error:
BadMethodCallException: Method Illuminate\Database\Eloquent\Collection::comments does not exist.
my questions are:
Is there any better method instead of creating a third controller?
Is there a solution to this?
p.s. I know I could very well build the queries without exploiting the relationship, but where's the beauty of that? :D
You do not need to create 3rd controller. You can create a class and here you write the query in a function and use this class in controller1 and controller2 by dependency injection.
First thing that's not a best practice to define a static method in one controller and call it in another controller (not recommended way).
Second you're calling Comment::find($id) with comments() relation. you should call a User class, like below snippet:
class ThirdController extends Controller
{
public static function example($id){
$comments = User::find($id)->comments();
return $comments;
}
}
RECOMEND APPROACH:
Creat a one seperate service/repository class in which you'll define a common method i.e. getUserComments() and use it in both or all of three controllers (upto your requirement/needs). By this way you implementations will be on a centric place.
If you want learn about Repository pattern you can get basic idea from: Article#1

Extending CodeIgniter core classes

I have in my core folder, 2 controllers:
MY_Controller
MY_AdminController
Both extend CI_Controller. First one works great, but second one no, when I call the controller which is inheriting from MY_AdminController I get an error:
Fatal error: Class 'MY_AdminController' not found
After doing some research I found:
https://codeigniter.com/user_guide/general/core_classes.html
In this document it says you use "MY_" prefix (possible to change it in config) to extend core classes, I am doing that.
What am I missing?
UPDATE
I am wondering if the problem is because since I am creating a file inside "core" folder, CI checks if it does exist an original on its own core with same name but prefix CI?
to allow any new class . means which class are note defined in system/core
solution could be as follow.
Try putting below function at the bottom of config file
/application/config/config.php
function __autoload($class) {
if(strpos($class, 'CI_') !== 0)
{
#include_once( APPPATH . 'core/'. $class . '.php' );
} }
My core class My_head not found in codeigniter
Here is a good explanation as to why you can't do it the way you have described. Essentially CodeIgniter looks for ['subclass_prefix'] . $Classname, e.g. 'MY_' . 'Controller'. And here is the same question for CI2
Solution:
Put both MY_Controller and MY_AdminController in MY_Controller.php
MY_Controller.php
class MY_Controller extends CI_Controller {
public function __construct() {
parent::__construct();
}
...
}
class MY_AdminController extends CI_Controller {
public function __construct() {
parent::__construct();
}
...
}

How to extend Code igniter cache class Redis class

I am using redis for caching in one of my assignment. I am using CI default redis library for this purpose.
Now the issue with library is that it has some specific set of method which are used to set, get, delete , increment and decrement the redis keys & values.
I want to additional function of redis like lpush, rpush,lrem, lrange etc.
So to achieve this , i am trying to extend default CI redis class. which i am putting in application/libraries/driver/cache_redis_extended.php.
my code for this class is as follow.
<?php defined('BASEPATH') OR exit('No direct script access allowed');
class Cache_redis_extended extends CI_Cache_redis
{
function __construct()
{
parent::self;
}
public function rpush($list, $data)
{
$push = $this->_redis->multi(Redis::PIPELINE);
return $push->rpush($list, json_encode($data));
}
public function lrem($list, $data)
{
if((is_string($data) && (is_object(json_decode($data)) || is_array(json_decode($data))))) {
$data = $data;
}else{
json_encode($data);
}
return $this->_redis->lrem($list,-1, $data);
}
public function __destruct()
{
if ($this->_redis)
{
$this->_redis->close();
}
}
}
and in my model I am loading this class as follows
$CI->load->driver('cache', array('adapter' => 'redis'));
But I get this error:
Unable to load the requested class: cache_redis_extended
Any help is appreciated for this issue.
As I can see your driver name is not started with Capitalized , so
it can be possible the cause of your issue.
Because according to codeigniter the naming rule of a class as follows
Naming Conventions
File names must be capitalized. For example: Myclass.php
Class declarations must be capitalized. For example: class Myclass
Class names and file names must match.
change your file name
from cache_redis_extended.php
to Cache_redis_extended.php
I hope it will be helpful for you.

How can I avoid to repeat myself in Laravel (4) Controllers?

I feel I repeat myself in Laravel (4) controllers. For example, I need some $variables for every view. I get them from cache or database. Because geting and processing them take some lines of codes (between 5-100 lines), I repeat them in every controller function. This is especially a problem when updating functions (They increase complexity).
How can I avoid this without any negative effect?
Note: $variables are mostly not global variables.
There are many ways to go about this, but it sounds like the variables are more specific to your View's than your controllers.
You can easily share variables across your views in the boot method of your AppServiceProvider.
view()->share('variables', function(){
//you can share whatever you want here and it will be availble in all views.
});
You can create a static helper class (all static functions)
e.g.
class VarHelper {
public static function getVars() {
return [];
}
}
You can create your own basecontroller you extend in every other controller
e.g.
class MyController extends Controller {
public function getVars() {
return [];
}
}
class BlaController extends MyController {
public function doBla() {
$vars = $this->getVars();
}
}
creating the function inside the controller and call it in the other functions
use a Trait
And probably more solutions
Create a trait with a method to set all of the necessary variables.
use View;
trait SharedControllerVariables {
public function loadUsersSubscription() {
View::make('user_subscription_variable_1', [...data...]);
View::make('user_subscription_variable_2', [...data...]);
}
}
Then call it in your controller constructor:
class MyController extends Controller {
use SharedControllerVariables;
public function __construct() {
$this->loadUsersSubscription();
}
}

Injection in Repository

I found many questions about my problem and tried (I think) all the solutions, but I can not make it work. I'm overlooking something very easy, probably.
I'm using Laravel 5. I try to implement a repository-pattern.
I have an Eloquent model '\Notos\Kind'.
Then I have this interface:
namespace Notos\Contracts;
interface Kind
{
public function findByName($name);
}
My Repository looks like this:
namespace Notos\Repository;
use Illuminate\Database\Eloquent\Model;
use Notos\Contracts\Kind as KindContract;
class Kind implements KindContract
{
protected $kind;
public function __construct(Model $kind)
{
$this->kind = $kind;
}
public function findByName($name)
{
return $this->kind->firstOrCreate(array('name' => $name));
}
}
My ServiceProvider:
namespace Notos\Providers;
use Illuminate\Support\ServiceProvider;
use Notos\Kind;
use Notos\Repository\Kind as KindRepository;
class RepoServiceProvider extends ServiceProvider
{
/**
* Register the service provider.
*
* #return void
*/
public function register()
{
$this->app->bind('Notos\Contracts\Kind', function ($app) {
return new KindRepository(new Kind);
});
}
}
And my controller that uses the repository:
namespace Notos\Http\Controllers;
use Notos\Repository\Kind as KindRepository;
class KindController extends Controller
{
protected $kind;
public function __construct(KindRepository $kind)
{
$this->kind = $kind;
}
public function find($name)
{
return $this->kind->findByName($name);
}
}
This provider is registered in config/app.php
When I try to execute the KindController#find I get this error:
BindingResolutionException in Container.php line 785:
Target [Illuminate\Database\Eloquent\Model] is not instantiable.
I can't find what I'm doing wrong.
It works perfect if I change __construct(Model $kind) to __construct(Kind $kind).
Any ideas?
Thanks
The first thing, I would advice you to add to your class names the function so for example instead of Kind for repository use KindRepository, the same for contract. Otherwise you will have 3 kinds classes (of course in different namespaces) but it will be hard to analyse the code.
The problem here is that in your KindController you try to inject KindRepository directly but in constructor you use Model. It won't work because Model is only abstract class. What you should do to make it work?
In the code:
$this->app->bind('Notos\Contracts\Kind', function ($app) {
return new KindRepository(new Kind);
});
you told Laravel that when you will use Notos\Contracts\Kind it should create KindRepository for you with Kind in constructor - look you told here about Contract, not about repository itself.
So to make it work, you should use in your controller not your repository, but your contract.
Instead of line:
use Notos\Repository\Kind as KindRepository;
you should write:
use Notos\Contracts\Kind as KindRepository;
and it should work now.

Resources