PHP Mehrdimensionale Arrays ausgeben -> PHP nach AngularJS

Endless Storm

Commander
Registriert
Dez. 2008
Beiträge
2.139
Hallo zusammen,

ich habe mal wieder eine Frage, und zwar geht es um das Auslesen von einer MongoDB mit PHP um sie dann an AngularJS zu übergeben. Die Daten liegen in der MongoDB wie folgt vor (Kopie aus dem cmd-Fenster):

Code:
{
        "_id" : ObjectId("58849e19310af72fa3c67304"),
        "userid" : "100",
        "recipename" : "Spaghettis",
        "persons" : "2",
        "preparationTime" : "40",
        "ingredients" : [
                {
                        "amount" : "150",
                        "unit" : "Gramm",
                        "ingredient" : "Spaghetti"
                },
                {
                        "amount" : "200",
                        "unit" : "Milliliter",
                        "ingredient" : "Soße"
                }
        ],
        "preparation" : "Spaghettis kochen, Soße erhitzen. Heiß servieren."
}

Außer ingredients sind alle Daten eindimensional. ingredients selbst kann ein, oder unbestimmt viele Inhalte haben.
Die Daten müssen dabei wie folgt übertragen werden (der Übersichtlichkeit in eigene Zeilen gesetzt):
Code:
[{"_id": "58849f88310af72fa3c67305", 
"userid": "100", 
"recipename": "Spaghettis", 
"persons": "2", 
"preparationTime": "40", 
"ingredients": [{
	"amount": "1500",
	"unit": "Gramm",
	"ingredient": "Spaghetti"},
	{"amount": "200",
	"unit": "Milliliter",
	"ingredient": "Soße"}]
"preparation": "Spaghettis kochen, Soße erhitzen. Heiß servieren."
}]

Frage 1: Wie müssen die Klammern von ingredients gesetzt werden, damit sie in JavaScript auch als Array im Array erkannt werden? Sind die so korrekt?

Frage 2: Wie löse ich das Auslesen vom §result in PHP?
PHP:
// dummy for testing
 $userid = '100';

// add all request-objects to array
$query = array(
	'userid' => $userid
);

$result = $collection->find($query);

if ($collection->count($query)) {
	$data = '';
	foreach ($result as $entry) {
		// $send[] = add following values to the array
		$send = $send.
			'{"_id": "'.$entry['_id'].'", '.
			'"userid": "'.$entry['userid'].'", '.
			'"recipename": "'.$entry['recipename'].'", '.
			'"persons": "'.$entry['persons'].'", '.
			'"preparationTime": "'.$entry['preparationTime'].'", '.
			'"ingredients": "[';
			foreach ($entry['ingredients'] as $property) {
				$data = $data.
				'{"amount": "'.$property['amount'].'", '.
				'"unit": "'.$property['unit'].'", '.
				'"ingredient": "'.$property['ingredient'].'"},';				
			}
			$data = substr($data, 0, -1);
			
			$send = $send.$data.
			'],"preparation": "'.$entry['preparation'].'"},';			
			$data = '';
	}
	// kill the last comma
	$send = substr($send, 0, -1);
	$send = '['.$send.']';	
} else {
	$send = null;
}
print_r($send);

Die Ausgabe der find.php erzeugt im Browser folgende Ausgabe für zwei vorliegende Treffer (etwas formatiert):
Code:
[
{"_id": "58849f88310af72fa3c67305", "userid": "100", "recipename": "Spaghettis", "persons": "2", "preparationTime": "40", 
    "ingredients": "[
        {"amount": "150", "unit": "Gramm", "ingredient": "Spaghetti"},
        {"amount": "200", "unit": "Milliliter", "ingredient": "Soße"}
    ],"preparation": "Spaghettis kochen, Soße erhitzen. Heiß servieren."},
{"_id": "58849fdc310af72fa3c67306", "userid": "100", "recipename": "Tee", "persons": "1", "preparationTime": "8", 
    "ingredients": "[
        {"amount": "230", "unit": "Milliliter", "ingredient": "Wasser"}
    ],"preparation": "Teewasser erhitzen, Teebeutel rein und 8 Minuten ziehen lassen."}]

... zu früh versand...

Wenn ich auf die PHP zugreife, bekomme ich auch oben genannten Code zurück. Kann diese aber nicht weiterverarbeiten.

Post: {"userId":"100"}

Antwort: [{"_id": "58849f88310af72fa3c67305", "userid": "100", "recipename": "Spaghettis", "persons": "2", "preparationTime"
: "40", "ingredients": "{{"amount": "150", "unit": "Gramm", "ingredient": "Spaghetti"},{"amount": "200"
, "unit": "Milliliter", "ingredient": "Soße"}},"preparation": "Spaghettis kochen, Soße erhitzen. Hei
ß servieren."},{"_id": "58849fdc310af72fa3c67306", "userid": "100", "recipename": "Tee", "persons": "1"
, "preparationTime": "8", "ingredients": "{{"amount": "230", "unit": "Milliliter", "ingredient": "Wasser"
}},"preparation": "Teewasser erhitzen, Teebeutel rein und 8 Minuten ziehen lassen."}]

Ich erhalte aber auch einen "TypeError: dbg is undefined" in Firebug...

Ausschnitte aus AngularJS:

Code:
var userId = '';

$scope.finddata=function() {
	userId = userFactory.getUserId();
	console.log('finddata, getUserId:');
	console.log(userId);
		$http.post('http://localhost/rezept/find.php', {
			'userId': userId
		})
		.then(function(data){
			console.log('finddata, erhaltene Daten:');
			console.log(data);
			console.log(data.data);
			$scope.recipes = data.data;
		});
	};

factory.factory('userFactory', function() {
	var userId = '';
	var userType = '';
	var item = {};
	return {
		getUserId: function() {
			return userId;
		},
		getUserType: function() {
			return userType;
		},
		setUser: function(data, data2) {
			if (data !== '') {
				userId = data;
				userType = data2;
				console.log('userId gesetzt: '+userId + ', userType gesetzt: ' +userType);
			} else {
				return null;
			}
		}
	};
});

Das setzen der UserId klappt. das finddata() funktioniert jedoch irgendwie nicht...
 
Zuletzt bearbeitet:
Wie würde das bei mir aussehen damit?
Ich habe bisher versucht, damit zu arbeiten, habe das aber nicht zum laufen bekommen. Also habe ich es auf diese Weise angegangen, bis auf den Punkt mit den mehrdimensionalen Arrays hatte es auch immer super funktioniert, nur diese Arrays im Array wollen bei mir nicht...
Ergänzung ()

Wenn ich in der PHP folgenden Code versuche:

PHP:
$result = $collection->find($query);
print json_encode($result);

Bekomme ich einen leeren String übermittelt: {}

Wie setze ich das korrekt ein?
 
Zeile 12 ersetzt du durch ein Array, hängst du die Datensätze der Variable an und nach der Schleife machst du ein einfaches json_encode vom Array. Ganz einfach. Alles in PHP (Arrays) und kein Gefrickel mit Strings. JSON hat hier nichts zu suchen, das machst du nach der Schleife mit json_encode.
Code:
<?php

$d = [];
foreach( getData() as $dataset )
{
	$dataset["nested property"] = [];
	foreach( getNestedProperty( $dataset["id"] ) as $nestedProperty )
	{
		$dataset["nested property"][] = $nestedProperty;
	}
	$d[] = $dataset;
}
echo json_encode( $d );
 
Jetzt stehe ich richtig auf dem Schlauch. Mit dem Code (geändert):
PHP:
$result = $collection->find($query);
	$d = [];
	foreach($result as $dataset )
	{
		$dataset["nested property"] = [];
		foreach( getNestedProperty( $dataset["id"] ) as $nestedProperty )
		{
			$dataset["nested property"][] = $nestedProperty;
		}
		$d[] = $dataset;
	}
echo json_encode($d);

erhalte ich einen Fehlercode. Mir fehlt die Funktion getNestedProperty( $dataset["id"] ). Wo bekomme ich das her? Was tut sie?
Ergänzung ()

Mein eigentliches Problem scheint nicht gelöst zu werden...

Ich muss die Daten irgendwie so formatieren, dass sie in angularjs korrekt abgelegt werden können.

Die userId wird korrekt abgefragt. Über die Funktion finddata() soll die Abfrage getätigt werden und die Variable recipes mit allen Daten gefüllt werden:
PHP:
$scope.finddata=function() {
	userId = userFactory.getUserId();
		$http.post('http://localhost/rezept/find.php', {
			'userId': userId
		})
		.then(function(data){
			$scope.recipes = data.data;
		});
	};

Anstelle der Zeile 7 habe ich mal folgendes getestet:
Code:
$scope.recipes =
			[{
				'recipename' : 'Spaghettis',
				'persons' : '2',
				'preparationTime' : '40',
				'ingredients' : 
					[{'amount': '150', 'unitSelect': 'Gramm', 'ingredient': 'Spaghetti'},
					{'amount': '200', 'unitSelect': 'Milliliter', 'ingredient': 'Soße'}],
				'preparation' : ''
			}];
Das Problem hier: anstelle von einer Zeile in der recipe.html erhalte ich gleich 5. Jede dieser Zeile erhält fälschlicherweise als {{recipename}} stets das nächste Feld. Also die Zeile 3 hat den recipename = 40...
Wie muss das Array aussehen, damit es klappt? Mit den Eckigen Klammern akzeptiert Firebug den Code nicht...

Problem gelöst, Code oben aktualisiert. Nun zeigt er brav eine Zeile, aber füllt die Tabelle der recipeDetail.html nicht aus...


Das Stück HTML, welche auf diese Daten zugreift sieht so aus:
HTML:
	<button type="button" ng-click="newRecipe()"/>Neues Rezept erstellen<br /></button>
	<table class="table">
		<tr>
			<th>Rezeptname</th>
			<th></th>
		</tr>
		<tr ng-repeat="item in recipes">
			<td>{{item.recipename}}</td>
			<td style="min-width:70px">
				<a title="Rezept öffnen" href="#/detail" ng-click="openrecipe(item)" ><img src="images/... .png" width="32" height="32"/></a>
			</td>
		</tr>
	</table>

Über den Button openrecipe(item) soll das Item aus dieser Zeile in die recipeDetail.html übergeben werden. Der obere Button soll die html mit leeren Daten öffnen für ein neues Rezept:

Code:
// neue, leere recipeDetails.html
$scope.newRecipe=function() {
		userFactory.setItem(
			{
				'recipename' : '',
				'persons' : '',
				'preparationTime' : '',
				'ingredients' : [{'amount': '', 'unitSelect': '', 'recipe': ''}],
				'preparation' : ''
			}
		);
		$location.path('/detail');
	};

// öffne dieses eine Rezept und lade das eine Item, der die weiterleitung steht im html-code
$scope.openrecipe=function(data) {
		itemFactory.setItem(data);
		finddetaildata();		
	};

// hole das aktuelle Item und lade es in die html
$scope.finddetaildata=function() {
		item = itemFactory.getItem();
		$scope.recipename = item.recipename;
		$scope.persons = item.persons;
		$scope.preparationTime = item.preparationTime;
		$scope.ingredients = item.ingredients;
		$scope.preparation = item.preparation;
	};

// factory um das Item zwischen zu speichern
factory.factory('itemFactory', function() {
	var item = {};
	return {
		getItem: function() {
			return item;
		},
		setItem: function(data) {
			if (data) {
				item = data;
			} else {
				return null;
			}
		}
	};
});


Wenn euch weiterer Code fehlt, bitte anfragen, da ich bereits einiges an Code habe, kann es sonst unübersichtlich werden...

Apropos: Die Abfragen der Daten und das Ausfüllen von den HTML-Seiten klappt mit einem Prototyp-Projekt mit eindimensionalen Arrays. Nur die Umstellung mit den mehrdimensionalen Arrays klappt jetzt nicht :(


[edit:]

Würde diese factory besser funktionieren?

Code:
factory.factory('detailFactory', function() {
	var recipename = '';
	var persons = '';
	var preparationTime = '';
	var ingredients = {
		'amount': '',
		'unitSelect': '',
		'recipe': ''
		};
	var preparation = '';
	return {
		getDetail: function() {
			$scope.recipename = recipename;
			$scope.persons = persons;
			$scope.preparationTime = .preparationTime;
			$scope.ingredients = ingredients;
			$scope.preparation = preparation;
		},
		setDetail: function() {
			// ToDo setting the variables from parameters
		},
		clearDetail: function() {
			recipename = '';
			persons = '';
			preparationTime = '';
			ingredients = {
				'amount': '',
				'unitSelect': '',
				'recipe': ''
				};
			preparation = '';
			console.log('clearDetail done');
		}
	};
});

Ich würde dann präziser versuchen, das Item zu sichern und abzufragen. Außerdem kann ich so theoretisch einfach jedes Element einzeln ansprechen... Sollte ich das hierrüber weiterverfolgen?
 
Zuletzt bearbeitet:
Endless Storm schrieb:
Jetzt stehe ich richtig auf dem Schlauch. Mit dem Code (geändert):
erhalte ich einen Fehlercode. Mir fehlt die Funktion getNestedProperty( $dataset["id"] ). Wo bekomme ich das her? Was tut sie?
Gar nichts. Das oben ist ne schematische Darstellung, wie dein Script aufgebaut werden sollte. Wie deine Daten organisiert sind weiß ich nicht, deshalb oben die Verwendung von getData(), welche dir allgemein die Datensätze zurück gibt und getNestedProperty(), um aufzuzeigen, dass hier anderweitige, damit zusammenhängende Daten geholt werden. Wie du die nun in deinen Code einbaust weiß ich nicht. Wenn das bereits so in den Datensätzen drin steht, erstell dir n temporäres Array, füg die Daten dort an und weis die Stelle korrekt zu. Ich kenn deine Daten nicht, kann daher nicht mehr als Allgemeines sagen.
Endless Storm schrieb:
Anstelle der Zeile 7 habe ich mal folgendes getestet:
PHP:
$scope.recipes =
			{
				'recipename' : 'Spaghettis',
				'persons' : '2',
				'preparationTime' : '40',
				'ingredients' : 
					[{'amount': '230', 'unitSelect': 'Milliliter', 'recipe': 'Wasser'},
					{"amount": "200",	"unit": "Milliliter",	"ingredient": "Soße"}],
				'preparation' : ''
			}
Das Problem hier: anstelle von einer Zeile in der recipe.html erhalte ich gleich 5. Jede dieser Zeile erhält fälschlicherweise als {{recipename}} stets das nächste Feld. Also die Zeile 3 hat den recipename = 40...
Wie muss das Array aussehen, damit es klappt? Mit den Eckigen Klammern akzeptiert Firebug den Code nicht...

Das Stück HTML, welche auf diese Daten zugreift sieht so aus:
HTML:
	<button type="button" ng-click="newRecipe()"/>Neues Rezept erstellen<br /></button>
	<table class="table">
		<tr>
			<th>Rezeptname</th>
			<th></th>
		</tr>
		<tr ng-repeat="item in recipes">
			<td>{{item.recipename}}</td>
			<td style="min-width:70px">
				<a title="Rezept öffnen" href="#/detail" ng-click="openrecipe(item)" ><img src="images/... .png" width="32" height="32"/></a>
			</td>
		</tr>
	</table>
Ich glaub du solltest dich erstmal mehr mit JS beschäftigen, denn das scheint hier eher das Problem zu sein.

Ich versuchs mal, kenne angular nich, aber vue.

Du versuchst hier im <tr> eine Schleife für jedes Rezept aufzubauen. Die Daten stammen hierfür aus der Variable recipes. recipes hast du hier ein Objekt zugewiesen. Warum hier genau fünf Datensätze erscheinen, lässt sich ganz einfach sagen: Dein Objekt hat genau fünf Keys (recipename, persons, preparationTime, ingredients, preparation). Das ist in JS halt so. Du kannst hier auch problemlos über Objekte iterieren. Was du willst ist ein Array von Objekten.

Mach aus deinem
PHP:
$scope.recipes =
			{
				'recipename' : 'Spaghettis',
				'persons' : '2',
				'preparationTime' : '40',
				'ingredients' : 
					[{'amount': '230', 'unitSelect': 'Milliliter', 'recipe': 'Wasser'},
					{"amount": "200",	"unit": "Milliliter",	"ingredient": "Soße"}],
				'preparation' : ''
			}
also ein
PHP:
$scope.recipes = [
			{
				'recipename' : 'Spaghettis',
				'persons' : '2',
				'preparationTime' : '40',
				'ingredients' : 
					[{'amount': '230', 'unitSelect': 'Milliliter', 'recipe': 'Wasser'},
					{"amount": "200",	"unit": "Milliliter",	"ingredient": "Soße"}],
				'preparation' : ''
			}
]
Somit hast du ein Array von Objekten (Array = [], Objekt = {}). Mit eckigen Klammern klappt es auch nicht, denn ein Array ist kein Key-Value-Store.
 
Zurück
Oben