Doctrine_Collection __toString() type of functionality - php

Anyone have any ideas on the best way to convert a Doctrine_Collection to a CSV based on a specific column name?
Example array:
array
0 =>
array
'id' => string '2' (length=1)
'name' => string 'metallica' (length=14)
'created_at' => string '2011-09-02 23:15:15' (length=19)
'updated_at' => string '2011-10-05 02:51:23' (length=19)
1 =>
array
'id' => string '7' (length=1)
'name' => string 'coal chamber' (length=13)
'created_at' => string '2011-09-06 00:24:02' (length=19)
'updated_at' => string '2011-10-05 02:51:11' (length=19)
2 =>
array
'id' => string '14' (length=2)
'name' => string 'slayer' (length=14)
'created_at' => string '2011-10-05 02:48:58' (length=19)
'updated_at' => string '2011-10-05 02:50:15' (length=19)
I would like to end up with:
string 'metallica,coal chamber,slayer' (length=29)
Now I could easily do this with something like:
foreach ($this->getBands()->toArray() as $array) {
$names[] = $array['name'];
}
var_dump(implode(',', $names));
But, I'd like to see if there is a more elegant solution using the built-in methods provided by the Doctrine_Collection class.

Ended up just writing a wrapper method to transform Doctrine_Collections to CSVs based on a specific column:
public static function toString(array $options)
{
$collection = $options['collection'];
$columnName = $options['columnName'];
$separator = (isset($options['separator'])) ? $options['separator'] : ', ';
foreach ($collection->toArray() as $element) {
if (isset($element[$columnName])) {
$columnValues[] = $element[$columnName];
}
}
return (isset($columnValues)) ? implode($separator, $columnValues) : null;
}

Related

MYSQL PHP Array grouping

Having trouble wrapping my head around this conceptually. Still new to this. Basically I have this return from my database :
array (size=456)
0 =>
object(stdClass)[358]
public 'id' => string '2432' (length=4)
public 'symbol' => string '.AMLP' (length=14)
public 'last' => string '0.01' (length=4)
public 'volume' => string '3690' (length=4)
public 'the_date' => string '2019-09-13' (length=10)
public 'the_screener' => string '1' (length=1)
public 'notes' => string 'notes here' (length=149)
1 =>
object(stdClass)[726]
public 'id' => string '2417' (length=4)
public 'symbol' => string '.ARCC' (length=14)
public 'last' => string '2.25' (length=4)
public 'volume' => string '1633' (length=4)
public 'the_date' => string '2019-09-13' (length=10)
public 'the_screener' => string '1' (length=1)
public 'notes' => string 'notes' (length=60)
2 =>
object(stdClass)[726]
public 'id' => string '2447' (length=4)
public 'symbol' => string '.ARCC' (length=14)
public 'last' => string '2.25' (length=4)
public 'volume' => string '1633' (length=4)
public 'the_date' => string '2019-09-12' (length=10)
public 'the_screener' => string '1' (length=1)
public 'notes' => string 'notes here 3' (length=60)
3 =>
What I'm trying to do with PHP is create an object/array that I can work with that displays these items like
AMLP 1 found on dates 2019-09-13
ARCC 2 found on dates 2019-09-13, 2019-09-12
In the end I would display these in a table, but conceptually this is what I'm trying to do.
I've tried creating an array in my foreach I use to display this information in a table, but I was thinking about it and it's probably better to just use the same query data and break it down separately.
So I'd like to create an array like :
Array
(
[1] => Array
(
[id] => 1
[symbol] => ARCC
[dates] => Array
(
[3] => Array
(
2019-09-13
2019-09-12
)
)
)
)
Consider your array is $arrDates. If you want to access properties like object properties
$arrFinal = [];
foreach ($arrDates as $intKey => $obj){
$strSymbol = getSubSymbol($obj->symbol);
if(!isset($arrFinal[$strSymbol])) {
$arrFinal[$strSymbol] = [ 'id' => $obj->id, 'symbol' => $obj->symbol];
}
$arrFinal[$strSymbol]['dates'][] = $obj->the_date;
}
// Now loop throuh arrFinal and do print the statements you want.
foreach($arrFinal as $strSubSymbol => $arrData){
echo $strSubSymbol . ' '. count($arrData['dates']) . ' found on dates ' . implode(',', $arrData['dates']). PHP_EOL;
}
Function to get the desired subpart of symbol
function getSubSymbol($symbol_original){
$symbol = preg_split('/(?=\d)/', $symbol_original, 2); //get everything up until first number or the date in the string in this case.
$symbol_here = substr($symbol[0], 1);
return $symbol_here;
}

Laravel CSV Import inserting with the same ID (Simple Import)

This is my store method which grabs the file and loops through each of the rows:
public function store()
{
$input = Input::file('statuses');
$filename = $input->getRealPath();
$i = 0;
$rows = Excel::load($filename, null, 'ISO-8859-1')->get()->toArray();
foreach($rows as $k => $row)
{
if(!isset($err)) {
if (!$this->repository->create($row))
$err = 'Error importing row ' + $i;
$i++;
}
}
if(isset($err)) {
Flash::error($err);
return Redirect::route('admin.importstatus.index');
}
Flash::success('Statuses Imported!');
return Redirect::route('admin.statuses.index');
}
In my repository, my create method looks like this:
public function create(array $data)
{
// Create the model
$model = $this->model->fill($data);
if ($model->save()) {
return $model;
}
return false;
}
Now, what appears to be happening when I import 6 rows only the final is actually getting inserted into the DB.
If I var_dump in my create method, I am being returned the following:
array (size=7)
'content' => string 'Imported two' (length=12)
'status' => float 0
'user_id' => float 1
'pinned' => float 0
'updated_at' => string '2015-06-28 16:13:22' (length=19)
'created_at' => string '2015-06-28 16:13:22' (length=19)
'id' => int 8
array (size=7)
'content' => string 'Imported three' (length=14)
'status' => float 0
'user_id' => float 1
'pinned' => float 0
'updated_at' => string '2015-06-28 16:13:22' (length=19)
'created_at' => string '2015-06-28 16:13:22' (length=19)
'id' => int 8
array (size=7)
'content' => string 'Imported four' (length=13)
'status' => float 0
'user_id' => float 1
'pinned' => float 0
'updated_at' => string '2015-06-28 16:13:22' (length=19)
'created_at' => string '2015-06-28 16:13:22' (length=19)
'id' => int 8
Notice how each of the ID's are all no. 8 (The next available row in the table). The tables ID is defo AUTO INCREMENT etc so no issues there, I guess its a logic issue? Any ideas?
Seems like you are using the same instance of a model over and over.
Try changing fill():
$this->model->fill($data);
with create():
$this->model->create($data);
With fill() you are only filling the already created model instance with some data. But if you use create() you are first creating a new instance (with a new id), then filling it with data and then saving it.
Important
When using create() you are also persisting it to the database, which means you don't have to save() it manually.

Doctrine hydrated array result

I want to get Doctrine to return a hydrated array with the values being the id for the key, then all values inside an array of results (i.e. if there are multiple items with same ID, then return ID with multiple results in array).
This is the current function I do:
public static function getMedia($em, $entity, $id = NULL)
{
$dql = 'SELECT m.id, m.url, m.nb, m.lang
FROM iMT\Entity\Media m INDEX BY m.id JOIN iMT\Entity\\' . $entity . ' r WITH m.id = r.id';
if($id) {
$dql .= " WHERE r.id = ?1";
}
$q = $em->createQuery($dql);
if($id) {
$q->setParameter(1, $id);
}
return $q->getResult(\Doctrine\ORM\AbstractQuery::HYDRATE_ARRAY);
}
Which returns:
array (size=44)
479600 =>
array (size=4)
'id' => int 479600
'url' => string 'pois/479600/Nonna.JPG' (length=48)
'nb' => null
'lang' => string 'fr' (length=2)
479615 =>
array (size=4)
'id' => int 479615
'url' => string 'pois/479615/Tramways.jpg' (length=51)
'nb' => null
'lang' => string 'fr' (length=2)
479580 =>
array (size=4)
'id' => int 479580
'url' => string 'pois/479580/ATLAS.jpg' (length=48)
'nb' => null
'lang' => string 'fr' (length=2)
479581 =>
array (size=4)
'id' => int 479581
'url' => string 'pois/479581/P'tit_sushi.jpg' (length=54)
'nb' => null
'lang' => string 'fr' (length=2)
However, I need the output to be:
array (size=44)
479600 =>
array (size=2)
array (size=4)
'id' => int 479600
'url' => string 'pois/479600/Nonna.JPG' (length=48)
'nb' => null
'lang' => string 'fr' (length=2)
array (size=4)
'id' => int 479600
'url' => string 'pois/479600/OtherPic.JPG' (length=48)
'nb' => null
'lang' => string 'fr' (length=2)
Would I need to create my own AbstractQuery::HYDRATE_ARRAY or is there something available that does what I need?
I'm using the result by checking if it contains a key that matches the ID of the current item (e.g. if(isset($data[$item])) // where $item = 479600 then output images), maybe there's a better way to check for the results?
EDIT
I've updated my function to return:
$result = $q->getResult(\Doctrine\ORM\AbstractQuery::HYDRATE_ARRAY);
$data = array();
$count = count($result);
for($i = 0; $i < $count; $i++) {
if(!isset($data[$result[$i]['id']])) {
$data[$result[$i]['id']] = array(
$result[$i]
);
} else {
$data[$result[$i]['id']][] = $result[$i];
}
}
return $data;
Which returns something more to what I want:
array (size=44)
479600 =>
array (size=1)
0 =>
array (size=4)
'id' => int 479600
'url' => string 'pois/479600/Nonna.JPG' (length=48)
'nb' => null
'lang' => string 'fr' (length=2)
479577 =>
array (size=2)
0 =>
array (size=4)
'id' => int 479577
'url' => string 'pois/479577/AOMC.JPG' (length=47)
'nb' => null
'lang' => string 'fr' (length=2)
1 =>
array (size=4)
'id' => int 479577
'url' => string 'pois/479577/Buffet AOMC.jpg' (length=54)
'nb' => null
'lang' => string 'fr' (length=2)
Can this be improved? Is there any Doctrine functions that can help, or should I leave my for() loop?
The problem with using INDEX BY together with a JOIN is that the result that doctrine gives you might not contain all data that's fetched from the database.
In your case the database might return multiple rows containing the same value for m.id (because of the JOIN). But each subsequent row containing the same value for m.id will overwrite the previous one (because of the INDEX BY m.id).
Doctrine does not come with a hydrator that can solve this problem out of the box. You shall indeed need to implement your own. Read more about creating custom hydration modes.
Alternative
Another solution would be to not use INDEX BY in this case.
You could write a repository method that translates the result given by Doctrine to the array you want to have. Other parts of your application can then call that repository method.
This is probably easier than creating a custom hydration mode.
Update
The translation can look like this:
$data = array();
foreach ($q->getArrayResult() as $row) {
if (!isset($data[$row['id']])) {
$data[$row['id']] = array();
}
$data[$row['id']][] = $row;
}
return $data;

Double foreach getting only one

Hi how can I retrieve only 'fname' from this
array (size=1)
0 =>
array (size=6)
'tcldbid' => int 7
'tname' =>
object(TeamSpeak3\Helper\String)[252]
protected 'string' => string 'TEST' (length=4)
protected 'position' => int 0
'fcldbid' => int 2
'fname' =>
object(TeamSpeak3\Helper\String)[251]
protected 'string' => string 'Pinky' (length=5)
protected 'position' => int 0
'message' =>
object(TeamSpeak3\Helper\String)[256]
protected 'string' => string 'aaaaaa' (length=6)
protected 'position' => int 0
'timestamp' => int 1395092502
I am using foreach in laravel 4.1 blade
#foreach($p as $l)
#foreach($l as $key => $value)
{{$key . " " . $value}}</br>
#endforeach
#endforeach
This foreach is working but I am getting all data when I want to get fname or message only. Can anyone help me with that? I newbie who started learning php so example would be nice :)
No need to loop, you can just access the correct array element:
$fname = $p[0]['fname'];
$message = $p[0]['message'];

php array count

I have a var dump of my sql query which return the following
I wanna to count in the array below that how many rows of myID = 5 are there. How would I do that. I am using php. Thanks in advance
array
0 =>
object(stdClass)[17]
public 'myID' => string '5' (length=1)
public 'data' => string '123' (length=3)
1 =>
object(stdClass)[18]
public 'myID' => string '5' (length=1)
public 'data' => string '123' (length=3)
2 =>
object(stdClass)[19]
public 'relativeTypeID' => string '2' (length=1)
public 'data' => string '256' (length=3)
3 =>
object(stdClass)[20]
public 'myID' => string '4' (length=1)
public 'data' => string '786' (length=3)
object(stdClass)[21]
public 'myID' => string '4' (length=1)
public 'data' => string '786' (length=3)
Do you always have the same value of data for the same myID? In other words, is data functionally dependant on myID?
If so, you can get the database to do this for you:
SELECT myID, data, COUNT(*) AS cnt
FROM (your query here)
GROUP BY myID, data
This would give you results like the following:
myID data cnt
'5' '123' 3
'2' '256' 1
'4' '786' 2
Or, you can use a foreach statement, like:
$count = 0;
foreach($arr as $item)
{
// Given that your item is an stdClass Object you access its property with "->"
// if an array $item["myID"] instead
if ( $item->myID == '4' )
{
$count ++;
}
}

Categories