Laravel 4 PHP: 502 Bad Gateway error after using new controller - php

This is related to the last question I asked on here where I'm trying to add a new controller to my app that will allow database columns to be edited and updated. I have defined a new controller that will update these edits but when I try to update my edit form, I keep getting a "502 Bad Gateway" error.
edit-album.blade.php:
{{ Form::model($album, array('method' => 'PUT', 'route' => array('edit_album', $album->album_id))) }}
/* Form code here */
{{ Form::close() }}
routes.php:
Route::put('gallery/album/{id}/edit', array('as'=>'edit_album', 'uses'=>'EditAlbumsController#update'));
EditAlbumsController.php:
class EditAlbumsController extends AlbumsController {
public function __construct()
{
parent::__construct();
}
public function update($id)
{
$input = \Input::except('_method');
$validation = new Validators\Album($input);
if ($validation->passes())
{
$album = Album::find($id);
$album->album_name = $input['album_name'];
/* Additional database fields go here */
$album->touch();
return $album->save();
return \Redirect::route('gallery.album.show', array('id' => $id));
}
else
{
return \Redirect::route('gallery.album.edit', array('id' => $id))
->withInput()
->withErrors($validation->errors)
->with('message', \Lang::get('gallery::gallery.errors'));
}
}
Could this be because I have a bad route or it is not defined properly?
I did run 'composer dumpautoload -o' after making some changes in the code as per a suggestion I found online, not sure if this had an effect.

This issue was being caused by a bad route and therefore the browser produced a '502 Bad Gateway error'.

Related

Very Confusing MethodNotAllowedHttpException on a put request laravel

So far all attempts to modify the routing methods have failed.
Been following some documentation on laravel restful controllers and have one set up to do basic editing and adding of items to a database. It was going well till I hit the snag on... well I'm not sure what precisely is triggering the problem, but basically, everything works till I hit submit on the form and then it's Game Over.
Normally I'd be able to diagnose this by checking to see if I'm using the right call, or made a spelling mistake or something. But this is a new request for me, so I can't quite debug where the problem is coming from.
This is the error those who know what to look for. In full here.
MethodNotAllowedHttpException in RouteCollection.php line 218:
My routes are pasted here.
A printout of the routes is here:
Controller:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests\ContactFormRequest;
use App\UserEdit;
use DB;
use App\Http\Requests;
class EditUserController extends Controller
{
public function index()
{
$array = UserEdit::all()->toArray();
return view('UserEntry', compact('array'));
}
public function create()
{
$id = UserEdit::find(715)->toArray();
return view('NewUser', compact('id'));
}
public function store(UserFormRequest $request)
{
//$user = new UserEdit([
// 'name'=>$request->get('First_Name'),
// 'email'=>$request->get('email'),
// 'username'=>$request->get('name')
//]);
//
//$user->save();
//return \Redirect::route('users')->with('message', 'Nice Work.');
}
public function show($id)
{
try {
$array = UserEdit::findorFail($id)->toArray();
return view('UserEdit')->with('array', $array);
} catch(\Exception $e) {
return \Redirect::route('users.index')
->withMessage('This user does not exist');
}
}
public function edit($id)
{
$user = UserEdit::findorFail($id);
return view('EditUser')->with('user',$user);
}
public function update($id, UserFormRequest $request)
{
$user = UserEdit::findorFail($id);
$user->update([
'name' => $request->get('name'),
'email' => $request->get('email')
]);
return \Redirect::route('users.edit', [$user->id])->with('message', 'Details Updated!');
}
public function destroy($id)
{
//
}
}
The Blade is here.
if you have a hard time finding the solution the easiest solution is using
Route::any('users/{user}', 'UserEntryController#update');
this allow you to access this action with any method type
OR
Route::match(array('get', 'put'), 'users/{user}', 'UserEntryController#update');
so you need 2 method which are
get -> view
put -> submit update
you can just indicate which method type you want to be accessible with in this action
i think you are using model in form.try this
{{ Form::open(['method' => 'put', 'route'=>['users.update', $user->id], 'class'=>'form']) }}
As per your route list and route put doesnt taking id so you get method not found exception
PUT users/{user} App\Http\Controllers\EditUserController#update
instead of using resouce just type each route for each method
Route::put('users/{user}', 'EditUserController #update');
It seems like after sorting out the routes, the issue fell to a bad capitalisation. $user->id should have been $user->ID.

Laravel phpunit test is failing. Going to an unexpected page. Only happens in the test

So, I have a page with a button on it with the value "Create". When I click that Create button, without filling out any of the fields, it validates the form and displays error messages on the same page. When I do that in the browser, it works fine, but when I do it with phpunit, it has unexpected results and I do not know why.
Here is my integration test:
public function testCreateValidation()
{
$this->visit(route('patients.indexes.create', $this->patient->id));
$this->press('Create');
$this->seePageIs(route('patients.indexes.create', $this->patient->id));
}
And this is the result:
There was 1 failure:
1) Tests\Integration\IndexControllerTest::testCreateValidation
Did not land on expected page [http://localhost/patients/69/indexes/create].
Failed asserting that two strings are equal.
--- Expected
+++ Actual
## ##
-'http://localhost/patients/69/indexes/create'
+'http://localhost/patients'
/vagrant/vendor/laravel/framework/src/Illuminate/Foundation/Testing/InteractsWithPages.php:141
/vagrant/tests/Integration/IndexControllerTest.php:51
I don't understand why it is being redirected to the patients page.
Here is the Laravel create method that is being tested:
public function create($id)
{
$index = $this->indexes->newInstance();
$patient = $this->patients->findOrFail($id);
return view('patient.index.create', ['index' => $index, 'patient' => $patient]);
}
And here is the relevant section of the create view:
<?= Form::open(['route' => array('patients.indexes.store', $patient->id), 'class' => 'form-horizontal']) ?>
#include('patient.index._form')
<?= Form::submit('Create', ['class' => 'btn btn-primary']) ?>
<?= Form::close() ?>
And finally the store method that it is being sent to:
public function store(IndexRequest $request, $id)
{
$index = $this->indexes->newInstance();
$index->fill($request->all());
$index->patient_id = $id;
$index->save();
$patient = $index->patient;
return redirect()->route('patients.edit', $patient);
}
I am also using a FormRequest to validate the input:
public function rules()
{
return [
'index_title' => 'required',
'index_description' => 'required',
];
}
So essentially, since it is failing the validation in the IndexRequest, the IndexRequest should kick it back to the patients.indexes.create view and display errors. But for some reason it's being kicked to the patients page (this ONLY happens in the test, if I try it out by manually clicking the Create button in the browser, it works as expected)
I've had this issue before but have never been able to solve it. Any ideas?
It sounds like you're having CSRF issues. When you navigate to the form in your browser, Laravel stores a special token in your browser's cookies and in the request headers. Then, when you submit the form it looks for that token to make sure you are the one submitting the form.
When you test with PHPUnit, that token isn't sent, so you either have to send it yourself, or you have to exclude your tests from the middleware that checks for the token. Excluding your tests is the easier method.
In Laravel 5.0 I did that by overriding the handle() method in the VerifyCsrfToken middleware.
class VerifyCsrfToken extends BaseVerifier {
// Override the handle() method in the BaseVerifier class
public function handle($request, Closure $next) {
// When the App environment is 'testing', skip CSRF validation.
if (app()->environment() === 'testing') {
return $next($request);
}
return parent::handle($request, $next);
}
}
By default, PHPUnit pulls the environment variables from the phpunit.xml file in your Laravel site root. The APP_ENV variable is the one that controls the application environment name, and it defaults to 'testing'. If yours is different, you then need to change the code I provided to match it.
If middleware is in fact the problem you can exclude it from the tests using the WithoutMiddleware trait:
class IndexControllerTest extends TestCase
{
use Illuminate\Foundation\Testing\WithoutMiddleware;
...

Passing argument from controller to controller not working

Aloha, I'm making a workout manager in which you have a dashboard displaying your 5 last workouts. I have set a form for each one workout for allowing the user to delete any of them. Here the form in the dashboard:
{!! Form::open(['route' => ['dashboard.workout.destroy', $workout->id], 'style' =>'display:inline-block;', 'method' => 'DELETE']) !!}
This route will call this method in WorkoutController.php
public function destroy($id, Request $request)
{
$workout = Workout::findOrFail($id);
$workout->delete();
$message = "Workout deleted successfully!";
return redirect()->route('dashboard.index', ['message' => $message]);
}
And this route will call this method in DashboardController.php
public function index($message = null)
{
$user = Auth::user();
// Workouts
...
// Inbodies
...
// Measures
...
return view('dashboard.index', compact('user','workoutsDesc','workouts','lastInbody','inbodies','measures','lastMeasure','message'));
}
The question is that I'm trying to pass the variable $message from WorkoutController to DashboardController for displaying a successfull alert after deleting a workout, but I don't know how to do it. I have tried with:
return redirect()->action('Dashboard\DashboardController#index', [$message]);
return redirect()->action('Dashboard\DashboardController#index')->with('message', $message);
return redirect()->route('dashboard.index', $message);
But I still trying to find the way for doing it.
First of all, from Laravel 5.1 Documentation:
If your route has parameters, you may pass them as the second argument to the route method
As the message is not a parameter to your route, so you can't pass that. A possible solution can be Flashing data. Check the next controller if the session has that key and contain a value, then add it to a variable and pass to the view.
Hope this works.

CakePHP 3 Filestorage Plugin Triggering the ImageProcessingListener to delete versions

https://github.com/burzum/cakephp-file-storage/blob/3.0/docs/Home.md
I have two tables
ProductStylesTable.php and ProductStyleImagesTable.php which extends ImageStorageTable which is connect to my FileStorage Table in my sql that was created with the migration tool.
Upload works fine.
// ProductStylesController.php
public function upload($product_style_id = null) {
$this->ProductStyles->ProductStyleImages->upload( $product_style_id, $entity)
//ProductStyleImagesTable.php
class ProductStyleImagesTable extends ImageStorageTable {
//initialize code...
public function upload($product_style_id, $entity) {
$entity = $this->patchEntity($entity, [
'adapter' => 'Local',
'model' => 'ProductStyles',
'foreign_key' => $product_style_id,
]);
return $this->save($entity);
}
Awesome, ProductStyleImages is listening for the upload method and places it in the appropriate folder. I was hoping this would work the same for delete.
So I called
//ProductStylesController.php
$this->ProductStyles->ProductStyleImages->delete($fileStorage_id)
//In my ProductStyleImagesTable.php
public function delete($fileStorageID = null) {
//deleting the row, hoping for ImageProcessingListener to pick it up?
$FileStorageTable = TableRegistry::get('FileStorage');
$query = $FileStorageTable->query();
$query->delete()
->where(['id' => $fileStorageID ])
->execute();
}
I get an error that delete must be compatible with the interface. So to avoid this conflict I renamed my function to 'removeImage'. It works in removing the row but the Listener isn't picking it up. I looked in ImageStorageTable.php and FileStorageTable.php. I see the afterDelete methods. But i'm unsure how to trigger them since i'm unsure how to configure my delete methods to match the interface.
I deleted wrong, it is this way
$entity = $this->get($fileStorageID);
$result = $this->delete($entity);

Can't update (but create new) objects in CakePHP with save()

Using CakePHP 2.4.9 on a LAMP setup (Ubuntu 13.10, Apache 2, MySQL Server 5.5, PHP 5.5.3).
Trying to package a model (User) into a plugin but I have run into a strange problem:
In two different actions I use save() to either create or update a User. This works:
if ($this->request->data) {
if ($this->User->create() && $this->User->save($this->request->data)) {
$this->Session->setFlash(_('<strong>Congratulations!</strong> Successfully created a new user.'), 'default', array('class' => 'alert alert-success'));
$this->redirect(array('action' => 'register'));
} else {
$this->Session->setFlash(_('<strong>Oops!</strong> Could not create a new user.'), 'default', array('class' => 'alert alert-danger'));
}
}
But this doesn't work:
if ($this->request->data) {
$this->User->id = $id;
if ($this->User->save($this->request->data)) {
$this->Session->setFlash(_('<strong>Congratulations!</strong> Successfully updated your user account.'), 'default', array('class' => 'alert alert-success'));
$this->redirect(array('action' => 'settings'));
} else {
$this->Session->setFlash(_('<strong>Oops!</strong> Could not update user account.'), 'default', array('class' => 'alert alert-danger'));
}
}
When I try to save the latter example (the "update action") it gives me the following error:
Fatal Error
Error: Call to a member function getColumnType() on a non-object
File: /home/johan/sites/userplugin/lib/Cake/Model/Model.php
Line: 1412
Notice: If you want to customize this error message, create app/View/Errors/fatal_error.ctp
The forms are pretty standard, I use the FormHelper to create form and fields. But in the update form I have a hidden field with the ID:
<?php echo $this->Form->hidden('id'); ?>
If I remove that, the update form goes through but creates a new object! So it's like $this->User->id = $id doesn't do anything. I currently set $id "manually", so $id = 1...
I tried searching for similar issues but didn't find anything. One discussion mentioned the ID field, maybe it's not correctly set up? But I couldn't find any solution in regards to that.
There's a bad model reference
The different code permutations are not directly related to the problem - or may simply indicate another different problem =).
The line of code that is failing is this:
$this->{$model}->getColumnType($column);
Where $this is the User model instance. What that probably means is that when it fails, the object is not the class you expect to check simply do:
debug(get_class($this->User));
In your controller, it is most likely AppModel.
What causes this
A typical cause of that kind of "sometimes it works, sometimes it doesn't" problem is that there are some references to the model using the plugin prefix, and there are some that don't i.e.
<?php
App::uses('MyPluginAppModel', 'MyPlugin.Model');
class Group extends MyPluginAppModel {
public $hasMany = array(
'User' => array(
'className' => 'User'
),
#'User' # Or like this
)
}
Whereas it should be like this:
<?php
App::uses('MyPluginAppModel', 'MyPlugin.Model');
class Group extends MyPluginAppModel {
public $hasMany = array(
'User' => array(
'className' => 'MyPlugin.User'
),
#'MyPlugin.User' # Or like this
)
}
What happens here is it depends upon how the relevant model is first accessed, as to what populates the User key in the class registry and is returned for all subsequent requests for that model reference.
To fix the problem, ensure that the model is always referenced with the correct plugin prefix (or of course no prefix if it's not a plugin model).
What I ultimately found out (and should've ruled out earlier, really) was that having an array defined in my AppModel, for configuring the plugin, named the same as my plugin was stupid, borderline retarded perhaps.
I.e. if your plugin is called MyPlugin, do not define a $myplugin array in your AppModel.
try this
//Controller
public function edit(){
if (!empty($this->request->data)) {
//if you want to save on User object
$this->User->id = $this->request->data['User']['id'];
if ($this->User->save($this->request->data)) {
.................................
$this->Session->setFlash(_('<strong>Congratulations!</strong> Successfully updated your user account.'), 'default', array('class' => 'alert alert-success'));
$this->redirect(array('action' => 'settings'));
} else {
$this->Session->setFlash(_('<strong>Oops!</strong> Could not update user account.'), 'default', array('class' => 'alert alert-danger'));
}
} else {
$this->request->data = $this->User->read(null, $id);
}
}
//edit view
<?php
echo $this->Form->create('User');
echo $this->Form->hidden('id');
echo $this->Form->input('first_name');
..
..
.
echo $this->Form->end(__('Save'));
?>

Categories