Ok so I currently have this Controller which basically retrieves a Model and does some calculation.
Original code has tonnes of calculation but this is a trimmed down version for simplicity.
I wanted to move all logic to the Model and have built the code below it so far but can not figure out how to pass the custom messages to the Controller.
I am a beginner in Laravel so trying to achieve this in an easy to understand way so I can maintain it and managed to get the code below working but without custom error messages being passed onto the Controller.
Can you give me an example code of how you are passing custom error messages to controller
This is the original code in controller.
Controller
public function getDetail()
{
$request = Model::where('id','=',8)->first();
if($request)
{
if($request->number >= 5)
{
return Redirect::back()->withMessage('You have 5 or more');
}
if($request->number > 0 && $request->number < 5)
{
return Redirect::back()->withMessage('You have between 1 and 4');
}
if($request->number <= 0)
{
return Redirect::back()->withErrors('You do not have enough points');
}
}
else
{
return Redirect::back()->withErrors('No details found');
}
}
This is the new code I tried to build to move logic to model but could not figure out how to pass the custom error messages along?
Model
Class Profile
{
private $model
function __construct()
{
$this->model = Model::where('id','=',8)->first();
}
public function Notification()
{
if($this->model->number >=5)
{
return true;
}
if($this->model->number > 0 && $this->model->number < 5)
{
return true;
}
if($this->model->number <=0)
{
return false;
}
}
}
Controller
public function getDetail()
{
$request = new Profile;
$result = $request->Notification();
if($result)
{
return Redirect::back()->withMessage(????????);
}
else
{
return Redirect::back()->withErrors(????????);
}
}
Just return the message from the Model function and use it in the controller to return like shown below.
Model function
public function Notification()
{
$returnArray = array();
if($this->model->number >=5)
{
$returnArray['isMessage'] = true;
$returnArray['message'] = "You have 5 or more";
}
if($this->model->number > 0 && $this->model->number < 5)
{
$returnArray['isMessage'] = true;
$returnArray['message'] = "You have between 1 and 4";
}
if($this->model->number <=0)
{
$returnArray['isError'] = true;
$returnArray['error'] = "You do not have enough points";
}
return $returnArray;
}
Controller function
public function getDetail()
{
$request = new Profile;
$result = $request->Notification();
if(isset($result['isMessage']) && $result['isMessage'] == true)
{
return Redirect::back()->withMessage($result['message']);
}
else if (isset($result['isError']) && $result['isError'] == true)
{
return Redirect::back()->withErrors($result['error']);
}
}
Ideally speaking you should not create an object of Model in controller. You can just create the function as a static method inside model and call it from controller.
Related
I'm working on a Silverstripe 4.3.1 project which has an object with an owner member attached via $has_one:
class Object extends DataObject
{
private static $has_one = [
'Member' => Member::class,
];
We want to limit the ability to view/ edit the object to Admins & the owner member.
Here is the code we've used:
public function canView($member = null)
{
return Permission::check('ADMIN') or
$this->Member()->ID === Security::getCurrentUser()->ID or
$this->Member()->ID === $member->ID;
}
public function canEdit($member = null)
{
return Permission::check('ADMIN') or
$this->Member()->ID === Security::getCurrentUser()->ID or
$this->Member()->ID === $member->ID;
}
From what I can tell this used to work, but recent framework upgrades or code changes have broken it.
We are currently getting the following PHP error:
Trying to get property of non-object on the lines containing $this->Member()->ID
Can anyone point me in the right direction for how to fix these errors?
It may be that some Object instances do no have a Member set. In those cases calling this->Member()->ID will error as Member() returns null.
First we should check if $this->Member() is for the Object. If it is not we can return false.
public function canView($member = null)
{
if (Permission::check('ADMIN')) {
return true;
}
if (!$this || !$this->exists()) {
return false;
}
if (!$this->Member() || !$this->Member()->exists()) {
return false;
}
if ($this->Member()->ID === $member->ID) {
return true;
}
if ($this->Member()->ID === Security::getCurrentUser()->ID) {
return true;
}
return false;
}
public function canEdit($member = null)
{
if (Permission::check('ADMIN')) {
return true;
}
if (!$this || !$this->exists()) {
return false;
}
if (!$this->Member() || !$this->Member()->exists()) {
return false;
}
if ($this->Member()->ID === $member->ID) {
return true;
}
if ($this->Member()->ID === Security::getCurrentUser()->ID) {
return true;
}
return false;
}
I have multiple nested methods inside a PHP class. What I want to do is, based on certain circumstances, I want to exit from NOT JUST the current method, but 2 above it, then the leftover code should continue running. Now the issue with die(), exit() is that they end the full script and I don't want that. I simply want to go a few methods up and continue the script.
Of course, there's the old school method of returning a value in each method and check if it's false for example. But that way I'll have to write tons of additional code if I have like 50 nested methods. Here's what I have right now - it's a very basic usage here, I'm using it in a lot more complicated scenarios (using PHP 7.2.4):
class Sites
{
public function __construct()
{
$this->fn1();
}
public function fn1()
{
$fn2 = $this->fn2();
echo 'I want this to be displayed no matter what!';
}
public function fn2()
{
$fn3 = $this->fn3();
if ($fn3)
{
return true;
}
}
public function fn3()
{
$fn4 = $this->fn4();
if ($fn4)
{
return true;
}
}
public function fn4()
{
$random = rand(1, 100);
if ($random > 50)
{
return true;
}
else
{
// I want to exit/break the scirpt to continue running after
// the $fn2 = $this->fn2() call in the $this->fn1() function.
exit();
echo "This shouldn't be displayed.";
}
}
}
Just as mentioned in the code comments, I want to break the script - if the random number is below 50 and go back to fn1() but continue executing the echo function there.
Is this possible somehow? Please let me know if you need more information and I'll provide.
You can use Exceptions to do this, not particularly elegant, but this should do what your after, replace these methods...
public function fn1()
{
try {
$fn2 = $this->fn2();
}
catch ( Exception $e ) {
}
echo 'I want this to be displayed no matter what!';
}
public function fn4()
{
$random = rand(1, 100);
if ($random > 50)
{
return true;
}
else
{
// I want to exit/break the scirpt to continue running after
// the $fn2 = $this->fn2() call in the $this->fn1() function.
//exit();
throw new Exception();
echo "This shouldn't be displayed.";
}
}
How about regular function call with a flag?
class Sites
{
protected $flag = false;
public function __construct()
{
$this->fn1();
}
public function fn1()
{
if ($this->flag) {
$this->flag = true;
} else {
echo 'I want this to be displayed no matter what!';
$fn2 = $this->fn2();
}
}
public function fn2()
{
$fn3 = $this->fn3();
if ($fn3)
{
return true;
}
}
public function fn3()
{
$fn4 = $this->fn4();
if ($fn4)
{
return true;
}
}
public function fn4()
{
$random = rand(1, 100);
if ($random > 50)
{
return true;
}
else
{
// I want to exit/break the scirpt to continue running after
// the $fn2 = $this->fn2() call in the $this->fn1() function.
//exit();
$this->flag = true;
$this->fn1();
exit();
echo "This shouldn't be displayed.";
}
}
}
$sites = new Sites;
I hope this helps!
I want to check whether a user has permission to an employee.
function hasEmployeePermission($employeeID, $userKey)
{
$usersID = DB::table('users')->where('key', $userKey)->value('id');
if($userID != null) {
$employeeID = DB::table('employees')->where('user_id', $userID)->value('id');
if($mployeeID != null)
return true;
else
return false;
}
return false;
}
I want the return value to be more expressive like throwing a exception. I think throwing an exception in logical error is not a best practice. I want t know how to modify the code to return an error.
Create a simple error class.
Class myError{
public $error = true;
public $message = null;
function __construct($error,$message) {
$this->error = $error;
$this->message = $message;
}
}
then you can do something like this,
if($mployeeID != null)
return new myError(true,"no permission");
else
return new myError(false,"has permission");
There could be a lot more functionality added to the class, e.g. logging the error somewhere or things like that
If you want to know why your function failed and in which case, I would recommend using an enum.
Here is an example :
abstract class EmployeeErrors
{
const WrongID = 1;
const NoPermissions = 2;
// etc.
}
function hasEmployeePermission($employeeID, $userKey)
{
$usersID = DB::table('users')->where('key', $userKey)->value('id');
if($userID != null) {
$employeeID = DB::table('employees')->where('user_id', $userID)->value('id');
if($mployeeID != null)
return 0;
else
if ($userKey == null)
return EmployeeErrors::WrongKey;
else ...
}
return EmployeeErrors::WrongID;
}
I am struggling to create an access object to sections stored in the Database. This is a skellington of the process, this contains static data until I can get the principle working.
class User {
const IS_ADMIN = 1;
const IS_MODERATOR = 2;
const IS_MEMBER = 4;
}
This class will auto-load data from the database eventually but for the time being, this class has default values.
class Scope {
private $priv = [];
public function __construct() {
$this->priv = [1];
}
public function getPrivilidges() {
return $this->priv;
}
}
This is where it messes up, I can tell that the second and third conditions cannot be met if the first fails, how can I stop this?
class Priverlidges {
public function canView($type, Scope $scope) {
if($type & User::IS_ADMIN) {
foreach($scope->getPrivilidges() as $p) {
if($p == User::IS_ADMIN) continue;
return false;
}
return true;
}
if($type & User::IS_MODERATOR) {
foreach($scope->getPrivilidges() as $p) {
if($p == User::IS_MODERATOR) continue;
return false;
}
return true;
}
if($type & User::IS_MEMBER) {
foreach($scope->getPrivilidges() as $p) {
if($p == User::IS_MEMBER) continue;
return false;
}
return true;
}
}
}
Example usage which works fine when the default value of the priverlidge is 1:
echo (int)(new Priverlidges)->canView(User::IS_ADMIN, new Scope());
Example usage which works fine when the default value of the priverlidge is 2:
echo (int)(new Priverlidges)->canView(User::IS_MODERATOR | User::IS_ADMIN, new Scope()); // it returns false at the first condition
Can anyone help me with when to return true or false? Thanks in advance.
P.S - Users can be both Mods and Admins
EDIT: I have tried to use in_array() and still am unsure when to return the value true or false because it get's overwrite if the second method runs.
I figured it out. First, check the user is not already authenticated using a placeholder ($this->_state). Then check the type of user and check it is inside the scope.
class Priverlidges {
private $_state = false;
public function canView($type, Scope $scope) {
if(!$this->_state && $type & User::IS_ADMIN && in_array(User::IS_ADMIN, $scope->getPrivilidges())) {
$this->_state = true;
}
if(!$this->_state && $type & User::IS_MODERATOR && in_array(User::IS_MODERATOR, $scope->getPrivilidges())) {
$this->_state = true;
}
if(!$this->_state && $type & User::IS_MEMBER && in_array($scope->getPrivilidges(), User::IS_MEMBER)) {
$this->_state = true;
}
return $this->_state;
}
}
how do i pass TRUE / FALSE after update done and redirect to Index() and set
condition $viewdata['show'] to append my html sucess or something
My Controller
class Description extends CI_Controller {
public function index()
{
$viewdata['content']=$this->General_model->get_page_uri();
$viewdata['show']=; //where i want to get value when update() method
//pass value so i can show sucess / error message
$this->load->view("backend/content_view",$viewdata);
}
public function update()
{
$title=$this->input->post('txttitle');
if($title != '')
{
if(!$this->update_model->update_all($title))
{
return FALSE;
}
return TRUE;
}
redirect('Admin/Description');
}
}
My Model
public function update_all($data)
{
$this->db->set('desc',$data)
->where('desc_id','1');
if(!$this->db->update('tbl_desc'))
{
return FALSE;
}
return TRUE;
}
#Ritesh d joshi thz it work but i face problem that i can't modify when update error i test to change my field name to other to test return false;
Admin/Description/update
it show me 'A Database Error Occurred' by Codeigniter
i don't want this to show i want to keep my Admin page still same just alert nomol message error that i have set not to show many info error. how could i prevent this or this can be done by Ajax request only ?
Controller index()
if($show_ses === '0')
{
$viewdata_result = $this->General_model->rk_alert_ok('Successfully Update');
$this->session->set_flashdata('show', 'false');
}elseif($show_ses === '1'){
$viewdata_result=$this->General_model->rk_alert_no('Fail Update Request');
$this->session->set_flashdata('show', '');
}
Controller update()
if(!$this->update_model->update_all($title))
{
$this->session->set_flashdata('show', '1');
//1= false
}else{
$this->session->set_flashdata('show', '0');
//0=true
}
Use the PHP header() function.
header('Location: your_URL');
Update:
In CI, you can use redirect() function, this document will help you to understand: http://www.codeigniter.com/user_guide/helpers/url_helper.html
Please try this
class Description extends CI_Controller {
public function index()
{
$viewdata['content']=$this->General_model->get_page_uri();
$show= $this->session->flashdata('show');
if($show){
// Here is code for show and message
$viewdata['show']="message";
$this->session->set_flashdata('show', 'false');
}
$this->load->view("backend/content_view",$viewdata);
}
public function update()
{
$title=$this->input->post('txttitle');
if($title != '')
{
if(!$this->update_model->update_all($title))
{
return FALSE;
}
$this->session->set_flashdata('show', 'true');
return TRUE;
}
redirect('Admin/Description');
}
}
You can use redirection in update() as:
public function update()
{
$title = $this->input->post('txttitle');
if($title != '')
{
$status = $this->update_model->update_all($title);
if($status){
redirect(base_url().'index?show=1');
}
else{
redirect(base_url().'index?show=0');
}
}
redirect('Admin/Description');
}
than you can check the status in index() as:
public function index()
{
$viewdata['content']=$this->General_model->get_page_uri();
if(isset($this->input->post('show')) && intval($this->input->post('show')) == 0){
$viewdata['show'] = 1; // if success than show 1
}
else{
$viewdata['show'] = 0; // if error than show 0
}
$this->load->view("backend/content_view",$viewdata);
}
You can use the Header function, and to detect it you can pass the parameters too in the GET Url like below.
By default set the status as FALSE. ANd you can update the status according to your conditions either to FALSE or TRUE.
public function update()
{
$status = false;
$title=$this->input->post('txttitle');
if($title != '')
{
if(!$this->update_model->update_all($title))
{
$status = FALSE;
return FALSE;
}
$this->session->set_flashdata('show', 'true');
$status = TRUE;
return TRUE;
}
header('Location: abc.php?status='.$status);
}
Hope This will work, Do let me know in case of any confusion.