My model class:
<?php class Permissions extends CI_Model {
private $userID = '';
private $permissions = '';
function __construct($userID)
{
// Call the Model constructor
parent::__construct();
$this->userID = $userID;
....
}
function __construct()
{.....}
?>
and I want to load this model with a parameter, apparently I could not do it.
Without a parameter I can load parameterless constructor by this way:
$this->load->model('Permissions');
My first question: is loading a model with a parameter nonsense?
Second one: if it is doable, how can I do that?
Thanks in advance.
you can instantiate the class it self, instead of loading it.
$permission = new Permission($param);
You could take a look at this forum thread: http://codeigniter.com/forums/viewthread/115681/
But I can't see why would you want to give a userid as a parameter in a way for permission checking? Guessing you use sessions to save userdata, write the userid in the session and call this in the Model with $this->session->userdata('user_id').
Happy coding!
You can do your customization in you model's function level. If you provide why do you extend the model, I can say whether it makes sense or not. If you want to create a user specific rule, you had better to do it on a controller.
class Shop_m extends CI_Model {
function getProductPriceInfo($cat,$id) {
$this->db->where('shop_price.catid', $cat);
$this->db->where('shop_price.relid', $id);
$this->db->select('optional.title,optional.desc,shop_price.*');
$this->db->join('optional', 'optional.id = shop_price.relid');
$q = $this->db->get('shop_price');
if($q->num_rows() > 0) {
foreach ($q->result() as $row) {
$data[] = $row;
}
return $data;
}
}
Related
I'm currently rebuilding my vanilla-PHP-App with Laravel and I have the following problem.
I have multiple database-tables, that represent word categories (noun, verb, adverb, ...). For each table I created a separate Model, a route::resource and a separate resource-Controller. For example:
NomenController.php
public function show($id)
{
$vocab = Nomen::find($id);
return view('glossarium.vocab_update', compact('vocab'));
}
and
VerbController.php
public function show($id)
{
$vocab = Verb::find($id);
return view('glossarium.vocab_update', compact('vocab'));
}
...which are essentially the same except the Model class.
I don't want to create a separate Controller for each model, that does exactly the same. What would be the most simple and elegant way to solve this?
Should I just create a VocabController.php and add a parameter for the Model-name like:
Route::resource('/vocab/{category}', 'VocabController');
and then add a constructor method in this controller like
public function __construct ($category) {
if ($category == 'nomen') {
$this->vocab = App\Nomen;
}
else if ($category == 'verb') {
$this->vocab = App\Verb;
}
}
I wonder if there is a simpler method to do that. Can I somehow do this with Route Model Binding?
Thanks in advance
Simply create a trait like this in App\Traits, (you can name it anything... Don't go with mine though... I feel its pretty lame... :P)
namespace App\Traits;
trait CommonControllerFunctions {
public function show($id) {
$modelObject = $this->model;
$model = $modelObject::find($id);
return view('glossarium.vocab_update', compact('model'));
}
}
and in your NomenController and VerbController, do this:
use App\Traits\CommonControllerFunctions;
class NomenController {
use CommonControllerFunctions;
protected $model = Nomen::class;
}
and
use App\Traits\CommonControllerFunctions;
class VerbController {
use CommonControllerFunctions;
protected $model = Verb::class;
}
Note: Please note that this example is just a work-around for your particular situation only... Everyone practices code differently, so this method might not be approved by all...
I think the simpliest way it to create only one controller, eg VocabController with methods nomen, verb and whatever you want.
Routes:
Route::get('/vocab/nomen/{nomen}', 'VocabController#item');
Route::get('/vocab/verb/{verb}', 'VocabController#item');
And the model binding:
Route::model('nomen', 'App\Nomen');
Route::model('verb', 'App\Varb');
Then your method shoud look like that:
public function item($item)
{
return view('glossarium.vocab_update', $item);
}
Keep in mind, that $item is already fetched model from the database.
I passed parameter from view to controller via URL. Now I want to send it from controller to model so that I can use it to pick data from tables. Here is my code:
controller:
function view(){
if(isset($_GET['r'])) {
$rank = $_GET['r'];
}
$rank=$this->uri->segment($rank);
$this->load->model('names_rank');
$data=$this->names_rank->get_names($rank);
print_r($rank);
}
model:
function get_names($rank){
$this->db->select('u.*,v.*');
$this->db->from('unit_member u, Vyeo v');
$this->db->where('v.fno = u.fno');
$this->db->where('u.present = ""');
$this->db->where('v.rank', $rank);
$this->db->where('v.date_of_end="0000-00-00"');
$query = $this->db->get();
return $query->result_array();
}
this is the result:
A PHP Error was encountered Severity: Warning Message: Missing
argument 1 for Names_rank::get_names(), called in
C:\xampp\htdocs\unit\application\controllers\names.php on line 32 and
defined
This will work to send to model but your code isn't understandable for me, you re-declare the variable after setting it in the IF? are you trying to print_r() the output from the model?
I think you are trying to achieve this maybe?
function view() {
if(isset($_GET['r'])) {
$rank = $_GET['r'];
}else{
$rank = $this->uri->segment($rank);
}
$this->load->model('names_rank');
$data = $this->names_rank->get_names($rank);
print_r($data);
}
You can pass a Parameter to your model. First you have to call your model within your controller if you not enable it on autoload.
Your Model:
<?php
class AwesomeModel extends CI_Model
{
publif function do_work($param, $anotherParam)
{
//code here
}
}
Then your controller:
<?php
class AwesomeController extends CI_Controller
{
public function __construct()
{
/*
* load in constructor so not need to recall every time you want use it
* second parameter is model renaming (optional)
*/
$this->load->model('AwesomeModel', 'awe');
}
public function pass_data()
{
$this->awe->do_work($param1, $param2);
}
?>
Thats all.
My Zend Framework 2 Application has a view whereby I display a log of events, in a simple table format. I use several basic View Helpers to manipulate the presentation of the data in the table, but on these existing View Helpers all of the logic is contained to the View Helper itself, e.g:
namespace Application\View\Helper;
use Zend\View\Helper\AbstractHelper;
class GetSystemName extends AbstractHelper
{
public function __invoke($val)
{
if ($val == 0){
return 'Something';
}
if ($val == 1){
return 'Something else';
}
}
}
My requirement is to build a function GetUserName to accept user_id and perform a check on the database to display the User's name, as the ID is of no value to the person using the system.
The way I see it I can either:
A) Start a new query from within the View Helper to return what I need or
B) Use a function called getUser() from within the 'User' Module / UserTable class.
The code for B is:
namespace User\Model;
use Zend\Db\TableGateway\TableGateway;
class UserTable
{
protected $tableGateway;
public function __construct(TableGateway $tableGateway)
{
$this->tableGateway = $tableGateway;
}
//..other functions
public function getUser($id)
{
$id = (int) $id;
$rowset = $this->tableGateway->select(array('id' => $id));
$row = $rowset->current();
if (!$row) {
throw new \Exception("Could not find row $id");
}
return $row;
}
What is the best option? And how would I implement it?
Apologies if this is a basic questions I am quite new to MVC and Zend.
In the model-view-controller pattern, the view should not be aware of the model layer. Information from the models are injected into the view through the controller.
Having your view helper call the getUser() method in your model breaks this pattern.
So, what do you do?
Have your controller get the user information into the view:
// controller
$userId = $this->params()->fromQuery("userID");
// or from session ID if this is a private profile page
// You might want some validation, too...
$userTable = $this->getServiceLocator()->get("UserTable");
// or whatever you've configured in the service config for this
$user = $userTable->getUser($userId);
// if this is a public profile page, you might want to
// exclude some fields like "password" so they don't
// accidentally get into the view
$view = new ViewModel();
$view->setVariable("user", $user);
return $view;
Then in the view.phtml you just do:
<?php $this->GetSystemName($user->whateverField); ?>
I have been working on my own library/framework for the learning experience for a while. MVC is one of those things that took me a while to really understand but I do finally "Get it".
Below is some sample code for a basic MVC setup in PHP. I think I am in the right direction so far, where I need a little help is down in the "Example controller" near the bottom, you will see where I can create a view, I just need to figure out how to best get my data from a model file into that controller class. Please help with example code if you can, hopefully I am making sense.
Also I am welcome to any comments/suggestions on any of the code
Abstract Controller class...
/**
* MVC Example Project
*/
/**
* Extend this class with your Controllers
* Reference to the model wrapper / loader functions via $this->model
* Reference to the view functions via $this->view
*/
abstract class Core_Controller {
protected $view;
protected $model;
function __construct($dependencyContainer){
$this->view = new Core_View();
//$this->view = $dependencyContainer->get(view);
}
}
Abstract Model class...
/**
* Extend this class with your models and reference to the database object via $this->$db
*/
abstract class Core_Model {
protected $db;
protected $session;
function __construct($dependencyContainer) {
$this->db = $dependencyContainer->get(database);
$this->session = $dependencyContainer->get(session);
}
}
View class, might make it abstract as well...
class Core_View {
protected $data;
# Load a view file (views/$view.php);
# $param data this gets extracted and be thus be used inside the view
# When loading another view from inside the view file the data is 'cached' so you
# don't have to pass them again
public function load($view,$data = null) {
if($data) {
$this->data = $data;
extract($data);
} elseif($this->data != null) {
extract($this->data);
}
require(APP_PATH . "Views/$view.php");
}
public function set($data = null) {
if($data) {
$this->data = $data;
extract($data);
} elseif($this->data != null) {
extract($this->data);
}
}
}
Example putting it together...
/**
* Example Controller
*/
class User_Controller extends Core_Controller {
public function profile()
{
$profileData = array();
$profileData = //GET from Model
$this->view->load('userProfile', $profileData);
}
}
?>
My suggestion is not to tie view and model to the controller at all. Let them be instantiable from controller code, just like any other classes. You can then get the model data (and pass it to the view) in standard object oriented way.
Will you use a Data access layer (DAL) / Object-relational mapping (ORM)? Take a look at Zend_Db, Doctrine or Propel
I'd say that you're missing the part of the application that manipulate your models. It could be your controller, but isn't a good practice. So we need a model mapper.
The best way to get model data from your controller is simply calling it. But generally we use a kind of "pointer" which knows how to populate your object model. This pointer is called "Mappers" (Data Mapper Pattern):
$MyModelMapper = new MyModelMapper();
$Profile = $MyModelMapper->getProfileById($id); // return Core_Model.
This function will perform a database query and will populate one specific model with the data. You could also get an array of objects for a "list" action for example.
Then you'll pass this model to your view.
I think you should take a look at the Zend Framewok quick start. It will give you some ideas.
See this question too: What's the difference between DAO and Data Mapper
I am using the following code to initialize a model from within my controller:
$this->load->model('model_name');
Is it possible to modify the above line somehow so that the model constructor recieves a parameter? I want to use the following code in the model constructor:
function __construct($param_var) {
parent::Model();
$this->$param_var = $param_var; //I'm not even sure this works in PHP..but different issue
}
This would be very helpful so that I can reuse my model classes. Thanks.
UPDATE:
(from one of the answers, my original question is solved..thanks!)
Just to explain why I wanted to do this: the idea is to be able to reuse a model class. So basically to give a simple example I would like to be able to pass an "order_by" variable to the model class so that I can reuse the logic in the model class (and dynamically change the order-by value in the sql) without having to create a separate class or a separate function.
Is this poor design? If so could you please explain why you wouldn't do something like this and how you would do it instead?
You can't pass parameters through the load function. You'll have to do something like:
$this->load->model('model_name');
$this->model_name->my_constructor('stuff');
In the model:
function my_constructor($param_var) {
...
}
Response to update:
You could just pass the order_by value when you're calling your model function. I'm assuming in your controller action, you have something like $this->model_name->get($my_id); Just add your order_by parameter to this function. IMO this makes your model logic more flexible/reusable because the way you were doing it, I assume setting order_by in the constructor will set the order_by value for every function.
In model
<?php
/* Load Model core model */
/* BASEPATH = D:\xampp\htdocs\ci_name_project\system\ */
include BASEPATH . 'core\\Model.php';
class User_model extends CI_Model {
/* Properties */
private $name;
/* Constructor parameter overload */
public function __construct($name) {
$this->set_name($name);
}
/* Set */
public function set_name($name) {
$this->name = $name;
}
/* Get */
public function get_name() {
return $this->name;
}
}
in controller
<?php
class User_controller extends CI_Controller {
public function index() {
/* Load User_model model */
/* APPPATH = D:\xampp\htdocs\ci_name_project\application\ */
include APPPATH . 'models\\User_model.php';
$name = 'love';
/* Create $object_user object of User_model class */
$object_user = new User_model($name);
echo $object_user->get_name(); // love
}
}
I see your reasoning for this, but may I suggest looking at Object-Relational Mapping for your database needs. There is a user-made ORM library for CodeIgniter called DataMapper that I've been using lately. You can use tables in your controllers as objects, and it may be a better fit for your problem.
Instead of using DataMapper i suggested to use IgnitedRecord because that the DataMapper is no longer maintained more over it has been replaced into Ruby
I am using CI ver 3.X, so what I am about to say is it will work for Codeigniter 3.X (and I haven't checked ver 4+ yet).
When I went thru the source code of the function model() in file system/libraries/Loader.php, noticed that it does not support loading the model with construct parameters. So if you want to make this happen you have to change the source code (bold, I know, and I just did).
Down below is how I did it.
1. Firstly, replace line 355
$CI->$name = new $model();
with some modifications:
$_args_count = func_num_args();
if(3 < $_args_count){
$refl = new ReflectionClass($model);
$CI->$name = $refl->newInstanceArgs(array_slice($_args_count, 3));
}else{
$CI->$name = new $model(); // origin source code
}
2. Load the model with a bit difference:
$this->load->model("model_name", "model_name", false, $param_var); // where amazing happens
Now you can have $this->model_name as you wished.