I have a problem with one of my controllers either in Laravel or Ember. I can get the record to save after filling out the form but the record will not persist to the database. Again the form saves the record but doesn't push the record to the database. I tried following Embers guides on pushing data to the server but no juice. Also thanks for all the help from this site, you have got me this far, hopefully I can get this worked out with your help. Here are the controllers,
Laravel Controller
$statusCode = 200;
$libraries = $request->all();
$library = Library::create($libraries);
$criteria = $library->toArray();
return Response::json([
'libraries' => $criteria],
$statusCode);
Ember Route
model() {
return this.store.createRecord('library');
},
actions: {
saveLibrary(item) {
item.save().then(() => this.transitionTo('libraries'));
},
willTransition() {
//rollbackAttributes() removes the record from the store
// if model is 'isNew'
this.controller.set('model').rollbackAttributes();
}
}
In controller, you should use transitionToRoute. and implement POST request for /libraries for save method call.
actions: {
saveLibrary() {
//You dont need to pass. you need to update model properties. and then call save method.
this.get('model').save().then(() => this.transitionToRoute('libraries'));
}
}
Related
How do I tell my API to display a particular result based on another column?
e.g. localhost:8000/api/gadgets/{{id}}
Normally it returns the particular information of the specific gadget with that ID and localhost:8000/api/gadgets/{{imei_code}} does not return any value or an error whereas imei_code is a column that I needed to pass as a GET request...
I'm using the normal resource controller
public function show(Gadgets $gadget)
{
$response = ['data' => new GadgetResource($gadget), 'message' => 'specific gadget'];
return response($response, 200);
}
Also I need help on how I can create like a search function in the controller.
You can`t do two similar URLs. I think your route for URL
localhost:8000/api/gadgets/{{imei_code}}
isn`t work. Also the order of the routes is important and route that defined firstly will be have higer priority then route that defined secondly.
Because your routes /api/gadgets/{{id}} and /api/gadgets/{{imei_code}} is similar in this case only the one described earlier will be processed.
You can define another router and handler, for example:
localhost:8000/api/gadgets
That will return a list of gadgets by default and you can add filters for imei_code. For example:
localhost:8000/api/gadgets?imei_code=123
And your handler for the new route may be writed something like that:
public function showList(Request $request): GadgetResource
{
if ($imeiCode = $request->query('imei_code')) {
$list = Gadget::query()->where('imei_code', $imeiCode)->get();
} else {
$list = Gadget::query()->take(10)->get();
}
return GadgetResource::collection($list);
}
Or like alternative solution you can create diferent route for searching of gadgets exactly by imei_code to get rid of any route conflicts
localhost:8000/api/gadgets/by_imei/123
public function findByImei(Request $request): GadgetResource
{
$imeiCode = $request->route('imei_code');
$item = Gadget::query()->where('imei_code', $imeiCode)->first();
return new GadgetResource($item);
}
You can specify the model key by scoping - check docs
Route::resource('gadgets', GadgetController::class)->scoped([
'gadget' => 'imei_code'
]);
Than, when Laravel try to bind Gadget model in Controller - model will will be searched by key imei_code.
This code equvalent of
Route::get('/gadget/{gadget:imei_code}');
Try to change response
public function show(Gadgets $gadget)
{
$response = ['data' => new GadgetResource($gadget), 'message' => 'specific gadget'];
return response()->json($response);
}
I am building a RESTful api in Laravel, with my front end app in Angular.
I have a number of models / controllers and routes. I am struggling to get to grips with creating restful route for nested resources.
For example, my route to show a list of clients is simple:
Route::resource('clients', 'ClientsController');
A client can have many campaigns:
class Client extends Model
{
public function campaigns()
{
return $this->hasMany('App\Campaign');
}
}
I do not need a route to show all campaigns, but I do need a route to show all campaigns based on a client.
Route::resource('clients.campaigns', 'CampaignsController');
My intention was for the endpoint requested by the Angular app to be:
myapp/api/clients/6/campaigns
Where '6' is the client ID. This would return a list of campaigns that belong to client with id 6.
In my index method, I am trying to use implicit model binding to get this client Id, but I always get an empty result set:
class CampaignsController extends ApiController
{
public function index(Client $client)
{
$campaigns = Campaign::where('client_id', $client->id)->get();
if (!count($campaigns)) {
Log::warning('Campaigns list is empty');
return $this->respondNotFound('No Campaigns Found');
}
try {
return $this->respond([
'data' => $this->campaignTransformer->transformCollection($campaigns->all())
]);
} catch (\Exception $e) {
Logging::logException($e, 'API error showing campaigns list');
return $this->respondInternalError('An internal error occurred');
}
}
}
Clearly my route isn't binding a client - a var_dump on $client shows this.
Where am I going wrong?
For anyone who comes across this issue - Laravel was injecting the client_id for me.
Therefore index method becomes:
public function index($client_id)
{
$campaigns = Campaign::where('client_id', $client_id)->get();
}
I already have Laravel web pages where i can add/update/delete/Read records from MySQL Database. Laravel version is 5.2.15
Now, I have to integrate Database with Android App. In order to do that I have to post and read Json Data.
Here question is: Should I have 2 public action methods? First for web page that will show records on webpage and second will return json data in Android.
I meant, when I return data to webPage..I will have to write the below code.
return View("View-Path", array("Data" => $Data));
but in case of Android App, I will have to request Json Data.
Please suggest the right approach.
You should develop a simple API to access your APP data from an android client:
Routes
First of all you need to create some specific routes for the API through which you'll serve your data in JSON format
Authentication
The API's routes should handle authentication in a different way in respect on what you're doing now: you can't use the classic session-based approach. Instead you have to use a basic or token-based approach. You've different alternatives, these are some of the most used (from the simplest, to the most complicated )
Laravel HTTP Basic Authentication
Laravel Json Web Token Authentication
Laravel OAUTH2
Data Acess
Once you've setup your routes and authentication, you have to serve your data via the API routes. Since you use the same data in your APP routes and API routes, you can wrap the logic of data building and retrieving in services, and use the services to get the data both in your APP routes and API routes.
Using different controllers for API and APP routes, you have:
//APP Controller method for route: www.app.com/app-route/users
public function getUsers()
{
//wrap the logic to build the data inside the service
$service = App::make('your_service');
//once is ready, get the built data from the service
$data = $service->getData();
return View("View-Path", array("Data" => $data));
}
//API Controller method for route: www.app.com/api/users
public function getUsers()
{
//use the same service to build and get the data you need
$service = App::make('your_service');
$data = $service->getData();
return response()->json( $data );
}
This way you can:
Encapsulate data building and retrieveng in services, so that you don't have the need to duplicate code for data retrieving between APP and API routes
Have different controllers to access APP or API routes; so you can get the data, transform it as you need and serve it to either views or api clients
About the Service class
Regarding the service class i've mentioned, it could be simply one or multiple wrapper classes that you use both in API and APP controllers to build and get the data without repeting code. The structure of such classes depends on how your app work.
For example let's suppose you need to compute some data for each user's project, store it in a variable and then send it to the viev:
public function getUsers($request)
{
$user = Users::with('projects')->find( $request->user_id )->get();
$data = [];
foreach ( $user->projects as $p )
{
//compute some data you need and store it in $data;
}
return View("View-Path", array("Data" => $data));
}
Now if want to make the same thing in the API controller, you'd need to repete this code to get the projects and create the data. To avoid this, you could 'wrap' the data access in a service class, and use the same class in boh controllers:
Service class
public class UserDataBuilder
{
protected $user;
public function setUser( Authenticatable $user )
{
$this->user = $user;
}
public function getData()
{
$user = Users::with('projects')->find( $this-user->id )->get();
$data = [];
foreach ( $user->projects as $p )
{
//compute some data you need and store it in $data;
}
return $data;
}
}
and use the same class in both API and APP controllers:
//APP controller: get the data and pass to the view
public function getUsers($request)
{
$service = App::make( UserDataBuilder::class );
$service->setUser( User::find( $request->user_id )->get() );
return View("View-Path", array("Data" => $service->getData() );
}
//API controller: get the data and convert to JSON
public function getUsers($request)
{
$service = App::make( UserDataBuilder::class );
$service->setUser( User::find(1)->get() );
return response()->json( $data );
}
For android you have to write a separate web service.
You can use one method to do that. Example
public function someMethod(Request $request){
$Data = ['laravel','is','awesome'];
// If the request has the content type is json return a json response
// So you android request will be true for this request
// else return data to webpage
if($request->isJson()){
return response()->json($Data);
}
return View("View-Path", array("Data" => $Data));
}
A couple of questions that I cannot seem to find definative answers for, I am working on a RESTful api at the moment, that in time will interact with a handful of client devices, for the time being I am concetrating, on the API, and the web application that goes along with it.
The api lives at http://api.local and the web application lives at http://webapplication.local. The web application is a Laravel installation with a Backbone front-end.
I am trying to save some data from the Backbone to the database of the API. So the API save method looks like this,
public function store()
{
$user_details = Input::all();
$user = new User;
$user->firstname = $user_details['firstname'];
$user->surname = $user_details['surname'];
$user->email = $user_details['email'];
$user->password = Hash::make($user_details['password']);
$user->remember_token = '';
$user->save();
return Response::json($user_details, 200);
}
And it has a route that looks like this,
Route::group(['prefix' => 'api/v1'], function(){
Route::get('users', 'UsersController#index');
Route::get('users/{id}', 'UsersController#get');
Route::post('users/create', 'UsersController#store');
/**
* PUT request to edit the database record
* #todo: Need to be a PUT request in the long run
*/
Route::post('users/update/{id}', 'UsersController#update');
/**
* DELETE request to edit the database record
* #todo: Need to be a DELETE request in the long run
*/
Route::post('users/delete/{id}', 'UsersController#delete');
});
On the front end side (web application) I am saving a model like this,
saveNewUser: function(e) {
e.preventDefault()
var data = this.$el.find('.js-create-new-user').serializeJSON();
// create a new model
var User = new app.User();
User.save(data, {
success: function(model, response){
console.log(model);
console.log(response);
console.log("sucess");
},
error: function(model, response) {
console.log(model);
},
wait:true
});
}
This sends a POST request to the webapplication.local/users/create method, that looks like this,
public function create()
{
$data = Input::all();
$curl = new Curl\Curl();
$curl->post('http://pops.local/api/v1/users/create', $data);
if ($curl->error) {
return Response::json($curl->error, $curl->error_code);
}
else {
return Response::json($curl->response, 200);
}
}
If I look at the $curl->response then I see the data object that is being sent - which I assume means the cURL request is successfully being sent. However nothing gets updated in the API's database?
Am I going about this all wrong? Should Backbone be sending/making requests directly to the API, and leave the PHP behind the web application to do things that the API does not do i.e resize images etc?
You may send requests directly from backbone but you dont have to. Everything looks fine. Check what is returned from $user->save(); by writing something like that:
dd($user->save());
You should get true if everyting is fine, false if there is any error.
I am new at Zend2:
I have a form, and in the first stage I create a new ViewModel and return it:
return new ViewModel(array('form' => $form, 'messages' => $messages));
In the post stage when the data comes back from the browser, how can I connect this same form to a new View (which has the same elements maybe less, maybe more) or create another form and rassign it the old form's data and relate it to a new view to show?
Any help would be appreciated.
EDIT:
I tried to do the following:
$form->setAttribute('action', $this->url('auth/index/login-post.phtml'));
But still shows the old one.
When I do this:
return $this->redirect()->toRoute('auth/default', array('controller' => 'index', 'action' => 'login-post'));
I get error page: The requested controller was unable to dispatch the request.
When I get the post of the request I need to load another view, I mean how do I specify which view is connected to which form?
The forms do not themselves have any knowledge of the view. If you wish to change the view after completing the form submission; where this new view provides perhaps a different form, this is something that should be done within the controller.
A (non-working) example with a few options on how a different view could be returned.
class FooController extends AbstractActionController
{
public function getFooForm()
{
return $this->getServiceLocator()->get('Form\Foo');
}
public function getBarForm()
{
return $this->getServiceLocator()->get('Form\Bar')
}
public function fooAction()
{
$request = $this->getRequest();
$form = $this->getFooForm();
if ($request->isPost()) {
$form->setData($request->getPost());
// Is the posted form vaild
if ($form->isValid()) {
// Forms validated data
$data = $form->getData();
// Now there are a few options
// 1. Return a new view with the data
$view = new ViewModel($data);
$view->setTemplate('path/to/file');
return $view;
// OR Option 2 - Redirect
return $this->redirect()->toRoute('bar', $someRouteParams);
// Option 3 - Dispatch a new controller action
// and then return it's view model/response
// We can also pass on the posted data so the controller
// action that is dispathed will already have our POSTed data in the
// request
$request->setPost(new \Zend\Stdlib\Parameters($data));
return $this->forward()->dispatch('App\Controller\Foo', array('action' => 'bar'));
}
}
// Render default foo.phtml or use $view->setTemplate('path/to/view')
// and render the form, which will post back to itself (fooAction)
return new ViewModel(array('form' => $form));
}
public function barAction()
{
$request = $this->getRequest();
$form = $this->getBarForm();
if ($request->isPost()) {
$form->setData($request->getPost());
// ....
}
// Renders the bar.phtml view
return $this->viewModel(array('form' => $form));
}
}
From what I understand form your question, you would need to be using option 3 as the new view should populate a second form with it's already validated data.
If you are referring to something like an edit view then you just need to bind your object to the form.
$form->bind($yourObject);
http://zf2.readthedocs.org/en/latest/modules/zend.form.quick-start.html#binding-an-object
Otherwise you can make the form post to any controller action using by setting it:
$form->setAttribute('action', $this->url('contact/process'));
Maybe post what code you have and more specifics and I'm sure you will get some more detailed answers