Slim Program Structure - php

I wanted to add a function to my Slim application but I'm not familiar enough with PHP to know the best way to structure something like this. This is not production ready code and I obviously will not be hard coding my username and password into the script. I made this simply to illustrate the concept.
$options = array(
'username' => 'admin',
'password' => 'password'
);
$app = new Slim(array(
'view' => new TwigView()
));
$app->config($ptions);
function authenticate($app, $username, $password) {
if($username==$app->config('username') && $password==$app->config('password')){
return true;
} else {
return false;
}
}
$app->get('/', function () use ($app) { // ... }
// ... other routes
$app->post('/login', function() use ($app) {
$username = $app->request()->post('username');
$password = $app->request()->post('password');
if(authenticate($app, $username,$password)) {
$app->redirect('/');
}
$app->redirect('/login');
});
$app->run();
Does it make sense to have to pass $app to authenticate() or is there a better way? authenticate() would not be middleware, but a function called in the POST route for pressing submit on a login form.

I suggest you use registry method.. ohbtw $app->config($ptions); should be $app->config($options);
as for "registry", I use the following class:
<?
class Registry {
private static $data;
/**
* Returns saved variable named $key
* #param string $key
* #return mixed
*/
public static function get($key) {
if(!empty(self::$data[$key])) {
return self::$data[$key];
}
return null;
}
/**
* Saves variable to registry with the name $key
* #param string $key
* #param mixed $value
* #return boolean
*/
public static function set($key, $value) {
if(!empty($value)) {
self::$data[$key] = $value;
return true;
}
return false;
}
}
?>
to save use
Registry::set('key', $value);
to retrieve use
Registry::get('key');

Related

PHP class has two methods with different parameters, how to take advantage of the constructor?

I want to make a class let's say it's called validation, it has two functions, either registrationVal or loginVal.
I want to pass data from two different pages that will use the same class. I want to initialize the variables in a constructor so it looks cleaner... how can I do this?
How can I call the constructor from one page when it doesn't have all the variables to be passed to the constructor?
For example:
registration page
$obj = new validation($password, $password2, $email, $phone);
$obj->registrationVal();
login page
$obj = new validation($email, $password);
$obj->loginVal();
You can make something like this. It's not the best code - but for start is not bad.
<?php
class Validator
{
private array $params;
private array $validated = [];
private array $errors = [];
public function __construct(array $params)
{
$this->params = $params;
$this->validate();
}
private function validate(): void
{
foreach ($this->params as $field => $param){
$validationMethod = 'validate' . ucfirst(strtolower($field));
if(! method_exists($this, $validationMethod)){
continue;
}
if($error = $this->{$validationMethod}($param)){
$this->errors[$field] = $error;
}else{
$this->validated[$field] = $param;
}
}
}
public function validateOrFail(): void
{
if($this->hasErrors()){
throw new ValidationException($this->getErrors());
}
}
public function validated(): array
{
return $this->validated;
}
private function validateLogin($value): ?string
{
//validation logic - return null on success or error string
return $validation_result;
}
public function __get($name)
{
return $this->params[$name] ?? null;
}
public function getErrors(): array
{
return $this->errors;
}
public function hasErrors(): bool
{
return count($this->errors) > 0;
}
}
You must write validation methods such validateLogin() for login field or validatePassword() for password field.
How it working:
$params = [
'login' => 'login',
'password' => 'password'
...
];
$validator = new Validator($params);
//it will throw exception when validation failing.
$validator->validateOrFail();
//or you can manually working with errors
if($validator->hasErrors()){
...
}
$password = $validator->password;
//or you can get only validated fields
$params = $validator->validated();

Connecting method/function in laravel

I'm trying to create a class function which resembles how we used to fetch database listing and convert into a dropdown listing.
eg: DB::table()->where()->get()
what i would like to achieve in laravel custom class or through model is this
Dropdown::fetch()->toArray()
Dropdown::fetch()->toDropdown()
I tried to figure out how this can be done through google. But couldn't find any solution to it.
I'm using laravel 5.8
--
Edit - Sample Code added
Code tried:
namespace App\Http\Models;
use DB;
use Closure;
use BadMethodCallException;
use Illuminate\Support\Traits\Macroable;
use Illuminate\Database\Eloquent\Model;
class Dropdown extends Model
{
private $result = [];
private $default;
public function _cities(){
$tbl_cities = config("tables.TBL_meta_cities");
$result = DB::table($tbl_cities)->select('id', 'cityname')
->orderBy('id')->get()->toArray();
$this->result = $result;
}
public function _select(){
}
public function _list(){
return $this->result;
}
public function _setDefault($def=''){
}
public static function __callStatic($method, $parameters)
{
$action = '_'.$method;
if(method_exists(get_called_class(), $action))
self::$action(...$parameters);
else echo 'not found';
}
public function __call($method, $parameters)
{
$action = '_'.$method;
if(method_exists($get_called_class(), $action))
self::$action(...$parameters);
else echo 'not found';
}
}
and i tried
Dropdown::cities()->list()
but ended with bugs
Well i figured it out myself.
class Dropdown extends Model
{
private static $result = [];
private function getCities(){
$result = City::select('id', 'cityname')
->orderBy('id')->get()->toArray();
self::$result = $result;
}
public function toArray(){
return self::$result;
}
public function toDropdown(){
// Do the dropdown works
}
/**
* Dynamically handle calls to the class.
*
* #param string $method
* #param array $parameters
* #return mixed
*
* #throws \BadMethodCallException
*/
public function __callMethod($method, $parameters){
// Check with inclusive
$class = get_called_class();
$avail = false;
$action = '';
// Check method availability - direct
if(!$avail){
$action = $method;
$avail = method_exists($class, $action);
}
// Check method 2
if(!$avail){
$action = 'get'.ucwords($method);
$avail = method_exists($class, $action);
}
if($avail){
// Call the method
$return = self::$action(...$parameters);
if(!empty($return)) return $return;
} else {
// Throw error if method not found
throw new BadMethodCallException("No such method exists: $name");
}
return new self;
}
public static function __callStatic($method, $parameters){
return (new self)->__callMethod($method, $parameters);
}
public function __call($method, $parameters){
return (new self)->__callMethod($method, $parameters);
}
}
All i need to do is return new self which does the trick instead of return $this so that the trailing function can be called easily.
Now i can able to call that function like this
Dropdown::cities()->toArray();
Reference:
https://stackoverflow.com/a/41631711/1156493
Thank you #Joseph for your time & support.

Laravel Controller use same object in two functions

Is there a way to use a object variable instantiated from a class in two functions?
Here's the code I've tried, but its just returning null:
class bookAppointmentsController extends APIController
{
private $business;
public funcition check($key)
{
$this->business = new APIClass();
$setconnection = $this->business->connectAPI($key);
}
public function book()
{
dd($this->business) //returns null
$this->business->book();
}
}
I am trying to use the $business object in two functions but it does not work, when I dd($business) it returns null
Any way to do this?
Move the instantiation to the constructor:
public function __construct(APIClass $business)
{
$this->business = $business;
}
However, it would be better if you make Laravel do the heavy lifting and prepare the APIClass for you.
In your AppServicePorvider under the register method, you can create the APIClass
/**
* Register any application services.
*
* #return void
*/
public function register()
{
$this->app->bind('APIClass', function ($app) {
$api = new APIClass();
// Do any logic required to prepare and check the api
$key = config('API_KEY');
$api->connectAPI($key);
return $api;
});
}
Check the documentations for more details.
Maybe the solution could be to make the variable Global
You could make the variable global:
function method( $args ) {
global $newVar;
$newVar = "Something";
}
function second_method() {
global $newVar;
echo $newVar;
}
Or you could return it from the first method and use it in the second method
public function check($key)
{
$this->business = new APIClass();
$setconnection = $this->business->connectAPI($key);
return $this->business;
}
public function book()
{
$business = check($key);
$business->book();
}

Authentication Middleware Slim 3.0

I am using a middleware to redirect to login page if session is not set.
$app->get('/dashboard', function (Request $request, Response $response, $args) {
include_once('employee-portal/dashboard.php');
return $response;})->add(new AuthMiddleware('counter', true, $app->getContainer()));
and my middleware:
class AuthMiddleware implements MiddlewareInterface{
private $min_role = 'counter';
private $redirect = true;
private $container = null;
public function __construct($role_required, $login_redirect, $container)
{
$this->min_role = $role_required;
$this->redirect = $login_redirect;
$this->container = $container;
}
public function __invoke($request, $response, $next)
{
if ($this->userIsAuthorised()) {
return $next($request, $response);
} else {
if ($this->redirect) {
/**
* #var \Slim\Router router`
*/
return $response->withRedirect(Details::getBaseUrl() . '/login' . '?ref=' . $request->getUri());
}
return $response->withStatus(401)->write("Sorry boss you are not authorised to see my secret");
}
}
private function userIsAuthorised()
{
if ($this->min_role == 'counter') {
return true;
} else if (SessionManager::isLoggedIn()) {
if ($_SESSION['user_type']=='counter') {
return true;
}
}
return false;
} }
but this doesn't works.
i can even see the dashboard page without login. and even after login i cannot access the $_SESSION['user_type'] session variable.
any help would be appriciated. thanks in advance.
You are passing 'counter' into your AuthMiddleware constructor, causing it to always return true in the first if() statement of userIsAuthorised() method.
if ($this->min_role == 'counter')
will always be true because you set $this->min = 'counter' in your constructor. Try rewriting the new AuthMiddleware() and constructor so that you just pass in the container. Before calling the new AuthMiddleware() you can do the following:
$container['min_role'] = 'counter' if you need it elsewhere in your app.

Phalcon\Mvc\Models - model relationship and caching

There's this in Phalcon docs:
http://docs.phalconphp.com/en/latest/reference/models.html#taking-advantage-of-relationships.
Suppose I have a code like this:
public function initialize()
{
$this->hasMany("id", "RobotsParts", "robots_id");
}
/**
* Return the related "robots parts"
*
* #return \RobotsParts[]
*/
public function getRobotsParts($parameters=null)
{
return $this->getRelated('RobotsParts', $parameters);
}
I wonder what is the best approach to cache what "->getRelated()" lookup is producing? Meaning, it should not go to database if it gets called more than once.
Thanks!
Assuming that you have defined your cache mechanism in the service container, you can do this:
public function getRobotsParts($parameters=null)
{
$di = \Phalcon\DI::getDefault();
$key = 'cache_robots_parts_' . $this->id;
$cache = $di->cache->get($key);
if (null == $cache) {
$results = $this->getRelated('RobotsParts', $parameters);
} else {
$results = $cache;
}
return $results;
}
It may be written on the short way:
public function getRobotsParts($parameters=null)
{
$parameters['cache'] = array(
'lifetime' => 123,
'key' => 'cache_robots_parts_' . $this->id,
);
return $this->getRelated('RobotsParts', $parameters);
}
Or more short, if $parameters['cache'] set in method, which caused this

Categories