Adding two Model Class - yii

In Category Model, getAll method is used for returning all category data. First Active Record in below method $roots have all roots category and $categories have roots category's descendants category. How to add these two Category. Following is getAll Method:
public function getAll()
{
$roots = Category::model()->roots()->findAll();
foreach($roots as $root)
{
$category = Category::model()->findByPk($root->root);
$categories = $category->descendants()->findAll();
}
return $category + $categories; // this does not concatenate, causes error
}

Two problems here:
You are only going to get the category and descendants of the last root in your table because the foreach loop will overwrite the variables each time. To prevent this, you will need to make $categoriy and $categories arrays, and assign like $category[] = ... and $categories[] = .... Or maybe better you could merge them into a composite array at the end of the loop. Maybe something like this:
foreach($roots as $root)
{
$category = Category::model()->findByPk($root->root);
$categories[] = $category;
$categories = array_merge($categories, $category->descendants()->findAll());
}
return $categories;
You now have an array of all root and descendent categories stored as root category, then its descendents, then the next root category, then its descendents, etc.
$category is a Category object as written, and $categories is an array of descendants(). I am hoping that these are Category objects as well. But you can't concatenate an object with an array, you have to use array_merge(), see my example above.

Related

Nested arrays to call map and shorten repeated maps for single object omit property

I have a situation here where I want to omit the nested maps and get it done in one liner . Can it be done using chain or any other ways .
self.workorder.tasklist = _.map(self.workorder.tasklists, function (tasklist) {
tasklist.tasklistGroups = _.map(tasklist.tasklistGroups, function (tasklistGroup, tgKey) {
tasklistGroup.tasklistItems = _.map(tasklistGroup.tasklistItems, function (taskListItem, tKey) {
taskListItem = _.omit(taskListItem, ["open"]);
return taskListItem;
});
return tasklistGroup;
});
return tasklist;
});
I don't want so many nested map calls .
Because you are modifying your items in place I would say this is possible:
_.chain(self.workorder.tasklists).map(function(tasklist) {
return tasklist.tasklistGroups;
}).flatten().map(function(group) {
return group.tasklistItems
}).flatten().forEach(function(item) {
delete item.open;
}).value();
Jsfiddle
The idea is to flatten your array to last level (level of items) and then modify them using forEach.

how to return the sum of a value in a table with where clause in grails 2.5.0

Domain class:
class Transaction {
String roundId
BigDecimal amount
:
}
The SQL we wish to execute the following:
"select sum(t.amount) from transaction t where t.roundId = xxx"
We have been unable to find an example which does not return Transaction rows.
We assume there are two approaches:
Use projections and/or criteria etc? All the examples we have found only return lists of transaction rows, not the sum.
Use raw SQL. How do we call SQL, and get a handle on the BigDecimal it returns?
I tried this:
class bla{
def sessionFactory
def someMethod() {
def SQLsession = sessionFactory.getCurrentSession()
def results = SQLsession.createSQLQuery("select sum(t.credit) from transaction t where t.round_id = :roundId", [roundId: roundId])
But this fails with
groovy.lang.MissingMethodException: No signature of method: org.hibernate.internal.SessionImpl.createSQLQuery() is applicable for argument types: (java.lang.String, java.util.LinkedHashMap)
Also, I have no idea what the return type would be (cant find any documentation). I am guessing it will be a list of something: Arrays? Maps?
==== UPDATE ====
Found one way which works (not very elegant or grails like)
def SQLsession = sessionFactory.getCurrentSession()
final query = "select sum(t.credit) from transaction t where t.round_id = :roundId"
final sqlQuery = SQLsession.createSQLQuery(query)
final results = sqlQuery.with {
setString('roundId', roundId)
list() // what is this for? Is there a better return value?
}
This seems to return an array, not a list as expected, so I can do this:
if (results?.size == 1) {
println results[0] // outputs a big decimal
}
Strangely, results.length fails, but results.size works.
Using Criteria, you can do
Transaction.withCriteria {
eq 'roundId', yourRoundIdValueHere
projections {
sum 'amount'
}
}
https://docs.jboss.org/hibernate/core/3.3/api/org/hibernate/classic/Session.html
Query createSQLQuery(String sql, String[] returnAliases, Class[] returnClasses)
Query createSQLQuery(String sql, String returnAlias, Class returnClass)
The second argument of createSQLQuery is one or more returnAliases and not meant for binding the statement to a value.
Instead of passing your values in the 2nd argument, use the setters of your Query object i.e. setString, setInteger, etc.
results.setInteger('roundId',roundId);

SQL to Magento model understanding

Understanding Magento Models by reference of SQL:
select * from user_devices where user_id = 1
select * from user_devices where device_id = 3
How could I perform the same using my magento models? getModel("module/userdevice")
Also, how can I find the number of rows for each query
Following questions have been answered in this thread.
How to perform a where clause ?
How to retrieve the size of the result set ?
How to retrieve the first item in the result set ?
How to paginate the result set ? (limit)
How to name the model ?
You are referring to Collections
Some references for you:
http://www.magentocommerce.com/knowledge-base/entry/magento-for-dev-part-5-magento-models-and-orm-basics
http://alanstorm.com/magento_collections
http://www.magentocommerce.com/wiki/1_-_installation_and_configuration/using_collections_in_magento
lib/varien/data/collection/db.php and lib/varien/data/collection.php
So, assuming your module is set up correctly, you would use a collection to retrieve multiple objects of your model type.
Syntax for this is:
$yourCollection = Mage::getModel('module/userdevice')->getCollection()
Magento has provided some great features for developers to use with collections. So your example above is very simple to achieve:
$yourCollection = Mage::getModel('module/userdevice')->getCollection()
->addFieldToFilter('user_id', 1)
->addFieldToFilter('device_id', 3);
You can get the number of objects returned:
$yourCollection->count() or simply count($yourCollection)
EDIT
To answer the question posed in the comment: "what If I do not require a collection but rather just a particular object"
This depends if you still require both conditions in the original question to be satisfied or if you know the id of the object you wish to load.
If you know the id of the object then simply:
Mage::getModel('module/userdevice')->load($objectId);
but if you wish to still load based on the two attributes:
user_id = 1
device_id = 3
then you would still use a collection but simply return the first object (assuming that only one object could only ever satisfy both conditions).
For reuse, wrap this logic in a method and place in your model:
public function loadByUserDevice($userId, $deviceId)
{
$collection = $this->getResourceCollection()
->addFieldToFilter('user_id', $userId)
->addFieldToFilter('device_id', $deviceId)
->setCurPage(1)
->setPageSize(1)
;
foreach ($collection as $obj) {
return $obj;
}
return false;
}
You would call this as follows:
$userId = 1;
$deviceId = 3;
Mage::getModel('module/userdevice')->loadByUserDevice($userId, $deviceId);
NOTE:
You could shorten the loadByUserDevice to the following, though you would not get the benefit of the false return value should no object be found:
public function loadByUserDevice($userId, $deviceId)
{
$collection = $this->getResourceCollection()
->addFieldToFilter('user_id', $userId)
->addFieldToFilter('device_id', $deviceId)
;
return $collection->getFirstItem();
}

Adding a index to collection using EF 4.1 and XAML (For a highscore table)

I have a webservice I call from a WP7 app. I get a list of high scores in a table (name/score).. What is the simpliest way to add a 3rd column on the far left which is simply the row?
Do I need to add a property to the entity? Is there someway to get the row #?
I tried these things below with no success..
[OperationContract]
public List<DMHighScore> GetScores()
{
using (var db = new DMModelContainer())
{
// return db.DMHighScores.ToList();
var collOrderedHighScoreItem = (from o in db.DMHighScores
orderby o.UserScore ascending
select new
{
o.UserName,
o.UserScore
}).Take(20);
var collOrderedHighScoreItem2 = collOrderedHighScoreItem.AsEnumerable().Select((x, i) => new DMHighScoreDTO
{
UserName = x.UserName,
UserScore = x.UserScore
}).ToList();
}
}
[DataContract]
public class DMHighScoreDTO
{
int Rank;
string UserName;
string UserScore;
}
So lets assume you want to load top 100 users in leaderboard and you want to have their rank included:
[OperationContract]
public List<ScoreDto> GetTop100()
{
// Linq to entities query
var query = (from u from context.Users
order by u.Score
select new
{
u.Name,
u.Score
}).Take(100);
// Linq to objects query from working on 100 records loaded from DB
// Select with index doesn't work in linq to entities
var data = query.AsEnumerable().Select((x, i) => new ScoreDto
{
Rank = i + 1,
Name = x.Name,
Score = x.Score
}).ToList();
return data;
}
what will the row number be used for? if this is for ordering might I suggest adding a column named Order, then map the column to your entity.
if you require a row index, you could also call the .ToList() on the query and fetch the index locations for each entity.
Edit:
you could add the Rank property and set it to Ignore. This will enable you to go through the collection set the rank with a simple for loop. This will also not be persisted in the database. It will also not have any required columns in the database.
It does add an extra iteration.
the other way to go about it. This would be to add the rank number in the generated UI and not in the data collection being used to bind.

Call to a member function num_rows() on a non-object [duplicate]

This question already has answers here:
Call to a member function on a non-object [duplicate]
(8 answers)
Closed 8 years ago.
I need to get the number of rows of a query (so I can paginate results).
As I'm learning codeigniter (and OO php) I wanted to try and chain a ->num_rows() to the query, but it doesn't work:
//this works:
$data['count'] = count($this->events->findEvents($data['date'], $data['keyword']));
//the following doesn't work and generates
// Fatal Error: Call to a member function num_rows() on a non-object
$data['count2'] = $this->events->findEvents($data['date'], $data['keyword'])->num_rows();
the model returns an array of objects, and I think this is the reason why I can't use a method on it.
function findEvents($date, $keyword, $limit = NULL, $offset = NULL)
{
$data = array();
$this->db->select('events.*, venues.*, events.venue AS venue_id');
$this->db->join('venues', 'events.venue = venues.id');
if ($date)
{
$this->db->where('date', $date);
}
if ($keyword)
{
$this->db->like('events.description', $keyword);
$this->db->or_like('venues.description', $keyword);
$this->db->or_like('band', $keyword);
$this->db->or_like('venues.venue', $keyword);
$this->db->or_like('genre', $keyword);
}
$this->db->order_by('date', 'DESC');
$this->db->order_by('events.priority', 'DESC');
$this->db->limit($limit, $offset); //for pagination purposes
$Q = $this->db->get('events');
if ($Q->num_rows() > 0)
{
foreach ($Q->result() as $row)
{
$data[] = $row;
}
}
$Q->free_result();
return $data;
}
Is there anything that i can do to be able to use it? EG, instead of $data[] = $row; I should use another (OO) syntax?
You function findEvents is returning $data which you declared to be an array at the start. This is not an object and does not allow you to access functions using the member access syntax.
To count the number of values in an array see count
Also, from what I understand you not only want the query results returned as an array, but you want to be able to access methods on the result $Q = $this->db->get('events'); However this is not possible as this is a local variable and it is not being returned out. The function here has a result type of array and is not an object and thus has no access to anything, but the array. One solution to this is to return an associative array:
return array("results" => $data, "count" => $Q->num_rows());
Then use array syntax to access the count or the results. Another option is return a new object that has result and count fields and use accessor methods to get to those.