I am working on my first module for magento version 1.3.2.3.
I have created a simple table (not EAV, just a primary key and 2 columns) and some classes to access it, following Alan Storm's articles which helped me a lot, but I can't figure out how to make a simple select: Alan explains how to load with the primary key, but not selecting rows that match some value.
In normal MySQL I'd write:
SELECT *
FROM my_table
WHERE some_field = '" . $someValue . "'
I've found a snippet which gives me the result I want:
$resource = new Mage_Core_Model_Resource();
$read = $resource->getConnection('core_read');
$select = $read->select()
->from('my_table')
->where('some_field = ?', $someValue);
return $read->fetchAll($select);
But there have to be an easier/prettier solution, using the model class I've created. The result will be a single row, not a collection.
I've tried everything I could think of, like:
return Mage::getModel('modulename/classname')->select()->where('some_field = ?', $comeValue);
return Mage::getModel('modulename/classname')->load()->where('some_field = ?', $comeValue);
return Mage::getModel('modulename/classname')->load(array('some_field = ?', $comeValue));
and more stuff, but no luck so far: what am I missing??
You probably want to use your model's Collection for that.
$collection = Mage::getModel('mygroup/mymodel')->getCollection();
$collection->addFieldToFilter('some_field',$some_value);
foreach($collection as $item)
{
var_dump($item);
}
var_dump($collection->getFirstItem());
var_dump($collection->getLastItem());
Here's an example of how this is achieved in the CoreUrlRewrite Model class:
public function loadByIdPath($path)
{
$this->setId(null)->load($path, 'id_path');
return $this;
}
You can create similar methods in your model classes. You can also use the alternative form of the load method anywhere in your code:
$model = Mage::getModel('modulename/classname')->load($someValue, 'some_field');
Related
Is is possible to concatenate a string to Model? The below doesn't seem to work.
I have Car Model and Train Model. Vehicle will be either Car or Train.
$vehicle = 'Car';
$result = $vehicle::where('model', $value)->count() > 0;
The above code exists the following error.
Symfony\Component\Debug\Exception\FatalThrowableError: Class 'Car' not found in file
How can I concatenate? Is it possible?
I think this is the closest to what you need,
you don't have to import anything since you have a dynamic value. (If you have 10 possible models you will have to import all of them)
So you should do something like this
$model = "Car";
$modelsPath = "\\App\\Models\\";
$className = $modelsPath.$model;
// if you need an instance you do this
// $instance = new $className;
$result = $className::where('model', $value)->count() > 0;
dd($result);
What i usually do is create a config file that contains an array of all possibilities where they key is the type (Car,Bus,Train in ur example)
And then i get the value using the key which is the input (car) and the model path will be in the config! that way you can swap it later easy and attach more conditions related to that type of model etc.
I hope this makes sense
Regards
use App\Car; //place this at the top of your page. Make sure the model exists
Yes, you can concatenate a model depending upon the condition. Below, I have added a workable code to implement.
Import both model.
//use App\Car;
//use App\Train;
$isCar = true; // boolean condition to check whether it is a car or train
$classVariable = null;
if ($variable) {
$classVariable = new Car();
}else{
$classVariable = new Train();
}
$result = $classVariable->where('model', $value)->get();
//this will provide you a car model query
dd($result);
Better Approach
A better approach will be to use a Vehicle model and Vehicle Type.
Add a vehicle_type_id in the vehicles table.
So whenever you need to retrieve car types, you can use
//Suppose vehicle_type_id for car is 1
$carVehicle = Vehicle::where('vehicle_type_id', 1)->get();
//Suppose vehicle_type_id for train is 2
$trainVehicle = Vehicle::where('vehicle_type_id', 2)->get();
It's Possible
use App\Car;
use App\Train;
/* Here You can now set Model name dynamically*/
$vehicle = 'Car';
$result = $vehicle::where('model', $value)->count() > 0;
I think one approach can as below:
$vehicle = Car::class; //this will dynamically add full namespace of Car class.
$result = $vehicle::where('model', $value)->count() > 0;
I am using default scope in my project and it works fine.
public static function find()
{
return parent::find()->where(['is_deleted' => 0]);
}
But now, I want to show all the deleted records in the report section.
How can I skip default scope for particular query only?
Use this to clear or redefine your condition:
$model = Model::find()->where('');
If you want to make sure that you're using fresh query (without any params or conditions), you need to create new ActiveQuery object for given model.
$query = Yii::createObject(ActiveQuery::className(), [Post::class]);
Or add a helper method in model itself:
public static function freshFind()
{
return parent::find();
}
and use it instead of Post::find().
You could avoid the use of find() ..using a findBySql
$sql = 'SELECT * FROM product';
$product= Product::findBySql($sql,)->all();
in this way you all the models of product ..
and you could also use
$sql = 'SELECT * FROM ' . Product::tableName() ;
for avoid explici table name for Products
I have some problem that, I am using criteria to customize a number column query
$criteria=new CDbCriteria();
$criteria->select =array('CompanyName', 'CompanyCountCoupon','CompanyDes', 'CompanyLogo');
$models = Company::model()->findAll($criteria);
After I put it to array and echo result
$rows = array();
foreach($models as $i=>$model1) {
$rows[$i] = $model1->attributes;
}
echo CJSON::encode($rows)
My problem is that the results contains all attributes of table, and attributes not in criteria->select will set = null
{"CompanyName":"abc","CompanyCountCoupon":"0","CompanyDes":"Hello","CompanyLogo":"\/upload\/company\/abc.jpg",**"CompanyID":null,"CompanyWebSite":null,"CompanyAdrress1":null,"CompanyAdrress2":null,"CompanyPhone1":null,"CompanyPhone2":null**}
Please help me.
Thanks to all
if you go with findAll() (using ActiveRecord) you won't be able to control that part, the way to go is a custom query :
$results = Yii::app()->db->createCommand()
->select('CompanyName ,CompanyCountCoupon ,CompanyDes ,CompanyLogo')
->from('company')
//->where() // where part
->queryAll();
echo CJSON::encode($results);
now its already good to be JSON encoded and also much faster than regular ActiveRecord
Use getAttributes()
Example
$rows = Company::model()->getAttributes(array('CompanyName','CompanyCountCoupon','CompanyDes', 'CompanyLogo'));
echo CJSON::encode($rows);
This is correct behaviour.
You are asking for specific columns, so this is being correctly provided.
Recall that the attributes is part of the model, not the query.
$model = Company::model()->findByPK();
print_r($model);
...
/* Company points to the TABLE. not the query */
class Company extends CActiveRecord
{
---
}
I am fetching data from Articles table but I want to extend returned result with some data from another table.
For example:
public function getArticlesByCategoryId($category_id = 0) {
$select = $this->_db->select()
->from($this->_name)
->limit(5)
->order("pubDate DESC");
$result = $this->_db->fetchAll($select);
$mCategories = new Model_Categories();
foreach($result as $row) { // as &$row doesn't work
$category_name = $mCategories->getNameById($row["category_id"]);
$row["category_name"] = $category_name; // this to add to $result but dunno how
// blah blah...
}
return $result; // the new one with ...->category_name in it.
}
I hope you could understand what I am looking for.
Or maybe it is better to write a single query (with joins, don't know how) and fetch all the data needed in once without calling methods from another Models?
This indeed looks like you should use a join. This definitely is the easiest way to solve your problem. The following query would do the trick:
$select = $this->_db->select()
->from($this->_name)
->join('category_table', 'category_table.id = ' . $this->_name . '.category_id', array('category_name'))
->limit(5)
->order("pubDate DESC");
This will add the category name to the row.
In case you don't want to use a join, you can add a custom field to your row by using a custom row class. This however requires a bit more work. Create the class as follows:
class MyApp_Model_Row_MyRow extends Zend_Db_Table_Row_Abstract
{
public $categoryName;
}
Then you should indicate in your DbTable class that you want to use this new row class:
class MyApp_Model_DbTable_Articles extends Zend_Db_Table_Abstract
{
...
protected $_rowClass = 'MyApp_Model_Row_MyRow';
}
You can then set the category name in a fetched row.
To get all articles with data from your category table your query could look like:
$select = $this->_db->select()
->from($this->_name)
->joinLeftUsing('category','category_id', array('category_name'))
->order("pubDate DESC");
See also: http://framework.zend.com/manual/en/zend.db.select.html
I'm dealing with database containing of many tables, with many field prefixes (two first letters of every table), so when I have users table I cannot use "name" property ($user->name) but I can use: $user->us_name.
I's there a way to simplify things and set automagic prefix for every field of a table ?
You'd have to extend Zend_Db_Table_Row to accomplish this. Fortunately, ZF includes a _transformColumn() method expressly for this purpose. But I'm getting ahead of myself. First, set up your table class. This assumes your database has a table called "foo_mytable":
class MyTable extends Zend_Db_Table_Abstract {
protected $_name = 'foo_mytable';
protected $_rowClass = 'My_Db_Table_Row';
}
Next, create your custom Row class:
class My_Db_Table_Row extends Zend_Db_Table_Row {
protected function _transformColumn($columnName) {
$columnName = parent::_transformColumn($columnName);
$prefix = 'us_';
return $prefix . $columnName;
}
}
Now, you can do something like this (for simplicity, this example ignores MVC design ideals):
$table = new MyTable();
$records = $table->fetchAll();
foreach ($records as $record) {
echo $record->name;
}
Assuming your table has a column named "us_name", this should work. I tested it myself. Note that in your custom table row, you might want to grab the table prefix from a config file. If you've got it stored in your registry, you could replace $prefix = 'us_'; with $prefix = Zend_Registry::get('tablePrefix');.
I didn't know about _transformColumn(). I'm gonna hop on top of #curtisdf 's example.
I think you should override with this (not tested):
protected function _transformColumn($columnName)
{
$tblName = $this->_table->info(Zend_Db_Table::NAME);
$prefix = substr($tblName, 0, 2);
return $prefix . '_' . parent::_transformColumn($columnName);
}
Using this, you won't need to store prefixes/table-names, as they are retrieved dinamically.