Why is PHP not finding my model class in CodeIgniter? - php

I keep seeing this error -
This is the offending function -
private function getInfo(){
$this->Features = new UserFeatures_Model($this->ID); //<-- Offending line of Code
/*Other Stuff - Not Relevant*/
}
This is from where it's being called -
public function __construct($UserID = NULL){
parent::__construct( TRUE );
$this->database = $this->load->database('users', TRUE);
$this->table = 'users';
$this->idKey = 'User_ID';
//Assigned UserID should have precedence.
if (!is_null($UserID)) { $this->ID = $UserID; }
//If there exists a UserID within this session, automatically load it.
elseif ($this->session->UserID){ $this->ID = $this->session->UserID; }
if (isset($this->ID)){ $this->getInfo(); }
}
My first guess as to why this is throwing a fit is because I'm calling the getInfo() method in the constructor... but I'm pretty sure that's not the issue.
Anyway, here is the class definition that it is saying does not exist -
class UserFeatures_Model extends MY_Model {
/*Irrelevant stuff since it's not 'seeing' this class anyway...*/
}
And here is the directory structure -
It's there unless I'm hallucinating (a distinct possibility, I am quite tired...)
Why is(are) CI/PHP not finding this class?

You must use $this->load->model('UserFeatures_Model'); inside your getInfo() controller before you call that model function.
private function getInfo($id){
$this->load->model('UserFeatures_Model');
$this->Features = $this->UserFeatures_Model->some_function_inside_model($id);
}

Related

Switching Classes during __construct()

Let's take the following classes for a moment:
class member {
public $id;
public function __construct($id) {
$this->id = $id;
// Check user level
if ($this->check_user_level() == moderator) {
$this = new moderator($this->id);
}
}
private function check_user_level() {
// Return user level from system based on user ID
}
}
class moderator extends member {
public function show_moderator_tools() {
// etc.
}
}
==================
$user = new member($user_id);
The desired behavior is to have $user detect whether the user is authorized to have moderator access, and if so recast the user using the moderator class instead of member.
PHP forbids simply reassigning $this, so what appears to be the best solution would be one of the following:
Run check_user_level($id) as a regular function and using an if statement
$user_level = check_user_level($id);
if ($user_level == "moderator") {
$user = new moderator($id);
} else {
$user = new member($id);
}
Set a flag in the base class that can be used for a check/redefinition after initializing $user
$user = new member($id);
if ($user->flag = TRUE) {
$user = new moderator($id);
}
The latter feels like it's introducing a security flaw, especially since the flag (which could just as easily be $user->user_level, or similar, I guess) would have to be public to be able to check it afterward.
What I would like to do would be to just make one call to new member($id) and have it handle things automatically from there, without the need for if statements after the fact. Is there a way to do this?
You can of do this by introducing another class (lets call it user) and using the __call magic method in php and call_user_func_array for calling the methods.
The logic is something like this -
Create a user class that has no method except check_user_level. It checks proper details and assigns it's $obj to the instance of either member or moderator class.
Here is how the classes would look like (I've changed the functions to print something out)-
class user{
public function __construct($id) {
$this->id = $id;
if ($this->check_user_level() == "moderator") {
$this->obj = new moderator($this->id);
}else{
$this->obj = new member($this->id);
}
}
public function __call($method, $args){
call_user_func_array(array($this->obj,$method), $args);
}
public function __get($prop){
if(isset($this->obj->$prop)){
return $this->obj->$prop;
}
return NULL;
}
private function check_user_level() {
// Return user level from system based on user ID
if($this->id == 1){
return "moderator";
}
return "member";
}
}
class member {
public $id;
public function __construct($id) {
$this->id = $id;
}
public function show_message($arg){
var_dump($this->id.$arg);
}
}
class moderator extends member{
public function show_moderator_tools() {
var_dump($this->id ."My toolset!");
}
}
So, now you can simply call the user class and that will automatically decide if it's a member or a moderator and call the method if it exists.
//Trying out a few examples
//Creating a member user
$mem_obj = new user(213);
$mem_obj->show_message("New message");
//Creating a moderator user
$mod_obj = new user(1);
$mod_obj->show_moderator_tools();
/*
OUTPUTS
-------
string(14) "213New message"
string(12) "1My toolset!"
*/
But you need to be careful with these kind of hacks.
For instance -
//This will fail
//because mem_obj doesn't have show_moderator_tools()
$mem_obj->show_moderator_tools();
EDIT
You can similarly go ahead with redirecting to properties using __get.
I have modified the code above to add this method beneath __call.
//Testing it
var_dump($mem_obj->id);
//This is an illegal property
var_dump($mem_obj->illegelProperty);
/*
OUTPUTS
int(213)
NULL
*/

Attempt to assign property of non-object error

I am getting this error and i can't see what i am doing wrong. I have done the same thing with other objects from other classes which are built in the exact same way and i can't see why i am getting this error now.
The code in which i create the object is this one:
$consulta2 = "SELECT * FROM TiposDireccion WHERE Cliente_CIF='$cif' and Direccion_Direccion='$direccion' and Direccion_CP=$cp ";
echo($consulta2."</br>");
if ($resultado2 = $conexion->query($consulta2)){
while($fila2 = $resultado2->fetch_object()){
$tipodireccion78=$fila2->TipoDireccion_Tipo;
//we see here that the select is returning a correct string with a correct value
echo($tipodireccion78);
//we try to instantiate and it fails =(
$unTipoDireccion=TipoDireccion::constructor1($tipodireccion78);
This is the class TipoDireccion:
<?php
class TipoDireccion{
private $tipo;
private $descripcion;
//Construct auxiliar
function __construct() {
}
//Constructor 1 : completo
function constructor1($tipo) {
$tipoDireccion = new TipoDireccion();
$tipoDireccion->tipo = $tipo;
return $tipoDireccion;
}
function ponTipo($tipo) {
$this->tipo = $tipo;
}
function devuelveTipo() {
return $this->tipo;
}
function ponDescripcion($descripcion) {
$this->descripcion = $descripcion;
}
function devuelveDescripcion() {
return $this->descripcion;
}
}
?>
Thank you a lot in advance!
Don't know if this is still relevant to you, but in case anyone else comes on here for an answer. The problem is in this function:
function constructor1($tipo) {
$tipoDireccion = new TipoDireccion();
$tipoDireccion->tipo = $tipo;
return $tipoDireccion;
}
Because in the class definition, you define private $tipo; and then you try and assign $tipoDireccion->tipo to what was passed through the function. However, you aren't trying to access that variable through the scope of the class, you are trying to assign it from the 'public' scope as far as the class is concerned.
The fix for this has two options, the first one would be to change private $tipo; to public $tipo;. But that isn't a good solution as you have an assignment function for it.
Instead, use your functions that you made, which would make the function look like:
function constructor1($tipo) {
$tipoDireccion = new TipoDireccion();
$tipoDireccion->ponTipo($tipo);
return $tipoDireccion;
}
That's how you need to access it from the public scope, which you are doing after you initiate a new one.
function constructor1($tipo) {}
should be
static function constructor1($tipo) {}

php oop constructor

OK. here is what I'm trying to do:
class Image{
public $_image;
public $_extension;
public $_mime;
public $_size;
public $_location;
public $_description;
public function __construct($image, $location){
$this->_image = $image;
$this->_location = $location;
$this->_extension = getExtension();
$this->_mime = getMime();
$this->_size = getSize();
}
private functions fallow.....
}
But I keep getting an internal server error when I try to run it. When I comment out the method calls it works. So the question is can I call methods from inside the constructor or am I doing something wrong with the methods.
Do your functions getExtension, getMime and getSize exist? Are they methods on this class? If they are methods, they need to be called with $this->... as in
$this->_extension = $this->getExtension();
If they are not methods, and are functions, you need to make sure the files that contain/define them are loaded before you run the constructor.
Well ..this fragment of code will work as expected:
class Foo
{
protected $secret = null;
public function __construct( $data )
{
$this->secret = $this->makeSecret($data);
}
public function makeSecret( $data )
{
return md5( $data );
}
}
$bar = new Foo( 'lorem ipsum' );
That is not a problem.
But you should know, that is considered to be a bad practice - to do computation/work in the constructor. It makes that class practically untestable. Instead, if you need to perform some computation before "releasing" the object to the rest of the code, you should use a factory. Something along the lines of :
class ImageFactory
{
public function build($image, $location)
{
$instance = new Image($image, $location);
$instance->prepare();
return $instance;
}
}
The class would need some changes:
class Image
{
protected $_image; // you were leaking abstraction
protected $_extension;
protected $_mime;
protected $_size;
protected $_location;
protected $_description;
public function __construct($image, $location)
{
$this->_image = $image;
$this->_location = $location;
}
public function prepare()
{
$this->_extension = $this->getExtension();
$this->_mime = $this->getMime();
$this->_size = $this->getSize();
}
private functions fallow.....
}
Now when you need to create new object you do:
$factory = new ImageFactory;
$image = $factory->build( $file, '/uploads/' );
Of course the instance of ImageFactory can be reusable, and if all your images use the same $location, then you would pass that variable to factory at the initialization. And the factory would be able to "remember it" and pass to all the images it creates:
$factory = new ImageFactory('/uploads/');
$img1 = $factory->build( $file );
$img2 = $factory->build( $something_else );
This is actually how one should deal with creating multiple objects, which all need access to same DB connection instance.
Yes, you can call methods from within the constructor. Remember that the __construct() magic method was implemented in PHP 5. Prior to that, you created a function named the same as your class which acted as your constructor so depending on your PHP version, that could be a problem.
Additionally, the function calls you are making, are they in the class or external? If they are inside the class you need to call them this way:
$this->_extension = $this->getExtension();
You didnt specified what error you are expiriencing clearly. But try calling you class methods even inside the class using this keyword, otherwise it would not work:
public function __construct($image, $location)
{
$this->_image = $image;
$this->_location = $location;
$this->_extension = $this->getExtension();
$this->_mime = $this->getMime();
$this->_size = $this->getSize();
}
Would be a better idea to post your code for the methods you wrote. There could be something wrong within them as well. Possibly forgetting to return a result or something...

Zend_Db_Table_Row_Abstract Extended Row Class Not Functioning

I'm using the Zend_Db framework, and I've run into a snag. I'm trying to add custom handling to the column naming at the row level, but it's failing to invoke my function for some reason.
I've stripped down the problem to simply try and figure out if the underlying "Row" class is ever even created. From what I can tell, it isn't.
Here's what I've got:
// this class functions correctly; I get "table" written to my output
class DHR_Table extends Zend_Db_Table_Abstract
{
protected $_rowClass = 'DHR_Row';
function __construct(){
echo "table";
parent::__construct();
}
}
// this class never gets called, at least not that is evident from the constructor echo
class DHR_Row extends Zend_Db_Table_Row_Abstract
{
protected $inflector = null;
function __construct(){
echo "row";
parent::__construct();
}
}
// this is the actual implementation class that uses these two:
class Application_Model_DbTable_Applicants extends DHR_Table
{
protected $_name = 'applicants';
}
My output includes some data (excluded from this post, but part of the "Applicants" class) and "table", but no "row". Any ideas why this might be happening? Version 1.11.11 of the Zend framework.
[Edit]
Here's the usage:
class ApplicantsController extends DHR_RestController
{
public function indexAction()
{
$applicants = new Application_Model_DbTable_Applicants();
$result = $applicants->fetchAll();
$this->success($result);
}
protected function success($data, $code = 200)
{
if(is_a($data, 'Zend_Db_Table_Rowset')){
// we could do some pagination work here
$data = $data->toArray();
}
$this->setResponseCode($code)->appendBody(Zend_Json::encode(array(
'success'=>true,
'data' => $data
)));
}
}
I would expect to at least have some method on the row class invoked when returning the serialized results...
[Update]
If I use "fetchRow" everything works as expected; fetchAll simply does't do the conversion to the underlying object type.
I was just looking at the code for the row/abstract class.
Try setting a value for $_tableClass. $_tableClass = 'DHR_Table';
I'm afraid that won't work as it looks like Zend/Db/Table/Row/Abstract.php is going to look for a table definition no matter what, so the level of abstraction you seem to be after may not be possible without further extending.
//excerpt from __construct Zend/Db/Table/Row/Abstract.php
public function __construct(array $config = array())
{
if (isset($config['table']) && $config['table'] instanceof Zend_Db_Table_Abstract) {
$this->_table = $config['table'];
$this->_tableClass = get_class($this->_table);
} elseif ($this->_tableClass !== null) {
$this->_table = $this->_getTableFromString($this->_tableClass);
}
// cont...
// Retrieve primary keys from table schema
if (($table = $this->_getTable())) {
$info = $table->info();
$this->_primary = (array) $info['primary'];
}
$this->init();

PHP Design Patterns: Are private constructors bad for classes that you will let others to extend?

I have an abstract class called ContentAbstract which looks something like this
abstract class ContentAbstract
{
protected static $type;
protected $id;
protected $title;
protected $description;
protected $page;
protected $section;
...
function __construct($id = NULL, Page $page = NULL, Section $section = NULL)
{
if($id != NULL)
{
$data = get_data_from_content_table_by_id($id);
if($data['type'] == static::$type)
{
initialize_fields_with_data($data);
$this->page = fetch_page_object_from_registry($data['page_id']);
$this->section = fetch_section_object_from_registry($data['section_id']);
}
else
throw new IncompatibleContentTypeException('Foo');
}
else if($page != NULL && $section != NULL)
{
$this->page = $page;
$this->section = $section;
}
else
throw new OphanContentException('Foo');
}
}
Then the Page Class is also a subclass of ContentAbstract
class Page extends ContentAbstract
{
protected static $type = 'Page';
private $template_file;
private $short_name;
static function newFromName($name)
{
$data = get_content_id_from_page_table_using_the_short_name($name);
$page = new Page($data['id']);
$page->template_file = $data['template_file'];
...
}
static function newFromID($id)
{
$data = get_content_id_from_page_table_using_the_ID($id);
$page = new Page($data['id']);
$page->template_file = $data['template_file'];
...
}
}
Now my problem lies in the fact that the Page constructor is public and users can do this:
$page = new Page($valid_page_id);
and end up calling ContentAbstract::__construct() but not being able to initialize the data for the page itself (template_file, and short_name) since it was called outside of Page::newFromName() and Page::newFromID(). So I end up with a half-cooked content data. One solution would be to override the parent constructor with something similar to Page::newFromID() making sure that we would be able to set all fields when the Page is instantiated (of course by still calling the parent constructor within Page::__construct()).
Now the problem lies in the Page::newFromName() method since such an approach will require me to make 2 queries, one is to get the content id of the page using the short_name column, and then when the constructor of the page is called within Page::newFromName(), it will then create a new query to get the data associated with the page. That's not desirable isn't it?
So the only solution I see is to make Page::__construct() private and force end users to use the static methods to instantiate the object.
My question is, this is something I'd like to release as an open source project and it allows users to add more types of contents by simply subclassing the ContentAbstract class. Is requiring a private constructor detrimental to the said objective (accounting for human error and the laziness to read through documentation)? Or should such matters be the least of my concerns? Or are the structures of the actual classes themselves lend to this problem?
"Now my problem lies in the fact that the Page constructor is public and users can do this:
$page = new Page($valid_page_id);"
According to the code you posted in the OP this shouldn't be the case. Your page extends ContentAbstract where the construct resides, but you aren't actually calling construct from the Page class. You would have to force a call to the parent from the child:
class Page extends Content // I wouldn't name this abstract as it may change in the future
{
public function __construct($args)
{
// Here I forced a call to parent
// If I comment this out, the parent construct will never be accessed
parent::__construct($args);
}
}

Categories