How can I construct array of instances of a kind of library (lets say Student) after loading it in CodeIgniter? As far as I know after loading student library using $this->load->library('student'); I can access single student using $this->student . Here is my question, I need an array of this students how can I do that.
You should really use a model instead of a library. Libraries are used to extend the functionality of CodeIgniter. Models let you interact with your data; Students in this case. Using a library to get your data and instantiating it is shooting yourself in the foot.
In your Student_model, you can put functions that grab your data (from a database or wherever):
function get_students() {
// Returns an array or object of all students and their info
}
function get($student_id) {
// Returns a single student's information
}
// Additional CRUD functions, if desired.
Additionally, I recommend having another look at:
http://ellislab.com/codeigniter/user-guide/overview/mvc.html
http://ellislab.com/codeigniter/user-guide/general/creating_libraries.html
inside your library file
function get_student_list()
{
// $uqery = SQL query to get the students - or a call to your model to get them
return $query;
}
then in your controller
$list = $this->student->get_student_list();
Related
I'm working on an application written in PHP. I decided to follow the MVC architecture.
However, as the code gets bigger and bigger, I realized that some code gets duplicated in some cases. Also, I'm still confused whether I should use static functions when quering the database or not.
Let's take an example on how I do it :
class User {
private id;
private name;
private age;
}
Now, inside this class I will write methods that operate on a single user instance (CRUD operations). On the other hand, I added general static functions to deal with multiple users like :
public static function getUsers()
The main problem that I'm facing is that I have to access fields through the results when I need to loop through users in my views. for example :
$users = User::getUsers();
// View
foreach($users as $user) {
echo $user['firstname'];
echo $user['lastname'];
}
I decided to do this because I didn't feel it's necessary to create a single user instance for all the users just to do some simple data processing like displaying their informations. But, what if I change the table fields names ? I have to go through all the code and change those fields, and this is what bothers me.
So my question is, how do you deal with database queries like that, and is it fine to use static functions when querying the database. And finally, where is it logical to store those "displaying" functions like the one I talked about ?
Your approach seems fine, howerver I would still use caching like memcached to cache values and then you can remove static.
public function getUsers() {
$users = $cacheObj->get('all_users');
if ($users === false) {
//use your query to grab users and set it to cache
$users = "FROM QUERY";
$cacheObj->set('all_users', $users);
}
return $users;
}
(M)odel (V)iew (C)ontroller is a great choice choice, but my advice is look at using a framework. The con is they can have a step learning curve, pro is it does a lot of heavy lifting. But if you want to proceed on your own fair play, it can be tough to do it yourself.
Location wise you have a choice because the model is not clearly define:
You'll hear the term "business logic" used, basically Model has everything baring views and the controllers. The controllers should be lean only moving data then returning it to the view.
You model houses DB interaction, data conversions, timezone changes, general day to day functions.
Moudle
/User
/Model
/DB or (Entities and Mapper)
/Utils
I use Zend and it uses table gateways for standard CRUD to avoid repetition.
Where you have the getUsers() method you just pass a array to it, and it becomes really reusable and you'd just have different arrays in various controller actions and it builds the queries for you from the array info.
Example:
$data = array ('id' => 26)
$userMapper->getUsers($data);
to get user 26
enter code here
$data = array ('active' => 1, 'name' => 'Darren')
$userMapper->getUsers($data);`
to get active users named Darren
I hope this help.
In my DB layer class I have a method that takes a select sql query as param:
public function select($sqlQuery) {
$stmt = $this->pdo->prepare($sqlQuery);
$stmt->execute();
$ret = $stmt->fetch(PDO::FETCH_ASSOC);
return $ret;
}
I want to be able to return the fetched data to my model, and then loop through it in my view class, without using any PDO in the view.
How should this be done the right way?
I want to be able to reach the table rows as $row['testCol'] etc.
Call fetchAll() instead of fetch(), which will return a full multidimensional array.
public function select($sqlQuery) {
$stmt = $this->pdo->prepare($sqlQuery);
$stmt->execute();
$ret = $stmt->fetchAll(PDO::FETCH_ASSOC);
return $ret;
}
$results = $your_object->select("SELECT * FROM yourtable");
// It's a 2D array!
var_dump($results);
Model is a layer. Not a class or object.
And, if you write your code by adhering to SRP, the model layer would contain several different types of structures. As minimum you would have separate classes for domain business logic and storage abstraction.
What you have here is complete mess. Not only you lumping both domain logic and storage mechanism in same class (and pretend that it is "model"), but you are also exposing SQL directly to presentation layer.
If you were trying to build a proper model layer, the current view would request information from service instance (which would be the type of structures, that one would use to separate domain business logic from views and controller) and acquire the data it need.
The service would instantiate the proper domain object(s) and, based on state, previously set by controller, retrieve information into them using some form of storage abstraction (either data mapper, repository, unit of work, dao or some similar structure). Then, after performing required data manipulations on the filled domain object(s), it would return data to the view.
View, based on received information and previous signals from controller, would decide what sort of response should be generated. If the indicated for of response is HTML, it would use one or (usually) multiple templates to compose the output. Thought it might as well send just a HTTP location header, to trigger a redirect.
For further reading I would recommend this answer.
The point is: you currently have simplified the concepts of MVC to the point where even separation between presentation and model layer has been broken.
You could easily return $stmt. It allows you to iterate over it and is accessible like PDO::FETCH_ASSOC:
$rows = $model->select($sqlQuery);
...
foreach($rows as $row)
{
echo $row['testCol'], "\n";
}
Inside your function it's like:
public function select($sqlQuery) {
$stmt = $this->pdo->prepare($sqlQuery);
$stmt->execute();
return $stmt;
}
Keep it simple, that will help you in the long run. You only want something in your view that is accessible like an array and PDO offers you that out of the box. You can easily replace it later with - let's say - an array if you need to. Maybe not the best example with the array, but I'm sure you get the idea.
And just a note in the margin: Don't call it model, just call it database or similar. It better names the thingy which is always helpful.
Is there a way to load a controller from a view ?
Here is what i am affter..
I want to use one view multiple times, but this view is being loaded by separate controller that gives the view, information from the db.So becouse of that information from the model i can't just set $this-load->view(); and etc. Is there a way to do this thing, or it has a better way ?
I think a lot of sites face similar challenges, including one I'm working on that loads the same db content into the sidebar on almost every page in the site. I implemented this with the combination of a library and a helper:
Put the data logic into the library (mine is named common.php). In addition to interfacing with the database, you may want the library to store the data in a local variable in case you want to reference it multiple times on a single load.public function get_total_items()
{
if ($this->_total_items === NULL)
{
$row = $this->ci->db->query("SELECT COUNT(*) FROM items")->row();
$this->_total_items = $row[0];
}
return $this->_total_items;
}
Create a helper to load the library. (Don't load libraries within a view!) I have MY_text_helper that loads the library and returns the data:function total_items()
{
$CI =& get_instance();
return $CI->common->get_total_items();
}
Call the helper function from within the view.<p> Total items: <?php echo total_items(); ?> </p>
Simply put, you can't and shouldn't load a controller from a view. That sad, I understand your frustration because you want to re-use the model-pulling/acting logic in the controller across multiples views.
There are various ways of doing this;
Re-use the models. Your models should be very simple to select data from, and should be sleek, but if you're doing the same thing over and over it does seem stupid. In which case...
Use a controller as a "main container" and extend upon it from any logic you need. So your basically using the controller as a template, which pulls data down from the model, loads the appropriate view.
MVC doesn't work that way ... Just re-use the model - that's why it's separate from the controller. If that doesn't fit your needs, you should probably implement a library that does the logic.
I would use a library.
That way you can wrap up the data retrieval in a reusable package that you can call from any controller you like.
just do this
if you controller named controller1
put a link in view just like that
http://your-site.com/index.php/controller1/
if you want specific function add it to your url
http://your-site.com/index.php/controller1/myfunction
that's it
For a project I used some logic in my view, this is not the way to go so I want to get it out.
The problem is that it can't be done from a class method of my model because Zend will make 10000 of queries from 10000 of instances to the database and it becomes very slow.
So I have to do it on a way that it loads all data at once, then processes it and returns the data back to the view. In my view it works the way I do it, the only problem is that it is IN the viewfiles.
What is the way to go? Just make a class in the model that inputs the values and returns required data?
Thanks
Here is the way i would go to display data from a MVC perspective
Controller
function someAction(){
$someTable = new Model_DbTable_SomeTable();
$allData = $someTable->fetchAll();
$arrayFormattedData = DataProcessor::process($allData);
$this->view->data = $arrayFormattedData;
}
You have to do your logic processing in a model (in the example above its done in the static class DataProcessor throught the process method (Not neccessarly the way to go, but it could be a good start)
View
echo $this->dataParser($this->data); // using a view helper to parse data to be displayed
or
echo $this->partialLoop('partialLoop.phtml', $this->data); // using the partial loop view helper built in in ZF
Finally, you should try to make your models as flexible as possible to make them reusable which is the key in oop development.
I have an element for my side bar navigation being called from my layouts/default.ctp file, I need to access some data about categories from my Photos controller. How would I go about doing this?
Be careful with requestAction unless you make effective use of caching it can really slow down your application as it starts a whole new request cycle every time you call it.
Travis Leleu's answer would be the standard way of doing things. But, if you must import the data (for portability or whatever reason) into the element then requestAction is not the way to go.
As you are not performing any business logic that must be in the controller I strongly recommend you import and instantiate the model class as a singleton into your element. You can do this using ClassRegistry::init();
$Photo = ClassRegistry::init('Photo');
$Photo->find('all');
If you need to do any additional processing of the data you should do that in the model itself either using Cakes afterFind callback or making a custom method in your Photo model:
class Photo extends AppModel {
function customFind () {
$photos = $this->find('all');
foreach ($photos as $photo) {
//processing code here...
}
}
}
Then call it in your element:
$Photo = ClassRegistry::init('Photo');
$Photo->customFind();
Basically what I'm trying to get across here is the only situation where requestAction is appropriate is where you need to do things like redirects or using components.
If you a simply retrieving and/or manipulating data then it belongs in the model.
You can just regard your layous/default.ctp as a normal template,and put
<?php echo $this->element('your element'); ?>
where you need it.
b.t.w,use:
$data = $this->requestAction('controller/action');
to access the data
You can send data to your element. For example in your default.ctp:
<?php echo $this->element('side_nav', $your_data); ?>
and in your side_nav.ctp you can process that data.
Why wouldn't you just do it the standard Cake convention for this?
In the controller,
$this->set( 'categories', $this->Photos->find(...) );