I was to update my database but I get the error, "no data to update". Here is my script;
I have created a simple toggle to up update the database. The toggle makes the user active (is_active=1) or inactive (is_active=0). The problem I am encountering is that although the object is change from 1 to 0 or 0 to 1, when I pass it to the model, it comes back with the error, "There is no data to update". The method is as follows;
namespace App\Controllers\Admin;
use App\Entities\User;
class Users extends \App\Controllers\BaseController
{
private $model;
public function __construct()
{
$this->model = new \App\Models\UserModel;
}
public function toggle_user_is_active($id)
{
$users = $this->model->where('id', $id)->first(); // get the record
// if the current user is ACTIVE, then set it to DEACTIVE
if ($users->is_active == 1) {
$users->is_active = 0;
$this->model->save($users)); // gives an error, nothing to update
return redirect()->to('/Admin/Users/index')
->with('info', 'Success - User deactivated');
} else {
// if the current used is ACTIVE(1), change to INACTIVE(0)
$users->is_active = 1;
$this->model->save($users); // same error as above
return redirect()->to('/Admin/Users/index')
->with('info', 'Success - User Activated');
}
} // end method
}
The really strange thing is this is a copy of another method that works perfectly as follows;
namespace App\Controllers\Admin;
use App\Entities\CategoryEntity;
use App\Entities\PostEntity;
class Post extends \App\Controllers\BaseController
{
private $model;
public function __construct()
{
$this->model = new \App\Models\PostModel;
$this->CategoryModel = new \App\Models\CategoryModel;
$auth = new \App\Libraries\Authentication;
$this->current_user = $auth->getCurrentUser();
}
public function toggle_post_is_published($post_id)
{
$post = $this->model->where('post_id', $post_id)->first();
// if the current post is PUBLISHED, then set it to UNPUBLISHED
if ($post->post_is_published == 1) {
echo
$post->post_is_published = 0;
$this->model->save($post);
return redirect()->to('/admin/post/post_index')
->with('info', 'Success - Post unpublished');
} else {
// if the current post is UNPUBLISHED, then set it to PUBLISHED
$post->post_is_published = 1;
$this->model->save($post);
return redirect()->to('/admin/post/post_index')
->with('info', 'Success - Post published');
}
}
} // end class
I finally figured it out. In my UserModel I did not add 'is_active' to protected $allowedFields . I have not added 'is_active' to the allowedFields and it works.
Have you declare your model, because look like you use $this- >model but not setup your model in your constructor or other method.
Related
I am building custom mvc framework in php in order to learn and when I am trying to submit my form with an mail that already exists in the database, my validation should prevent me to do so, instead I get this error:
Fatal error: Uncaught Error: Call to a member function findUserByEmail() on null in C:\xampp\htdocs\gacho\App\Controllers\UsersController.php:
UsersController.php
<?php
namespace App\Controllers;
use App\Models\User;
use Core\Controller;
class UsersController extends Controller
{
public function __construct($controller, $action)
{
parent::__construct($controller, $action);
$this->userModel = $this->load_model('User');
}
public function registerAction()
{
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$data = [
'email' => trim($_POST['email']),
];
}
if (empty($data['email'])) {
$data['email_err'] = "Please enter your email!!!";
} else {
if ($this->userModel->findUserByEmail($data['email'])) {
$data['email_err'] = "Email is already taken!";
}
}
}
User.php
<?php
namespace App\Models;
use Core\Database;
class User
{
private $db;
public function __construct()
{
$this->db = new Database();
}
public function findUserByEmail($email)
{
$this->db->query('SELECT * FROM users WHERE email = :email');
$this->db->bind(':email', $email);
$row = $this->db->single();
if ($this->db->rowCount() > 0) {
return true;
} else {
return false;
}
}
}
Controller.php:
<?php
namespace Core;
class Controller
{
protected $_controller;
protected $_action;
public $view;
public function __construct($controller, $action)
{
$this->_controller = $controller;
$this->_action = $action;
$this->view = new View();
}
protected function load_model($model)
{
$modelPath = 'App\Models\\' . $model;
if (class_exists($modelPath)) {
$this->{$model.'Model'} = new $modelPath();
}
}
}
I think the mistake is about $this->userModel , but I'm stuck and any help is appreciated.
The problem is that in __construct of UsersController you have:
$this->userModel = $this->load_model('User');
So you assign to userModel property the return value of load_model method.
load_model method doesn't return anything so $this->userModel is always set to NULL, doesn't matter if load_model succeeded or not.
You should just return new $modelPath(); in load_model if you want to assign it to a property by return value.
Also add throw new Exception($modelPath. 'not found'); at the end of load_model method to be sure it did load the model, and not just failed silently to find it.
Note that $this->userModel is not the same as $this->UserModel (case sensitive) and $modelPath = 'App\Models\\' . $model; - why \ after App, and two \ after Models?
I think you need to access your model in $this->UserModel, since User was passed into the load_model method.
I would like to know how to implement a check for a field inside voters of an entity.
I have for example my entity Post where I want that a user not admin can't edit title field. Only admin can edit this field.
So I have created my voters but I don't know how to create this check because inside $post there is the old post entity and I don't know how to implement the check for title field
This is my easy voters file
class PostVoter extends Voter
{
const VIEW = 'view';
const EDIT = 'edit';
private $decisionManager;
public function __construct(AccessDecisionManagerInterface $decisionManager)
{
$this->decisionManager = $decisionManager;
}
protected function supports($attribute, $subject)
{
if (!in_array($attribute, array(self::VIEW, self::EDIT))) {
return false;
}
if (!$subject instanceof Post) {
return false;
}
return true;
}
protected function voteOnAttribute(
$attribute,
$subject,
TokenInterface $token
) {
$user = $token->getUser();
if (!$user instanceof User) {
return false;
}
if ($this->decisionManager->decide($token, array('ROLE_SUPER_ADMIN'))) {
return true;
}
/** #var Post $post */
$post = $subject;
switch ($attribute) {
case self::VIEW:
return $this->canView($post, $user);
case self::EDIT:
return $this->canEdit($post, $user);
}
throw new \LogicException('This code should not be reached!');
}
private function canView(Post $post, User $user)
{
if ($this->canEdit($post, $user)) {
return true;
}
return true;
}
private function canEdit(Post $post, User $user)
{
return $user === $post->getUser();
}
}
I would like to implement inside canEdit a check for the title field.
I have tried to print $post but there is only old value not some information for new value.
Couple of possible approaches.
The one I would use is to add a 'edit_title' permission to the voter then adjust my form to make the title read only if the edit_title permission was denied. This not only eliminates the need to check for a changed title but also makes things a bit friendlier for the users. One might imagine them being a bit frustrated with a form that allows them to change the title but then the app rejects the change.
If you really wanted to detect a title change then you could adjust the setTitle method in your post entity. Something like:
class Post {
private $titleWasChanged = false;
public function setTitle($title) {
if ($title !== $this->title) $this->titleWasChanged = true;
$this->title = $title;
And then of course check $titleWasChanged from the voter.
If you really wanted to go all out, the Doctrine entity manager actually has some change checking capability. You could probably access it via the voter but that would probably be overkill. http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/change-tracking-policies.html
I am working on notifications I have 2 tables: one is notify and the other is notify_status. Through notify I am showing data like title and description and in notify_status I have field read_status which is by default 0. After I show it I want to change it to 1. I also have notify_id in it as a foreign key. This is my show method:
public function show($id)
{
$notify = Notify::find($id);
$notify_status = NotifyStatus::where('notify_id', $id)->get();
$user_data['read_status'] = 1;
$user = NotifyStatus::create($user_data);
return view('notify.desr')->with(compact('notify'));
}
But it isn't creating against notify_id. What should I do?
Your models should define the following relationships:
class Notify extends Model
{
public function setAsRead()
{
$this->status->read_status = 1
$this->status->save();
}
public function wasRead()
{
return (bool) $this->status->read_status;
}
public function status()
{
return $this->hasOne(NotifyStatus::class);
}
}
class NotifyStatus extends Model
{
public function notify()
{
return $this->belongsTo(Notify::class);
}
}
Take a look at Laravel Eloquent Relationships for further reading.
In your controller you can use it like:
$notify = Notify::find($id);
$notify->status->read_status = 1;
$notify->status->save();
return view('notify.desr')->with(compact('notify'));
Or you can simply create a new method to set the new status (take a look at first method of Notify class):
$notify = Notify::find($id);
$notify->setAsRead();
return view('notify.desr')->with(compact('notify'));
public function show($id)
{
$notify = Notify::find($id);
$notify_status = NotifyStatus::where('notify_id', $id)->first();
$notify_status->read_status = 1;
$notify_status->save()
return view('notify.desr')->with(compact('notify'));
}
<?php
class Admin extends MY_Controller
{
public function dashboard()
{
/*
if(! $this->session->userdata('user_id')) // This condition is check condition which will show dashboard only if person is logged in else will redirect to login page.
return redirect('login');
*/
$this->load->model('articlesmodel','articles'); // This "articles" is the secondary name which we have given here and will be refering to.
$articles = $this->articles->articles_list(); // If we have given the secondary name then we need to use that seconary name here too.
// In above line, we will get the titles/title which will get stored in $articles.
$this->load->view('admin/dashboard.php',['articles'=>$articles]); // we are passing the received articles in here.
// The above 'articles' will be received by "dashboard.php" in the form of "$articles".
}
public function add_article()
{
$this->load->helper('form');
$this->load->view('admin/add_article.php');
}
public function store_article()
{
// Previously we use to form validate from the same file. But, now we have set the rules and all in config's form_validation file.
// We just need to pass the rule in the run like below.
$this->load->library('form_validation');
if($this->form_validation->run('add_articles_rules'))
{
// If we pass the parameter inside post then we will get that value only else it will give all the inputs in the array.
$post = $this->input->post();
unset($post['submit']); // this is to remove submit value received in $post array else it will give error.
$this->load->model('articlesmodel','articles');
if($this->articles->add_article($post))
{
echo "Insert sucessful";
}
else
{
echo "Insert uncessful";
}
}
else
{
return redirect('admin/add_article');
}
}
public function edit_article()
{
}
public function delete_article()
{
}
public function __construct()
{
parent::__construct();
if(! $this->session->userdata('user_id'))
return redirect('login');
}
// Above constructor can be placed in MY_Controller but then we need to undo the "login extends My_Controller" or make it as
// "login extends CI_Controller" as in this "admin" file we can have more methods.
}
?>
Im currently facing this strange behaviour.
<?php
// Models
class User extends \Eloquent {
protected $table = 'user';
public $timestamps = FALSE;
public function credit() {
return $this->hasOne('Credit', 'uid');
}
}
class Credit extends \Eloquent {
protected $table = 'user_credit';
public $timestamps = FALSE;
public function user() {
return $this->belongsTo('User', 'uid');
}
}
// Service
function doThings() {
// This is always working
$credit = Credit::where('uid', $user->id)->first();
// This doesn't work in test environment, but it does outside of it, i.e. in a route
// $credit = $user->credit;
if (empty($credit)) {
$credit = new Credit();
// Set some fields... then save.
$credit->foo = 'bar';
}
$user->credit()->save($credit);
}
// Test
Service::doThings(); // <--- works as expected the first time
Service::doThings(); // <--- fails, trying to save a new record instead of updating.
// In a test route
Route::get('/test', function() {
$user = User::find(1);
Service::doThings(); // <--- works as expected
Service::doThings(); // <--- works as expected
Service::doThings(); // <--- works as expected
return 'test';
});
Problem is that when accessing the credit model via the $user->credit, in the testing environment the model is not loaded and NULL is returned regardless the presence of the item inside the database.. It works when explicitly loaded, using Credit::find().
Outside the testing env, things works as expected.
Any hint?
In your class
class User extends \Eloquent {
protected $table = 'user';
public $timestamps = FALSE;
public function credit() {
return $this->hasOne('User', 'uid');
}
}
You should use (to make a one to one relation between User <-> Credit using a custom key uid)
class User extends \Eloquent {
protected $table = 'user';
public $timestamps = FALSE;
public function credit() {
return $this->hasOne('Credit', 'uid'); // <---
}
}
So, you can query like
$credit = User::find(1)->credit;