select column magento - php

I was wondering how you can select columns. Above you can see the sql I wanna write in the controller. But I want to do this the wright way. Like other sql statements in magento.
I tried to add ->columns('o.sku AS SKU') but this didn't work.
Any ideas? Thanks in advance!
//sql
$readresult="SELECT o.name AS 'Product', o.sku AS 'SKU', c.entity_id AS 'Order', c.customer_email AS 'Email', c.customer_firstname AS 'Voornaam', c.customer_lastname AS 'Achternaam', c.customer_middlename AS 'Tussenvoegsel', o.product_options AS 'Options', a.telephone AS 'Telefoon', a.postcode AS 'Postcode', a.street AS 'Street', a.city AS 'City', c.increment_id AS 'Bestelnr' FROM magento_sales_flat_order AS c INNER JOIN magento_sales_flat_order_item AS o ON c.entity_id = o.order_id INNER JOIN magento_sales_flat_order_address AS a ON a.parent_id = c.entity_id WHERE o.product_id =".$product." GROUP BY c.entity_id ORDER BY o.sku;";
//THE MAGENTO WAY!
$resource = Mage::getSingleton('core/resource');
$read = $resource->getConnection('core_read');
$o = $resource->getTableName('magento_sales_flat_order');
$o_item = $resource->getTableName('magento_sales_flat_order_item');
$o_address = $resource->getTableName('magento_sales_flat_order_address');
$select = $read->select()->from(array('c'=>$o))
->join(array('o'=>$o_item), 'c.entity_id = o.order_id', array(o.sku AS 'SKU'))
->join(array('a'=>$o_address), 'a.parent_id = c.entity_id', array())
->where('o.product_id', $product)
->group('c.entity_id')
->order('o.sku');

You souldn't work like this with core modules at all. Those low level SQL queries should be used by resource models only. Especially not within a controller.
You should get an instance of Mage_Sales_Model_Resource_Order_Collection by calling Mage::getModel('sales/order')->getCollection() and build your query from there. Just have a look at the source code to find out about how to do that exactly; start at app/code/core/Mage/Sales/Model/Resource/Order/Collection.php and work your way down the inheritance chain.
For example, you can add a WHERE using something like $collection->addAttributeToSearchFilter().
Magento's got great database abstraction and you sould definately be using it.
Hope this helps.

Related

Where should I place complex queries in Laravel?

So I've searched the internet for similar cases, and I just got lost from all contradicting answers, and unrelated scenarios. So I thought to put my case hoping to get some specific answers.
I am new to Laravel, and creating small application. In the application I have to search for offeres and show the result in a blade view. Since the query is complex, and output of the search does not belong to a specific Model, I just wish to keep it as a raw query.
I have placed the query in the controller, but I just don't feel it's the right place. Especially if I need to reuse the query in many places.
Here's the method from the OfferController:
public function search(Request $request)
{
$area = $request->area;
$size = $request->size;
$sql = "SELECT distinct product_name,product_offer.quantity, product_offer.price
FROM product
inner join brand on product.brand_id = brand.brand_id
inner join brand_area on brand_area.brand_id = brand.brand_id
inner join area on area.area_id = brand_area.area_id
inner join product_offer on product_offer.product_id = product.product_id
where area.area_id = :area
and product.size_id = :size ";
$params = array(
'area'=>$area,
'size'=>$size
);
$offers = DB::select( DB::raw($sql), $params);
return view('searchresult')->with($offers);
}
So in short: should I move the query to the model, create DAL class, or keep it here? Baring in mind the project is small scale.
in my opinion, if you are going to reuse it, create a service that will perform that query and gives you back a result, something like SearchService that looks like this:
<?php
class SearchService
{
public static function perform(array $params){
$sql = "SELECT distinct product_name,product_offer.quantity, product_offer.price
FROM product
inner join brand on product.brand_id = brand.brand_id
inner join brand_area on brand_area.brand_id = brand.brand_id
inner join area on area.area_id = brand_area.area_id
inner join product_offer on product_offer.product_id = product.product_id
where area.area_id = :area
and product.size_id = :size ";
return DB::select( DB::raw($sql), $params);
}
}
?>
And by doing so, you can just call
SearchService::perform([...]);
to get the results.
Obviously this is version1.0, you can improve it in a lot of ways, for example making it not static in order to make it testable, and also to allow getter and setter to exists, and a lot of other things, that might be usefull
You have a fair point saying it does not look right to place query in the controller. I would offer you to have a look at the concept of Laravel repository pattern:
https://dev.to/asperbrothers/laravel-repository-pattern-how-to-use-why-it-matters-1g9d
Also, I think you could use Laravel DB for this kind of query without the need to write it as a raw query. I do not think there is a huge need to have a raw query here. Laravel DB table(), select(), where() and other methods should be enough.
Actually, you could potentially write this using models and their relationships, but if the query is quite slow, it is better to use query builder for better efficiency.
EDIT:
also for some specific queries which do not belong to anything I remember seeing custom trait used, could also be a solution.
I'm writing my previous comment as an answer since I think its really what you are looking for:
I suggest you use a Trait to do this. The reason why is that it will keep your code clean and you'll be able to reuse this code later for other uses. A Trait is made for reusable code.
You will create a Trait:
<?php
namespace App\Traits; // Optional, but you could create a namespace for all your Traits if you need others
trait MyCustomTrait
{
public function perform(array $params) {
$sql = "SELECT distinct product_name,product_offer.quantity, product_offer.price
FROM product
inner join brand on product.brand_id = brand.brand_id
inner join brand_area on brand_area.brand_id = brand.brand_id
inner join area on area.area_id = brand_area.area_id
inner join product_offer on product_offer.product_id = product.product_id
where area.area_id = :area
and product.size_id = :size ";
return DB::select( DB::raw($sql), $params);
}
}
To use it, only write: use MyCustomTrait in the scope of your controller and call your function like this: $this->perform([...]).
Here's some links to learn more about traits:
https://www.w3schools.com/php/php_oop_traits.asp
https://www.develodesign.co.uk/news/laravel-traits-what-are-traits-and-how-to-create-a-laravel-trait/.
Hope it helps you!

cake php custom query

I have use custom query in cakephp but I dont understand how to run custom join query.
I am using this code
$arrayTemp1 = $this->User->query('SELECT DISTINCT
u.id,u.hunting_association FROM ht_users as u LEFT JOIN
`ht_user_animal_prices` as uap ON uap.user_id=u.id WHERE
uap.animal_type_id='.$this->request->data['User']['animal'].' ');
User is the model for ht_users and UserAnimalPrice is the model for ht_user_animal_prices. How to combine the query?
Please help.
If you want to use custom queries and you want the data of UserAnimalPrice model, you just have to put the fields in the query. Something like:
$arrayTemp1 = $this->User->query('SELECT DISTINCT u.id,u.hunting_association, uap.* FROM ht_users as u LEFT JOIN ht_user_animal_prices as uap ON uap.user_id=u.id WHERE uap.animal_type_id='.$this->request->data['User']['animal'].' ');
If you prefer not to use custom queries:
$fields = array('User.id','User.hunting_association','UserAnimalPrice.*');
$join = array(
array(
'table' => 'ht_user_animal_prices',
'alias' => 'UserAnimalPrice',
'type' => 'LEFT',
'conditions' => array('UserAnimalPrice.user_id = User.id')
)
);
$conditions = array('UserAnimalPrice.animal_type_id' => $this->request->data['User']['animal']);
$group = array('User.id');
arrayTemp1=arrayTemp1->find('all',array('fields'=>$fields,'joins'=>$join,'conditions'=>$conditions,'group'=>$group));
This is Correct Query u used .You can also use it in User Model like
public function getCustomUsersQuery()
{
$arrayTemp1 = $this->query("
SELECT
DISTINCT u.id,u.hunting_association FROM ht_users as u
LEFT JOIN
ht_user_animal_prices as uap ON uap.user_id=u.id
WHERE
uap.animal_type_id='".$this->request->data['User']['animal']."'");
return $arrayTemp1;
}
And call inside Users Controller
$result = $this->getCustomUsersQuery();
Sorry I cannot comment on Rizwan answer. If you received the "Call to a member function..." problem, make sure you have the following code
public $uses = array('User');
this tells that you want to access the user model in that controller. Then you will be allowed to do so.

How to use CDbCriteria in Yii to apply SQL filters on Model

I try to get this mysql query to work with Yii model but i can't.
SELECT COUNT( qhc.countries_id) AS counter, q.question, co.name
FROM questions AS q , countries as co, questions_has_countries AS qhc
WHERE qhc.questions_id = q.id
AND co.id = qhc.countries_id
GROUP BY question
HAVING counter = 2
So far i have this, but somehow thou it seems ok, it doesnt work :
$criteria = new CDbCriteria();
$criteria->select = 'question, COUNT(countries_id) as counter';
$criteria->with = array('countries', 'categories');
$criteria->addInCondition('countries.id' , $_POST['Questions']['countries']);
$criteria->group = 'question';
$criteria->having = ('counter = 1');
$model = Questions::model()->findAll($criteria)
Pls help, I'am pretty new to Yii framework.
Thanks.
Sql from the log :
SELECT `t`.`question` AS `t0_c1`,
COUNT(countries_id) as counter, `t`.`id` AS `t0_c0`, `countries`.`id` AS
`t1_c0`, `countries`.`name` AS `t1_c1`, `categories`.`id` AS `t2_c0`,
`categories`.`name` AS `t2_c1` FROM `questions` `t` LEFT OUTER JOIN
`questions_has_countries` `countries_countries` ON
(`t`.`id`=`countries_countries`.`questions_id`) LEFT OUTER JOIN `countries`
`countries` ON (`countries`.`id`=`countries_countries`.`countries_id`)
LEFT OUTER JOIN `questions_has_categories` `categories_categories` ON
(`t`.`id`=`categories_categories`.`questions_id`) LEFT OUTER JOIN
`categories` `categories` ON
(`categories`.`id`=`categories_categories`.`categories_id`) WHERE
(countries.id=:ycp0) GROUP BY question HAVING (counter = 2). Bound with
:ycp0='1'
You have done most of work. Now you need to call the $criteria into model. Just like this
$rows = MODEL ::model()->findAll($criteria);
Where MODEL is model class of table which you want to apply criteria on.
To learn more about this you can follow this CActiveRecord Class.
Try to set together in CDbCriteria
...
$criteria->together = true;
$model = Question::model()->findAll($criteria);
when you use "as counter", your model must have a property named "counter" or it will not load it into your model.
if you don't have a property named "counter", try using another one of your models property that you are not selecting right now : "as someColumn"
and use condition or addCondition or .. instead of having
cheers

Sub-queries ActiveRecord Yii

Is it possible to make sub-queries in ActiveRecord in Yii?
i have a query like this:
select * from table1
where table1.field1 in (select table2.field2 from table2)
i'm currently using the fallowing code:
object1::model()->findAll(array('condition'=>'t.field1 in (select table2.field2 from table2)'))
[Edit]
i would like to know if there is a manner to construct the sub-query without using SQL, and without using joins.
Is there any solution ?
and thanks in advance.
First find doublets by db fields:
$model=new MyModel('search');
$model->unsetAttributes();
$criteria=new CDbCriteria();
$criteria->select='col1,col2,col3';
$criteria->group = 'col1,col2,col3';
$criteria->having = 'COUNT(col1) > 1 AND COUNT(col2) > 1 AND COUNT(col3) > 1';
Get the subquery:
$subQuery=$model->getCommandBuilder()->createFindCommand($model->getTableSchema(),$criteria)->getText();
Add the subquery condition:
$mainCriteria=new CDbCriteria();
$mainCriteria->condition=' (col1,col2,col3) in ('.$subQuery.') ';
$mainCriteria->order = 'col1,col2,col3';
How to use:
$result = MyModel::model()->findAll($mainCriteria);
Or:
$dataProvider = new CActiveDataProvider('MyModel', array(
'criteria'=>$mainCriteria,
));
Source: http://www.yiiframework.com/wiki/364/using-sub-query-for-doubletts/
No, there is not a way to programmatically construct a subquery using Yii's CDbCriteria and CActiveRecord. It doesn't look like the Query Builder has a way, either.
You can still do subqueries a few different ways, however:
$results = Object1::model()->findAll(array(
'condition'=>'t.field1 in (select table2.field2 from table2)')
);
You can also do a join (which will probably be faster, sub-queries can be slow):
$results = Object1::model()->findAll(array(
'join'=>'JOIN table2 ON t.field1 = table2.field2'
);
You can also do a direct SQL query with findAllBySql:
$results = Object1::model()->findAllBySql('
select * from table1 where table1.field1 in
(select table2.field2 from table2)'
);
You can, however, at least provide a nice AR style interface to these like so:
class MyModel extends CActiveRecord {
public function getResults() {
return Object1::model()->findAll(array(
'condition'=>'t.field1 in (select table2.field2 from table2)')
);
}
}
Called like so:
$model = new MyModel();
$results = $model->results;
One interesting alternative idea would be to create your subquery using the Query Builder's CDbCommand or something, and then just pass the resulting SQL query string into a CDbCritera addInCondition()? Not sure if this will work, but it might:
$sql = Yii::app()->db->createCommand()
->select('*')
->from('tbl_user')
->text;
$criteria->addInCondition('columnName',$sql);
You can always extend the base CDbCriteria class to process and build subqueries somehow as well. Might make a nice extension you could release! :)
I hope that helps!
I know this an old thread but maybe someone (like me) still needs an answer.
There is a small issues related to the previous answers. So, here is my enhancement:
$model=new SomeModel();
$criteria=new CDbCriteria();
$criteria->compare('attribute', $value);
$criteria->addCondition($condition);
// ... etc
$subQuery=$model->getCommandBuilder()->createFindCommand($model->getTableSchema(),$criteria)->getText();
$mainCriteria=new CDbCriteria();
$mainCriteria->addCondition($anotherCondition);
// ... etc
// NOW THIS IS IMPORTANT
$mainCriteria->params = array_merge($criteria->params, $mainCriteria->params);
// Now You can pass the criteria:
$result = OtherModel::model()->findAll($mainCriteria);

CakePHP - Building a Complex Query

I have the following query I want to build using CakePHP. How should I go about this?
SELECT
`Artist`.`id`,
CONCAT_WS(' ', `Person`.`first_name`, `Person`.`last_name`, `Person`.`post_nominal_letters`) AS `name`,
`Portfolio`.`count`
FROM
`people` as `Person`,
`artists` as `Artist`
LEFT OUTER JOIN
(SELECT
`Product`.`artist_id`,
COUNT(DISTINCT `Product`.`id`) AS `count`
FROM
`product_availabilities` AS `ProductAvailability`,
`products` AS `Product`
LEFT OUTER JOIN
`order_details` AS `OrderDetail`
ON
`Product`.`id` = `OrderDetail`.`product_id`
LEFT OUTER JOIN
`orders` AS `Order`
ON
`Order`.`id` = `OrderDetail`.`order_id`
WHERE
`ProductAvailability`.`id` = `Product`.`product_availability_id`
AND
`Product`.`online` = true
AND
(`ProductAvailability`.`name` = 'For sale')
OR
((`ProductAvailability`.`name` = 'Sold') AND (DATEDIFF(now(),`Order`.`order_date`) <= 30))
GROUP BY
`Product`.`artist_id`)
AS
`Portfolio`
ON
`Artist`.`id` = `Portfolio`.`artist_id`
WHERE
`Artist`.`person_id` = `Person`.`id`
AND
`Artist`.`online` = true
GROUP BY
`Artist`.`id`
ORDER BY
`Person`.`last_name`, `Person`.`first_name`;
I think that the model is Artist and It has a belongsTo Relationship with , then you could use the CakePHP ORM on this way and hasMany with Portfolio
first you mus distroy the relation between Artist and Portfolio
$this->Artist->unbindModel(array('hasMany'=>array('Portfolio')));
and then Build the relations
$this->Artist->bindModel(array('hasOne'=>array('Portfolio')));
Finally you must create the other relationsships
$this->Artist->bindModel(array(
'belongsTo'=>array(
'Product'=>array(
'clasName'=>'Product',
'foreignKey'=> false,
'conditions'=>'Product.id = Artist.product_id'
),
'ProductAvaibility'=>array(
'clasName'=>'ProductAvaibility',
'foreignKey'=> false,
'conditions'=>'ProductAvaibility.id = Product.product_avaibility_id'
),
'OrderDetail'=>array(
'clasName'=>'OrderDetail',
'foreignKey'=> false,
'conditions'=>'Product.id = OrderDetail.product_id'
),
'Order'=>array(
'clasName'=>'Order',
'foreignKey'=> false,
'conditions'=>'Order.id = OrderDetail.order_id'
),
)
));
Now, when the relationships are done, you could do your find
$this->Artist->find('all', array(
'conditions'=>array(
'Artist.online'=>true
),
'group'=>array(
'Artist.id'
),
'order'=>array(
'Person.last_name',
'Person.first_name',
)
))
I hope it could be useful for you
You should place it in your model. If you haven't read yet, I suggest you to read about skinny controllers and fat models.
class YourModel extends AppModel {
public function getArtistsAndPortfolioCounts() {
return $this->query("SELECT ... ");
}
}
So in your controller:
class ArtistsControllre extends AppController {
public function yourAction() {
debug($this->YourModel->getArtistsAndPortfolioCounts());
}
}
Do not try to build that query using ORM. It will be a disaster in slow motion.
Instead you should try to do that request as "close to metal" as possible. I am not familiar with CakePHP's API ( as i tend to avoid it like black plague ), but you should be able to create a Model which is not related to ActiveRecord, and most likely have access to anything similar to PDO wrapper. Use that to execute the query and map results to variables.
That said, you might want to examine your query ( you seem to have some compulsive quoting sickness ). One of improvements you could do would be stop using id columns in tables.
This whole setup could really benefit from creation of another column in Artists table : portfolio_size. Which you can update each time it should be changed. Yes , it would de-normalize your table, but it also will make this query trivial and blazing fast, with minor costs elsewhere.
As for names of columns, if table Artists has a id, then keep it in column artist_id , and if Products has a foreign key referring to Artists.artist_id then name it too artist_id. Same thing should have same name all over your database. This would additionally let you use in SQL USING statement. Here is a small example :
SELECT
Users.name
Users.email
FROM Users
LEFT JOIN GroupUsers USING (user_id)
LEFT JOIN Groups USING (group_id)
WHERE Groups.name = 'wheel'
I assume that this query does not need explanation as it is a simple many-to-many relationship between users and groups.
You could use the query method, but that method is treated as a last resort, when find or any of the other convenience methods don't suffice.
But it's also possible to manually specify joins in the Cake find method, see the cookbook. I'm not entirely sure, but I believe nested joins are also supported. CONCAT_WS could just be called, with the relevant fields, in the field property of the find method.

Categories