I'm very new to PHP and having trouble making an API that's essentially taking a GET request and returning all users stored in a table. This application uses Zend Framework 2 and Doctrine.
Controller:
public function viewAllAction(){
$restService = $this->getServiceLocator()->get("Rest");
$restService->auth();
$business = $restService->getIdentity();
$bizID = $business->getId();
$clientModel = $this->getServiceLocator()->get('clientModel');
$clients = $clientModel->findAllByBusinessID($bizID);
$params['client'] = array(
"name" => $clients->getName(),
"email" => $clients->getEmail(),
"phone" => $clients->getPhone(),
"address" => $clients->getAddress(),
"suburb" => $clients->getSuburb(),
"postcode" => $clients->getPostcode(),
"state" => $clients->getState(),
"country" => $clients->getCountry(),
);
return $restService->send($params);
}
Model:
public function findAllByBusinessID( $business_id ){
$clientRepository = $this->getMapper()->getRepository( self::ENTITY_CLASS );
$clients= $clientRepository->findBy(array("bid" => $business_id));
foreach($clients as $client) {
return $client;
}
}
At the moment I can successfully retrieve data and return it via rest, but only the first set(row) of data. There are more in the table with the same business ID.
How to I return all rows that have the same business ID instead of just the first one? Thank you!
The problem is in your loop in findAllByBusinessID method. return breaks your loop, so only first row is returned. What do you want is probably something like this:
public function findAllByBusinessID( $business_id ){
$clientRepository = $this->getMapper()->getRepository( self::ENTITY_CLASS );
$clients= $clientRepository->findBy(array("bid" => $business_id));
$results = [];
foreach($clients as $client) {
$results['client'][] = [
"name" => $client->getName(),
"email" => $client->getEmail(),
"phone" => $client->getPhone(),
"address" => $client->getAddress(),
"suburb" => $client->getSuburb(),
"postcode" => $client->getPostcode(),
"state" => $client->getState(),
"country" => $client->getCountry(),
];
}
return $results;
}
But you should split this method into 2 separate functions. One function for retrieving data from database, one to format data the way you want.
Another solution would be to use Doctrine's queryBuilder and return data as array set (getArrayResult())
Related
I have an array, which looks like this:
array:3 [▼
"field" => array:2 [▼
0 => "fromName"
1 => "from"
]
"operator" => array:2 [▼
0 => "="
1 => "="
]
"value" => array:2 [▼
0 => "Oliver"
1 => "oliver#mywebsite.com"
]
]
I am trying to save the above array, into my database table called email_rules:
Below is my code.
StreamEmailRulesController.php:
public function store(Stream $stream)
{
//Validate the request.
//Validate the request.
$attributes = request()->validate([
'field' => 'required|array|min:1',
'field.*' => [
'required', 'string',
Rule::in(['fromName', 'from']),
],
'operator' => 'required|array|min:1',
'operator.*' => [
'required', 'string',
Rule::in(['=', '!=', 'matches']),
],
'value' => 'required|array|min:1',
'value.*' => 'required|string|min:3|max:255',
]);
//Add the document to the database.
$stream->addRules($attributes);
//Return back.
return redirect()->back();
}
Now the $stream->addRules() function is responsible for saving the data to the database.
Stream.php:
/**
* A stream can have many rules.
*/
public function rules()
{
return $this->hasMany(EmailRule::class);
}
/**
* Add Email Rules(s) to the stream
*
* #return Illuminate\Database\Eloquent\Model
*/
public function addRules(array $attributes)
{
return $this->rules()->create($attributes);
}
Now, above does not work. I get below error:
Argument 1 passed to Illuminate\Database\Grammar::parameterize() must be of the type array, int given,
What am I doing wrong?
If you dump $attributes you may be getting an int (bool) as a pass or fail or even json, depending on what's going in, from the validation. This might just be a matter of changing syntax from
$attributes = request()->validate([...
to
$attributes= $this->validate(request(), [...
I believe your issue is that you're trying to save an array as a singular value. IE those attributes need to be iterated over to create a new set of rules for each one, instead. Normally, I'd expect to see the array ready to create individual objects. In this case, though it looks like it is structured to create individual fields (field, operator, value), so looping through those may not do what you wish either -- it provides multiple fields to the create construct, rather than a full set of object params for a new rule(). I think Laravel is hinting that you may wish to change your request/return structure to match the model format.
I think it could be the array structure. Can you modify the array to?:
[
[
"field" => "fromName",
"operator" => "=",
"value" => "Oliver"
],
[
"field" => "from",
"operator" => "=",
"value" => "oliver#mywebsite.com"
],
]
EDIT:
In the Controller add a loop like this:
...
foreach ($attributes as $key => $value) {
foreach ($value as $k => $v) {
$data [$k][$key] = $v;
}
}
//Add the document to the database.
$stream->addRules($data);
The problem was that Laravels create or createMany expect an array with key => pair values, where the key corresponds to the database columns.
This article from Adam Wathan helped me out a lot.
This is what I ended up doing:
$requestData = collect(request()->only('field', 'operator', 'value'));
$rules = $requestData->transpose()->map(function ($ruleData) {
return new EmailRule([
'field' => $ruleData[0],
'operator' => $ruleData[1],
'value' => $ruleData[2],
]);
})->toArray();
//Add the rules to the database.
$stream->addRules($rules);
I am trying to update records in a mongodb by using php codeigniter, but I am unable to do so.
My controller class:
function updatetodb_post(){
$updateddata = array('$set' => array("lang" => "English"));
$this->load->model('data_model');
$uid = 1;
$this->data_model->updaterecords($uid, $updateddata);
}
My Model class:
function updaterecords($uid, $updatedata){
$this->load->library('mongo_db');
$recoundsbyuid = $this->mongo_db->get_where($this->_testcollectoin, array("uid" => $uid));
$this->mongo_db->update($this->_testcollectoin, $recoundsbyuid, $updatedata);
}
data that I want to update in a collectoin:
$data = array(
"uid" => "1",
"type" => "Movie",
"genre" => "Action"
);
where _testcollectoinis my collection name. I want to add one more field (lang) to the array.
We can use below commands to update with given data
$this->mongo_db->where(array("uid" => $uid))->set($updatedata)->update($this->_testcollectoin);
I'm learning Laravel and have created a public endpoint where I want to output only certain information of some comments if a user is not authenticated from a GET request.
I have managed to filter out the comments based on whether or not they are approved. I now want to filter out the data that is returned. I have attached a screenshot of what is currently returned.
Ideally, I only want to return the id, name and the body in the json. How can I go about this? I tried the pluck() method which did not give the desired results. Any pointers would be greatly appreciated
public function index(Request $request)
{
if (Auth::guard('api')->check()) {
return Comment::all();
} else {
$comments = Comment::where('approved', 1)->get();
return $comments->pluck('id','name','body');
}
}
To select the particular columns, you can pass columns name to get as
$comments = Comment::where('approved', 1) -> get(['id','name','body']);
You can use a transformer to map the incoming data to a sensible output based on the auth state. The following example comes from the Fractal lib:
<?php
use Acme\Model\Book;
use League\Fractal;
$books = Book::all();
$resource = new Fractal\Resource\Collection($books, function(Book $book) {
return [
'id' => (int) $book->id,
'title' => $book->title,
'year' => $book->yr,
'author' => [
'name' => $book->author_name,
'email' => $book->author_email,
],
'links' => [
[
'rel' => 'self',
'uri' => '/books/'.$book->id,
]
]
];
});
Ideally, you would create 2 classes that extend from Transformer and pass the correct one to the output.
If you want to pass the result as json respose
$comments = Comment::where('approved', 1)->pluck('id','name','body')->toArray();
return Response::json($comments);
If you want to pass the result as to blade
$comments = Comment::where('approved', 1)->pluck('id','name','body')->toArray();
return view('your_blade_name')->with('comments',$comments);
I have difficult to build and return a nested json. I want obtain the information from two differents table joined with an id.
This is my situation:
With this method on my controller:
public function eventOccList(EventOccurrence $eventOccurrence){
return new EventOccurrenceResourceCollection(EventOccurrence::all());
}
and with the mapping in the class EventOccurrenceResource
return [
'type' => 'event',
'id' => (string) $this->id,
'name' => $this->name,
'description' => $this->description,
'location_id' => $this->location_id
];
I obtain this JSON:
{"data":[{"type":"event","id":"1","name":"event_1","description":"event blabla","location_id":11}
If I want to obtain all the informations about the table "location" with the id "location_id" and show in the same json, what is the best way to retrieved this data?
Thanks !
I assume your Event Model have a location relationship :
public function location{
return $this->belongsTo(Event::class);
}
you can do this once you have your event in a Controller :
$event->load('location');
return $event->toJson();
You can then hide or append any attribute you want :)
After doing a query, how can I create and echo a formatted JSON like this:
{
"results": [
{
"user_id": "1",
"name": "Apple",
"address": "7538 N LA CHOLLA BLVD",
"city": "Palo Alto",
"state": "CA",
"latlon": [
-111.012654,
32.339807
],
},
{
"user_id": "2",
"name": "Microsoft",
"address": "75 S BWY STE 400",
"city": "Palo Alto",
"state": "CA",
"latlon": [
-73.764497,
41.031858
],
},
],
"meta": {
"page": 1,
"per_page": 10,
"count": 493,
"total_pages": 50
}
}
This is my current query:
public function getAgenciesJson() {
$agencies = DB::table('users')->where('type','a')->orWhere('type','l');
}
Haven't figured out how to output JSON like that, considering I have a "latlon" field like [-111.012654,32.339807], also a "results" tag and a "meta" tag.
Thanks in advance
What you need is something called a transformer (or presenter) to convert your raw model into a format that can be sent to your users.
A very popular package is called Fractal (http://fractal.thephpleague.com/) by Phil Sturgeon. There's a Laravel package, that might make it a bit easier to use, called Larasponse (https://github.com/salebab/larasponse).
Phil actually a blog post about this just the other day - https://philsturgeon.uk/api/2015/05/30/serializing-api-output/ - that goes into why you should always have some kind of transformer between your models and what you send to your users.
There's also a guide about using Larasponse and Fractal that might be of use here - http://laravelista.com/laravel-fractal/.
The gist of it boils down to passing the model through another class that will take the models values and build an array/object in a known/fixed format, e.g. (from Phil's blog post)
return [
'id' => (int) $book->id,
'title' => $book->title,
'year' => (int) $book->yr,
'author' => [
'name' => $book->author_name,
'email' => $book->author_email,
],
'links' => [
[
'rel' => 'self',
'uri' => '/books/'.$book->id,
]
]
];
This way you're not exposing your original field names and if at any point your column names should change you only need to update that in 1 place rather than having to get any user of your JSON to update their site/app. It will also allow you to do string manipulation of your latlon column so that you can split it into 2 different values.
Using a slightly modified example from the Fractal documentation. Say you have a transformer for a User
class UserTransformer extends Fractal\TransformerAbstract
{
public function transform(User $user)
{
return [
'id' => (int) $user->id,
'name' => $user->first_name . ' ' . $user->last_name,
];
}
}
You can then use this class to either transform a single item of a collection
$user = User::find(1);
$resource = new Fractal\Resource\Item($user, new UserTransformer);
// Or transform a collection
// $users = User::all();
// $resource = new Fractal\Resource\Collection($users, new UserTransformer);
// Use a manager to convert the data into an array or json
$json = (new League\Fractal\Manager)->createData($resource)->toJson();
Fractal includes a paginator adapter for Laravel that can be used straight away
$paginator = User::paginate();
$users = $paginator->getCollection();
$resource = new Collection($users, new UserTransformer);
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
The method exists:
->toJson()
REF: http://laravel.com/docs/4.2/eloquent#converting-to-arrays-or-json
Update your getAgenciesJson to :
public function getAgenciesJson() {
return DB::table('users')->where('type','a')->orWhere('type','l')->toJson();
}
Then you could echo by:
<?= SomeModel::getAgenciesJson(); ?>
To modify the column names you can update your select. Here is an example taken from the Laravel Docs:
$users = DB::table('users')->select('name as user_name')->get();
Here would be a more fully realized version of what you are looking for minus the column aliases since you didn't really mention what they were.
public function getAgenciesJson($page, $per_page = 10) {
$output = [
'results' => [],
'meta' => [],
];
// Get Results
$output['results'] = DB::table('users')->where('type','a')->orWhere('type','l')->take($per_page)->skip($per_page * ($page - 1))->get();
// Set Meta
$output['meta'] = [
'page' => $page,
'per_page' => $per_page,
'count' => DB::select('SELECT FOUND_ROWS()'),
'total_pages' => DB::table('users')->count() / $per_page
];
// Return
return json_encode($output);
}
Your original code didn't attempt to get or handle the pagination information but this example covers that in order to provide the meta data you indicated you wanted returned.
Not sure if you wanted Count to be the number of the current result set or a count of all the records on that table. If you don't want the current set you but rather the entire count you can use DB::table('users')->count() though I would assign it to a variable and use that rather than calling it twice in the meta info.
public function getAgenciesJson() {
$agencies = DB::table('users')->where('type','a')->orWhere('type','l')->get();
return response()->tojson($agencies,200);//for response with status code 200
}
You should call get function to get data in array format and response function will format your output to json. Second paramater signifies which status code you have to assign for your response.