Having trouble to set $_SESSION['lang'] - slim-3

Im facing a though nut to crack here... Hope someone out there can help me out !? :-)
Im making a site with slim3, where im trying to setup localization based on this course over at CodeCourse and it seem's that im having troubles to set my session properly, since im using DI-Bridge whereas he is not...
I can't seem to figure out, WHY it fails accordingly to the stacktrace !?
Can anyone help perhaps?
Here's my contaner.php
use function DI\get;
use Interop\Container\ContainerInterface;
use Slim\Csrf\Guard;
use Slim\Flash\Messages;
use Slim\Views\Twig;
use Slim\Views\TwigExtension;
use Illuminate\Translation\Translator;
use Illuminate\Translation\FileLoader;
use Illuminate\Filesystem\Filesystem;
//use Noodlehaus\Config;
use app\views\extensions\TranslationExtension;
use app\handlers\auth\Auth;
use app\handlers\errors\NotFoundHandler;
use app\models\data\About;
use app\models\data\Contact;
use app\models\data\Framework;
use app\models\data\Project;
use app\models\data\Service;
use app\models\data\Site;
use app\models\data\Testimonial;
use app\models\data\User;
use app\validation\contracts\ValidatorInterface;
use app\validation\Validator;
use app\validation\domain\DomainCheck;
use app\validation\email\EmailAvailable;
use app\validation\password\MatchesPassword;
return [
/**
* attaching : XX ->
*/
/* ROUTER */
'router' => get(Slim\Router::class),
/* 404 ERROR */
'notFoundHandler' => function(ContainerInterface $c) {
return new NotFoundHandler ($c->get(Twig::class));
},
/* AUTH */
Auth::class => function (ContainerInterface $c) {
return new Auth;
},
/* CSRF */
Guard::class => function (ContainerInterface $c) {
return new Guard;
},
/* FLASH */
Messages::class => function (ContainerInterface $c) {
return new Messages;
},
/* VALIDATOR */
ValidatorInterface::class => function (ContainerInterface $c) {
return new Validator;
},
/* TRANSLATOR */
Translator::class => function (ContainerInterface $c) {
$fallback = $c->get('settings.translations.fallback');
$loader = new FileLoader(
new Filesystem(), $c->get('settings.translations.path')
);
$translator = new Translator($loader, $_SESSION['lang'] ?? $fallback);
$translator->setFallback($fallback);
return $translator;
},
/* TWIG */
Twig::class => function (ContainerInterface $c) {
$view = new Twig(__DIR__ . '/../resources/views', [
'cache' => false
]);
$view->addExtension(new TwigExtension(
$c->get('router'),
$c->get('request')->getUri()
));
$view->addExtension(new TranslationExtension(
$c->get(Translator::class)
));
$view->getEnvironment()->addGlobal('flash', $c->get(Messages::class));
$view->getEnvironment()->addGlobal('auth', [
'check' => $c->get(Auth::class)->check(),
'user' => $c->get(Auth::class)->user(),
]);
return $view;
},
/**
* attaching : RESPECT -> VALIDATION -> CUSTOM RULES
*/
/* DOMAIN */
DomainCheck::class => function (ContainerInterface $c) {
return new DomainCheck;
},
/* EMAIL */
EmailAvailable::class => function (ContainerInterface $c) {
return new EmailAvailable;
},
/* PASSWORD */
MatchesPassword::class => function (ContainerInterface $c) {
return new MatchesPassword ($c->get(password));
},
/**
* attaching : MODELS ->
*/
/* ABOUT */
About::class => function (ContainerInterface $c) {
return new About;
},
/* CONTACT */
Contact::class => function (ContainerInterface $c) {
return new Contact;
},
/* FRAMEWORK */
Framework::class => function (ContainerInterface $c) {
return new Framework;
},
/* PROJECT */
Project::class => function (ContainerInterface $c) {
return new Project;
},
/* SERVICE */
Service::class => function (ContainerInterface $c) {
return new Service;
},
/* SITE */
Site::class => function (ContainerInterface $c) {
return new Site;
},
/* TESTIMONIAL */
Testimonial::class => function (ContainerInterface $c) {
return new Testimonial;
},
/* USER */
User::class => function (ContainerInterface $c) {
return new User;
},
];
and here's my TranslationController.php
<?php
namespace App\Controllers;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Router;
class TranslationController {
/**
* #param Request $request
* #param Response $response
* #param Router $router
* #param $args
*
* #return mixed
*/
public function switch(Request $request, Response $response, Router $router, $args) {
if (isset($args['lang'])) {
$_SESSION['lang'] = $args['lang'];
}
return $response->withRedirect($router->pathFor('home'));
}
}
plus the route for translate:
<?php
/**
* adding to view : LOCALIZATION
*/
$app->get('/translate/{lang}', ['app\controllers\TranslationController', 'switch'])->setName('translate.switch');
and finally, here's is the error stacktrace

I don't have much experience with PHP DI, but I would suggest removing the $args argument and get the param via the $request->getAttribute('lang') instead.
<?php
namespace App\Controllers;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Router;
class TranslationController {
/**
* #param Request $request
* #param Response $response
* #param Router $router
* #param $args
*
* #return mixed
*/
public function switch(Request $request, Response $response, Router $router) {
$_SESSION['lang'] = $request->getAttribute('lang');
return $response->withRedirect($router->pathFor('home'));
}
}

after a litte bit more examination and try/correct, this is what ended up solving it! :
public function switch(Request $request, Response $response, Router $router, $lang) {
if (isset($lang)) {
$_SESSION['lang'] = $lang;
}
return $response->withRedirect($router->pathFor('home'));
}

Related

How to send notifications to Laravel Users with Onesignal notification channel?

I'm trying to use laravel-notification-channels/onesignal with Laravel 9, Inertia React project.
For first I setup the client in this way:
useEffect(() => {
OneSignal.init({
appId: "PRIVATE-KEY"
});
}, []);
Testing from Onesignal panel the client is listening.
For the back-end I have created a Notification:
<?php
namespace App\Notifications;
use NotificationChannels\OneSignal\OneSignalChannel;
use NotificationChannels\OneSignal\OneSignalMessage;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Notifications\Messages\BroadcastMessage;
use App\Models\Order;
class OrderPlacedNotification extends Notification
{
use Queueable;
public $order;
/**
* Create a new notification instance.
*
* #return void
*/
public function __construct(Order $order)
{
$this->order = $order;
}
/**
* Get the notification's delivery channels.
*
* #param mixed $notifiable
* #return array
*/
public function via($notifiable)
{
return ['database', 'broadcast', OneSignalChannel::class];
}
/**
* Get the array representation of the notification.
*
* #param mixed $notifiable
* #return array
*/
public function toArray($notifiable)
{
return [
'order' => $this->order,
];
}
public function toBroadcast($notifiable)
{
return new BroadcastMessage([
'order' => $this->order
]);
}
public function toOneSignal($notifiable)
{
return OneSignalMessage::create()
->setSubject("Nuovo ordine!")
->setBody("Vedi l'ordine.")
->setUrl('http://onesignal.com');
}
}
and I send the notification via controller to all users.
All config setted but I can't listen to the user.
I found the solution. In my client I subscibe user to the specific interest and in backend I send notifictions at the users with that specific interest:
Frontend
useEffect(() => {
if(auth.user) {
window.Echo.private(`App.Models.User.${auth.user.id}`).notification(notification => {
console.log(notification);
setNotifications(() => [...notifications, notification]);
})
OneSignal.init(
{
appId: "KEY",
},
//Automatically subscribe to the new_app_version tag
OneSignal.sendTag("orders", "orders", tagsSent => {
// Callback called when tag has finished sending
console.log('TAG SENT', tagsSent);
})
);
}
}, [notifications]);
User Model:
public function routeNotificationForOneSignal()
{
return ['tags' => ['key' => 'orders', 'relation' => '=', 'value' => 'orders']];
}

How to register afterMarshal in CakePHP 4.1

I noticed that there is new afterMarshal event in 4.1.
Where to put it? In Table model? And how?
I want to do some work with results every time it's loaded.
Thanks for help
For Encryption and Decryption through model in 'CAKEPHP 4'
public $encryptedFields = ['first_name','last_name'];
public function beforeSave($event, $entity, $options)
{
foreach($this->encryptedFields as $fieldName)
{ if($entity->has($fieldName))
{ $entity->set($fieldName, encodeBeforeSave($entity->get($fieldName)));}
} return true;
}
public function beforeFind( $event, $query, $options)
{ $query->formatResults(
function ($results)
{ return $results->map(function ($row){
foreach($this->encryptedFields as $fieldName)
{
if(isset($row[$fieldName]) && !empty($row[$fieldName]) )
{
$row[$fieldName] = decodeBeforefind($row[$fieldName]);
}
}
return $row;
});
}
);
}

Laravel 5.8 and React Native using pusher: error listening to private channel: No callbacks on conversations34 for pusher:subscription_succeeded

The problem is when the app developer tries to listen to the event via pusher private channel. Here's the laravel code.
routes/api.php
Route::middleware('auth:api')->post('/broadcast/auth', 'Api\Auth\BroadcastAuthController#auth');
routs/channels.php:
// notifications channel
Broadcast::channel('users.{id}', function ($user, $id) {
return (int)$user->id === (int)$id;
});
// conversations channel
Broadcast::channel('conversations.{conversation}', function ($user, \App\Models\Conversation
$conversation) {
return $conversation->users->contains($user);
});
MessageSent event
class MessageSent implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $message;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct($message)
{
$this->message = $message;
}
/**
* Get the channels the event should broadcast on.
*
* #return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('conversations.' . $this->message->conversation_id);
}
/**
* Load user relation.
*
* #return array
*/
public function broadcastWith()
{
return [
'message' => $this->message->load('user')
];
}
}
React receiving the message
var Echotest= new Echo({
broadcaster: 'pusher',
key: 'xxxxxxxxxxx',
forceTLS: true,
cluster:"eu",
authEndpoint: 'https://example.com/api/broadcast/auth' ,
auth: {
headers: {
Authorization: "Bearer " + token ,
}
}
});
console.log(Echotest);
Echotest.channel("conversations" + this.state.conversation_id)
.listen("App\Events\MessageSent", e => {
alert(e)
});
But the result is:
Pusher : Event sent : {"event":"pusher:subscribe","data":{"channel":"conversations34"}}
Pusher : Event recd :
{"event":"pusher_internal:subscription_succeeded","channel":"conversations34","data":{}}
Pusher : No callbacks on conversations34 for pusher:subscription_succeeded
Is there anything else need to be done in Laravel to make it work in react? or the issue in react and need to be fixed? Please advise and thanks in advance.
Just Change the "Echotest.channel" to "Echotest.private"

How can I mock a validation provider in Cakephp

I have a validator that checks if a vat-number is correct. In order to do that it calls an external service. This external call slows the tests down and is unreliable, so I would like to mock it, but I don't understand how I could do it.
public function validationDefault(Validator $validator)
{
$validator->setProvider('vat', 'App\Model\Validation\VatValidation');
$validator->add('vat_no', 'isValidVatNo', [
'rule' => 'validVatNumber',
'provider' => 'vat',
]);
}
And this is the validation provider:
<?php
namespace App\Model\Validation;
use Cake\Core\Configure;
use Cake\Validation\Validation;
use VatNumberCheck\Utility\Model\VatNumberCheck;
class VatValidation extends Validation
{
public static function validVatNumber($check)
{
$vatNumberCheck = new VatNumberCheck();
try {
return $vatNumberCheck->check($check);
} catch (InternalErrorException $e) {
return false;
}
}
}
public function testValidationFail() {
$VatValidator = $this->getMockBuilder('Cake\Validation\Validator')
->setMethods(['validVatNumber'])
->getMock();
$VatValidator->expects($this->any())
->method('validVatNumber')
->will($this->returnValue(false));
$this->Users->getValidator()->setProvider('vat', $VatValidator);
$user = $this->Users->newEntity([
'vat_no' => 'asdf',
]);
$errors = $user->errors();
$this->assertArrayHasKey('vat_no', $errors);
}

Codeigniter - Array dont work correctly

Whenever I call this function, I get the user_id correctly but the password isnt checked...
Model:
<?php
class Prometheus_model extends CI_Model {
var $tables = array(
'bots' => 'bots',
'users' => 'users'
);
function __construct() {
parent::__construct();
}
public function tablename($table = NULL) {
if(! isset($table)) return FALSE;
return $this->tables[$table];
}
public function get($table, $where = array(), $order = NULL) {
$this->db->where($where);
if(isset($order)) {
$this->db->order_by($order);
}
$q = $this->db->get_where($this->tablename($table),$where);
$result = $q->result_array();
// You should use $q->num_rows() to detect the number of returned rows
if($q->num_rows()) {
return $result[0];
}
return $result;
}
public function update($table, $where = array(), $data) {
$this->db->update($this->tablename($table),$data,$where);
return $this->db->affected_rows();
}
public function insert($table, $data) {
$this->db->insert($this->tablename($table),$data);
return $this->db->insert_id();
}
public function delete($table, $where = array()) {
$this->db->delete($this->tablename($table),$where);
return $this->db->affected_rows();
}
public function explicit($query) {
$q = $this->db->query($query);
if(is_object($q)) {
return $q->result_array();
} else {
return $q;
}
}
public function num_rows($table, $where = NULL) {
if(isset($where)){
$this->db->where($where);
}
$q = $this->db->get($table);
return $q->num_rows();
}
public function get_bot_data_by_hw_id($bot_hw_id) {
$q = $this->get('bots', array('bot_hw_id' => $bot_hw_id));
return $q;
}
public function check_user_data($user_incredials, $user_password) {
if($this->num_rows('users', array('user_name' => $user_incredials, 'user_password' => $this->encrypt->decode($user_password))) == 1){
$q = $this->get('users', array('user_name' => $this->security->xss_clean($user_incredials)));
return $q['user_id'];
}
return FALSE;
}
}
?>
My function-calling at the controller:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class Login extends CI_Controller {
public function index(){
if($this->input->post('user_login')){
var_dump($this->prometheus_model->check_user_data($this->input->post('user_incredials'), $this->input->post('user_password')));
}
$this->load->view('login_index');
}
}
How can i fixx this ?
In your check_user_data() method you are using
if($this->num_rows('users', array('user_name' => $user_incredials, 'user_password' => $this->encrypt->decode($user_password))) == 1)
I think (logically) following code
$this->encrypt->decode($user_password)
should be
$this->encrypt->encode($user_password)
because, you are calling num_rows() method and it is
public function num_rows($table, $where = NULL)
{
if(isset($where)){
$this->db->where($where);
}
$q = $this->db->get($table);
return $q->num_rows();
}
which is actually querying the data base something like, for example,
select * from USERS where user_name = 'heera' and password = decode('abcde12345')
In this case, the password you are trying to match is need to be encrypted using encode (not decode) method, because the user has given you a non-encrypted (plain) password and the password saved in the database is already encrypted, so encode the plain password using encode method before you query the database to match with already encoded passwords.

Resources