Class methods and instance methods in codeigniter, how can I use them? - php

I am very new to codeigniter but understand OOP and MVC as I do a lot of Rails development. One thing I haven't figured out yet is how to write a class level method in codeigniter and access it in a controller. For example, I have
<?php
class User_model extends Model {
function user_model()
{
parent::Model();
}
public static function get_total_users_count(){
$results = $this->db->query("SELECT * FROM bhr_users GROUP BY userid");
if($results){
return $results->num_rows();
}
return 0;
}
}
?>
I think what I have done here is established a class level method for my model that I should be able to call with User_model::get_total_users_count() Now in my controller which a previous programmer called "Welcome" I have something like:
<?php
class Welcome extends Controller {
function Welcome()
{
parent::Controller();
$this->load->model('bhr_model');
$this->load->model('user_model');
}
function index()
{
$invite = $this->uri->segment(3);
if($invite == 'invitefriends') {
$pagedata['invitefriends'] = $invite;
} else {
$pagedata['invitefriends'] = '';
}
$pagedata['numberofpeople'] = User_model::get_total_users_count();
$this->load->view('default_page', $pagedata);
}
}
The above method call to get_total_users_count does not work because it says because I am using the db method on a class level function in get_total_users_count. In other words $this has no db method when I reference a class.
So now my question is a bit more theoretical. I always thought that instance methods should only be used when a method is acting on a specific instance of an class. Makes sense, right? However, get_total_users_count is acting on all "users" and counting them. It just seems like that should be a class level method. Do you agree? If do, do you know how I can access the database from withing the framework inside a class level function?
Thanks!

Since you are not instantiating User_model, you must get the CI instance, then use that for your db queries.
Inside get_total_users_count():
$ci_ins =& get_instance();
$ci_ins->db->query();

You can make your class as a helper so it will not be load as a instance. Only the code will be included so you can just call it as:
$sample = class_name::method();

CodeIgnighter works is by instantiating your models as you load them. What Thorpe Obazee said is the correct codeIgnighter way to use your Model.
What you are asking is if you can use a static method as you'd expect in most circumstances, which just isn't how CI works.
To accomplish what you're after, mives points out get_instance() which is the correct way to get at the main CI object. I use that way myself to do what you're doing.

get_total_user_count is more of a function for a user table gateway.
User model should have things like getUsername and getLastLogin.
User Table Gateway should have things like findUserById, createNewUser, and getTotalUserCount

$pagedata['numberofpeople'] = $this->user_model->get_total_users_count();
That's the CI way.

Related

PHP OOP class structuring

I am wondering if such this subclassing structure is possible in PHP. If this is a duplicate I apologize as I couldn't figure out what this process would be called and the only I could find was a closed question with no answer.
I am working with multiple classes. For example we will say Main and User.
The Main class will hold all of the initiation code. So
class Main{
//Setters for core variables and data needed to make calls
...
protected function fetchInfo(){
//Do Stuff to return info from other source(Curl calls in my case)
}
}
and User
class User extends Main{
public function getName(){
$data = $this->fetchInfo();
return $data['name'];
}
}
But instead of having it where I would. Do $exampe1 = new Main(...); to set varaibles, and $example2 = new User(); to call the subclass to do $example2->getName(); is there a way to do something like $example = new Main(); whcih could then call the subclasses when needed like $example->User->getName();?
I know there are a lot of different ways this could be handled, but I want the classes separate for organization and I plan on having a lot of subclasses that need to pull info from that main class and would like to know if there is a way they can be linked in that fashion.
EDIT: The reason I dont want to just call User calls to get the function is I'll end up having 15+ classes that handle the returned data differently and making wonder if there was a better way than making a new Object for each one if I want to use it.
A "Main" is not a "User" so I would say this type of subclassing is a poor choice.
I might instead look at injection.
class MainDataHandler {
//...
}
class User {
private $main;
public function __construct(MainDataHandler $main) {
$this->main = $main;
}
public function getName() {
return $this->main->getData('name');
}
}
The benefits of injection is that your classes can work and be tested independently without dependencies on another class to do the work. Also if "Main" ever changes you your User class isn't dependent on how the new Main works.

Init another class in construct method?

I am looking into trying to simplify my PHP code some more, and I have yet to find an answer with this methodology one of my team members are using. Nor, have I ever saw this done before anywhere on the web.
Here is the code example from our web application which he is working on with me.
<?php
class ArticlesHandler {
public function __construct() {
require 'Articles.php';
$articles = new Articles;
}
}
?>
Is this proper to init one class within another class?
For me, this just seems not proper standard to init classes to work together.
Yes and no. It works, but this particular code can lead to a number of problems.
You should be using require_once instead of require to avoid possible errors of including the same file twice. As it is this code here will bring your app to a complete stop:
new ArticlesHandler;
new ArticlesHandler;
This creates a hard coupling to the Articles class. You should probably rather be using dependency injection and pass an instance of Article to the constructor of ArticlesHandler. See How Not To Kill Your Testability Using Statics.
Yes, it is proper and normal to call constructors in a constructor. There is nothing weird/bad about it.
This is what I normally do.
class Repository {
protected $_models = array();
public function getModel($model, array $params = array()){
require_once $model.'.php'; //Replace this with an autoloader
if(empty($this->_models[$model])){
if(!empty($params)){
$this->_models[$model] = new $model($params);
} else {
$this->_models[$model] = new $model();
}
}
return $this->_models[$model];
}
}
And call the other class like this.
class ArticlesHandler extends Repository {
public function __construct() {
$articles = $this->getModel('Articles');
}
}
it seem's right.
For me, this just seems not proper standard to init classes to work together.
you can extend Articles class if you want to use Articles class inside the ArticlesHandler

How to store query results as member variables from within a class using a mysqli function?

At the moment I use mysqli_fetch_object('ModelClass') to instantiate my class with all the query results... but... I'd like to keep all my "business" logic inside the model_class.
I tried...
class ModelClass
{
function __construct($model_id)
{
if($model_id)
{
//query code goes here...
return $mysqli_result->mysqli_fetch_object('ModelClass',$model_id);
}
}
}
$model = new ModelClass();
That method seems a bit wonky. Essentially I'm instantiating the class twice there.
I could also return the results as an array then cycle through storing each member variable...
Is there a different / better way to go about storing query results within a class into member variables?
php mysqli_fetch_object
You could store the result as a different class in a single member variable:
class ModelClass {
public $result;
function __construct($model_id)
{
if($model_id)
{
//query code goes here...
$result = $mysqli_result->mysqli_fetch_object('ModelClassResult',$model_id);
}
}
}
Then you can do:
$model = new ModelClass();
// Now access $model->result-><fieldname>
I guess I don't follow why you would want to include your instantiation logic within the object you are trying to instantiate. In essence, what you are trying to implement is a factory pattern. I would think you would be better off building a class to serve as the factory to instantiate such objects. The instantiation logic (i.e. MySQL interactions) could take place in that factory. Usage might look something like this:
$model_object = mysql_factory::instantiate('ModelClass', $model_id);
You could then use this factory to instantiate any sort of class (even classes other than ModelClass) if you like using the same exact methods. There is no reason to put SQL interaction into every class you might want to instantiate in this manner.

Can a site user pass their own arguments to model functions?

Are functions inside of models directly accessible by users?
Can a user pass arguments directly to a function in a model? Or, do arguments have to be passed through php?
In otherwords:
I have a model called notifications and in there a function called get_notifs($user)... I use the controller to call the function like the get_notifs($_SESSION['user_id']) (which is encrypted). I don't want someone to be able to call get_notifs() with anything but their $_session as a argument. What is the best solution?
Am I already okay?
Should I rename get_notifs() to
_get_notifs()?
Should I check the
$_SESSION['user_id'] in the method
itself?
Or, is there another better solution
than any of these?
I have a controller: ajax.php which loads the model notification
function __construct()
{
parent::__construct();
$this->load->helper('url');
$this->load->library('tank_auth');
$this->load->model('notification');
$this->load->model('search');
}
function get_notifs()
{
$me = $this->session->userdata('user_id');
if ($e = $this->notification->get_notif($me))
{
...........
}
else{
echo "nothing was found wtf?";
}
.........................................................
model: notification.php
function get_notifs($user){
......
}
Your code is perfectly fine!
Am I already okay?
I Think so
Should I rename get_notifs() to _get_notifs()?
No, it's a public method so no need to make it look private.
Should I check the $_SESSION['user_id'] in the method itself?
No, this is the controller's job
Or, is there another better solution than any of these?
You only need a solution to a problem, and i don't see a problem here
it sounds liek your application may be used by people other then yourself, i.e the public developers, why would you want enforce developers to code things your way, that's going to make them upset at your application.
CI Only routes requests to a controller, the user cannot access a model or library or any other class, the route goes like so: /controller/method/param
the first segment will only ever load a controller file, the second will call the method in the param, passing any other variables such as param to that method.
Source: http://codeigniter.com/user_guide/overview/appflow.html
As you can see from the flow chart above, only the controller has access to the model's
If you'll only use it while in a session the best way would be this:
function get_notifs(){
if(!isset($_SESSION['user_id'])){
return false;
}
$user = $_SESSION['user_id'];
/* Your code here */
}
There's no point of requiring an argument when you'll only use the function with one specific variable which is also available globaly.
Edit: I don't know why you're using functions in your models. Doesn't make any sense, do you mean methods?

Should this function be instance level or class level? ...and how to make it work in codeigniter

In my codeigniter project I have
<?php
class User_model extends Model {
function user_model()
{
parent::Model();
}
// should we use instance method?
function get_total_users_count(){
$results = $this->db->query("SELECT * FROM bhr_users GROUP BY userid");
if($results){
return $results->num_rows();
}
return 0;
}
// or class method?
public static function get_total_users_count(){
$obj =& get_instance();
$results = $obj->db->query("SELECT * FROM bhr_users GROUP BY userid");
if($results){
return $results->num_rows();
}
return 0;
}
}
?>
I feel like this should be a class level method because it operates on multiple users. Do you agree? Is get_instance the proper way to do this in codeigniter?
Honestly, I don't think there's one right way for this. I'd say the instance method is the most common way, but that's not to say that it's right or wrong.
One big difference between CodeIgniter and some other frameworks is that models can be whatever you want them to be. According to the CI manual "The Model represents your data structures." it than says that models will "typically" interact with your database.
I like the loose definition that CodeIgniter uses for models, because it allows me to create models for dealing with any dataset. Want to use an RSS feed as a data source? You could use a model for that. Want to pull data from a webservice? You could use a model for that. You have the freedom to define how you use models.
I'd say the most important thing is consistency. Choose one method and use it consistently throughout your project. If you're working with other developers on the project, it may be better to use the instance methods. That way they won't get confused about what's going on when they compare working code on your site to the CodeIgniter documentation. That, of course, depends on the skill level of the devs you work with.
To answer your question directly - the get_instance() function call is the proper way to do what you're trying to do from within a static function.
You should be using
$results = $this->db->query("SELECT * FROM bhr_users GROUP BY userid");
Unless you are getting an instance of another class, you should do it this way.

Categories