doctrine 2 findby function , get keys and values - doctrine

can i get the keys and values dynamically.
in php, you would: foreach ($array as $key => $value)
but you can do this for :
$this->_em->getRepository('Members')->findBy(array('id' =>5));
any way to get the keys from this with their values..?
i can do this by turning it into an array and extract it but i wouldnt get any association results inside the array ..
i want to do this as i want to be able to extract all properties and values of this object and extract all other objects within it too..

Ih had the same issue as you now have and after some research i just found a solution which you might be interested.what you need is an associative array of keys/values and not an object.findBy()method only returns entity OBJECT.so you will need to use DQL(doctrine query language).
//create a QueryBuilder instance
$qb = $this->_em->createQueryBuilder();
$qb->add('select', 'a')
//enter the table you want to query
->add('from', 'Members a')
->add('where', 'a.id = :id')
//order by username if you like
//->add('orderBy', 'a.username ASC')
//find a row with id=5
->setParameter('id', '5');
query = $qb->getQuery();
//if you dont put 3 or Query::HYDRATE_ARRAY inside getResult() an object is returned and if you put 3 an array is returned
$accounts = $query->getResult(3);
from doctrine documentation:
13.7.4. Hydration Modes
Each of the Hydration Modes makes assumptions about how the result is
returned to user land. You should know about all the details to make
best use of the different result formats:
The constants for the different hydration modes are:
Query::HYDRATE_OBJECT
Query::HYDRATE_ARRAY
Query::HYDRATE_SCALAR
Query::HYDRATE_SINGLE_SCALAR
To learn more about 'The Query Builder' please refer to doctrine2 documentation
Update:
To fetch associated Entities you will need to define fetch joins.Here is an example provided in doctrine documentation:
$dql = "SELECT b, e, r, p FROM Bug b JOIN b.engineer e ".
"JOIN b.reporter r JOIN b.products p ORDER BY b.created DESC";
$query = $entityManager->createQuery($dql);
$bugs = $query->getArrayResult();
foreach ($bugs AS $bug) {
echo $bug['description'] . " - " . $bug['created']->format('d.m.Y')."\n";
echo " Reported by: ".$bug['reporter']['name']."\n";
echo " Assigned to: ".$bug['engineer']['name']."\n";
foreach($bug['products'] AS $product) {
echo " Platform: ".$product['name']."\n";}
echo "\n";}
The code mentioned above will fetch your entities as array of arrays and you can do whatever you want with $keys and $values.
Hope this helps...

Related

Update a database field with Joomla UpdateObject method with a calculated field from same table

Right to the point.
I need to update a field in the database using the field to calculate the new value first.
E.g of fields: https://i.stack.imgur.com/FADH6.jpg
Now I am using the Joomla updateObject function. my goal is to take the "spent" value from the DB table without using a select statement.
Then I need to calculate a new value with it like (spent + 10.00) and update the field with the new value. Check out the code below:
// Create an object for the record we are going to update.
$object = new stdClass();
// Must be a valid primary key value.
$object->catid = $item['category'];
$object->spent = ($object->spent - $item['total']);
// Update their details in the users table using id as the primary key.
$result = JFactory::getDbo()->updateObject('#__mytable', $object, 'catid');
The bit which i need to make the calculation on is
$object->spent = ($object->spent - $item['total']);
I realise I can use a seperate insert statement but I am wondering if there is a better way. Any help is much appreciated.
It needs to work like this, WITHOUT THE SELECT (working example)
$query = $db->getQuery(true);
$query->select($db->quoteName('spent'));
$query->from($db->quoteName('#__mytable'));
$query->where($db->quoteName('catid')." = ". $item['category']);
// Reset the query using our newly populated query object.
$db->setQuery($query);
$oldspent = $db->loadResult();
// Create an object for the record we are going to update.
$object = new stdClass();
// Must be a valid primary key value.
$object->catid = $item['category'];
$object->spent = ($oldspent - $item['total']);
// Update their details in the users table using id as the primary key.
$result = JFactory::getDbo()->updateObject('#__mytable', $object, 'catid');
The sticking point with trying to use updateObject('#__mytable', $object, 'catid'); is that your query logic needs to reference the column name in the calculation to assign the "difference" as the new value. The raw mysql query syntax to update a column value with the value minus another value is like:
"`spent` = `spent` - {$item['total']}"
updateObject() will convert spent - {$item['total']} to a literal string, the database will expect a numeric value, so UPDATE results in a 0 value recorded. In other words, $db->getAffectedRows() will give you a positive count and there will be no errors generated, but you don't get the desired mathematical action.
The workaround is to discard updateObject() as a tool and build an UPDATE query without objects -- don't worry it's not too convoluted. I'll build in some diagnostics and failure checking, but you can remove whatever parts that you wish.
I have tested the following code to be successful on my localhost:
$db = JFactory::getDBO();
try {
$query = $db->getQuery(true)
->update($db->quoteName('#__mytable'))
->set($db->quoteName("price") . " = " . $db->qn("price") . " - " . (int)$item['total'])
->where($db->quoteName("catid") . " = " . (int)$item['category']);
echo $query->dump(); // see the generated query (but don't show to public)
$db->setQuery($query);
$db->execute();
if ($affrows = $db->getAffectedRows()) {
JFactory::getApplication()->enqueueMessage("Updated. Affected Rows: $affrows", 'success');
} else {
JFactory::getApplication()->enqueueMessage("Logic Error", 'error');
}
} catch (Exception $e) {
JFactory::getApplication()->enqueueMessage("Query Syntax Error: " . $e->getMessage(), 'error'); // never show getMessage() to public
}
Here is a StackOverflow page discussing the mysql subtraction logic: update a column by subtracting a value

Sorting a field based on several values in Laravel

I have an array of city codes
$cities=[9,12,14,2,3,4,5,6,8,10,11,13]
My posts table has a foreign key named city_id
I want sorting posts based on the values of this array
In this way: the first posts of the city 9 then the posts of the city 12 and then posts of city 14 and etc to be loaded
I tried using this method but this is wrong
$posts->orderByRaw('city_id in ? desc',$cities);
Can you help me find the best solution?
The only way i can i think of doing something like that(at least right now) is by doing something like so
$all_posts = [];
$cities=[9,12,14,2,3,4,5,6,8,10,11,13];
foreach ($cities as city) {
$city_posts = Post::whereRaw('city_id = ?', $city)->orderByRaw('created_at DESC');
array_push($all_posts, $city_posts);
}
dd($all_posts);
1st find all the posts relevant to cities and then sort w.r.t given order like
$cities = [9,12,14,2,3,4,5,6,8,10,11,13]; // order you'd like to see with posts
$posts = Post::whereIn('city_id', $cities)->sort(function($a, $b) uses ($cities) {
$pos_a = array_search($a->getAttributes()['city_id'], $cities);
$pos_b = array_search($b->getAttributes()['city_id'], $cities);
return $pos_a - $pos_b;
})->get();
// $posts contains the required order with city_ids
You can use raw query with "CASE something THEN index" this way you tell the query to see something as index so you can assign 0 to the first item in your array.
$sql .= "....";
foreach($cities as $index => $city) {
$sql .= "CASE {$city} THEN {$index}";
}
$sql .= "....";
Thanks to the friends solution,I used this method, and I think it's less complicated than the suggested methods of friends
$posts=$posts->orderByRaw('FIELD(city_id, '.$cities->implode( ', ').') asc')->orderBy('created_at','desc')->get();

Only one row is returned using where in with comma seperated value in Laravel raw query

I am developing a php project using Laravel 5.2. In my app I am retrieving records from database using manual query. But I am having a problem with retrieving records by using where in statement with csv.
Example how I am retrieving
$csv = "1,3,5";
$sql = "SELECT * FROM `items` WHERE `id` IN (?)";
$rows = DB::select($sql,[$csv]);
As you can see above I am retrieving three rows. But it returns only one row where id is 1. Why is that?
You can't do it like that. Each entry in your csv is a separate parameter, so for your code you would actually need IN (?, ?, ?), and then pass in the array of values. It would be pretty easy to write the code to do this (explode the string to an array, create another array of question marks the same size, put it all together).
However, you are using Laravel, so it would be easier to use the functionality Laravel provides to you.
Using the query builder, you can do this like:
$csv = "1,3,5";
// turn your csv into an array
$ids = explode(",", $csv);
// get the data
$rows = DB::table('items')->whereIn('id', $ids)->get();
// $rows will be an array of stdClass objects containing your results
dd($rows);
Or, if you have an Item model setup for your items table, you could do:
$items = Item::whereIn('id', $params)->get();
// $items will be a Collection of Item objects
dd($items);
Or, assuming id is the primary key of your items table:
// find can take a single id, or an array of ids
$items = Item::find($params);
// $items will be a Collection of Item objects
dd($items);
Edit
If you really want to do it the manual way, you could use a loop, but you don't need to. PHP provides some pretty convenient array methods.
$csv = "1,3,5";
// turn your csv into an array
$ids = explode(",", $csv);
// generate the number of parameters you need
$markers = array_fill(0, count($ids), '?');
// write your sql
$sql = "SELECT * FROM `items` WHERE `id` IN (".implode(',', $markers).")";
// get your data
$rows = DB::select($sql, $ids);

Laravel query optimization

I have a query in laravel:
...
$query = $model::group_by($model->table().'.'.$model::$key);
$selects = array(DB::raw($model->table().'.'.$model::$key));
...
$rows = $query->distinct()->get($selects);
this works fine and gives me the fields keys' that I need but the problem is that I need to get all the columns and not just the Key.
using this:
$selects = array(DB::raw($model->table().'.'.$model::$key), DB::raw($model->table().'.*'));
is not an option, cuz it's not working with PostgreSQL, so i used $rows to get the rest of columns:
for ($i = 0; $i<count($rows); $i++)
{
$rows[$i] = $model::find($rows[$i]->key);
}
but as you see this is it's so inefficient, so what can i do to make it faster and more efficient?
you can find the whole code here: https://gist.github.com/neo13/5390091
ps. I whould use join but I don't know how?
Just don't pass anything in to get() and it will return all the columns. Also the key is presumably unique in the table so I don't exactly understand why you need to do the group by.
$models = $model::group_by( $model->table() . '.'. $model::$key )->get();

Get values from a doctrine collection with composite key

4 for on on my applications with Doctrine.
In there I'm using the following doctrine command to retrieve person object collection
//query
$people = $q->execute();
This return 20 objects. The primary key of the person object is a composite key with three attributes. Those are
id
department_id
name
I need to get person objects by searching in it as follows.
$id = 10;
$department_id = 1;
$name = "abc";
$people->get($id, $department_id, $name);
But this doesn't work and not give correct results. I tried with this and it gives null results which seems my collections primary key is not set.
$people->getKeyColumn();
I don't want to go through a foreach loop in collection and process it because when I deal with about 500 people, it slow down my application.
Can some one help me with this issue to get values from a doctrine collection.
Can you use something like this?
$people = Doctrine::getTable('Persons')
->createQuery()
->where('id = ? AND department_id = ? AND name = ?', array($id, $department_id, $name))
->execute();
It will get you a DoctrineCollection already filtered by the parameters provided.
'Persons' here is a Doctrine model name, not a table name from mySQL.
You can also use Doctrine's magic finders findBy*():
$people = Doctrine_Core::getTable('Persons')
->findByIdAndDepartmentIdAndName($id, $department_id, $name);

Resources