Get an array of arrays in PHP with a loop - php

I am working on Symfony 3.4 in PHP 5.6.
Here is the context of my problem:
I have an "information" table that contains several lines. I want to sort these lines and display them according to a certain column called "Zone". So the goal is to have for example
"Zone 1"
* Lines of information corresponding to this area "
"Zone 2"
* Lines of information corresponding to this area "
...
I realized my functions in the Repository, and I also made the layout under Twig. Everything worked. All I had to do was optimize my code on the controller to make it cleaner.
My idea was therefore:
Retrieve an array containing all the existing distinct areas by a query.
Loop on this array using each value of the array as a parameter for the SQL query that retrieves the rows corresponding to the passed field and retrieve them in an array variable
Make an array_push () of the array of each zone, in another array that will contain the array of each zone.
But I can't. This is my code
Repository :
public function getInformationsZone($zone)
{
$queryBuilder = $this->createQueryBuilder("i")
->where("i.zone = :zone")
->orderBy("i.updatedAt","DESC")
->orderBy("i.criticite","DESC")
->setParameter('zone',$zone);
return $queryBuilder->getQuery()->getResult();
}
public function getZonesActives()
{
$queryBuilder = $this->createQueryBuilder("i")
->select("i.zone")
->distinct(true);
return $queryBuilder->getQuery()->getResult();
}
controller
/**
* Lists all information entities.
*
* #Route("/", name="informations_index")
* #Method("GET")
*/
public function indexAction()
{
$em = $this->getDoctrine()->getManager();
$information = $em->getRepository('PagesBundle:Information')->findAll();
$listZones = $this->getDoctrine()->getRepository('PagesBundle:Information')->getZonesActives();
$tabInfos = array();
foreach($listZones as $key=>$value)
{
$zone = $this->getDoctrine()->getRepository('PagesBundle:Information')->getInformationsZone($value);
array_push($tabInfos,$zone);
}
// This is what i did just before
/* $infosZone1 = $this->getDoctrine()->getRepository('PagesBundle:Information')->getInformationsZone("Zone 1");
$infosZone2 = $this->getDoctrine()->getRepository('PagesBundle:Information')->getInformationsZone("Zone 2");
$infosZone3 = $this->getDoctrine()->getRepository('PagesBundle:Information')->getInformationsZone("Zone 3");
$tabInfos = array($infosZone1,$infosZone2,$infosZone3);*/
return $this->render('information/index.html.twig', array(
/* 'information' => $information,
'infosZone1'=> $infosZone1,
'infosZone2'=> $infosZone2,
'infosZone3'=> $infosZone3,*/
'tabInfos'=>$tabInfos,
));
}
I've this error :
An exception occurred while executing 'SELECT i0_.id AS id_0, i0_.contenu AS contenu_1, i0_.updated_at AS updated_at_2, i0_.zone AS zone_3, i0_.titre AS titre_4, i0_.criticite AS criticite_5 FROM information i0_ WHERE i0_.zone = ? ORDER BY i0_.criticite DESC' with params ["Zone 1"]:
SQLSTATE[HY093]: Invalid parameter number: parameter was not defined

Replace:
$zone = $this->getDoctrine()->getRepository('PagesBundle:Information')->getInformationsZone($value);
With this:
$zone = $this
->getDoctrine()
->getRepository('PagesBundle:Information')
->getInformationsZone($value->getZone());
You are passing the all zone entity to the getInformationsZone method.
So to get the title of the zone, you must call the getter of the zone.
$value to $value->getZone();
Edit: So, just change $value->getZone() to $value['zone'];

Related

Craft CMS - How to include asset fields in PHP entry query?

I am trying to figure out how to return asset field(s) in a PHP entry query. Also if I could learn how to return "custom fields" when returning an Object that would be great too! Right now I am having to specify asArray() to even get access to most of my "custom fields"
As as example: I have a Vehicle Entry which has a custom field with the handle of price (number field) and another custom field (asset field) with the handle of images. When I execute the query without specifying the asArray() param I cannot find the custom fields included in the results. But if I specify asArray() then they are all there with the exception of my images field which I think is because it is an asset field or possible because it can be a collection of images? How can I make sure all the fields tied to an entry are returned in my query?
Here are some examples of queries and the corresponding results:
PHP Query without asArray():
$entry_query = Entry::find()
->section('inventory')
->all();
Returns:
PHP Query results with asArray():
$entry_query = Entry::find()
->section('inventory')
->asArray();
Returns:
However even when specifing to make the result set an array I still cannot figure out how to include the 'images' field.
I am having a difficult time finding an answer via the documentation or an example of someone doing the same. All the examples i find are for the template side in twig.
Thanks!
This is what I ended up with:
$vehicles = array(); // empty container to hold our modified entries
// Lets Query our Inventory - all of it
/** #var array $entry_query the name of our query to get our inventory - return a list of inventory after we execute query */
$entries = Entry::find()
->section('inventory')
->all();
foreach($entries as $entry) {
/*
* Let's get all our custom fields we want
* to include with our entries
*/
// Get our image field and add to result set - because it's an asset field this returns a query object
$ourimages = $entry->images->all(); // get all our images
$price = $entry->price;
$featured = $entry->featureThisVehicle;
$make = $entry->make;
$model = $entry->model;
$year = $entry->year;
$description = $entry->description;
$inventoryStatus = $entry->inventoryStatus;
$bodyStyle = $entry->bodyStyle;
$color = $entry->color;
$miles = $entry->miles;
$vin = $entry->vin;
$stkid = $entry->stkid;
// cast out entry object as an array - so we can add props to it
$entry = (array)$entry;
// add our custom fields to our newly casted entry array
$entry['images'] = $ourimages;
$entry['price'] = $price;
$entry['featured'] = $featured;
$entry['make'] = $make;
$entry['model'] = $model;
$entry['year'] = $year;
$entry['description'] = $description;
$entry['inventoryStatus'] = $inventoryStatus;
$entry['bodyStyle'] = $bodyStyle;
$entry['color'] = $color;
$entry['miles'] = $miles;
$entry['vin'] = $vin;
$entry['stkid'] = $stkid;
// Recast back to object just cause (not really necessary since we are json_encode'ing this)
$entry = (object)$entry;
array_push($vehicles, $entry);
}
return json_encode($vehicles);
Yii has an array helper function that simplifies this. See this stack exchange entry – it’s essentially the same approach as the one you describe, but simpler (less queries, less lines of code).

Get Record Localization within backend module

I'm struggling with the TYPO3 l10n and the modifying of localized records.
Short Question:
How can I get the localized record from my extbase model?
In more detail:
I am using a backend module to modify multiple records at the same time. At the moment it only works for origin records. But the customer wants to use this module to edit localized records also.
This is what I tryed so far:
An array is passing the origin uid's to the repository class. Depending on the SysLanguageUid I am doing a findByUid if its an origin record and if the SysLanguageUid is anything higher than 0 I do the following query:
protected function findByUidAndSysLanguageUid($uid, $sysLanguageUid) {
$query = $this->createQuery();
$query->matching(
$query->equals('l10n_parent', $uid),
$query->equals('sys_language_uid', $sysLanguageUid)
);
return $query->execute();
}
This query works fine for the first record. But what really confuses me is, ongoing from the second entry the query returns the origin records (even while the sys_language_uid in the query is set to >0).
Any ideas how to handle this?
PS: If you need some more information then let me know it.
UPDATE:
So far I managed it to get the raw query from the above constraint:
Query of the first record:
SELECT tx_extkey_domain_model_mymodel.*
FROM tx_extkey_domain_model_mymodel
WHERE (tx_extkey_domain_model_mymodel.l10n_parent = '133' AND tx_extkey_domain_model_mymodel.sys_language_uid = '1') AND
(tx_extkey_domain_model_mymodel.sys_language_uid IN (1, -1) OR
(tx_extkey_domain_model_mymodel.sys_language_uid = 0 AND
tx_extkey_domain_model_mymodel.uid NOT IN (SELECT tx_extkey_domain_model_mymodel.l10n_parent
FROM tx_extkey_domain_model_mymodel
WHERE tx_extkey_domain_model_mymodel.l10n_parent > 0 AND
tx_extkey_domain_model_mymodel.sys_language_uid = 1 AND
tx_extkey_domain_model_mymodel.deleted = 0))) AND
tx_extkey_domain_model_mymodel.hidden = 0 AND (tx_extkey_domain_model_mymodel.starttime 1479390060) AND
tx_extkey_domain_model_mymodel.deleted = 0
ORDER BY tx_extkey_domain_model_mymodel.name ASC
LIMIT 1;
Query of the second record:
SELECT tx_extkey_domain_model_mymodel.*
FROM tx_extkey_domain_model_mymodel
WHERE (tx_extkey_domain_model_mymodel.l10n_parent = '134' AND tx_extkey_domain_model_mymodel.sys_language_uid = '1') AND
(tx_extkey_domain_model_mymodel.sys_language_uid IN (1, -1) OR
(tx_extkey_domain_model_mymodel.sys_language_uid = 0 AND
tx_extkey_domain_model_mymodel.uid NOT IN (SELECT tx_extkey_domain_model_mymodel.l10n_parent
FROM tx_extkey_domain_model_mymodel
WHERE tx_extkey_domain_model_mymodel.l10n_parent > 0 AND
tx_extkey_domain_model_mymodel.sys_language_uid = 1 AND
tx_extkey_domain_model_mymodel.deleted = 0))) AND
tx_extkey_domain_model_mymodel.hidden = 0 AND (tx_extkey_domain_model_mymodel.starttime 1479390360) AND
tx_extkey_domain_model_mymodel.deleted = 0
ORDER BY tx_extkey_domain_model_mymodel.name ASC
LIMIT 1;
UPDATE 2
This now confuses me even more...
I put both of the sql queries into heidisql and run them manually. They work perfectly!
So it seems like there is no problem with the query itself.
UPDATE 3
This is the method of the repository which gets called by the controller.
/**
* #param array $parentUidCollection
* #param int $L
*/
protected function updateByCollection(array $parentUidCollection, $L = 0) {
//$L is the language $_GET parameter. cant use TSFE because of inside of a backend module
if($L > 0) {
$this->setTempQuerySettings($L);
}
foreach ($parentUidCollection as $parentUid){
$myModel = $this->findTranslatedByParentId($parentUid)->getFirst();
$myModel->setDescription('foo');
$this->update($myModel);
}
}
My defaultQuerySettings are overwritten in the third line if the actual language is not the default language.
/**
* #param $sysLanguageUid
*/
protected function setTempQuerySettings($sysLanguageUid) {
/** #var \TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings $tempQuerySettings */
$this->originalQuerySettings = $this->objectManager->get('TYPO3\\CMS\\Extbase\\Persistence\\Generic\\Typo3QuerySettings');
$tempQuerySettings = clone $this->originalQuerySettings;
$tempQuerySettings->setRespectStoragePage(false);
$tempQuerySettings->setRespectSysLanguage(true);
$tempQuerySettings->setLanguageUid($sysLanguageUid);
$tempQuerySettings->setLanguageMode(false);
$tempQuerySettings->setLanguageOverlayMode(false);
$this->setDefaultQuerySettings($tempQuerySettings);
}
And now with the function suggessted by Toke Herkild but without the query settings inside. they are set in the above snipped.
/**
* #param int|string $parentUid
* #return array|\TYPO3\CMS\Extbase\Persistence\QueryResultInterface
*/
public function findTranslatedByParentId($parentUid)
{
$query = $this->createQuery();
$query->matching($query->equals('l10n_parent', $parentUid));
return $query->execute();
}
UPDATE 4:
After executing the code the database looks like this:
The 100 uid's are the origin and the 200 are the localized records in this picture.
NOTICE: Below solution would work except for this bug:
https://forge.typo3.org/issues/47192
Maybe just make it simple, inside your ModelRepository do something like:
public function findTranslatedByParentId($parentUid) {
$query = $this->createQuery()
$qrySettings = $query->getQuerySettings();
$qrySettings->setLanguageMode('ignore');
$qrySettings->setLanguageOverlay(FALSE);
$query->setDefaultQuerySettings($qrySettings);
return $query->matching($query->equals('l18n_parent', $parentUid))->execute();
}
You need to disable the persistence layers language handling or it believes you try to fetch the localized version of the record for your current sys_language.

slim framework calling functions within functions

I don't know if you're supposed to refer to them as "functions" but...
My when my add_record function is called, I want to re-use another function I have made which gets a list of team names from the database;
public function add_record($data){
$teamnames = function get_teamnames;
print_r($teamnames);
exit;
/*
$this->db->query('INSERT INTO reports(`date`,refereename, refereeteam, hometeam, homecaptain, awayteam) VALUES (
"'.strtotime($data['date']).'",
"'.$data['refereename'].'",
"'.$data['refereeteam'].'",
"'.$data['hometeam'].'",
"'.$data['captainname'].'",
"'.$data['awayteam'].'"
)');
*/
}
And here is my get_teamnames function (from within the same file)
public function get_teamnames(){
//Get team data from database, place into resource.
$teamsData = $this->db->query('SELECT * FROM teamnames ORDER BY teamname ASC');
// Array which we will return to the Slim router
$teams = array();
// PLace all the teams from the mysql resource into the array
while ($row = $teamsData->fetch_object()) {
$teams[] = $row;
}
// Return the teams array
return $teams;
}
The reason I want the list of teamnames available in my add_record function, is so that I can do some validation on the $data and make sure that what's being submitted is only one of those team names stored in the database.
Assuming these functions are in the same class and you are using an object of the class, just do:
$teamnames = $this->get_teamnames();

Cannot pass parameter 2 by reference

The code:
final class SimpleEventManager {
private $listeners = array();
public function listen($event, $callable) {
$this->listeners[$event][] = $callable;
}
public function fire($event, array $arguments = array()) {
foreach ($this->listeners[$event] as $listener) {
call_user_func_array($listener, $arguments);
}
}
}
$manager = new SimpleEventManager;
$manager->listen('sql', function($sql) {
$sql .= " order by username desc";
});
$sql = "select * from users";
$manager->fire('sql', array($sql));
var_dump($sql); // is: select * from users
// want: select * from users order by username desc
So basically i want my event listeners to be able to modify the arguments that come in. I've tried doing things like array &$arguments = array() but then I'm getting the Cannot pass parameter 2 by reference error.
Does anyone know how I can solve this?
You can't pass it by reference because only variable may be passed by reference. The literal array($sql) is clearly not a variable.
That said, this isn't the problem.
In fact, there's a lot of problems, mostly because of $sql being "copied" so many times:
When creating the array($sql)
When calling fire() (due to not being passed by reference)
When calling the anonymous function (again, not being passed by reference)
First of all you need to define your array as a variable, such as $arr = array(&$sql);
Then keep your current "fix" of passing &$arguments by reference.
Finally, adjust your anonymous function to function(&$sql) to also work by reference.
All in all, this could be made a lot easier if your code weren't so convoluted ;)

zend_db_table how do i select all distinct values for a specific column

Hi guys i believe this could turn out to be trivial but i have the following code
$response = $groupsmapper->getDbTable()->fetchAll(
$groupsmapper->getDbTable()->select('group_area_residence')
->distinct()
which is supposed to get me all the distinct group_area_residence. However it fetches all the columns for the group.
I am using zend_db_table btw. How do i fix this?
According to select() in Zend/Db/Table/Abstract.php, it checks whether to include the from part, instead of getting the field name
/**
* Returns an instance of a Zend_Db_Table_Select object.
*
* #param bool $withFromPart Whether or not to include the from part of the select based on the table
* #return Zend_Db_Table_Select
*/
public function select($withFromPart = self::SELECT_WITHOUT_FROM_PART)
{
require_once 'Zend/Db/Table/Select.php';
$select = new Zend_Db_Table_Select($this);
if ($withFromPart == self::SELECT_WITH_FROM_PART) {
$select->from($this->info(self::NAME), Zend_Db_Table_Select::SQL_WILDCARD, $this->info(self::SCHEMA));
}
return $select;
}
See if the below code snippet helps (replacing table_name by desired one)
$select = $groupsmapper->getDbTable()
->select()
->distinct()
->from(array('table_name'), array('group_area_residence'));
$response = $groupsmapper->getDbTable()->fetchAll($select);

Categories