(1/1) FatalErrorException Call to a member function all() on null in laravel 5.4 - laravel-5.4

4 and i have a form when submitted i want to validate its fields, what happened is when i submit the form this is what it gets
(1/1) FatalErrorException
Call to a member function all() on null
This is my code below
$validator = app('validator')->make($this->request->all(),[
'postTitle' => 'required',
'postContent' =>'required']);
In laravel 5.2 this validator works well but in laravel 5.4 it returns null
can someone help me figured this thing out?
Any help is muchly appreciated. TIA
this is my full code
<?php
namespace App\Repositories;
use App\Repositories\Contracts\addPostRepositoryInterface;
use Validator;
use Illuminate\Http\Request;
use DB;
use Session;
use Hash;
class addPostRepository implements addPostRepositoryInterface{
protected $request;
// Intialize request instance
public function __contruct(Request $request){
$this->request = $request;
}
public function addPosts(Request $request){
//validate posts
echo "test";
$validator = Validator::make($request->all(), [
'postTitle' => 'required',
'postContent' =>'required',
]);
//if validation fails return error response
if($validator->fails())
return redirect()->route('get.addPost')->withErrors($validator)->withInput();
try{
}catch(\Exception $e){
return redirect()->route('get.addPost')->withErrors(["error"=>"Could not add details! Please try again."])->withInput();
}
}
public function postCreate($screen){
switch($screen){
case 'add':
return $this->addPosts($screen);
break;
}
}
//getAddPost View
public function getAddPost(){
return view('addPost');
}
}

Seems an issue with the method injection (in the constructor) or something.
You may try creating the request object on the local(addPosts()) function.
Please try below alternative solution.
<?php
namespace App\Repositories;
use App\Repositories\Contracts\addPostRepositoryInterface;
use Validator;
use DB;
use Session;
use Hash;
class addPostRepository implements addPostRepositoryInterface{
public function addPosts(Request $request){
//validate posts
$reqeust = new \Illuminate\Http\Request;
$validator = Validator::make($request->all(), [
'postTitle' => 'required',
'postContent' =>'required',
]);
//if validation fails return error response
if($validator->fails())
return redirect()->route('get.addPost')->withErrors($validator)->withInput();
try{
}catch(\Exception $e){
return redirect()->route('get.addPost')->withErrors(["error"=>"Could not add details! Please try again."])->withInput();
}
}
public function postCreate($screen){
switch($screen){
case 'add':
return $this->addPosts($screen);
break;
}
}
//getAddPost View
public function getAddPost(){
return view('addPost');
}
// REST OF THE CODE GOES HERE...
}

Given the information you gave, I will demonstrate you how to validate a request properly in Laravel 5.4
public function store(Request $request)
{
$validator = Validator::make($request->all(), [
'postTitle' => 'required',
'postContent' =>'required',
]);
if ($validator->fails()) {
return redirect('your.view')
->withErrors($validator)
->withInput();
}
// Store the blog post...
}
This will successfully validate the request for you wherever need be. If the validation fails, you will be forwarded to your view with the according errors.
Make sure you use Validator; on top of your file.
For more information, you can read up on https://laravel.com/docs/5.4/validation

Related

Pass two variable to method in Laravel

i want to find post by slug also in url ..
but the comments must be found by post_id
Controller
public function post($slug,$id)
{
$post = Post::where('slug',$slug)->first();
$comments = Comment::where('post_id',$id)->get();
return view('content.post',compact('post','comments'));
}
Route
Route::get('post/{slug}', 'PagesController#post')->name('post.show');
Route::get('post/{slug}', 'PagesController#post')->name('post.show');
public function post($slug)
{
$post = Post::where('slug',$slug)->first();
$comments = Comment::where('post_id',$post->id)->get();
return view('content.post',compact('post','comments'));
}
Here you go:
Get post_id from the $post itself.
public function post($slug){
$post = Post::where('slug',$slug)->first();
$comments = Comment::where('post_id',$post->id)->get();
...
}
You can use Route Model Binding to ensure that routes will find your model based on the provided key.
Your Post model will require that you add the following method:
public function getRouteKeyName()
{
return 'slug';
}
Then, in your routes, you can just refer the model directly, and binding will happen automatically:
public function post(App\Post $post)
{
$comments = Comment::where('post_id',$post->id)->get();
return view('content.post',compact('post','comments'));
}
This enables you to to use the following route:
Route::get('post/{post}', 'PagesController#post')->name('post.show');
Now, additionally, to ease up your reference of the comments, add them as relations to your Post model:
public function comments()
{
return $this->hasMany(Comment::class);
}
and your Comment model:
public function post()
{
return $this->belongsTo(Post::class);
}
This will allow you to shorten your controller method even more:
public function post(App\Post $post)
{
return view('content.post',compact('post'));
}
and in your Blade view do the following instead:
#foreach($post->comments as $comment)
From: {{ $comment->name }} blah blha
#endforeach
in web.php:
Route::get('post/{slug}', 'PagesController#post')->name('post.show');
in controller:
public function post($slug)
{
$post = Post::where('slug',$slug)->first();
$comments = Comment::where('post_id',$post->id)->get(); //use founded_post_id to find it's comments
return view('content.post',compact('post','comments'));
}

how can i login to yii2 based on md5 encryption?

I have a table with a large number of users whose passwords are stored as md5,
How can I change my login to the site based on md5 encryption?
I want forgiveness for a weak English language!
Take a look here: http://www.yiiframework.com/doc-2.0/guide-security-authentication.html
Here you can find guidelines on how to create user model to support authentication, the methods who actually login/logout such users; all the burden to fetch a user and compare password is up to you based on your data model and controllers flow.
I arrived at the result like the following.
change sitecontroller file and actionlogin to:
public function actionLogin()
{
if (!Yii::$app->user->isGuest) {
return $this->goHome();
}
$model = new LoginForm();
if (yii::$app->request->post())
{
$model->username = $_POST['username'];
$model->password = $_POST['password'];
if($model->login())
{
$this->goBack();
}
}
else
{
return $this->renderPartial('login.tpl', [
'model' => $model,
]);
}
}
and then common/models/LoginForm.php change login method to :
public function login()
{
if ($this->validate()) {
return Yii::$app->user->login($this->getUser(), 0); // remember me changed to 0
}
return false;
}
and in rules method comment rememberme =====>>
// ['rememberMe', 'boolean'],
Explanation: I know this is not the right way, but it's not a problem to carry out your project!
I will suggest following solution
class User extends \yii\db\ActiveRecord implements \yii\web\IdentityInterface {
...........
public function validatePassword($password) {
return $this->password === md5($password);
}
.........
}
You just need to modify the validatePassword() methode as shown above.

Yii2 model save returns true but there is no change in MySQL

Actually, If I update my model in the action of controller(in this case it is actionTest) it gets updated. Here is my code:
public function actionTest()
{
$model = ProviderOrder::find()->where(['is_used' => 0,'type' => Transaction::COD])->orderBy(['id' => SORT_ASC])->one();//const COD = 0
$model->is_used = 1;
$model->save();
}
But in my case I defined afterSave function to my Booking model. There I call getTrackNumber function which has Transaction Class in its body.
class Booking extends ActiveRecord
{
public function afterSave($insert, $changedAttributes)
{
$this->getTrackNumber($this->id);
parent::afterSave($insert, $changedAttributes);
}
public static function getTrackNumber($bookingId){
$transaction = new Transaction();
....
}
}
Inside of Transaction class there is the same code like in actionTest.
But the problem is $model->save() returns true but when I look through phpmyadmin there is no any change is_used is still 0.
But in the first case, i.e. in actionTest everything is fine. Please help me!

Restricting controller action to creator of post in Yii2

Is there an easy way to restrict a controller action to the owner/creator of the post without using full blown RBAC?
Right now I'm doing this for every controller:
public function actionUpdate( $id ) {
$model = $this->findModel( $id );
if ( $model->user_id != Yii::$app->user->identity->id ) {
throw new NotFoundHttpException( 'The requested page does not exist.' );
}
}
But I think there must be a better way to restrict certain controllers to the users who created the $model thats being edited.
1) The recommended way is to use RBAC and rules. It's covered well in official docs in according dedicated section.
Example of rule that checks if author id matches current user id passed via params:
namespace app\rbac;
use yii\rbac\Rule;
/**
* Checks if authorID matches user passed via params
*/
class AuthorRule extends Rule
{
public $name = 'isAuthor';
/**
* #param string|integer $user the user ID.
* #param Item $item the role or permission that this rule is associated with
* #param array $params parameters passed to ManagerInterface::checkAccess().
* #return boolean a value indicating whether the rule permits the role or permission it is associated with.
*/
public function execute($user, $item, $params)
{
return isset($params['post']) ? $params['post']->createdBy == $user : false;
}
}
Then you need to tie it with existing permission (can be done in migration or with extensions):
$auth = Yii::$app->authManager;
// add the rule
$rule = new \app\rbac\AuthorRule;
$auth->add($rule);
// add the "updateOwnPost" permission and associate the rule with it.
$updateOwnPost = $auth->createPermission('updateOwnPost');
$updateOwnPost->description = 'Update own post';
$updateOwnPost->ruleName = $rule->name;
$auth->add($updateOwnPost);
// "updateOwnPost" will be used from "updatePost"
$auth->addChild($updateOwnPost, $updatePost);
// allow "author" to update their own posts
$auth->addChild($author, $updateOwnPost);
Then you can check if you user can update post like this:
use yii\web\ForbiddenHttpException;
use Yii;
public function actionUpdate($id)
{
$model = $this->findModel($id);
if (!Yii::$app->user->can('updatePost', ['post' => $model])) {
throw new ForbiddenHttpException('You are not allowed to edit this post');
}
...
}
Also note that in case you found model first and user has no access to edit it, logically it's better to throw 403 Forbidden exception rather than 404, since it's found, but not allowed for editing.
Don't forget to include rule like that in AccessControl behavior:
[
'allow' => true,
'actions' => ['update'],
'roles' => ['#'],
],
It means that update action of this controller can be only accessed by authorized users excluding guests.
2) If for some reason you don't want to use RBAC, you can use your approach:
use yii\web\ForbiddenHttpException;
public function actionUpdate($id)
{
$model = $this->findModel($id);
if ($model->user_id != Yii::$app->user->id ) {
throw new ForbiddenHttpException('You are not allowed to edit this post.');
}
...
}
To improve this you can abstract from this check by moving this logic to helper method:
namespace app\posts\components;
use Yii;
class PostPermission
{
/**
* #param $model Post
* #return boolean
*/
public static function allowedToUpdate($model)
{
return $model->user_id = Yii:$app->user->id;
}
}
Then call it like that:
use app\posts\components\PostPermission;
use yii\web\ForbiddenHttpException;
if (!PostPermission::allowedToUpdate($model) {
throw new ForbiddenHttpException('You are not allowed to edit this post.');
}
It's just an example, method doesn't have to be static, you can construct instance using $model.
You can just directly create method in Post model, but it's better to not pollute model with such logic.
3) Another alternative that I can advise is to restrict scope initially to current user when finding model:
use yii\web\NotFoundHttpException;
/**
* #param integer $id
* #return Post
* #throws NotFoundHttpException
*/
protected function findModel($id)
{
$model = Post::find(['id'=> $id, 'user_id' => Yii::$app->user->id])->one();
if ($model) {
return $model;
} else {
throw new NotFoundHttpException('This post does not exist.');
}
}
This can be improved for site administrators:
use yii\web\NotFoundHttpException;
/**
* #param integer $id
* #return Post
* #throws NotFoundHttpException
*/
protected function findModel($id)
{
$query = Post::find()->where(['id' => $id]);
if (!Yii::$app->user->is_admin) { // replace with your own check
$query->andWhere(['user_id' => Yii::$app->user->id]);
}
$model = $query->one();
if ($model) {
return $model;
} else {
throw new NotFoundHttpException('This post does not exist.');
}
}
Then you only write:
public function actionUpdate($id)
{
$model = $this->findModel($id);
...
}
That way in both cases (model not found and not allowed for editing by current user), 404 Not Found exception will be raised. From other side, nothing is wrong with that, because technically for this user this model does not exist (since he is not author of it).
We can use
AccessControlFilter
for restricting controller action instead of RBAC. This below code will give access to the actionUpdate if it is only pass the denyCallback.
use yii\filters\AccessControl;
class SiteController extends Controller
{
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'only' => ['update','delete'],
'rules' => [
[
'actions' => ['update'],
'allow' => false,
'denyCallback' => function ($rule, $action) { //PHP callable that should be called when this rule will deny the access.
//Write your logic here to deny the action
throw new \Exception('You are not allowed to access this page');
}
],
],
],
];
}
public function actionUpdate()
{
return $this->render('update');
}
}
For your reference https://github.com/yiisoft/yii2/blob/master/docs/guide/security-authorization.md

Difference between afterSave and a Event in yii2?

I wanted to send an email to admin when a new user registers. I think i can do it using two ways. one way is to use events and other is by using afterSave.
By using Events
Controller code
public function actionCreate()
{
$model = new Registeration();
if ($model->load(Yii::$app->request->post()))
{
if($model->save())
{
$model->trigger(Registeration::EVENT_NEW_USER);
}
return $this->redirect(['view', 'id' => $model->id]);
} else {
return $this->render('create', [
'model' => $model,
]);
}
}
Model code
const EVENT_NEW_USER = 'new-user';
public function init(){
$this->on(self::EVENT_NEW_USER, [$this, 'sendMail']);
}
public function sendMail($event){
// code
}
I can do the same using the afterSave method
Model code
public function afterSave($insert)
{
//code
return parent::afterSave($insert);
}
So is there any difference between the two methods? Which one is better using Events or afterSave() ?
I am new to Yii,
It depends on what you are trying to implement.
When you use afterSave email will be sent on updates also.
So event would be a better choice to your problem.
Thanks & Regards
Paul P Elias