I am working in a app where I need to create database tables on the fly, I did that. But now I need an elegant way to access the database tables. So here is my problem
In regular practice we create a database table and create a class to map a table (ORM). But I cannot take that approach in this case. THis is what I have done so far..
I am extending the MY_Model in the Crud Model, I try to setup the database table name in the set_table() method. It works fine.
class Crud extends MY_Model
{
private $customer_id;
public function __construct()
{
parent::__construct();
$this->_database = $this->load->database('customer', TRUE);
}
public function set_table($customer_id, $table_name)
{
$this->customer_id = $customer_id;
$this->_table = 'tbl_' . $customer_id . '_' . $table_name;
}
}
Test.php Controller to test the code.
class Test extends CI_Controller
{
public function index(){
$this->load->model('editor/crud');
var_dump($this->crud->set_table(1, 'alpha'));
var_dump($this->crud->get_all());
}
}
But I need an elegant way to access the table. eg.
$this->alpha->get_all()
OR
$this->crud->alpha->get_all()
would be easy to understand & it will make much sense. Is it actually possible to do in PHP? Any help would be much appreciable.
I'm guessing you can do something like:
class Test extends CI_Controller
{
public function index(){
$this->load->model('editor/crud');
$this->crud->set_table(1, 'alpha');
$this->alpha = clone $this->crud; // in case you use set_table again
$info = this->alpha->get_all();
}
}
If I recall correctly, you should be able to do it in the model too.
public function set_table($customer_id, $table_name)
{
$this->customer_id = $customer_id;
$this->_table = 'tbl_' . $customer_id . '_' . $table_name;
$this->{$table_name} = clone $this;
}
and then access it like: $this->crud->alpha->get_all();
Related
I have a models.php page that contains the specification of form for a specific model.
models.php
$books = [
['Book Name', 'text' ],
['Author', 'text']
];
$vegetables = [
['Name', 'text'],
['Photo', 'file']
]
Now this page is accessed by an admin.php page, which generate an appropriate HTML form on the basis of the given name and input type.
I want to fill the form and send the data into a handle.php and handle the data with the specific function to fill the data into appropriate table.
handle.php
function books(){
// this will fill the details into table of books.
INSERT INTO BOOKS
name = $_POST['book_name']
author $_POST['author']
}
function vegetables(){
// this will fill the details into table of vegetables.
INSERT INTO VEGETABLES
name = $_POST['book_name']
photo = $_FILE['photo']
}
(If there's any other better way of doing this, so please mention, I'll do that way and delete my question.)
Here's my suggestion. As stated in the comments, this is just my way to do such things, it's not necessarily the best solution for every situation.
I have a base model, that defines all methods all model need to have in common. Here's a very simplified version:
class Model {
public $modelName = 'default';
public $id = null;
private $fields = [];
private $tableName = 'default';
private $tableDefinition = [];
private $idField = 'id';
public function insert($dataset) {
// do some database magic by using $this->fields, or $this->tableDefinition
$sql = "INSERT into {$this->tableName} ...";
...
return $id;
}
public function update($id, $dataset) {
// do some more database magic by using $this->fields, or $this->tableDefinition
}
// many more methods. To get data, delete, sort, ..
//...
}
Every model now extends this base model class and sets it's specific params, maybe even overrides some methods or adds special ones:
class Books extends Model {
public $modelName = 'book';
private $fields = ['bookName','Author'];
private $tableName = 'BOOKS';
private $tableDefinition = [
['bookName','varchar'],
['Author','varchar']
];
// private $idField = 'id'; // you can ommit that, if it's the default.
}
If Vegetables behaves different you can simply override a method:
class Vegetables extends Model {
public $modelName = 'vegetable';
// set all other properties...
// override insert() for example
public function insert($dataset) {
// do something that doesn't comply with the standard procedure
}
}
Then in handle.php you can do something like this:
<?php
$modelName = $request; // get it from your form, your url, ..
// & verify this model(file) exists.
$model = new $modelName();
$model->insert($dataSet);
Make a base interface BaseModel.php
which would have the basic signatures of insertion , updation and selection
Make a derived class booksModel.php and vegetablesModel.php that would implement the BaseModel class.
In this way, you have made your code extendable. If there is some common functionality, you can make the base class as Abstract class.
abstract class BaseModel {
abstract function add($dataObject);
abstract function get($dataObject);
}
class BooksModel extends BaseModel {
public function add($dataObject) {
/* Implementation */
}
public function get($dataObject) {
/* Implementation */
}
}
class VegetableModel extends BaseModel {
public function add($dataObject) {
/* Implementation */
}
public function get($dataObject) {
/* Implementation */
}
}
My website has Object as the model and ObjectSearch as the searchModel. I realized that I am already having a lot of duplicates in my two different controllers. For example, FirstController has this:
$arr = Yii::$app->db->createCommand('SELECT id, name, address
FROM hosts)->queryAll();
Then at some part of my website SecondController also needs to use that same query.
How can I re-use that query over and over again from different controllers?
I am talking about this:
public function search($params)
{
$query = Host::find();
$dataProvider = new ActiveDataProvider([
'query' => $query,
]
]);
.
.
.
return $dataProvider;
}
I have another question also. I am planning to do different queries. What is the best approach for making another query? Should I use that
public function search($params)
again and maybe add on the parameter like this?
public function search($params, $cond)
{
if ($cond == true) {
$query = *something;
}
else {
$query = *something_else;
}
.
.
.
return $dataProvider;
}
In your root folder, you are having component folder. Inside component folder, create one page like UserInfoComponent.php. This page will be common and can be use anywhere.
This is the Directory Structure
YourProjectFolder
->assets
->commands
->components
->UserInfoComponent.php
.
.
UserInfoComponent.php
<?php
namespace app\components;
use Yii;
use yii\base\Component;
class UserInfoComponent extends Component
{
.
.
public function getUserDetails() {
$arr = Yii::$app->db->createCommand('SELECT id, name, address FROM hosts')->queryAll();
return $arr;
}
.
.
.
}
Now, how to call this function in your controller or view.
Controller or view
<?
$arrValue = Yii::$app->userinfo->getUserDetails();
?>
For common function you can create an helper class
namespace myapp\myhelperdir
class MyQueryHelper
{
public static function mySelectFunction ($param)
{
// your code for function
return $yourResult;
}
then you can refer to these function in every part of your project simply adding
use myapp\myhelperdir\MyQueryHelper
$myResult = MyQueryHelper::mySelectFunction($myParam);
I am working on creating models for a module I'm developing but I've run into a problem echoing out the result from a query.
What I get when using a var_dump() calling the the model in the block is NULL
I don't understand because in the resource model, if i do an echo $select it prints out the query which I enter into phpMyAdmin and it find the row. I think i must be trying to output the row wrongly.
This is my resource model:
class MyCompany_Facebook_Model_Resource_Facebookcoupon extends Mage_Core_Model_Resource_Db_Abstract
{
protected function _construct()
{
$this->_init('facebook/facebookcoupon', 'entity_id');
}
public function loadByField($field,$value)
{
$table = $this->getTable('facebook/facebookcoupon');
$where = $this->_getReadAdapter()->quoteInto("$field = ?", $value);
$select = $this->_getReadAdapter()->select()->from($table,array('facebook_id'))->where($where);
$id = $this->_getReadAdapter()->fetchOne($select);
return $id;
}
This is my model
class MyCompany_Facebook_Model_Facebookcoupon extends Mage_Core_Model_Abstract
{
protected function _construct()
{
parent::_construct();
$this->_init('facebook/facebookcoupon');
}
public function loadByField($field,$value)
{
$id = $this->getResource()->loadByField($field,$value);
$this->load($id);
}
}
and i call it using this block
class MyCompany_Facebook_Block_Content extends Mage_Core_Block_Template
{
private $couponCode;
public function displayCoupon($test)
{
$facebookid = Mage::getModel('facebook/facebookcoupon')->loadByField('facebook_id', '14547854');
var_dump($facebookid);
Adrock.use the below for more suitable solution
$model = Mage::getModel('facebook/facebookcoupon') ->getCollection()
->addFieldToFilter('facebook_id', 14547854) ->getFirstItem();
// here you'll get a collection but single record -
Please note:
loadByField($field,$value) in resource model is wrong.you can use load()
function only whenever,you will be trying to fetch data using primary key.
I'm a relative beginner in Laravel 4 and I'm having trouble retrieving data from a joined table as defined in my model. I tried following the directions in Laravel's documentation here and here.
Here's what I did: I have a model (car.php) that successfully retrieves data from my cars table:
class Car extends Eloquent{
public function parts(){
return $this->hasMany('CarParts');
}
}
Here's my CarParts model (car-parts.php):
class CarParts extends Eloquent{
protected $table = 'car_parts';
public function car(){
return $this->hasOne('Car');
}
}
I tried these to get to the data in the joined table:
echo Car::find(1)->parts;
// also tried:
$cars = Car::find(1)->get();
echo $cars->parts;
But I get this error message: Undefined property:Car::$parts
The best way is to use the dynamic property (->parts) so this should work for you:
$car = Car::find(1);
echo $car->parts;
or
$car = Car::find(1);
foreach($car->parts as $part)
{
echo $part->name;
}
The parts() method gives you a query object, which may be used to filter a little more your parts:
$car = Car::find(1);
$parts = $car->parts()->where('model', '=', 'FORD')->get();
foreach($parts as $part)
{
echo $part->name;
}
Also you probably will have to change your CarParts relation to:
$this->belongsTo('Car');
The problem you are having is in your relationship. The inverse of hasMany() is belongsTo() so with that in mind, your models should looking something like this...
class Car extends Eloquent
{
public function parts()
{
return $this->hasMany('CarParts');
}
}
class CarParts extends Eloquent
{
protected $table = 'car_parts';
public function car()
{
return $this->belongsTo('Car');
}
}
In order to find a car's parts, you can do something like this...
$parts = Car::find(1)->parts;
foreach($parts as $part) {
echo $part->name;
}
You should also add the primaryKey properties to your models as well if they are not following the Laravel standards. Add this to CarPart with the appropriate key.
protected $primaryKey = 'car_part_id';
First, your relations should be defined like this:
<?php
class Car extends Eloquent {
public function parts(){
return $this->hasMany('CarPart');
}
}
class CarPart extends Eloquent {
protected $table = 'car_parts';
public function car(){
return $this->belongsTo('Car');
}
}
You should do this:
Car::parts();
Or this:
$cars = Car::find(1);
$carParts = $cars->parts();
Figured it out... I renamed my "CarParts" model to just "Parts". Also renamed the model file to "parts.php" and it worked. (Also fixed the relationship as edvinas.me noticed... but that didn't seem to matter to the result.) The camel-case thing is strange. Can anyone explain this to me? Here's what it looks like now:
class Car extends Eloquent{
public function parts(){
return $this->hasMany('Parts');
}
}
class Parts extends Eloquent{
protected $table = 'car_parts';
public function car(){
return $this->belongsTo('Car');
}
}
Does eloquent just hate camel case?
Update:
I figured out why I was having this problem with the way I was naming my classes. As it turns out, one of my migration classes was already called CarParts. Simple problem, but I decided to post this update since I think it's pretty easy for someone else to make the same mistake.
I have two models:
class Product extends Eloquent {
...
public function defaultPhoto()
{
return $this->belongsTo('Photo');
}
public function photos()
{
return $this->hasMany('Photo');
}
}
class Photo extends Eloquent {
...
public function getThumbAttribute() {
return 'products/' . $this->uri . '/thumb.jpg';
}
public function getFullAttribute() {
return 'products/' . $this->uri . '/full.jpg';
}
...
}
This works fine, I can call $product->defaultPhoto->thumb and $product->defaultPhoto->full and get the path to the related image, and get all photos using $product->photos and looping through the values.
The problem arises when the product does not have a photo, I can't seem to figure out a way to set a default value for such a scenario.
I have tried doing things such as
public function photos()
{
$photos = $this->hasMany('Photo');
if ($photos->count() === 0) {
$p = new Photo;
$p->url = 'default';
$photos->add($p);
}
return $photos;
}
I have also creating a completely new Collection to store the new Photo model in, but they both return the same error:
Call to undefined method Illuminate\Database\Eloquent\Collection::getResults()
Has anyone done anything similar to this?
Thanks in advance!
You could create an accessor on the Product model that did the check for you. Works the same if you just wanted to define it as a method, also (good for if you want to abstract some of the Eloquent calls, use an interface for your Product in case you change it later, etc.)
/**
* Create a custom thumbnail "column" accessor to retrieve this product's
* photo, or a default if it does not have one.
*
* #return string
*/
public function getThumbnailAttribute()
{
$default = $this->defaultPhoto;
return ( ! is_null($default))
? $default->thumb
: '/products/default/thumb.jpg';
}
You might also want to look into Presenters. A bit overkill for some situations, but incredibly handy to have (and abstract things like this away from your models).