I want to log my users as soon as they register. here's my UserController's code (which works) :
<?php
namespace App\Http\Controllers;
use App\Http\Requests\Login;
use App\Http\Requests\Register;
use App\User;
class UserController extends Controller
{
public function register(Register $request)
{
User::create($request->all());
$loginRequest = new Login();
$loginRequest['email'] = $request->get('email');
$loginRequest['password'] = $request->get('password');
return $this->login($loginRequest);
}
public function login(Login $request)
{
return 'ok';
}
}
I feel I'm doing something ugly with my $loginRequest. Is there a neater way to do the same ? Aka transform my Register request into a Login request ?
You are simply trying to logged in user into his account after the registration so use Auth::login($user)
class UserController extends Controller
{
public function register(Register $request)
{
$user = User::create($request->all());
\Auth::login($user);
}
}
As soon as user register you can use this snippet of code to attempt a login
if (Auth::attempt(['email' => request('email'), 'password' => request('password')])) {
return Redirect::route('dashboard');
}
So the code should be
User::create($request->all());
$loginRequest = new Login();
$loginRequest['email'] = $request->get('email');
$loginRequest['password'] = $request->get('password');
if (Auth::attempt(['email' => $request->get('email'),
'password' => $request->get('password')])) {
return Redirect::route('dashboard');
}
I want to test a repository pattern in Laravel 5.6 using PHPUnit and Mockery.
This is my code:
// PackageControllerTest.php
namespace Tests\Feature;
use Tests\TestCase;
use App\Contracts\PackageInterface;
use App\Http\Controllers\PackageController;
use Illuminate\Database\Eloquent\Collection;
class PackageControllerTest extends TestCase
{
protected $mock;
protected $target;
public function setUp()
{
parent::setUp();
parent::initDatabase();
$this->mock = $this->initMock(PackageInterface::class);
$this->target = $this->app->make(PackageController::class);
}
public function testIndex()
{
$expected = new Collection([
['name' => 'Name 1', 'html_url' => 'HTML URL 1'],
['name' => 'Name 2', 'html_url' => 'HTML URL 2'],
['name' => 'Name 3', 'html_url' => 'HTML URL 3'],
]);
$this->mock
->shouldReceive('getAllPackages')
->once()
->andReturn($expected);
$actual = $this->target->index()->packages;
$this->assertEquals($expected, $actual);
}
public function testUpdate()
{
//
}
public function tearDown()
{
parent::resetDatabase();
$this->mock = null;
$this->target = null;
}
}
// PackageControllerTest.php
...
public function index()
{
$packages = $this->package->getAllPackages();
return view('package.index', compact('packages'));
}
public function update($package_id)
{
$package = $this->package->updatePackage($package_id);
return redirect()->back();
}
// PackageRepository.php
...
public function getAllPackages()
{
$packages = $this->package->all();
return $packages;
}
public function updatePackage($package_id)
{
$package = $this->package->find($package_id);
$package->description = $this->request->description;
$package->save();
return $package;
}
The part of "testIndex()" works.
But next, I want to test the part of "testUpdate()".
How can I do?
Please help, thanks.
like this
$this->mock
->shouldReceive('updatePackage')
->with(1)
->once()
->andReturn($expected);
$actual = $this->target->update(1);
$this->assertRedirect('edit page url');
or
use DatabaseTransactions in top of class
$id = DB::table('your_table')->insertGetId(['description' => 'old'])
request()->set('description', 'test');
$actual = $this->target->update(id);
$this->assertDatabaseHas('your_table', [
'id' => $id,
'description' => 'test'
]);
I want to know what is wrong in my code given below, I am make my code clean and problem arises since function is not called in another function.example my retrieve function is not called in form method...similary my saveintodatabase function in not called in form method?
there is my code
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Register;
class Admincontroller extends Controller
{
public function form(Request $request)
{
return $this->retrieve($request);
$register= new Register;
return $this->saveintodatabase($name,$phone,$email,$course,$address);
if($register->save())
{
return redirect()->route('displaydata');
}
else
{
echo "fail to insert";
}
}
public function display()
{
$records = Register::all();
return view('displaydata',['records' => $records]);
}
public function delete($id)
{
$records = Register::destroy($id);
$records = Register::all();
if(count($records) > 0)
{
return redirect()->route('displaydata');
}
else
{
echo "No record found";
}
}
public function update($id)
{
$records = Register::find($id);
return view('updatedata',['records' => $records]);
}
public function afterupdate(Request $request)
{
return $this->retrieve($request);
$id=$request->id;
$register = Register::find($id);
if($register->save())
{
//$this->display();
return redirect()->route('displaydata');
}
else
{
echo "fail to insert";
}
}
public function __construct(Request $request)
{
$this->validate($request,[
'name' =>'required',
'phone' => 'required',
'email' => 'required',
'course' => 'required',
'address' => 'required',
]);
}
private function saveintodatabase($name,$phone,$email,$course,$address)
{
$register->name=$name;
$register->phone=$phone;
$register->email=$email;
$register->course=$course;
$register->address=$address;
}
private function retrieve(Request $request )
{
$name=$request->name;
$phone=$request->phone;
$email=$request->email;
$course=$request->course;
$address=$request->address;
}
}
From your code if form function is called then retrieve function should be called However:
your retrieve function does not return anything or change any value for form function. How can you know if it is called. Set XDebugger could be good for you to check. Or simple put die in retrieve function to see if you are there or not.
Chances are your validatoin is failed in your constructor for this you also need to check by either debugger or die method
Laravel 5 has middleware, check if you are using it to cause you never reach to form function
Error Message: http://puu.sh/d4l0F/5b0ac07e68.png
I've even saved the $transportation object before trying to create associations. I've verified that both $transporation, $from and $to are all their respective objects and they are.
I'm sure I'm missing something stupid here but I'm out of ideas.
My code:
class RideBuilder implements RideBuilderInterface
{
public function create(Advance $advance)
{
$ride = new Ride;
if($ride->validate(Input::all())) {
$ride->save();
$to = Location::find(Input::get('dropoffLocation'));
$from = Location::find(Input::get('pickupLocation'));
$transportation = new Transportation;
$transportation->save();
$transportation->transportable()->associate($ride);
$transportation->to()->associate($to);
$transportation->from()->associate($from);
$event = new Event;
$event->start = Input::get('ridePickUpTime');
$event->save();
$event->eventable->save($transportation);
$event->subjectable->save($advance);
}
return $ride;
}
}
Location Model:
class Location extends Elegant
{
protected $table = 'locations';
public $rules = array(
'label' => 'required|min:2',
'street' => 'required',
'city' => 'required',
'state' => 'required',
'type' => 'required',
);
public function advance()
{
return $this->belongsTo('Booksmart\Booking\Advance\Model\Advance');
}
public function locationable()
{
return $this->morphTo();
}
}
Transportation Model:
class Transportation extends Elegant
{
protected $table = 'transportations';
public function event()
{
$this->morphOne('Booksmart\Component\Event\Model\Event');
}
public function start_location()
{
$this->belongsTo('Booksmart\Component\Location\Model\Location', 'start_location');
}
public function end_location()
{
$this->belongsTo('Booksmart\Component\Location\Model\Location', 'end_location');
}
}
I had a similar issue. I made the stupid mistake of not adding the "return" in the relationship method!
Make sure you return the relationship... Obviously this will not work:
public function medicineType()
{
$this->belongsTo('MedicineType', 'id');
}
This is the correct way:
public function medicineType()
{
return $this->belongsTo('MedicineType', 'id');
}
Easy to miss, hard to debug...
I've built a simple form model & view, a simple AR model, and a simple controller. The form model assigns the correct values to the AR instance, but when I call save(), none of those values are saved in the DB. Any ideas?
The form model:
<?php
namespace app\models;
use Yii;
use yii\base\Model;
class PromptForm extends Model
{
public $name;
public $intro;
public $prompt;
public $notes;
public $questions;
public function attributeLabels()
{
return [
'name' => 'Prompt title',
'intro' => 'Intro',
'prompt' => 'Prompt body',
'notes' => 'Closing notes',
'questions' => 'Exploration questions',
];
}
/**
* #return array the validation rules.
*/
public function rules()
{
return [
[['name', 'prompt'], 'required'],
['name', 'filter', 'filter' => 'trim'],
['name', 'string', 'max' => 255],
[['intro', 'prompt', 'notes', 'questions'], 'default'],
];
}
public function post()
{
if ($this->validate()) {
$prompt = new Prompt();
$prompt->name = $this->name;
$prompt->intro = $this->intro;
$prompt->prompt = $this->prompt;
$prompt->notes = $this->notes;
$prompt->questions = $this->questions;
$prompt->author = \Yii::$app->user->getId();
//die(print_r($prompt, TRUE));
$prompt->save();
return $prompt;
}
return null;
}
}
The AR model:
<?php
namespace app\models;
use Yii;
use yii\db\ActiveRecord;
/**
* Prompt is the model behind the prompt item.
*/
class Prompt extends ActiveRecord
{
public $name;
public $intro;
public $prompt;
public $notes;
public $questions;
public $status;
public $author;
public $id;
/**
* #return string the name of the table associated with this ActiveRecord class.
*/
public static function tableName()
{
return 'prompt';
}
/**
* #return array the attribute labels.
*/
public function attributeLabels()
{
return [
'name' => 'Prompt title',
'intro' => 'Intro',
'prompt' => 'Prompt body',
'notes' => 'Closing notes',
'questions' => 'Exploration questions',
'status' => 'Status',
'author' => 'Author ID',
];
}
}
The controller:
<?php
namespace app\controllers;
use Yii;
use yii\filters\AccessControl;
use yii\web\Controller;
use yii\filters\VerbFilter;
use app\models\PromptForm;
use app\models\Prompt;
class PromptsController extends Controller
{
public function actionIndex()
{
// Return a list of all prompts:
return $this->render('index');
}
public function actionNew()
{
if (\Yii::$app->user->isGuest) {
return $this->goHome();
}
$model = new PromptForm();
if ($model->load(Yii::$app->request->post())) {
if ($prompt = $model->post()) {
Yii::$app->getSession()->setFlash('success', 'Your prompt was created successfully!');
return $this->goHome();
} else {
Yii::$app->getSession()->setFlash('error', 'Error while submitting your prompt.');
}
}
return $this->render('create', [
'model' => $model,
]);
}
}
Okay, I figured it out. Turns out that if you declare public attributes in your ActiveRecord model, they obscure the automatic attributes that are created by AR. Data gets assigned to your obscuring attributes but doesn't get sent into the database.
The correct AR model should have been simply this:
<?php
namespace app\models;
use Yii;
use yii\db\ActiveRecord;
class Prompt extends ActiveRecord
{
/**
* #return string the name of the table associated with this ActiveRecord class.
*/
public static function tableName()
{
return 'prompt';
}
}
Use
$prompt->save(false);
If that works that means that some validation rule fails.
Try
if ($model->load(Yii::$app->request->post())) {
if ($prompt = $model->post()) {
$model->save()
Yii::$app->getSession()->setFlash('success', 'Your prompt was created successfully!');
return $this->goHome();
} else {
Yii::$app->getSession()->setFlash('error', 'Error while submitting your prompt.');
}
}
In controller, change your if condition as follow :
if ($prompt = $model->post() !== null) {
This will validate that the value which is return is not null.
Your current validation condition is only validating where value is get assigned to variable $prompt or not. And that's why it's always returns true.
I ran across the same problem recently, when I combine the Active Record class with The Model class. Cause I know that AR actually extends Model in Yii2. Why not write less code.So I move the code from the Model to the AR.
$model = new User();
$model->load(Yii::$app->request->post())
But the AR's _attribute didn't get the post data in the form. the form data is actually in a Model object.
object(app\models\User)#39 (12) { ["password"]=> string(6) "google"
["newpass"]=> NULL ["name"]=> string(5) "Jane1" ["email"]=> string(16)
"jane#outlook.com" ["_attributes":"yii\db\BaseActiveRecord":private]=>
array(2) { ["password_hash"]=> string(60)
"$2y$13$.vNKpmosLjW/oYAhIezOZOj8rIG6QJvQj8tGHN2x78.75poXVn6Yi"
["auth_key"]=> string(32) "4XggNakVd-oeU28ny7obdw7gOmZJ-Rbu" }
simply delete the public attribute you want mass assign to the AR instance will make it work.
For who is struggling with this problem, I would remember to check the beforeSave method, if present. I mistakenly commented out the return statement.
public function beforeSave($insert)
{
// never toggle comment on this!!!
return parent::beforeSave( $insert);
}
How to Troubleshoot
First thing you should add while developing to your _form.php is errorSummary():
<?php $form = ActiveForm::begin(); ?>
// Some input fields
...
<?= $form->errorSummary($model); ?> // <--- Add this
...
<?php ActiveForm::end(); ?>
Simplify
Why not use scenarios instead if there is some minimal variation form to form:
In your model:
public function rules()
{
return [
[['field_1'], 'required', 'on' => self::SCENARIO_ADD], // only on add
[['field_2'], 'required', 'on' => self::SCENARIO_UPDATE], // only on update
[['field_3', 'field_4'], 'required'], // required all the time
];
}
In your controller:
public function actionAdd()
{
$model = new Model();
$model->scenario = Model::SCENARIO_ADD;
if ($model->load(Yii::$app->request->post())) {
return $this->redirect(['view', 'id' => $model->id]);
}
return $this->render('add', ['model' => $model]);
}
Behaviors
Alternatively, rather than assign the user directly in your model, you could use a behavior like so:
https://www.yiiframework.com/doc/api/2.0/yii-behaviors-blameablebehavior
/**
* {#inheritdoc}
*/
public function behaviors()
{
return [
[
'class' => \yii\behaviors\BlameableBehavior::className(),
'value' => Yii::$app->user->identity->username,
],
[
'class' => \yii\behaviors\TimestampBehavior::className(),
'value' => new \yii\db\Expression('NOW()'),
],
[
'class' => 'sammaye\audittrail\LoggableBehavior',
'userAttribute' => 'updated_by', //blameable attribute of the current model.
'ignored' => ['updated_by', 'updated_at'], // This ignores fields from a selection of all fields, not needed with allowed
],
];
}